/* @pages-only:start
 *
 * 这一段到 @pages-only:end 之间，只有品牌站自己的页面用得上（首页各节、排盘工具介绍页）。
 * 内容层那四千多页（古籍 / 词条 / 工具落地页）一条都不需要，所以构建时把它切成单独一个
 * 文件，只让品牌页去链——见 build-legal-static.mjs 的 writeCss。
 *
 * 分开的理由不是省那几十 KB 的磁盘，而是：搜索来的访客几乎每次都是第一次访问，
 * 缓存永远轮不到发挥，渲染阻塞的字节是每一次访问都要付的。
 *
 * 加新的首页板块请写在这两个标记之间；写在外面会让四千多页跟着变重。
 */

/* ── Hero ─────────────────────────────────────────────── */

/*
 * Hero 刻意压扁：openai.com 的首屏在标题 + 输入框 + 气泡之后就直接露出下一屏内容，
 * 让人一眼知道页面还有东西。留白给多了会把板块整个推到折叠线以下。
 */
.hero {
  padding: 40px 0 32px;
  text-align: center;
}

@media (min-width: 768px) {
  .hero {
    padding: 64px 0 40px;
  }
}

/*
 * 中间那一档用 vw 而不是固定值：桌面上 3.2vw 早就顶到 2.5rem 的上限，可到了手机
 * 3.2vw 只有 12px，会一路掉到 1.6rem 的下限，一句大标题缩成正文大小。
 * 改成 8vw 后，390 宽的手机上约 33px，正好占满一行，桌面仍旧封顶在 2.5rem。
 */
.hero h1 {
  margin: 0 auto 1.5rem;
  max-width: 20em;
  font-size: clamp(1.6rem, 8vw, 2.5rem);
  line-height: 1.25;
  /* 居中多行标题最忌末行只剩一两个字；balance 让各行长度均匀。不支持的浏览器按普通换行。 */
  text-wrap: balance;
}

/*
 * 首页大标题专用字体。拉丁那份排在前面：它没有 CJK 字形，中文会自动落到 Hero CJK，
 * 一条 font-family 同时管住两种语言。只作用于 .display，板块页的 h1 不受影响
 * （那些字不在子集里）。
 */
.hero h1.display {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.01em;
}

/*
 * Great Vibes 是连笔体：字距一放宽字母之间就断开，所以必须贴着排；
 * 又因为它的上下伸展远超字身，窄屏折行时 1.25 的行距会让上一行的下沿撞到下一行的上沿。
 */
html[lang="en"] .hero h1.display {
  letter-spacing: 0;
  line-height: 1.45;
}

/*
 * 逐字模糊渐显，与应用「问 AI」流式回答的 tokenFade 同参数（0.4s ease-out，
 * opacity 0→1 配 blur(1px)→0）。起跑时刻由 JS 写在各 span 的 animation-delay 上。
 */
.hero h1.display .ch {
  opacity: 0;
  animation: tokenFade 0.4s ease-out forwards;
}

@keyframes tokenFade {
  from {
    opacity: 0;
    filter: blur(1px);
  }

  to {
    opacity: 1;
    filter: blur(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero h1.display .ch {
    opacity: 1;
    animation: none;
  }
}

.hero .lede {
  margin: 0 auto 2.25rem;
  max-width: 40rem;
  color: var(--muted);
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  text-wrap: balance;
}

/* 对话框：整体一个圆角面板。openai.com 实测是 700px，这里放宽到 820px。 */
.composer {
  max-width: 820px;
  margin: 0 auto;
  text-align: left;
}

/*
 * 发送键绝对定位在右下角，不单独占一行——占一行会平白把面板拉高一截。
 * 文字不会压到按钮上：textarea 自己留了 padding-bottom，正文永远排在按钮所在的那条带之上。
 */
.composer form {
  position: relative;
  padding: 0.9rem 1rem;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  box-shadow: 0 6px 24px rgba(31, 27, 22, 0.06);
}

/*
 * 输入框聚焦不做任何描边或高亮：页面一进来就自动聚焦，任何焦点样式都会一直亮着，
 * 看上去像是报错或选中态。文本框本身有闪烁的光标，那已经是它的焦点指示；
 * 发送键仍保留全局的 :focus-visible 轮廓，键盘导航不会失去落点。
 */

/*
 * 轮换占位的容器。
 *
 * 高度锁一行、overflow:hidden，文字才能「从下方推上来」而不是在框外露头。
 * 只覆盖第一行：输入超过一行时 ghost 已经被 JS 隐藏，不会挡住内容。
 */
.composer .field {
  position: relative;
}

.composer .ghost {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1.6em;
  overflow: hidden;
  pointer-events: none;
  color: #a99374;
  font-size: 1rem;
  line-height: 1.6;
  text-align: left;
}

.composer .ghost .t {
  display: block;
  white-space: nowrap;
}

.composer .ghost .t.in {
  animation: ghostIn 0.34s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.composer .ghost .t.out {
  animation: ghostOut 0.24s ease-in both;
}

/* 进出方向一致（都朝上走），读起来才像一条向上滚动的列表，而不是原地闪烁。 */
@keyframes ghostIn {
  from {
    opacity: 0;
    transform: translateY(100%);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes ghostOut {
  from {
    opacity: 1;
    transform: translateY(0);
  }

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

.composer textarea {
  display: block;
  width: 100%;
  /* 两行正文 + 一条留给发送键的底带。 */
  height: 5.4em;
  max-height: 12rem;
  padding: 0 0 2.2em;
  border: 0;
  outline: none;
  resize: none;
  overflow-y: auto;
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  font-size: 1rem;
  line-height: 1.6;
}

.composer textarea::placeholder {
  color: #a99374;
}

.composer .send {
  position: absolute;
  right: 0.85rem;
  bottom: 0.85rem;
  width: 2.2rem;
  height: 2.2rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

.composer .send:hover {
  background: var(--accent-ink);
}

.composer .hint {
  margin: 0.75rem 0 0;
  color: var(--muted);
  font-size: 0.85rem;
  text-align: center;
}

/* 示例问题：点一下填进输入框 */
.suggests {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
}

.suggests a {
  display: inline-block;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  font-size: 0.88rem;
}

.suggests a:hover {
  background: var(--tint);
  border-color: var(--accent);
  text-decoration: none;
}

/* @pages-only:end */
/* @pages-only:start */

/* ── 中道 ─────────────────────────────────────────────── */

/*
 * 首页第二屏，也是首页唯一一屏内容。
 *
 * 整块是一条墨色通栏，与上方米色的 Hero 硬接——这一刀本身就是分界，不再加分隔线。
 * 中心压一层极淡的暖光，像纸被灯照着；四周沉下去，字浮上来。
 *
 * 配色不进 :root：这套墨底金字只服务这一节，放进全局令牌会诱使别处误用。
 */
/*
 * 首屏：Hero 撑到「一屏 − 入口引导 − 顶栏」，于是折叠线正好落在中道那一节的上沿——
 * 首屏因此是完整的一片米白，墨色一点都不露。
 *
 * 顶栏要减掉：它虽然是 sticky，停在页顶时仍然实打实占着文档流的那一格，
 * 并没有浮在 Hero 上面。
 */
.hero:has(+ .tao-enter) {
  display: grid;
  align-content: center;
  min-height: calc(100svh - var(--enter-h) - var(--header-h));
  padding-top: 0;
  padding-bottom: 0;
}

/*
 * 首屏底部的入口：箭头 + 一句引导语，点它进中道。
 *
 * 这块不带底色。此前试过在这里探出一道墨色（先是四级阶梯，后来是一条横带），
 * 两版都不成立：首屏是米白的场，底下压一条黑就把整屏割成两截，
 * 而那条黑既不承载信息也不属于 Hero。现在留白到底，邀请全交给箭头和文字，
 * 墨色一直等到折叠线以下才出现。
 */
.tao-enter {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  height: var(--enter-h);
  text-decoration: none;
}

.tao-enter:hover {
  text-decoration: none;
}

/* 引导语：与箭头同为邀请的一部分，字距放开，像页脚上题的一行小字。 */
.tao-enter-label {
  color: var(--muted);
  font-family: var(--font-serif);
  font-size: 0.95rem;
  letter-spacing: 0.42em;
  /* 字距是加在每个字右侧的，末字之后那一份会让整行看起来偏左，补回去。 */
  text-indent: 0.42em;
  transition: color 0.25s ease;
}

.tao-enter:hover .tao-enter-label,
.tao-enter:focus-visible .tao-enter-label {
  color: var(--accent-ink);
}

/* 箭头落在引导语上方。 */
.tao-enter-arrow {
  display: block;
  width: 26px;
  color: var(--line-strong);
  transition:
    color 0.25s ease,
    transform 0.25s ease;
}

.tao-enter-arrow svg {
  display: block;
  width: 100%;
  height: auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tao-enter:hover .tao-enter-arrow,
.tao-enter:focus-visible .tao-enter-arrow {
  color: var(--accent-ink);
  transform: translateY(3px);
}

/* 一下一下地点，像在招手。指到它上面就停——已经不需要再提示了。 */
@media (prefers-reduced-motion: no-preference) {
  .tao-enter-arrow {
    animation: enterBeckon 2.4s ease-in-out infinite;
  }

  .tao-enter:hover .tao-enter-arrow {
    animation: none;
  }
}

@keyframes enterBeckon {
  0%,
  62%,
  100% {
    transform: translateY(0);
  }

  28% {
    transform: translateY(5px);
  }
}

.tao {
  position: relative;
  background:
    radial-gradient(115% 62% at 50% 34%, rgba(200, 165, 106, 0.11), transparent 62%),
    var(--ink-bg);
  color: var(--ink-fg);
  /*
   * 必须是 clip 不能是 hidden：hidden 会让这一节变成滚动容器，里面 sticky 的舞台
   * 就改为相对它定位，钉屏直接失效。clip 同样挡住横向溢出（起手时放大的圆相），
   * 但不创建滚动容器。
   */
  overflow-x: clip;

  /* 编排进度，由脚本按滚动位置逐帧改写；没有脚本时就是收势那一帧。 */
  --enso: 1;
  --reveal: 1;
  --tail: 1;
  --n: 9999;
}

.tao.anim {
  --enso: 0;
  --reveal: 0;
  --tail: 0;
  --n: 0;
}

.tao-stage {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: clamp(1.5rem, 4vh, 2.4rem);
  width: 100%;
  max-width: calc(72rem + var(--gutter) * 2);
  min-height: 100vh;
  margin: 0 auto;
  /* 顶栏是 sticky 的，永远压在这一节上沿，上边距得把它让出来。 */
  padding: calc(clamp(56px, 9vh, 104px) + var(--header-h)) var(--gutter) clamp(56px, 9vh, 104px);
  text-align: center;
}

.tao-mark {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.tao-crest {
  position: relative;
  display: grid;
  place-items: center;
  /* 题名按圆径取字号，两者的比例才不会随断点走样。 */
  --crest: clamp(180px, 46vw, 244px);
  width: var(--crest);
  aspect-ratio: 1;
}

/* 圆相：从顶端起笔顺时针描一圈，收笔处留一道口子——圆相本就不闭合。 */
.tao-enso {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-96deg);
  overflow: visible;
}

/*
 * r=112 的周长约 703.7（用户单位，与渲染尺寸无关）。dasharray 取整到 704——
 * 实线与间隔等长且都盖满一整圈，所以圆是闭合的，起收笔处不留缺口；
 * 略微超出周长也是有意的，免得收尾差零点几个单位露出一道发丝缝。
 * dashoffset 从 704 收到 0 就是一笔描完，进度由 --enso 给。
 */
.tao-enso circle {
  fill: none;
  stroke: rgba(212, 180, 126, 0.34);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-dasharray: 704;
  stroke-dashoffset: calc(704 * (1 - var(--enso)));
}

.tao-name {
  position: relative;
  margin: 0;
  font-family: "Hero CJK", var(--font-serif);
  font-weight: 400;
  font-size: calc(var(--crest) * 0.3);
  line-height: 1;
  letter-spacing: 0.14em;
  /* 字距会在末字右侧多留一格，缩进同量补回来才是真居中。 */
  text-indent: 0.14em;
  color: #f7f0e3;
  /* 圆相描到一半时题名才浮出来。 */
  opacity: clamp(0, calc(var(--enso) * 2 - 0.55), 1);
}

.tao-latin {
  margin: 1.15rem 0 0;
  color: rgba(212, 180, 126, 0.82);
  font-size: clamp(0.7rem, 1.5vw, 0.82rem);
  font-weight: 500;
  letter-spacing: 0.42em;
  text-indent: 0.42em;
  text-transform: uppercase;
  opacity: var(--reveal);
}

/* 引线：从名号垂下来一道金丝，把视线带到偈子上。 */
.tao-rule {
  width: 1px;
  height: clamp(36px, 6vh, 60px);
  margin: 1.5rem 0 0;
  background: linear-gradient(
    180deg,
    rgba(212, 180, 126, 0),
    rgba(212, 180, 126, 0.55),
    rgba(212, 180, 126, 0)
  );
  transform: scaleY(var(--reveal));
  transform-origin: top;
}

/*
 * 竖排偈子。
 *
 * writing-mode: vertical-rl 之后每个 .line 就是一列，从右往左排——与古籍的读序一致，
 * DOM 里照常按第一句到第三句写即可。此时 line-height 管的是列间距，height 管的是列长，
 * 所以给 max-content 让它按最长那句自己撑开，nowrap 兜住不让某句折成两列。
 */
.tao-verse {
  writing-mode: vertical-rl;
  height: max-content;
  margin: 0;
  /*
   * 竖排下 text-align 管的是列内的纵向对齐，继承来的 center 会让短的那列吊在半空。
   * 各列一律从顶端起写，才是古籍的样子。
   */
  text-align: start;
  font-family: var(--font-serif);
  font-size: clamp(1.1rem, 2.4vw, 1.8rem);
  line-height: 2.9;
  letter-spacing: 0.14em;
  color: #efe4d2;
}

.tao-verse .line {
  display: block;
  white-space: nowrap;
}

/*
 * 中文版把落款竖排收在偈子左侧——竖排卷轴的题款本就写在正文之后，
 * 而 vertical-rl 里「之后」就是更左的那一列。row-reverse 让 DOM 顺序保持
 * 「正文在前、题款在后」（读屏与复制都按这个序），视觉上题款落到左边。
 */
.tao-scroll {
  display: flex;
  flex-direction: row-reverse;
  align-items: flex-start;
  justify-content: center;
  gap: clamp(0.9rem, 2.5vw, 2rem);
}

.tao-source-aside {
  writing-mode: vertical-rl;
  height: max-content;
  /*
   * 与偈子的末字齐脚。题款比正文短得多，齐头的话下面会空出一大截，
   * 整列像是吊在半空；卷轴上的落款本来也是沉在末尾的。
   */
  align-self: flex-end;
  margin: 0;
  font-size: clamp(0.72rem, 1.6vh, 0.92rem);
  letter-spacing: 0.2em;
  white-space: nowrap;
  /* 落款跟着偈子的收尾一起浮出来，不自成一拍。 */
  opacity: var(--tail);
}

/*
 * 逐字渗墨。--n 是「已写到第几个字」，--i 是这个字的序号；两者相减钳到 0..1
 * 就是它该显到几分。除以 3 让每个字的渐显跨三格，笔画像是漫上来的，不是一格一格跳。
 * 全部由 CSS 现算，滚动时脚本只改 --n 一个值，不碰 DOM。
 */
.tao-verse .ch {
  --shown: clamp(0, calc((var(--n) - var(--i)) / 3), 1);
  opacity: var(--shown);
  filter: blur(calc((1 - var(--shown)) * 3px));
}

.tao-colophon {
  opacity: var(--tail);
}

.tao-gloss {
  max-width: 30rem;
  margin: 0 auto;
  color: rgba(240, 230, 214, 0.5);
  font-size: 0.9rem;
  line-height: 1.85;
}

/* 落款 */
.tao-source {
  margin: 1.1rem 0 0;
  color: rgba(212, 180, 126, 0.72);
  font-family: var(--font-serif);
  font-size: 0.9rem;
  letter-spacing: 0.08em;
}

.tao-act {
  margin: 1.8rem 0 0;
}

.tao-cta {
  display: inline-block;
  padding: 0.85rem 2.4rem;
  border: 1px solid rgba(212, 180, 126, 0.42);
  /* 方角比胶囊更像一方牌记，与这一节的气口一致；全站的圆角按钮留在别处。 */
  border-radius: 2px;
  background: transparent;
  color: #e8d6b0;
  font-family: inherit;
  font-size: 0.95rem;
  letter-spacing: 0.24em;
  text-indent: 0.24em;
  text-decoration: none;
  cursor: pointer;
  transition:
    background 0.32s ease,
    border-color 0.32s ease,
    color 0.32s ease;
}

.tao-cta:hover {
  border-color: rgba(212, 180, 126, 0.8);
  background: rgba(212, 180, 126, 0.1);
  color: #f8efdb;
  text-decoration: none;
}

/*
 * 宽屏：题名与落款分列左侧上下，竖排偈子立在右侧，中间大片留白——
 * 这是卷轴的章法，正文在右，题款在后（也就是左）。
 *
 * 徽记的位移由脚本写 transform，所以这里只管收势那一帧的位置；起手的居中大圆
 * 是从这个位置反推出来的，改这里的排布不用回去改脚本。
 */
@media (min-width: 900px) {
  .tao-stage {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
      "mark  verse"
      ".     verse"
      "colo  verse";
    align-content: stretch;
    justify-items: start;
    gap: 0 clamp(2rem, 7vw, 6rem);
    padding-right: clamp(var(--gutter), 9vw, 148px);
    text-align: left;
  }

  .tao-mark {
    grid-area: mark;
    align-items: flex-start;
  }

  .tao-crest {
    --crest: clamp(104px, 11vw, 140px);
  }

  /*
   * 竖排要立得住：列长跟着视口高走（vh 而不是 vw），一屏之内偈子才占得满，
   * 不至于在大片墨色里缩成一小簇。
   */
  /* 竖排那一栏整体占 verse 格：中文版里它装着偈子与题款两列，英文版只有偈子。 */
  .tao-scroll {
    grid-area: verse;
    align-self: center;
  }

  .tao-verse {
    align-self: center;
    font-size: clamp(1.4rem, 5vh, 2.75rem);
    line-height: 2.5;
  }

  .tao-colophon {
    grid-area: colo;
    align-self: end;
    max-width: 26rem;
  }

  .tao-gloss {
    margin: 0;
  }

  /* 左栏那道金丝拉长成一条界行，把题名与落款之间的空档串起来。 */
  .tao-rule {
    height: clamp(64px, 20vh, 200px);
  }
}

/* 脚本已按减动效偏好整段跳过，这里再兜一层，免得将来改脚本时漏掉。 */
@media (prefers-reduced-motion: reduce) {
  .tao,
  .tao.anim {
    --enso: 1;
    --reveal: 1;
    --tail: 1;
    --n: 9999;
  }
}

/* ── 入口两卡（人生解读 / 趋势占测） ───────────────────── */

/*
 * 中道之后回到米白。这一节是全站唯一的产品入口，所以只放两张卡，别的什么都不放。
 */
.entries {
  text-align: center;
}

.entries-head {
  max-width: 40rem;
  margin: 0 auto clamp(1.8rem, 5vh, 3rem);
}

.entries-head h2 {
  margin: 0 0 0.7rem;
  font-size: clamp(1.4rem, 3vw, 2rem);
  line-height: 1.35;
  text-wrap: balance;
}

.entries-head p {
  margin: 0;
  color: var(--muted);
  font-size: clamp(0.95rem, 1.6vw, 1.05rem);
}

/*
 * 两栏摊开，中间一道竖线分界。
 *
 * 竖线用容器的伪元素画在 50% 处，而不是给右栏加 border-left——后者会贴在栏的左沿，
 * 也就是间隙的右边，不在正中。
 */
.entry-cols {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(2rem, 9vw, 8rem);
  /* 比正文栏宽：这一节要摊到接近版心两侧，画才立得住。 */
  max-width: 88rem;
  margin: 0 auto;
  padding: 0;
  list-style: none;
  text-align: left;
}

.entry-cols::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  background: var(--line);
}

.entry-cols li {
  margin: 0;
}

/* 不是卡片：没有底色、没有描边，画与字直接落在纸面上。 */
.entry {
  display: block;
  color: var(--ink);
  text-decoration: none;
}

.entry:hover {
  text-decoration: none;
}

/*
 * 切图自带透明，落在米色上就是纸上的一幅画，不垫底色。
 *
 * 画框与正文同宽同心（都是 26rem 居中），画在里面 cover 填满。两张横图的比例并不一致
 * （1.38 与 1.91），cover 会各裁掉一点：窄的那张削去上下一线，宽的那张削去左右一截。
 * 这样两栏的画与字左右齐平、两张画彼此等高，下面的标题也就齐平。
 * 用 contain 的话宽度会各随各的比例，画比正文宽出一截，看着就散了。
 */
.entry-art {
  display: block;
  width: 100%;
  max-width: 26rem;
  height: clamp(170px, 24vw, 290px);
  margin: 0 auto clamp(1rem, 3vh, 1.8rem);
  object-fit: cover;
  /* 画是插图，别在触屏上被长按当成可保存的图片。 */
  pointer-events: none;
  user-select: none;
}

/* 贴右摆：多出来的宽度从左边裁，把焦点留在框内（见 pages.mjs 的 ENTRY_ART.anchor）。 */
.entry-art-right {
  object-position: right center;
}

/* 图居中、字左齐；文字块限宽后整体居中，两者的重心才对得上。 */
.entry-body {
  display: block;
  max-width: 26rem;
  margin: 0 auto;
}

.entry .t {
  display: block;
  font-family: var(--font-serif);
  font-size: clamp(1.15rem, 2.2vw, 1.45rem);
  font-weight: 700;
}

/* 题前一点朱，是这一节唯一的颜色。 */
.entry .t::before {
  content: "";
  display: inline-block;
  width: 0.4em;
  height: 0.4em;
  margin-right: 0.55em;
  border-radius: 50%;
  background: var(--accent);
  vertical-align: 0.1em;
}

.entry:hover .t {
  color: var(--accent-ink);
}

.entry .d {
  display: block;
  margin-top: 0.4rem;
  color: var(--muted);
  font-size: 1rem;
}

.entry-lines {
  display: block;
  margin-top: 1.1rem;
}

/* 一句一行，句子自己该换行就换行。 */
.entry-lines span {
  display: block;
  margin-top: 0.45rem;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.85;
}

@media (max-width: 767px) {
  /* 竖排下中缝改成横线：两栏高度不一，伪元素定位不准，交给相邻兄弟的上边框。 */
  .entry-cols {
    grid-template-columns: 1fr;
    gap: 2.4rem;
  }

  .entry-cols::before {
    display: none;
  }

  .entry-cols li + li {
    padding-top: 2.4rem;
    border-top: 1px solid var(--line);
  }
}

/*
 * 入场，全站共用一套。
 *
 * 带 data-reveal 的元素是一个入场单元，脚本给它挂 .anim（内部 .reveal 先藏起来），
 * 滚到跟前挂 .in 放行；每个元素差多少由生成时算好的 --d 决定（见 pages.mjs）。
 * .anim 由脚本挂，所以没有 JS 时下面这些「先藏起来」的规则一条都不生效，页面是静态的。
 */
.anim .reveal {
  opacity: 0;
}

.anim.in .reveal {
  animation: entryRise 0.85s cubic-bezier(0.22, 0.61, 0.36, 1) var(--d, 0ms) forwards;
}

/* 画不走位移，改成从虚到实收拢一点——像墨落在纸上洇开又收住。 */
.anim.in .entry-art.reveal,
.anim.in .row-art.reveal,
.anim.in .master-portrait.reveal {
  animation: entryArtIn 1.15s cubic-bezier(0.22, 0.61, 0.36, 1) var(--d, 0ms) forwards;
}

.entries.anim .entry-cols::before {
  transform: scaleY(0);
  transform-origin: top;
}

.entries.anim.in .entry-cols::before {
  animation: entryRule 1s cubic-bezier(0.22, 0.61, 0.36, 1) 0.18s forwards;
}

@keyframes entryRise {
  from {
    opacity: 0;
    transform: translateY(14px);
    filter: blur(3px);
  }

  to {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}

@keyframes entryArtIn {
  from {
    opacity: 0;
    transform: scale(1.035);
    filter: blur(7px);
  }

  to {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}

@keyframes entryRule {
  to {
    transform: scaleY(1);
  }
}

/* 脚本已按减动效偏好整段跳过，这里再兜一层，免得将来改脚本时漏掉。 */
@media (prefers-reduced-motion: reduce) {
  .anim .reveal {
    opacity: 1;
    animation: none;
  }

  .entries.anim .entry-cols::before {
    transform: none;
    animation: none;
  }
}

/* ── 提问条 ───────────────────────────────────────────── */

/*
 * 穿插在各节之间的一条：左边一问，右边一个输入框直达问 AI。
 * 整页读到底才见到入口对多数人来说太晚，这一条让人随时能开口。
 */
.askband {
  padding: clamp(28px, 5vh, 48px) 0;
}

.askband-box {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  max-width: var(--maxw-text);
  margin: 0 auto;
  padding: clamp(1.1rem, 3vw, 1.9rem) clamp(1.2rem, 3.5vw, 2.4rem);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
}

.askband-title {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(1.05rem, 2.4vw, 1.5rem);
  font-weight: 700;
}

.askband-field {
  display: flex;
  align-items: center;
  flex: 1 1 20rem;
  /*
   * 弹性子项的最小宽度默认是 auto，也就是「不小于自身内容」。里面的按钮是 nowrap 的，
   * 窄屏上这一条就把整个输入框顶得比视口还宽，整页跟着能横向拖。显式归零才允许它收缩。
   */
  min-width: 0;
  max-width: 30rem;
  padding: 0.3rem 0.3rem 0.3rem 1rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--bg);
}

.askband-field:focus-within {
  border-color: var(--accent);
}

.askband-field input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  font-size: 0.95rem;
}

.askband-field input:focus {
  outline: none;
}

.askband-field button {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  flex: none;
  padding: 0.5rem 1.1rem;
  border: 0;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.2s ease;
}

.askband-field button:hover {
  background: var(--accent-ink);
}

/* 按钮的长短两句，宽屏出长的那句。窄屏对调，见下面 560px 那一档。 */
.askband-cta-short {
  display: none;
}

/*
 * 右边不是输入框而是一个直接跳转的按钮时用它（排盘页九门之前那一条）。
 * 比常规按钮宽一点：这一条右侧只有它一件东西，按常规尺寸会压不住左边那句话。
 */
.askband-cta {
  flex: none;
  padding: 0.7rem 1.8rem;
  font-size: 1rem;
}

/*
 * 窄屏：一问一框并排放不下，改成上下两行，输入框独占一行。
 * 按钮标签在有些语种里很长（英文的「Ask your first question」），所以这里放开 nowrap，
 * 宁可折成两行也不要把整条顶宽。
 */
@media (max-width: 560px) {
  .askband-box {
    flex-direction: column;
    align-items: stretch;
    text-align: center;
    /*
     * 转成一列之后 flex-wrap 必须一起关掉，否则这一条会横着顶出屏幕。
     *
     * 换行的弹性容器，每条流的横向尺寸是按行内各项的 max-content 撑出来的，而 stretch 又让
     * 每一项都长到那个尺寸——于是横排时那句「Ask your first question」有多宽，竖排后整条就有
     * 多宽，容器自己反倒管不着（英文 320 宽的屏上顶出十二像素，整页能横向拖）。竖着排本来
     * 就只有一条流，wrap 在这里没有任何用处，关掉即可，各项这才回去听容器的宽度。
     */
    flex-wrap: nowrap;
  }

  .askband-field {
    flex-basis: auto;
    max-width: none;
  }

  /* 窄屏换上短的那句（见 pages.mjs 的 askBox）。 */
  .askband-cta-long {
    display: none;
  }

  .askband-cta-short {
    display: inline;
  }

  /*
   * 胶囊里的内距一并收一收，把省下的十来像素让给输入框。
   *
   * 换短句之后占位那行「说出来，就已经是开始」只剩一像素余量——同一句话在别的机器上换个
   * 回退字体就又被截了。这里的目标不是「刚好放下」，是留出一个字的富余。
   */
  .askband-field {
    padding-left: 0.75rem;
  }

  .askband-field button {
    padding-inline: 0.8rem;
    white-space: normal;
  }
}

/* ── 康立波老师 ───────────────────────────────────────── */

/*
 * 三段往下排：其人（像左字右）→ 玄天模式 → 九门术数。
 * 头一段左右分栏，后两段居中成块，层次才拉得开。
 */
.master-who {
  display: grid;
  gap: clamp(1.4rem, 5vw, 3.5rem);
  align-items: center;
  /* 两列都按内容定宽再整组居中，不铺满整行——否则右边会空出一大块。 */
  justify-content: center;
  justify-items: center;
  max-width: var(--maxw-text);
  margin: 0 auto clamp(2.5rem, 7vh, 4.5rem);
  text-align: center;
}

@media (min-width: 760px) {
  .master-who {
    grid-template-columns: auto auto;
  }

  /* 名字与头衔右对齐，右缘取齐；画像在左，两边各自成边。 */
  .master-intro {
    text-align: right;
  }

  .master-intro .master-since {
    margin-right: 0;
  }
}

.master-intro {
  max-width: 34rem;
}

/* 线描画像，与整站的纸面是一路的；不用真人照片。 */
.master-portrait {
  display: block;
  width: clamp(150px, 20vw, 220px);
  height: auto;
  pointer-events: none;
  user-select: none;
}

.master-name {
  margin: 0;
  font-size: clamp(1.5rem, 3.2vw, 2.1rem);
}

.master-titles {
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.9;
}

.master-since {
  max-width: 30rem;
  margin: 1rem auto 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.8;
  /* 两行之间匀一匀，免得末行只剩一个字。 */
  text-wrap: balance;
}

/*
 * 结尾那句同行：套 Hero 的书法体写成大字，逐字浮现。
 *
 * 字是构建期就拆好的（见 pages.mjs 的 typeChars），所以没有 JS 时它只是一行正常的大字；
 * .anim 由脚本挂、.in 由 IntersectionObserver 挂，下面「先藏起来」那条才会生效。
 */
.master-oath {
  /* 放得下中文那句的一整行；英文长句自然折行，靠 balance 匀开。 */
  max-width: 52rem;
  margin: clamp(2.2rem, 6vh, 3.6rem) auto 0;
  font-family: var(--font-display);
  /* 同 .hero h1：中间那一档要够大，否则手机上这句大字会掉到下限，跟正文分不出来。 */
  font-size: clamp(1.5rem, 7vw, 2.9rem);
  line-height: 1.7;
  text-align: center;
  text-wrap: balance;
}

.master-oath .w {
  white-space: nowrap;
}

.master-oath.anim .ch {
  opacity: 0;
}

.master-oath.anim.in .ch {
  animation: tokenFade 0.42s ease-out var(--d, 0ms) forwards;
}

@media (prefers-reduced-motion: reduce) {
  .master-oath.anim .ch {
    opacity: 1;
    animation: none;
  }
}

/*
 * 玄天这段：标题 → 九门格 → 解释。
 * 九门正是玄天可调的那些盘，所以标题统领它们，解释放在格子之后收口。
 */
.xuantian {
  /* 与上面老师那一段拉开一档，两件事才不粘在一起。 */
  margin-top: clamp(3rem, 9vh, 5.5rem);
}

.xuantian-head {
  margin: 0 0 clamp(1.4rem, 3.5vh, 2.2rem);
  font-size: clamp(1.35rem, 2.8vw, 1.85rem);
  line-height: 1.4;
  text-align: center;
}

/* 与上面的九宫格同宽，左右缘对齐。 */
.xuantian-lede {
  max-width: var(--maxw-text);
  margin: clamp(1.6rem, 4vh, 2.4rem) auto 0;
  color: var(--muted);
  font-size: 0.98rem;
  line-height: 1.95;
  text-align: center;
  text-wrap: pretty;
}

/* ── 九门术数：1 + 2×4 ────────────────────────────────── */


/*
 * 卡片规格照搬应用（见 h5/components/GuoxueCard.module.css）：竖卡 175×205、整卡底图、
 * 文字压在画面底部居中、10px 圆角、#cab49f 细线。切图 525×615 与卡片同比例，所以铺满
 * 既不拉伸也不裁切。
 *
 * 宽度取正文栏，与下面「立波择吉」那三行左右缘对齐，整页的版心才是一条线。
 * 卡片随之比应用里的 175px 大一点，但切图是 525×615、比版位还大，放大不会糊。
 */
.shushu-grid {
  --scard-gap: 0.7rem;
  display: grid;
  gap: var(--scard-gap);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  max-width: var(--maxw-text);
  margin: 0 auto;
}

/* 六列两行：八字占左边两列两行，其余八门填右边四列。 */
@media (min-width: 780px) {
  .shushu-grid {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }

  .scard-lead {
    grid-column: span 2;
    grid-row: span 2;
    /* 跨两格两行时高度由行高决定，不再自带比例，否则会与行高打架。 */
    aspect-ratio: auto;
  }
}

.scard {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  /* 175:205 —— 应用里竖卡的尺寸。 */
  aspect-ratio: 175 / 205;
  padding: 0 6px 8px;
  border: 1px solid #cab49f;
  border-radius: 10px;
  background: var(--bg);
  color: var(--ink);
  overflow: hidden;
  text-align: center;
  text-decoration: none;
  transition:
    border-color 0.25s ease,
    transform 0.25s ease;
}

.scard:hover {
  border-color: var(--accent);
  text-decoration: none;
}

/* 底图铺满整卡，文字直接叠在画面上——与应用一致。 */
.scard-art {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  user-select: none;
  transition: transform 0.35s ease;
}

.scard:hover .scard-art {
  transform: scale(1.04);
}

.scard-copy {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  max-width: 164px;
}

.scard .t {
  font-family: var(--font-serif);
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.3;
}

.scard .d {
  color: #8f6f4c;
  font-size: 0.75rem;
  line-height: 1.35;
}

/* 八字是主位，卡片大一倍，字也跟着放一档。 */
.scard-lead .scard-copy {
  max-width: 22rem;
}

.scard-lead .t {
  font-size: clamp(1.5rem, 2.6vw, 2rem);
}

.scard-lead .d {
  font-size: 0.85rem;
}

@media (min-width: 780px) {
  .scard-lead {
    padding-bottom: 1.4rem;
  }

  /*
   * 风水那张是横版列表卡的切图（616×366），放进竖格若按整卡 cover，等于只取中间三成再放大，
   * 罗盘会撑满整格；若按 contain 整幅缩进去，又比另外八张小一截。
   * 折中：只占上面六成半的高度，在这个盒子里 cover——左右轻裁一点，罗盘的尺度就和其余八门齐了。
   */
  .scard:last-child .scard-art {
    inset: 5% 0 auto;
    height: 70%;
    object-position: center;
  }
}

/*
 * 两列版的末位（风水）横过来占满一行。
 *
 * 九张卡两列排会多出一张落单，而风水那张切图本就是横版列表卡用的（616×366），应用里
 * 也正是把它单独做成横卡（见 GuoxueCard.module.css 的 .list.fengshui）。这里照搬：
 * 画按卡高贴右、不裁，左边留给文字。
 */
@media (max-width: 779px) {
  .scard:last-child {
    grid-column: span 2;
    aspect-ratio: 362 / 122;
    align-items: flex-start;
    justify-content: center;
    padding: 0 0 0 15px;
    text-align: start;
  }

  .scard:last-child .scard-art {
    object-fit: contain;
    object-position: right center;
  }

  .scard:last-child .scard-copy {
    max-width: 68%;
  }
}

/* ── 交错三行 ─────────────────────────────────────────── */

.row-list {
  display: grid;
  gap: clamp(3rem, 9vh, 6rem);
  max-width: var(--maxw-text);
  margin: 0 auto;
  padding: 0;
  list-style: none;
}

.row {
  display: grid;
  gap: clamp(1.4rem, 4vw, 3.5rem);
  align-items: center;
  margin: 0;
}

@media (min-width: 860px) {
  .row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /*
   * 左右交错：DOM 恒为「图在前、字在后」，偶数行靠列序翻转而不是换一套结构——
   * 读屏与窄屏堆叠的顺序才始终一致。
   */
  .row:nth-child(even) .row-art {
    grid-column: 2;
    grid-row: 1;
  }

  .row:nth-child(even) .row-copy {
    grid-column: 1;
    grid-row: 1;
  }
}

/*
 * 三张画裁去透明边之后比例各不相同（1.60 / 1.72 / 0.89），所以按等高摆放、宽度各随各的，
 * 三行的分量才一致；否则那张竖的会比另外两张矮一大截。
 */
.row-art {
  display: block;
  width: 100%;
  max-width: 26rem;
  height: clamp(190px, 26vw, 300px);
  margin: 0 auto;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
}

.row-copy h3 {
  margin: 0;
  font-size: clamp(1.25rem, 2.6vw, 1.6rem);
}

.row-sub {
  margin: 0.35rem 0 0;
  color: var(--accent-ink);
  font-size: 0.95rem;
}

.row-lines {
  margin-top: 1rem;
}

.row-lines span {
  display: block;
  margin-top: 0.5rem;
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.9;
}

.row-act {
  margin: 1.4rem 0 0;
}

/* ── 用户评价 ─────────────────────────────────────────── */

.voices-head {
  margin: 0 0 clamp(1.6rem, 4vh, 2.4rem);
  font-size: clamp(1.35rem, 3vw, 1.9rem);
  text-align: center;
}

/*
 * 跑马灯：两份同样的卡片并排，一起左移一整份的宽度，走完正好接上，看不出断点。
 * 轨道要出血到版心之外，两端的卡片半露在屏幕边上，才有「还在往下滚」的意思。
 */
.voices-rail {
  display: flex;
  overflow: hidden;
  /* 两端各淡出一截，卡片是滚进滚出而不是被切断。 */
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}

.voices-track {
  --voice-gap: clamp(1rem, 2vw, 1.6rem);
  display: flex;
  flex: none;
  gap: var(--voice-gap);
  margin: 0;
  padding: 0.6rem var(--voice-gap) 0.6rem 0;
  list-style: none;
  animation: voicesRoll 72s linear infinite;
}

@keyframes voicesRoll {
  to {
    transform: translateX(-100%);
  }
}

/* 停下来才读得完：鼠标停住、或键盘走到里面的链接时都暂停。 */
.voices-rail:hover .voices-track,
.voices-rail:focus-within .voices-track {
  animation-play-state: paused;
}

.voice {
  display: flex;
  flex-direction: column;
  flex: none;
  width: clamp(17rem, 26vw, 22rem);
  margin: 0;
  padding: 1.6rem 1.7rem 1.5rem;
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(60, 42, 24, 0.05), 0 8px 24px rgba(60, 42, 24, 0.06);
}

.voice-mark {
  color: var(--accent);
  font-family: var(--font-serif);
  font-size: 2rem;
  line-height: 1;
}

.voice blockquote {
  flex: 1 1 auto;
  margin: 0.7rem 0 0;
  color: var(--ink);
  font-size: 0.95rem;
  line-height: 1.95;
}

.voice-who {
  margin: 1.4rem 0 0;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.85rem;
}

.voice-who .n {
  color: var(--ink);
}

.voice-who .m::before {
  content: " · ";
}

/*
 * 要求减少动态效果时不自动滚，退成一条可以自己横向拖的卡片带——内容一条都不少。
 * 遮罩也去掉，否则拖到两端的卡片会被淡成半透明。
 */
@media (prefers-reduced-motion: reduce) {
  .voices-rail {
    overflow-x: auto;
    mask-image: none;
  }

  .voices-track {
    animation: none;
  }

  /* 第二份是给无缝滚动用的复制品，不滚了就没有它的位置。 */
  .voices-track[aria-hidden='true'] {
    display: none;
  }
}

/* ── 结尾 ─────────────────────────────────────────────── */

/* 页尾用的还是提问条那个盒子，上面先落一句中道的话安顿一下。 */
.closing {
  text-align: center;
}

.closing-lede {
  max-width: 34rem;
  margin: 0 auto clamp(1.6rem, 4vh, 2.4rem);
  color: var(--muted);
  font-size: clamp(0.98rem, 1.8vw, 1.08rem);
  line-height: 1.95;
  text-wrap: pretty;
}

/* ── 排盘工具页：Hero ───────────────────────────────────── */

/*
 * 这一页的标语要求整句不断行，所以字号得跟着屏宽走，而不是先定死再指望它放得下。
 *
 * 二十二个全角字，占宽正好是字号的二十二倍；版心是屏宽减两侧 20px 的边。3.9vw 这一档
 * 让两者始终差着十几像素：390 宽的手机上排 15.2px，一行 335px 落在 350px 的版心里；
 * 窄到 320 也还剩五像素的余量。早先中间那档取 2.9vw、下限 0.86rem，390 上只有 13.8px
 * ——比正文还小一号，是这一句在手机上显得虚的原因；而到了 320 宽，下限那 13.8px 反而
 * 排不下，会横着顶出版心。
 *
 * 只对中文生效：其余语种那一句长得多，禁止断行会让它横着顶出版心，把整页撑出一条横向滚动条。
 * 繁体那一句与简体同长（二十二个全角字，见 product-copy.mjs），所以两个书写系统一起放进来。
 */
html[lang='zh-Hans'] .hero-charting .lede,
html[lang='zh-Hant'] .hero-charting .lede {
  max-width: none;
  font-size: clamp(0.72rem, 3.9vw, 1.15rem);
  white-space: nowrap;
}

/* ── 排盘工具页：页顶九门跑马灯 ─────────────────────────── */

/*
 * 九张竖卡从右往左滚。做法与「听听他们怎么说」同一套：两份同样的卡片并排，一起向左平移
 * 一整份的宽度，走完正好接上，看不出断点（详见 .voices-rail 那段说明）。轨道出血到版心
 * 之外、两端各淡出一截，卡片是滚进滚出而不是被切断。
 *
 * 卡片刻意不是链接：它一直在动，点移动的目标本身就难受；这一节要说的是「有哪九门」，
 * 真要进去，下面那个主按钮（charting/copy.mjs 的 tryCta）是唯一且明确的入口。
 */
.crail {
  padding: 0 0 clamp(2.2rem, 6vh, 3.4rem);
}

.crail-rail {
  display: flex;
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}

.crail-track {
  --crail-gap: clamp(0.7rem, 1.4vw, 1.1rem);
  display: flex;
  flex: none;
  gap: var(--crail-gap);
  margin: 0;
  padding: 0.4rem var(--crail-gap) 0.4rem 0;
  list-style: none;
  animation: crailRoll 56s linear infinite;
}

@keyframes crailRoll {
  to {
    transform: translateX(-100%);
  }
}

/* 停下来才看得清哪张是哪张。 */
.crail-rail:hover .crail-track {
  animation-play-state: paused;
}

/* 与首页九宫格那九张同一个规格：175:205，是应用里竖卡的尺寸。 */
.crail-card {
  position: relative;
  display: flex;
  flex: none;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  width: clamp(138px, 15vw, 184px);
  aspect-ratio: 175 / 205;
  margin: 0;
  padding: 0 6px 8px;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  background: var(--bg);
  overflow: hidden;
  text-align: center;
}

.crail-art {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  user-select: none;
}

/*
 * 风水那张是横版列表卡的切图（616×366）。塞进竖格按整卡 cover，等于只取中间三成再放大，
 * 罗盘会撑破格子；只让它占上面约七成高、在那个盒子里 cover，尺度就和另外八门齐了。
 * 与首页九宫格里 .scard:last-child 同一处理。
 */
.crail-card:last-child .crail-art {
  inset: 6% 0 auto;
  height: 68%;
}

.crail-copy {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
}

.crail-copy .t {
  font-family: var(--font-serif);
  font-size: clamp(1rem, 1.5vw, 1.24rem);
  font-weight: 600;
  line-height: 1.3;
}

.crail-copy .d {
  color: var(--muted);
  font-size: 0.7rem;
  line-height: 1.35;
}

/* 按钮在跑马灯之上，紧接着 Hero 那句话。 */
.crail-act {
  margin-bottom: clamp(1.6rem, 4vh, 2.4rem);
  text-align: center;
}

/* 比常规按钮长一截：它是这一页唯一的主入口，短按钮压不住上面那句标语。 */
.crail-cta {
  min-width: min(20rem, 78vw);
  padding: 0.85rem 2.4rem;
  font-size: 1.02rem;
}

/*
 * 要求减少动态效果时不自动滚，退成一条可以自己横向拖的卡片带——内容一条都不少。
 * 遮罩也去掉，否则拖到两端的卡片会被淡成半透明。
 */
@media (prefers-reduced-motion: reduce) {
  .crail-rail {
    overflow-x: auto;
    mask-image: none;
  }

  .crail-track {
    animation: none;
  }

  /* 第二份是给无缝滚动用的复制品，不滚了就没有它的位置。 */
  .crail-track[aria-hidden='true'] {
    display: none;
  }
}

/* ── 排盘工具页：九门交错长节 ───────────────────────────── */

.csys-head {
  max-width: 46rem;
  margin: 0 auto clamp(2rem, 6vh, 3.2rem);
  text-align: center;
}

/*
 * 版心与页上别的东西同宽（--maxw-text）：两个功能板块、这九节、上下两条提问条，四处
 * 左右边沿在一条线上。早先这里独用 84rem，比提问条宽出 8rem，宽屏上看得出参差。
 */
.csys-list {
  display: grid;
  gap: clamp(3.5rem, 10vh, 6.5rem);
  max-width: var(--maxw-text);
  margin: 0 auto;
  padding: 0;
  list-style: none;
}

/*
 * 版式的两条竖线，两个功能板块与九节共用。
 *
 * --chart-card-w  入口卡 / 演示屏的宽度。卡在栏里居中，栏比它宽出来的那一段就是**左沿线**
 *                 的缩进量，落在左栏的正文与演示屏都按它起排。
 * --chart-text-w  正文的行宽上限。正文在栏里靠左，它的右端就是**右沿线**，落在右栏的
 *                 卡片、演示屏与衬底图都按它收边。
 *
 * 两个值各只写一处，改宽度不会把对齐改坏。
 */
.cfeat,
.csys {
  --chart-card-w: 24rem;
  --chart-text-w: 34rem;
}

.csys {
  display: grid;
  gap: clamp(1.6rem, 4vw, 3.4rem);
  align-items: center;
  margin: 0;
  /* 顶栏是 sticky，从跑马灯或外链锚点跳过来时要给它让出高度。 */
  scroll-margin-top: calc(var(--header-h) + 16px);
}

@media (min-width: 900px) {
  /* 盘面那栏窄一点：盘本来就有自己的宽度上限，两栏均分会让它孤零零浮在半栏正中。 */
  .csys {
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr);
  }

  /*
   * 左右交错：DOM 恒为「盘在前、字在后」，偶数节靠列序翻转而不是换一套结构——
   * 读屏与窄屏堆叠的顺序才始终一致。与首页交错三行同一做法。
   *
   * 交错到右边的那几节，盘面靠右沿线收边，不停在栏心。
   *
   * 偶数节的盘面占的正是奇数节正文占的那一栏（都是第 2 列、都是 1fr），所以这里的 100%
   * 与那一栏同宽，100% - 行宽上限 就是正文在栏里靠左之后右边剩下的那一段。把它让成
   * padding、卡片再靠右，卡的右沿便与正文的右端在同一条线上。
   */
  .csys:nth-child(even) .csys-chart {
    grid-column: 2;
    grid-row: 1;
    justify-content: flex-end;
    padding-right: max(0px, 100% - var(--chart-text-w));
  }

  /*
   * 交错到左边的那几节，正文跟着盘面的左沿走，不去贴版心的外沿。
   *
   * 偶数节的正文占的正是奇数节盘面占的那一栏——都是第 1 列、都是 0.85fr，所以这里的
   * 100% 与那一栏同宽，(100% - 卡宽) / 2 算出来的就是 .csys-frame 在栏内居中时让出的
   * 那段空白。两侧因此逐像素对齐，且栏窄到装不下一张卡时两边同时归零，不必为断点另写一档。
   */
  .csys:nth-child(even) .csys-copy {
    grid-column: 1;
    grid-row: 1;
    padding-left: max(0px, (100% - var(--chart-card-w)) / 2);
  }
}

.csys-chart {
  display: flex;
  justify-content: center;
  min-width: 0;
}

/*
 * 入口卡的位置。
 *
 * 这里原先摆的是问 AI 对话里那张小排盘卡，随内容长高、不封高度。换成插图卡之后改为定比例：
 * 九张插图本来就是同一套竖版切图（175:205），封住比例九节看下来才是齐的，
 * 而卡里那一层起盘动画也需要一个确定的框才好编排。
 */
.csys-frame {
  position: relative;
  width: 100%;
  max-width: var(--chart-card-w);
}

/*
 * 入口卡：插图铺满，底下压一句祈使句（copy.tryCardCta），最上面盖着那一层起盘动画。
 *
 * 与首页九宫格那张卡（.scard）刻意同形——同一张切图、同样的边框圆角、同样的悬停放大。
 * 差别只在这张会动：停上去先演一遍这一门怎么起盘，演完浮出整页排盘（见 chartingScript）。
 */
.csys-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  aspect-ratio: 175 / 205;
  padding: 0 6px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  background: var(--bg);
  color: var(--ink);
  overflow: hidden;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition:
    border-color 0.25s ease,
    box-shadow 0.25s ease;
}

.csys-card:hover,
.csys-card:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 6px 24px rgba(60, 42, 24, 0.14);
  text-decoration: none;
}

.csys-card-art {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  user-select: none;
  transition: transform 0.35s ease;
}

.csys-card:hover .csys-card-art {
  transform: scale(1.04);
}

/*
 * 末位（风水）那张是横版列表卡的切图（616×366）。竖卡按整卡 cover，等于把罗盘放大到出框：
 * 左右各裁掉一截，盘沿被切平。只让它占中间八成高、在那个盒子里 cover，整只罗盘就落在卡内。
 * 与页顶跑马灯的 .crail-card:last-child、首页九宫格的 .scard:last-child 同一手法；这张卡
 * 比那两处大得多，收到八成即可，不必也收到七成。
 */
.csys:last-child .csys-card-art {
  inset: 10% 0 auto;
  height: 80%;
}

/*
 * 那一句祈使句。
 *
 * 压在插图上，所以要一层从下往上的暗角托底——九张切图深浅不一，只靠字色保证不了对比度。
 */
.csys-card-cta {
  position: relative;
  z-index: 1;
  padding: 0.35em 1.1em;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: rgba(250, 249, 245, 0.92);
  font-family: var(--font-serif);
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  color: var(--accent-ink);
  transition:
    background-color 0.25s ease,
    color 0.25s ease;
}

.csys-card:hover .csys-card-cta {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/*
 * 起盘动画那一层。
 *
 * 平时整层透明、不占事件；脚本挂上 .is-casting 才显形（内部九套关键帧见 charting/_cast.css）。
 * 动画期间把卡面那句 CTA 淡掉——话已经听懂了，留着只会挡住正在演的盘。
 */
/*
 * 卡面上的起盘动画——应用里排盘算完之前盖在整页上的那一层，整份搬来（见 charting/reveals.mjs）。
 *
 * 它在应用里是 `position:absolute; inset:0` 铺满一整屏手机，尺寸（门板宽度、梅枝 340×240、
 * 双手贴图、蓍草长度）全是按那个尺度定的。直接塞进两百来像素的卡框，门板会宽得只剩一条缝、
 * 梅枝只露出一截。所以给它一个固定尺寸的虚拟视口，再整体缩放贴进卡框：比例与应用完全一致，
 * 只是小一号。缩放系数由脚本按卡片实测尺寸下发（--rev-scale），CSS 算不出「缩到刚好装下」。
 */
/*
 * 裁切层要盖满整张卡。
 *
 * 负的左右下偏移是在抵消卡片自己的 `padding: 0 6px 12px`——这张卡是 flex 容器，绝对定位子元素
 * 的 inset 落在内容盒上，写 `inset: 0` 会比卡片窄 12px、矮 12px，两侧各露出一条底色。
 * 数值与上面 .csys-card 的 padding 一一对应，改那边记得改这里。
 */
.csys-card-reveal {
  position: absolute;
  inset: 0 -6px -12px;
  z-index: 2;
  overflow: hidden;
  border-radius: inherit;
  opacity: 0;
  pointer-events: none;
}

.csys-card.is-casting .csys-card-reveal {
  opacity: 1;
}

/*
 * 虚拟视口：动画在这块 390×560 里按应用的原尺度铺开，再整体缩放**铺满**卡框
 * （scale 取两个方向的较大者，短边溢出的部分由外层裁掉）。取较小者会在卡里留出黑边，
 * 动画只占中间一小块，看起来像没对齐。缩放系数由脚本按卡片实测尺寸下发。
 */
.csys-card-vp {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 390px;
  height: 560px;
  transform: translate(-50%, -50%) scale(var(--rev-scale, 0.6));
}

.csys-card.is-casting .csys-card-cta {
  opacity: 0;
  transition: opacity 140ms ease-out;
}

/*
 * 入场时卡片不做位移，改成从虚到实收拢一点——与首页那几张画同一条规则（见 entryArtIn）。
 * 一整块界面上下弹一下太重，何况它旁边的文字正在逐行浮起，两种动作叠在一起会打架。
 */
.anim.in .csys-frame.reveal {
  animation: entryArtIn 1.15s cubic-bezier(0.22, 0.61, 0.36, 1) var(--d, 0ms) forwards;
}

/*
 * 文字那一栏。
 *
 * overflow 收住是为了底纹：那张图贴着栏的外沿、还要探出去一点，不收的话它会把整页撑宽，
 * 在窄屏上多出一条横向滚动条。
 */
.csys-copy {
  position: relative;
  min-width: 0;
  overflow: hidden;
}

/*
 * 文字背后压着的那张门类配图——就是页顶跑马灯上的同一张，放大、调淡、贴在版心外侧。
 *
 * 它不承载信息（alt 为空、aria-hidden），作用是让每一节有自己的气质：九节结构完全相同，
 * 只靠文字区分会读成一张长表格。靠内的一侧用遮罩渐隐，免得图的硬边横穿正文。
 */
.csys-ghost {
  position: absolute;
  z-index: 0;
  top: 50%;
  /*
   * 收在右沿线上，与这一栏正文的右端齐平——它先前是 -1.5rem（贴栏的外沿再探出去一点，
   * 多出的部分由 .csys-copy 的 overflow 切掉），那条线比正文的右端还要靠外六七个字，
   * 一节里于是有两条右边界。
   */
  right: max(0px, 100% - var(--chart-text-w));
  width: auto;
  height: min(115%, 25rem);
  transform: translateY(-50%);
  opacity: 0.085;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
  mask-image: linear-gradient(90deg, transparent, #000 55%);
}

/* 交错到左边那几节，底纹跟着挪到左沿线上，始终背对盘面那一栏。 */
.csys:nth-child(even) .csys-ghost {
  right: auto;
  left: max(0px, (100% - var(--chart-card-w)) / 2);
  mask-image: linear-gradient(270deg, transparent, #000 55%);
}

.csys-text {
  position: relative;
  z-index: 1;
  max-width: var(--chart-text-w);
}

.csys-name {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(1.3rem, 2.8vw, 1.75rem);
  line-height: 1.3;
  color: var(--accent-ink);
}

/* 罗马字副名跟在门名后面，小一档淡一档——像书口上的拉丁转写，不与门名争。 */
.csys-sub {
  margin-left: 0.7em;
  color: var(--muted);
  font-family: var(--font-sans);
  font-size: 0.68em;
  font-style: italic;
  font-weight: 400;
  letter-spacing: 0.02em;
}

.csys-lines {
  margin-top: 1rem;
}

.csys-lines p {
  margin: 0.7rem 0 0;
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.95;
}

.csys-acts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.7rem 1.4rem;
  margin: 1.6rem 0 0;
}

/*
 * 这里曾有一个「排盘示例」的文字按钮，是浮层唯一的触发点。撤了：现在左边整张卡就是触发点，
 * 停上去先演起盘动画再浮出那一页，一个入口比「一张静态卡 + 旁边一行小字」清楚得多。
 */

/*
 * 「××详解」。有内容层工具页的门类是 <a>，还没写的是 <span>（见 charting/page.mjs）。
 * 两种形态同一副字样——它在版面上的分量不该随「那一页写没写」而变。
 */
.csys-wiki {
  color: var(--muted);
  font-size: 0.92rem;
  cursor: default;
}

/*
 * 可点的那一版才给链接的手感。
 *
 * 底线用 text-decoration-color 调淡而不是平时不画、悬停才画：后者会在悬停瞬间把这一行
 * 顶高一点（下划线要占行盒），旁边就是「立即排盘」那个按钮，一起抖。
 */
a.csys-wiki {
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
  text-underline-offset: 0.28em;
  transition: color 0.18s ease, text-decoration-color 0.18s ease;
}

a.csys-wiki:hover,
a.csys-wiki:focus-visible {
  color: var(--accent-ink);
  text-decoration-color: currentColor;
}

/* ── 排盘工具页：排盘示例浮层 ───────────────────────────── */

/*
 * 卡面上那一下起盘演完，这一层就从那张卡长出来。
 *
 * 位置与放大原点由脚本按卡片的位置算（见 chartingScript），这里只管外观与那一下放大。
 * 不是模态：没有背板、不锁焦点、指针一离开就收——它是浮起来看一眼的东西，不是要人确认的
 * 对话。所以也没有标题栏，浮层里直接就是那一页排盘；关闭键只在触屏上出，理由见 .cpop-close。
 */
.cpop {
  position: fixed;
  z-index: 90;
  display: flex;
  flex-direction: column;
  width: min(94vw, 30rem);
  max-height: min(86vh, 54rem);
  border-radius: var(--radius-lg);
  background: var(--bg);
  box-shadow: 0 2px 6px rgba(60, 42, 24, 0.1), 0 18px 50px rgba(60, 42, 24, 0.22);
  overflow: hidden;
  /* 起手是很小的一点，落在卡心上。.cpop-in 再把它放开。 */
  opacity: 0;
  transform: scale(0.12);
  /*
   * 收起时不能接指针，否则它会把卡片的 hover 抢走。
   *
   * 上面那句 `display: flex` 盖过了浏览器默认的 `[hidden] { display: none }`（作者样式恒压
   * UA 样式），所以脚本里的 `pop.hidden = true` 只管无障碍，撤不掉布局——真正让它隐形的是
   * 这里的 opacity。于是关掉之后，一团缩到 12% 的隐形浮层就停在上一张卡的正中：鼠标一碰，
   * 卡片收到 pointerleave、起盘动画被掐断，挪开又从第一帧重演，看着就是「怎么老也弹不出来」。
   * 补一句 display:none 也能解，但那样每次浮起都要现算一整页排盘的布局；留在布局里、
   * 只摘掉命中测试，浮起时就没有这一下停顿。
   */
  pointer-events: none;
}

.cpop-in {
  opacity: 1;
  transform: scale(1);
  pointer-events: auto;
  transition:
    transform 240ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 160ms ease-out;
}

/*
 * 排盘页在这里是完整的一页，高了就在框内滚。滚动容器是这一层而不是页面本身：
 * 盘面整块 pointer-events:none（它是一幅画，不该被点也不该被选中），自己接不到滚轮。
 */
.cpop-stage {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/*
 * 关闭键：只给手指。
 *
 * 鼠标那一路不需要它——指针离开卡片与浮层，140ms 后自己就收了，画一个叉子上去反倒是在说
 * 「这是个要处理掉的对话」，而它不是。手指没有「离开」这一说：浮层摆下来占掉大半个屏幕，
 * 出路虽有三条（点浮层之外、Esc、再点一次那张卡），可三条都得先猜到。
 *
 * 摆在浮层自己身上而不是那一页的页眉里：页眉是从应用照搬的一条（.ppv-bar），那里画什么都
 * 会被当成应用界面的一部分——而应用的排盘页上并没有这么一个叉子。它属于浮层，不属于盘。
 * 44px 是触控下限，与全站 pointer: coarse 那一段同一个数。
 */
.cpop-close {
  display: none;
}

@media (pointer: coarse) {
  .cpop-close {
    position: absolute;
    z-index: 3;
    top: 2px;
    right: 2px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    border-radius: 999px;
    /* 页眉是浅色的，底下滚过去的是盘面，两种底色都要压得住。 */
    background: rgba(250, 249, 245, 0.88);
    color: var(--muted);
    font-family: inherit;
    font-size: 1.45rem;
    line-height: 1;
    cursor: pointer;
  }
}

/* 减少动态效果时不做那一下放大，直接出现——位置仍贴着卡片，交互不受影响。 */
@media (prefers-reduced-motion: reduce) {
  .cpop {
    transform: none;
  }

  .cpop-in {
    transition: none;
  }
}

/*
 * 九节之前的两个功能板块（盘上符号可点、排盘与 AI 同窗）。
 *
 * 一侧文字一侧演示，逐节左右对调。**整套版式与下面九节共用一份**：同样的版心宽度、同样的
 * 两栏比例、同样的断点、左栏内容同样落在盘面卡的左沿上（见 .csys 与 .csys-copy 的说明）。
 * 早先这里是自成一套的——版心不限宽（宽屏上比九节宽出一大截）、左右靠 order 对调而两栏
 * 比例跟着翻，于是「左边那一栏」时宽时窄，与下面九节对不上，滚下来像是两页拼在一起。
 *
 * 演示那一侧是一块手机比例的画，给它固定的最大宽度而不是按比例分栏：演示内容本身有确定
 * 尺度（弹窗、四柱表、输入框都是照应用尺寸搬的），栏宽一变它就得跟着缩放，字会糊。
 */
.cfeat-wrap {
  display: grid;
  gap: clamp(1.6rem, 4vw, 3.4rem);
  align-items: center;
  max-width: var(--maxw-text);
  margin-inline: auto;
}

/* 断点与 .csys 那条对齐（900px）：两处同宽同比例，就该在同一处并栏。 */
@media (min-width: 900px) {
  .cfeat-wrap {
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr);
  }

  /*
   * 左右交错：DOM 恒为「先标题后演示」，对调靠列序而不是 order——与九节同一做法，
   * 读屏与 Tab 的次序才不受影响。两栏的比例不跟着翻，第 1 列永远是窄的那一栏。
   */
  .cfeat-flip .cfeat-copy {
    grid-column: 2;
    grid-row: 1;
  }

  .cfeat-flip .cfeat-demo {
    grid-column: 1;
    grid-row: 1;
  }

  /* 正文落在左栏时，缩进与九节同一个算法（见 .csys:nth-child(even) .csys-copy）。 */
  .cfeat:not(.cfeat-flip) .cfeat-copy {
    padding-left: max(0px, (100% - var(--chart-card-w)) / 2);
  }

  /* 演示屏落在右栏时，靠右沿线收边（见 .csys:nth-child(even) .csys-chart）。 */
  .cfeat:not(.cfeat-flip) .cfeat-demo {
    justify-content: flex-end;
    padding-right: max(0px, 100% - var(--chart-text-w));
  }

  /*
   * 演示屏自身只有 340px 宽（尺度是照应用量的，见 charting/_features.css 的 .pp-feat），
   * 比 24rem 的框窄 44px；它默认 `margin: 0 auto` 居中，于是无论落在哪一栏，都比九节那张卡
   * 的边沿又往里缩 22px。所以按它所在的那一栏贴边：在左栏贴左，在右栏贴右，空出来的
   * 那 44px 是透明的，看不出来。
   *
   * 只在双栏时这么摆：并成一栏之后没有要对齐的卡，贴边反倒是整块画偏在屏幕一侧。
   */
  .cfeat-flip .cfeat-frame .ppz.pp-feat {
    margin-inline: 0 auto;
  }

  .cfeat:not(.cfeat-flip) .cfeat-frame .ppz.pp-feat {
    margin-inline: auto 0;
  }
}

/*
 * 标题与正文的字号字色跟下面九节同一套（.csys-name / .csys-lines p），两块读下来才是
 * 一页而不是两页——这两个板块与九节之间只隔着一条分隔线。改这里记得连那边一起改。
 */
.cfeat-name {
  margin: 0 0 0.6em;
  font-family: var(--font-serif);
  font-size: clamp(1.3rem, 2.8vw, 1.75rem);
  line-height: 1.3;
  color: var(--accent-ink);
}

/* 行宽上限与九节同一个值（.csys-text）：正文落在右栏时，右端要与那边收在同一条线上。 */
.cfeat-copy {
  max-width: var(--chart-text-w);
}

.cfeat-lines p {
  margin: 0 0 0.85em;
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.95;
}

.cfeat-lines p:last-child {
  margin-bottom: 0;
}

/* 与九节的 .csys-chart / .csys-frame 同构：一块与入口卡同宽的框，在栏里居中。 */
.cfeat-demo {
  display: flex;
  justify-content: center;
}

.cfeat-frame {
  width: 100%;
  max-width: var(--chart-card-w);
}

/* ── 排盘工具页：窄屏 ───────────────────────────────────── */

/*
 * 手机上这一页的毛病不在某一处不好看，在于整体太长：九门各占一节，每节先是一张几乎占满
 * 屏宽的竖幅大卡，再接三段文言，一台 390×664 的手机要滚十八屏才到底。而九节结构完全相同，
 * 滚下来像同一屏被复制了九遍——「长」与「重复」叠在一起，人看两节就走了。
 *
 * 这一段只改版式，一句文案都不删：文字本身是这一页的分量，删了就只剩九张图。
 * 900px 这个断点与上面 .csys 分两栏那条对齐，两边合起来正好覆盖所有宽度。
 */
@media (max-width: 899px) {
  /*
   * Hero 与它下面那个主按钮之间不留一节的空。
   *
   * 板块页通用的 Hero 自带 32px 的下边距，是给「Hero 之后是另一节」准备的；这一页的下一样
   * 东西是承接标语的那个按钮，两者本是一句话的两截，中间空出七十来像素就断开了。
   */
  .hero-charting {
    padding-bottom: 8px;
  }

  /*
   * 跑马灯与下一节之间收紧一档。
   *
   * 首屏的次序是：标语、主按钮、九门跑马灯，然后就该露出「哪里不懂点哪里」的标题——
   * 让人一眼知道下面还有东西。原先跑马灯下面留 40px、下一节自己又带 56px 的上边距，
   * 两截加起来正好把那个标题顶到折叠线以下，首屏底下剩一片空白。
   */
  .crail {
    padding-bottom: 1.1rem;
  }

  .crail + .section {
    padding-top: 2rem;
  }

  /*
   * 那张大卡收成一枚小图版。
   *
   * 它在宽屏上是与文字并排的一整栏，收窄成一栏之后却变成了「文字前面挡着一张大图」：
   * 三百五十见方的卡里只有一幅留白很多的插图和一句「试演此盘」，九节加起来近三千像素，
   * 全是要划过去的路。竖幅比例（175:205）保留不动——九张切图都是按这个比例裁的，
   * 改比例就得重裁；只把它缩到一枚图版的大小。它仍是那张可以点开的卡，点它照样浮出整页排盘。
   *
   * 图版靠左浮起来，门名与头几行绕着它排。只缩不浮的话，一枚一百来像素的卡孤零零占着一整行，
   * 右边空出大半行米色，看着像是图没加载完；绕排之后这一节的开头就是「一幅插图 + 一个门名」，
   * 正是书里一门起头的样子。
   */
  .csys {
    display: block;
  }

  /*
   * z-index 不能省，否则这张卡整个点不动。
   *
   * 绕排只收窄行盒，`<h3>` 与 `<p>` 的块盒仍是满栏宽的，横着盖在图版上——它们那一片虽然
   * 不显字，命中测试照样算数。平时这不要紧：按绘制次序，浮动元素排在块盒背景之后，还是浮动
   * 在上。可入场动画（entryRise）给每个 .reveal 挂了 transform，而带 transform 的元素自成
   * 层叠上下文，绘制阶次一下子跳到浮动之上——于是九张卡全被自己旁边的文字挡住，手指点下去
   * 落在段落上。给图版一个层号把它抬回最上面。
   *
   * 只在这里出现是因为宽屏是两栏网格，盘与字各占一格，压根没有重叠。
   */
  .csys-chart {
    position: relative;
    z-index: 1;
    float: left;
    width: clamp(7.5rem, 27vw, 11rem);
    margin: 0 1rem 0.6rem 0;
  }

  .csys-frame {
    max-width: none;
  }

  /*
   * 这一层原本 overflow: hidden 是为了收住底纹（那张图要探出版心）。底纹在窄屏上已经撤了，
   * 而 overflow 非 visible 会另起一个块级格式化上下文——那正好是「不绕浮动元素排」的开关，
   * 留着它文字就会整块让到图版下面去，浮动等于白做。
   */
  .csys-copy {
    overflow: visible;
  }

  /*
   * 文字那一层抬起来是为了压住底纹（.csys-text 的 z-index: 1）。底纹在这一档已经撤了，
   * 这个层号就只剩下副作用：它与上面图版同号而排在后面，同号比后来居上——刚抬起来的图版
   * 又被它压回去，卡还是点不动。放回 auto。
   */
  .csys-text {
    z-index: auto;
  }

  /* 三段文字与下面那排按钮清出浮动，免得按钮挤在图版旁边。 */
  .csys-acts {
    clear: left;
  }

  /* 卡小了，卡面那句话跟着收，否则一枚胶囊就顶满了卡宽。 */
  .csys-card-cta {
    padding: 0.3em 0.9em;
    font-size: clamp(0.82rem, 2.5vw, 1.05rem);
  }

  /*
   * 底纹撤掉。
   *
   * 它在宽屏上的作用是「让每一节有自己的气质」，靠的是把门类插图放大调淡贴在版心外侧。
   * 一栏之后版心没有外侧可贴，它只能压在正文正下方，成了一团横穿三段文字的脏印子；
   * 而那张图此刻已经以图版的样子明明白白摆在门名上头了，同一张图不必再影一遍。
   */
  .csys-ghost {
    display: none;
  }

  /*
   * 节与节之间画一条线。
   *
   * 宽屏上左右交错本身就是分节的记号——上一节的盘在左，下一节的盘在右，一眼看得出换了一节。
   * 一栏之后交错没有了，九节首尾相接只隔着一段空白，滚过去分不清是同一节的下半截还是新的
   * 一节。留白照旧给足，中间补一条发丝线交代边界。
   */
  .csys-list {
    gap: 0;
  }

  .csys + .csys {
    margin-top: clamp(2.2rem, 7vw, 3.2rem);
    padding-top: clamp(2.2rem, 7vw, 3.2rem);
    border-top: 1px solid var(--line);
  }

  /*
   * 正文按手机的尺度重排。
   *
   * 0.95rem 配 1.95 的行距是给宽屏那半栏定的：那里一行二十几个字，行距放开才不串行。
   * 手机上一行只有十七八个字，同样的行距把三段文言撑得又瘦又长，而 15.2px 的文言本来
   * 就偏小。字放大到与正文同号、行距收到 1.8，读着更稳，通篇还短了一截。
   *
   * 两个功能板块与九节共用一套字号字色（见上面 .cfeat-lines p 的说明），一起改。
   */
  .csys-lines p,
  .cfeat-lines p {
    font-size: 1rem;
    line-height: 1.8;
  }

  /*
   * 详解页还没写的那几门，这一项是一行不可点的字。宽屏上鼠标停上去有 title 说明
   * 「尚在编撰」，手指没有「停上去」这一说：那个「›」在触屏上就是一个点了没反应的链接。
   * 记号去掉，留一行素字，不再假装自己通向什么地方。
   *
   * 限定 span：真链接（a.csys-wiki）那几门要留着记号，它们点了确实有下文。
   */
  span.csys-wiki span[aria-hidden] {
    display: none;
  }
}

/* @pages-only:end */