/* wanctl docs site — wc.z10.dev/docs
   视觉真源 docs/design/DESIGN.md，第三种密度见 §9 那张表。
   这一层只加密度和三栏骨架：token、字体、顶栏、页脚全部来自 app.css，
   所以文档站的外壳跟官网是同一份代码，改不动它也漂不走。

   参照 api-docs.deepseek.com（PORTAL-HANDOFF §4 实截）：三栏只用发丝线分隔、
   无背景；面包屑最后一节是浅蓝胶囊；行内代码是浅灰圆角块；表格全边框加灰表头。
   不抄的是它的 try-it 面板 —— wanctl 对用户的界面是 CLI，没有那种东西可试。 */

:root{
  /* 当前项与面包屑末节的底色。它承载的是 --blue 文字（4.5:1 已验，
     tools/contrast.py 的 docs 表），不承载正文，也不是第二个强调色。
     跟门户用的是同一个值。 */
  --blue-wash:#eaf2fc;
  /* 内容锁比官网的 1440 窄：官网是海报要用掉整幅宽度，文档是拿来读的。
     三栏 232 + 正文 + 196，正文落在 70 字符左右。
     --pad 在 app.css 里是 var(--maxw) 的函数，改这一个值顶栏也跟着收。 */
  --maxw:1240px;
  /* app.css 的吸顶条高度，写死在那边的 `.nav{height:48px}`。
     两根侧栏吸在它底下，所以这个数在这里要有个名字。 */
  --dhead:48px;
}

/* ── 密度 ──────────────────────────────────────────────────────────
   官网 17px、门户 15px、文档 16px。文档是长文，比工具松、比海报紧。 */
body.docs{font-size:16px;line-height:1.65;letter-spacing:-.2px}
/* 这一条的中文重置只能写在这里。app.css 的 `body:lang(zh)` 是 0,1,1，
   跟 `body.docs` 打平，而本文件后加载，打平就是它赢 —— 于是读者切到中文之后，
   顶栏、面包屑、翻页那些不在 <article lang> 里的中文照样带着 -.2px。
   0,2,1 才压得住。行高 1.65 不动：对汉字来说它本来就比 1.6 还松一点。 */
body.docs:lang(zh){letter-spacing:0}
.docs h1,.docs h2,.docs h3,.docs h4{text-wrap:pretty}
/* 每页两份正文、两份本页目录，docs.js 用 hidden 挑一份。UA 样式表里的
   [hidden]{display:none} 权重是 0，本文件任何一条给 article 或 ul 设 display
   的规则都会盖掉它，于是两种语言一起显示。这一条把它钉死。 */
.docs [hidden]{display:none}

/* 顶栏：跟官网同一份 .nav，只多一个「你现在在文档里」的标签。
   gap 收到 14px，好让这个标签贴着字标站，而不是浮在中间。 */
.docs .nav{gap:14px}
/* align-self:stretch 跟官网的 .brand / .links a 一个道理：这一条也是链接，
   手机上它只有 24px 高。撑到顶栏的 48 之后按压面够得着，墨迹一个像素不动。 */
.docs .nav .here{
  display:flex;align-items:center;align-self:stretch;
  color:var(--ink-2);font-size:14px;font-weight:400;letter-spacing:-.2px;flex:none;
}
/* 「文档」两个字，同上：0,3,0 得由 0,4,0 来重置。 */
.docs .nav .here:lang(zh){letter-spacing:0}
.docs .nav .here:hover{color:var(--ink);text-decoration:none}

/* ── 三栏 ──────────────────────────────────────────────────────────
   分隔只用发丝线，三栏都不上背景色。 */
.dpage{
  display:grid;align-items:start;
  grid-template-columns:232px minmax(0,1fr) 196px;
  padding:0 var(--pad);
}
.dpage.no-toc{grid-template-columns:232px minmax(0,1fr)}

/* 两根侧栏都吸在顶栏底下，各自滚各自的，只有正文跟着页面走。

   吸顶必须落在**栏本身**，不能落在栏里面那个盒子上 —— 这是 issue #26 的根因：
   `.dpage` 是 `align-items:start`，于是 `.dnav` / `.dtoc` 这两个 grid item
   的高度等于自己内容的高度（实测 902px 和 201px），而一个 sticky 元素只能在
   它的**包含块**里挪动。包含块就那么高，正文有 4000px，读者滚过去两栏就出画了。
   grid item 自己做 sticky 时包含块是它的 grid area —— 那一格跟整行一样高，
   所以两栏能一直吸着。栏高被 max-height 收进视口，超出的部分栏内自己滚。

   `top` 只写顶栏高度、不再补 22px：两栏本来就有 34px / 30px 的上内边距，
   那口气它们自己带着，补了反而比原来低一截。 */
.dnav,.dtoc{
  position:sticky;top:var(--dhead);max-height:calc(100vh - var(--dhead));
  overflow-y:auto;
  /* 滚动条安静下来：细、用发丝线那个灰、槽透明。不写 `::-webkit-scrollbar`
     —— 那条会把 macOS 的覆盖式滚动条换成占位的经典滚动条，凭空吃掉栏宽。 */
  scrollbar-width:thin;scrollbar-color:var(--hairline) transparent;
}

/* 左栏 */
.dnav{
  border-right:1px solid var(--hairline);
  padding:34px 26px 60px 0;font-size:14px;line-height:1.5;
}
/* 抽屉的三件套（触发钮、遮罩、抽屉自己的标题行）只在窄屏存在。 */
.dnav-open,.dscrim,.dnav-head{display:none}
.dnav .g{
  margin:22px 0 7px;font-size:12px;font-weight:600;color:var(--ink-2);
  letter-spacing:.04em;text-transform:uppercase;
}
.dnav .g:first-child{margin-top:0}
.dnav ul{margin:0;padding:0;list-style:none}
.dnav li{margin:0}
.dnav li a{
  display:block;padding:5px 10px;margin-left:-10px;border-radius:8px;
  color:var(--ink-2);
}
.dnav li a:hover{color:var(--ink);background:var(--canvas-2);text-decoration:none}
/* 当前项：蓝字加一层浅蓝底。整站唯一的「你在这」信号，跟门户是同一个语法。 */
.dnav li a.on{color:var(--blue);background:var(--blue-wash)}
.dnav li a.on:hover{color:var(--blue)}

/* 中栏 */
.dbody{min-width:0;padding:30px 44px 72px;overflow-wrap:break-word}
.dpage.no-toc .dbody{padding-right:0;max-width:78ch}

/* 面包屑。最后一节不是链接 —— 它就是你现在这一页，做成浅蓝胶囊。 */
.crumbs{
  display:flex;flex-wrap:wrap;align-items:center;gap:7px;
  font-size:13px;color:var(--ink-2);margin-bottom:22px;
}
.crumbs a{color:var(--ink-2)}
.crumbs a:hover{color:var(--ink);text-decoration:none}
/* 唯一一处 --ink-3：那两道斜杠是 CSS 画的分隔笔画，不是文字，
   正是 DESIGN.md §3 给 ink-3 划的用途。这一栏其余每一个字都是 ink-2 起步。 */
.crumbs>*:not(:last-child)::after{content:"/";margin-left:7px;color:var(--ink-3)}
.crumbs .pill{
  color:var(--blue);background:var(--blue-wash);
  border-radius:999px;padding:3px 11px;
}

/* 右栏 */
.dtoc{
  border-left:1px solid var(--hairline);
  padding:30px 0 60px 24px;font-size:13px;line-height:1.5;
}
.dtoc .t{
  margin:0 0 10px;font-size:12px;font-weight:600;color:var(--ink-2);
  letter-spacing:.04em;text-transform:uppercase;
}
.dtoc ul{margin:0;padding:0;list-style:none}
.dtoc ul ul{margin:2px 0 2px 12px}
.dtoc li{margin:0 0 2px}
.dtoc a{display:block;padding:3px 0;color:var(--ink-2)}
.dtoc a:hover{color:var(--blue);text-decoration:none}
/* 读到哪一节，右栏就标哪一条。跟左栏的当前项同一个语法（--blue），
   但**不上底色** —— 左栏说的是「你在哪一页」，右栏说的是「你读到哪儿了」，
   后者随着滚动一直在动，给它一块会跟着跳的底色是页面上最吵的东西。 */
.dtoc a.now{color:var(--blue)}

/* ── 正文排版 ──────────────────────────────────────────────────────
   大而紧排的标题，但比官网小一档：这里的标题是导航，不是主张。 */
/* balance 而不是 pretty：中文标题在这个宽度上会断成很不匀的两行
   （「把一台设备变成「可远程控制」（Mac」/「/ Linux）」——第二行只剩一个尾巴）。
   pretty 只管最后一行不落单，匀不匀它不管；balance 才会把几行拉到差不多长。
   标题一共就两三行，balance 的性能代价在这个规模上不存在。 */
.dbody article h1{
  margin:0 0 6px;font-size:clamp(30px,3.4vw,38px);font-weight:600;
  line-height:1.12;text-wrap:balance;
}
.dbody article h2{
  margin:44px 0 12px;font-size:24px;font-weight:600;line-height:1.2;
}
.dbody article h3{
  margin:32px 0 10px;font-size:18px;font-weight:600;line-height:1.3;
}
.dbody article h4{
  margin:26px 0 8px;font-size:16px;font-weight:600;color:var(--ink-2);
}

/* 标题的负字距单独一条，而且**故意压到 0,0,1**。
   这几个数是给拉丁字母调的（DESIGN.md §4 的字号阶）。中文不需要负字距，
   而中文排版归 app.css 的 `:lang(zh)` 管 —— `h2:lang(zh)` 是 0,1,1，
   要赢过 `.dbody article h2` 的 0,1,2 是赢不了的，就算 0,1,2 打平，
   docs.css 后加载还是它赢。`:where()` 把这一条的权重清成 0，
   于是一条最朴素的 `h2:lang(zh)` 就能接管，谁先加载都一样。
   **别把这几行合回上面的块里。**

   字距是唯一压权重的东西：`text-wrap:balance` 必须留在 0,1,2 那边，
   因为本文件上头还有一条 `.docs h1,…{text-wrap:pretty}`（0,1,1），
   压到 0,0,1 会被它盖掉，中文标题就又断回不匀的两行了。 */
:where(.dbody article) h1{letter-spacing:-.5px}
:where(.dbody article) h2{letter-spacing:-.4px}
:where(.dbody article) h3{letter-spacing:-.25px}
:where(.dbody article) h4{letter-spacing:-.2px}
/* 吸顶条 48px：锚点跳过去时别把标题压在它底下。app.css 已经给了
   scroll-padding-top，这里再补一点呼吸。 */
.dbody article :is(h1,h2,h3,h4){scroll-margin-top:64px}
.dbody article>*:first-child{margin-top:0}
.dbody article p{margin:0 0 14px}
.dbody article ul,.dbody article ol{margin:0 0 14px;padding-left:24px}
.dbody article li{margin:0 0 5px}
.dbody article li>ul,.dbody article li>ol{margin:5px 0 0}
.dbody article strong{font-weight:600}
.dbody article hr{border:0;border-top:1px solid var(--hairline);margin:38px 0}

/* 只有一种语言的那种文章，另一种语言下顶上的一句说明。
   现在十三篇都翻了，这条留给以后新加的文章。 */
.dbody article .only{
  margin:0 0 20px;padding:9px 14px;border-radius:8px;
  background:var(--canvas-2);color:var(--ink-2);font-size:14px;
}

/* 引用块：一条竖发丝线，没有底色、没有斜体。 */
.dbody article blockquote{
  margin:0 0 14px;padding:2px 0 2px 16px;
  border-left:2px solid var(--hairline);color:var(--ink-2);
}
.dbody article blockquote>*:last-child{margin-bottom:0}

/* 代码。不上语法高亮：这些正文里的命令是要照抄去跑的，
   多一套颜色只会多一个跟「蓝色 = 可点」打架的信号。 */
.dbody article code{
  font-family:var(--mono);font-size:.87em;letter-spacing:0;
  background:var(--canvas-2);border-radius:8px;padding:.12em .38em;
  font-variant-ligatures:none;font-feature-settings:"liga" 0,"calt" 0;
}
.dbody article pre{
  margin:0 0 16px;padding:14px 16px;background:var(--canvas-2);border-radius:8px;
  overflow-x:auto;
}
.dbody article pre code{
  background:none;padding:0;border-radius:0;font-size:13.5px;line-height:1.62;
  display:block;white-space:pre;
}

/* 表格：全边框 + 灰表头。宽表在自己的盒子里横滚，页面不滚。
   「右边还有」那道遮罩挂在窄屏那一档里（见 .tw.more），桌面上有滚动条替它说话。 */
.tw{overflow-x:auto;margin:0 0 16px}
.dbody article table{border-collapse:collapse;font-size:14px;line-height:1.5}
.dbody article th,.dbody article td{
  border:1px solid var(--hairline);padding:8px 12px;text-align:left;vertical-align:top;
}
.dbody article thead th{background:var(--canvas-2);font-weight:600;white-space:nowrap}
.dbody article td code,.dbody article th code{white-space:nowrap}

/* ── 上一篇 / 下一篇 ───────────────────────────────────────────────── */
.pager{
  display:flex;gap:16px;margin-top:52px;padding-top:22px;
  border-top:1px solid var(--hairline);
}
.pager a{
  flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:3px;
  padding:12px 14px;border-radius:8px;color:var(--ink);
}
.pager a:hover{background:var(--canvas-2);text-decoration:none}
.pager .n-side{margin-left:auto;text-align:right;align-items:flex-end}
.pager .k{font-size:12px;color:var(--ink-2);letter-spacing:.04em;text-transform:uppercase}
.pager .n{font-size:15px;color:var(--blue)}

/* ── 目录页 ────────────────────────────────────────────────────────── */
.dindex{padding:56px var(--pad) 76px}
/* 字距按本文件上头那条约定压到 0,0,1，好让 app.css 的 `h1:lang(zh)` 接管；
   字号留在 0,1,1，它跟语言无关。 */
.dindex h1{font-size:clamp(32px,4vw,44px)}
:where(.dindex) h1{letter-spacing:-.4px}
.dindex .lead{margin:14px 0 0;max-width:56ch;font-size:18px}
/* 六个分组落成 3×2 而不是 4+2：四栏那版第二行只填了两格，右半边空着，
   看起来像少了两组东西。三栏两行是满的。
   `min(330px,100%)` 而不是裸的 330px：auto-fit 的轨道**不会**缩到 minmax 的
   下限以下，所以 320px 的手机上（正文可用 276）这一格仍旧要 330，页面装不下，
   Chrome 于是把布局视口撑到 352 —— 整页按 352 排版再缩着显示，标题和链接一起
   被右边缘切掉。加了 min() 之后下限跟着容器走，330 只在放得下的时候才生效。 */
.dindex .cols{
  display:grid;gap:26px 48px;margin-top:46px;
  grid-template-columns:repeat(auto-fit,minmax(min(330px,100%),1fr));
}
.dindex .g h2{
  margin:22px 0 9px;font-size:12px;font-weight:600;color:var(--ink-2);
  letter-spacing:.04em;text-transform:uppercase;line-height:1.4;
}
.dindex .g ul{margin:0;padding:0;list-style:none;font-size:15px}
.dindex .g li{margin:0 0 6px}
.dindex .g a{color:var(--ink)}
.dindex .g a:hover{color:var(--blue);text-decoration:none}

/* ── 窄屏：一栏 + 抽屉 ─────────────────────────────────────────────
   本页目录整块退场 —— 它是给有富余宽度的屏幕用的旁注，
   在一栏里它只是把同一批标题在正文上方再念一遍。

   分组导航以前是顶部一个 `<details>`：展开就把十三条目录顶在正文前面，
   「菜单和内容挤在同一屏」—— 门户上被甲方否掉的同一个毛病（issue #26）。
   现在它是一块覆盖层：正文一步都不动，选完一篇就退场。 */
@media (max-width:1099px){
  .dpage,.dpage.no-toc{grid-template-columns:minmax(0,1fr)}
  .dtoc{display:none}
  /* 本页目录退场之后没有东西接手它那一栏，于是 1024 下正文拿到整整 942px ——
     实测一行 118 个字符，而 DESIGN.md §9 给文档定的是 70 上下。没有目录的文章
     （.no-toc）本来就封在 78ch，同一个站于是在同一个宽度上有两种行长。
     封顶挪到 .dbody 自己身上，两种文章从此同一条规矩；手机上正文本来就不到
     78ch，这一条在那里不生效。 */
  .dbody{padding:22px 0 56px;max-width:78ch}
  .dpage.no-toc .dbody{padding-right:0}
  .dbody article h1{font-size:clamp(27px,6vw,34px)}
  .dbody article h2{font-size:21px;margin-top:36px}

  /* .87em 是相对正文的，正文 16 给出 13.9px。但表格的正文是 14px，同一条规则
     在单元格里落到 12.18px —— 而单元格里的等宽字全是环境变量名和参数，是这一页
     最需要被逐字符读准的东西。13px 的地板只加在窄屏这一档：桌面 1440 是全站
     唯一冻着的一档，而这条缺陷是在手机上量到的。 */
  .dbody article code{font-size:max(13px,.87em)}

  /* 命令里以 - 开头的那一节不许在自己的横杠后面断行。浏览器默认允许在连字符后
     断开，于是 `--transport` 在中文段落里被切成 `--` 和 `transport`，读起来是
     两个参数 —— HANDOFF §3.5 和 §3.11 在官网上修过两次的同一个坑。正文由
     markdown 生成，包不进 span，所以由 docs.js 在加载时包；这一条决定它什么
     宽度上生效。长标识符（release-public.pem 那种）照旧可以在自己的连字符处
     断开，那种断法本来就读得通。 */
  .dbody article code .tok{white-space:nowrap}

  /* 「右边还有」这个信号。手机上没有常驻滚动条可以指望（实测：移动端模拟下
     scrollbar-width 无论怎么写都是覆盖式的），而表格被切在两条发丝线之间的
     单元格中间，看着不像「还能滚」，看着像坏了 —— 390 下 environment 那张
     1175px 的表只露得出 346px。用的是跟安装胶囊同一件东西：一道 24px 的遮罩
     把末端擦成透明，露出页面自己的白，不铺任何一层新颜色（DESIGN.md §8 禁的
     是装饰性渐变）。`.more` 由 docs.js 按真实的 scrollLeft 挂上，滚到底就摘掉
     —— 一道永远亮着的淡出在滚到头之后就是在撒谎。 */
  .tw.more{
    -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 24px),transparent);
            mask-image:linear-gradient(90deg,#000 calc(100% - 24px),transparent);
  }

  /* 没有脚本时到此为止：导航还是正文上面那一整份清单，跟以前一样能用。
     下面每一条都挂在 `.js` 上，抽屉是脚本兑现得起的那部分。 */
  /* 「文档」那个标签跟官网的链接一样加 6px 的透明内边距凑够 40 的按压面，
     等量的负外边距钉住左缘 —— 它左边就是字标，墨迹落点不动。 */
  .docs .nav .here{padding:0 6px;margin-left:-6px}

  .dnav{
    position:static;max-height:none;overflow:visible;
    border-right:0;border-bottom:1px solid var(--hairline);padding:0 0 4px;
  }
  .dnav-in{padding-bottom:16px}

  /* 触发钮站在正文最上面，长得就是以前那条 summary —— 关着的时候
     这一屏跟以前逐像素一样，变的只是点下去之后发生什么。 */
  .js .dnav-open{
    display:flex;align-items:center;gap:7px;width:100%;
    padding:14px 0;border:0;background:none;cursor:pointer;
    font:inherit;font-size:14px;color:var(--ink-2);text-align:left;
    border-bottom:1px solid var(--hairline);
  }
  /* 角标：一个朝下的角，跟以前那条 summary 上的是同一笔，不是图标库。 */
  .js .dnav-open::after{
    content:"";width:6px;height:6px;flex:none;
    border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
    transform:rotate(45deg) translate(-2px,-2px);
  }
  .js .dnav-open:hover{color:var(--ink)}

  /* 遮罩。黑不是新颜色，是 --ink 压到三成 —— 它在这儿的职责是让底下那页
     退后，不是自己成为一个色块。 */
  .js .dscrim{
    display:block;position:fixed;inset:0;z-index:6;
    background:rgba(29,29,31,.34);
    opacity:0;pointer-events:none;transition:opacity .24s var(--ease);
  }
  .js.dnav-on .dscrim{opacity:1;pointer-events:auto}

  /* 抽屉本体：从左边滑进来，盖住顶栏 —— 它是这一刻屏幕上唯一的事。
     关着的时候 `visibility:hidden` 把里面十三个链接一起从 tab 序里拿掉，
     不用再写一行 JS 去 inert 它们。 */
  .js .dnav{
    position:fixed;inset:0 auto 0 0;z-index:7;
    width:min(320px,86vw);max-width:100%;
    padding:0 22px 28px;border:0;
    background:var(--canvas);border-right:1px solid var(--hairline);
    overflow-y:auto;overscroll-behavior:contain;
    transform:translateX(-100%);visibility:hidden;
    transition:transform .26s var(--ease),visibility .26s var(--ease);
  }
  .js.dnav-on .dnav{transform:none;visibility:visible}

  /* 抽屉自己的标题行：一个「全部文档」加一个叉。 */
  .js .dnav-head{
    display:flex;align-items:center;justify-content:space-between;gap:12px;
    position:sticky;top:0;z-index:1;margin:0 -22px 6px;padding:13px 22px;
    background:var(--canvas);border-bottom:1px solid var(--hairline);
    font-size:14px;color:var(--ink-2);
  }
  /* 叉也是画出来的：两笔发丝，跟角标同一套手法。
     40×40 而不是 34×34：它是抽屉里唯一的关闭键，34 够不着。那两笔的位置跟着
     盒子重算，画出来的叉一个像素没变。 */
  .js .dnav-close{
    position:relative;flex:none;width:40px;height:40px;margin-right:-12px;
    border:0;border-radius:8px;background:none;cursor:pointer;color:var(--ink-2);
  }
  .js .dnav-close::before,.js .dnav-close::after{
    content:"";position:absolute;left:14px;top:19px;width:12px;height:1.5px;
    background:currentColor;
  }
  .js .dnav-close::before{transform:rotate(45deg)}
  .js .dnav-close::after{transform:rotate(-45deg)}
  .js .dnav-close:hover{color:var(--ink);background:var(--canvas-2)}

  .js .dnav .g:first-child{margin-top:16px}
  /* 抽屉里的十三条是手机上进文章的唯一入口，一条 31px 高、彼此不留缝，
     点错一条就是读错一篇。内边距 5 → 10 让每条 41px 高，抽屉本来就在滚。 */
  .js .dnav li a{margin-left:-10px;padding:10px}

  /* 目录页那六组链接同理：18~19px 高、行距 6px，是这一页仅有的内容。
     做成块级并给上下 11px 的内边距，行距归零，节距从 24 变成 41。
     只在这个断点里改，桌面那一档（鼠标）保持原样。 */
  .dindex .g ul{line-height:1.4}
  .dindex .g li{margin:0}
  .dindex .g a{display:block;padding:11px 0}

  /* 抽屉开着时页面不滚。两个元素都写：iOS Safari 只认 body 上那一条。
     这一条留在窄屏断点里 —— 抽屉开着时把窗口拉宽，抽屉本身随断点退场，
     锁要是留在外头，桌面那一版就再也滚不动了。 */
  html.dnav-on,html.dnav-on body{overflow:hidden}
}

/* 动效是这里唯一一处动的东西，关掉它抽屉照样能用。 */
@media (prefers-reduced-motion:reduce){
  .js .dnav,.js .dscrim{transition:none}
}

@media (max-width:640px){
  .pager{flex-direction:column;gap:8px}
  .pager .n-side{margin-left:0;text-align:left;align-items:flex-start}
  /* 13 而不是 12.5：这些是要照抄去跑的命令，13px 是这一版给正文定的地板。
     多出来的半个像素让最长的那条多滚 4%，代价比读错一个字符小。 */
  .dbody article pre code{font-size:13px}
  /* 面包屑在这个宽度上一定会换行，标题那一节自己占一行。
     那道斜杠于是吊在上一行的行尾，指着一片空白 —— 关掉它。
     字号留在 13（默认值）：这一行说的是「你在站里的哪儿」，是内容不是标签。 */
  .crumbs>*:nth-last-child(2)::after{content:none}
  .dindex{padding-top:38px}
}
