/*
 * 设计 token。
 *
 * ── 颜色不在这里 ──────────────────────────────────────────────────────
 * 颜色由**当前画风**给（`@aisi/ui` 的 `applyTheme()` 把一张 `--p-*` 变量表挂到 `<html>` 上）。
 * 本文件只负责给这些变量起页面侧的语义名，并带一份兜底值——
 * 兜底只在"画风还没挂上来"的那一瞬间生效（首屏），不是第二套配色。
 *
 * 所以：**组件里不许出现十六进制色值，也不许出现 `--p-*`**，只许用 `--c-*`。
 * 这样换画风时页面和插画是一起变的，不会出现"画换了、按钮还是老颜色"。
 */
:root {
  --c-data: var(--p-text-data);
  --c-live: var(--p-text-live);
  --c-violet-ink: var(--p-text-violet);
  /* ── 底与纸 ───────────────────────────── */
  --c-bg:        var(--p-ground, #05080b);
  --c-bg-raise:  var(--p-wall,   #0b1116);
  --c-bg-sink:   var(--p-night,  #03060a);
  --c-ink:       var(--p-text,   #d7e6e4);
  --c-ink-dim:   var(--p-text-mute, #6d8a8b);
  /* 第三档字色。原来是 `--c-ink-dim 58% + 底色` —— 亮档算出来大约 #9a9ea2 压在
     #fbfaf7 上，对比度 2.8:1，**连 WCAG 的大字下限 3:1 都不到**。
     目录页的元信息、时长、主题计数全在这一档上，所以整页的小字都像蒙了一层。
     提到 82%：亮档约 4.9:1、暗档约 6.4:1，两档都过正文的 4.5:1。
     它仍然比 --c-ink-dim 弱一档，层级没有丢，只是不再糊。 */
  --c-ink-faint: color-mix(in srgb, var(--c-ink-dim) 82%, var(--c-bg));
  --c-line:      color-mix(in srgb, var(--c-ink) 14%, transparent);
  /* 页面上绝大多数"线"用这一档。**不许再写十六进制的深色描边**——
     写死的深色在暗色档看着像分隔线，到亮色档就是一条黑杠。 */
  --c-line-soft: color-mix(in srgb, var(--c-ink) 7%, transparent);

  /* ── 毛玻璃：顶栏 / 下拉 / 浮层 ───────────
     三层叠起来才像玻璃：半透的底、一道极淡的边、顶边一条高光。
     只有"半透 + blur"的话是蒙了层雾，不是玻璃。 */
  --c-glass:        color-mix(in srgb, var(--c-bg) 55%, transparent);
  --c-glass-tint:   color-mix(in srgb, var(--c-bg-raise) 50%, transparent);
  --c-glass-line:   color-mix(in srgb, var(--c-ink) 14%, transparent);
  --c-glass-sheen:  color-mix(in srgb, var(--c-ink) 10%, transparent);
  --c-glass-shadow: rgba(0, 0, 0, .4);
  --c-glass-hover:  color-mix(in srgb, var(--c-ink) 8%, transparent);
  --glass-blur: 18px;
  /* 外壳玻璃（顶栏、文章页顶栏下的位置条）：两条贴在一起，必须是**同一块**玻璃——同一个底、同一个模糊。
     磨砂到底下的字认不出、但看得出那里有一行行字在滚过；上面的按钮和字仍是主角。
     不能是实底，也不能糊成一片看不出有字。 */
  --c-chrome-glass: color-mix(in srgb, var(--c-bg) 45%, transparent);
  --chrome-blur: 7px;

  /* ── 代码块 ───────────────────────────────
     词元色是同步阶段 Shiki 分好的，底色必须跟着词元色的明度关系走，
     所以这一组由 themeVars() 按亮暗算，这里只留暗色兜底。 */
  --c-code-bg:     #121212;
  --c-code-fg:     #dbd7ca;
  --c-code-bar:    #1a1a1a;
  --c-code-line:   rgba(255, 255, 255, .08);
  --c-code-gutter: rgba(255, 255, 255, .28);
  --c-code-note:   #171717;
  --c-code-hot:    #2a1f25;
  --c-code-tag:    rgba(201, 144, 118, .18);
  --c-code-tag-fg: #c99076;

  /* ── 强调：**和插画里的强调色是同一个色** ── */
  --c-gold:      var(--p-text-accent, #2ff3c8);   /* 当前焦点、重点词 */
  --c-mint:      var(--p-text-good,   #34e0a1);   /* 次强调、对照 */
  --c-coral:     var(--p-text-alert,  #ff4d5e);   /* 选中态、警示 */
  --c-violet:    var(--p-violet,      #9d7bff);   /* AI 相关 */
  --c-amber:     var(--p-text-live,   #f0a040);   /* 黄灯：注意、等待（和 gold 分开——有的画风里 gold 是红的） */
  /* 当色当底 / 当字是两个值：当底用饱和原色，当字要先过对比度 */
  --c-accent-bg: var(--p-accent,     #2ff3c8);
  --c-on-accent: var(--p-on-accent,  #04120f);
  --c-accent-soft: color-mix(in srgb, var(--c-gold) 13%, var(--c-bg-raise));
  --c-on-accent-soft: var(--c-ink);
  --c-good-bg:   var(--p-good,       #34e0a1);
  --c-on-good:   var(--p-on-good,    #04120f);

  /* ── 语义 ─────────────────────────────── */
  --c-note:   var(--c-mint);
  --c-warn:   var(--c-gold);
  --c-danger: var(--c-coral);
  --c-ai:     var(--c-violet);
  --c-free:   var(--c-mint);
  --c-locked: var(--c-ink-faint);

  /* ── 投影：**形状也归画风管** ──────────────
     画风决定的是"投影长什么样"（硬位移 / 柔和 / 辉光 / 描边），
     页面这三档只是把同一套语言用到 DOM 上，插画和卡片才是一个世界的东西。 */
  /* 三档投影的**形态**由画风给（硬位移 / 柔和 / 辉光 / 套印 / 无），
     这里只留兜底值，供画风还没挂上来的那一瞬间用。 */
  --shadow-color: rgba(0, 0, 0, .55);
  --shadow-lg: 0 10px 20px var(--shadow-color);
  --shadow-md: 0 7px 14px var(--shadow-color);
  --shadow-sm: 0 4px 9px var(--shadow-color);
  /* 描边：粗野/硬边的画风用实色粗线，柔和的画风用一道淡线 */
  --c-border-w: 1px;
  --c-border: var(--c-line);

  /* ── 字号阶梯（移动优先）──────────────────
     这里是**手机竖屏**的值，往上逐档放大（见文件末尾的断点块）。
     定这套值的依据只有一条：**中文正文每行 20–24 个字**。
     少于 18 字一行读着碎，多于 26 字一行眼睛会跳行。
     手机竖屏内容宽 = 393 − 2×16 = 361px，除以 22 ≈ 16.4px → --t-base 就取 16.5px。

     踩过的坑：原来整套阶梯写死不随断点变，只有 --t-base 动了一点点，
     结果 h1 在手机上 40px、h2 31px、代码 15px 等宽——标题占满两行、代码行行被切。 */
  --t-xs:   0.75rem;      /* 12px  角标、版本号 */
  --t-sm:   0.875rem;     /* 14px  表格、图注、次要信息 */
  --t-code: 0.8125rem;    /* 13px  代码。等宽字比正文显小，要单独一档 */
  --t-base: 1.03125rem;   /* 16.5px 正文 */
  --t-lg:   1.125rem;     /* 18px  引文、重点段 */
  --t-xl:   1.3125rem;    /* 21px  h3 */
  --t-2xl:  1.4375rem;    /* 23px  h2 */
  --t-3xl:  1.75rem;      /* 28px  h1 */
  --lh-tight: 1.3;
  --lh-body:  1.75;

  /* ── 间距节奏（4 的倍数） ──────────────── */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 32px; --s-7: 48px; --s-8: 64px; --s-9: 96px;

  /* 圆角也归画风管：木刻线稿是方角，蜡笔浮雕是大圆角。兜底值在这里。 */
  --r-sm: 6px; --r-md: 12px; --r-lg: 20px; --r-xl: 30px;

  /* ── 版心 ─────────────────────────────── */
  --measure: 42rem;       /* 正文最佳阅读宽度 */
  --page-pad: var(--s-4);

  --ease: cubic-bezier(.22,.61,.36,1);
  --dur-fast: 140ms; --dur: 260ms; --dur-slow: 520ms;

  /* 字体也归画风管：水墨那套是宋楷，终端那套是等宽，软陶那套是圆体。
     画里的字和页面上的字必须是同一套，否则画风只换了一半。 */
  --font-body:    var(--p-font-body, 'PingFang SC','Noto Sans SC',system-ui,sans-serif);
  --font-display: var(--p-font-display, var(--font-body));
  --font-mono:    var(--p-font-mono, 'SF Mono', ui-monospace, Menlo, monospace);
}

/* ── 六档：字号与留白一起走 ────────────────────────────────────
   每一档都要保证"每行 20–24 个汉字"。屏幕越宽，版心（--measure）先放宽，
   放到 70ch 就不再放了——再宽就该靠留白和侧边目录，不是靠把字撑大。 */

/* 手机横屏起：宽度够了，字可以稍微大一点 */
@media (min-width: 431px) {
  :root {
    --page-pad: var(--s-5);
    --t-base: 1.0625rem;  /* 17px */
    --t-2xl: 1.5625rem;   /* 25px */
    --t-3xl: 1.9375rem;   /* 31px */
  }
}
/* 平板竖屏 */
@media (min-width: 744px) {
  :root {
    --page-pad: var(--s-6);
    --t-sm: 0.9375rem; --t-code: 0.875rem;
    --t-base: 1.09375rem; /* 17.5px */
    --t-lg: 1.1875rem;
    --t-xl: 1.4375rem; --t-2xl: 1.75rem; --t-3xl: 2.25rem;
  }
}
/* 平板横屏：右侧页内目录开始出现（见 app.css），版心不再吃满 */
@media (min-width: 1024px) { :root { --page-pad: var(--s-6); --measure: 40rem; } }
/* 电脑 1440 */
@media (min-width: 1280px) {
  :root {
    --page-pad: var(--s-7); --measure: 42rem;
    --t-base: 1.125rem;   /* 18px */
    --t-lg: 1.25rem; --t-xl: 1.5rem; --t-2xl: 1.875rem; --t-3xl: 2.5rem;
  }
}
/* 电脑 1920：只放留白与版心，字号到此为止 */
@media (min-width: 1728px) { :root { --page-pad: var(--s-8); --measure: 44rem; } }

/* 有人会晕：尊重系统的"减少动效" */
@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast: 1ms; --dur: 1ms; --dur-slow: 1ms; }
  *, *::before, *::after { animation-duration: 1ms !important; transition-duration: 1ms !important; }
}
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-ink);
  font: var(--t-base)/var(--lh-body) var(--font-body);
  -webkit-font-smoothing: antialiased;
  /* 移动端 100vh 会被地址栏吃掉，用 dvh */
  min-height: 100dvh;
}
h1,h2,h3,h4 { line-height: var(--lh-tight); font-weight: 700; margin: 0; }
p { margin: 0 0 var(--s-4); }
/*
 * 链接的下划线**从左往右画出来**，不是瞬间出现。
 * 用 background-size 过渡而不是 text-decoration：后者不能过渡。
 */
a {
  color: var(--c-gold); text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1.5px;
  transition: background-size var(--dur) var(--ease);
}
a:hover, a:focus-visible { background-size: 100% 1.5px; }
a:focus-visible { outline: 2px solid var(--c-gold); outline-offset: 3px; border-radius: 2px; }

/*
 * 正文里的重点词：底下垫一道**半高的**色带，像荧光笔划过。
 * 划过的动作由滚动驱动——读到那一行时它才亮起来，
 * 这比"一进页面全部高亮"更接近人读书时用笔划重点的节奏。
 */
strong {
  font-weight: 700; color: var(--c-ink);
  background-image: linear-gradient(color-mix(in srgb, var(--c-gold) 26%, transparent),
                                    color-mix(in srgb, var(--c-gold) 26%, transparent));
  background-repeat: no-repeat;
  background-position: 0 88%;
  background-size: 100% 0.42em;
  padding-inline: 1px;
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    strong {
      animation: mark-in linear both;
      animation-timeline: view();
      animation-range: entry 20% entry 70%;
    }
    @keyframes mark-in { from { background-size: 0% 0.42em; } to { background-size: 100% 0.42em; } }
  }
}
em { font-style: normal; color: var(--c-mint); font-weight: 600; }
img, svg, video { max-width: 100%; height: auto; display: block; }
button { font: inherit; color: inherit; }

/* 键盘能不能走完全程 —— 可访问性底线 */
:focus-visible { outline: 3px solid var(--c-gold); outline-offset: 3px; border-radius: var(--r-sm); }
:focus:not(:focus-visible) { outline: none; }

/* 宽内容自己滚，页面整体永不横向滚动 */
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }
body { overflow-x: hidden; }

.page { width: 100%; max-width: 1600px; margin: 0 auto; padding-inline: var(--page-pad); }
.prose { max-width: var(--measure); }
.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;
}
/*
 * 设计 token。
 *
 * ── 颜色不在这里 ──────────────────────────────────────────────────────
 * 颜色由**当前画风**给（`@aisi/ui` 的 `applyTheme()` 把一张 `--p-*` 变量表挂到 `<html>` 上）。
 * 本文件只负责给这些变量起页面侧的语义名，并带一份兜底值——
 * 兜底只在"画风还没挂上来"的那一瞬间生效（首屏），不是第二套配色。
 *
 * 所以：**组件里不许出现十六进制色值，也不许出现 `--p-*`**，只许用 `--c-*`。
 * 这样换画风时页面和插画是一起变的，不会出现"画换了、按钮还是老颜色"。
 */
:root {
  --c-data: var(--p-text-data);
  --c-live: var(--p-text-live);
  --c-violet-ink: var(--p-text-violet);
  /* ── 底与纸 ───────────────────────────── */
  --c-bg:        var(--p-ground, #05080b);
  --c-bg-raise:  var(--p-wall,   #0b1116);
  --c-bg-sink:   var(--p-night,  #03060a);
  --c-ink:       var(--p-text,   #d7e6e4);
  --c-ink-dim:   var(--p-text-mute, #6d8a8b);
  /* 第三档字色。原来是 `--c-ink-dim 58% + 底色` —— 亮档算出来大约 #9a9ea2 压在
     #fbfaf7 上，对比度 2.8:1，**连 WCAG 的大字下限 3:1 都不到**。
     目录页的元信息、时长、主题计数全在这一档上，所以整页的小字都像蒙了一层。
     提到 82%：亮档约 4.9:1、暗档约 6.4:1，两档都过正文的 4.5:1。
     它仍然比 --c-ink-dim 弱一档，层级没有丢，只是不再糊。 */
  --c-ink-faint: color-mix(in srgb, var(--c-ink-dim) 82%, var(--c-bg));
  --c-line:      color-mix(in srgb, var(--c-ink) 14%, transparent);
  /* 页面上绝大多数"线"用这一档。**不许再写十六进制的深色描边**——
     写死的深色在暗色档看着像分隔线，到亮色档就是一条黑杠。 */
  --c-line-soft: color-mix(in srgb, var(--c-ink) 7%, transparent);

  /* ── 毛玻璃：顶栏 / 下拉 / 浮层 ───────────
     三层叠起来才像玻璃：半透的底、一道极淡的边、顶边一条高光。
     只有"半透 + blur"的话是蒙了层雾，不是玻璃。 */
  --c-glass:        color-mix(in srgb, var(--c-bg) 55%, transparent);
  --c-glass-tint:   color-mix(in srgb, var(--c-bg-raise) 50%, transparent);
  --c-glass-line:   color-mix(in srgb, var(--c-ink) 14%, transparent);
  --c-glass-sheen:  color-mix(in srgb, var(--c-ink) 10%, transparent);
  --c-glass-shadow: rgba(0, 0, 0, .4);
  --c-glass-hover:  color-mix(in srgb, var(--c-ink) 8%, transparent);
  --glass-blur: 18px;
  /* 外壳玻璃（顶栏、文章页顶栏下的位置条）：两条贴在一起，必须是**同一块**玻璃——同一个底、同一个模糊。
     磨砂到底下的字认不出、但看得出那里有一行行字在滚过；上面的按钮和字仍是主角。
     不能是实底，也不能糊成一片看不出有字。 */
  --c-chrome-glass: color-mix(in srgb, var(--c-bg) 45%, transparent);
  --chrome-blur: 7px;

  /* ── 代码块 ───────────────────────────────
     词元色是同步阶段 Shiki 分好的，底色必须跟着词元色的明度关系走，
     所以这一组由 themeVars() 按亮暗算，这里只留暗色兜底。 */
  --c-code-bg:     #121212;
  --c-code-fg:     #dbd7ca;
  --c-code-bar:    #1a1a1a;
  --c-code-line:   rgba(255, 255, 255, .08);
  --c-code-gutter: rgba(255, 255, 255, .28);
  --c-code-note:   #171717;
  --c-code-hot:    #2a1f25;
  --c-code-tag:    rgba(201, 144, 118, .18);
  --c-code-tag-fg: #c99076;

  /* ── 强调：**和插画里的强调色是同一个色** ── */
  --c-gold:      var(--p-text-accent, #2ff3c8);   /* 当前焦点、重点词 */
  --c-mint:      var(--p-text-good,   #34e0a1);   /* 次强调、对照 */
  --c-coral:     var(--p-text-alert,  #ff4d5e);   /* 选中态、警示 */
  --c-violet:    var(--p-violet,      #9d7bff);   /* AI 相关 */
  --c-amber:     var(--p-text-live,   #f0a040);   /* 黄灯：注意、等待（和 gold 分开——有的画风里 gold 是红的） */
  /* 当色当底 / 当字是两个值：当底用饱和原色，当字要先过对比度 */
  --c-accent-bg: var(--p-accent,     #2ff3c8);
  --c-on-accent: var(--p-on-accent,  #04120f);
  --c-accent-soft: color-mix(in srgb, var(--c-gold) 13%, var(--c-bg-raise));
  --c-on-accent-soft: var(--c-ink);
  --c-good-bg:   var(--p-good,       #34e0a1);
  --c-on-good:   var(--p-on-good,    #04120f);

  /* ── 语义 ─────────────────────────────── */
  --c-note:   var(--c-mint);
  --c-warn:   var(--c-gold);
  --c-danger: var(--c-coral);
  --c-ai:     var(--c-violet);
  --c-free:   var(--c-mint);
  --c-locked: var(--c-ink-faint);

  /* ── 投影：**形状也归画风管** ──────────────
     画风决定的是"投影长什么样"（硬位移 / 柔和 / 辉光 / 描边），
     页面这三档只是把同一套语言用到 DOM 上，插画和卡片才是一个世界的东西。 */
  /* 三档投影的**形态**由画风给（硬位移 / 柔和 / 辉光 / 套印 / 无），
     这里只留兜底值，供画风还没挂上来的那一瞬间用。 */
  --shadow-color: rgba(0, 0, 0, .55);
  --shadow-lg: 0 10px 20px var(--shadow-color);
  --shadow-md: 0 7px 14px var(--shadow-color);
  --shadow-sm: 0 4px 9px var(--shadow-color);
  /* 描边：粗野/硬边的画风用实色粗线，柔和的画风用一道淡线 */
  --c-border-w: 1px;
  --c-border: var(--c-line);

  /* ── 字号阶梯（移动优先）──────────────────
     这里是**手机竖屏**的值，往上逐档放大（见文件末尾的断点块）。
     定这套值的依据只有一条：**中文正文每行 20–24 个字**。
     少于 18 字一行读着碎，多于 26 字一行眼睛会跳行。
     手机竖屏内容宽 = 393 − 2×16 = 361px，除以 22 ≈ 16.4px → --t-base 就取 16.5px。

     踩过的坑：原来整套阶梯写死不随断点变，只有 --t-base 动了一点点，
     结果 h1 在手机上 40px、h2 31px、代码 15px 等宽——标题占满两行、代码行行被切。 */
  --t-xs:   0.75rem;      /* 12px  角标、版本号 */
  --t-sm:   0.875rem;     /* 14px  表格、图注、次要信息 */
  --t-code: 0.8125rem;    /* 13px  代码。等宽字比正文显小，要单独一档 */
  --t-base: 1.03125rem;   /* 16.5px 正文 */
  --t-lg:   1.125rem;     /* 18px  引文、重点段 */
  --t-xl:   1.3125rem;    /* 21px  h3 */
  --t-2xl:  1.4375rem;    /* 23px  h2 */
  --t-3xl:  1.75rem;      /* 28px  h1 */
  --lh-tight: 1.3;
  --lh-body:  1.75;

  /* ── 间距节奏（4 的倍数） ──────────────── */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 32px; --s-7: 48px; --s-8: 64px; --s-9: 96px;

  /* 圆角也归画风管：木刻线稿是方角，蜡笔浮雕是大圆角。兜底值在这里。 */
  --r-sm: 6px; --r-md: 12px; --r-lg: 20px; --r-xl: 30px;

  /* ── 版心 ─────────────────────────────── */
  --measure: 42rem;       /* 正文最佳阅读宽度 */
  --page-pad: var(--s-4);

  --ease: cubic-bezier(.22,.61,.36,1);
  --dur-fast: 140ms; --dur: 260ms; --dur-slow: 520ms;

  /* 字体也归画风管：水墨那套是宋楷，终端那套是等宽，软陶那套是圆体。
     画里的字和页面上的字必须是同一套，否则画风只换了一半。 */
  --font-body:    var(--p-font-body, 'PingFang SC','Noto Sans SC',system-ui,sans-serif);
  --font-display: var(--p-font-display, var(--font-body));
  --font-mono:    var(--p-font-mono, 'SF Mono', ui-monospace, Menlo, monospace);
}

/* ── 六档：字号与留白一起走 ────────────────────────────────────
   每一档都要保证"每行 20–24 个汉字"。屏幕越宽，版心（--measure）先放宽，
   放到 70ch 就不再放了——再宽就该靠留白和侧边目录，不是靠把字撑大。 */

/* 手机横屏起：宽度够了，字可以稍微大一点 */
@media (min-width: 431px) {
  :root {
    --page-pad: var(--s-5);
    --t-base: 1.0625rem;  /* 17px */
    --t-2xl: 1.5625rem;   /* 25px */
    --t-3xl: 1.9375rem;   /* 31px */
  }
}
/* 平板竖屏 */
@media (min-width: 744px) {
  :root {
    --page-pad: var(--s-6);
    --t-sm: 0.9375rem; --t-code: 0.875rem;
    --t-base: 1.09375rem; /* 17.5px */
    --t-lg: 1.1875rem;
    --t-xl: 1.4375rem; --t-2xl: 1.75rem; --t-3xl: 2.25rem;
  }
}
/* 平板横屏：右侧页内目录开始出现（见 app.css），版心不再吃满 */
@media (min-width: 1024px) { :root { --page-pad: var(--s-6); --measure: 40rem; } }
/* 电脑 1440 */
@media (min-width: 1280px) {
  :root {
    --page-pad: var(--s-7); --measure: 42rem;
    --t-base: 1.125rem;   /* 18px */
    --t-lg: 1.25rem; --t-xl: 1.5rem; --t-2xl: 1.875rem; --t-3xl: 2.5rem;
  }
}
/* 电脑 1920：只放留白与版心，字号到此为止 */
@media (min-width: 1728px) { :root { --page-pad: var(--s-8); --measure: 44rem; } }

/* 有人会晕：尊重系统的"减少动效" */
@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast: 1ms; --dur: 1ms; --dur-slow: 1ms; }
  *, *::before, *::after { animation-duration: 1ms !important; transition-duration: 1ms !important; }
}
/* ── 正文排版 ───────────────────────────── */
.kp-h  { margin: var(--s-7) 0 var(--s-4); }
.kp-h2 { font-size: var(--t-2xl); color: var(--c-ink); }
.kp-h3 { font-size: var(--t-xl); color: var(--c-gold); }
.kp-h4 { font-size: var(--t-lg); color: var(--c-mint); }
.kp-list { margin: 0 0 var(--s-4); padding-left: var(--s-5); }
.kp-list li { margin-bottom: var(--s-2); }
.kp-quote {
  margin: var(--s-5) 0; padding: var(--s-4) var(--s-5);
  background: var(--c-bg-sink); border-left: 4px solid var(--c-gold);
  border-radius: 0 var(--r-md) var(--r-md) 0; color: var(--c-ink-dim);
}
/* 表格同理：窄屏放不下就横滑，右缘给渐隐提示 */
.scroll-x { position: relative; }
.kp-table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); margin: var(--s-5) 0; }
.kp-table th, .kp-table td { padding: var(--s-3) var(--s-4); text-align: left; }
.kp-table thead th { background: var(--c-bg-raise); color: var(--c-gold); white-space: nowrap; }
.kp-table tbody tr + tr td { border-top: 1px solid var(--c-line-soft); }
/* ── 代码块：做成编辑器的样子 ─────────────────────────
   语言标签 + 行号槽 + 语法着色 + 重点行高亮 + 版本角标。
   着色是同步阶段 Shiki 分好的（见 pipeline/lib/highlight.mjs），这里只负责画。
   宽代码在 .scroll-x 里自己横滚，绝不把页面撑宽。

   **底色一律走 --c-code-*，不许写十六进制。** 那一组由 themeVars() 按亮暗算：
   词元色是烘焙进内容里的（vitesse-dark 分的词），亮色档下由 Code.tsx 映射到
   vitesse-light，底色必须跟着一起翻，否则要么浅字压浅底，要么亮色页上戳一块黑砖。 */
.code {
  margin: var(--s-5) 0; border-radius: var(--r-md); overflow: hidden;
  background: var(--c-code-bg);
  color: var(--c-code-fg);
  /* 内容层不投影（两层法则，见 theme.ts）。代码块和正文的分界靠底色差 +
     一道发丝线，不靠浮起来——它本来就没浮，它是页面上凹下去的一块。 */
  border: 1px solid var(--c-code-line);
}
.code__bar {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--s-3); background: var(--c-code-bar);
  border-bottom: 1px solid var(--c-code-line);
  font-size: var(--t-xs); line-height: 1.5;
}
.code__lang {
  font-family: var(--font-mono); color: var(--c-code-tag-fg); background: var(--c-code-tag);
  padding: 2px 8px; border-radius: var(--r-sm); letter-spacing: .04em;
}
.code__hint { color: var(--c-code-gutter); font-weight: 600; letter-spacing: .02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.code__ver {
  margin-left: auto; color: var(--c-code-gutter); font-family: var(--font-mono); white-space: nowrap;
}
/* 复制按钮靠右；有版本角标时由角标顶到右边 */
.code__bar .copy-btn { margin-left: auto; }
.code__ver + .copy-btn { margin-left: 0; }
/* 横滚提示：**只在真的还能划的时候出现。**
   原来是一个固定的 ::after 渐隐，代码没超宽时右边也糊着一条——
   暗色档看不太出来，亮色档就是右缘一道说不清的白边。
   改用经典的 scroll-shadow：两层 `local` 的底色块跟着内容滚，
   两层 `scroll` 的阴影钉在容器上；滚到头时底色块正好盖住阴影，
   没超宽时两边都被盖住 = 什么都不画。纯 CSS，不用量宽度。 */
.code__body {
  position: relative;
  background:
    linear-gradient(to right,  var(--c-code-bg), transparent) left  / 28px 100% no-repeat local,
    linear-gradient(to left,   var(--c-code-bg), transparent) right / 28px 100% no-repeat local,
    radial-gradient(farthest-side at 0   50%, var(--c-code-line), transparent) left  / 14px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, var(--c-code-line), transparent) right / 14px 100% no-repeat scroll;
}
.code__pre { margin: 0; padding: var(--s-3) 0; font: var(--t-code)/1.7 var(--font-mono); }
.code__pre code { display: block; min-width: max-content; }
.code__line { display: flex; gap: var(--s-4); padding-inline: var(--s-3) var(--s-5); }
.code__no {
  flex: none; text-align: right; color: var(--c-code-gutter); user-select: none;
  position: sticky; left: var(--s-3);      /* 横滚时行号钉住 */
  background: var(--c-code-bg);
}
.code__text { white-space: pre; }
/* 重点行：正文里写 hl="3-5"，配合 note= 的「你要看的是什么」 */
.code__line.is-hot { background: var(--c-code-hot); }
.code__line.is-hot .code__no { background: var(--c-code-hot); color: var(--c-gold); font-weight: 700; }
.code__note {
  margin: 0; padding: var(--s-3) var(--s-4); background: var(--c-code-note);
  border-top: 1px solid var(--c-code-line);
  font-size: var(--t-sm); color: var(--c-ink-dim); line-height: 1.6;
}
.code__ver { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* 手机上行号槽收窄，别把本来就紧的宽度再吃掉 */
@media (max-width: 430px) {
  .code__line { gap: var(--s-3); padding-inline: var(--s-2) var(--s-4); }
  .code__hint { display: none; }            /* 窄屏优先保住语言标签和版本号 */
}

/* ── Reveal：先问后答 ─────────────────────
   动效要有**起因**（点了那一下）和**结果**（内容真的展开了）。
   位移永远伴随不透明度或形变——单纯平移一下是敷衍。 */
.reveal { margin: var(--s-5) 0; }
.reveal__trigger {
  width: 100%; display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-4) var(--s-5); cursor: pointer; text-align: left;
  background: var(--c-glass-tint); border: none;
  border-radius: var(--r-md);
  box-shadow: inset 0 0 0 1px var(--c-glass-line), inset 0 1px 0 var(--c-glass-sheen);
  transition: background var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.reveal__trigger:hover { background: var(--c-glass-hover); }
/* 按下去是"按进玻璃里"，不是把整块牌子挪走——控件不该在页面上跳 */
.reveal__trigger:active {
  box-shadow: inset 0 0 0 1px var(--c-glass-line), inset 0 2px 6px var(--shadow-color); }
.reveal__trigger:focus-visible {
  outline: none; box-shadow: inset 0 0 0 2px var(--c-gold); }
.reveal__label { flex: 1; font-weight: 600; color: var(--c-gold); }
.reveal__hint {
  font-size: var(--t-xs); color: var(--c-ink-faint);
  transition: color var(--dur-fast) var(--ease);
}
.reveal__trigger:hover .reveal__hint { color: var(--c-ink-dim); }
.reveal__chevron {
  color: var(--c-ink-dim); flex: none;
  transition: transform var(--dur) var(--ease), color var(--dur-fast) var(--ease);
}
.reveal.is-open .reveal__chevron { transform: rotate(180deg); color: var(--c-gold); }

/* 高度过渡靠 0fr → 1fr，不用 JS 量高度，内容多高都对 */
.reveal__wrap {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-slow) var(--ease);
}
.reveal.is-open .reveal__wrap { grid-template-rows: 1fr; }
.reveal__body { overflow: hidden; min-height: 0; }
.reveal__inner {
  margin-top: var(--s-2); padding: var(--s-5);
  background: var(--c-bg-sink); border-radius: var(--r-md);
  /* 答案是"被揭开"的：从上往下擦出来，同时轻微上浮。
     clip-path 比单纯 opacity 更像掀开一张纸。 */
  clip-path: inset(0 0 100% 0);
  opacity: 0; transform: translateY(-4px);
  transition: clip-path var(--dur-slow) var(--ease),
              opacity var(--dur) var(--ease),
              transform var(--dur-slow) var(--ease);
}
.reveal.is-open .reveal__inner {
  clip-path: inset(0 0 0 0); opacity: 1; transform: none;
  transition-delay: 60ms;           /* 等高度先撑开一点点，再擦出内容 */
}
.reveal__body > :last-child { margin-bottom: 0; }

/* ── Tabs ─────────────────────────────────
   滑块滑过去，而不是"换个底色"：标签是同一件东西的几个面，
   滑块在说"你还在同一个地方"。换底色则像跳到了另一个页面。 */
.tabs { margin: var(--s-5) 0; }
.tabs__bar {
  position: relative; display: flex; gap: var(--s-2);
  padding-bottom: var(--s-3); margin-bottom: var(--s-2);
}
.tabs__tab {
  position: relative; z-index: 1;
  padding: var(--s-3) var(--s-4); white-space: nowrap; cursor: pointer;
  background: transparent; border: none; border-radius: var(--r-sm);
  color: var(--c-ink-dim); font-size: var(--t-sm); font-weight: 600;
  transition: color var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.tabs__tab:hover { color: var(--c-ink); }
.tabs__tab:active { transform: translateY(1px); }
.tabs__tab.is-active { color: var(--c-on-accent); }
.tabs__tab:focus-visible { outline: 2px solid var(--c-gold); outline-offset: 2px; }
.tabs__indicator {
  position: absolute; z-index: 0; top: 0; left: 0; height: calc(100% - var(--s-3));
  width: var(--ind-w, 0); transform: translateX(var(--ind-x, 0));
  background: var(--c-accent-bg); border-radius: var(--r-sm);
  box-shadow: inset 0 0 0 1px var(--c-line-soft);
  transition: transform var(--dur) var(--ease), width var(--dur) var(--ease);
}
.tabs__panel {
  padding: var(--s-5); background: var(--c-bg-sink); border-radius: var(--r-md);
}
/* 切面板时内容轻微右移淡入，方向与滑块一致，读者的注意力被带着走 */
.tabs__panel.is-active { animation: tab-in var(--dur) var(--ease); }
@keyframes tab-in { from { opacity: 0; transform: translateX(6px); } }

/* ── Callout ────────────────────────────── */
.callout {
  margin: var(--s-5) 0; padding: var(--s-4) var(--s-5);
  background: var(--c-bg-raise); border-radius: var(--r-md);
  border-left: 4px solid var(--accent);
}
.callout--note   { --accent: var(--c-note); }
.callout--warn   { --accent: var(--c-warn); }
.callout--danger { --accent: var(--c-danger); }
.callout__head { display: flex; align-items: center; gap: var(--s-2); margin-bottom: var(--s-3); }
.callout__icon { color: var(--accent); }
.callout__label { font-size: var(--t-xs); font-weight: 700; letter-spacing: .08em; color: var(--accent); }
.callout__body > :last-child { margin-bottom: 0; }

/* ── 动画与示意图 ───────────────────────── */
.anim, .diagram { margin: var(--s-6) 0; }
.anim__stage, .diagram__stage {
  background: var(--c-bg-sink); border-radius: var(--r-lg);
  padding: var(--s-4); display: flex; justify-content: center;
}

/* 书上的插图：不给底、不留内边距，图和正文融在一起 */
.anim--plate .anim__stage { background: none; padding: 0; border-radius: 0; }

/*
 * 窄屏满幅。**这是手机上"字看不清"的一半解法。**
 *
 * 正文栏在手机竖屏只有 361px（393 − 2×16 的页边距），插画再套一层 16px 内边距就只剩 329px。
 * viewBox 1000 宽的画缩到 0.329 倍，一个 30 单位的字落到屏幕上是 9.9px——读不了。
 * 让插画横向挣脱页边距、铺满 393px 之后是 11.8px，能读。
 * 差的这一截不靠"把字调大"换，靠"把画放大"换——调字号会挤坏构图，放大不会。
 *
 * 另一半解法是字号下限（见 @aisi/ui 的 MIN_TEXT，由 tools/check-scene-text.mjs 强制）。
 */
@media (max-width: 743px) {
  .anim { margin-inline: calc(-1 * var(--page-pad)); }
  .anim__stage { padding: 0; border-radius: 0; }
  .anim__caption { padding-inline: var(--page-pad); }
}
/*
 * 宽屏限高。**竖一点的画不许比标准横图高。**
 *
 * 画布不一定是 1000×600：书上插图常裁成近方形（600×500 这类）。width 100% 撑满版心时，
 * 高度跟着比例走——1440 屏上版心 864px，一张 520×540 的画有 897px 高，比可视区还高。
 * 上限 = 同宽下一张 1000×600 横图的高度（60cqw）。超出的部分 SVG 自己按 meet 居中，
 * 两侧露出的是页面的底（无底插图）——相当于把背景往两边加长，画不变小到看不清：
 * 字号按画布折算（docs/PAGE-FORMS.md 2.7.2，tools/check-scene-text.mjs 查上下限）。
 * 有底的图不许裁成比 1000×600 更方的画布（pnpm check:scenes 查），所以有底的图碰不到这条线。
 * 手机（< 744px）不限：满幅才看得清，竖图在手机上本来就该铺满。
 */
@media (min-width: 744px) {
  .anim__stage { container-type: inline-size; }
  .anim__stage > svg { max-height: 60cqw; }
}
.anim__caption, .diagram__caption {
  margin-top: var(--s-3); font-size: var(--t-xs); color: var(--c-ink-faint);
  text-align: start; line-height: 1.6;
}

/*
 * 插画进场：滚到它的时候浮起来。
 *
 * 用**滚动驱动**（animation-timeline: view()），不是 IntersectionObserver：
 * 它跟着滚动条走，往回滚会倒着播，手感是连续的；JS 那套只会"触发一次"。
 * 浏览器不支持就整段失效——图仍然好好地在那儿，没有任何副作用。
 */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .anim__stage, .diagram__stage {
      animation: plate-in linear both;
      animation-timeline: view();
      animation-range: entry 8% entry 46%;
    }
    @keyframes plate-in {
      from { opacity: 0; transform: translateY(18px) scale(.985); }
      to   { opacity: 1; transform: none; }
    }
  }
}

.anim--missing { padding: var(--s-6); text-align: start; color: var(--c-ink-faint);
  background: var(--c-bg-sink); border-radius: var(--r-lg); }

/* 三个结构块（对话 / 步骤 / 对比）的样子在 blocks.css。 */
/*
 * 正文里的块：对话 / 步骤 / 对比，以及截图、流程图、图表、终端、提示词、外链卡片。
 * 组件在 components/ 下。**只许用 --c-* 变量**，不许写十六进制——换画风、换明暗时要一起变。
 *
 * .blk-shell 是"铺在正文里的一片底色"：不画描边框，只给一块比页面略深的底，
 * 宽度和正文栏一样，跟正文融在一起。外壳的气质归画风（蜡笔 / 水彩 / 构序 / 星轨）。
 */

.blk-shell {
  --blk-pad: var(--s-5);
  --blk-shell: color-mix(in srgb, var(--c-ink) 4.5%, var(--c-bg));
  position: relative; isolation: isolate;
  margin: var(--s-7) 0;
  padding: var(--blk-pad);
  border-radius: var(--r-lg);
  background: var(--blk-shell);
}
.blk-shell::before {
  content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none;
  background: var(--blk-motif, none);
}
@media (max-width: 600px) {
  .blk-shell { --blk-pad: var(--s-4); }
}
/* 蜡笔：圆滚滚、不太规整的边，像手帐上用蜡笔涂出来的一块 */
:root[data-style='crayon-book'] .blk-shell {
  --blk-shell: color-mix(in srgb, var(--c-accent-bg) 3%, color-mix(in srgb, var(--c-ink) 4%, var(--c-bg)));
  border-radius: var(--frame-r-lg);
}
/* 水彩：两团淡彩从角上洇开 */
:root[data-style='watercolor'] .blk-shell {
  border-radius: var(--frame-r-lg);
  background:
    radial-gradient(110% 80% at 0% 0%, color-mix(in srgb, var(--c-gold) 10%, transparent), transparent 62%),
    radial-gradient(80% 70% at 100% 100%, color-mix(in srgb, var(--c-mint) 8%, transparent), transparent 60%),
    var(--blk-shell);
}
/* 构序：方角、平涂，左上角一道短短的朱橙色条——杂志版面上的栏头 */
:root[data-style='studio'] .blk-shell {
  border-radius: var(--frame-r-lg);
  background:
    linear-gradient(var(--c-accent-bg), var(--c-accent-bg)) 0 0 / 2.4rem 3px no-repeat,
    var(--blk-shell);
}
/* 星轨：从左上角亮起来的一道冷光 */
:root[data-style='orbit'] .blk-shell {
  background:
    linear-gradient(155deg, color-mix(in srgb, var(--c-accent-bg) 9%, var(--blk-shell)), var(--blk-shell) 58%);
}

/* ═══════════════════════════════════════════════════════════════════════
   三个结构块：对话 / 步骤 / 对比。

   **它们不是"给交互件加过渡"，是自己带内容的块。** 三条共同规矩：
   ① 进场一律**滚动驱动**（animation-timeline: view()）。往回滚会倒着播，
      手感是连续的；IntersectionObserver 那套只会"触发一次"。
   ② **静止态 = 动画的终态**，关键帧只写 `from`。
      这样浏览器不支持滚动时间线时整段失效，内容仍然是排好的、读得了的。
   ③ 位移必须伴随遮罩 / 不透明度 / 形变，且有起因（读到这儿了）和结果（内容状态变了）。
      纯位移是敷衍。
   时长与曲线走 token；`prefers-reduced-motion` 由 tokens.css 全局兜底，
   滚动驱动那几段另外用 @media 关掉（它们不吃 animation-duration）。
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 对话：你说一句，它答一段 ─────────────────────────────────────────
   D0 最常用的块——元技能讲的就是"话该怎么说"。
   这块的内容本身就是**时序**：你先说，它才答，而它的答案是一点点出来的。
   所以动画演的是时序，不是装饰。 */
.dlg { --tone: var(--c-gold); }
.dlg__title {
  margin: 0 0 var(--s-4); font-family: var(--font-display); font-size: var(--t-lg); font-weight: 700; color: var(--c-ink);
}
.dlg__list { list-style: none; margin: 0; padding: 0; }
.dlg__turn { margin-bottom: var(--s-4); }
.dlg__turn:last-child { margin-bottom: 0; }
/* 两个角色各有一个色：你 = 当前焦点色，AI = 全站统一的 AI 色 */
.dlg__turn--you { --tone: var(--c-gold); }
.dlg__turn--ai  { --tone: var(--c-ai); }

.dlg__who {
  display: flex; align-items: center; gap: var(--s-2);
  margin-bottom: var(--s-2); padding-left: 2px;
  font-size: var(--t-base); font-weight: 700; color: var(--tone);
}
/* 头像是一颗点。你 = 实心圆；AI = 一个菱形加一圈很淡的光晕，
   形状上一眼分得开，不靠读那两个字。 */
.dlg__avatar {
  width: 9px; height: 9px; flex: none; background: var(--tone); border-radius: 50%;
}
.dlg__turn--ai .dlg__avatar {
  border-radius: 2px; transform: rotate(45deg);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--tone) 20%, transparent);
}

.dlg__bubble {
  position: relative;
  padding: var(--s-4) var(--s-5);
  border-radius: var(--r-md);
  background: color-mix(in oklab, var(--tone) 8%, var(--c-bg));
}
/* 气泡的尖角：左上角收一口，指回它的头像。比画一个三角干净，
   而且换画风时圆角变了它跟着变。 */
.dlg__turn--you .dlg__bubble { border-top-left-radius: var(--s-1); }
.dlg__turn--ai  .dlg__bubble { border-top-left-radius: var(--s-1); }
/* AI 那条多一道顶线：它是"机器产出"，多这一道就够了，不用画个机器人 */
.dlg__turn--ai .dlg__bubble::after {
  content: ''; position: absolute; inset-inline: var(--s-5); top: 0; height: 2px;
  background: linear-gradient(to right, var(--tone), transparent 70%);
  opacity: .5; border-radius: 2px;
}
.dlg__bubble > .dlg__body > :last-child { margin-bottom: 0; }
.dlg__body > p:first-child { margin-top: 0; }

/* 旁白：不带气泡，居中，两边各一道短线。它是"画外音"，不是第三个人在说话。 */
.dlg__note {
  display: flex; align-items: center; gap: var(--s-4);
  margin: var(--s-5) 0; font-size: var(--t-base); color: var(--c-ink-dim); text-align: start;
}
.dlg__note > p { margin: 0; }
.dlg__note::before, .dlg__note::after {
  content: ''; flex: 1; height: 1px; background: var(--c-line);
}

/* 生成扫描线：沿着 AI 那段自上而下扫一遍，和文字揭开是同一段行程。
   这比"末尾一个闪烁光标"好：光标要贴着最后一个字，而正文是块级的多段内容，
   贴不准；扫描线说的是同一件事，而且贴哪儿都对。 */
.dlg__caret {
  position: absolute; left: 0; right: 0; top: 0; height: 2px; opacity: 0;
  background: linear-gradient(to right, transparent, var(--tone), transparent);
  box-shadow: 0 0 10px color-mix(in srgb, var(--tone) 55%, transparent);
  pointer-events: none;
}
.dlg__turn--ai .dlg__bubble { overflow: hidden; }

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* 每段按 --i 错开落位。用 animation-range 错开而不是 animation-delay——
       滚动时间线上 delay 是没有意义的，行程才是"时间"。 */
    .dlg__turn {
      animation: mo-dlg-in linear both;
      animation-timeline: view();
      animation-range: entry calc(4% + var(--i) * 6%) entry calc(42% + var(--i) * 6%);
    }
    @keyframes mo-dlg-in {
      from { opacity: 0; transform: translateY(16px) scale(.985); }
    }
    /* AI 的正文被一道遮罩自上而下揭开 = 它正在生成。
       正文和扫描线都挂在**气泡**的时间线上，不各自用 view()：扫描线动的是自己的 top，
       拿自己当参照物时，位置一变进度就变、进度一变位置又变——Safari 里停着不动也会一闪一闪 */
    .dlg__turn--ai .dlg__bubble { view-timeline: --dlg-bubble block; }
    .dlg__turn--ai .dlg__body {
      animation: mo-dlg-type linear both;
      animation-timeline: --dlg-bubble;
      animation-range: entry calc(20% + var(--i) * 6%) entry calc(62% + var(--i) * 6%);
    }
    @keyframes mo-dlg-type { from { clip-path: inset(0 0 100% 0); } }
    .dlg__turn--ai .dlg__caret {
      animation: mo-dlg-scan linear both;
      animation-timeline: --dlg-bubble;
      animation-range: entry calc(20% + var(--i) * 6%) entry calc(66% + var(--i) * 6%);
    }
    @keyframes mo-dlg-scan {
      0%   { opacity: 0; top: 0; }
      10%  { opacity: .95; }
      88%  { opacity: .95; }
      100% { opacity: 0; top: 100%; }
    }
  }
}

/* ── 步骤：一条随阅读生长的脊线 ───────────────────────────────────────
   <ol> 表达的是"有几条"，这个块要表达的是"走到第几步了"。
   脊线不是装饰：你滚多少它长多少，流程这件事就变成身体能感觉到的东西。 */
.steps__title {
  margin: 0 0 var(--s-4); font-family: var(--font-display); font-size: var(--t-lg); font-weight: 700; color: var(--c-ink);
}
.steps__list { position: relative; list-style: none; margin: 0; padding: 0; }
.steps__spine {
  position: absolute; left: 15px; top: 16px; bottom: 16px; width: 2px;
  border-radius: 2px; transform-origin: top center;
  background: linear-gradient(var(--c-gold),
              color-mix(in srgb, var(--c-gold) 22%, transparent));
}
.steps__item {
  position: relative; display: grid; grid-template-columns: 32px 1fr;
  gap: 0 var(--s-4); padding-bottom: var(--s-5);
}
.steps__item:last-child { padding-bottom: 0; }
/* 序号：静止态就是"已点亮"。动画只负责把它从灭到亮点一遍——
   不支持滚动时间线的浏览器看到的是一排亮着的序号，那也是对的。 */
.steps__dot {
  grid-row: span 2; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--c-accent-bg); color: var(--c-on-accent);
  border: 2px solid transparent;
  font-family: var(--font-display); font-size: var(--t-base); font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.steps__body { min-width: 0; padding-top: 3px; }
.steps__label { margin: 0 0 var(--s-2); font-size: var(--t-lg); color: var(--c-ink); }
.steps__body > :last-child { margin-bottom: 0; }

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .steps__spine {
      animation: mo-spine-grow linear both;
      animation-timeline: view();
      animation-range: entry 26% cover 68%;
    }
    @keyframes mo-spine-grow { from { transform: scaleY(0); } }
    /* 每个序号在脊线走到它那儿的时候亮起来。
       行程按 --i/--n 均分，所以三步和十步都对。 */
    .steps__dot {
      animation: mo-dot-lit linear both;
      animation-timeline: view();
      animation-range:
        cover calc(12% + (var(--i) / var(--n)) * 52%)
        cover calc(22% + (var(--i) / var(--n)) * 52%);
    }
    @keyframes mo-dot-lit {
      from {
        background: var(--c-bg); color: var(--c-ink-faint);
        border-color: var(--c-line);
        transform: scale(.82);
      }
    }
    .steps__body {
      animation: mo-step-body-in linear both;
      animation-timeline: view();
      animation-range:
        cover calc(12% + (var(--i) / var(--n)) * 52%)
        cover calc(26% + (var(--i) / var(--n)) * 52%);
    }
    @keyframes mo-step-body-in { from { opacity: 0; transform: translateX(10px); } }
  }
}

/* ── 对比：两栏必须同时在场 ───────────────────────────────────────────
   和 tabs 的分工：tabs 是"同一个问题的几种解法"，一次看一种；
   compare 是"这两件事必须摆在一起才看得出差别"，藏起一半这块就废了。
   所以窄屏也不折叠成标签页，只是堆成上下两块。 */
.cmp__grid {
  display: grid; grid-template-columns: 1fr; gap: var(--s-4);
  align-items: stretch;
}
.cmp__side { padding: var(--s-4) 0; }
/* 左栏是"朴素的那个"（次级色 + 虚线），右栏是"要你记住的那个"（焦点色 + 实线）。
   不用红/绿——对比不一定是"错/对"，也可能是"传统/现在"。 */
.cmp__side--a { --tone: var(--c-ink-dim); }
.cmp__side--b { --tone: var(--c-gold); }
.cmp__label {
  margin: 0 0 var(--s-3); padding-bottom: var(--s-2);
  font-family: var(--font-display); font-size: var(--t-lg); font-weight: 700; color: var(--tone);
  border-bottom: 2px dashed color-mix(in srgb, var(--tone) 45%, transparent);
}
.cmp__side--b .cmp__label { border-bottom-style: solid; }
.cmp__body > :last-child { margin-bottom: 0; }
.cmp__body > p:first-child { margin-top: 0; }
/* 两栏各占一半，很长的网址、路径这类行内代码要能在栏里断行，不然会把整页撑宽 */
.cmp__side { min-width: 0; }
.cmp__body code { overflow-wrap: anywhere; }
/* 中缝：窄屏是一道横线，宽屏是一道竖线。它是"对立"的语法，不是分隔符。 */
.cmp__rule {
  align-self: center; justify-self: center;
  width: 100%; height: 2px; border-radius: 2px; transform-origin: center;
  background: linear-gradient(to right, transparent, var(--c-line), transparent);
}
@media (min-width: 744px) {
  .cmp__grid { grid-template-columns: 1fr auto 1fr; gap: var(--s-5); }
  .cmp__rule {
    width: 2px; height: 100%;
    background: linear-gradient(transparent, var(--c-line), transparent);
  }
}
/* 结论行：马克笔扫过去。它是这块的落点，所以它最后到。 */
.cmp__so {
  margin: var(--s-4) 0 0; text-align: start;
  font-family: var(--font-display); font-size: var(--t-lg); font-weight: 700; color: var(--c-ink);
}
.cmp__so-mark {
  padding-inline: .18em;
  background-image: linear-gradient(color-mix(in oklab, var(--c-gold) 28%, transparent) 0 100%);
  background-repeat: no-repeat;
  background-position: 0 86%;
  background-size: 100% .62em;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .cmp__side {
      animation: mo-cmp-in linear both;
      animation-timeline: view();
      animation-range: entry 8% entry 52%;
    }
    /*
      两栏从各自的外侧推进来，带一道由外向内的遮罩——"推开"这件事有方向，纯淡入没有。

      **但那是宽屏才成立的说法。** 窄屏两栏是上下堆着的，"从各自外侧进来"在这里
      既没有意义，还有实际代价：正文在手机竖屏本来就是满幅，右边那栏往右推 18px
      会顶出屏幕右缘（响应式门禁抓到过）。body 的 overflow-x:hidden 只是把它藏住了，
      不是没发生。
      所以堆叠时改成从下方浮起——方向跟着阅读顺序走，一样有方向，且不出界。
    */
    .cmp__side { --from-x: 0px; --from-y: 14px; --from-clip: inset(0 0 16% 0); }
    @media (min-width: 744px) {
      .cmp__side { --from-y: 0px; }
      .cmp__side--a { --from-x: -18px; --from-clip: inset(0 0 0 16%); }
      .cmp__side--b { --from-x:  18px; --from-clip: inset(0 16% 0 0); }
    }
    @keyframes mo-cmp-in {
      from {
        opacity: 0;
        transform: translate(var(--from-x), var(--from-y));
        clip-path: var(--from-clip);
      }
    }
    .cmp__rule {
      animation: mo-rule-draw linear both;
      animation-timeline: view();
      animation-range: entry 14% entry 56%;
    }
    @keyframes mo-rule-draw { from { transform: scale(0); } }
    .cmp__so-mark {
      animation: mo-mark-sweep linear both;
      animation-timeline: view();
      animation-range: entry 48% entry 92%;
    }
    @keyframes mo-mark-sweep { from { background-size: 0% .62em; } }
  }
}



/* ═══════════════════════════════════════════════════════════════════════
   截图、流程图、图表、终端、提示词、外链卡片、互动组件
   这些块装的是"真东西"：真实截图、真跑过的命令、能直接复制的话。
   所以它们的样子都朝"你在自己电脑上会看到的那个画面"去做，不做装饰。
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 复制按钮（提示词、终端共用） ───────────────────────────────────── */
.copy-btn {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  padding: 4px 10px; border: 0; border-radius: var(--r-sm); cursor: pointer;
  background: color-mix(in srgb, var(--c-ink) 8%, transparent); color: var(--c-ink-dim);
  font-size: var(--t-xs); font-weight: 600; white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.copy-btn:hover { background: color-mix(in srgb, var(--c-ink) 14%, transparent); color: var(--c-ink); }
.copy-btn[data-done] { color: var(--c-mint); }
.copy-btn:focus-visible { outline: 2px solid var(--c-gold); outline-offset: 2px; }

/* ── 图片 ─────────────────────────────────────────────────────────── */
.fig { margin: var(--s-6) 0; }
.fig__frame { margin-inline: auto; border-radius: var(--r-md); overflow: hidden; }
.fig__zoom { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: zoom-in; }
.fig__zoom img, .fig__svg svg { display: block; width: 100%; height: auto; }
.fig:not(.fig--browser):not(.fig--window):not(.fig--vector) .fig__frame {
  box-shadow: 0 0 0 1px var(--c-line-soft);
}
/* 浏览器 / 应用窗口外框：一条标题栏，三个圆点，地址栏写着这张图来自哪里 */
.fig--browser .fig__frame, .fig--window .fig__frame {
  background: var(--c-bg-raise); box-shadow: 0 0 0 1px var(--c-line), var(--shadow-sm);
}
.fig__chrome {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 8px var(--s-3); background: var(--c-bg-sink); border-bottom: 1px solid var(--c-line-soft);
}
.fig__dots, .term__dots { display: inline-flex; gap: 6px; flex: none; }
.fig__dots i, .term__dots i { width: 10px; height: 10px; border-radius: 50%; background: var(--c-line); }
.fig__url {
  flex: 1; min-width: 0; padding: 3px 12px; border-radius: 999px;
  background: var(--c-bg); color: var(--c-ink-dim); font-size: var(--t-xs); font-family: var(--font-mono);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fig--vector .fig__frame { overflow: visible; }
.fig__caption, .mmd__caption, .chart__caption, .term__caption, .widget__caption {
  margin-top: var(--s-3); font-size: var(--t-sm); color: var(--c-ink-faint); line-height: 1.65;
}
.fig__credit { display: inline-block; margin-left: .6em; color: var(--c-ink-faint); }
.fig__credit a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
/* 讲解短片：和截图同宽，圆角、下沉色的底；视频比例由文件本身决定 */
.vid { margin: var(--s-6) 0; }
.vid__frame { border-radius: var(--r-md); overflow: hidden; background: var(--c-bg-sink); }
.vid__frame video { display: block; width: 100%; height: auto; }
.fig__lightbox {
  max-width: min(96vw, 1600px); max-height: 94vh; padding: 0; border: 0; border-radius: var(--r-md);
  background: var(--c-bg); cursor: zoom-out; overflow: auto;
}
.fig__lightbox::backdrop { background: color-mix(in srgb, var(--c-bg-sink) 82%, transparent); backdrop-filter: blur(4px); }
.fig__lightbox img { display: block; max-width: 100%; height: auto; }
.fig__lightbox { width: min(94vw, 1400px); max-height: 92dvh; cursor: default; color: var(--c-ink); border: 1px solid var(--c-line); }
.fig__lightbox-tools { display: flex; align-items: center; gap: 12px; padding: 12px 16px; border-bottom: 1px solid var(--c-line); background: var(--c-bg-raise); }
.fig__lightbox-tools > span { flex: 1; min-width: 0; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fig__lightbox-tools button { flex: none; min-height: 40px; padding: 6px 12px; border: 1px solid var(--c-line); border-radius: var(--r-sm); background: var(--c-glass); color: var(--c-ink); cursor: pointer; font-size: 12px; }
.fig__lightbox-tools button:hover { background: var(--c-glass-hover); }
.fig__lightbox-tools .fig__close { font-size: 22px; min-width: 40px; padding: 0; }
.fig__lightbox-image { overflow: auto; max-height: calc(92dvh - 70px); overscroll-behavior: contain; padding: 8px; }
.fig__lightbox-image img { max-height: calc(92dvh - 86px); width: auto; max-width: 100%; object-fit: contain; margin-inline: auto; }
.fig__lightbox[data-zoomed='true'] .fig__lightbox-image img { max-width: none; max-height: none; }
.copy-btn { min-height: 36px; }
.copy-btn[data-failed] { color: var(--c-coral); }

/* ── Mermaid 图 / ECharts 图表 / 互动组件：铺在正文里的一块底 ──────────── */
.mmd, .chart, .widget { margin: var(--s-6) 0; }
.mmd__stage, .chart__stage, .widget__stage {
  position: relative; padding: var(--s-5) var(--s-4);
  background: color-mix(in srgb, var(--c-ink) 3.5%, var(--c-bg)); border-radius: var(--r-lg);
}
.mmd__svg { display: flex; justify-content: center; }
.mmd__svg svg { max-width: 100%; height: auto; }
/* Mermaid 兜底画的图：节点字和正文一样大，连线字小一号；窄屏整张等比缩小（上一条 max-width） */
.mmd__svg .nodeLabel, .mmd__svg .label { font-size: var(--t-base); }
.mmd__svg .edgeLabel { font-size: var(--t-sm); }
.mmd__loading, .chart__loading {
  position: absolute; inset: 0; display: grid; place-items: center; margin: 0;
  color: var(--c-ink-faint); font-size: var(--t-sm); white-space: nowrap;
}
.mmd[data-state='loading'] .mmd__stage { min-height: 180px; }
.mmd__error { margin: 0; font-size: var(--t-xs); color: var(--c-coral); white-space: pre-wrap; }
.chart__stage { padding: var(--s-4) var(--s-2); }
.chart__canvas { width: 100%; }
@media (max-width: 743px) {
  .mmd__stage, .chart__stage, .widget__stage { margin-inline: calc(-1 * var(--page-pad)); border-radius: 0; }
  .mmd__caption, .chart__caption, .widget__caption { padding-inline: 0; }
}

/* ── 终端 ─────────────────────────────────────────────────────────── */
.term {
  margin: var(--s-5) 0; border-radius: var(--r-md); overflow: hidden;
  background: var(--c-code-bg); color: var(--c-code-fg); border: 1px solid var(--c-code-line);
}
.term__bar {
  display: flex; align-items: center; gap: var(--s-3); padding: 7px var(--s-3);
  background: var(--c-code-bar); border-bottom: 1px solid var(--c-code-line);
}
.term__dots i { background: var(--c-code-gutter); }
.term__title {
  flex: 1; min-width: 0; font-size: var(--t-xs); font-family: var(--font-mono); color: var(--c-code-gutter);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.term .copy-btn { background: var(--c-code-tag); color: var(--c-code-tag-fg); }
.term .copy-btn[data-done] { color: var(--c-mint); }
.term__caption { margin: 0; padding: var(--s-3) var(--s-4); background: var(--c-code-note); border-top: 1px solid var(--c-code-line); color: var(--c-ink-dim); }
.term__pre { margin: 0; padding: var(--s-3) var(--s-4); font: var(--t-code)/1.7 var(--font-mono); min-width: max-content; }
.term__pre > span { display: block; white-space: pre; }
.term__cmd { font-weight: 700; }
.term__ps { color: var(--c-mint); user-select: none; }
.term__out { opacity: .78; }
.term__note {
  /* 注释行（@note、@args）：等宽、shell 注释色，和真终端里的 # 注释一样；
     整句不跟着长命令横向溢出，卡在终端可见的那一块里换行，横向滚动时贴着左边不动 */
  white-space: pre-wrap !important; overflow-wrap: anywhere;
  box-sizing: border-box; max-width: calc(100cqw - 2 * var(--s-4)); position: sticky; left: var(--s-4);
}
.term__body { container-type: inline-size; }

/* ── 术语（[[词]]，PAGE-FORMS.md 2.13）：虚线下划线的词，点开一张小卡片 ── */
.term-word {
  font: inherit; color: inherit; background: none; border: 0; padding: 0; margin: 0; cursor: help;
  text-decoration: underline dotted color-mix(in srgb, currentColor 55%, transparent);
  text-decoration-thickness: 1.5px; text-underline-offset: .22em;
}
.term-word:hover, .term-word[aria-expanded='true'] { color: var(--c-gold); text-decoration-color: currentColor; }
.term-word:focus-visible { outline: 2px solid var(--c-gold); outline-offset: 2px; border-radius: 2px; }
.term-card {
  position: fixed; z-index: 80; box-sizing: border-box; width: min(340px, calc(100vw - 24px));
  padding: var(--s-3) var(--s-4); border-radius: var(--r-md);
  background: var(--c-bg-raise); color: var(--c-ink); border: 1px solid var(--c-line);
  box-shadow: var(--shadow-md); font-size: var(--t-sm); line-height: 1.65;
  animation: term-card-in var(--dur) var(--ease);
}
.term-card__name { display: block; font-family: var(--font-display); font-weight: 700; font-size: var(--t-base); color: var(--c-ink); margin-bottom: 4px; }
.term-card__def { margin: 0; color: var(--c-ink-dim); }
.term-card__more { display: inline-block; margin-top: var(--s-2); font-size: var(--t-xs); }
@keyframes term-card-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .term-card { animation: none; } }

/* ── 提示词卡片 ───────────────────────────────────────────────────── */
.prompt {
  margin: var(--s-5) 0; border-radius: var(--r-md); overflow: hidden;
  background: color-mix(in srgb, var(--c-violet) 7%, var(--c-bg));
  box-shadow: inset 3px 0 0 var(--c-violet);
}
.prompt__bar { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-3) var(--s-4) 0; }
.prompt__tag {
  flex: none; padding: 2px 8px; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--c-violet) 16%, transparent); color: var(--c-violet);
  font-size: var(--t-xs); font-weight: 700; letter-spacing: .04em; white-space: nowrap;
}
.prompt__title { flex: 1; min-width: 0; font-size: var(--t-sm); font-weight: 600; color: var(--c-ink); }
.prompt__copy { margin-left: auto; }
.prompt__body {
  padding: var(--s-3) var(--s-4) var(--s-4); white-space: pre-wrap; word-break: break-word;
  font-size: var(--t-base); line-height: 1.75; color: var(--c-ink);
}
.prompt__slot {
  padding: 0 2px; border-radius: 3px; color: inherit;
  background: color-mix(in srgb, var(--c-amber) 26%, transparent);
}
.prompt__hint { margin: 0; padding: 0 var(--s-4) var(--s-3); font-size: var(--t-xs); color: var(--c-ink-faint); }

/* ── 外链卡片 ─────────────────────────────────────────────────────── */
.links { margin: var(--s-5) 0; }
.links__title { margin: 0 0 var(--s-3); font-weight: 700; color: var(--c-ink); }
.links__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-3); grid-template-columns: 1fr; }
@media (min-width: 744px) { .links__list { grid-template-columns: 1fr 1fr; } }
.links__card {
  position: relative; display: grid; gap: 2px; height: 100%;
  padding: var(--s-3) var(--s-6) var(--s-3) var(--s-4); border-radius: var(--r-md);
  background: color-mix(in srgb, var(--c-ink) 4%, var(--c-bg)); color: inherit; text-decoration: none;
  transition: background var(--dur-fast) var(--ease);
}
.links__card:hover { background: color-mix(in srgb, var(--c-ink) 8%, var(--c-bg)); }
.links__card:focus-visible { outline: 2px solid var(--c-gold); outline-offset: 2px; }
.links__host { font-size: var(--t-xs); font-family: var(--font-mono); color: var(--c-ink-faint); }
.links__name { font-weight: 700; color: var(--c-gold); line-height: 1.45; }
.links__desc { font-size: var(--t-sm); color: var(--c-ink-dim); line-height: 1.55; }
.links__go { position: absolute; top: var(--s-3); right: var(--s-3); color: var(--c-ink-faint); }


/* ═══════════════════════════════════════════════════════════════════════
   画风外框（铁律，见 docs/SYSTEM.md 第八节）

   正文里的每一种块——代码、终端、截图、录屏、流程图、图表、表格、提示框、
   提示词、点开看、标签页、外链卡片、引用、插画舞台、互动组件——外框都挂
   .blk-frame，由这里按四种画风各画一套。只换颜色不换形状，四种画风看起来就是
   "同一个网站换了主题色"；形状跟着画法走，页面才像另一套东西。

   仍守两层法则：这是**内容层**，是纸——底色 + 至多一道发丝线，不投影、不描粗边。
   每套画风只动三样：
     ① 形状   --frame-r（圆角的样子）
     ② 画材   ::before 铺在底色之上、内容之下的一层（洇开的淡彩 / 冷光）
     ③ 标记   ::after 一个小记号（构序的栏头色条）；.blk-frame--quiet 不要它
   外加两处画风自己的小零件：窗口三颗圆点、表格表头。

   新加一种块：外框挂 .blk-frame，这里不用改；pnpm check:css 会查。
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  --frame-r: var(--r-md);
  --frame-r-lg: var(--r-lg);
}
/* 蜡笔：手涂出来的块，四个角圆得不一样 */
:root[data-style='crayon-book'] {
  --frame-r: 20px 13px 18px 11px / 13px 20px 11px 18px;
  --frame-r-lg: 30px 22px 28px 20px / 22px 30px 20px 28px;
}
/* 水彩：规整的小圆角，气质交给洇开的颜色 */
:root[data-style='watercolor'] { --frame-r: var(--r-md); --frame-r-lg: var(--r-md); }
/* 构序：几乎直角，杂志版面 */
:root[data-style='studio'] { --frame-r: var(--r-sm); --frame-r-lg: var(--r-sm); }
/* 星轨：精密仪器的圆角 */
:root[data-style='orbit'] { --frame-r: var(--r-md); --frame-r-lg: var(--r-lg); }

/* :root 前缀把优先级抬到组件自己的 border-radius 之上 */
:root .blk-frame {
  position: relative; isolation: isolate;
  border-radius: var(--frame-r);
}
.blk-frame::before, .blk-frame::after {
  content: none; position: absolute; pointer-events: none;
}
.blk-frame::before { inset: 0; z-index: -1; border-radius: inherit; }

/* ① 蜡笔：暖色的一层蜡——强调色兑进一点点，像蜡笔在纸上蹭过 */
:root[data-style='crayon-book'] .blk-frame::before {
  content: '';
  background: linear-gradient(170deg, color-mix(in srgb, var(--c-accent-bg) 5%, transparent), transparent 55%);
}
/* ② 水彩：两团淡彩从对角洇开 */
:root[data-style='watercolor'] .blk-frame::before {
  content: '';
  background:
    radial-gradient(90% 70% at 0% 0%, color-mix(in srgb, var(--c-gold) 9%, transparent), transparent 65%),
    radial-gradient(70% 60% at 100% 100%, color-mix(in srgb, var(--c-mint) 7%, transparent), transparent 62%);
}
/* ③ 构序：一道发丝线框住，左上角一截朱橙色条——栏头 */
:root[data-style='studio'] .blk-frame::before {
  content: ''; box-shadow: inset 0 0 0 1px var(--c-line-soft);
}
:root[data-style='studio'] .blk-frame:not(.blk-frame--quiet)::after {
  content: ''; left: 0; top: 0; z-index: 2; width: 2.4rem; height: 3px;
  background: var(--c-accent-bg);
}
/* ④ 星轨：左上角亮起一道冷光，边上一圈极淡的强调色发丝线 */
:root[data-style='orbit'] .blk-frame::before {
  content: '';
  background: linear-gradient(155deg, color-mix(in srgb, var(--c-accent-bg) 10%, transparent), transparent 55%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-accent-bg) 22%, transparent);
}

/* ── 窗口的三颗圆点（终端、浏览器外框、应用窗口外框） ─────────────── */
:root[data-style='crayon-book'] :is(.term__dots, .fig__dots) i { border-radius: 50% 42% 55% 46%; }
:root[data-style='crayon-book'] :is(.term__dots, .fig__dots) i:nth-child(1) { background: var(--c-coral); }
:root[data-style='crayon-book'] :is(.term__dots, .fig__dots) i:nth-child(2) { background: var(--c-amber); }
:root[data-style='crayon-book'] :is(.term__dots, .fig__dots) i:nth-child(3) { background: var(--c-mint); }
:root[data-style='watercolor'] :is(.term__dots, .fig__dots) i:nth-child(1) { background: color-mix(in srgb, var(--c-coral) 55%, transparent); }
:root[data-style='watercolor'] :is(.term__dots, .fig__dots) i:nth-child(2) { background: color-mix(in srgb, var(--c-amber) 55%, transparent); }
:root[data-style='watercolor'] :is(.term__dots, .fig__dots) i:nth-child(3) { background: color-mix(in srgb, var(--c-mint) 55%, transparent); }
:root[data-style='studio'] :is(.term__dots, .fig__dots) i { width: 9px; height: 9px; border-radius: 0; }
:root[data-style='studio'] :is(.term__dots, .fig__dots) i:nth-child(1) { background: var(--c-accent-bg); }
:root[data-style='orbit'] :is(.term__dots, .fig__dots) i {
  background: transparent; box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--c-mint) 75%, transparent);
}

/* ── 表格：外框走 .blk-frame，表头各有各的写法 ──────────────────────── */
.kp-table-wrap { margin: var(--s-5) 0; background: color-mix(in srgb, var(--c-ink) 2.5%, var(--c-bg)); }
.kp-table-wrap .kp-table { margin: 0; }
/* 蜡笔：表头是一道蜡笔涂过的色块 */
:root[data-style='crayon-book'] .kp-table thead th {
  background: color-mix(in srgb, var(--c-accent-bg) 10%, var(--c-bg-raise));
}
/* 水彩：表头不涂底，只在下面洇一道淡彩线 */
:root[data-style='watercolor'] .kp-table thead th {
  background: none; box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--c-gold) 30%, transparent);
}
/* 构序：杂志表格——表头无底、墨色字，下面一道实线 */
:root[data-style='studio'] .kp-table thead th {
  background: none; color: var(--c-ink); box-shadow: inset 0 -2px 0 var(--c-ink);
  letter-spacing: .02em;
}
/* 星轨：表头一层冷光 */
:root[data-style='orbit'] .kp-table thead th {
  background: linear-gradient(180deg, color-mix(in srgb, var(--c-accent-bg) 14%, transparent), transparent);
}

/* ── 终端：上过色的输出不再压暗 ──────────────────────────────────── */
.term__out.is-lit { opacity: 1; }

/* ── 流程图的线：构序细而准，蜡笔粗一点（蜡笔还有手绘线条，见 MermaidBlock） ── */
:root[data-style='studio'] .mmd__svg :is(.flowchart-link, .edgePath .path, .messageLine0, .messageLine1) { stroke-width: 1px; }
:root[data-style='crayon-book'] .mmd__svg :is(.flowchart-link, .edgePath .path) { stroke-width: 1.8px; }

/* 手机上流程图、图表、互动组件铺满屏宽：不要圆角，也不要构序的栏头 */
@media (max-width: 743px) {
  :root :is(.mmd__stage, .chart__stage, .widget__stage).blk-frame { border-radius: 0; }
}

/* 代码块、终端自己有一道发丝线：构序、星轨不再叠第二道，星轨改让那道线带一点冷光 */
:root[data-style='studio'] :is(.term, .code).blk-frame::before { box-shadow: none; }
:root[data-style='orbit'] :is(.term, .code).blk-frame::before { box-shadow: none; }
:root[data-style='orbit'] :is(.term, .code).blk-frame { border-color: color-mix(in srgb, var(--c-accent-bg) 26%, transparent); }

.media-error { padding: var(--s-4); color: var(--c-ink-dim); font-size: var(--t-sm); }
.media-frame { position: relative; }
.media-frame[data-pending] { min-height: 200px; background: var(--c-bg-raise); }
.media-frame[data-pending][style*="aspect-ratio"] { min-height: 0; }
.chart__stage { position: relative; }
.chart__stage > .media-state { position: absolute; inset: 0; background: var(--c-bg-raise); }
.media-frame[data-pending] > .fig__zoom img { opacity: 0; }
.media-frame > .media-state { position: absolute; inset: 0; overflow: auto; background: var(--c-bg-raise); }
.media-state { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; padding: 16px; color: var(--c-ink-dim); box-sizing: border-box; font-size: var(--t-sm); }
.media-state > .status-artwork { width: min(180px, 50%); flex: 0 1 auto; min-height: 0; }
.media-state p { margin: 0; }
.media-state button { flex-shrink: 0; }
.media-state details { width: 100%; }
.media-error p { margin: 0 0 var(--s-3); }
.media-error details { margin-top: var(--s-3); }
.media-error summary { cursor: pointer; }
.fig__zoom:disabled { cursor: default; }

/* 「代码」开关关掉时（文章页顶上，apps/web 的 ReadingTools）：代码块和终端整块不显示；text、markdown 文字块和 keep="true" 的块照常 */
.is-codeless :is(.term, .code:not(.code--prose)):not(.is-keep) { display: none; }
/*
 * 设计 token。
 *
 * ── 颜色不在这里 ──────────────────────────────────────────────────────
 * 颜色由**当前画风**给（`@aisi/ui` 的 `applyTheme()` 把一张 `--p-*` 变量表挂到 `<html>` 上）。
 * 本文件只负责给这些变量起页面侧的语义名，并带一份兜底值——
 * 兜底只在"画风还没挂上来"的那一瞬间生效（首屏），不是第二套配色。
 *
 * 所以：**组件里不许出现十六进制色值，也不许出现 `--p-*`**，只许用 `--c-*`。
 * 这样换画风时页面和插画是一起变的，不会出现"画换了、按钮还是老颜色"。
 */
:root {
  --c-data: var(--p-text-data);
  --c-live: var(--p-text-live);
  --c-violet-ink: var(--p-text-violet);
  /* ── 底与纸 ───────────────────────────── */
  --c-bg:        var(--p-ground, #05080b);
  --c-bg-raise:  var(--p-wall,   #0b1116);
  --c-bg-sink:   var(--p-night,  #03060a);
  --c-ink:       var(--p-text,   #d7e6e4);
  --c-ink-dim:   var(--p-text-mute, #6d8a8b);
  /* 第三档字色。原来是 `--c-ink-dim 58% + 底色` —— 亮档算出来大约 #9a9ea2 压在
     #fbfaf7 上，对比度 2.8:1，**连 WCAG 的大字下限 3:1 都不到**。
     目录页的元信息、时长、主题计数全在这一档上，所以整页的小字都像蒙了一层。
     提到 82%：亮档约 4.9:1、暗档约 6.4:1，两档都过正文的 4.5:1。
     它仍然比 --c-ink-dim 弱一档，层级没有丢，只是不再糊。 */
  --c-ink-faint: color-mix(in srgb, var(--c-ink-dim) 82%, var(--c-bg));
  --c-line:      color-mix(in srgb, var(--c-ink) 14%, transparent);
  /* 页面上绝大多数"线"用这一档。**不许再写十六进制的深色描边**——
     写死的深色在暗色档看着像分隔线，到亮色档就是一条黑杠。 */
  --c-line-soft: color-mix(in srgb, var(--c-ink) 7%, transparent);

  /* ── 毛玻璃：顶栏 / 下拉 / 浮层 ───────────
     三层叠起来才像玻璃：半透的底、一道极淡的边、顶边一条高光。
     只有"半透 + blur"的话是蒙了层雾，不是玻璃。 */
  --c-glass:        color-mix(in srgb, var(--c-bg) 55%, transparent);
  --c-glass-tint:   color-mix(in srgb, var(--c-bg-raise) 50%, transparent);
  --c-glass-line:   color-mix(in srgb, var(--c-ink) 14%, transparent);
  --c-glass-sheen:  color-mix(in srgb, var(--c-ink) 10%, transparent);
  --c-glass-shadow: rgba(0, 0, 0, .4);
  --c-glass-hover:  color-mix(in srgb, var(--c-ink) 8%, transparent);
  --glass-blur: 18px;
  /* 外壳玻璃（顶栏、文章页顶栏下的位置条）：两条贴在一起，必须是**同一块**玻璃——同一个底、同一个模糊。
     磨砂到底下的字认不出、但看得出那里有一行行字在滚过；上面的按钮和字仍是主角。
     不能是实底，也不能糊成一片看不出有字。 */
  --c-chrome-glass: color-mix(in srgb, var(--c-bg) 45%, transparent);
  --chrome-blur: 7px;

  /* ── 代码块 ───────────────────────────────
     词元色是同步阶段 Shiki 分好的，底色必须跟着词元色的明度关系走，
     所以这一组由 themeVars() 按亮暗算，这里只留暗色兜底。 */
  --c-code-bg:     #121212;
  --c-code-fg:     #dbd7ca;
  --c-code-bar:    #1a1a1a;
  --c-code-line:   rgba(255, 255, 255, .08);
  --c-code-gutter: rgba(255, 255, 255, .28);
  --c-code-note:   #171717;
  --c-code-hot:    #2a1f25;
  --c-code-tag:    rgba(201, 144, 118, .18);
  --c-code-tag-fg: #c99076;

  /* ── 强调：**和插画里的强调色是同一个色** ── */
  --c-gold:      var(--p-text-accent, #2ff3c8);   /* 当前焦点、重点词 */
  --c-mint:      var(--p-text-good,   #34e0a1);   /* 次强调、对照 */
  --c-coral:     var(--p-text-alert,  #ff4d5e);   /* 选中态、警示 */
  --c-violet:    var(--p-violet,      #9d7bff);   /* AI 相关 */
  --c-amber:     var(--p-text-live,   #f0a040);   /* 黄灯：注意、等待（和 gold 分开——有的画风里 gold 是红的） */
  /* 当色当底 / 当字是两个值：当底用饱和原色，当字要先过对比度 */
  --c-accent-bg: var(--p-accent,     #2ff3c8);
  --c-on-accent: var(--p-on-accent,  #04120f);
  --c-accent-soft: color-mix(in srgb, var(--c-gold) 13%, var(--c-bg-raise));
  --c-on-accent-soft: var(--c-ink);
  --c-good-bg:   var(--p-good,       #34e0a1);
  --c-on-good:   var(--p-on-good,    #04120f);

  /* ── 语义 ─────────────────────────────── */
  --c-note:   var(--c-mint);
  --c-warn:   var(--c-gold);
  --c-danger: var(--c-coral);
  --c-ai:     var(--c-violet);
  --c-free:   var(--c-mint);
  --c-locked: var(--c-ink-faint);

  /* ── 投影：**形状也归画风管** ──────────────
     画风决定的是"投影长什么样"（硬位移 / 柔和 / 辉光 / 描边），
     页面这三档只是把同一套语言用到 DOM 上，插画和卡片才是一个世界的东西。 */
  /* 三档投影的**形态**由画风给（硬位移 / 柔和 / 辉光 / 套印 / 无），
     这里只留兜底值，供画风还没挂上来的那一瞬间用。 */
  --shadow-color: rgba(0, 0, 0, .55);
  --shadow-lg: 0 10px 20px var(--shadow-color);
  --shadow-md: 0 7px 14px var(--shadow-color);
  --shadow-sm: 0 4px 9px var(--shadow-color);
  /* 描边：粗野/硬边的画风用实色粗线，柔和的画风用一道淡线 */
  --c-border-w: 1px;
  --c-border: var(--c-line);

  /* ── 字号阶梯（移动优先）──────────────────
     这里是**手机竖屏**的值，往上逐档放大（见文件末尾的断点块）。
     定这套值的依据只有一条：**中文正文每行 20–24 个字**。
     少于 18 字一行读着碎，多于 26 字一行眼睛会跳行。
     手机竖屏内容宽 = 393 − 2×16 = 361px，除以 22 ≈ 16.4px → --t-base 就取 16.5px。

     踩过的坑：原来整套阶梯写死不随断点变，只有 --t-base 动了一点点，
     结果 h1 在手机上 40px、h2 31px、代码 15px 等宽——标题占满两行、代码行行被切。 */
  --t-xs:   0.75rem;      /* 12px  角标、版本号 */
  --t-sm:   0.875rem;     /* 14px  表格、图注、次要信息 */
  --t-code: 0.8125rem;    /* 13px  代码。等宽字比正文显小，要单独一档 */
  --t-base: 1.03125rem;   /* 16.5px 正文 */
  --t-lg:   1.125rem;     /* 18px  引文、重点段 */
  --t-xl:   1.3125rem;    /* 21px  h3 */
  --t-2xl:  1.4375rem;    /* 23px  h2 */
  --t-3xl:  1.75rem;      /* 28px  h1 */
  --lh-tight: 1.3;
  --lh-body:  1.75;

  /* ── 间距节奏（4 的倍数） ──────────────── */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 32px; --s-7: 48px; --s-8: 64px; --s-9: 96px;

  /* 圆角也归画风管：木刻线稿是方角，蜡笔浮雕是大圆角。兜底值在这里。 */
  --r-sm: 6px; --r-md: 12px; --r-lg: 20px; --r-xl: 30px;

  /* ── 版心 ─────────────────────────────── */
  --measure: 42rem;       /* 正文最佳阅读宽度 */
  --page-pad: var(--s-4);

  --ease: cubic-bezier(.22,.61,.36,1);
  --dur-fast: 140ms; --dur: 260ms; --dur-slow: 520ms;

  /* 字体也归画风管：水墨那套是宋楷，终端那套是等宽，软陶那套是圆体。
     画里的字和页面上的字必须是同一套，否则画风只换了一半。 */
  --font-body:    var(--p-font-body, 'PingFang SC','Noto Sans SC',system-ui,sans-serif);
  --font-display: var(--p-font-display, var(--font-body));
  --font-mono:    var(--p-font-mono, 'SF Mono', ui-monospace, Menlo, monospace);
}

/* ── 六档：字号与留白一起走 ────────────────────────────────────
   每一档都要保证"每行 20–24 个汉字"。屏幕越宽，版心（--measure）先放宽，
   放到 70ch 就不再放了——再宽就该靠留白和侧边目录，不是靠把字撑大。 */

/* 手机横屏起：宽度够了，字可以稍微大一点 */
@media (min-width: 431px) {
  :root {
    --page-pad: var(--s-5);
    --t-base: 1.0625rem;  /* 17px */
    --t-2xl: 1.5625rem;   /* 25px */
    --t-3xl: 1.9375rem;   /* 31px */
  }
}
/* 平板竖屏 */
@media (min-width: 744px) {
  :root {
    --page-pad: var(--s-6);
    --t-sm: 0.9375rem; --t-code: 0.875rem;
    --t-base: 1.09375rem; /* 17.5px */
    --t-lg: 1.1875rem;
    --t-xl: 1.4375rem; --t-2xl: 1.75rem; --t-3xl: 2.25rem;
  }
}
/* 平板横屏：右侧页内目录开始出现（见 app.css），版心不再吃满 */
@media (min-width: 1024px) { :root { --page-pad: var(--s-6); --measure: 40rem; } }
/* 电脑 1440 */
@media (min-width: 1280px) {
  :root {
    --page-pad: var(--s-7); --measure: 42rem;
    --t-base: 1.125rem;   /* 18px */
    --t-lg: 1.25rem; --t-xl: 1.5rem; --t-2xl: 1.875rem; --t-3xl: 2.5rem;
  }
}
/* 电脑 1920：只放留白与版心，字号到此为止 */
@media (min-width: 1728px) { :root { --page-pad: var(--s-8); --measure: 44rem; } }

/* 有人会晕：尊重系统的"减少动效" */
@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast: 1ms; --dur: 1ms; --dur-slow: 1ms; }
  *, *::before, *::after { animation-duration: 1ms !important; transition-duration: 1ms !important; }
}
/* ═══════════════════════════════════════════════════════════════════════
   页面外壳。
   **本文件里不许出现十六进制色值。** 一处写死，亮色档就多一块不跟着翻的东西——
   原来顶栏那条 `border-bottom: 1px solid #1a252b` 就是这么来的：
   暗色档看着像分隔线，亮色档是一道黑杠横在纸上。
   要线用 --c-line / --c-line-soft，要玻璃用 --c-glass-*，都跟着画风和亮暗走。
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 外壳的两个尺寸 ────────────────────────────────────────────────────
   顶栏高度和侧栏宽度在这里定义一次。JS（lib/pagenav.tsx）读的也是 --topbar-h，
   不另存一份——手机横屏那档顶栏会变矮，两边各写一个 60 迟早会对不上。 */
:root {
  --topbar-h: 60px;
  --sidenav-w: 16rem;
  /* 外壳（顶栏 + 侧栏）贴边留多少。
     **顶栏左上角那组和侧栏里的目录必须对齐**，所以它们只能读同一个值。
     原来顶栏走 .page（1600 居中 + --page-pad），侧栏走自己的 --s-4：
     1920 上一个从 224 起，一个从 16 起，中间空了一大条。 */
  --chrome-pad: var(--s-5);
}

/* 正文让出的宽度。默认 0：窄屏侧栏是盖上去的抽屉，正文一像素都不让。
   ≥1024（平板横屏起）才推开——在 700px 的屏上把正文再推窄 256px 等于把正文挤死。 */
.app { --nav-w: 0px; }
@media (min-width: 1024px) {
  .app[data-nav='open'] { --nav-w: var(--sidenav-w); }
}
/*
  内容跟着侧栏动。用 padding 而不是 margin/transform：
  .page 自己是 `max-width:1600px; margin:0 auto`，padding 把可用宽度改小之后
  它会**重新居中**，正文因此是"在剩下的地方居中"，而不是"整体被推走一截"。
  这正是要的效果：开关侧栏时版面重新排，不是平移。
*/
.app__main {
  padding-inline-start: var(--nav-w);
  transition: padding-inline-start var(--dur) var(--ease);
}

/* ── 顶栏：一块浮在内容上的玻璃 ─────────────────────────────────────────
   玻璃不需要底边线。底下的内容从玻璃后面透上来、在边缘被裁断，
   这个裁断本身就是分界；再压一条深色实线，等于在玻璃下面垫了块木板。
   三层叠起来才像玻璃：
     ① 半透的环境色（内容透上来）
     ② backdrop-filter 的模糊 + 提饱和（透上来的东西要糊，但不能糊到发灰）
     ③ 顶边一道高光 + 底边一道极淡的厚度线（玻璃的棱）
   ────────────────────────────────────────────────────────────────────── */
.topbar {
  position: sticky; top: 0; z-index: 30;
  background: var(--c-chrome-glass);
  -webkit-backdrop-filter: blur(var(--chrome-blur)) saturate(1.6);
  backdrop-filter: blur(var(--chrome-blur)) saturate(1.6);
}
/* 厚度线和高光用伪元素，不用 border：border 会参与布局高度，
   而且没法同时画"顶边亮一道、底边淡一道"。 */
.topbar::after {
  content: ''; position: absolute; inset-inline: 0; bottom: 0; height: 1px;
  background: linear-gradient(to right, transparent, var(--c-glass-line) 12%,
                              var(--c-glass-line) 88%, transparent);
  pointer-events: none;
}
/* 不支持 backdrop-filter 的浏览器：玻璃不成立，就给一个实底，别让字压在内容上 */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .topbar { background: var(--c-bg); }
}

.topbar__inner { display: flex; align-items: center; justify-content: space-between;
  height: var(--topbar-h); gap: var(--s-4); }
/* 顶栏是**外壳**，不是内容：它贴着窗口两边走，不跟正文一起被 1600 夹住居中。
   .topbar__inner 上还挂着 .page（为了拿 box-sizing 和基础样式），
   这里把 .page 的宽度约束撤掉，只留下内边距，并换成外壳自己那一档。 */
.topbar .topbar__inner.page { max-width: none; padding-inline: var(--chrome-pad); }

.topbar__left { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
.topbar__brand { display: inline-flex; align-items: center; gap: var(--s-3);
  font-family: var(--font-display); font-weight: 800; color: var(--c-ink);
  letter-spacing: .01em; background-image: none;
  /* 手机竖屏上顶栏本来就挤，品牌一旦折行会把整条顶栏撑成两行高，
     底下所有 sticky 的偏移量（--topbar-h）就全错了。宁可省略号，不许折行。 */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar__brand:hover { text-decoration: none; color: var(--c-ink); }
/* 品牌前面那颗点：换画风时它跟着换色，是"画风生效了"最小的一处证据 */
.topbar__mark { width: 9px; height: 9px; flex: none; border-radius: 50%;
  background: var(--c-accent-bg);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-accent-bg) 22%, transparent);
  transition: box-shadow var(--dur) var(--ease); }
.topbar__brand:hover .topbar__mark {
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--c-accent-bg) 26%, transparent); }

/* 页内导航开关。它在品牌左边——那是"这一页的结构"该在的地方，
   跟右边那组"全站设置"分得开。 */
.navtoggle {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 30px; height: 30px; margin-inline-end: calc(-1 * var(--s-1));
  padding: 0; cursor: pointer; border: none; border-radius: var(--r-sm);
  background: transparent; color: var(--c-ink-faint);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.navtoggle:hover { background: var(--c-glass-hover); color: var(--c-ink); }
/* 开着的时候那一栏是实的：按钮自己就是当前状态的图示，不用另配文字 */
.navtoggle[data-on='false'] .navtoggle__fill { opacity: 0; }
.navtoggle[data-on='true'] { color: var(--c-gold); }
.navtoggle__fill { transition: opacity var(--dur-fast) var(--ease); }

/* 阅读进度：压在玻璃下沿的 2px。它回答"还剩多少"——章节名回答不了这件事，
   而它不占任何版面。用 scaleX 而不是 width：只碰合成层，滚动时不触发布局。 */
.topbar__progress {
  position: absolute; left: 0; bottom: 0; z-index: 1;
  width: 100%; height: 2px; transform-origin: left center;
  transform: scaleX(var(--p, 0));
  background: linear-gradient(to right, var(--c-accent-bg), var(--c-gold));
  pointer-events: none;
}

.topbar__nav { display: flex; align-items: center; gap: var(--s-4); }
/* 三个控件是一组"设置"，用一块更实的玻璃托住它们，
   跟右边的登录按钮分开——不分组的话顶栏右侧就是一排零件。 */
.topbar__controls {
  display: flex; align-items: center; gap: var(--s-1);
  padding: 3px; border-radius: calc(var(--r-md) + 3px);
  background: var(--c-glass-tint);
  box-shadow: inset 0 0 0 1px var(--c-glass-line),
              inset 0 1px 0 var(--c-glass-sheen);
}

/* ── 自定义下拉（见 components/Select.tsx，原生 select 不认识画风）──── */
.sel { position: relative; }
.sel__btn {
  display: inline-flex; align-items: center; gap: var(--s-2);
  max-width: 11rem; padding: var(--s-2) var(--s-3);
  border: none; border-radius: var(--r-md); cursor: pointer;
  background: transparent; color: var(--c-ink-dim);
  font-size: var(--t-xs); font-weight: 600; line-height: 1.6;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.sel__btn:hover { background: var(--c-glass-hover); color: var(--c-ink); }
.sel__btn.is-open { background: var(--c-glass-hover); color: var(--c-ink); }
.sel__icon { display: inline-flex; flex: none; color: var(--c-ink-faint); }
.sel__btn:hover .sel__icon, .sel__btn.is-open .sel__icon { color: var(--c-gold); }
.sel__value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sel__chev { flex: none; color: var(--c-ink-faint);
  transition: transform var(--dur) var(--ease); }
.sel__btn.is-open .sel__chev { transform: rotate(180deg); }

/* 弹层：比顶栏更实的一块玻璃。它悬在内容之上，太透就读不了 */
.sel__list {
  position: absolute; z-index: 40; top: calc(100% + var(--s-2)); right: 0;
  /* 宽度跟着内容走：语言那个只有"中文/English"，撑成一样宽会很蠢；
     画风那个带一句话定位，不给它宽度就会把一句话折成一竖条。
     max-content + 上下界 = 两个都合身。 */
  width: max-content; min-width: 100%;
  max-width: min(23rem, calc(100vw - 2 * var(--page-pad)));
  max-height: min(60vh, 22rem); overflow-y: auto;
  margin: 0; padding: var(--s-1); list-style: none;
  border-radius: var(--r-md);
  background: linear-gradient(var(--c-glass-tint), var(--c-glass-tint)), var(--c-bg);
  -webkit-backdrop-filter: blur(calc(var(--glass-blur) + 6px)) saturate(1.8);
  backdrop-filter: blur(calc(var(--glass-blur) + 6px)) saturate(1.8);
  box-shadow: inset 0 0 0 1px var(--c-glass-line),
              inset 0 1px 0 var(--c-glass-sheen),
              0 16px 34px var(--c-glass-shadow);
  animation: sel-in var(--dur-fast) var(--ease);
}
/* 从触发处往下"掉"出来，不是凭空淡入：有起因也有方向 */
@keyframes sel-in { from { opacity: 0; transform: translateY(-6px) scale(.98); } }

.sel__opt {
  display: flex; align-items: flex-start; gap: var(--s-2);
  padding: var(--s-2) var(--s-3); border-radius: var(--r-sm); cursor: pointer;
  color: var(--c-ink-dim); font-size: var(--t-xs); line-height: 1.5;
}
/* 高亮跟着键盘和鼠标走，用 data-active 而不是 :hover：
   键盘操作时鼠标可能正停在别的行上，两个高亮会同时亮着 */
.sel__opt[data-active='true'] { background: var(--c-glass-hover); color: var(--c-ink); }
.sel__opt.is-on { color: var(--c-ink); }
.sel__opt[aria-disabled='true'] { opacity: .55; cursor: not-allowed; }
.sel__tick { flex: none; margin-top: .3em; color: var(--c-gold); }
.sel__opt-text { min-width: 0; }
.sel__opt-label { display: block; font-weight: 600; }
.sel__opt-hint { display: block; margin-top: 2px; color: var(--c-ink-faint);
  font-size: var(--t-xs); font-weight: 400; line-height: 1.45; }

/* ── 明暗开关：两格 + 一块滑块 ──────────────────────────────────────── */
.schemer { position: relative; display: flex; padding: 2px; border-radius: var(--r-md); }
.schemer__slide {
  position: absolute; z-index: 0; top: 2px; bottom: 2px; width: calc(50% - 2px);
  border-radius: calc(var(--r-md) - 2px);
  background: var(--c-bg-raise);
  box-shadow: inset 0 0 0 1px var(--c-glass-line), 0 1px 3px var(--c-glass-shadow);
  transition: transform var(--dur) var(--ease);
}
/* 滑块滑过去，不是"另一格亮起来"：两档是同一个开关的两端 */
.schemer[data-on='dark'] .schemer__slide { transform: translateX(100%); }
.schemer__opt {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 24px; padding: 0; cursor: pointer;
  background: none; border: none; border-radius: calc(var(--r-md) - 2px);
  color: var(--c-ink-faint);
  transition: color var(--dur-fast) var(--ease);
}
.schemer__opt:hover { color: var(--c-ink-dim); }
.schemer__opt[aria-checked='true'] { color: var(--c-gold); }

/* ── 按钮：玻璃，不是贴纸 ─────────────────────────────────────────────
   原来每个按钮背后拖着一块 `6px 7px 0` 的实心硬投影，按下去还会往右下"掉"两像素。
   那是插画里的语言——**一张纸压在另一张纸上**——安到控件上就变成了一排贴纸。

   控件改玻璃，三层：半透的底 + 一道内描边（玻璃的厚度）+ 顶边一条高光。
   状态变化只走底色和高光，**不位移、不投影**：按钮不该在页面上跳来跳去，
   那一下位移还会把相邻的行一起推着动。
   ────────────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  padding: var(--s-3) var(--s-5);
  border: none; border-radius: var(--r-md); cursor: pointer;
  font-weight: 600; font-size: var(--t-sm); line-height: 1.4;
  color: var(--c-ink); background: var(--c-glass-tint);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.6);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.6);
  box-shadow: inset 0 0 0 1px var(--c-glass-line), inset 0 1px 0 var(--c-glass-sheen);
  background-image: none;
  transition: background var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
.btn:hover:not(:disabled) { background: var(--c-glass-hover); color: var(--c-ink); text-decoration: none; }
/* 按下去是"按进玻璃里"：内阴影，不是把整块牌子挪走 */
.btn:active:not(:disabled) {
  box-shadow: inset 0 0 0 1px var(--c-glass-line), inset 0 2px 6px var(--shadow-color);
}
.btn:disabled { opacity: .45; cursor: not-allowed; }

/* 主按钮是整页唯一的实心色块——它要被一眼找到，所以它不透明。
   但它同样不投影：一道顶边高光就够把它托起来。 */
.btn--primary {
  background: var(--c-accent-bg); color: var(--c-on-accent);
  -webkit-backdrop-filter: none; backdrop-filter: none;
  box-shadow: inset 0 1px 0 color-mix(in srgb, #fff 22%, transparent);
}
.btn--primary:hover:not(:disabled) {
  background: var(--c-accent-hover, var(--c-accent-bg));
  color: var(--c-on-accent); text-decoration: none;
}
.btn--ghost { background: transparent; box-shadow: inset 0 0 0 1px var(--c-line);
  color: var(--c-ink-dim); -webkit-backdrop-filter: none; backdrop-filter: none; }
.btn--ghost:hover:not(:disabled) { background: var(--c-glass-hover); color: var(--c-ink); }
.btn--sm { padding: var(--s-2) var(--s-4); font-size: var(--t-xs); }

/* 角标。用色块的淡底 + 同色的字，不描边不投影。 */
.tag { display: inline-block; padding: 2px var(--s-2); border-radius: var(--r-sm);
  font-size: var(--t-xs); font-weight: 600; line-height: 1.6; }
.tag--free  { background: color-mix(in oklab, var(--c-free) 14%, transparent); color: var(--c-free); }
/* 两档锁。**它们必须长得不一样** —— 一个只要登录（不花钱），一个要开通。
   用同一个灰色徽章的话，只差一次登录的人会以为自己得掏钱。 */
.tag--member { display: inline-flex; align-items: center; gap: 3px;
  background: color-mix(in oklab, var(--c-ink) 9%, transparent); color: var(--c-ink-dim); }
.tag--paid { display: inline-flex; align-items: center; gap: 3px;
  background: color-mix(in oklab, var(--c-gold) 15%, transparent); color: var(--c-gold); }
/* 收费和可见范围的角标（components/AccessTag.tsx）：前台、后台、知识、课程全站同一个样子。
   公开可见 / 免费：绿；登录可见：灰（只差一次登录，不能长得像要花钱）；会员可见 / 付费可见：金，付费可见多一圈描边。 */
.access-tag { display: inline-flex; align-items: center; gap: 3px; width: fit-content; padding: 2px var(--s-2); border-radius: var(--r-sm);
  font-size: var(--t-xs); font-weight: 600; line-height: 1.6; white-space: nowrap; }
.access-tag[data-level='public'] { background: color-mix(in oklab, var(--c-free) 14%, transparent); color: var(--c-free); }
.access-tag[data-level='login'] { background: color-mix(in oklab, var(--c-ink) 9%, transparent); color: var(--c-ink-dim); }
.access-tag:is([data-level='member'], [data-level='paid']) { background: color-mix(in oklab, var(--c-gold) 15%, transparent); color: var(--c-gold); }
.access-tag[data-level='paid'] { box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--c-gold) 55%, transparent); }
.access-tag__lock { flex: none; }
/* 「筹备中」= 正文还没落笔。它跟上面两档锁是**两个维度**，
   所以不能长得像第三档锁：不用金色（那是会员的意思），不画锁的图标。
   一圈虚线的描边，里面不填色 —— 地图上还没修的那条路。 */
.tag--upcoming { background: transparent; color: var(--c-ink-faint); font-weight: 500;
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--c-ink) 18%, transparent); }
.tag--video { background: color-mix(in oklab, var(--c-coral) 14%, transparent); color: var(--c-coral); }
.tag--d1 { background: color-mix(in oklab, var(--c-mint) 14%, transparent); color: var(--c-mint); }
.tag--d2 { background: color-mix(in oklab, var(--c-gold) 14%, transparent); color: var(--c-gold); }
.tag--d3 { background: color-mix(in oklab, var(--c-coral) 14%, transparent); color: var(--c-coral); }

.state { padding-block: var(--s-9); text-align: start; color: var(--c-ink-faint); }
.state--err { color: var(--c-coral); }
/* 用 padding-block，别用 padding 简写 —— 简写会把 .page 的 padding-inline 清成 0 */
.footer { padding-block: var(--s-8); color: var(--c-ink-faint); font-size: var(--t-xs); }

/* ── 页面的底：一层属于本画风的纹 ──────────────────────────────────────
   template/game 那批原型没有一个是纯色底：水墨是纸纹、折纸是斜织、笔记本是横线。
   少了这一层，页面就只是"排版正确的信息"，不是一个有气质的地方。
   纹路用 CSS 渐变拼，不引图片：跟着 --c-* 走，换画风和换亮暗自动成立，也没有额外请求。 */
body {
  background-attachment: fixed;
  background-repeat: repeat;
}
/* 蜡笔：纸的颗粒感，细点阵 */
:root[data-style='crayon-book'] body {
  background-image:
    radial-gradient(color-mix(in srgb, var(--c-ink) 5%, transparent) 1px, transparent 1.2px);
  background-size: 22px 22px;
}
/* 水彩：冷压纸的纹。两层疏密不同的点错开叠，避免蜡笔那种整齐的点阵感——
   水彩纸的纹是不规则的，一整齐就成了网格本 */
:root[data-style='watercolor'] body {
  background-image:
    radial-gradient(color-mix(in srgb, var(--c-ink) 3.5%, transparent) 1px, transparent 1.6px),
    radial-gradient(color-mix(in srgb, var(--c-ink) 2.5%, transparent) 1.4px, transparent 2px);
  background-size: 17px 19px, 31px 29px;
  background-position: 0 0, 9px 13px;
}

/* ═══════════════════════════════════════════════════════════════════════
   目录页
   ─────────────────────────────────────────────────────────────────────
   2026-09-21 重排。原来这页乱在三处，都不是配色问题：

   ① **报纸分栏**（`columns: 300px`）。阅读顺序变成"先往下再往右"，卡片在哪一栏
      断掉不可控，1920 上会裂成五条窄栏。换成 grid：位置可预测，行对齐。
   ② **一次把 1167 个知识点全摊开。** 现在默认只展到"领域 → 主题"，
      知识点收在 <details> 里，谁想看谁点开。目录的职责是让人**找得到**，
      不是把整本书倒在地上。
   ③ 三处 AI 味的套路：全大写疏排眉题、标题里挑一个词上色、`A · B · C` 中点串。
      三个都删了。
   ═══════════════════════════════════════════════════════════════════════ */
.catalog { padding-block: 0 var(--s-9); }

/* ── 首屏 ──────────────────────────────────────────────────────────── */
.hero {
  position: relative; isolation: isolate;
  margin-inline: calc(-1 * var(--page-pad));
  padding: var(--s-8) var(--page-pad) var(--s-7);
  margin-bottom: var(--s-8);
  overflow: hidden;              /* 底画铺满即可，绝不撑出横向滚动条 */
}
.hero__body { position: relative; z-index: 1; max-width: 32em; }

/* 底画：铺满首屏、压在内容下面。颜色全部取自当前画风。 */
.heroart { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
/* 标题整句一个颜色。原来是后半截换色——挑一个词上色是最好认的 AI 生成痕迹之一，
   而且这句话里没有哪个词值得被单独挑出来。 */
.hero__title {
  font-family: var(--font-display); font-size: var(--t-3xl); font-weight: 800;
  letter-spacing: -.02em; line-height: 1.14; text-wrap: balance; color: var(--c-ink);
}
.hero__sub { margin: var(--s-4) 0 0; color: var(--c-ink-dim); font-size: var(--t-lg);
  line-height: 1.65; }

/* 数据片：一行数字，靠字号和字重分主次，不做成三块牌子。
   牌子（底色+边框+投影）把三个数字变成了三个控件，看起来像能点。 */
.hero__stats { display: flex; flex-wrap: wrap; gap: var(--s-6); margin: var(--s-6) 0 0; }
.stat { display: flex; flex-direction: column; gap: 2px; }
.stat__n { margin: 0; font-family: var(--font-mono); font-size: var(--t-2xl);
  font-weight: 700; line-height: 1; color: var(--c-ink);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.stat__label { font-size: var(--t-xs); color: var(--c-ink-faint); }

/* ── 分档规则那一行 ────────────────────────────────────────────────── */
.catalog__rule {
  margin: calc(-1 * var(--s-4)) 0 var(--s-6);
  font-size: var(--t-sm); color: var(--c-ink-dim);
}

/* ── 一条带 = 一个领域 ────────────────────────────────────────────────
   **整张目录是一列。**
   原来是 `repeat(auto-fill, minmax(21rem, 1fr))`，宽屏上并排三张卡。
   问题不在"三列不好看"，在于卡里的主题是可以展开的：
   展开一张卡里的一个主题，它变高，旁边两列跟着被拉长，而它们里面是空的。
   **越认真看目录的人，看到的空白越多** —— 这是三列布局在这种内容上的必然结果。

   现在一列，宽屏那点富余给到每一条的**内部**：
   左边一栏交代"这是哪个域"，右边横贯的一片放主题清单。
   宽度是被用掉的，不是靠再并一张卡填满的。 */
.catalog__list { display: grid; gap: var(--s-5); }

.band {
  --tone: var(--c-gold);
  position: relative; isolation: isolate;
  padding: var(--s-6);
  border-radius: var(--r-lg);
  background: var(--c-bg-raise);
  box-shadow: inset 0 0 0 1px var(--c-line-soft);
  overflow: hidden;
  display: grid; gap: var(--s-4);
  transition: box-shadow var(--dur) var(--ease);
}
.band:hover { box-shadow: inset 0 0 0 1px var(--c-line), var(--shadow-md); }
/* 左边一道色带：整张目录里唯一的"线"，而且它有意义（区分域），不是装饰 */
.band::before {
  content: ''; position: absolute; inset-block: 0; left: 0; width: 4px;
  background: var(--tone);
}

/* 元技能带跟域**故意长得不一样**：它横贯整幅、头在上面、有自己的开场白。
   域是并列的十二选一，它是唯一的入口。 */
.band--meta { --tone: var(--c-gold); }

.band__head { max-width: 46em; }
.band__no {
  display: block; margin-bottom: var(--s-1);
  font-family: var(--font-mono); font-size: var(--t-xl); font-weight: 700;
  line-height: 1; color: var(--tone);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.band__title {
  margin: 0; font-family: var(--font-display); font-size: var(--t-xl);
  font-weight: 700; color: var(--c-ink); text-wrap: balance;
}
.band--meta .band__title { font-size: var(--t-2xl); }
.band__lead { margin: var(--s-3) 0 0; color: var(--c-ink-dim); font-size: var(--t-sm);
  line-height: 1.7; }
/* 元信息一句话说完，不用中点把三段串起来 */
.band__meta { margin: var(--s-2) 0 0; font-size: var(--t-xs); color: var(--c-ink-faint); }

.band__topics { list-style: none; margin: 0; padding: 0; }

/* 宽屏：左边交代"这是哪个域"，右边放主题。
   1024 以下叠成上下两块——那个宽度再切一栏，主题名就要换行了。 */
@media (min-width: 1024px) {
  .band {
    grid-template-columns: minmax(13rem, 17rem) 1fr;
    gap: var(--s-4) var(--s-7);
    align-items: start;
  }
  /* 域名跟着滚一段：主题清单长的时候，读者随时知道自己在哪个域里。
     top 要让开顶栏那块玻璃，否则标题会从玻璃后面透出来 */
  .band__head { position: sticky; top: calc(var(--topbar-h) + var(--s-5)); }
  /* 元技能带的头是一段开场白，不是一个标签：它横在上面，主题铺满整幅 */
  .band--meta { grid-template-columns: 1fr; }
  .band--meta .band__head { position: static; }
}

/* ── 主题行：默认只到这一层，知识点收着 ────────────────────────────────
   用原生 <details>/<summary>：键盘、读屏、Ctrl+F 全都天然成立，不用写一行 JS。

   主题行**永远独占一整行**。它是可以展开的东西，而可展开的东西一旦并排，
   就会出现"展开一个、旁边空一片"——这正是整张目录改成一列的原因，
   在带的内部再犯一次就白改了。 */
.topic + .topic { border-top: 1px solid var(--c-line-soft); }
.topic__fold { display: block; }
.topic__sum {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-2); cursor: pointer; list-style: none;
  font-size: var(--t-sm); font-weight: 600; color: var(--c-ink);
  border-radius: var(--r-sm);
  transition: background var(--dur-fast) var(--ease);
}
.topic__sum::-webkit-details-marker { display: none; }
.topic__sum:hover { background: var(--c-glass-hover); }
.topic__sum:focus-visible { outline: 2px solid var(--c-gold); outline-offset: -2px; }
.topic__name { flex: 1; min-width: 0; }
/* 编号留着：课程**确实**是有顺序的，01/02/03 在这里是信息不是装饰 */
.topic__no {
  flex: none; font-family: var(--font-mono); font-size: var(--t-xs); color: var(--tone);
  font-variant-numeric: tabular-nums;
}
.topic__n { flex: none; font-size: var(--t-xs); font-weight: 400; color: var(--c-ink-faint);
  font-variant-numeric: tabular-nums; }
/* 收起来的时候也能看出这个主题值不值得展开：
   12 条全是草稿和 12 条全写完，折叠行上本来长得一模一样。 */
.topic__live { flex: none; font-size: var(--t-xs); font-weight: 600; color: var(--tone);
  font-variant-numeric: tabular-nums; }
.topic__live[data-none='true'] { font-weight: 400; color: var(--c-ink-faint); }
.topic__caret { flex: none; color: var(--c-ink-faint);
  transition: transform var(--dur) var(--ease); }
.topic__fold[open] .topic__caret { transform: rotate(90deg); }
.topic__fold[open] .topic__sum { color: var(--c-gold); }

/* 还没有知识点的主题：一行灰字，长得就点不了——因为它确实点不了 */
.topic--bare { display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-2); font-size: var(--t-sm); color: var(--c-ink-faint); }
.topic--bare .topic__no { color: var(--c-ink-faint); }

/* 知识点**可以**铺成几栏 —— 它们是叶子，点开没有下一层，
   所以不存在"展开一个、旁边空一片"。宽屏上一个主题的十几条一屏就看完了。 */
.topic__kps {
  list-style: none; margin: 0 0 var(--s-3); padding: 0 0 0 var(--s-5);
  display: grid; gap: 0 var(--s-5);
  grid-template-columns: repeat(auto-fill, minmax(min(23rem, 100%), 1fr));
}

/* 一条知识点。标题和角标同一行：行现在有的是宽度，
   原来标题独占一行是因为卡片只有 21rem。 */
.kplink { position: relative; display: flex; align-items: baseline;
  gap: var(--s-2) var(--s-4);
  padding: var(--s-2) var(--s-3); border-radius: var(--r-sm);
  color: var(--c-ink-dim); font-size: var(--t-sm); line-height: 1.45;
  background-image: none;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); }
.kplink:hover, .kplink:focus-visible {
  background: color-mix(in srgb, var(--tone) 10%, transparent);
  color: var(--c-ink); text-decoration: none; }
/* 序号。知识点在宽屏上铺成好几栏 = 它们横着排，而横排的文字看不出先后。
   两位数、等宽、贴着标题左边 —— 它是这一列唯一的方向指示。
   `tabular-nums` 不能省：比例数字下 01 比 11 窄，一列号码会参差不齐。 */
.kplink__no {
  flex: none; font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--c-ink-faint); font-variant-numeric: tabular-nums;
}
.kplink:hover .kplink__no, .kplink:focus-visible .kplink__no { color: var(--tone); }
.kplink__title { flex: 1; min-width: 0; }
.kplink__tail { display: flex; align-items: center; gap: var(--s-2); flex: none; }
.kplink__tail:empty { display: none; }
.kplink__min { font-size: var(--t-xs); color: var(--c-ink-faint);
  font-variant-numeric: tabular-nums; }
/* 锁着的**照样是链接**，只是淡一档：点进去能看到标题、时长和一句"为什么看不了"。
   做成不可点的灰字，等于让人连这条讲什么都不知道。 */
.kplink[data-locked='true'] .kplink__title { color: var(--c-ink-faint); }
.kplink[data-locked='true']:hover .kplink__title { color: var(--c-ink-dim); }
/* 还没写的也**照样是链接**（点进去有标题、时长、和上下节）。
   但它不能跟能读的一样显眼：一屏 12 条里 9 条还没写的时候，
   读者要一眼挑出能读的那 3 条，而不是反过来数。 */
.kplink[data-upcoming='true'] .kplink__title { color: var(--c-ink-faint); }
.kplink[data-upcoming='true'] .kplink__min { opacity: .6; }
.kplink[data-upcoming='true']:hover .kplink__title { color: var(--c-ink-dim); }
/* ── 知识点页 ── 版面见文件末尾的「知识点页的版面」一节 ────────── */


/* ── 登录 ─────────────────────────────────────────────────────────────
   一次只问一件事：先问号码，发完再问验证码。
   原来两个框同时摆着，下面并排两个一样大的实心按钮（提交 / 重发）——
   两个等重的按钮等于让人先读完才知道该按哪个，而这页只有一件事要做。 */
.login { display: flex; justify-content: center; padding-block: var(--s-9) var(--s-9); }
.login__col { width: 100%; max-width: 23rem; }
.login__title { font-family: var(--font-display); font-size: var(--t-2xl); font-weight: 700;
  color: var(--c-ink); }
.login__lead { margin: var(--s-3) 0 var(--s-6); color: var(--c-ink-dim); font-size: var(--t-sm);
  line-height: 1.6; }
.login__form { display: flex; flex-direction: column; gap: var(--s-4); }

.field { display: flex; flex-direction: column; gap: var(--s-2); }
.field__label { font-size: var(--t-xs); color: var(--c-ink-faint); }
/* 框本身是一块玻璃：底 + 一道内描边。聚焦时描边换成强调色并加粗到 2px，
   **不换布局**——用 box-shadow 画边而不是 border，避免聚焦时内容跳 1px。 */
.field__box {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-3) var(--s-4); border-radius: var(--r-md);
  background: var(--c-glass-tint);
  box-shadow: inset 0 0 0 1px var(--c-glass-line);
  transition: box-shadow var(--dur-fast) var(--ease);
}
.field__box:focus-within { box-shadow: inset 0 0 0 2px var(--c-accent-bg); }
.field__prefix { flex: none; color: var(--c-ink-faint); font-family: var(--font-mono);
  font-size: var(--t-sm); }
.field__input {
  flex: 1; min-width: 0; padding: 0; border: none; background: none;
  color: var(--c-ink); font: var(--t-base)/1.4 var(--font-body);
}
.field__input:focus { outline: none; }
.field__input::placeholder { color: var(--c-ink-faint); }
.field__input--code { letter-spacing: .48em; font-family: var(--font-mono); }

.btn--block { width: 100%; }

/* 退路降级成文字链：重发、换号码都不是主路 */
.login__alt { display: flex; justify-content: space-between; gap: var(--s-4); margin: 0; }
.linkbtn {
  padding: 0; border: none; background: none; cursor: pointer;
  color: var(--c-gold); font-size: var(--t-xs);
  text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--c-gold) 40%, transparent);
}
.linkbtn:hover:not(:disabled) { text-decoration-color: currentColor; }
.linkbtn:disabled { color: var(--c-ink-faint); cursor: default; text-decoration: none; }

.login__err { margin: 0; color: var(--c-coral); font-size: var(--t-sm); }
/* 账号被禁用：比一行报错重要，单独一块；二维码白底，暗色档也不反色（扫不出来） */
.login__banned { display: grid; gap: var(--s-2); justify-items: start; padding: var(--s-4);
  border-radius: var(--r-md); color: var(--c-ink); font-size: var(--t-sm); line-height: 1.6;
  background: color-mix(in srgb, var(--c-coral) 10%, transparent); }
.login__banned p { margin: 0; }
.login__banned-title { color: var(--c-coral); font-weight: 700; }
.login__banned-qr { width: 160px; height: 160px; padding: 8px; border-radius: var(--r-sm); background: #fff; }
.login__agreement { margin: var(--s-5) 0 0; font-size: var(--t-xs); color: var(--c-ink-faint);
  line-height: 1.6; }

/* 开发模式那块：虚线框。虚线在这套语言里只有一个意思——**这东西不上线**。 */
.devbox {
  margin-top: var(--s-8); padding: var(--s-4) var(--s-5);
  border: 1px dashed var(--c-line); border-radius: var(--r-md);
}
.devbox__title { margin: 0; font-size: var(--t-xs); font-weight: 700; color: var(--c-ink-dim); }
.devbox__lead { margin: var(--s-2) 0 var(--s-4); font-size: var(--t-xs); color: var(--c-ink-faint);
  line-height: 1.6; }

/* 读不了的时候那一块。**不是错误页**，所以它长得像一块说明，不是一块警告——
   红色在这套语言里的意思是"出错了"，而读到第四条被请去登录、
   或者翻到一条还没写的，都不是出错。

   两种墙共用一个壳（见 KnowledgePoint.tsx 的 Wall），区别只在那个记号的颜色：
   锁是金的（跟会员角标同色，说的是同一件事），笔是弱字色（它跟钱无关）。 */
.wall { margin-top: var(--s-6); padding: var(--s-8) var(--s-7); text-align: start;
  background: var(--c-bg-raise); border-radius: var(--r-lg);
  box-shadow: inset 0 0 0 1px var(--c-line-soft); }
.wall__mark { display: inline-flex; margin-bottom: var(--s-4); color: var(--c-gold); }
.wall--upcoming .wall__mark { color: var(--c-ink-faint); }
/* 还没写的那一块不该跟付费墙一样重：它没有任何要读者做的事。
   实底 + 描边会让它看起来像在拦人，而它只是在说一句话。 */
.wall--upcoming { background: transparent;
  box-shadow: inset 0 0 0 1px var(--c-line-soft); }
.wall__title { font-family: var(--font-display); font-size: var(--t-xl); color: var(--c-ink); }
.wall__lead { max-width: 30em; margin: var(--s-3) auto var(--s-6);
  color: var(--c-ink-dim); font-size: var(--t-sm); line-height: 1.75; }
.wall--upcoming .wall__lead { margin-bottom: var(--s-3); }
.wall__acts { display: flex; flex-wrap: wrap; gap: var(--s-3); justify-content: center; }
.wall__note { margin: var(--s-5) 0 0; font-size: var(--t-xs); color: var(--c-ink-faint); }
.wall--upcoming .wall__note { margin-top: 0; }

/* ── 会员芯片 ──────────────────────────────────────────────────────────
   已开通显示"年会员"（画风强调色），没开通显示"开通会员"（实心金色，见 accounts.css）。两种都只是一个链接，
   点进去是会员页 —— 顶栏上不放任何一点就扣钱的东西。 */

/* ── 会员页 ────────────────────────────────────────────────────────────
   版面整个借登录页（.login 两栏）：左边一张画，右边一列只放一件事。
   价格是这一列里最大的字 —— 付钱之前，读者第一个要知道的就是多少钱。 */
.buy__price { display: flex; align-items: baseline; gap: var(--s-2); margin: var(--s-4) 0 var(--s-2); }
.buy__num { font: 700 clamp(44px, 6vw, 56px)/1 var(--font-display); color: var(--c-ink);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.buy__unit { color: var(--c-ink-dim); font-size: var(--t-sm); }
.buy .login__lead { margin-bottom: var(--s-5); }
/* 三条好处：一个金色的勾，不是一排小卡片 */
.buy__perks { display: grid; gap: var(--s-3); margin: 0 0 var(--s-6); padding: 0; list-style: none; }
.buy__perks li { position: relative; padding-inline-start: 1.7em; color: var(--c-ink);
  font-size: var(--t-sm); line-height: 1.6; }
.buy__perks li::before { content: ''; position: absolute; inset-inline-start: .15em; top: .42em;
  width: .75em; height: .4em; border-inline-start: 2px solid var(--c-gold);
  border-bottom: 2px solid var(--c-gold); transform: rotate(-45deg); }
/* 标题旁的「去水印」小签：会员看文章没有水印（ACCOUNT-SPEC 第六节） */
.buy__title { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.buy__badge { padding: 3px 10px; border: 1px solid color-mix(in srgb, var(--c-gold) 45%, transparent); border-radius: 999px;
  background: var(--c-accent-soft); color: var(--c-on-accent-soft);
  font: 500 var(--t-xs)/1.4 var(--font-body); letter-spacing: .04em; white-space: nowrap; }
.buy__status { margin: 0 0 var(--s-4); color: var(--c-gold); font-size: var(--t-sm); font-weight: 600; }
.buy .login__alt { margin-top: var(--s-4); }
.buy__note { margin: var(--s-3) 0 0; color: var(--c-ink-faint); font-size: var(--t-xs); line-height: 1.6; }
/* 二维码：SVG 自带白底和留白，这里只管尺寸。一道发丝线让它在亮档乳白底上也有边 */
.buy__qr { width: min(240px, 100%); aspect-ratio: 1; margin: var(--s-5) 0 var(--s-4);
  border-radius: var(--r-md); overflow: hidden; box-shadow: 0 0 0 1px var(--c-line-soft); }
.buy__qr svg { display: block; width: 100%; height: 100%; }

/* ── 窄屏：顶栏放不下画风名，收成纯图标 ─────────────────────────────
   收的是**值**不是控件：图标还在，按钮还能点，弹层里仍然是全名。
   直接把控件藏掉的话，手机上就换不了画风了。 */
@media (max-width: 743px) {
  .topbar__nav { gap: var(--s-3); flex: none; }
  /* 品牌是这条里唯一可以被压缩的东西：开关要能点，控件要能换画风，
     只有"我们叫什么"可以先让出去。 */
  .topbar__left { flex: 0 1 auto; overflow: hidden; }
  .sel__value { display: none; }
  .sel__chev { display: none; }
  .sel__btn { padding-inline: var(--s-2); }
  .hero__stats { gap: var(--s-5); }
}

/* ── 手机横屏：竖向空间紧张，压缩留白 ─────────────────────────────── */
@media (max-height: 460px) and (orientation: landscape) {
  .login { padding-block: var(--s-4); }
  .hero { margin-bottom: var(--s-6); }
  .hero__title { font-size: var(--t-xl); }
  :root { --topbar-h: 48px; }
}

/* ── 知识点页的版面 ───────────────────────────────────────────────────
   一栏，不是两栏。页内目录搬去了左边那块可开可关的侧栏。

   ── **一条版心，所有东西共用** ──────────────────────────────────────
   原来这里是两条：正文按 --measure（约 66ch）居中，插画/代码/表格再往两边
   各多要一截（+14rem）。道理上站得住——「要读的窄、要看的宽」——
   可它在屏幕上是这样的：**一段字、一张比它宽出 224px 的图、又一段字。**
   每滚过一张图，文字的左右边缘就往里缩一次，再吐出来一次。
   读一页要在两条边缘之间来回切十几次，那个不适感比"行有点长"强得多。

   所以现在只有一条：文字、区块、插画、代码、表格全都齐着同一条左右边缘。
   两侧的留白照旧，只是**留白的宽度不再随内容变**。
   版心取的是原先那条"宽块"的宽度，不是正文那条——
   把图缩到文字那么窄，图里的东西就看不清了，而那才是图存在的理由。 */
.kp { padding-block: var(--s-5) var(--s-9);
  /* min(…, 100%) 里的 100% 是 .page 的内容宽，所以任何一档都不会撑出横向滚动条 */
  --kp-w: min(calc(var(--measure) + 14rem), 100%);
}

/*
  ── 两条空白一样宽 ──────────────────────────────────────────────────
  这里返工过两次，把结论写死：

  **判据是「目录栏右边缘 → 正文左边缘」等于「正文右边缘 → 窗口右边缘」。**

  做法就是最朴素的那一种：`.app__main` 用 padding 给侧栏让出 16rem，
  正文在**剩下那块**里 `margin-inline: auto`。剩下那块的左边就是侧栏的边，
  右边就是窗口的边，居中自然让两边等宽。

  中间试过"按整个窗口居中"（让文章在窗口里看着正）——那是错的：
  窗口的左边一大截被侧栏占着，按窗口居中等于把正文往侧栏那边推，
  1920 上算出来是左 235 右 491，**两条空白差了一倍**。
  文章在窗口里正不正不重要，**挨着它的那两条空白一样宽才重要**。
*/
.kp__head, .kp__body { max-width: var(--kp-w); margin-inline: auto; }

.kp__title { font-family: var(--font-display); font-size: var(--t-2xl); }
.kp__meta { display: flex; align-items: center; gap: var(--s-3); margin-top: var(--s-3);
  font-size: var(--t-xs); color: var(--c-ink-faint); }
.kp__body { margin-top: var(--s-6); }
/* 行内代码里的长网址、长路径在手机上要能断行，不然把整页撑出横向滚动 */
.kp__body :not(pre) > code { overflow-wrap: anywhere; }

/* 文章页的字不许复制（ACCOUNT-SPEC 第六节）：选不中、手机长按不弹菜单；输入框照常能选能改 */
.kp { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
.kp :is(input, textarea, [contenteditable='true']) { -webkit-user-select: text; user-select: text; }

/* 非会员的水印：公司名用遮罩画，底色取正文色，四种画风、亮暗自动跟着变。
   只铺正文这一栏（不铺两侧留白和顶上的工具条），压在图和代码上面，但不挡点击 */
.kp__body { position: relative; }
.kp-watermark { position: absolute; inset: 0; z-index: 3; pointer-events: none; background: var(--c-ink); opacity: .07;
  -webkit-mask: var(--kp-watermark) 0 0 / 440px 260px repeat; mask: var(--kp-watermark) 0 0 / 440px 260px repeat; mask-mode: alpha; }
:root[data-scheme='dark'] .kp-watermark { opacity: .16; }

/* 锚点跳转时别被顶栏和位置条盖住 */
.kp-h2 { scroll-margin-top: calc(var(--topbar-h) + 44px + var(--s-3)); }

/* ── 左侧页内导航 ─────────────────────────────────────────────────────
   fixed，不参与流式布局。让一条 100dvh 的侧栏参与布局，它就要跟正文抢滚动容器，
   而且 sticky 一旦遇上祖先的 overflow 裁剪就会静静失效——那种 bug 查起来最费劲。
   收起来不是 display:none：要有位移动画，而且 inert 已经把它从 Tab 序里摘掉了。 */
.sidenav {
  position: fixed; z-index: 24;
  inset-block: var(--topbar-h) 0; inset-inline-start: 0;
  width: var(--sidenav-w);
  overflow-y: auto; overscroll-behavior: contain;
  transform: translateX(-101%);          /* 多 1% 把投影也带出屏幕 */
  transition: transform var(--dur) var(--ease);
  background: var(--c-bg-raise);
  box-shadow: 1px 0 0 var(--c-line-soft);
}
.app[data-nav='open'] .sidenav { transform: none; }
/* 左内边距跟顶栏同源（--chrome-pad）：目录和顶栏左上角那组要对齐。 */
.sidenav__inner { padding: var(--s-5) var(--s-4) var(--s-8); padding-inline-start: var(--chrome-pad); }

.sidenav__title {
  margin: 0 0 var(--s-5); font-family: var(--font-display);
  font-size: var(--t-sm); font-weight: 700; line-height: 1.4; color: var(--c-ink);
}
.sidenav__label {
  margin: 0 0 var(--s-2); font-size: var(--t-xs); font-weight: 700;
  letter-spacing: .14em; color: var(--c-ink-faint);
}

/* 清单本身。左边一条细轨，当前节那一格亮起来——
   「读到哪」由这一格回答，所以清单可以一直是全的，不用折叠。 */
.sidenav__list { list-style: none; margin: 0; padding: 0; counter-reset: toc;
  border-inline-start: 2px solid var(--c-line-soft); }
.sidenav__list li { counter-increment: toc; }
.sidenav__list a {
  position: relative; display: flex; gap: var(--s-2);
  padding: var(--s-2) var(--s-3); margin-inline-start: -2px;
  border-inline-start: 2px solid transparent;
  color: var(--c-ink-dim); font-size: var(--t-sm); line-height: 1.5;
  background-image: none;
  transition: color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
.sidenav__list a::before {
  content: counter(toc, decimal-leading-zero); flex: none;
  font-family: var(--font-mono); font-size: var(--t-xs); line-height: 1.7;
  color: var(--c-ink-faint); font-variant-numeric: tabular-nums;
}
.sidenav__list a:hover { color: var(--c-ink); text-decoration: none;
  border-inline-start-color: var(--c-line); }
.sidenav__list a[aria-current] {
  color: var(--c-ink); font-weight: 600;
  border-inline-start-color: var(--c-gold);
  background: color-mix(in srgb, var(--c-gold) 12%, transparent);
}
.sidenav__list a[aria-current]::before { color: var(--c-gold); }
.sidenav__text { min-width: 0; }
/* 第二级：只在正在读的那一节下面展开。缩进对齐到上一级的文字，不编号，字小一档 */
.sidenav__sub { list-style: none; margin: 0 0 var(--s-2); padding: 0; padding-inline-start: 2.1rem; }
.sidenav__sub a {
  display: block; padding: 5px var(--s-3) 5px var(--s-2);
  margin-inline-start: 0; border-inline-start: 0; border-radius: var(--r-sm);
  font-size: var(--t-xs); line-height: 1.55; color: var(--c-ink-faint);
}
.sidenav__sub li { counter-increment: none; }
.sidenav__sub a::before { content: none; }
.sidenav__sub a:hover { color: var(--c-ink); }
.sidenav__sub a[aria-current] { color: var(--c-ink); font-weight: 600; background: color-mix(in srgb, var(--c-gold) 10%, transparent); }

/* 抽屉档：盖在正文上，就得宽一点、厚一点，并且配一层遮罩 */
@media (max-width: 1023px) {
  .sidenav { width: min(19rem, 84vw); box-shadow: var(--shadow-lg); }
}
.scrim {
  position: fixed; z-index: 22; inset: var(--topbar-h) 0 0 0;
  border: none; padding: 0; cursor: pointer;
  background: color-mix(in srgb, var(--c-bg-sink) 72%, transparent);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  animation: scrim-in var(--dur-fast) var(--ease);
}
@keyframes scrim-in { from { opacity: 0; } }

/* ── 顶栏下的位置条 ───────────────────────────────────────────────────
   只在「看不到侧栏」的时候出现（侧栏收着，或者屏幕窄到侧栏是抽屉），
   而且要滚过标题区才出现。侧栏开着时当前节已经在左边高亮着，再说一遍是噪音。
   它是浮层，不占版面：收起时整条移出屏幕，正文的位置一像素都不动。 */
.readbar {
  position: fixed; z-index: 26; inset-inline: 0; top: var(--topbar-h);
  padding-inline-start: var(--nav-w);
  transform: translateY(-100%); opacity: 0;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease),
              padding-inline-start var(--dur) var(--ease);
  pointer-events: none;
}
.readbar[data-show='true'] { transform: none; opacity: 1; }
/* 分两层：玻璃铺在外层、横贯整幅（.page 的 max-width 只管版心，铺不满一整条），
   里面那层才是 .page + 按钮。 */
/* 它紧贴在顶栏下面，和顶栏是同一块玻璃：底色、模糊都用外壳玻璃那一组（tokens.css --c-chrome-glass），
   两条之间只隔顶栏那道极淡的厚度线。磨砂够重，正文的字透上来只剩一团明暗，压不花这条上的字 */
.readbar {
  background: var(--c-chrome-glass);
  -webkit-backdrop-filter: blur(var(--chrome-blur)) saturate(1.6);
  backdrop-filter: blur(var(--chrome-blur)) saturate(1.6);
  box-shadow: 0 1px 0 var(--c-glass-line);
}
.readbar__inner {
  display: flex; align-items: center; gap: var(--s-2);
  height: 44px; border: none; cursor: pointer; text-align: start;
  background: none;
  color: var(--c-ink-dim); font-size: var(--t-xs);
  pointer-events: auto;
}
.readbar__inner:hover { color: var(--c-ink); }
.readbar__inner:hover .readbar__sec { color: var(--c-gold); }
.readbar__title {
  flex: 0 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.readbar__sep { flex: none; opacity: .5; }
/* 手机上这一条放不下「文章标题 / 当前节」两截，两截都被省略号截断，哪截都看不全。
   文章标题读者刚看过、顶栏下也不缺它，窄屏只留当前节和进度 */
@media (max-width: 743px) {
  .readbar__title, .readbar__sep { display: none; }
}
/* 当前节是这条的主角：它不许被标题挤没，所以标题先缩，它后缩 */
.readbar__sec {
  flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
  color: var(--c-ink); font-weight: 600;
  transition: color var(--dur-fast) var(--ease);
}

/* ── 场景实验室（仅开发环境）───────────────────────────── */
.lab__bar { position: sticky; top: 0; z-index: 10; display: flex; align-items: center; gap: var(--s-5);
  padding: var(--s-4) 0; flex-wrap: wrap;
  background: linear-gradient(var(--c-glass), var(--c-glass-tint));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.7);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.7);
  box-shadow: 0 1px 0 var(--c-line-soft); }
.lab__bar h1 { font-size: var(--t-lg); margin: 0; }
.lab__bar label { display: flex; align-items: center; gap: var(--s-3); font-size: var(--t-sm); color: var(--c-ink-dim); }
.lab__bar input[type=range] { width: 16rem; accent-color: var(--c-gold); }
.lab__scene { margin: var(--s-7) 0; }
.lab__scene h2 { font-size: var(--t-sm); color: var(--c-gold); font-family: var(--font-mono); margin-bottom: var(--s-3); }
.lab__scene h2 small { color: var(--c-ink-faint); margin-left: var(--s-3); }
.lab__strip { display: grid; gap: var(--s-4); grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); }
.lab__grid { display: grid; gap: var(--s-2); grid-template-columns: repeat(4, minmax(0, 1fr)); }
.lab__frame { margin: 0; background: var(--c-bg-sink); border-radius: var(--r-md); overflow: hidden; }
.lab__frame figcaption { padding: var(--s-2) var(--s-3); font-size: var(--t-xs);
  color: var(--c-ink-faint); font-family: var(--font-mono); }
.lab--solo .lab__strip { grid-template-columns: 1fr; }

/* ── 读完这一节之后往哪走 ─────────────────────────────────────────────
   两块并排，左边上一节、右边下一节，各占一半。

   为什么两边都写标题：读者在这儿要做的决定是"接着读，还是回目录"，
   而这个决定取决于下一节讲什么。只给一个「下一节 →」，等于让他点进去才知道。

   没有上一节（或下一节）时留一个空位（.prevnext__gap），不把剩下那块拉宽——
   最后一节的"上一节"跳到左边、独占整行，会让人以为那是"下一节"。 */
.prevnext {
  display: grid; gap: var(--s-4);
  grid-template-columns: 1fr 1fr;
  margin-top: var(--s-9);
  padding-top: var(--s-6);
  border-top: 1px solid var(--c-line-soft);
}
.prevnext__gap { display: block; }
.prevnext__side {
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-4) var(--s-5);
  border-radius: var(--r-lg);
  background: var(--c-bg-raise);
  box-shadow: inset 0 0 0 1px var(--c-line-soft);
  color: var(--c-ink); background-image: none;
  transition: box-shadow var(--dur) var(--ease), background var(--dur-fast) var(--ease);
}
.prevnext__side:hover {
  text-decoration: none; color: var(--c-ink);
  box-shadow: inset 0 0 0 1px var(--c-line), var(--shadow-md);
}
/* 下一节靠右排：方向感由版面给，不靠多写一个箭头 */
.prevnext__side[data-dir='next'] { text-align: end; align-items: flex-end; }
.prevnext__dir {
  display: inline-flex; align-items: center; gap: var(--s-2);
  font-size: var(--t-xs); color: var(--c-ink-faint);
}
.prevnext__side:hover .prevnext__dir { color: var(--c-gold); }
.prevnext__title {
  font-family: var(--font-display); font-weight: 700; font-size: var(--t-sm);
  line-height: 1.45;
}

/* 手机上并排两块各只剩一半宽，标题要折三行。叠成上下两块。 */
@media (max-width: 559px) {
  .prevnext { grid-template-columns: 1fr; }
  .prevnext__gap { display: none; }
}

/* Account settings share the reading theme tokens. */
.account-avatar { display: block; flex-shrink: 0; border-radius: 26%; object-fit: cover; }
.account-page { max-width: 44rem; padding-block: 3rem; }
.account-page h1 { margin-bottom: 2rem; }
.account-section { display: grid; gap: 1.1rem; padding-block: 1.5rem; }
.account-section .login__form { max-width: 30rem; }
.account-actions { display: flex; flex-wrap: wrap; gap: .75rem; }
.account-hint { color: var(--c-ink-dim); font-size: .9rem; line-height: 1.7; margin-block: 1rem; }
.password-strength { display: flex; align-items: center; flex-wrap: wrap; gap: .75rem; }
.password-strength meter { width: 8rem; }
.avatar-editor { display: grid; gap: 1rem; max-width: 26rem; }
.avatar-editor canvas { width: min(100%, 256px); aspect-ratio: 1; background: var(--c-bg-raise); }
.avatar-editor input { max-width: 100%; }
.account-dialog { margin: auto; padding: 2rem; width: min(32rem, calc(100% - 2rem)); border: 0; border-radius: 1rem; background: var(--c-bg-raise); color: var(--c-ink); }
.account-dialog::backdrop { background: rgb(0 0 0 / .45); }
.account-dialog p { margin-block: 1.2rem; }
.learning-progress { padding-block: 2rem; display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; }
.progress-tag[data-completed="true"] { color: var(--c-on-accent); background: var(--c-accent-bg); }

.field > .field__input { padding: var(--s-3) var(--s-4); border-radius: var(--r-md); background: var(--c-glass-tint); box-shadow: inset 0 0 0 1px var(--c-glass-line); }
.field > .field__input:focus { box-shadow: inset 0 0 0 2px var(--c-accent-bg); }
.login__col > .account-avatar { margin-block: 1rem; }

.login__exit { margin-block-start: var(--s-6); }
.account-avatar[data-avatar-style] { overflow: hidden; background: var(--c-bg-raise); }

.password-toggle { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 2.25rem; width: 2.25rem; height: 2.25rem; margin-block: -.4rem; padding: 0; border: 0; border-radius: var(--r-md); background: transparent; color: var(--c-ink-dim); cursor: pointer; }
.password-toggle:hover { color: var(--c-ink); background: var(--c-glass-hover); }
.password-toggle:focus-visible { outline: 2px solid var(--c-accent-bg); outline-offset: 2px; }
.password-toggle:disabled { cursor: default; opacity: .5; }

/* 表单里的下拉（Select variant="field"）：和输入框一个样子，窄屏也显示当前值 */
.sel--field { width: 100%; }
.sel--field .sel__btn {
  width: 100%; max-width: none; min-height: 44px; justify-content: space-between;
  padding: 0 12px; border: 1px solid var(--c-line); border-radius: var(--r-md);
  background: var(--c-glass); color: var(--c-ink); font: 400 16px/1.4 var(--font-body);
}
.sel--field .sel__btn:hover, .sel--field .sel__btn.is-open { border-color: var(--c-gold); background: var(--c-glass-hover); }
.sel--field .sel__btn:disabled { cursor: not-allowed; opacity: .55; }
.sel--field .sel__value, .sel--field .sel__chev { display: inline-block; }
.sel--field .sel__value { text-align: start; }
.sel--field .sel__list { left: 0; right: auto; min-width: 100%; }
.sel--field .sel__opt { font-size: var(--t-sm); }
.sel__group { padding: var(--s-2) var(--s-3) var(--s-1); color: var(--c-ink-faint); font-size: var(--t-xs); letter-spacing: .04em; }
.sel__group:not(:first-child) { margin-top: var(--s-1); border-top: 1px solid var(--c-line-soft); }

/* 日期（components/DatePicker.tsx）：弹层和下拉同一块玻璃，里面是一张月历 */
.datepick__pop { width: 18.5rem; max-height: none; padding: var(--s-2); }
.datepick__head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); padding: 2px 2px var(--s-2); }
.datepick__month { font-weight: 700; font-size: var(--t-sm); color: var(--c-ink); white-space: nowrap; }
.datepick__nav, .datepick__day, .datepick__today { border: 0; background: transparent; color: var(--c-ink-dim); font: inherit; cursor: pointer; border-radius: var(--r-sm); }
.datepick__nav { display: inline-grid; place-items: center; width: 36px; height: 36px; }
.datepick__nav:hover, .datepick__day:hover, .datepick__today:hover { background: var(--c-glass-hover); color: var(--c-ink); }
.datepick__row { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 2px; }
.datepick__wd { display: block; padding: 4px 0; color: var(--c-ink-faint); font-size: var(--t-xs); white-space: nowrap; text-align: center; }
.datepick__day { height: 36px; font-size: var(--t-sm); font-variant-numeric: tabular-nums; white-space: nowrap; text-align: center; }
.datepick__day[data-out] { color: var(--c-ink-faint); opacity: .6; }
.datepick__day[data-today] { box-shadow: inset 0 0 0 1px var(--c-line); color: var(--c-ink); }
.datepick__day[data-on] { background: var(--c-gold); color: var(--c-bg); font-weight: 700; }
.datepick__day:focus-visible, .datepick__nav:focus-visible, .datepick__today:focus-visible { outline: 2px solid var(--c-gold); outline-offset: 1px; }
.datepick__foot { display: flex; justify-content: flex-end; padding-top: var(--s-2); margin-top: var(--s-1); border-top: 1px solid var(--c-line-soft); }
.datepick__today { padding: 6px 12px; font-size: var(--t-xs); font-weight: 600; color: var(--c-gold); }
/* Shared interaction and layout. Each art direction then supplies its own surfaces and geometry. */
:root { --topbar-h: 72px; }
.app__main { min-height: calc(100dvh - var(--topbar-h)); display: flex; flex-direction: column; }
.app__main > main { flex: 1; }
.app__main:focus { outline: none; }
.page { max-width: 1360px; }
.topbar .topbar__inner.page { max-width: none; padding-inline: var(--chrome-pad) clamp(16px, 3vw, 48px); }
/* 左侧必须读 --chrome-pad：左上角开关要和侧栏目录的文字左缘对齐（见 app.css 的 --chrome-pad）。
   原来这里是 1600 居中 + clamp 内边距，开关比目录文字靠右了近 20px。 */
.topbar__left { gap: 12px; }
.topbar__brand { font-size: 20px; font-weight: 800; gap: 10px; letter-spacing: 0; line-height: 30px; }
/* 站标和站名一样高：站标线稿的高度等于站名汉字的墨迹高度（20px 粗体约 19px），不是行高 */
.brand-symbol { flex: none; width: 20px; height: 20px; color: var(--c-ink); }
.brand-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.navtoggle { width: 34px; height: 34px; margin-inline-end: 0; border: 1px solid var(--c-line); border-radius: 8px; background: var(--c-bg-raise); color: var(--c-ink-dim); }
.navtoggle[data-on='true'] { color: var(--c-gold); border-color: color-mix(in srgb, var(--c-gold) 28%, var(--c-bg)); background: color-mix(in srgb, var(--c-accent-bg) 5%, var(--c-bg-raise)); }
.navtoggle:hover { border-color: var(--c-gold); background: var(--c-bg-raise); }
.topbar__nav { gap: 24px; }
.topbar__controls { gap: 8px; }
/* 顶栏右侧所有控件同高 40px（和头像、会员入口一致）：设置组外框 40，里面的按钮 34 */
.topbar__controls { height: 40px; padding: 3px; box-sizing: border-box; }
.topbar__controls .sel__btn, .topbar__controls .theme-picker__trigger { height: 34px; min-height: 34px; padding-block: 0; box-sizing: border-box; }
.topbar__controls .schemer { height: 34px; padding: 3px; box-sizing: border-box; }
.topbar__controls .schemer__slide { top: 3px; left: 3px; width: 28px; height: 28px; }
.topbar__catalog { color: var(--c-ink-dim); font-size: 13px; white-space: nowrap; }
.btn { min-height: 44px; padding: 12px 22px; white-space: nowrap; }
.btn--sm { min-height: 36px; padding: 8px 16px; font-size: 13px; }
.btn--primary { gap: 24px; }
.schemer { padding: 4px; }
.schemer__slide { top: 4px; left: 4px; width: 28px; height: 28px; }
.schemer__opt { height: 28px; }
.footer { display: flex; justify-content: space-between; align-items: center; gap: 24px; padding-block: 32px; margin-top: 32px; border-top: 1px solid var(--c-line); }
.footer__note { display: block; margin-top: 4px; color: var(--c-ink-dim); }
.footer a { white-space: nowrap; color: var(--c-ink-dim); }
.skip-link { position: fixed; top: -100px; left: 16px; z-index: 100; padding: 12px 20px; background: var(--c-bg-raise); }
.skip-link:focus { top: 12px; }
.icon-button { display: grid; place-items: center; width: 32px; height: 32px; border: 0; border-radius: var(--r-sm); background: transparent; font-size: 24px; cursor: pointer; }
.icon-button:hover { background: var(--c-glass-hover); color: var(--c-gold); }
.icon-button .line-icon { display: block; }

/* Four live previews. The card tokens are scoped, so every option previews its own style. */
.theme-picker { position: relative; }
.theme-picker__trigger { display: flex; align-items: center; gap: 9px; border: 1px solid var(--c-line); background: var(--c-bg-raise); color: var(--c-ink); border-radius: var(--r-md); padding: 8px 12px; min-height: 36px; font-size: 13px; cursor: pointer; white-space: nowrap; }
.theme-picker__trigger:hover, .theme-picker__trigger[aria-expanded='true'] { border-color: var(--c-gold); }
.theme-picker__panel { position: absolute; z-index: 45; top: calc(100% + 18px); right: -72px; width: 440px; padding: 22px; background: var(--c-bg-raise); border: 1px solid var(--c-line); border-radius: var(--r-lg); box-shadow: var(--shadow-lg); max-height: calc(100dvh - var(--topbar-h) - 24px); overflow-y: auto; overscroll-behavior: contain; }
.theme-picker__heading { display: flex; align-items: start; justify-content: space-between; gap: 12px; margin-bottom: 18px; }
.theme-picker__heading h2 { font-size: 17px; font-family: var(--font-display); }
.theme-picker__heading p, .theme-picker__foot { margin: 4px 0 0; font-size: 12px; color: var(--c-ink-dim); line-height: 1.6; }
.theme-picker__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.theme-card { min-width: 0; text-align: left; cursor: pointer; color: var(--c-ink); background: var(--c-bg); padding: 0 0 12px; border: 1px solid var(--c-line); border-radius: 8px; overflow: hidden; }
.theme-card:hover { border-color: var(--c-gold); }
.theme-card[aria-pressed='true'] { outline: 2px solid var(--c-gold); outline-offset: 2px; }
.theme-card__preview { position: relative; display: block; height: 84px; border-bottom: 1px solid var(--c-line); overflow: hidden; }
.theme-card__lines { position: absolute; left: 14px; top: 25px; width: 45%; }
.theme-card__lines i { display: block; height: 4px; margin-bottom: 6px; width: 90%; background: var(--c-ink); border-radius: 4px; }
.theme-card__lines i:nth-child(2) { width: 60%; }
.theme-card__lines i:nth-child(3) { height: 9px; width: 26%; margin-top: 10px; background: var(--c-accent-bg); }
.theme-card__art { position: absolute; display: block; right: 2px; top: 3px; width: 48%; height: 78px; }
.theme-card__art .heroart__object { display: block; position: static; width: 100%; height: 100%; max-height: none; transform: none; }
.theme-card__check { position: absolute; display: grid; place-items: center; right: 7px; top: 7px; width: 20px; height: 20px; border-radius: 50%; background: var(--c-bg-raise); font: 12px var(--font-body); }
.theme-card__check:empty { display: none; }
.theme-card__name { display: flex; justify-content: space-between; gap: 8px; margin: 10px 12px 3px; font: 600 15px var(--font-display); }
.theme-card__name > span { font: 10px var(--font-mono); color: var(--c-ink-dim); align-self: center; }
.theme-card__hint { display: block; margin-inline: 12px; font: 11px/1.6 var(--font-body); color: var(--c-ink-dim); }
.theme-picker__foot { margin-top: 18px; }
/* The opening spreads: one reading order on every screen. */
.hero { display: flex; align-items: center; min-height: 460px; margin: 0; padding: 60px 0 48px; overflow: hidden; }
.hero__body { max-width: 640px; }
.hero__eyebrow { display: flex; align-items: center; gap: 10px; margin-bottom: 24px; font-size: 12px; color: var(--c-ink-dim); }
.hero__eyebrow > span { width: 6px; height: 6px; border-radius: 50%; background: var(--c-accent-bg); }
.hero__title { font-size: clamp(34px, 4.2vw, 60px); letter-spacing: -.045em; line-height: 1.2; }
.hero__sub { max-width: 29em; font-size: clamp(15px, 1.4vw, 18px); line-height: 1.9; margin-top: 24px; }
.hero__actions { display: flex; align-items: center; gap: 30px; margin-top: 32px; }
.hero__actions .btn { flex: none; }
.hero__explore { display: inline-flex; align-items: center; gap: 14px; color: var(--c-ink); font-size: 13px; }
.hero__stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); padding-block: 24px; margin: 0; border-block: 1px solid var(--c-line); gap: 0; }
.stat { padding-inline: 28px; border-inline-start: 1px solid var(--c-line); flex-direction: row; align-items: baseline; gap: 12px; }
.stat:first-child { padding-left: 0; border: 0; }
.stat__n { font-size: clamp(24px, 2.5vw, 34px); font-weight: 500; letter-spacing: -.06em; }
.stat__label { font-size: 12px; white-space: nowrap; }
.catalog__rule { margin: 18px 0 0; font-size: 12px; line-height: 1.8; }
.heroart__object { position: absolute; right: 0; top: 50%; transform: translateY(-50%); width: 44%; max-height: 100%; height: auto; }
.hero:has(.heroart__object) .hero__body { width: 56%; }

/* Discovery stays separate from access rules: “published” never implies “unlocked”. */
.catalog-tools { margin-block: 48px 28px; scroll-margin-top: calc(var(--topbar-h) + 20px); }
.catalog-tools__heading, .catalog__section-label { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin-bottom: 20px; }
.catalog-tools__heading h2, .catalog-tools__heading h3, .catalog__section-label h2 { font: 600 20px/1.5 var(--font-display); }
.catalog-tools__heading > span, .catalog__section-label > span { color: var(--c-ink-dim); font-size: 12px; }
.catalog-tools__row { display: flex; gap: 12px; }
.catalog-search { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0; padding: 0 16px; border: 1px solid var(--c-line); background: var(--c-bg-raise); border-radius: var(--r-md); color: var(--c-ink-dim); }
.catalog-search:focus-within { border-color: var(--c-gold); box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-gold) 12%, transparent); }
.catalog-search > svg { flex: none; }
.catalog-search input { width: 100%; min-width: 0; background: transparent; border: 0; padding-block: 14px; font: 14px var(--font-body); color: var(--c-ink); outline: none; }
.catalog-search input::placeholder { color: var(--c-ink-dim); }
.catalog-filter { display: inline-flex; gap: 9px; align-items: center; flex: none; padding-inline: 18px; font-size: 13px; border: 1px solid var(--c-line); background: var(--c-bg-raise); border-radius: var(--r-md); cursor: pointer; }
.catalog-filter[aria-pressed='true'] { color: var(--c-gold); border-color: var(--c-gold); background: color-mix(in srgb, var(--c-accent-bg) 8%, var(--c-bg)); }
.catalog-filter__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--c-ink-dim); }
.catalog-filter[aria-pressed='true'] .catalog-filter__dot { background: var(--c-gold); }
.domain-jumps { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.domain-jumps a { display: flex; gap: 7px; align-items: center; padding: 5px 9px; border: 1px solid transparent; border-radius: var(--r-sm); color: var(--c-ink-dim); font-size: 12px; background-image: none; }
.domain-jumps a:hover { background: var(--c-bg-raise); border-color: var(--c-line); color: var(--c-gold); }
.domain-jumps a > span { font: 10px var(--font-mono); opacity: .7; }
.catalog__section-label { margin: 40px 0 20px; }
.band { scroll-margin-top: calc(var(--topbar-h) + 20px); padding: 32px; }
.band--meta { margin-bottom: 0; }
.band__eyebrow { display: block; color: var(--c-gold); font: 12px var(--font-mono); margin-bottom: 16px; }
.band__title { font-size: 24px; }
.band--meta .band__title { font-size: 28px; }
.band__lead { max-width: 26em; }
.topic__sum { min-height: 52px; }
.topic__kps { padding-block: 8px; }
.kplink { min-height: 42px; }
.search-results { --tone: var(--c-gold); }
.search-results__count { font-size: 13px; color: var(--c-ink-dim); }
.search-results > ul { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; padding: 0; margin: 0 0 24px; list-style: none; }
.search-results > ul > li { padding: 16px; border: 1px solid var(--c-line); border-radius: var(--r-md); background: var(--c-bg-raise); }
.search-results__context { font-size: 11px; color: var(--c-ink-dim); margin: 0 12px 6px; }
.search-results__empty { text-align: start; padding: 32px; }
.search-results__empty p { font-size: 14px; color: var(--c-ink-dim); margin-top: 12px; }

/* Reading and account flows: shared type and controls, independent compositions. */
.kp__head { padding-bottom: 28px; border-bottom: 1px solid var(--c-line); margin-bottom: 32px; }
.kp__title { letter-spacing: -.025em; }
.kp__tools { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 44px; margin-bottom: 22px; }
.quiet-link { display: inline-flex; align-items: center; gap: 8px; padding: 6px 0; border: 0; background: none; color: var(--c-ink-dim); font: 13px/1.6 var(--font-body); cursor: pointer; text-decoration: none; }
.quiet-link:hover { color: var(--c-gold); }
.prevnext { gap: 16px; }
.prevnext__heading { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 8px; color: var(--c-ink-dim); font-size: 14px; }
.prevnext__side { padding: 24px; border: 1px solid var(--c-line-soft); background: var(--c-bg-raise); box-shadow: none; }
.prevnext__side[data-dir='next'] { text-align: start; align-items: flex-start; background: color-mix(in srgb, var(--c-accent-bg) 5%, var(--c-bg-raise)); }
.prevnext__side:hover { box-shadow: none; border-color: var(--c-gold); }
.prevnext__dir { width: 100%; font-size: 13px; }
.prevnext__side[data-dir='next'] .prevnext__dir { justify-content: space-between; }
.prevnext__title { font-size: 17px; font-weight: 600; line-height: 1.6; }
.prevnext__meta { color: var(--c-ink-dim); font-size: 12px; margin-top: 4px; }
.prevnext[data-single] { grid-template-columns: 1fr; }
.prevnext[data-single] .prevnext__gap { display: none; }
.wall { border: 0; box-shadow: none; background: var(--c-bg-raise); padding: 36px 40px; }
.wall__lead { margin-inline: 0; }
.wall__acts { justify-content: flex-start; margin-top: 24px; }
.wall .state-art { width: 144px; margin: -8px 0 12px -18px; }
.page-art { width: 100%; min-width: 0; pointer-events: none; }
.page-art svg { overflow: visible; }
.page-art__sand { animation: page-art-sand 1s linear infinite; }
@keyframes page-art-sand { to { stroke-dashoffset: -14; } }
.state-art { width: 200px; max-width: 100%; color: var(--c-gold); }
.page-state { display: grid; place-items: center; min-height: 65dvh; padding-block: 80px; }
.page-state__body { display: grid; grid-template-columns: 200px minmax(0, 380px); column-gap: 40px; align-items: center; max-width: 640px; text-align: start; }
.page-state__body > .state-art { grid-row: 1 / 4; }
.page-state h1 { font: 600 28px/1.4 var(--font-display); align-self: end; }
.page-state p { margin: 12px 0 24px; font-size: 15px; line-height: 1.8; color: var(--c-ink-dim); }
.page-state__actions { display: flex; flex-wrap: wrap; justify-content: flex-start; gap: 12px; align-self: start; }
.search-results__empty .state-art { width: 150px; margin-bottom: 16px; }
.login { display: grid; grid-template-columns: minmax(0, 1.12fr) minmax(0, 1fr); align-items: center; gap: clamp(40px, 7vw, 104px); padding-block: 48px; min-height: calc(100dvh - 220px); }
.login__story { position: relative; display: flex; flex-direction: column; min-height: 580px; align-self: stretch; overflow: hidden; background: var(--c-bg-raise); border: 0; border-radius: var(--r-lg); }
.login__story-copy { position: relative; padding: 40px 40px 0; }
.login__story h2 { font: 600 clamp(30px, 3.2vw, 44px)/1.35 var(--font-display); letter-spacing: -.035em; white-space: pre-line; }
.login__story-copy > p:last-child { max-width: 26em; margin-top: 20px; font-size: 15px; line-height: 1.9; color: var(--c-ink-dim); }
.login__story > .page-art { width: 94%; margin: auto auto 0; }
.login__story-foot { padding: 12px 40px 30px; font-size: 12px; color: var(--c-ink-dim); }
.login__col { max-width: 384px; padding-block: 24px; }
.login__back { margin-bottom: 28px; }
.login__step { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; color: var(--c-ink-dim); font: 12px var(--font-body); }
.login__step-track { display: flex; gap: 4px; }
.login__step-track i { width: 22px; height: 3px; border-radius: 2px; background: var(--c-line); }
.login__step-track i:first-child, .login__step-track[data-step='code'] i { background: var(--c-gold); }
.login__title { font-size: 34px; letter-spacing: -.025em; line-height: 1.35; }
.login__lead { margin-bottom: 28px; font-size: 15px; line-height: 1.8; }
.login__form { gap: 20px; }
.login__form .btn { min-height: 50px; }
.field__box { min-height: 54px; background: var(--c-glass-tint); backdrop-filter: blur(var(--glass-blur)); }
.field__label { color: var(--c-ink-dim); font-size: 13px; }
.login__alt .linkbtn { min-height: 44px; font-size: 13px; }
.devbox { margin-top: 28px; padding: 14px 0; border: 0; border-top: 1px dashed var(--c-line); border-radius: 0; }
.devbox__title { cursor: pointer; }
.devbox__lead { margin-block: 14px; }
.buy { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); align-items: center; gap: clamp(40px, 7vw, 104px); padding-block: 48px 64px; }
.buy__story { min-width: 0; }
.buy__story-copy { margin-top: 32px; }
.buy__story h2 { font: 600 clamp(32px, 3.2vw, 44px)/1.4 var(--font-display); letter-spacing: -.03em; white-space: pre-line; }
.buy__story-copy > p:last-child { max-width: 28em; margin-top: 20px; font-size: 15px; line-height: 1.9; color: var(--c-ink-dim); }
.buy__story > .page-art { width: min(480px, 100%); margin: 12px 0 0; }
.buy__caption { font-size: 13px; color: var(--c-ink-dim); margin-top: 8px; }
.buy__card { min-width: 0; width: 100%; max-width: 456px; padding: clamp(28px, 3vw, 44px); background: var(--c-bg-raise); border-radius: var(--r-lg); border: 1px solid var(--c-line-soft); }
.buy__plan-label { margin: 0 0 12px; color: var(--c-gold); font-size: 13px; }
.buy__price { margin-block: 28px 20px; gap: 10px; }
.buy__num { font-size: clamp(52px, 5vw, 68px); font-weight: 500; letter-spacing: -.055em; }
.buy__perks { gap: 16px; margin-block: 28px; }
.buy__perks li { font-size: 14px; line-height: 1.7; }
.buy__availability { margin: 0 0 24px; padding-block: 18px; border-block: 1px solid var(--c-line-soft); font-size: 12px; color: var(--c-ink-dim); line-height: 1.8; }
.buy__payment-note { margin: 14px 0 0; font-size: 12px; line-height: 1.7; color: var(--c-ink-dim); }
.buy__card .btn--block { min-height: 50px; white-space: normal; text-align: start; }
.buy__state-art { width: 156px; margin: -8px 0 12px -18px; }
.buy__qr { width: min(240px, 100%); margin-block: 24px; }
.buy__waiting { display: flex; align-items: center; gap: 8px; font-size: 13px; line-height: 1.7; color: var(--c-gold); }
.buy__waiting > span { flex: none; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.buy__card .login__err { margin-block: 12px; }
.buy__card > .quiet-link { margin-top: 12px; }
.topbar__admin { gap: 7px; padding-inline: 10px; }
.topbar__admin[aria-current='page'] { color: var(--c-gold); background: var(--c-glass-hover); }

/* Crayon: a considered notebook. Colour belongs to the drawing; controls stay calm. */
:root[data-style='crayon-book'] body {
  background-image: radial-gradient(color-mix(in srgb, var(--c-ink) 3%, transparent) .8px, transparent 1px);
  background-size: 24px 24px;
}
:root[data-style='crayon-book'] .hero__eyebrow > span { width: 8px; height: 8px; border-radius: 40% 55% 45% 60%; }
:root[data-style='crayon-book'] .hero__title { letter-spacing: -.025em; }
:root[data-style='crayon-book'] .hero__stats { border: 1px solid var(--c-line); border-radius: var(--r-lg); background: var(--c-bg-raise); }
:root[data-style='crayon-book'] .stat:first-child { padding-left: 28px; }
:root[data-style='crayon-book'] .band { box-shadow: inset 0 0 0 1px var(--c-line-soft); }
:root[data-style='crayon-book'] .band::before { top: 0; bottom: auto; left: 32px; width: 36px; height: 3px; border-radius: 0 0 4px 4px; }
:root[data-style='crayon-book'] .band--meta { background: linear-gradient(135deg, color-mix(in srgb, var(--c-accent-bg) 4%, var(--c-bg-raise)), var(--c-bg-raise) 55%); }
:root[data-style='crayon-book'] .band__no { display: inline-grid; place-items: center; min-width: 42px; min-height: 42px; padding: 6px; border-radius: 14px; background: color-mix(in srgb, var(--tone) 9%, transparent); font-size: 19px; margin-bottom: 16px; }
:root[data-style='crayon-book'] .topic__fold[open] .topic__sum { background: color-mix(in srgb, var(--c-accent-bg) 5%, transparent); }
:root[data-style='crayon-book'] .domain-jumps a { background: var(--c-bg-raise); border-color: var(--c-line-soft); border-radius: var(--r-md); }
:root[data-style='crayon-book'] .login__story { background: linear-gradient(145deg, color-mix(in srgb, var(--c-accent-bg) 4%, var(--c-bg-raise)), var(--c-bg-raise) 55%); }
:root[data-style='crayon-book'] .wall { background: linear-gradient(145deg, color-mix(in srgb, var(--c-accent-bg) 3%, var(--c-bg-raise)), var(--c-bg-raise) 60%); }

/* Watercolor: the same structure with quiet paper surfaces and pigment-soft boundaries. */
:root[data-style='watercolor'] body {
  background-image: radial-gradient(color-mix(in srgb, var(--c-ink) 2%, transparent) .5px, transparent 1px),
    radial-gradient(ellipse at 85% 0%, color-mix(in srgb, var(--c-accent-bg) 3%, transparent), transparent 60%);
  background-size: 7px 9px, 100% 100%;
  background-position: 0 0;
  background-repeat: repeat, no-repeat;
}
:root[data-style='watercolor'] .hero__title { letter-spacing: .01em; font-weight: 600; }
:root[data-style='watercolor'] .hero__eyebrow > span { width: 24px; height: 2px; border-radius: 50%; opacity: .6; }
:root[data-style='watercolor'] .stat__n { color: var(--c-gold); }
:root[data-style='watercolor'] .hero__stats { border-color: color-mix(in srgb, var(--c-accent-bg) 17%, var(--c-bg)); }
:root[data-style='watercolor'] .band { background: color-mix(in srgb, var(--c-bg-raise) 78%, transparent); box-shadow: inset 0 0 0 1px var(--c-line-soft); }
:root[data-style='watercolor'] .band::before { top: 32px; bottom: 32px; left: 0; width: 2px; background: linear-gradient(transparent, color-mix(in srgb, var(--tone) 50%, transparent), transparent); }
:root[data-style='watercolor'] .band--meta { background: linear-gradient(135deg, color-mix(in srgb, var(--c-accent-bg) 4%, var(--c-bg-raise)), var(--c-bg-raise) 65%); }
:root[data-style='watercolor'] .band__title { font-weight: 600; }
:root[data-style='watercolor'] .band__no { font-weight: 400; margin-bottom: 16px; color: var(--c-gold); }
:root[data-style='watercolor'] .topic__fold[open] .topic__sum { background: color-mix(in srgb, var(--c-accent-bg) 4%, transparent); }
:root[data-style='watercolor'] .topic__sum, :root[data-style='watercolor'] .kplink { transition: background var(--dur) var(--ease), color var(--dur) var(--ease); }
:root[data-style='watercolor'] .btn--primary { box-shadow: inset 0 1px 0 color-mix(in srgb, var(--c-on-accent) 16%, transparent), 0 3px 12px color-mix(in srgb, var(--c-accent-bg) 8%, transparent); }
:root[data-style='watercolor'] .login__story { background: linear-gradient(150deg, var(--c-bg-raise), color-mix(in srgb, var(--c-accent-bg) 4%, var(--c-bg))); }
:root[data-style='watercolor'] .kp__head { border-bottom-color: color-mix(in srgb, var(--c-accent-bg) 20%, var(--c-bg)); }

/* Studio: editorial spacing, measured rules, squared controls, sculptural geometry. */
:root[data-style='studio'] body { background-image: none; }
:root[data-style='studio'] .topbar::after { background: var(--c-line); }
:root[data-style='studio'] .hero__eyebrow { font-family: var(--font-mono); }
:root[data-style='studio'] .hero__eyebrow > span { border-radius: 0; }
:root[data-style='studio'] .hero__title { font-weight: 500; }
:root[data-style='studio'] .btn, :root[data-style='studio'] .field__box { backdrop-filter: none; }
:root[data-style='studio'] .band { background: transparent; border-top: 1px solid var(--c-line); padding: 32px 0; box-shadow: none; border-radius: 0; }
:root[data-style='studio'] .band::before { display: none; }
:root[data-style='studio'] .band--meta { padding: 36px; background: var(--c-bg-raise); border: 1px solid var(--c-line); }
:root[data-style='studio'] .band__no { color: var(--c-gold); font-weight: 400; font-size: 38px; margin-bottom: 24px; }
:root[data-style='studio'] .band__title { font-weight: 500; }
:root[data-style='studio'] .topic__fold[open] { border-left: 2px solid var(--c-accent-bg); padding-left: 12px; }
:root[data-style='studio'] .login__story { border-radius: 0; }
:root[data-style='studio'] .kp__title { font-weight: 500; }
:root[data-style='studio'] .state-art { filter: none; }

/* Orbit: low-light instruments, luminous boundaries and quiet depth. */
:root[data-style='orbit'] body { background-image: radial-gradient(ellipse at 80% 0%, color-mix(in srgb, var(--c-accent-bg) 5%, transparent), transparent 60%); background-repeat: no-repeat; }
:root[data-style='orbit'] .hero__title { font-weight: 600; }
:root[data-style='orbit'] .hero__eyebrow { color: var(--c-gold); }
:root[data-style='orbit'] .hero__eyebrow > span { box-shadow: 0 0 12px var(--c-accent-bg); }
:root[data-style='orbit'] .heroart__object { filter: drop-shadow(0 0 24px color-mix(in srgb, var(--c-accent-bg) 9%, transparent)); }
:root[data-style='orbit'] .hero__stats { padding: 24px 0; border: 1px solid var(--c-line); border-radius: var(--r-lg); background: var(--c-bg-raise); }
:root[data-style='orbit'] .stat:first-child { padding-left: 28px; }
:root[data-style='orbit'] .stat__n { color: var(--c-gold); }
:root[data-style='orbit'] .band::before { top: 32px; bottom: auto; left: 0; height: 36px; width: 2px; box-shadow: 0 0 14px var(--tone); }
:root[data-style='orbit'] .band--meta { background: linear-gradient(120deg, color-mix(in srgb, var(--c-accent-bg) 6%, var(--c-bg-raise)), var(--c-bg-raise)); }
:root[data-style='orbit'] .btn--primary { box-shadow: 0 3px 20px color-mix(in srgb, var(--c-accent-bg) 10%, transparent); }
:root[data-style='orbit'] .login__story { background: linear-gradient(155deg, var(--c-bg-raise), var(--c-bg)); }
:root[data-style='orbit'] .state-art { filter: drop-shadow(0 0 10px color-mix(in srgb, var(--c-accent-bg) 12%, transparent)); }

@media (min-width: 1024px) {
  .band--meta { grid-template-columns: minmax(13rem, 17rem) 1fr; gap: 48px; }
}
@media (max-width: 1023px) {
  /* A rotating device must drop the desktop sidebar inset immediately. */
  .app__main { transition: none; }
  .readbar { padding-inline-start: 0; transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease); }
  .stat { flex-direction: column; gap: 8px; }
  .hero { min-height: 360px; }
  .hero__body { max-width: 65%; }
  .hero__actions { gap: 18px; }
  .hero__title { font-size: 40px; }
  .heroart__object { right: -4%; width: 46%; }
  .login { gap: 40px; }
  .login__story-copy { padding: 32px 24px 0; }
  .login__story-foot { padding-inline: 24px; }
  .buy { gap: 32px; }
}
@media (max-width: 743px) {
  :root { --topbar-h: 64px; }
  .topbar__nav { gap: 12px; }
  .topbar__catalog { display: none; }
  .topbar__brand { font-size: 16px; gap: 7px; line-height: 26px; }
  .topbar__left { min-width: 32px; gap: 8px; }
  .topbar__left:has(.navtoggle) { min-width: 74px; }
  .topbar__brand { min-width: 32px; }
  .brand-symbol { width: 16px; height: 16px; }
  .topbar__controls { gap: 5px; }
  .theme-picker__trigger { padding-inline: 8px; }
  .theme-picker__panel { position: fixed; top: calc(var(--topbar-h) + 8px); left: 12px; right: 12px; width: auto; max-width: 440px; margin-left: auto; padding: 18px; }
  .hero { min-height: 0; padding-block: 44px 36px; }
  .hero__body, .hero:has(.heroart__object) .hero__body { max-width: none; width: 100%; }
  .hero__title { font-size: 40px; }
  .hero__eyebrow { margin-bottom: 20px; font-size: 11px; }
  .hero__sub { font-size: 15px; max-width: 26em; margin-top: 18px; }
  .catalog .hero:has(.heroart__object) { display: block; padding-bottom: 224px; }
  .heroart__object { top: auto; bottom: 8px; right: 50%; transform: translateX(50%); width: 250px; height: 212px; }
  .hero__actions { gap: 24px; margin-top: 24px; }
  .hero__stats, :root[data-style='orbit'] .hero__stats { padding-block: 20px; }
  .stat { padding-inline: 12px; }
  :root:is([data-style='orbit'], [data-style='crayon-book']) .stat:first-child { padding-left: 16px; }
  .stat__n { font-size: 25px; }
  .stat__label { font-size: 11px; }
  .catalog-tools { margin-top: 32px; }
  .catalog-tools__heading, .catalog__section-label { align-items: start; flex-direction: column; gap: 5px; }
  .catalog-filter { padding-inline: 12px; font-size: 12px; }
  .catalog-tools__row { gap: 8px; }
  .catalog-search { padding-inline: 12px; gap: 8px; }
  .catalog-search input { font-size: 13px; }
  .domain-jumps { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 8px; }
  .domain-jumps a { flex: none; border-color: var(--c-line); }
  .band, :root[data-style='studio'] .band--meta { padding: 24px 20px; }
  .band__title { font-size: 22px; }
  .band--meta .band__title { font-size: 26px; }
  .band__lead { max-width: none; }
  .band__no, :root[data-style='studio'] .band__no { font-size: 26px; margin-bottom: 12px; }
  .search-results > ul { grid-template-columns: 1fr; }
  .topic__sum { gap: 8px; flex-wrap: wrap; }
  .topic__name { flex-basis: 60%; }
  .topic__n { margin-left: 35px; }
  .topic__kps { padding-left: 0; }
  .login { grid-template-columns: 1fr; padding-block: 24px; gap: 24px; }
  .login__story { min-height: 170px; display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); align-items: center; }
  .login__story-copy { padding: 24px 0 24px 24px; }
  .login__story .hero__eyebrow { margin-bottom: 12px; }
  .login__story h2 { font-size: 24px; }
  .login__story-copy > p:last-child, .login__story-foot { display: none; }
  .login__story > .page-art { width: 135%; margin: 0 0 0 -18%; }
  .login__col { margin-inline: auto; padding: 0 4px 24px; }
  .login__back { margin-bottom: 20px; }
  .login__step { margin-bottom: 16px; }
  .login__title { font-size: 28px; }
  .buy { grid-template-columns: 1fr; gap: 28px; padding-block: 24px 40px; }
  .buy__story { position: relative; }
  .buy__story-copy { margin-top: 20px; padding-right: 27%; }
  .buy__story .hero__eyebrow { margin-bottom: 12px; }
  .buy__story h2 { font-size: 28px; }
  .buy__story-copy > p:last-child { font-size: 14px; padding-right: 0; }
  .buy__story > .page-art { position: absolute; width: 40%; right: -4%; top: 50px; }
  .buy__caption { display: none; }
  .buy__card { max-width: none; padding: 28px; }
  .buy__price { margin-block: 20px; }
  .page-state { padding-block: 40px; }
  .page-state__body { grid-template-columns: minmax(0, 1fr); max-width: 380px; }
  .page-state__body > .state-art { grid-row: auto; width: 156px; margin: 0 0 20px -16px; }
  .page-state h1 { font-size: 25px; }
  .wall { padding: 24px; }
  .kp__tools .btn { font-size: 12px; }
  .topbar__admin { padding-inline: 8px; min-width: 34px; }
  .topbar__admin span { display: none; }
  .footer { margin-top: 16px; font-size: 11px; }
}
@media (max-width: 430px) {
  .topbar__inner { gap: 8px; }
  .topbar__brand { max-width: 122px; }
  .topbar__nav { gap: 8px; }
  .topbar__controls > .sel .sel__value, .topbar__controls > .sel .sel__chev { display: none; }
  .topbar__controls > .sel .sel__btn { padding: 8px 4px; }
  .topbar__controls > .sel .sel__icon { display: inline-flex; }
  .schemer__opt { width: 24px; }
  .schemer__slide { width: 24px; }
  .theme-picker__trigger > svg:last-child { display: none; }
  .theme-picker__trigger { gap: 6px; }
  .topbar:has(.navtoggle) .theme-picker__trigger > span { display: none; }
  .topbar:has(.navtoggle, .memberchip) .brand-name { display: none; }
  .topbar__nav > .btn { padding-inline: 10px; }
  .hero__title { font-size: 36px; }
  .hero__explore { font-size: 12px; gap: 8px; }
  .theme-card__hint { font-size: 10px; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .page-art__sand { animation: none; }
}
/* Account surfaces use the active illustration palette in both color schemes. */
/* 头像一律圆角方形（四种画风同一个形状），圆角按边长的比例，大小头像看起来一样圆 */
.account-avatar, .account-avatar[data-avatar-style] { border-radius: 26%; overflow: hidden; }
.account-avatar > svg { width: 100%; height: 100%; }
.account-page { max-width: 1100px; padding-block: clamp(28px, 4vw, 52px) 28px; }
.profile-heading { display: flex; align-items: center; justify-content: space-between; gap: 20px; margin-bottom: 28px; }
.profile-eyebrow { margin: 0 0 9px; color: var(--c-gold); font-size: 11px; font-weight: 650; letter-spacing: .14em; }
.account-page h1 { margin: 0 0 9px; font-size: clamp(27px, 3vw, 34px); line-height: 1.3; letter-spacing: -.035em; }
.profile-heading > div > p:last-child { color: var(--c-ink-dim); font-size: 14px; margin: 0; }
.profile-return { display: inline-flex; align-items: center; gap: 12px; min-height: 44px; font-size: 13px; color: var(--c-ink-dim); background: none; white-space: nowrap; }
.profile-return:hover { color: var(--c-gold); }
.profile-identity { display: flex; align-items: center; gap: 22px; padding: 28px 32px; background: linear-gradient(115deg, color-mix(in srgb, var(--c-accent-bg) 7%, var(--c-bg-raise)), var(--c-bg-raise) 65%); border-radius: 22px; position: relative; }
.profile-avatar-button { position: relative; flex: none; padding: 0; border: 0; border-radius: 26%; background: var(--c-bg); cursor: pointer; box-shadow: 0 0 0 4px var(--c-bg-raise), 0 0 0 5px var(--c-line-soft); transition: transform .22s ease; }
.profile-avatar-button:hover { transform: translateY(-2px); }
.profile-avatar-button:focus-visible { outline: 2px solid var(--c-gold); outline-offset: 7px; }
.profile-avatar-edit { position: absolute; right: -1px; bottom: -1px; display: grid; place-items: center; width: 23px; height: 23px; border: 2px solid var(--c-bg-raise); border-radius: 50%; background: var(--c-ink); color: var(--c-bg); }
.profile-identity__copy { min-width: 0; flex: 1; }
.profile-identity__name { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.profile-identity__name h2 { margin: 0; max-width: 100%; overflow-wrap: anywhere; font-size: 21px; font-weight: 650; letter-spacing: -.02em; }
.profile-id { display: flex; align-items: baseline; gap: 7px; margin: 7px 0 0; color: var(--c-ink-dim); font: 12px/1.6 var(--font-mono); letter-spacing: .035em; }
.profile-id > span:first-child { opacity: .75; font-size: 10px; }
.profile-avatar-actions { display: flex; align-items: center; gap: 10px; margin-top: 7px; color: var(--c-line); }
.profile-avatar-actions .linkbtn { min-height: 30px; font-size: 12px; color: var(--c-ink-dim); text-decoration: none; }
.profile-avatar-actions .linkbtn:hover { color: var(--c-gold); }
.profile-identity__member { display: grid; gap: 5px; padding-left: 28px; border-left: 1px solid var(--c-line-soft); flex: 0 0 245px; }
.profile-identity__member p { margin: 0; font-size: 14px; font-weight: 600; }
.profile-identity__member > span { color: var(--c-ink-dim); font-size: 12px; line-height: 1.8; }
.profile-identity__member a { width: fit-content; margin-top: 4px; font-size: 12px; color: var(--c-gold); background: none; }
.member-badge { display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px 4px 7px; border-radius: 6px; color: var(--c-ink-dim); background: color-mix(in srgb, var(--c-ink) 6%, transparent); font-size: 10px; font-weight: 650; letter-spacing: .04em; white-space: nowrap; }
.member-badge[data-active='true'] { color: var(--c-gold); background: linear-gradient(125deg, color-mix(in srgb, var(--c-accent-bg) 19%, var(--c-bg-raise)), color-mix(in srgb, var(--c-accent-bg) 5%, var(--c-bg-raise))); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-gold) 22%, transparent); }
.profile-editor { padding: 24px 32px; margin-top: 12px; background: var(--c-bg-raise); border-radius: 18px; }
.profile-editor .avatar-editor { max-width: 100%; grid-template-columns: minmax(0, 256px) minmax(0, 1fr); column-gap: 32px; }
.profile-editor .avatar-editor > .field:first-child { grid-column: 1 / -1; }
.profile-editor .avatar-editor canvas { grid-row: span 3; border-radius: 26%; }
.profile-feedback:empty { height: 24px; }
.profile-feedback:not(:empty) { padding-block: 14px; }
.profile-notice { display: flex; align-items: center; gap: 8px; margin: 0; color: var(--c-mint); font-size: 13px; }
.profile-grid { display: grid; grid-template-columns: minmax(0, 1fr) 300px; align-items: start; gap: 24px; }
.profile-settings { display: grid; gap: 20px; min-width: 0; }
.profile-card { padding: 27px 28px; border-radius: 18px; background: var(--c-bg-raise); min-width: 0; }
.profile-card__heading { display: flex; align-items: flex-start; gap: 13px; margin-bottom: 24px; }
.profile-card__icon { font: 11px/29px var(--font-mono); color: var(--c-gold); border-bottom: 1px solid var(--c-line); }
.profile-card__heading h2 { font-size: 16px; font-weight: 650; margin: 0 0 5px; line-height: 1.6; }
.profile-card__heading p { margin: 0; color: var(--c-ink-dim); font-size: 12px; line-height: 1.6; }
.profile-form { gap: 18px; }
.profile-form .field__input { min-height: 48px; font-size: 14px; }
.profile-static-field { display: flex; align-items: center; gap: 15px; padding-block: 4px 12px; font-size: 12px; color: var(--c-ink-dim); }
.profile-static-field strong { font: 13px var(--font-mono); color: var(--c-ink); }
.profile-verified { margin-left: auto; color: var(--c-mint); font-size: 11px; white-space: nowrap; }
.profile-form__footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; border-top: 1px solid var(--c-line-soft); padding-top: 18px; }
.profile-form__footer > span { color: var(--c-ink-dim); font-size: 11px; }
.profile-form__footer .btn { min-height: 40px; flex: none; font-size: 12px; }
.profile-security__row { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.profile-security__row strong { font-size: 13px; font-weight: 550; }
.profile-security__row p { margin: 5px 0 0; color: var(--c-ink-dim); font-size: 12px; line-height: 1.7; }
.profile-security__signout { margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--c-line-soft); }
.profile-security__row .btn { flex: none; min-height: 40px; font-size: 12px; }
.profile-password { padding-top: 24px; margin-top: 24px; border-top: 1px solid var(--c-line-soft); }
.password-form .account-hint { margin: -10px 0 0; font-size: 12px; }
.password-strength { font-size: 12px; color: var(--c-ink-dim); }
.profile-progress__total { display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px; position: relative; padding: 8px 0 24px; }
.profile-progress__total strong { font: 500 58px/1.15 var(--font-display); letter-spacing: -.05em; }
.profile-progress__total > span { width: 100%; font-size: 12px; color: var(--c-ink-dim); }
.profile-progress__total svg { position: absolute; right: 0; top: 10px; color: var(--c-gold); opacity: .75; }
.profile-progress__started { display: flex; align-items: center; justify-content: space-between; padding: 14px 0; border-block: 1px solid var(--c-line-soft); color: var(--c-ink-dim); font-size: 13px; }
.profile-progress__started strong { color: var(--c-ink); font-family: var(--font-mono); }
.profile-progress__note { margin: 20px 0 24px; font-size: 13px; color: var(--c-ink-dim); line-height: 1.9; }
.profile-progress > .btn { min-height: 44px; justify-content: space-between; font-size: 13px; }
.profile-progress__clear { display: flex; justify-content: center; padding-top: 14px; }
.profile-progress__clear .linkbtn { min-height: 36px; color: var(--c-ink-dim); font-size: 11px; text-decoration-color: var(--c-line); }
.profile-progress__clear .linkbtn:disabled { opacity: .45; cursor: default; }
.profile-footer { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding-top: 24px; font-size: 12px; color: var(--c-ink-dim); }

/* Recovery has one stable primary action and a single inline resend control. */
.auth-emblem { display: grid; place-items: center; width: 50px; height: 50px; margin-bottom: 22px; border-radius: 16px; color: var(--c-gold); background: color-mix(in srgb, var(--c-accent-bg) 10%, transparent); }
.auth-emblem[data-success='true'] { color: var(--c-mint); background: color-mix(in srgb, var(--c-good-bg) 12%, transparent); }
.auth-steps { list-style: none; display: flex; align-items: center; gap: 20px; margin: 24px 0; padding: 0; }
.auth-steps li { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--c-ink-dim); }
.auth-steps li + li::before { content: ''; width: 24px; height: 1px; background: var(--c-line); margin-right: 6px; }
.auth-steps li > span { display: grid; place-items: center; width: 22px; height: 22px; flex: none; border-radius: 50%; background: var(--c-glass-hover); font: 11px var(--font-mono); }
.auth-steps li[data-active='true'] { color: var(--c-ink); }
.auth-steps li[data-active='true'] > span, .auth-steps li[data-done='true'] > span { background: var(--c-accent-bg); color: var(--c-on-accent); }
.otp-field { padding-right: 6px; gap: 4px; }
.otp-field .field__input { width: 0; letter-spacing: .17em; font-size: 16px; }
.otp-field .field__input::placeholder { font-size: 13px; letter-spacing: .04em; }
.otp-send { flex: 0 0 112px; display: inline-flex; justify-content: center; align-items: center; min-height: 40px; border: 0; border-left: 1px solid var(--c-line); border-radius: 0; background: transparent; color: var(--c-gold); font: 12px var(--font-body); cursor: pointer; white-space: nowrap; font-variant-numeric: tabular-nums; }
.otp-send:hover:enabled { background: var(--c-glass-hover); border-radius: 0 8px 8px 0; }
.otp-send:disabled { color: var(--c-ink-dim); cursor: default; }
.otp-send:focus-visible { outline: 2px solid var(--c-gold); outline-offset: -2px; }
.auth-code-note { margin: -8px 0 0; font-size: 12px; line-height: 1.6; color: var(--c-ink-dim); }
.auth-footer { display: flex; justify-content: space-between; align-items: center; gap: 16px; margin-top: 16px; }
.auth-footer .linkbtn { min-height: 44px; font-size: 13px; text-decoration: none; }
/* 谷歌登录：看到的是自己画的按钮（.auth-google__face，和输入框同高、跟画风配色），
   谷歌的按钮（iframe）完全透明盖在上面（透明也照样接点击；0.01 在手机上会透出一道色差）接点击和键盘；悬停、聚焦靠外层的 :hover / :focus-within 画在自己的按钮上 */
.auth-google { position: relative; margin: 4px 0 0; }
.auth-google[aria-disabled='true'] { pointer-events: none; opacity: .6; }
.auth-google__face { display: flex; align-items: center; justify-content: center; gap: 12px; height: 54px; padding: 0 20px; border: 1px solid var(--c-line); border-radius: var(--r-md); background: var(--c-bg-raise); color: var(--c-ink); font: 600 15px var(--font-body); transition: border-color .15s, background-color .15s; }
.auth-google__face svg { flex: none; }
.auth-google:hover .auth-google__face { border-color: var(--c-gold); background: var(--c-glass-hover); }
.auth-google:focus-within .auth-google__face { outline: 2px solid var(--c-gold); outline-offset: 2px; }
.auth-google__button { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; overflow: hidden; opacity: 0; }
.auth-google__button iframe { color-scheme: light; transform: scaleY(1.35); }
.auth-divider { display: flex; align-items: center; gap: 12px; margin: 18px 0; font-size: 12px; color: var(--c-ink-dim); }
.auth-divider::before, .auth-divider::after { content: ''; flex: 1; border-top: 1px solid var(--c-line); }
.auth-email-toggle { margin: 14px 0 0; text-align: center; white-space: nowrap; }
.auth-email-toggle .linkbtn { min-height: 36px; font-size: 13px; color: var(--c-ink-dim); }
.auth-phone-note { margin: 8px 0 0; font-size: 12px; line-height: 1.6; color: var(--c-ink-dim); }
.auth-phone-note .linkbtn { font-size: 12px; }
.auth-back { display: inline-flex; align-items: center; gap: 9px; color: var(--c-ink-dim); }
.auth-success { margin-top: 22px; }

/* ── 标记为已学：整页唯一一次"庆祝" ─────────────────────────────────────
   按钮本身是外壳（DESIGN-SPEC §一）：实心强调色 + 顶边高光，不描粗边、不拖硬投影、悬停不位移。
   原来蜡笔 / 构序给它加了 `border + 4px 5px 0 var(--c-ink)` 的贴纸投影，暗档下 --c-ink 是白的，
   按钮底下就拖着一块白板。力气全花在"点下去、服务器存好之后"那一下：
   闪光 → 三道冲击波 → 44 片碎片抛出去再落下 → 按钮弹一下变成印章 → 读数"已学 N 节"。
   只在存成功后播，只播一次；prefers-reduced-motion 下整段不播。
   ────────────────────────────────────────────────────────────────────── */
.learning-progress { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px; padding-block: 64px 36px; overflow-x: clip; }
.completion-wrap { position: relative; isolation: isolate; }
/* 「标记为已学」：画风强调色的实心按钮；点了以后变成强调色淡底的「已学」。规则见 SYSTEM.md 界面一节：不用成功绿 */
.completion-button { position: relative; display: inline-flex; justify-content: center; align-items: center; gap: 12px;
  min-width: min(260px, 76vw); min-height: 56px; padding: 14px 30px; border: 0; border-radius: var(--r-lg);
  color: var(--c-on-accent); background: var(--c-accent-bg); font: 650 var(--t-base)/1 var(--font-body); letter-spacing: .02em; cursor: pointer;
  box-shadow: inset 0 1px 0 var(--c-glass-sheen), 0 10px 24px -14px color-mix(in srgb, var(--c-accent-bg) 80%, transparent);
  transition: background var(--dur-fast) var(--ease), color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.completion-button:hover:not([aria-disabled='true']) { background: var(--c-accent-hover, var(--c-accent-bg)); }
.completion-button:active:not([aria-disabled='true']) { box-shadow: inset 0 2px 8px color-mix(in srgb, var(--c-ink) 22%, transparent); }
.completion-button:focus-visible { outline: 2px solid var(--c-accent-bg); outline-offset: 5px; }
.completion-button[aria-disabled='true'] { cursor: default; }
.completion-button[aria-busy='true'] { opacity: .8; }
.completion-button[data-completed='true'] { color: var(--c-on-accent-soft); background: var(--c-accent-soft);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-accent-bg) 30%, transparent); }
.completion-button__icon { display: grid; place-items: center; }
/* 图标：没学时是一个空心圈（里面淡淡一个勾）；学了以后圈填满强调色、勾变成反白 */
.completion-seal { transform-box: fill-box; transform-origin: center; stroke: currentColor; stroke-width: 1.8; fill: transparent; transition: fill var(--dur) var(--ease), stroke var(--dur) var(--ease); }
.completion-check { stroke: currentColor; stroke-width: 2.2; opacity: .45; }
[data-completed='true'] .completion-seal { fill: var(--c-accent-bg); stroke: var(--c-accent-bg); }
[data-completed='true'] .completion-check { stroke: var(--c-on-accent); opacity: 1; }
.completion-status { display: flex; flex-direction: column; align-items: center; gap: 6px; min-height: 26px; font-size: var(--t-base); color: var(--c-ink-dim); }
.completion-count { font: 650 var(--t-sm)/1.4 var(--font-body); color: var(--c-accent-bg); white-space: nowrap; }

/* ── 点下去的那一下 ── */
.completion-burst { position: absolute; left: 50%; top: 50%; width: 0; height: 0; pointer-events: none; z-index: -1; }
.completion-ring { position: absolute; left: 0; top: 0; width: 260px; height: 76px; margin: -38px 0 0 -130px; border-radius: var(--r-lg);
  border: 2px solid var(--c-accent-bg); opacity: 0; animation: completion-ripple 900ms cubic-bezier(.2,.7,.3,1) both; }
.completion-burst i { position: absolute; left: 0; top: 0; width: var(--s); height: var(--s); margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2);
  border-radius: 50%; background: var(--c-accent-bg); opacity: 0; animation: completion-spark 900ms cubic-bezier(.15,.7,.3,1) var(--delay) both; }
.completion-burst i[data-k='1'] { background: color-mix(in srgb, var(--c-accent-bg) 55%, var(--c-bg-raise)); }
.completion-burst i[data-k='2'] { width: calc(var(--s) * .6); height: calc(var(--s) * .6); }
[data-celebrating='true'] .completion-button { animation: completion-press 520ms cubic-bezier(.3,1.5,.5,1) both; }
[data-celebrating='true'] .completion-seal { animation: completion-fill 480ms ease 80ms both; }
[data-celebrating='true'] .completion-check { stroke-dasharray: 16; animation: completion-check 360ms ease 260ms both; }
[data-celebrating='true'] .completion-status > * { animation: completion-message 420ms ease 300ms both; }

/* 画风各有自己的手感：形状变，颜色不变（都是强调色） */
[data-completion-style='crayon-book'] .completion-button { border-radius: 20px 24px 19px 23px / 23px 19px 24px 20px; }
[data-completion-style='crayon-book'] .completion-ring { border-width: 2.5px; border-style: dashed; border-radius: 26px 30px 24px 28px; }
[data-completion-style='crayon-book'] .completion-burst i { width: calc(var(--s) * .5); height: calc(var(--s) * 1.6); border-radius: 40% 60% 45% 55%; }
[data-completion-style='watercolor'] .completion-ring { border-width: 8px; filter: blur(5px); opacity: 0; }
[data-completion-style='watercolor'] .completion-burst i { width: calc(var(--s) * 2.2); height: calc(var(--s) * 2.2); filter: blur(2px); opacity: 0; }
[data-completion-style='studio'] .completion-button, [data-completion-style='studio'] .completion-ring { border-radius: 2px; }
[data-completion-style='studio'] .completion-burst i { border-radius: 0; }
[data-completion-style='studio'][data-celebrating='true'] .completion-button { animation: completion-stamp 460ms cubic-bezier(.2,.8,.2,1) both; }
[data-completion-style='orbit'] .completion-button, [data-completion-style='orbit'] .completion-ring { border-radius: 999px; }
[data-completion-style='orbit'] .completion-ring { box-shadow: 0 0 14px var(--c-accent-bg), inset 0 0 10px var(--c-accent-bg); border-width: 1.5px; }
[data-completion-style='orbit'] .completion-burst i { box-shadow: 0 0 8px 1px var(--c-accent-bg); }

@keyframes completion-ripple { 0% { transform: scale(.9); opacity: .7; } 100% { transform: scale(1.35, 1.9); opacity: 0; } }
@keyframes completion-spark { 0% { transform: translate(0, 0) scale(.4); opacity: 0; } 20% { opacity: 1; } 100% { transform: translate(var(--x), var(--y)) scale(1); opacity: 0; } }
@keyframes completion-press { 0% { transform: scale(1); } 30% { transform: scale(.96); } 70% { transform: scale(1.03); } 100% { transform: none; } }
@keyframes completion-stamp { 0% { transform: none; } 35% { transform: translateY(2px) scale(.97); } 100% { transform: none; } }
@keyframes completion-fill { 0% { transform: scale(.6); } 60% { transform: scale(1.12); } 100% { transform: none; } }
@keyframes completion-check { from { stroke-dashoffset: 16; } to { stroke-dashoffset: 0; } }
@keyframes completion-message { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

:root[data-style='studio'] .profile-card, :root[data-style='studio'] .profile-identity { border-radius: 10px; }
:root[data-style='watercolor'] .profile-card, :root[data-style='watercolor'] .profile-identity { background-color: color-mix(in srgb, var(--c-bg-raise) 80%, transparent); }
:root[data-style='orbit'] .profile-identity { background: radial-gradient(ellipse at top left, color-mix(in srgb, var(--c-accent-bg) 9%, transparent), transparent 65%), var(--c-bg-raise); }
:root[data-style='orbit'] .member-badge[data-active='true'] { border-radius: 999px; }
@media (max-width: 799px) {
  .profile-grid { grid-template-columns: minmax(0, 1fr); }
  .profile-identity { flex-wrap: wrap; padding: 24px; gap: 18px; }
  .profile-identity__member { flex: 1 0 100%; border-left: 0; border-top: 1px solid var(--c-line-soft); padding: 18px 0 0; }
  .profile-progress__total { padding-bottom: 20px; }
}
@media (max-width: 479px) {
  .profile-heading { align-items: flex-start; gap: 8px; }
  .profile-return { font-size: 11px; gap: 5px; }
  .profile-identity { padding: 22px 18px; gap: 16px; }
  .profile-avatar-button .account-avatar { width: 52px !important; height: 52px !important; }
  .profile-identity__name h2 { font-size: 18px; }
  .profile-identity__name { gap: 8px; }
  .profile-card { padding: 22px 20px; }
  .profile-card__heading { margin-bottom: 20px; }
  .profile-security__row { align-items: flex-start; }
  .profile-security__row p { max-width: 16em; }
  .profile-static-field { gap: 10px; }
  .profile-editor { padding: 20px; }
  .profile-editor .avatar-editor { grid-template-columns: minmax(0, 1fr); }
  .profile-editor .avatar-editor canvas { grid-row: auto; }
  .profile-avatar-actions { gap: 7px; }
  .profile-avatar-actions .linkbtn { font-size: 11px; }
  .auth-steps { gap: 10px; }
  .auth-steps li { font-size: 11px; gap: 6px; }
  .auth-steps li + li::before { width: 15px; margin-right: 3px; }
  .completion-button { min-width: min(270px, 75vw); }
}
@media (prefers-reduced-motion: reduce) {
  .profile-avatar-button, .completion-button, .completion-button::after { transition: none; }
  .learning-progress *, .learning-progress *::before, .learning-progress *::after { animation: none !important; }
  .completion-burst { display: none; }
}
/* Scenery, discovery and reading share the existing four art directions. */
html { scrollbar-gutter: stable; }
html:has(dialog[open]) { overflow: hidden; }
.app { --reading-base: var(--t-base); --reading-lg: var(--t-lg); --reading-xl: var(--t-xl); --reading-2xl: var(--t-2xl); position: relative; isolation: isolate; min-height: 100dvh; }
.atmosphere { position: absolute; inset: 0; z-index: -1; overflow: clip; pointer-events: none; }
.atmosphere > svg { position: absolute; inset: 0; width: 100%; height: 1100px; max-width: none; }
.atmosphere__wash { position: absolute; inset: 0 0 auto; height: 1100px; background: radial-gradient(ellipse at 95% 6%, color-mix(in srgb, var(--c-gold) 7%, transparent), transparent 45%), radial-gradient(ellipse at 0% 60%, color-mix(in srgb, var(--c-mint) 4%, transparent), transparent 50%); }
.atmosphere[data-reading='true'] { opacity: .45; }
:root[data-style='watercolor'] .atmosphere__wash { background: radial-gradient(ellipse at 100% 8%, color-mix(in srgb, var(--c-mint) 10%, transparent), transparent 48%), radial-gradient(ellipse at 0% 40%, color-mix(in srgb, var(--c-violet) 7%, transparent), transparent 40%); }
:root[data-style='studio'] .atmosphere__wash { background: linear-gradient(110deg, color-mix(in srgb, var(--c-bg-raise) 60%, transparent), transparent 65%); }
:root[data-style='orbit'] .atmosphere__wash { background: radial-gradient(ellipse at 90% 0, color-mix(in srgb, var(--c-data) 10%, transparent), transparent 55%), radial-gradient(ellipse at 10% 65%, color-mix(in srgb, var(--c-violet) 6%, transparent), transparent 50%); }
::selection { color: var(--c-ink); background: color-mix(in srgb, var(--c-gold) 22%, var(--c-bg)); }
:focus-visible { scroll-margin-block: calc(var(--topbar-h) + 48px) 36px; }
button, a, summary { -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
button, input, summary { transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease; }
button:disabled { cursor: default; }
mark { color: inherit; background: color-mix(in srgb, var(--c-gold) 18%, var(--c-bg)); border-radius: 3px; padding-block: 1px; }
kbd { display: inline-flex; align-items: center; justify-content: center; min-width: 23px; min-height: 23px; padding: 0 5px; border: 1px solid var(--c-line); border-radius: 5px; color: var(--c-ink-dim); background: var(--c-bg); font: 11px/1.4 var(--font-mono); white-space: nowrap; }
.icon-button { min-width: 36px; min-height: 36px; flex: none; }
.topbar__nav { gap: clamp(12px, 1.6vw, 24px); }
.topbar__brand { min-height: 44px; }
.topbar__catalog { min-height: 40px; display: inline-flex; align-items: center; position: relative; }
.topbar__catalog[aria-current='page'] { color: var(--c-ink); }
.topbar__catalog[aria-current='page']::after { content: ''; width: 4px; height: 4px; background: var(--c-gold); position: absolute; bottom: 0; left: calc(50% - 2px); border-radius: 50%; }
.topbar__controls { padding: 4px; }
.theme-picker__trigger { min-height: 40px; background: var(--c-glass); }
.theme-picker__panel { border-color: var(--c-glass-line); background: linear-gradient(var(--c-glass-tint), var(--c-glass-tint)), var(--c-bg); padding: 24px; }
.theme-picker__heading p { max-width: 25em; }
.theme-card { border-radius: var(--r-sm); }
.theme-card__preview { height: 98px; }
.theme-card__art { top: 8px; height: 85px; }
.theme-card__check { color: var(--c-gold); }
.theme-picker__mobile-settings { display: none; }
.quick-search-trigger { display: inline-flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 12px; color: var(--c-ink-dim); background: var(--c-glass); border: 1px solid var(--c-line-soft); border-radius: var(--r-md); cursor: pointer; font-size: 13px; }
.quick-search-trigger:hover { color: var(--c-ink); background: var(--c-glass-hover); border-color: var(--c-line); }
.quick-search-trigger kbd { margin-left: 18px; }

/* The opening spread: a reading invitation and an illustrated workspace. */
.hero { min-height: 448px; margin-top: 28px; padding: 52px clamp(24px, 4vw, 56px); border: 1px solid var(--c-line-soft); border-radius: var(--r-lg); background: color-mix(in srgb, var(--c-bg-raise) 68%, transparent); }
.hero:has(.heroart__object) .hero__body { width: 51%; max-width: 620px; }
.hero__eyebrow { margin-bottom: 22px; font-size: 12px; }
.hero__title { font-size: clamp(36px, 3.9vw, 56px); line-height: 1.25; }
.hero__sub { max-width: 25em; font-size: 16px; line-height: 1.9; }
.hero__actions { gap: 28px; margin-top: 30px; }
.hero__actions .btn { min-height: 48px; padding-inline: 24px; }
.heroart { inset: 0 0 0 auto; width: 49%; }
.heroart__halo { position: absolute; inset: 9% 8% 13%; border: 1px solid color-mix(in srgb, var(--c-gold) 12%, transparent); border-radius: 50%; background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--c-mint) 7%, transparent), transparent 72%); }
.heroart__halo::after { content: ''; position: absolute; inset: 20px -18px; border: 1px dashed var(--c-line-soft); border-radius: 50%; transform: rotate(-20deg); }
.heroart__path { position: absolute; inset: 2% 3%; width: 94%; height: 94%; }
.heroart .heroart__object { width: 80%; height: 80%; right: 10%; top: 45%; bottom: auto; transform: translateY(-50%); max-height: none; }
.heroart .heroart__object > svg { width: 100%; height: 100%; }
.heroart__note { position: absolute; z-index: 2; display: flex; align-items: center; gap: 10px; padding: 12px 16px; background: var(--c-bg-raise); border: 1px solid var(--c-line); border-radius: var(--r-md); color: var(--c-ink); font-size: 12px; line-height: 1.6; }
.heroart__note > svg { color: var(--c-gold); flex: none; }
.heroart__note small { display: block; color: var(--c-ink-dim); font-size: 10px; margin-top: 2px; }
.heroart__note--idea { top: 12%; left: 0; transform: rotate(-4deg); }
.heroart__note--connect { bottom: 17%; right: 5%; transform: rotate(3deg); }
.heroart__caption { position: absolute; bottom: 5%; left: 8%; right: 8%; display: flex; justify-content: center; align-items: center; gap: 9px; color: var(--c-ink-dim); font-size: 11px; line-height: 1.6; }
.heroart__caption > span { height: 1px; width: 24px; background: var(--c-gold); flex: none; }
.hero__stats { margin-top: 20px; }
:root[data-style='crayon-book'] .hero { border-radius: 24px 44px 28px 18px / 26px 24px 40px 28px; }
:root[data-style='crayon-book'] .heroart__note { border-radius: 12px 9px 14px 6px; }
:root[data-style='watercolor'] .hero { border-color: transparent; background: radial-gradient(ellipse at 85% 48%, color-mix(in srgb, var(--c-mint) 8%, var(--c-bg-raise)), transparent 72%); }
:root[data-style='watercolor'] .heroart__halo { border: 0; background: radial-gradient(ellipse, color-mix(in srgb, var(--c-mint) 10%, transparent), transparent 70%); }
:root[data-style='watercolor'] .heroart__halo::after { border: 0; }
:root[data-style='watercolor'] .heroart__note { background: color-mix(in srgb, var(--c-bg-raise) 88%, transparent); border-color: var(--c-line-soft); border-radius: 22px 8px 26px 12px; }
:root[data-style='studio'] .hero { border-radius: 0; background: var(--c-bg-raise); }
:root[data-style='studio'] .heroart__halo { border-radius: 0; inset: 12% 12%; border: 1px solid var(--c-line); }
:root[data-style='studio'] .heroart__halo::after { border-radius: 0; transform: none; inset: 12px; }
:root[data-style='studio'] .heroart__note { border-radius: 0; transform: none; border-inline-start: 3px solid var(--c-gold); }
:root[data-style='orbit'] .hero { background: radial-gradient(ellipse at 95% 25%, color-mix(in srgb, var(--c-data) 8%, var(--c-bg-raise)), var(--c-bg-raise)); border-color: color-mix(in srgb, var(--c-gold) 20%, var(--c-line)); }
:root[data-style='orbit'] .heroart__note { transform: none; border-color: color-mix(in srgb, var(--c-gold) 25%, var(--c-line)); }

/* Discovery has one clear control surface and distinct subject landmarks. */
.catalog-tools { padding: 24px; border-radius: var(--r-lg); background: linear-gradient(var(--c-glass-tint), var(--c-glass-tint)), var(--c-bg); border: 1px solid var(--c-glass-line); box-shadow: inset 0 1px var(--c-glass-sheen); }
.catalog-tools__heading { margin-bottom: 18px; }
.catalog-search { min-height: 54px; }
.catalog-search input { font-size: 15px; }
.catalog-search input:focus-visible { outline: none; }
.catalog-tools__hint { color: var(--c-ink-dim); font-size: 12px; margin: 12px 0 0; }
.catalog-filter { min-height: 48px; }
.catalog-filter__dot { display: grid; place-items: center; width: 17px; height: 17px; border: 1px solid var(--c-line); background: transparent; border-radius: 5px; font-size: 12px; }
.catalog-filter[aria-pressed='true'] .catalog-filter__dot { background: var(--c-accent-bg); border-color: var(--c-accent-bg); color: var(--c-on-accent); }
.catalog-filter__count { font: 11px var(--font-mono); padding: 3px 6px; background: var(--c-bg); color: var(--c-ink-dim); border-radius: 5px; }
.domain-jumps { margin-top: 20px; gap: 8px 6px; padding-top: 16px; border-top: 1px solid var(--c-line-soft); }
.domain-jumps a { min-height: 36px; padding-inline: 10px; border-color: var(--c-line-soft); background: var(--c-bg-raise); }
.domain-jumps a > span { opacity: 1; color: var(--c-gold); }
.continue-card { margin-top: 24px; display: flex; align-items: center; gap: 16px; padding: 20px 24px; background: var(--c-bg-raise); border: 1px solid var(--c-line); border-radius: var(--r-lg); background-image: none; color: var(--c-ink); }
.continue-card:hover { border-color: var(--c-gold); }
.continue-card__icon { display: grid; place-items: center; width: 40px; height: 40px; flex: none; border-radius: 50%; color: var(--c-gold); background: color-mix(in srgb, var(--c-gold) 9%, var(--c-bg)); }
.continue-card__label { display: block; color: var(--c-gold); font-size: 11px; margin-bottom: 5px; }
.continue-card__title { font-size: 15px; }
.continue-card__context { margin-left: auto; font-size: 12px; color: var(--c-ink-dim); }
.band { background: color-mix(in srgb, var(--c-bg-raise) 94%, var(--tone)); }
.band:hover { box-shadow: inset 0 0 0 1px var(--c-line); }
.domain-art { width: 80px; height: 80px; color: var(--tone); margin: 0 0 20px -4px; }
.domain-art[data-medium='crayon-book'] .domain-art__plate { transform: rotate(-5deg); transform-origin: center; }
.domain-art[data-medium='watercolor'] .domain-art__spot { r: 26; opacity: .08; }
.domain-art[data-medium='orbit'] .domain-art__plate { fill: none; stroke: currentColor; stroke-dasharray: 2 4; opacity: .3; }
.band--meta .band__head { display: grid; grid-template-columns: 96px minmax(0, 1fr); column-gap: 22px; max-width: none; }
.band--meta .domain-art { width: 96px; height: 96px; grid-row: 1 / 5; margin: 0; align-self: center; }
.band--meta .band__eyebrow { margin-bottom: 8px; }
.band--meta .band__lead { max-width: none; }
.band__no { font-size: 14px; letter-spacing: .1em; margin-bottom: 14px; }
.topic__sum { min-height: 60px; padding-inline: 12px; }
.topic__fold { scroll-margin-top: calc(var(--topbar-h) + 24px); }
.topic__fold[open] .topic__sum { background: color-mix(in srgb, var(--tone) 6%, var(--c-bg-raise)); }
.kplink { padding-block: 14px; min-height: 48px; border-radius: var(--r-sm); }
.kplink:hover { background: color-mix(in srgb, var(--tone) 7%, var(--c-bg-raise)); }
.search-results { position: relative; padding-top: 8px; }
.search-results__count { min-height: 40px; display: flex; align-items: center; padding-right: 160px; }
.search-results > .btn { position: absolute; top: 8px; right: 0; min-height: 36px; padding: 8px 14px; font-size: 12px; }
.search-results > ul > li { padding: 18px 16px 8px; }
.search-results__context { line-height: 1.6; }
.search-results__empty { border: 1px dashed var(--c-line); border-radius: var(--r-lg); background: var(--c-bg-raise); }

/* The search dialog owns focus, scroll and keyboard selection through native dialog. */
.quick-search { width: min(660px, calc(100vw - 32px)); max-width: none; padding: 0; margin: min(15dvh, 120px) auto auto; max-height: calc(100dvh - 48px); border: 1px solid var(--c-glass-line); border-radius: var(--r-lg); background: var(--c-bg-raise); color: var(--c-ink); box-shadow: var(--shadow-lg); overflow: hidden; }
.quick-search::backdrop, .sidenav--drawer::backdrop { background: color-mix(in srgb, var(--c-bg-sink) 64%, transparent); backdrop-filter: blur(6px); }
.quick-search[open] { display: flex; flex-direction: column; animation: surface-in 160ms ease; }
.quick-search__input { display: flex; align-items: center; flex: none; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--c-line); }
.quick-search__input > svg { flex: none; color: var(--c-gold); }
.quick-search__input input { width: 100%; min-width: 0; min-height: 36px; background: none; border: 0; color: var(--c-ink); font: 16px var(--font-body); outline: none; }
.quick-search__input input::placeholder { color: var(--c-ink-dim); }
.quick-search__close { min-height: 32px; padding: 4px 8px; border: 1px solid var(--c-line); border-radius: 6px; background: var(--c-bg); color: var(--c-ink-dim); font-size: 11px; cursor: pointer; }
.quick-search__body { overflow-y: auto; overscroll-behavior: contain; min-height: 140px; max-height: 55dvh; padding: 12px; }
.quick-search__label { font-size: 12px; padding: 4px 10px; margin-bottom: 8px; color: var(--c-ink-dim); }
.quick-search__body ul { list-style: none; padding: 0; margin: 0; }
.quick-result { display: flex; align-items: center; gap: 12px; min-height: 66px; border-radius: var(--r-sm); padding: 12px; background-image: none; border: 1px solid transparent; color: var(--c-ink); }
.quick-result[aria-selected='true'] { border-color: var(--c-line-soft); background: color-mix(in srgb, var(--c-gold) 7%, var(--c-bg)); }
.quick-result__icon { font: 12px var(--font-mono); color: var(--c-gold); flex: none; }
.quick-result__text { min-width: 0; flex: 1; }
.quick-result__title { display: block; font-size: 14px; font-weight: 600; line-height: 1.6; }
.quick-result__context { display: block; font-size: 11px; margin-top: 3px; line-height: 1.6; color: var(--c-ink-dim); }
.quick-result__meta { flex: none; font-size: 11px; color: var(--c-ink-dim); }
/* 搜索结果的类别徽标：知识用强调色，课程用另一种色，一眼分开 */
.quick-result__badge { flex: none; align-self: flex-start; margin-top: 1px; font-size: 11px; font-weight: 600; line-height: 1.6; padding: 1px 8px; border-radius: 999px; white-space: nowrap;
  color: var(--c-gold); background: color-mix(in srgb, var(--c-gold) 12%, transparent); }
.quick-result__badge[data-kind="course"] { color: var(--c-violet); background: color-mix(in srgb, var(--c-violet) 14%, transparent); }
.quick-result__enter { opacity: 0; font-size: 16px; color: var(--c-gold); }
.quick-result[aria-selected='true'] .quick-result__enter { opacity: 1; }
.quick-search__empty { padding: 32px 20px; }
.quick-search__empty > svg { color: var(--c-gold); width: 32px; height: 32px; margin-bottom: 16px; }
.quick-search__empty h3 { font-size: 17px; }
.quick-search__empty p { font-size: 13px; margin-top: 12px; color: var(--c-ink-dim); }
.quick-search__footer { display: flex; justify-content: space-between; align-items: center; flex: none; gap: 16px; padding: 14px 22px; border-top: 1px solid var(--c-line); font-size: 12px; }
.quick-search__footer > span { color: var(--c-ink-dim); font-size: 11px; }

/* The reading desk leaves controls outside the text's visual hierarchy. */
.kp { padding-top: 32px; }
.kp__head { padding-bottom: 32px; }
.kp__title { font-size: clamp(28px, 2.8vw, 40px); line-height: 1.5; text-wrap: balance; }
.kp__meta { flex-wrap: wrap; gap: 12px 18px; margin-top: 20px; }
.kp__body { font-size: var(--t-base); line-height: 1.9; }
.app[data-reading-size='1'] .kp__body { --t-base: calc(var(--reading-base) + .125rem); --t-lg: calc(var(--reading-lg) + .125rem); --t-xl: calc(var(--reading-xl) + .125rem); --t-2xl: calc(var(--reading-2xl) + .125rem); }
.app[data-reading-size='2'] .kp__body { --t-base: calc(var(--reading-base) + .25rem); --t-lg: calc(var(--reading-lg) + .25rem); --t-xl: calc(var(--reading-xl) + .25rem); --t-2xl: calc(var(--reading-2xl) + .25rem); }
/* 超大档同时放大正文的说明文字、代码和小节标题，保持版心宽度，窄屏自然换行。 */
.app[data-reading-size='3'] .kp__body {
  --t-base: calc(var(--reading-base) + .4375rem);
  --t-sm: calc(var(--reading-base) + .1875rem);
  --t-xs: calc(var(--reading-base) + .125rem);
  --t-code: calc(var(--reading-base) + .125rem);
  --t-lg: calc(var(--reading-lg) + .4375rem);
  --t-xl: calc(var(--reading-xl) + .4375rem);
  --t-2xl: calc(var(--reading-2xl) + .4375rem);
  line-height: 1.85;
  overflow-wrap: anywhere;
}
.kp__tools { flex-wrap: wrap; row-gap: 12px; padding-bottom: 14px; margin-bottom: 28px; border-bottom: 1px solid var(--c-line-soft); }
.reader-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.reader-size { display: flex; align-items: center; border: 1px solid var(--c-line); background: var(--c-glass-tint); border-radius: var(--r-sm); }
.reader-size button { display: grid; place-items: center; width: 32px; min-height: 34px; background: transparent; border: 0; color: var(--c-ink); cursor: pointer; border-radius: var(--r-sm); font-size: 18px; }
.reader-size button:disabled { color: var(--c-ink-faint); opacity: .45; cursor: default; }
.reader-size button:hover:not(:disabled) { background: var(--c-glass-hover); }
.reader-size > span { min-width: 3.5em; padding-inline: 6px; text-align: center; white-space: nowrap; font-size: 11px; color: var(--c-ink-dim); }
.reader-focus, .reader-outline { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 36px; padding: 6px 10px; border: 1px solid var(--c-line); border-radius: var(--r-sm); background: var(--c-glass); color: var(--c-ink-dim); cursor: pointer; font-size: 12px; }
.reader-focus:hover, .reader-outline:hover { color: var(--c-gold); background: var(--c-glass-hover); }
.reader-focus[aria-pressed='true'] { color: var(--c-gold); border-color: var(--c-gold); }
/* 「代码」开关：亮点 = 显示代码和终端；空心 = 收起（PAGE-FORMS.md 2.1、2.3） */
.reader-code { display: inline-flex; align-items: center; gap: 7px; min-height: 36px; padding: 6px 12px; border: 1px solid var(--c-line); border-radius: var(--r-sm); background: var(--c-glass); color: var(--c-ink-dim); cursor: pointer; font-size: 12px; white-space: nowrap; }
.reader-code:hover { color: var(--c-gold); background: var(--c-glass-hover); }
.reader-code__dot { width: 9px; height: 9px; border-radius: 50%; border: 1.5px solid currentColor; }
.reader-code[aria-pressed='true'] { color: var(--c-gold); border-color: color-mix(in srgb, var(--c-gold) 55%, transparent); }
.reader-code[aria-pressed='true'] .reader-code__dot { background: currentColor; }
.reader-code:focus-visible { outline: 2px solid var(--c-gold); outline-offset: 2px; }
.reader-tools .reader-copy { min-height: 36px; font-size: 12px; padding-inline: 10px; background: transparent; }
.app[data-focus='true'] .atmosphere, .app[data-focus='true'] .topbar__nav, .app[data-focus='true'] .navtoggle { display: none; }
.app[data-focus='true'] .sidenav { visibility: hidden; }
.focus-exit { margin-left: auto; }
.sidenav { background: linear-gradient(var(--c-glass-tint), var(--c-glass-tint)), var(--c-bg); }
.sidenav__heading { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.sidenav__heading .sidenav__label { margin: 0; letter-spacing: .03em; font-weight: 500; }
.sidenav__title { font-size: 15px; line-height: 1.7; margin-bottom: 20px; }
.sidenav__list a { min-height: 42px; align-items: baseline; font-size: 13px; }
.sidenav__sub a { font-size: 12px; }
.sidenav__progress { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px; margin-bottom: 24px; color: var(--c-ink-dim); font-size: 11px; }
.sidenav__progress > span:last-of-type { font-family: var(--font-mono); color: var(--c-gold); }
.sidenav__progress progress { appearance: none; width: 100%; height: 3px; overflow: hidden; border: 0; border-radius: 4px; color: var(--c-gold); background: var(--c-line-soft); }
.sidenav__progress progress::-webkit-progress-bar { background: var(--c-line-soft); }
.sidenav__progress progress::-webkit-progress-value { background: var(--c-gold); }
.sidenav__progress progress::-moz-progress-bar { background: var(--c-gold); }
.sidenav--drawer { margin: 0; inset: 0 auto 0 0; height: 100dvh; max-height: none; max-width: calc(100vw - 40px); padding: 0; border: 0; color: var(--c-ink); transform: none; width: min(340px, 86vw); }
.sidenav--drawer:not([open]) { display: none; }
.sidenav--drawer[open] { animation: surface-in 160ms ease; }
.sidenav--drawer .sidenav__inner { padding-top: max(24px, env(safe-area-inset-top)); padding-bottom: max(40px, env(safe-area-inset-bottom)); }
.readbar__percent { margin-left: auto; flex: none; color: var(--c-gold); font: 11px var(--font-mono); }
.prevnext__side { min-height: 144px; border-radius: var(--r-md); }
.prevnext__title { text-wrap: pretty; }
.wall { position: relative; overflow: hidden; border: 1px solid var(--c-line-soft); background: radial-gradient(ellipse at 95% 0, color-mix(in srgb, var(--c-gold) 7%, transparent), transparent 65%), var(--c-bg-raise); }
.wall .state-art { width: 172px; }

/* Account and status scenes sit in their own illustrated environments. */
.login__story { background: radial-gradient(ellipse at 100% 0, color-mix(in srgb, var(--c-gold) 8%, var(--c-bg-raise)), var(--c-bg-raise)); border: 1px solid var(--c-line-soft); }
.login__story-copy { padding-top: 48px; }
.login__story::after { content: ''; position: absolute; width: 220px; height: 220px; border: 1px solid var(--c-line-soft); border-radius: 50%; right: -110px; top: 12%; pointer-events: none; }
.login__col { width: 100%; }
.field__box:focus-within { box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-gold) 12%, transparent); }
.field__box:has(input[aria-invalid='true']) { border-color: var(--c-coral); }
.buy__card { position: relative; border-color: var(--c-line); box-shadow: inset 0 3px var(--c-gold); }
.page-state__body { padding: 32px; max-width: 780px; grid-template-columns: 220px minmax(0, 400px); border-radius: var(--r-lg); border: 1px solid var(--c-line-soft); background: color-mix(in srgb, var(--c-bg-raise) 88%, transparent); }
.page-state__body > .state-art { width: 220px; }
:root[data-style='watercolor'] .login__story { border-radius: 44px 16px 64px 24px; }
:root[data-style='studio'] .login__story::after { border-radius: 0; transform: rotate(30deg); }
:root[data-style='orbit'] .login__story { background: radial-gradient(ellipse at 50% 65%, color-mix(in srgb, var(--c-gold) 10%, var(--c-bg-raise)), var(--c-bg)); }
:root[data-style='orbit'] .login__story::after { border-style: dashed; }
.footer { align-items: flex-start; line-height: 1.8; }
.footer > a { min-height: 36px; display: inline-flex; align-items: center; }
/* 页脚右侧：联系我们（标签 + 各渠道，渠道登记在 lib/site.ts）+ 回到顶部。
   标签和渠道之间一道细竖线；渠道之间只留空，不再加线——加了企业微信也还是一排。 */
.footer__links { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 4px 24px; }
.footer__links a, .footer__channel { min-height: 36px; display: inline-flex; align-items: center; gap: 6px; color: var(--c-ink-dim); text-decoration: none; }
.footer__links a:hover, .footer__channel:hover, .footer__channel[aria-expanded='true'] { color: var(--c-ink); }
.footer__links a:hover .footer__mail { color: var(--c-ink-dim); }
.footer__contact { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0 16px; }
.footer__contact-label { padding-right: 16px; margin-right: -2px; border-right: 1px solid var(--c-line); color: var(--c-ink-dim); line-height: 1.2; }
.footer__channels { display: contents; }
.footer__channels > li { display: inline-flex; list-style: none; }
.footer__channel { padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
.footer__channel-logo { flex: none; display: block; }
.footer__mail { color: var(--c-ink-faint); font-variant-numeric: tabular-nums; letter-spacing: .01em; }
/* 左边：站名 │ 标语，一行，和右边「联系我们 │ 渠道」同一种细竖线。标语是短语，不带句号 */
.footer__brand { display: flex; flex-wrap: wrap; align-items: center; gap: 0 12px; min-height: 36px; margin: 0; }
.footer__brand > span:first-child { padding-right: 12px; border-right: 1px solid var(--c-line); line-height: 1.2; white-space: nowrap; }
.footer__brand .footer__note { display: inline; margin: 0; white-space: nowrap; }
/* 复制邮箱的提示：浮在地址上方，不占位 */
.footer__mailwrap { position: relative; display: inline-flex; }
.footer__toast { position: absolute; left: 50%; bottom: calc(100% + 2px); padding: 2px 10px; border-radius: 999px; background: var(--c-ink); color: var(--c-bg); font-size: 11px; line-height: 1.8; white-space: nowrap; opacity: 0; transform: translate(-50%, 4px); transition: opacity 160ms ease, transform 160ms ease; pointer-events: none; }
.footer__toast[data-show] { opacity: 1; transform: translate(-50%, 0); }
/* 二维码卡片：朝上弹，右边和按钮对齐；底色固定白色，暗色档也不反色，不然扫不出来 */
.footer__qr { position: relative; }
.footer__qr-card { position: absolute; z-index: 40; right: 0; bottom: calc(100% + 8px); margin: 0; padding: 12px 12px 10px; width: 170px; border: 1px solid var(--c-line); border-radius: var(--r-md); background: #fff; box-shadow: var(--shadow-lg); animation: surface-in 160ms ease; }
.footer__qr-card img { display: block; width: 144px; height: 144px; margin: 0 auto; }
.footer__qr-card figcaption { margin-top: 6px; color: #555; font-size: 11px; line-height: 1.5; text-align: center; white-space: nowrap; }
.footer__links .line-icon { flex: none; }
@keyframes surface-in { from { opacity: 0; } to { opacity: 1; } }
@media (min-width: 1024px) {
  .heroart__note { max-width: 240px; }
  .band--meta { grid-template-columns: minmax(240px, .8fr) minmax(0, 1.6fr); gap: 40px; }
  .band--meta .band__head { display: block; }
  .band--meta .domain-art { margin-bottom: 24px; }
  .band--meta .band__lead { max-width: 24em; }
}
@media (max-width: 1279px) {
  .quick-search-trigger kbd { display: none; }
  .topbar__nav { gap: 12px; }
  .hero { min-height: 420px; }
  .heroart__note { padding: 10px 12px; font-size: 11px; gap: 7px; }
  .heroart__note > svg { width: 24px; }
}
@media (max-width: 1023px) {
  .hero { padding-inline: 28px; }
  .hero:has(.heroart__object) .hero__body { width: 53%; }
  .heroart { width: 47%; }
  .heroart__note small { display: none; }
  .hero__title { font-size: 40px; }
  .hero__sub { font-size: 15px; }
  .hero__actions { gap: 16px; }
  .hero__actions .btn { padding-inline: 18px; }
  .heroart__note--idea { top: 19%; }
  .heroart__note--connect { bottom: 25%; }
  .heroart__caption { bottom: 14%; }
  .band__head:not(.band--meta .band__head) .domain-art { float: right; margin-left: 20px; }
  .reader-tools { gap: 6px; }
}
@media (max-width: 743px) {
  .topbar .topbar__inner.page { padding-inline: 16px; gap: 8px; }
  .topbar__catalog { display: none; }
  .topbar__controls { padding: 0; box-shadow: none; background: none; }
  .topbar__controls > .sel, .topbar__controls > .schemer { display: none; }
  .topbar__nav { gap: 8px; }
  .theme-picker__trigger, .quick-search-trigger { width: 40px; height: 40px; padding: 0; display: flex; justify-content: center; }
  .theme-picker__trigger > span, .theme-picker__trigger > svg:last-child, .quick-search-trigger > span { display: none; }
  .theme-picker__mobile-settings { display: grid; gap: 10px; margin-top: 22px; padding-top: 14px; border-top: 1px solid var(--c-line-soft); }
  .theme-picker__mobile-settings > div { display: flex; align-items: center; justify-content: space-between; gap: 16px; font-size: 13px; color: var(--c-ink-dim); }
  .theme-picker__mobile-settings .sel__btn { min-height: 40px; padding-inline: var(--s-3); }
  /* 窄屏顶栏那条规则把下拉的当前值藏了；这里的语言下拉没有图标，值要显示出来 */
  .theme-picker__mobile-settings .sel__value, .theme-picker__mobile-settings .sel__chev { display: inline-block; }
  /* 语言在面板最底下，面板自己会滚动、会裁掉溢出的部分，列表往上开 */
  .theme-picker__mobile-settings .sel__list { top: auto; bottom: calc(100% + var(--s-2)); }
  .theme-picker__mobile-settings .schemer__opt { width: 36px; height: 32px; }
  .theme-picker__mobile-settings .schemer__slide { width: 36px; height: 32px; }
  .theme-picker__panel { position: fixed; top: calc(var(--topbar-h) + 8px); inset-inline: 12px; width: auto; max-height: calc(100dvh - var(--topbar-h) - 24px); padding: 20px; }
  .theme-card__hint { font-size: 11px; }
  .theme-card__name > span { font-size: 9px; }
  .hero, .catalog .hero:has(.heroart__object) { display: block; min-height: 0; padding: 30px 24px 332px; margin-top: 18px; }
  .hero:has(.heroart__object) .hero__body { width: 100%; max-width: none; }
  .hero__eyebrow { font-size: 11px; margin-bottom: 18px; }
  .hero__title { font-size: 36px; }
  .hero__sub { font-size: 14px; margin-top: 18px; }
  .hero__actions { gap: 24px; margin-top: 22px; }
  .hero__actions .btn { min-height: 44px; font-size: 13px; }
  .heroart { width: 100%; height: 300px; top: auto; bottom: 12px; }
  .heroart .heroart__object { width: 84%; max-width: 320px; height: 260px; top: 46%; right: 50%; transform: translate(50%, -50%); }
  .heroart__halo { inset: 10% 10% 14%; }
  .heroart__note { font-size: 10px; padding: 9px 10px; }
  .heroart__note > svg { width: 20px; height: 20px; }
  .heroart__note--idea { top: 10%; left: 5%; }
  .heroart__note--connect { right: 4%; bottom: 18%; }
  .heroart__caption { bottom: 1%; font-size: 10px; }
  .heroart__path { inset: 0 10%; width: 80%; }
  .hero__stats { margin-top: 16px; }
  .catalog__rule { font-size: 11px; }
  .catalog-tools { padding: 18px 16px; margin-top: 28px; }
  .catalog-tools__row { flex-wrap: wrap; }
  .catalog-search { flex-basis: 100%; min-height: 48px; }
  .catalog-search input { font-size: 16px; }
  .catalog-search kbd { display: none; }
  .catalog-filter { min-height: 40px; padding-inline: 12px; font-size: 12px; }
  .catalog-tools__hint { font-size: 11px; }
  .domain-jumps { margin-right: -16px; padding-right: 16px; }
  .domain-jumps a { min-height: 40px; }
  .band { padding: 24px 20px; }
  .band--meta .band__head { grid-template-columns: 60px minmax(0, 1fr); column-gap: 14px; }
  .band--meta .domain-art { width: 60px; height: 60px; grid-row: 1 / 3; align-self: start; }
  .band--meta .band__lead, .band--meta .band__meta { grid-column: 1 / -1; }
  .band--meta .band__title { font-size: 24px; }
  .domain-art { width: 64px; height: 64px; margin-bottom: 12px; }
  .topic__sum { padding: 12px 8px; }
  .topic__name { flex-basis: 62%; }
  .topic__n { margin-left: 35px; }
  .kplink { align-items: flex-start; flex-wrap: wrap; column-gap: 8px; }
  .kplink__title { flex-basis: calc(100% - 38px); }
  .kplink__tail { padding-left: 28px; gap: 8px; flex-wrap: wrap; max-width: 100%; margin-top: 3px; }
  .continue-card { padding: 16px; gap: 12px; }
  .continue-card__context { display: none; }
  .continue-card > span:last-child { margin-left: auto; }
  .quick-search { margin-top: max(12px, env(safe-area-inset-top)); width: calc(100vw - 24px); max-height: calc(100dvh - 24px); }
  .quick-search__input { padding: 12px; gap: 8px; }
  .quick-search__body { max-height: 65dvh; padding: 8px; }
  .quick-search__footer { padding: 12px 16px; }
  .quick-search__footer > span { display: none; }
  .quick-search__footer a { min-height: 36px; display: flex; align-items: center; justify-content: space-between; width: 100%; }
  .quick-result { padding: 12px 8px; gap: 10px; flex-wrap: wrap; }
  .quick-result__meta { margin-left: 25px; font-size: 10px; }
  .quick-result__enter { margin-left: auto; }
  .quick-result__text { flex-basis: calc(100% - 28px); }
  .quick-result__title { font-size: 13px; }
  .quick-result__context { font-size: 10px; }
  .kp { padding-top: 20px; }
  .kp__tools { gap: 14px; margin-bottom: 22px; }
  .reader-tools { width: 100%; justify-content: space-between; gap: 6px; }
  .reader-tools .reader-copy { display: none; }
  .reader-focus, .reader-outline, .reader-code { min-height: 40px; font-size: 11px; padding-inline: 8px; }
  .reader-size button { min-height: 38px; width: 30px; }
  .reader-size > span { font-size: 10px; }
  .kp__title { font-size: 28px; }
  .kp__meta { font-size: 12px; gap: 10px; }
  .kp__head { padding-bottom: 24px; }
  .prevnext__side { padding: 20px; }
  .wall { padding: 24px; }
  .wall .state-art { width: 148px; }
  .login__story-copy { padding-top: 24px; }
  .page-state__body { grid-template-columns: minmax(0, 1fr); padding: 24px; gap: 12px; }
  .page-state__body > .state-art { width: 170px; margin-bottom: 0; }
  .footer { font-size: 11px; gap: 16px; }
  .footer { flex-direction: column; gap: 8px; }
  .footer__links { justify-content: flex-start; gap: 0 20px; }
  /* 窄屏上按钮可能排在一行中间：卡片改成对齐整排链接的左边，不跟着按钮走，免得顶出屏幕 */
  .footer__links { position: relative; }
  .footer__qr { position: static; }
  .footer__qr-card { right: auto; left: 0; }
}
@media (max-width: 430px) {
  .topbar:has(.navtoggle, .memberchip) .brand-name { display: none; }
  .topbar__left:has(.navtoggle) { min-width: 72px; }
  .topbar__brand { max-width: 140px; }
  .hero__actions { gap: 16px; flex-wrap: wrap; }
  .stat__n { font-size: 24px; }
  .stat__label { font-size: 10px; }
  .reader-focus { gap: 4px; }
  .reader-focus svg { width: 14px; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
}
@media (forced-colors: active) {
  .atmosphere, .heroart__halo, .heroart__path { display: none; }
  .quick-result[aria-selected='true'], .theme-card[aria-pressed='true'], .sidenav__list a[aria-current] { outline: 2px solid Highlight; }
}

/* ── 顶栏的会员入口和头像：和顶栏其他按钮同高 40px、同一种圆角（规则见 SYSTEM.md 界面一节）──
   颜色跟着画风走：没开通是画风强调色实底，已开通是强调色淡底；不写死任何颜色。 */
.memberchip {
  display: inline-flex; align-items: center; gap: 7px; height: 40px; padding: 0 14px;
  border: 0; border-radius: var(--r-md); white-space: nowrap; text-decoration: none;
  font-size: var(--t-sm); font-weight: 650; letter-spacing: .02em;
  transition: background var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.memberchip svg { width: 17px; height: 17px; flex: none; }
.memberchip:not([data-on]) {
  color: var(--c-on-accent); background: var(--c-accent-bg);
  box-shadow: inset 0 1px 0 var(--c-glass-sheen), 0 6px 16px -8px color-mix(in srgb, var(--c-accent-bg) 75%, transparent);
}
.memberchip:not([data-on]):hover { color: var(--c-on-accent); background: var(--c-accent-hover, var(--c-accent-bg)); text-decoration: none; }
.memberchip[data-on] {
  color: var(--c-on-accent-soft); background: var(--c-accent-soft);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-accent-bg) 28%, transparent);
}
.memberchip[data-on]:hover { color: var(--c-on-accent-soft); background: color-mix(in srgb, var(--c-accent-bg) 14%, var(--c-accent-soft)); text-decoration: none; }
.memberchip:focus-visible { outline: 2px solid var(--c-accent-bg); outline-offset: 3px; }
.account-avatar-link { display: grid; place-items: center; width: 40px; height: 40px; flex: none; border-radius: 26%; overflow: hidden; }
.account-avatar-link .account-avatar { width: 40px; height: 40px; }
.account-avatar-link:focus-visible { outline: 2px solid var(--c-accent-bg); outline-offset: 3px; }
/* 头像是账号菜单的开关（components/AccountMenu.tsx）：个人中心、学习详情、退出登录 */
.account-menu { position: relative; }
.account-menu .account-avatar-link { padding: 0; border: 0; background: none; cursor: pointer; }
.account-menu__panel { position: absolute; z-index: 45; top: calc(100% + 14px); right: 0; width: 240px; padding: 8px; border: 1px solid var(--c-glass-line); border-radius: var(--r-lg); background: linear-gradient(var(--c-glass-tint), var(--c-glass-tint)), var(--c-bg); box-shadow: var(--shadow-lg); }
.account-menu__who { display: grid; gap: 2px; padding: 10px 12px 12px; margin-bottom: 6px; border-bottom: 1px solid var(--c-line-soft); }
.account-menu__name { font-size: 14px; font-weight: 600; color: var(--c-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-menu__who span { font-size: 12px; color: var(--c-ink-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-menu__item { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px; padding: 0 12px; border: 0; border-radius: var(--r-sm); background: none; color: var(--c-ink); font: 14px var(--font-body); text-align: start; text-decoration: none; cursor: pointer; }
.account-menu__item:hover, .account-menu__item:focus-visible { background: var(--c-glass-hover); outline: none; }
.account-menu__signout { margin-top: 6px; border-top: 1px solid var(--c-line-soft); border-radius: 0 0 var(--r-sm) var(--r-sm); color: var(--c-gold); font-weight: 600; }

@media (max-width: 760px) {
  /* 已开通只留皇冠（字给读屏）；没开通字常显——只剩图标的话读者认不出是开会员 */
  .memberchip[data-on] { width: 40px; padding: 0; justify-content: center; }
  .memberchip[data-on] span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .memberchip:not([data-on]) { padding: 0 10px; gap: 5px; font-size: 13px; }
}
@media (max-width: 430px) {
  .memberchip:not([data-on]) { padding: 0 8px; gap: 4px; font-size: 12px; letter-spacing: 0; }
}
/* Shared interaction surfaces keep their geometry when the art direction changes. */
.catalog-menu { position: relative; }
.topbar__catalog { display: inline-flex; align-items: center; justify-content: center; gap: 7px; min-height: 40px; padding: 0 10px; border: 1px solid var(--c-line-soft); border-radius: var(--r-md); background: var(--c-glass); color: var(--c-ink-dim); font-size: 13px; cursor: pointer; }
.topbar__catalog:hover, .topbar__catalog[aria-expanded='true'] { background: var(--c-glass-hover); color: var(--c-gold); }
.catalog-menu__chevron { flex: none; }
.catalog-menu__panel { position: absolute; right: 0; top: calc(100% + 14px); width: min(440px, calc(100vw - 32px)); padding: 20px; border: 1px solid var(--c-glass-line); border-radius: var(--r-lg); background: linear-gradient(var(--c-glass-tint), var(--c-glass-tint)), var(--c-bg); box-shadow: var(--shadow-lg); backdrop-filter: blur(var(--glass-blur)); max-height: calc(100dvh - var(--topbar-h) - 24px); display: flex; flex-direction: column; z-index: 50; animation: surface-in 160ms ease; }
.catalog-menu__body { overflow: auto; overscroll-behavior: contain; min-height: 0; }
.catalog-menu__body > p { font-size: 13px; color: var(--c-ink-dim); padding: 12px; }
.catalog-menu__body ul { list-style: none; padding: 0; margin: 0; }
.catalog-menu__item { display: flex; gap: 14px; align-items: center; padding: 12px; border: 1px solid transparent; border-radius: var(--r-md); color: var(--c-ink); background-image: none; }
.catalog-menu__item:hover, .catalog-menu__item[aria-current] { background: color-mix(in srgb, var(--c-gold) 8%, transparent); border-color: var(--c-line-soft); text-decoration: none; }
.catalog-menu__item .domain-art { width: 48px; height: 48px; margin: 0; flex: none; }
.catalog-menu__text { display: grid; gap: 4px; flex: 1; min-width: 0; }
.catalog-menu__text strong { background: none; font-size: 14px; font-weight: 600; line-height: 1.6; }
.catalog-menu__text > span { font-size: 12px; line-height: 1.7; color: var(--c-ink-dim); }
.catalog-menu__text small { font-size: 11px; color: var(--c-ink-dim); }
/* 进入箭头和右上角的关闭叉同一套细线、同一尺寸；平时淡，指到哪一行才亮 */
.catalog-menu__go { display: grid; place-items: center; width: 24px; height: 24px; flex: none; color: var(--c-ink-faint); transition: color .15s; }
.catalog-menu__item:hover .catalog-menu__go, .catalog-menu__item:focus-visible .catalog-menu__go, .catalog-menu__item[aria-current] .catalog-menu__go { color: var(--c-gold); }
.catalog-menu__all { display: flex; align-items: center; justify-content: space-between; min-height: 44px; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--c-line); font-size: 13px; flex: none; }

/* 从顶栏「目录」跳到课程里的某一组：别被顶栏压住 */
#course-outline, .course-catalog [id^="section-"], .link-lessons__tree [id^="section-"] { scroll-margin-top: calc(var(--topbar-h) + 20px); }
.article-search { position: fixed; z-index: 35; top: calc(var(--topbar-h) + 12px); right: max(16px, env(safe-area-inset-right)); display: flex; align-items: center; gap: 8px; width: min(560px, calc(100vw - 32px)); padding: 10px 12px; border: 1px solid var(--c-glass-line); border-radius: var(--r-md); background: var(--c-bg-raise); color: var(--c-ink); box-shadow: var(--shadow-md); }
.article-search > svg { flex: none; color: var(--c-gold); }
.article-search input { min-width: 0; flex: 1; width: 100%; border: 0; background: transparent; color: var(--c-ink); min-height: 36px; font: inherit; font-size: 16px; }
.article-search input:focus { outline: none; }
.article-search:focus-within { border-color: var(--c-gold); }
.article-search__count { color: var(--c-ink-dim); font-size: 12px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.article-search .icon-button:disabled { opacity: .4; }
::highlight(article-matches) { color: var(--c-ink); background-color: color-mix(in srgb, var(--c-gold) 22%, var(--c-bg-raise)); }
::highlight(article-current) { color: var(--c-on-accent); background-color: var(--c-accent-bg); }
.sidenav__list > li { counter-increment: toc; }
.sidenav__sub li { counter-increment: none; }
.sidenav__collapse { width: 36px; height: 36px; color: var(--c-ink-dim); border: 1px solid transparent; }
.sidenav__collapse:hover { color: var(--c-gold); border-color: var(--c-line); }
.kp__body :is(h2, h3, h4) { scroll-margin-top: calc(var(--topbar-h) + 60px); }
.kp__body :is(h2, h3, h4):focus { outline: none; }
.kp__body :is(h2, h3, h4):focus-visible { outline: 2px solid var(--c-gold); outline-offset: 6px; }
.completion-retry { margin-top: 12px; }
/* Equal baseline boxes prevent the rounded font and theme decorations moving controls. */
.topbar :is(button, a) { line-height: 1.5; }
.reader-tools { justify-content: flex-end; }
.reader-tools > button, .reader-size { flex: none; }
.reader-size button { width: 40px; min-height: 40px; }
.reader-size > span { font-size: 13px; }
@media (max-width: 1279px) {
  .catalog-menu__panel { position: fixed; right: 16px; top: calc(var(--topbar-h) + 8px); }
}
@media (max-width: 743px) {
  .topbar__catalog { width: 40px; height: 40px; padding: 0; }
  .topbar__catalog > span { display: none; }
  .catalog-menu__panel { inset-inline: 12px; width: auto; padding: 16px; }
  .reader-tools { justify-content: flex-start; gap: 8px; }
  .reader-size button { width: 44px; min-height: 44px; }
  .reader-size > span { font-size: 13px; }
  .reader-tools .reader-copy { display: inline-flex; }
  .reader-find { min-height: 40px; }
  .article-search { flex-wrap: wrap; gap: 4px; }
  .article-search input { flex-basis: calc(100% - 32px); }
  .article-search__count { flex: 1; padding-left: 4px; }
  .article-search .icon-button { min-height: 40px; min-width: 40px; }
}
@media (max-width: 430px) {
  .topbar .brand-name { display: none; }
  /* 站名藏起来以后站标单独出现，没有字可对齐，按图标的大小给 */
  .topbar .brand-symbol { width: 26px; height: 26px; }
  .topbar__nav { gap: 6px; }
  .topbar .topbar__inner.page { gap: 6px; padding-inline: 12px; }
  .topbar__nav > .btn { padding-inline: 10px; }
}
@media (forced-colors: active) {
  .completion-button[data-completed='true'], .catalog-menu__item[aria-current] { outline: 2px solid Highlight; }
  ::highlight(article-current) { color: HighlightText; background-color: Highlight; }
}

/* 浏览器自带的搜索框清空叉：粗、黑、跟画风无关，和旁边的细线图标并排很扎眼。清空由各自的按钮负责。 */
input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; display: none; }

/* 顶栏「目录」弹层里，线下的课（企业内训）不列目录，说清是线下课程、怎么约 */
.catalog-menu__offline { display: grid; gap: 10px; padding: 8px 4px 4px; }
.catalog-menu__offline p { margin: 0; color: var(--c-ink-dim); font-size: 14px; line-height: 1.7; }
.catalog-menu__offline .btn { justify-self: start; }
/* Admin workspace. Tokens keep all four styles and both color schemes intact. */
.admin, .admin__dialog {
  --c-admin-danger: color-mix(in srgb, var(--c-coral) 80%, var(--c-ink));
  --c-admin-success: color-mix(in srgb, var(--c-free) 80%, var(--c-ink));
}
.admin { padding-block: 24px 40px; }
.admin :is(button, a, input, textarea):focus-visible, .admin__dialog :is(button, textarea):focus-visible { outline: 2px solid var(--c-gold); outline-offset: 3px; }
.admin :is(button, a, input), .admin__dialog :is(button, textarea) { scroll-margin-block: calc(var(--topbar-h) + 24px) 24px; }
.admin__head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px; margin-bottom: 18px; }
.admin__eyebrow { margin: 0 0 6px; color: var(--c-ink-dim); font-size: var(--t-xs); font-weight: 600; letter-spacing: .08em; }
.admin__title { margin: 0; color: var(--c-ink); font: 700 var(--t-2xl)/1.3 var(--font-display); }
.admin__who { margin: 0; display: flex; align-items: center; gap: 8px; color: var(--c-ink-dim); font-size: var(--t-xs); }
.admin__online { width: 7px; height: 7px; flex: none; border-radius: 50%; background: var(--c-admin-success); }
.admin__overview { margin-bottom: 20px; }
.admin__overview > summary { display: flex; align-items: center; justify-content: space-between; min-height: 44px; color: var(--c-ink-dim); font-size: var(--t-xs); cursor: pointer; list-style: none; }
.admin__overview > summary::-webkit-details-marker { display: none; }
.admin__overview > summary span { color: var(--c-gold); }
.admin__overview > summary:focus-visible { outline: 2px solid var(--c-gold); outline-offset: 2px; }
.admin__stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0; border: 1px solid var(--c-line-soft); border-radius: var(--r-lg); background: var(--c-bg-raise); }
.admin__stats > div { padding: 14px 20px; min-width: 0; border-inline-end: 1px solid var(--c-line-soft); }
.admin__stats > div:last-child { border-inline-end: 0; }
.admin__stats dt { color: var(--c-ink-dim); font-size: var(--t-xs); }
.admin__stats dd { margin: 4px 0; color: var(--c-ink); font: 700 clamp(1.4rem, 2.4vw, 2rem)/1.2 var(--font-display); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.admin__stats dd a { display: flex; align-items: center; justify-content: space-between; gap: 8px; color: inherit; text-decoration: none; min-height: 44px; }
.admin__stats dd a:hover { color: var(--c-gold); }
.admin__stats dd .line-icon { opacity: .55; flex: none; }
.admin__stats p { font-family: var(--font-body); font-weight: 400; margin: 5px 0 0; color: var(--c-ink-dim); font-size: var(--t-xs); line-height: 1.6; }
.admin__stats-error { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 16px; margin-bottom: 20px; color: var(--c-ink-dim); border: 1px solid var(--c-line-soft); border-radius: var(--r-md); }
.admin__tabs { display: flex; gap: 6px; padding: 5px; margin-bottom: 20px; width: fit-content; max-width: 100%; border: 1px solid var(--c-glass-line); border-radius: var(--r-lg); background: var(--c-glass); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); }
.admin__tab { display: flex; align-items: baseline; justify-content: center; gap: 14px; padding: 9px 20px; min-height: 44px; border-radius: var(--r-md); color: var(--c-ink-dim); font-weight: 700; text-decoration: none; }
.admin__tab span { font-size: var(--t-xs); font-weight: 400; }
.admin__tab:hover { background: var(--c-glass-hover); color: var(--c-ink); }
.admin__tab[aria-current='page'] { color: var(--c-on-accent-soft); background: var(--c-accent-soft); box-shadow: inset 0 0 0 1px var(--c-glass-line); }
.admin__panel, .admin__section { padding: 20px; border: 1px solid var(--c-line-soft); border-radius: var(--r-lg); background: var(--c-bg-raise); min-width: 0; }
.admin__panel-head, .admin__detail-head { display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 20px; }
.admin__panel-head { margin-bottom: 16px; }
.admin__panel-head h2 { margin: 0; font: 700 var(--t-lg)/1.4 var(--font-display); color: var(--c-ink); }
.admin__panel-head p { margin: 6px 0 0; color: var(--c-ink-dim); font-size: var(--t-xs); line-height: 1.7; }
.admin__tools { display: flex; align-items: flex-end; flex-wrap: wrap; gap: 12px; padding: 12px 14px; background: color-mix(in srgb, var(--c-ink) 3%, transparent); border-radius: var(--r-md); }
.admin__search { flex: 1 1 18rem; min-width: 0; }
.admin__search .field__box { margin-top: 7px; min-height: 44px; padding: 0 12px; }
.admin__search .field__input { min-width: 0; width: 100%; padding-block: 11px; font-size: 16px; }
.admin__filter { flex: 0 1 12rem; min-width: 0; }
.admin__filter .sel { margin-top: 7px; width: 100%; }
.admin__filter .sel__btn { border: 1px solid var(--c-line-soft); border-radius: var(--r-md); padding-inline: 12px; width: 100%; justify-content: space-between; }
.admin :is(.btn, .sel__btn), .admin__dialog :is(.btn, .sel__btn) { min-height: 44px; }
.admin .sel__value, .admin .sel__chev, .admin__dialog .sel__value, .admin__dialog .sel__chev { display: inline-block; }
.admin__filter .sel__list { min-width: 100%; }
.admin__icon-btn { display: inline-flex; align-items: center; justify-content: center; flex: none; min-width: 44px; min-height: 44px; padding: 8px; border: 0; border-radius: var(--r-sm); background: transparent; color: var(--c-ink-dim); cursor: pointer; }
.admin__icon-btn:hover { color: var(--c-ink); background: var(--c-glass-hover); }
.admin__result-bar { display: flex; justify-content: space-between; align-items: center; gap: 8px 20px; flex-wrap: wrap; min-height: 50px; padding-block: 12px; color: var(--c-ink-dim); font-size: var(--t-xs); }
.admin__filters-applied { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; min-width: 0; }
.admin__query { max-width: 24rem; overflow-wrap: anywhere; padding: 4px 10px; border-radius: var(--r-sm); background: var(--c-accent-soft); color: var(--c-on-accent-soft); }
.admin__table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); line-height: 1.6; }
.admin__table th { padding: 12px; color: var(--c-ink-dim); background: color-mix(in srgb, var(--c-ink) 3%, transparent); font-size: var(--t-xs); font-weight: 600; text-align: start; white-space: nowrap; border-block: 1px solid var(--c-line-soft); }
.admin__table td { padding: 7px 12px; border-bottom: 1px solid var(--c-line-soft); color: var(--c-ink); vertical-align: middle; overflow-wrap: anywhere; }
.admin__table tr:last-child td { border-bottom: 0; }
.admin__table tbody tr:hover { background: color-mix(in srgb, var(--c-ink) 2%, transparent); }
.admin__table .admin__identity { font-weight: 650; }
.admin__table--orders .admin__identity { max-width: 15rem; }
.admin__product-cell { min-width: 8rem; overflow-wrap: anywhere; }
.admin__nowrap { white-space: nowrap; }
.admin__product-name { display:block; margin-top:6px; font-size:.78rem; line-height:1.6; color:var(--c-ink-dim); overflow-wrap:anywhere; }
.admin__mono { font-family: var(--font-mono); font-size: var(--t-xs); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.admin__amount { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.admin__link { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; max-width: 100%; padding: 0; border: 0; background: transparent; color: var(--c-gold); font: inherit; font-variant-numeric: tabular-nums; text-align: start; text-decoration: none; cursor: pointer; overflow-wrap: anywhere; }
.admin__link.admin__mono { font-family: var(--font-mono); font-size: var(--t-xs); word-break: break-all; }
.admin__link:hover { text-decoration: underline; text-underline-offset: 4px; }
.admin__link .line-icon { flex: none; }
.admin__row-action { white-space: nowrap; }
.admin__row-action .admin__link { font-size: var(--t-xs); }
.admin__tags { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.admin__tag { display: inline-flex; align-items: center; padding: 3px 9px; border-radius: var(--r-sm); font: 600 var(--t-xs)/1.7 var(--font-body); white-space: nowrap; color: var(--c-ink-dim); background: color-mix(in srgb, var(--c-ink) 7%, transparent); }
.admin__tag:is([data-s='active'], [data-s='paid'], [data-s='action-grant'], [data-s='action-unban']) { color: var(--c-admin-success); background: color-mix(in srgb, var(--c-admin-success) 10%, var(--c-bg-raise)); }
.admin__tag:is([data-s='expired'], [data-s='refund-abnormal'], [data-s='banned'], [data-s='action-ban']) { color: var(--c-admin-danger); background: color-mix(in srgb, var(--c-admin-danger) 9%, var(--c-bg-raise)); }
.admin__tag[data-s='refund-processing'] { color: var(--c-on-accent-soft); background: var(--c-accent-soft); }
.admin__pager { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; padding-top: 20px; margin-top: 8px; border-top: 1px solid var(--c-line-soft); color: var(--c-ink-dim); font-size: var(--t-xs); }
.admin__pages { display: flex; align-items: center; gap: 14px; }
.admin__page-number { font-variant-numeric: tabular-nums; white-space: nowrap; }
.admin__state { display: flex; min-height: 260px; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 32px 16px; color: var(--c-ink-dim); text-align: start; }
.admin__state strong { color: var(--c-ink); font-size: var(--t-base); }
.admin__state p { max-width: 30rem; margin: 0 0 8px; font-size: var(--t-sm); line-height: 1.7; }
.admin__state-symbol { display: grid; place-items: center; width: 44px; height: 44px; background: var(--c-accent-soft); color: var(--c-on-accent-soft); border-radius: 50%; font: 600 var(--t-xl)/1 var(--font-body); }
.admin__spinner { width: 20px; height: 20px; border: 2px solid var(--c-line); border-top-color: var(--c-gold); border-radius: 50%; animation: admin-spin .8s linear infinite; }
@keyframes admin-spin { to { transform: rotate(360deg); } }
.admin__breadcrumbs { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; min-height: 44px; margin-bottom: 16px; color: var(--c-ink-dim); font-size: var(--t-xs); }
.admin__back { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; color: var(--c-gold); text-decoration: none; }
.admin__back:hover { text-decoration: underline; text-underline-offset: 4px; }
.admin__back-icon { display: flex; transform: rotate(180deg); }
.admin__detail-head > div { min-width: 0; }
.admin__detail-head h2 { margin: 0 0 12px; color: var(--c-ink); font: 700 var(--t-xl)/1.4 var(--font-display); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.admin__detail-head .admin__order-amount { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; font-size: var(--t-2xl); }
.admin__acts { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.admin__danger:not(:disabled) { color: var(--c-admin-danger); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-admin-danger) 35%, transparent); }
.admin__sub { margin: 0; color: var(--c-ink-dim); }
.admin__facts { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; margin: 24px 0 0; padding-top: 24px; border-top: 1px solid var(--c-line-soft); }
.admin__facts dt { color: var(--c-ink-dim); font-size: var(--t-xs); }
.admin__facts dd { margin: 7px 0 0; color: var(--c-ink); font-size: var(--t-sm); overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
.admin__facts .admin__link { margin-block: -10px; }
.admin__fact-wide { grid-column: span 2; }
.admin__copy-value { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 8px; min-width: 0; max-width: 100%; }
.admin__copy-value > span { min-width: 0; overflow-wrap: anywhere; }
.admin__copy { color: var(--c-gold); background: transparent; border: 1px solid var(--c-line-soft); border-radius: var(--r-sm); padding: 5px 10px; min-height: 32px; max-width: 100%; font: 500 var(--t-xs)/1.5 var(--font-body); cursor: pointer; }
.admin__copy:hover { background: var(--c-glass-hover); }
.admin__notice { margin-top: 20px; padding: 14px 16px; border-radius: var(--r-md); border: 1px solid color-mix(in srgb, var(--c-admin-success) 25%, transparent); background: color-mix(in srgb, var(--c-admin-success) 6%, var(--c-bg-raise)); color: var(--c-ink); font-size: var(--t-sm); line-height: 1.7; overflow-wrap: anywhere; }
.admin__notice[data-error='true'] { border-color: color-mix(in srgb, var(--c-admin-danger) 30%, transparent); background: color-mix(in srgb, var(--c-admin-danger) 6%, var(--c-bg-raise)); }
.admin__hint { margin: 12px 0 0; color: var(--c-ink-dim); font-size: var(--t-xs); line-height: 1.7; }
.admin__section { margin-top: 20px; }
.admin__section-title { display: flex; align-items: center; gap: 10px; margin: 0 0 20px; color: var(--c-ink); font-size: var(--t-base); }
.admin__count { padding: 2px 8px; border-radius: var(--r-sm); background: color-mix(in srgb, var(--c-ink) 6%, transparent); color: var(--c-ink-dim); font-size: var(--t-xs); font-variant-numeric: tabular-nums; }
.admin__empty { margin: 0; padding: 24px 0; color: var(--c-ink-dim); font-size: var(--t-sm); }
.admin__timeline { list-style: none; padding: 0; margin: 0; }
.admin__timeline li { position: relative; margin-left: 5px; padding: 0 0 24px 22px; border-left: 1px solid var(--c-line); }
.admin__timeline li:last-child { padding-bottom: 0; }
.admin__timeline li::before { content: ''; position: absolute; top: 8px; left: -4px; width: 7px; height: 7px; border-radius: 50%; background: var(--c-gold); }
.admin__timeline-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 16px; }
.admin__timeline time { color: var(--c-ink-dim); font-size: var(--t-xs); }
.admin__timeline p { margin: 8px 0 5px; color: var(--c-ink); font-size: var(--t-sm); white-space: pre-wrap; overflow-wrap: anywhere; }

/* Modal surfaces use the same theme tokens as the workspace. */
.admin__dialog { color: var(--c-ink); background: var(--c-bg-raise); border: 1px solid var(--c-glass-line); border-radius: var(--r-lg); padding: 0; width: min(560px, calc(100% - 32px)); max-width: none; max-height: calc(100dvh - 40px); margin: auto; overflow: auto; overscroll-behavior: contain; box-shadow: 0 24px 80px color-mix(in srgb, var(--c-ink) 18%, transparent); }
.admin__dialog::backdrop { background: color-mix(in srgb, var(--c-bg) 48%, transparent); backdrop-filter: blur(8px) brightness(.7); -webkit-backdrop-filter: blur(8px) brightness(.7); }
.admin__confirm { padding: 28px; }
.admin__confirm-heading { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.admin__confirm-heading h3 { margin: 5px 0 0; font: 700 var(--t-lg)/1.6 var(--font-display); }
.admin__confirm-heading .admin__icon-btn { margin: -6px -10px 0 0; }
.admin__confirm-lead { margin: 16px 0 22px; padding: 12px 16px; border-radius: var(--r-md); background: var(--c-accent-soft); color: var(--c-on-accent-soft); font-size: var(--t-sm); line-height: 1.8; }
.admin__confirm[data-danger='true'] .admin__confirm-lead { background: color-mix(in srgb, var(--c-admin-danger) 7%, var(--c-bg-raise)); color: var(--c-ink); border-left: 3px solid var(--c-admin-danger); }
.admin__confirm fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
.admin__duration { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; margin-bottom: 20px; }
.admin__duration > .field__label { width: 100%; }
.admin__duration .admin__hint { margin: 0; }
.admin__duration .sel__btn { min-width: 120px; justify-content: space-between; }
.admin__textarea { display: block; width: 100%; padding: 12px 14px; border: 1px solid var(--c-line); border-radius: var(--r-md); color: var(--c-ink); background: var(--c-glass); font: 400 16px/1.6 var(--font-body); resize: vertical; min-height: 108px; max-height: 220px; }
.admin__textarea[aria-invalid='true'] { border-color: var(--c-admin-danger); }
.admin__textarea::placeholder { color: var(--c-ink-dim); }
.admin__required { font-size: var(--t-xs); font-weight: 400; color: var(--c-admin-danger); }
.admin__field-hint { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px; margin-top: 8px; color: var(--c-ink-dim); font-size: var(--t-xs); }
.admin__field-error { color: var(--c-admin-danger); font-size: var(--t-sm); }
.admin__confirm-actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 24px; }
.admin__danger-primary { background: var(--c-admin-danger); color: var(--c-bg); border: 1px solid transparent; }
.admin__danger-primary:hover:not(:disabled) { filter: brightness(.94); }
.admin__dialog button:disabled { cursor: wait; opacity: .55; }

/* Breakpoints mirror packages/shared-config/src/breakpoints.ts. */
@media (max-width: 1279px) {
  .admin__table th, .admin__table td { padding-inline: 8px; }
  .admin__table { font-size: var(--t-xs); }
}
@media (max-width: 1023px) {
  .admin__stats > div { padding: 18px; }
  .admin__table { font-size: var(--t-sm); }
  .admin__table thead { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .admin__table, .admin__table tbody { display: block; }
  .admin__table tr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 20px; padding: 18px; margin-bottom: 12px; border: 1px solid var(--c-line-soft); border-radius: var(--r-md); }
  .admin__table tr:last-child { margin-bottom: 0; }
  .admin__table td { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; padding: 0; border: 0; }
  .admin__table td::before { content: attr(data-label); color: var(--c-ink-dim); font-size: var(--t-xs); }
  .admin__table .admin__identity { grid-column: 1 / -1; max-width: none; border-bottom: 1px solid var(--c-line-soft); padding-bottom: 8px; }
  .admin__identity .admin__link { font-size: var(--t-base); }
  .admin__table .admin__row-action { grid-column: 1 / -1; align-items: flex-end; border-top: 1px solid var(--c-line-soft); padding-top: 6px; }
  .admin__row-action::before { display: none; }
  .admin__row-action .admin__link { min-width: 100%; justify-content: flex-end; font-size: var(--t-sm); }
  .admin__table td:not(.admin__identity):not(.admin__row-action) .admin__link { min-height: 32px; }
  .admin__facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 743px) {
  .admin { padding-block: 24px 40px; }
  .admin__head { gap: 12px; margin-bottom: 20px; }
  .admin__title { font-size: var(--t-xl); }
  .admin__who { width: 100%; }
  .admin__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-bottom: 20px; }
  .admin__stats > div:nth-child(2) { border-inline-end: 0; }
  .admin__stats > div:nth-child(-n+2) { border-bottom: 1px solid var(--c-line-soft); }
  .admin__stats dd { margin-block: 4px; }
  .admin__tabs { width: 100%; }
  .admin__tab { flex: 1; padding-inline: 12px; }
  .admin__tab span { display: none; }
  .admin__panel, .admin__section { padding: 18px; }
  .admin__panel-head { flex-wrap: nowrap; gap: 12px; margin-bottom: 18px; }
  .admin__panel-head > div { min-width: 0; }
  .admin__panel-head .btn { flex: none; padding-inline: 12px; }
  .admin__tools { padding: 14px; gap: 12px; }
  .admin__search { flex-basis: 100%; }
  .admin__filter { flex: 1; }
  .admin__result-bar { align-items: flex-start; flex-direction: column; justify-content: center; }
  .admin__table tr { padding: 14px; gap: 12px; }
  .admin__table--users td:nth-child(5), .admin__table--users td:nth-child(6) { font-size: var(--t-xs); }
  .admin__table--orders .admin__identity .admin__link { font-size: var(--t-xs); }
  .admin__pager { align-items: stretch; gap: 12px; }
  .admin__pager > span { width: 100%; }
  .admin__pages { width: 100%; justify-content: space-between; gap: 6px; }
  .admin__pages .btn { padding-inline: 12px; }
  .admin__detail-head { gap: 16px; }
  .admin__acts { width: 100%; }
  .admin__acts .btn { flex: 1; }
  .admin__detail-head h2 { font-size: var(--t-lg); }
  .admin__facts { gap: 20px 16px; }
  .admin__facts dd { font-size: var(--t-xs); }
  .admin__copy { min-height: 44px; }
  .admin__dialog { width: 100%; max-height: calc(100dvh - 20px); margin: auto 0 0; border-radius: var(--r-lg) var(--r-lg) 0 0; border-bottom: 0; }
  .admin__confirm { padding: 22px 20px max(24px, env(safe-area-inset-bottom)); }
  .admin__confirm-actions { position: sticky; bottom: 0; padding-top: 14px; padding-bottom: 2px; background: var(--c-bg-raise); }
  .admin__confirm-actions .btn { flex: 1; }
}
@media (prefers-reduced-motion: reduce) { .admin__spinner { animation: none; border-style: dotted; } }
.admin__step-up { margin-top: 16px; }
.admin__step-up .admin__field-hint { margin: 8px 0 0; }
.admin__step-up-ok { margin: 16px 0 0; }

.admin__tools { flex-wrap:wrap; }

/* ── 课程模块 ── */
button.admin__back { padding: 0; border: 0; background: transparent; font: inherit; font-size: var(--t-xs); cursor: pointer; }
.admin-courses { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); gap: 16px; margin-top: 16px; }
.admin-course { display: flex; flex-direction: column; gap: 10px; padding: 18px; border: 1px solid var(--c-line-soft); border-radius: var(--r-md); background: var(--c-bg); min-width: 0; }
.admin-course__head { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; }
.admin-course h3 { margin: 0; font: 700 var(--t-base)/1.5 var(--font-display); color: var(--c-ink); }
.admin-course__summary { margin: 0; color: var(--c-ink-dim); font-size: var(--t-xs); line-height: 1.75; }
.admin-course__facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 16px; margin: 4px 0 0; padding-top: 12px; border-top: 1px solid var(--c-line-soft); }
.admin-course__facts dt { color: var(--c-ink-dim); font-size: var(--t-xs); }
.admin-course__facts dd { margin: 3px 0 0; color: var(--c-ink); font-size: var(--t-sm); font-variant-numeric: tabular-nums; }
.admin-course__acts .admin__link { font-size: var(--t-sm); }
.admin-course__acts { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-top: auto; padding-top: 8px; }
.admin-course__acts .admin__link { margin-left: auto; }
/* 产品配置页底部：进目录子页的入口 */
.admin-course-entry { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px 24px; }
.admin-course-entry h2 { margin: 0 0 6px; font-size: var(--t-lg); }
.admin-course-entry .admin__hint { margin: 0; max-width: 40rem; }
.admin-course-entry .btn { gap: 10px; }
.admin-visibility__lead { margin: 0 0 4px; color: var(--c-ink); line-height: 1.7; }
.admin-outline-page h2 .admin__count { margin-left: 10px; vertical-align: middle; }
.admin-form { display: grid; gap: 22px; margin-top: 20px; }
.admin-form fieldset { min-width: 0; margin: 0; padding: 0; border: 0; display: grid; gap: 14px; }
.admin-form__legend { padding: 0; margin-bottom: 4px; color: var(--c-ink); font-weight: 700; font-size: var(--t-sm); }
.admin-form__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); gap: 14px; }
.admin-form__pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 18px; }
.admin-form__switches { display: flex; flex-wrap: wrap; gap: 10px 24px; }
.admin-form__actions { display: flex; justify-content: flex-end; }
.admin-field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.admin-field[data-wide] { grid-column: 1 / -1; }
.admin-field .admin__field-hint { margin-top: 0; }
.admin-input { width: 100%; min-height: 44px; padding: 0 12px; border: 1px solid var(--c-line); border-radius: var(--r-md); color: var(--c-ink); background: var(--c-glass); font: 400 16px/1.4 var(--font-body); }
.admin-field__box { display: flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 12px; border: 1px solid var(--c-line); border-radius: var(--r-md); background: var(--c-glass); color: var(--c-ink-dim); }
.admin-field__box .field__input { flex: 1; min-width: 0; font-size: 16px; }
.admin-textarea--tall { min-height: 200px; max-height: 420px; }
.admin-switch { display: inline-flex; align-items: center; gap: 10px; min-height: 44px; color: var(--c-ink); font-size: var(--t-sm); cursor: pointer; }
.admin-switch input { width: 20px; height: 20px; accent-color: var(--c-gold); }
.admin-lessons__add { margin-bottom: 16px; }
.admin-lessons { list-style: none; margin: 16px 0 0; padding: 0; }
.admin-lessons li { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 14px; padding: 14px 0; border-bottom: 1px solid var(--c-line-soft); }
.admin-lessons li:last-child { border-bottom: 0; }
.admin-lessons li[data-published='false'] .admin-lessons__title { color: var(--c-ink-dim); }
.admin-lessons__no { color: var(--c-gold); font-size: var(--t-xs); font-variant-numeric: tabular-nums; }
.admin-lessons__body { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.admin-lessons__title { color: var(--c-ink); font-size: var(--t-sm); font-weight: 700; overflow-wrap: anywhere; }
.admin-lessons__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; color: var(--c-ink-dim); font-size: var(--t-xs); font-variant-numeric: tabular-nums; }
.admin-lessons__warn { color: var(--c-admin-danger); }
.admin-lessons__url { min-height: 0; font-size: var(--t-xs); }
.admin-lessons__acts { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 6px; }
.admin-attachments { list-style: none; margin: 0; padding: 0; }
.admin-attachments li { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--c-line-soft); }
.admin-attachments__body { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.admin-attachments__title { color: var(--c-ink); font-size: var(--t-sm); font-weight: 700; overflow-wrap: anywhere; }
.admin-attachments__acts { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; }
.admin-attachments__form { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--c-line); }
.admin-attachments__group { display: grid; gap: 10px; }
.admin-attachments__group + .admin-attachments__group { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--c-line); }
.admin-attachments__group h4 { margin: 0; font-size: var(--t-sm); color: var(--c-ink); }
.admin-attachments__group > .btn { justify-self: start; }
@media (max-width: 743px) {
  .admin-attachments li { grid-template-columns: minmax(0, 1fr); }
  .admin-attachments__acts { justify-content: flex-start; }
}
.admin-uploader { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 16px; margin-bottom: 16px; }
.admin-uploader label.btn { cursor: pointer; }
.admin-uploader label.btn[aria-disabled] { opacity: .55; pointer-events: none; }
.admin-uploader__progress { display: grid; gap: 8px; width: 100%; padding: 14px 16px; border: 1px solid var(--c-line-soft); border-radius: var(--r-md); }
.admin-uploader__line { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px; color: var(--c-ink); font-size: var(--t-xs); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.admin-uploader progress { width: 100%; height: 8px; accent-color: var(--c-gold); }
.admin-uploader__progress .btn { justify-self: start; }
.admin__dialog--wide { width: min(760px, calc(100% - 32px)); }
.admin-preview { display: block; width: auto; max-width: 100%; max-height: 70dvh; margin: 0 auto; border-radius: var(--r-md); background: #000; }
@media (max-width: 743px) {
  .admin-form__pair { grid-template-columns: minmax(0, 1fr); }
  .admin-form__actions .btn { width: 100%; }
  .admin-lessons li { grid-template-columns: auto minmax(0, 1fr); }
  .admin-lessons__acts { grid-column: 1 / -1; justify-content: flex-start; }
  .admin__dialog--wide { width: 100%; }
}
.admin-textarea--short { min-height: 72px; }
.admin-toasts { position: fixed; z-index: 1000; left: 50%; bottom: max(24px, env(safe-area-inset-bottom)); transform: translateX(-50%); display: grid; gap: 8px; width: max-content; max-width: calc(100% - 32px); pointer-events: none; }
.admin-toast { margin: 0; padding: 12px 18px; border-radius: var(--r-md); background: var(--c-ink); color: var(--c-bg); font-size: var(--t-sm); line-height: 1.6; box-shadow: 0 12px 40px color-mix(in srgb, var(--c-ink) 25%, transparent); animation: admin-toast-in 180ms ease; overflow-wrap: anywhere; }
@keyframes admin-toast-in { from { opacity: 0; transform: translateY(8px); } }
@media (prefers-reduced-motion: reduce) { .admin-toast { animation: none; } }

/* ── 课程目录（领域 → 主题 → 课时） ── */
.admin__tag[data-s='missing'] { color: var(--c-admin-danger); background: color-mix(in srgb, var(--c-admin-danger) 9%, var(--c-bg-raise)); }
.admin-outline__stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin: 0 0 16px; }
.admin-outline__stats > div { padding: 12px 14px; border: 1px solid var(--c-line-soft); border-radius: var(--r-md); }
.admin-outline__stats dt { color: var(--c-ink-dim); font-size: var(--t-xs); }
.admin-outline__stats dd { margin: 4px 0 0; color: var(--c-ink); font: 700 var(--t-lg)/1.3 var(--font-display); font-variant-numeric: tabular-nums; }
.admin-outline__tools { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; padding: 12px 14px; border-radius: var(--r-md); background: color-mix(in srgb, var(--c-ink) 3%, transparent); }
.admin-outline__upload { margin-bottom: 14px; position: sticky; top: calc(var(--topbar-h, 64px) + 8px); z-index: 5; background: var(--c-bg-raise); }
.admin-outline { border-top: 1px solid var(--c-line-soft); }
.admin-outline__section { border-bottom: 1px solid var(--c-line-soft); }
.admin-outline__section[data-depth='1'] { border-bottom: 0; border-top: 1px dashed var(--c-line-soft); margin-left: 4px; }
.admin-outline__section > summary { display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 6px 4px; list-style: none; cursor: pointer; }
.admin-outline__section > summary::-webkit-details-marker { display: none; }
.admin-outline__section > summary::before { content: ''; flex: none; width: 7px; height: 7px; border-right: 1.5px solid var(--c-ink-dim); border-bottom: 1.5px solid var(--c-ink-dim); transform: rotate(-45deg); margin: 0 4px; transition: transform .15s; }
.admin-outline__section[open] > summary::before { transform: rotate(45deg); }
.admin-outline__section > summary:hover .admin-outline__title { color: var(--c-gold); }
.admin-outline__section > summary:focus-visible { outline: 2px solid var(--c-gold); outline-offset: 2px; }
.admin-outline__title { min-width: 0; flex: 1; color: var(--c-ink); font-weight: 700; font-size: var(--t-sm); overflow-wrap: anywhere; }
.admin-outline__section[data-depth='1'] .admin-outline__title { font-weight: 600; }
.admin-outline__count { flex: none; color: var(--c-ink-dim); font-size: var(--t-xs); font-variant-numeric: tabular-nums; white-space: nowrap; }
.admin-outline__count[data-done='true'] { color: var(--c-admin-success); }
.admin-outline__acts { flex: none; }
.admin-outline__body { padding: 0 0 10px 22px; }
.admin-outline__lessons { list-style: none; margin: 0; padding: 0; }
.admin-outline__lesson { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px solid var(--c-line-soft); }
.admin-outline__lesson:has(> .admin-drag) { grid-template-columns: auto auto minmax(0, 1fr) auto; gap: 8px 10px; }
.admin-outline__section > summary > .admin-drag { order: -1; }
.admin-outline__lesson[data-published='false'] .admin-lessons__title { color: var(--c-ink-dim); }
.admin-outline__flat { border-top: 1px solid var(--c-line-soft); }
.admin-video-field__row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.admin-video-field__file { color: var(--c-ink); font-size: var(--t-sm); overflow-wrap: anywhere; }
.admin-video-field label.btn { cursor: pointer; }

/* 「更多」菜单 */
.admin-menu { position: relative; }
.admin-menu > summary { list-style: none; cursor: pointer; }
.admin-menu > summary::-webkit-details-marker { display: none; }
.admin-menu > summary[aria-disabled] { opacity: .55; cursor: not-allowed; }
.admin-menu__list { position: absolute; z-index: 20; right: 0; top: calc(100% + 6px); display: grid; min-width: 9.5rem; padding: 6px; border: 1px solid var(--c-glass-line); border-radius: var(--r-md); background: var(--c-bg-raise); box-shadow: 0 16px 40px color-mix(in srgb, var(--c-ink) 18%, transparent); }
.admin-menu__list button { min-height: 40px; padding: 8px 12px; border: 0; border-radius: var(--r-sm); background: transparent; color: var(--c-ink); font: inherit; font-size: var(--t-sm); text-align: start; white-space: nowrap; cursor: pointer; }
.admin-menu__list button:hover, .admin-menu__list button:focus-visible { background: var(--c-glass-hover); }
.admin-menu__list .admin-menu__danger { color: var(--c-admin-danger); }
.admin-menu__list { overflow-y: auto; max-width: calc(100vw - 32px); overscroll-behavior: contain; }
.admin-menu__list button { white-space: normal; overflow-wrap: anywhere; }
@media (max-width: 743px) {
  .admin-outline__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .admin-outline__section > summary { flex-wrap: wrap; row-gap: 4px; }
  .admin-outline__title { flex-basis: calc(100% - 120px); }
  .admin-outline__count { order: 3; margin-left: 30px; }
  .admin-outline__acts { order: 2; margin-left: auto; }
  .admin-outline__body { padding-left: 8px; }
  .admin-outline__lesson { grid-template-columns: auto minmax(0, 1fr); }
  .admin-outline__lesson .admin-lessons__acts { grid-column: 1 / -1; justify-content: flex-start; }
  .admin-outline__lesson:has(> .admin-drag) { grid-template-columns: auto auto minmax(0, 1fr); }
}

/* 「放在哪」的层级选择（components/admin/ParentPicker.tsx） */
.tree-pick__list { width: 100%; max-width: none; max-height: min(52vh, 24rem); }
.tree-pick__row { display: flex; align-items: center; gap: 2px; }
.tree-pick__row[data-depth='1'] { padding-left: 22px; }
.tree-pick__twist { display: inline-grid; place-items: center; flex: none; width: 30px; height: 36px; padding: 0; border: 0; border-radius: var(--r-sm); background: transparent; color: var(--c-ink-faint); cursor: pointer; }
button.tree-pick__twist:hover { background: var(--c-glass-hover); color: var(--c-ink); }
.tree-pick__twist svg { transition: transform var(--dur-fast) var(--ease); }
.tree-pick__twist[aria-expanded='true'] svg { transform: rotate(90deg); }
.tree-pick__item { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; min-height: 40px; padding: 6px 10px; border: 0; border-radius: var(--r-sm); background: transparent; color: var(--c-ink-dim); font: 600 var(--t-sm)/1.5 var(--font-body); text-align: start; cursor: pointer; }
.tree-pick__item:hover, .tree-pick__item:focus-visible { background: var(--c-glass-hover); color: var(--c-ink); outline: none; }
.tree-pick__item.is-on { color: var(--c-ink); }
.tree-pick__kind { flex: none; padding: 1px 7px; border-radius: var(--r-sm); background: color-mix(in srgb, var(--c-ink) 7%, transparent); color: var(--c-ink-faint); font-size: var(--t-xs); font-weight: 600; }
.tree-pick__title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.tree-pick__count { flex: none; color: var(--c-ink-faint); font-size: var(--t-xs); font-weight: 400; font-variant-numeric: tabular-nums; }
.tree-pick__row[data-kind='root'] .tree-pick__item { font-weight: 700; }

/* 弹框里的下拉、日历、层级选择：弹层就地展开（把下面的内容往下推），不浮在外面——弹框自己会滚动，浮层会被它的边裁掉 */
.admin__dialog .sel--field .sel__list { position: static; width: 100%; max-width: none; margin-top: 6px; animation: none; }
.admin__dialog .datepick__pop { width: min(100%, 18.5rem); }

/* 视频来源（外部链接 / 本站视频）：两项的分段选择 */
.admin-segmented { display: inline-flex; width: fit-content; gap: 4px; padding: 3px; border-radius: var(--r-sm); background: color-mix(in srgb, var(--c-ink) 6%, transparent); }
.admin-segmented__item { position: relative; }
.admin-segmented__item input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.admin-segmented__item span { display: block; padding: 6px 14px; border-radius: var(--r-sm); font: 600 var(--t-xs)/1.6 var(--font-body); color: var(--c-ink-dim); }
.admin-segmented__item input:checked + span { color: var(--c-ink); background: var(--c-bg-raise); box-shadow: inset 0 0 0 1px var(--c-line); }
.admin-segmented__item input:focus-visible + span { outline: 2px solid var(--c-accent); outline-offset: 1px; }
.admin-segmented__item input:disabled + span { opacity: .55; }

/* 拖拽排序（AdminUI 的 DragHandle）：手柄是六个小点。拖的时候：原来那一行换成虚线框；一张写着名字和「放到第几位」的卡片跟着指针；
   要放的位置是两行之间一道强调色粗线，行首一个圆点。放回原处时不画线 */
.admin-drag { flex: none; display: inline-grid; place-items: center; width: 28px; height: 28px; padding: 0; border: 0; border-radius: var(--r-sm); background: transparent; color: var(--c-ink-faint); cursor: grab; touch-action: none; }
.admin-drag:hover, .admin-drag:focus-visible { color: var(--c-ink); background: color-mix(in srgb, var(--c-ink) 7%, transparent); }
.admin-drag:active { cursor: grabbing; }
.admin-drag:disabled { visibility: hidden; }
body.admin-dragging, body.admin-dragging * { cursor: grabbing !important; user-select: none; }
[data-sort-group][data-dragging='true'] { outline: 2px dashed var(--c-accent); outline-offset: -2px; border-radius: var(--r-md); background: color-mix(in srgb, var(--c-accent) 6%, transparent); }
[data-sort-group][data-dragging='true'] > * { opacity: .45; }
.admin-drag-ghost { position: fixed; z-index: 2000; left: 0; top: 0; display: grid; gap: 2px; max-width: min(420px, calc(100vw - 32px)); padding: 10px 14px; border: 1px solid var(--c-accent); border-radius: var(--r-md); background: var(--c-bg-raise); color: var(--c-ink); box-shadow: 0 14px 36px color-mix(in srgb, var(--c-ink) 22%, transparent); pointer-events: none; }
.admin-drag-ghost strong { font-size: var(--t-sm); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.admin-drag-ghost span { font-size: var(--t-xs); color: var(--c-ink-dim); }
.admin-drag-ghost[data-ok='true'] span { color: var(--c-accent); font-weight: 600; }
.admin-drop-line { position: fixed; z-index: 1999; left: 0; top: 0; height: 4px; border-radius: 2px; background: var(--c-accent); pointer-events: none; display: none; }
.admin-drop-line[data-on='true'] { display: block; }
.admin-drop-line::before { content: ''; position: absolute; left: -6px; top: -4px; width: 12px; height: 12px; border-radius: 50%; background: var(--c-accent); box-shadow: 0 0 0 3px var(--c-bg-raise); }
/* Paper surfaces and themed artwork; interactive controls keep the existing glass. */
.section-nav{display:flex;align-items:center;gap:8px;padding:20px 0;border-bottom:1px solid var(--c-line);flex-wrap:wrap}
.section-nav a{color:var(--c-ink-dim);font-size:15px;font-weight:500;padding:8px 20px;border-radius:12px;text-decoration:none}
.section-nav a[aria-current="page"]{color:var(--c-gold);background:color-mix(in srgb,var(--c-gold) 8%,transparent)}
.section-nav a:hover{color:var(--c-ink);background:var(--c-bg-raise)}
.section-nav a{display:inline-flex;align-items:center;justify-content:center;line-height:1.4}
.section-nav a .line-icon{width:11px;height:11px;margin-left:3px;flex:none;opacity:.7}
/* 顶栏里那一份：只在电脑宽度出现，紧凑一些；这时页面顶部那一份藏起来 */
.section-nav--top{display:none}
@media (min-width:1280px){
.section-nav--top{display:flex;flex-wrap:nowrap;gap:2px;padding:0;border:0;margin-left:14px}
.section-nav--top a{font-size:15px;padding:7px 11px;white-space:nowrap}
.section-nav--page{display:none}
}
/* 1280–1727 顶栏要多放一排栏目：搜索、目录收成只有图标（和手机上一样），站名保持完整 */
@media (min-width:1280px) and (max-width:1727px){
.topbar .quick-search-trigger{width:40px;height:40px;padding:0;display:flex;justify-content:center}
.topbar .quick-search-trigger>span,.topbar .quick-search-trigger kbd{display:none}
.topbar__catalog{width:40px;height:40px;padding:0;justify-content:center}
.topbar__catalog>span,.topbar__catalog .catalog-menu__chevron{display:none}
.topbar__nav{gap:12px}
}
.portal-breadcrumbs{display:flex;flex-wrap:wrap;gap:9px;align-items:center;color:var(--c-ink-dim);font-size:.8rem;padding:22px 0 4px}
.portal-breadcrumbs__step{display:inline-flex;align-items:center;gap:9px;min-width:0;max-width:100%}.portal-breadcrumbs a{color:inherit;text-decoration:none;overflow-wrap:anywhere}.portal-breadcrumbs a:hover{color:var(--c-gold)}.portal-breadcrumbs svg{width:12px;height:12px;flex:none}.portal-breadcrumbs [aria-current]{overflow-wrap:anywhere}
.portal-hero{display:grid;grid-template-columns:1fr 1fr;align-items:center;gap:24px;padding:60px 0 64px}
.portal-eyebrow{display:flex;align-items:center;gap:9px;font-size:.77rem;letter-spacing:.12em;color:var(--c-gold);margin:0 0 20px}
.portal-eyebrow>span:empty{width:6px;height:6px;border-radius:50%;background:currentColor}
.portal h1{font-size:clamp(2.2rem,3.8vw,4rem);line-height:1.35;letter-spacing:-.045em;margin:0 0 23px;font-weight:750}.portal h1 em{font-style:normal;color:var(--c-gold)}
.portal-lead{color:var(--c-ink-dim);line-height:1.95;font-size:1.02rem;max-width:40em;margin:0;text-wrap:pretty}
/* 几个分句的导语：只在标点、空格处换行，不让最后两三个字单独掉到下一行；一个分句比一行还长时才在中间断 */
.portal-lead--clauses{word-break:keep-all;overflow-wrap:anywhere}
.portal-actions{display:flex;flex-wrap:wrap;gap:22px;align-items:center;margin-top:30px}.portal-actions .btn,.portal-membership .btn,.knowledge-series .btn{gap:14px}
.portal-signature{margin:28px 0 0;font-size:.75rem;letter-spacing:.05em;color:var(--c-ink-dim)}.portal-hero__art{position:relative;min-width:0}
.portal-art-caption{display:block;text-align:left;letter-spacing:.16em;font-size:.72rem;color:var(--c-ink-dim);margin-top:14px}
.product-art{width:100%;min-width:0;aspect-ratio:600 / 380}.product-art svg{height:100%}
.portal-section-heading{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin:0 0 24px}.portal-section-heading h2{font-size:1.35rem;margin:0}.portal-section-heading p{color:var(--c-ink-dim);font-size:.83rem;margin:0}
.portal-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:22px}
.offering-card{display:flex;flex-direction:column;color:var(--c-ink);text-decoration:none;background:var(--c-bg-raise);border:1px solid var(--c-line);border-radius:22px;overflow:hidden;min-width:0;transition:border-color .2s,background .2s}
.offering-card:hover,.knowledge-series:hover{border-color:var(--c-gold)}
.offering-card__label{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:10px;padding:22px 24px 0;font-size:.73rem;color:var(--c-ink-dim)}.offering-card__label>span:first-child:not(.portal-badge){font-variant-numeric:tabular-nums;letter-spacing:.08em;color:var(--c-gold)}
.offering-card .product-art{margin:10px 0 0}.offering-card__body{padding:6px 26px 26px;display:flex;flex-direction:column;flex:1}.offering-card h2,.offering-card h3{font-size:1.35rem;line-height:1.5;margin:0 0 12px}.offering-card p{color:var(--c-ink-dim);font-size:.88rem;line-height:1.85;margin:0 0 26px}
.offering-card__foot{display:flex;justify-content:space-between;gap:12px;align-items:center;padding-top:19px;border-top:1px solid var(--c-line);margin-top:auto;color:var(--c-gold);font-size:.84rem}
.portal-membership{display:flex;justify-content:space-between;align-items:center;gap:28px;margin:54px 0 35px;padding:32px 0;border-top:1px solid var(--c-line)}.portal-membership .portal-eyebrow{margin-bottom:10px}.portal-membership h2{font-size:1.23rem;margin:0 0 10px}.portal-membership p:last-child{font-size:.85rem;color:var(--c-ink-dim);line-height:1.85;margin:0}.portal-membership .btn{flex-shrink:0}
.portal-list-head{display:flex;justify-content:space-between;gap:24px;align-items:end;padding:50px 0 36px}.portal-list-head h1{font-size:2.65rem;margin-bottom:14px}.portal-list-head .portal-eyebrow{margin-bottom:13px}.portal-list-count{flex-shrink:0;font-size:.78rem;color:var(--c-ink-dim);padding-bottom:6px}
.knowledge-series{display:grid;grid-template-columns:1fr 1.2fr;align-items:center;gap:32px;text-decoration:none;color:var(--c-ink);background:var(--c-bg-raise);border:1px solid var(--c-line);border-radius:24px;padding:30px}.knowledge-series__body{padding:20px 20px 20px 0}.knowledge-series h2{font-size:clamp(1.55rem,2.5vw,2.4rem);line-height:1.5;margin:17px 0}.knowledge-series p{color:var(--c-ink-dim);line-height:1.85;margin:0}
.portal-badge{display:inline-flex;width:fit-content;font-size:.73rem;border:1px solid var(--c-line);border-radius:6px;padding:5px 10px;color:var(--c-gold);background:var(--c-bg)}.portal-badge[data-free="true"]{color:var(--c-free)}
.portal-topics{display:flex;flex-wrap:wrap;list-style:none;padding:0;margin:22px 0 28px;gap:12px;color:var(--c-ink-dim);font-size:.8rem}.portal-topics li+li::before{content:'·';margin-right:12px}
.portal-grid--courses .offering-card .product-art{max-height:290px}
.offering-detail{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:center;gap:55px;padding:50px 0 35px}.offering-detail h1{font-size:clamp(1.8rem,2.8vw,3rem);margin:20px 0;text-wrap:balance;overflow-wrap:anywhere}.offering-detail__body{min-width:0}.offering-detail__art{background:var(--c-bg-raise);border-radius:26px;padding:40px 0}
.coming-soon{border-top:1px solid var(--c-line);border-bottom:1px solid var(--c-line);padding:22px 0;margin-top:30px}.coming-soon .portal-eyebrow{margin:0 0 10px}.coming-soon h2{font-size:1.3rem;margin:0 0 10px}.coming-soon>p:last-child{color:var(--c-ink-dim);line-height:1.85;font-size:.85rem;margin:0}.portal-contact{margin-top:28px}
:root[data-style="crayon-book"] .offering-card{border-radius:24px 17px 28px 19px / 18px 26px 21px 25px}
:root[data-style="watercolor"] .offering-card{background:linear-gradient(148deg,color-mix(in srgb,var(--c-gold) 5%,var(--c-bg-raise)),var(--c-bg-raise) 70%);border-radius:28px 40px 26px 34px}
:root[data-style="studio"] :is(.offering-card,.knowledge-series,.offering-detail__art){border-radius:3px}:root[data-style="studio"] .offering-card__label{border-top:3px solid var(--c-gold);padding-top:20px}
:root[data-style="orbit"] .offering-card{border-radius:18px;background:radial-gradient(ellipse at 50% 30%,color-mix(in srgb,var(--c-gold) 6%,var(--c-bg-raise)),var(--c-bg-raise) 70%)}
:root[data-style="orbit"] .portal-hero__art{background:radial-gradient(ellipse at center,color-mix(in srgb,var(--c-gold) 7%,transparent),transparent 68%)}
@media (max-width:1023px){.portal-hero{padding:44px 0;gap:8px}.portal h1{font-size:2.7rem}.portal-grid{gap:14px}.offering-card__body{padding:4px 19px 22px}.offering-card__label{padding:20px 18px 0}.offering-detail{gap:28px}}
@media (max-width:743px){.section-nav{gap:3px;padding:14px 0}.section-nav a{flex:1;text-align:center;white-space:nowrap;padding:8px 6px;font-size:15px}.portal-hero{grid-template-columns:1fr;padding:32px 0}.portal h1{font-size:clamp(2rem,7.8vw,3rem)}.portal-hero__art{max-width:460px;width:100%;margin:12px auto 0}.portal-art-caption{margin-top:0}.portal-actions{gap:20px}.portal-signature{margin-top:22px}.portal-section-heading{display:block}.portal-section-heading p{margin-top:10px;line-height:1.7}.portal-grid,.portal-grid--courses{grid-template-columns:1fr;gap:22px}.offering-card .product-art{max-height:245px}.offering-card__body{padding:6px 24px 24px}.offering-card__label{padding:22px 24px 0}.portal-membership{align-items:start;flex-direction:column;gap:22px;margin-top:38px}.portal-list-head{padding:34px 0 28px;align-items:start}.portal-list-head h1{font-size:2.2rem}.portal-list-count{padding-top:5px}.knowledge-series{grid-template-columns:1fr;gap:0;padding:12px 22px 28px}.knowledge-series__art{max-width:390px;width:100%;margin:auto}.knowledge-series__body{padding:0}.offering-detail{grid-template-columns:1fr;padding:24px 0;gap:30px}.offering-detail__art{padding:0;max-width:480px;width:100%;margin:auto}.portal-breadcrumbs{font-size:.75rem}}
.learning-page { padding-bottom:40px; }
.learning-series { display:grid; gap:24px; }
.learning-series-card { display:grid; grid-template-columns:220px 1fr; gap:24px; align-items:center; padding:24px; background:var(--c-bg-raise); color:var(--c-ink); border:1px solid var(--c-line); border-radius:20px; text-decoration:none; }
.learning-series-card h2 { margin:0 0 24px; font-size:1.4rem; }.learning-series-card .portal-eyebrow { margin-bottom:10px; }
.learning-series-card__body>p { font-size:.8rem; color:var(--c-ink-dim); }
.learning-stats { display:grid; grid-template-columns:repeat(6,minmax(0,1fr)); gap:18px; margin:0 0 22px; }
.learning-stats dt { color:var(--c-ink-dim); font-size:.75rem; margin-bottom:7px; }.learning-stats dd { margin:0; font-size:1.45rem; font-variant-numeric:tabular-nums; }
.learning-series progress { width:100%; height:6px; accent-color:var(--c-gold); }
.learning-tools { display:flex; flex-wrap:wrap; align-items:center; gap:20px; margin:30px 0 18px; }.learning-search { flex:1; min-width:200px; }.learning-search input { width:100%; }
.learning-filters { display:flex; flex-wrap:wrap; gap:8px; }.learning-filters button[aria-pressed="true"] { color:var(--c-gold); background:color-mix(in srgb,var(--c-gold) 10%,var(--c-bg)); }
.learning-progress-note,.learning-results { color:var(--c-ink-dim); font-size:.83rem; }
.learning-items { list-style:none; padding:0; margin:0; }.learning-items li { display:flex; justify-content:space-between; align-items:center; gap:24px; padding:20px 0; border-bottom:1px solid var(--c-line); }.learning-items li>div { min-width:0; }.learning-items p { margin:0 0 8px; font-size:.73rem; color:var(--c-ink-dim); }.learning-items a { display:inline-flex; align-items:center; gap:12px; color:var(--c-ink); text-decoration:none; }.learning-items a:hover { color:var(--c-gold); }.learning-items .portal-badge { flex-shrink:0; }.learning-items a svg { flex-shrink:0; }
.learning-empty { padding:28px 0; color:var(--c-ink-dim); }.learning-empty .product-art { max-width:350px; }.learning-empty h2 { color:var(--c-ink); }
@media (max-width:743px) { .learning-series-card { grid-template-columns:1fr; padding:22px; gap:12px; }.learning-series-card>.product-art { max-width:270px; margin:auto; }.learning-stats { grid-template-columns:repeat(3,minmax(0,1fr)); gap:18px 12px; }.learning-items li { gap:12px; }.learning-items a { font-size:.9rem; } }

/* ── 知识系列列表、产品卡片的价格 ── */
.knowledge-list{display:grid;gap:24px}
.offering-card__foot{flex-wrap:wrap}.offering-card__price{color:var(--c-ink);font-weight:700;font-variant-numeric:tabular-nums}.offering-card__go{display:inline-flex;align-items:center;gap:10px}
.portal-loading,.portal-note{color:var(--c-ink-dim);font-size:.9rem;line-height:1.85;margin:0}
.portal-owned{color:var(--c-ink-dim);font-size:.85rem}

/* ── 产品详情：价格、介绍、企业微信、按小时预约 ── */
.price-tag{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 16px;margin-top:26px;padding:16px 0;border-top:1px solid var(--c-line);border-bottom:1px solid var(--c-line)}
.price-tag strong{font:750 clamp(1.6rem,2.6vw,2.2rem)/1.2 var(--font-display);color:var(--c-ink);font-variant-numeric:tabular-nums}
.price-tag span{color:var(--c-ink-dim);font-size:.86rem;line-height:1.7}
.hours-picker{display:flex;flex-wrap:wrap;align-items:center;gap:12px}
.hours-picker__label{color:var(--c-ink-dim);font-size:.85rem}
.hours-picker__select{width:9rem}
.offering-section{padding:36px 0 8px;border-top:1px solid var(--c-line);margin-top:24px}
#lessons,#contact{scroll-margin-top:calc(var(--topbar-h) + 24px)}
.offering-section h2{display:flex;align-items:baseline;flex-wrap:wrap;gap:12px;font-size:1.35rem;margin:0 0 22px}
.product-intro{max-width:44em;color:var(--c-ink);line-height:1.95;font-size:1rem}
.product-intro p{margin:0 0 16px;white-space:pre-line}.product-intro ul{margin:0 0 16px;padding-left:1.2em;color:var(--c-ink-dim)}.product-intro li{margin:6px 0}
.wecom-card{display:flex;align-items:center;gap:20px;width:fit-content;max-width:100%;margin:28px 0 0;padding:16px 22px 16px 16px;border:1px solid var(--c-line);border-radius:var(--r-lg);background:var(--c-bg-raise)}
.wecom-card>img{flex:none;width:148px;height:148px;padding:8px;border-radius:var(--r-md);background:#fff}
.wecom-card figcaption{display:flex;flex-direction:column;gap:8px;min-width:0}
.wecom-card strong{display:flex;align-items:center;gap:8px;font-size:1rem;color:var(--c-ink)}
.wecom-card span{color:var(--c-ink-dim);font-size:.86rem;line-height:1.75;max-width:22em}


/* 竖的视频：按高度立起来，不撑满宽度 */


/* ── 课时文档页（任务卡片、复盘笔记）：版面和文章页同一套（.kp），标题上面一行写这是哪一种 ── */
.lesson-doc__kind{margin:0 0 6px;color:var(--c-gold);font-size:.82rem;letter-spacing:.12em}
.lesson-doc__fallback{margin:0 0 24px;padding:10px 14px;border-radius:var(--r-md);background:var(--c-bg-raise);color:var(--c-ink-dim);font-size:.88rem}


/* ── 结算页 ── */
.checkout__lines{margin:18px 0;display:grid;gap:12px}
.checkout__lines>div{display:flex;justify-content:space-between;align-items:center;gap:16px}
.checkout__lines dt{color:var(--c-ink-dim);font-size:.88rem}.checkout__lines dd{margin:0;color:var(--c-ink);font-variant-numeric:tabular-nums}
.checkout__total{padding-top:12px;border-top:1px solid var(--c-line)}.checkout__total dd{font-size:1.4rem;font-weight:750}
.checkout .wecom-card{margin:6px 0 22px}

@media (max-width:1023px){
  /* 竖屏视频高度最多约四分之三屏，宽度按宽高比算，一屏看全；横屏铺满宽度 */
}
@media (max-width:743px){
  .link-lessons li{grid-template-columns:minmax(0,1fr);gap:8px}
  .link-lessons__go{justify-self:start}.link-lessons__acts{justify-content:flex-start}
  .wecom-card{flex-direction:column;align-items:flex-start;width:100%}
  .hours-picker{width:100%}.hours-picker .btn{width:100%}
}
/* 外壳上的粗体不是正文重点词：不要荧光笔底纹（base.css 的 strong） */
.price-tag strong,.wecom-card strong{background:none;animation:none;padding-inline:0}
#contact{scroll-margin-top:calc(var(--topbar-h, 64px) + 24px)}

/* ── 文章结尾：对应的课程那一节（components/KpCourses.tsx） ── */
.kp-courses{display:grid;gap:12px;margin:40px 0 0}
.kp-courses__card{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"eyebrow go" "name go" "lesson go";align-items:center;gap:2px 20px;padding:18px 22px;color:var(--c-ink);text-decoration:none;border-radius:var(--r-lg);background:var(--c-bg-raise)}
.kp-courses__card:hover .kp-courses__go{color:var(--c-gold)}
.kp-courses__eyebrow{grid-area:eyebrow;color:var(--c-gold);font-size:.75rem;letter-spacing:.08em}
.kp-courses__name{grid-area:name;font-weight:700;font-size:1rem}
.kp-courses__lesson{grid-area:lesson;color:var(--c-ink-dim);font-size:.88rem;line-height:1.7}
.kp-courses__go{grid-area:go;display:inline-flex;align-items:center;gap:8px;color:var(--c-ink-dim);font-size:.88rem;white-space:nowrap}
@media (max-width:743px){.kp-courses__card{grid-template-columns:minmax(0,1fr);grid-template-areas:"eyebrow" "name" "lesson" "go";gap:4px}.kp-courses__go{margin-top:8px}}

/* 系列卡片、系列页顶上：收费方式角标 + 更新节奏 */
.series-access{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:0;font-size:.73rem;color:var(--c-ink-dim)}

/* ── 课程目录：和知识目录同一套带子（.band / .topic / .kplink，四种画风跟着走），这里只补课程自己的几处 ── */
.course-catalog{display:grid;grid-template-columns:minmax(0,1fr);gap:24px}
.course-catalog__loose{list-style:none;margin:0;padding:0}
.course-lesson__doc{color:var(--c-gold);background:color-mix(in srgb,var(--c-gold) 10%,transparent)}

/* ── 课程里一节的页面：标题、看视频（本站播放器或各平台卡片）、这一节的资料、上一节下一节 ── */
.lesson-head{padding:26px 0 6px;max-width:48rem}
.lesson-head__no{margin:0 0 10px;color:var(--c-gold);font-size:.8rem;letter-spacing:.08em}
.lesson-head h1{margin:0 0 12px;text-wrap:balance;overflow-wrap:anywhere}
.lesson-head__meta{display:flex;flex-wrap:wrap;align-items:center;gap:14px;margin:16px 0 0;color:var(--c-ink-dim);font-size:.85rem}
.lesson-view{display:grid;gap:36px;padding:22px 0 44px}
.lesson-stage{position:relative;width:100%;max-height:calc(100dvh - var(--topbar-h, 64px) - 48px);border-radius:var(--r-lg);overflow:hidden;background:#000}
.lesson-stage[data-portrait="true"]{width:auto;height:min(calc(100dvh - var(--topbar-h, 64px) - 72px),820px);justify-self:start}
.lesson-stage video{display:block;width:100%;height:100%;object-fit:contain;background:#000}
.lesson-stage--locked,.lesson-stage--empty{aspect-ratio:16/9;max-height:420px;display:grid;place-items:center;padding:24px;background:color-mix(in srgb,var(--c-gold) 7%,var(--c-bg-raise))}
.lesson-stage--empty p{margin:0;color:var(--c-ink);font-size:.98rem;max-width:26em;text-wrap:balance}
.lesson-locked{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;color:var(--c-ink-dim)}
.lesson-stage:not(.lesson-stage--locked) .lesson-locked{position:absolute;inset:0;padding:24px;background:color-mix(in srgb,var(--c-gold) 7%,var(--c-bg-raise))}
.lesson-locked p{margin:0;color:var(--c-ink);font-size:.95rem;text-wrap:balance}
.lesson-block__title{margin:0 0 16px;font-size:1.15rem}
.watch-links{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(250px,100%),1fr));gap:12px}
.watch-link{display:flex;align-items:center;gap:14px;min-height:76px;padding:14px 18px;color:var(--c-ink);text-decoration:none;background:var(--c-bg-raise)}
.watch-link:hover{color:var(--c-gold)}
.watch-link:focus-visible{outline:2px solid var(--c-gold);outline-offset:2px}
.watch-link__badge{flex:none;display:grid;place-items:center;width:42px;height:42px;border-radius:var(--r-md);background:color-mix(in srgb,var(--c-gold) 14%,transparent);color:var(--c-gold);font-weight:700;font-size:1rem}
.watch-link__text{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}
.watch-link__name{font-size:1rem;font-weight:650;overflow-wrap:anywhere}
.watch-link__go{flex:none;display:inline-flex;align-items:center;gap:4px;color:var(--c-gold);font-size:.85rem}
.watch-link__text small{color:var(--c-ink-dim);font-size:.78rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.watch-link[data-locked]{color:var(--c-ink-dim)}
.lesson-docs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
.doc-card{display:flex;flex-direction:column;gap:10px;min-height:156px;padding:22px 24px;color:var(--c-ink);text-decoration:none;background:var(--c-bg-raise)}
.doc-card:hover .doc-card__kind{color:var(--c-gold)}
.doc-card:focus-visible{outline:2px solid var(--c-gold);outline-offset:2px}
.doc-card__kind{font-size:1.15rem;font-weight:700}
.doc-card__desc{flex:1;color:var(--c-ink-dim);font-size:.9rem;line-height:1.75}
.doc-card__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;color:var(--c-gold);font-size:.86rem}
.doc-card[data-ready="false"] .doc-card__foot{color:var(--c-ink-dim)}
.lesson-nav{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);align-items:center;gap:16px;padding-top:22px;border-top:1px solid var(--c-line)}
.lesson-nav__step{display:flex;flex-direction:column;gap:4px;min-width:0;padding:12px 14px;border-radius:var(--r-md);color:var(--c-ink);text-decoration:none}
.lesson-nav__step:hover{background:color-mix(in srgb,var(--c-gold) 8%,transparent)}
.lesson-nav__step>span:first-child{color:var(--c-ink-dim);font-size:.78rem}
.lesson-nav__title{max-width:100%;font-size:.93rem;font-weight:600;overflow-wrap:anywhere;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.lesson-nav__step--next{align-items:flex-end;text-align:right}
.lesson-nav__center{display:flex;flex-direction:column;align-items:center;gap:8px}
.lesson-nav__center>.quiet-link{min-height:44px;display:inline-flex;align-items:center}
.lesson-doc__next{display:flex;flex-wrap:wrap;gap:12px;margin-top:40px}
.wall .lesson-doc__next{justify-content:center;margin-top:20px}
@media (max-width:1023px){.lesson-stage[data-portrait="true"]{height:min(76svh,820px);justify-self:center}}
@media (max-width:743px){
  .lesson-docs{grid-template-columns:minmax(0,1fr)}
  .lesson-nav{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .lesson-nav__center{grid-column:1/-1;grid-row:2;padding-top:12px;border-top:1px solid var(--c-line)}
}

/* 手机详情页先交代是什么、价格和入口，插画作为下方的补充。 */
@media (max-width:743px){
  .offering-detail__body{grid-row:1}
  .offering-detail__art{max-width:320px}
  .offering-detail__art .product-art{max-height:170px}
  .offering-detail .portal-actions{gap:12px}
  .offering-detail .portal-actions>.btn{min-height:46px}
  .offering-detail .hours-picker{width:100%}
  .offering-detail .hours-picker>.btn{flex:1;min-height:46px}
}

/* ── 服务条款、隐私政策、退款政策（pages/Legal.tsx）：纯文字页，正文栏宽、左对齐 ── */
.legal { max-width: calc(var(--measure) + 64px); padding-block: 40px 24px; }
.legal__head h1 { margin: 10px 0 8px; font-size: clamp(28px, 4vw, 40px); letter-spacing: -.02em; }
.legal__updated { margin: 0; font-size: 13px; color: var(--c-ink-dim); }
.legal__lead { margin: 18px 0 0; font-size: 16px; line-height: 1.85; color: var(--c-ink); }
.legal__docs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }
.legal__docs a { min-height: 36px; display: inline-flex; align-items: center; padding-inline: 14px; border: 1px solid var(--c-line); border-radius: var(--r-md); color: var(--c-ink-dim); text-decoration: none; font-size: 13px; }
.legal__docs a:hover { color: var(--c-ink); background: var(--c-glass-hover); }
.legal__docs a[aria-current='page'] { color: var(--c-gold); border-color: var(--c-gold); background: color-mix(in srgb, var(--c-accent-bg) 8%, var(--c-bg)); }
.legal__toc { margin: 32px 0 8px; padding: 18px 20px; border: 1px solid var(--c-line); border-radius: var(--r-md); background: var(--c-bg-raise); }
.legal__toc p { margin: 0 0 8px; font-size: 12px; color: var(--c-ink-dim); }
.legal__toc ol { margin: 0; padding-left: 1.4em; display: grid; gap: 4px; font-size: 14px; }
.legal__toc a { color: var(--c-ink); text-decoration: none; }
.legal__toc a:hover { color: var(--c-gold); }
.legal__body section { padding-top: 28px; scroll-margin-top: 88px; }
.legal__body h2 { margin: 0 0 12px; font-size: 20px; }
.legal__body p, .legal__body li { font-size: 15px; line-height: 1.9; color: var(--c-ink); }
.legal__body p { margin: 0 0 12px; white-space: pre-line; overflow-wrap: anywhere; }
.legal__body ul { margin: 0 0 12px; padding-left: 1.3em; display: grid; gap: 6px; }
/* 页脚左侧一行：站名 | 一句话 | 服务条款 隐私政策 退款政策；放不下才折行。
   每组前面都有一道 1px 竖线 + 12px 空；整组往左挪 13px 再把最左边 6px 裁掉——
   排在行首的那道竖线落在被裁的地方，不管在哪个宽度折行，行首都不会多出一道线。 */
.footer__left { display: flex; flex-wrap: wrap; align-items: center; gap: 0 12px; margin-left: -13px; clip-path: inset(-24px -24px -24px 6px); }
.footer__brand::before, .footer__legal::before { content: ''; flex: none; width: 1px; height: 1.2em; background: var(--c-line); }
.footer__legal { display: flex; flex-wrap: wrap; align-items: center; gap: 0 16px; }
.footer__legal::before { margin-right: -4px; }
.footer__legal a { min-height: 32px; display: inline-flex; align-items: center; color: var(--c-ink-dim); text-decoration: none; }
.footer__legal a:hover { color: var(--c-ink); }
@media (max-width: 640px) {
  .legal { padding-block: 24px 16px; }
  .legal__toc { padding: 14px 16px; }
  .legal__body h2 { font-size: 18px; }
}
/* Also inlined into the HTML startup screen, before application CSS arrives. */
.status-artwork { width: 100%; min-width: 0; }
.status-artwork svg { width: 100%; height: auto; display: block; }
.status-artwork__offline, .status-artwork__error { display: none; }
[data-art='offline'] .status-artwork__offline, [data-art='error'] .status-artwork__error { display: inline; }
[data-art='offline'] .status-artwork__loading, [data-art='error'] .status-artwork__loading { display: none; }
[data-art='loading'] .status-artwork__float { animation: state-float 4s ease-in-out infinite; }
[data-art='loading'] .status-artwork__signal { animation: state-signal 2s ease-in-out infinite; }
.page-state { min-height: 65dvh; width: 100%; box-sizing: border-box; display: grid; place-items: center; padding: 48px 24px; }
.page-state__body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; justify-items: center; width: min(100%, 560px); max-width: 560px; text-align: start; padding: 24px; border: 0; background: transparent; box-sizing: border-box; }
.page-state__body > .state-art { grid-row: auto; width: min(100%, 400px); margin: 0 0 12px; }
.page-state__copy { width: 100%; }
.page-state h1, .page-state h2 { font: 600 clamp(23px, 3vw, 30px)/1.45 var(--font-display); color: var(--c-ink); margin: 0; text-wrap: balance; }
.page-state p { max-width: 36em; margin: 12px auto 24px; font: 14px/1.85 var(--font-body); color: var(--c-ink-dim); overflow-wrap: anywhere; }
.page-state__actions { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 12px; margin-top: 12px; }
.page-state--fullscreen { min-height: 100dvh; background: var(--c-bg); }
.state-progress { width: 112px; height: 3px; border-radius: 3px; background: var(--c-line-soft); overflow: hidden; }
.state-progress > span { display: block; width: 42%; height: 100%; background: var(--c-gold); border-radius: inherit; animation: state-progress 1.8s ease-in-out infinite alternate; }
.page-state--compact { min-height: 0; padding: 16px 8px; }
.page-state--compact .page-state__body { padding: 0; }
.page-state--compact .state-art { width: 180px; margin: 0; }
.page-state--compact h2 { font-size: 17px; }
.page-state--compact p { font-size: 13px; margin-block: 8px 12px; }
.page-state--compact .page-state__actions { margin-top: 8px; }
.admin__state > .state-art { width: 160px; margin: auto; }
.admin__notice > .state-art { width: 72px; flex: 0 0 72px; }
.login__banned > .state-art { width: 140px; margin-inline: auto; }
.quick-search__empty > .state-art { width: 160px; margin: auto; }
.payment-error { display: flex; align-items: center; gap: 12px; }
.payment-error .state-art { flex: 0 0 92px; }
.state-notice { display: flex; align-items: center; gap: 12px; width: 100%; min-width: 0; }
.state-notice > .state-art { flex: 0 0 72px; width: 72px; }
.state-notice > div:last-child { min-width: 0; overflow-wrap: anywhere; }
.status-image { max-width: 100%; }
.status-image .page-state { padding: 8px; }
.status-image .page-state h2 { font-size: 13px; }
.status-image .page-state p { font-size: 11px; margin-block: 4px; }
.status-image .state-art { width: 100px; }
.status-image .page-state .btn { min-height: 32px; padding: 4px 12px; font-size: 12px; }
.course-player { position: relative; }
.player-buffering { position: absolute; top: 12px; left: 12px; right: 12px; display: flex; align-items: center; gap: 12px; padding: 8px 16px; border-radius: var(--r-md); background: var(--c-bg-raise); color: var(--c-ink); font: 13px/1.5 var(--font-body); pointer-events: none; }
.player-buffering .state-art { width: 80px; flex-shrink: 0; }
.network-notice { display: flex; align-items: center; gap: 12px; padding: 8px 20px; background: var(--c-bg-raise); border-bottom: 1px solid var(--c-line); color: var(--c-ink); font: 13px/1.6 var(--font-body); }
.network-notice .state-art { flex: 0 0 72px; width: 72px; }
.network-notice p { margin: 0; }
.network-notice small { display: block; color: var(--c-ink-dim); }
@keyframes state-float { 50% { translate: 0 -6px; } }
@keyframes state-signal { 50% { opacity: .45; } }
@keyframes state-progress { to { transform: translateX(138%); } }
@media (max-width: 600px) {
  .page-state { padding: 32px 20px; }
  .page-state__body { padding: 12px 0; }
  .page-state__body > .state-art { width: min(100%, 320px); margin: 0 0 12px; }
  .page-state--compact { padding: 12px 4px; }
  .page-state--compact .state-art { width: 148px; }
  .network-notice { padding-inline: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .status-artwork *, .state-progress > span { animation: none !important; }
}
