/* 页面骨架有两栏可折叠的侧栏,都由本文件管:
 *   - 左栏 `<toc-component>`(全站目录,toc.js 定义的 web component)
 *   - 右栏 `nav.outline`(本页目录,outline.typ 生成)
 * 顶栏是 `<site-header>`(header.js 抓 lib/header.html 渲染),只占 body
 * grid 的第一行;它内部长什么样是 header.css 的事 —— shadow 边界里外
 * 两侧的样式各管一段,这里只管外壳。
 * 窄屏下两栏都是盖在正文上的抽屉,共用一层遮罩。
 * 分三档,窗口收窄时先收左栏:
 *   <768px       两栏都收起成抽屉;☰ 在顶栏左 / 右两端
 *   768–1079px   右栏恢复成常驻列,左栏仍是抽屉
 *   ≥1080px      两栏都常驻,三列
 * 两档宽屏的**列数是按「面板在不在」算的(`body:has(> .outline)` /
 * `body:has(> toc-component)`),不是按视口 —— 某页把侧栏关了
 * (`template.with(toc: false, …)`),格子就不能还留着。
 * 正文那 600pt 的行宽上限跟着常驻列走:没有常驻侧栏列时不设上限
 * (1fr),铺满整行。 */

/* 左栏。窄屏是抽屉:固定定位、默认推到屏幕外,`.open` 滑进来。
 * 用 transform 而不是 `left` 偏移,因为宽度是 min(85vw, 320px) ——
 * 窄到 85vw < 320px 时按固定 px 值藏不干净,总有一截留在屏内。 */
toc-component {
    display: block;
    position: fixed;
    /* 顶栏是 fixed/sticky 的,盖在正文之上。抽屉从它下沿开始,否则打开时
     * 目录的第一行会被顶栏压住。 */
    top: var(--header-h);
    left: 0;
    /* 高度跟着内容走,上限一屏减去顶栏。满屏白底而目录只占顶上一点时,
     * 底下一大片纯白很扎眼;内容多过一屏才滚。 */
    max-height: calc(100vh - var(--header-h));
    width: min(85vw, 320px);
    background-color: var(--bg);
    box-shadow: 6px 0 24px var(--shadow-drawer);
    transform: translateX(-100%);
    transition: transform 0.3s ease;
    z-index: 1002;
    overflow: hidden auto;

    &.open {
        transform: translateX(0);
    }
}

body {
    background-color: var(--bg);
    min-height: 100vh;
    display: grid;
    /* 窄屏单列:两栏侧栏都是 fixed 抽屉,脱离文档流,grid 里只剩正文。
     * 唯一的正文列不设上限(1fr)。600pt 那个行宽只在侧栏常驻、真有
     * 两个格子并排时才用得上,见下面各档 media query。 */
    grid-template-columns: minmax(0, 1fr);
    /* 两行:第一行给顶栏(它 grid-column: 1 / -1,横跨全部列),第二行放
     * 正文。没有这一行的话顶栏会占掉正文那一格,把它顶到下一行、
     * 或者挤出网格。 */
    grid-template-rows: auto 1fr;
    /* 窄屏只有一列,这个 gap 用不上;宽屏那份在 media query 里自己设。 */
    gap: 16px;
    justify-content: center;
    box-sizing: border-box;
    padding: 0;
    margin: 0;
}

/* 两个抽屉共用的遮罩,由 outline.js 创建。 */
.drawer-overlay {
    position: fixed;
    /* 遮罩的 z-index(1001)比顶栏(1000)高,所以顶栏不会靠层级豁免,只能
     * 靠这块遮罩**不铺到它身上**:从顶栏下沿开始铺,开抽屉时顶栏和它那两颗
     * 按钮照样点得到。 */
    top: var(--header-h);
    left: 0;
    right: 0;
    bottom: 0;
    background-color: var(--overlay);
    z-index: 1001;
    display: none;

    &.open {
        display: block;
    }
}

/* 顶栏的外壳。顶栏本体(`.site-header`)在 `<site-header>` 的 shadow root
 * 里,页面样式表选不到,它的样式全在 header.css。这个自定义元素是宿主,
 * 在 light DOM 里,所以 grid 定位、sticky、z-index 都归这里。
 *
 * grid-row 显式写 1,不靠自动放置。宽屏下 toc-component 从 fixed 变回
 * sticky、重回 grid 流,谁先占掉第 1 行会随导出顺序和 media query 变;
 * 定死行号,顶栏永远在第 1 行,其余项再依次填第 2 行。 */
site-header {
    display: block;
    position: sticky;
    top: 0;
    z-index: 1000;
    grid-row: 1;
    grid-column: 1 / -1;
}

.outline {
    position: fixed;
    padding-inline-start: 3pt;
    font-size: 12pt;
    color: var(--muted);
    font-weight: 600;
    align-self: start;
    box-sizing: border-box;
    overflow: hidden auto;
    padding-left: 20px;
    padding-right: 40px;
    /* 抽屉上下留一圈:目录树的行盒自己是贴边的,不留的话第一条紧顶着
     * 面板上沿、跟右上角的 ✕ 挤在同一行,最后一条也贴着下沿。 */
    padding-top: 12px;
    padding-bottom: 12px;
    max-width: 240pt;

    /* 窄屏下这一栏是盖在正文上的抽屉,必须有实底 —— 否则目录文字和底下
     * 的正文叠在一起,读不了。宽屏下它在 grid 里独占右列,底色与 body
     * 相同,看不出来。宽度也定死:只写 max-width 会按内容撑,条目少的页
     * 抽屉只有 160 多 px,文字被挤成一列。 */
    width: min(85vw, 320px);
    background-color: var(--bg);
    box-shadow: -6px 0 24px var(--shadow-drawer);

    top: var(--header-h);
    /* 同左栏:抽屉高度贴着内容,别撑成一整屏白。 */
    max-height: calc(100vh - var(--header-h));
    right: 0;
    transform: translateX(100%);
    z-index: 1002;
    transition: transform 0.3s ease;

    &.open {
        transform: translateX(0);
    }
}
.outline-close {
    position: sticky;
    float: right;
    top: 0;
    right: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background-color: var(--close-bg);
    border: 1px solid var(--close-border);
    font-size: 18px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}

@media (min-width: 768px) {
    /* 这一档起,列数按「常驻面板实际存在」算,不按视口宽窄 —— 也不按
     * 元素在不在 DOM 里(`toc-component` 在 768–1079 还是抽屉,不占格)。
     * 这一档常驻列只有右栏。 */
    body {
        /* 一个常驻侧栏列都没有的页面(「摆弄」分区是 `template.with(toc:
         * false, with_outline: false)`,另有 toc / header 两个片段页):
         * 正文铺满,不设行宽上限。600pt 是配侧栏用的行宽,没有侧栏就不该
         * 还留着 —— 原来这里无条件写死 minmax(0, 600pt),宽屏下正文被框
         * 在中间 600pt 里,两边白一大片。
         * 窄屏那条基础规则本来就是 1fr,不用管。 */
        grid-template-columns: minmax(0, 1fr);
        column-gap: 50pt;
    }
    /* 右栏(本页目录)常驻时,正文才收进 600pt 的行宽。左栏(全站目录)在
     * ≥1080 那档常驻,同理由下面那条管。 */
    body:has(> .outline) {
        grid-template-columns: minmax(0, 600pt) minmax(0, auto);
    }
    /* 右栏的关闭按钮在它常驻之后就没用了(开关在顶栏的 shadow 里,
     * 由 header.css 自己那份同断点的 media query 管)。
     *
     * 顺带 `p:has(...)` 那两条:历史上 Typst 的 HTML 导出会把按钮包进
     * 一层 `<p>`,`display: none` 掉按钮不够,那层壳还在 grid 流里占一个
     * 格子、顶掉侧栏该在的位置。现在导出的是 body 的直接子元素,规则匹配
     * 不到,留着以防导出行为再变。 */
    .outline-close, p:has(> .outline-close) {
        display: none !important;
    }
    /* 定高一屏 + sticky:不定住的话目录树会把 body 第一行 grid 拉高几千 px,
     * grid 里其它格子(含正文)跟着 stretch,整页被撑高。 */
    .outline {
        position: sticky;
        /* 顶栏 sticky 占着视口顶上 --header-h,这一列从它下面 16px 处开始,
         * 底部同样留 16px,合起来就是原来的 32px / 64px。 */
        top: calc(var(--header-h) + 16px);
        height: calc(100vh - var(--header-h) - 32px);
        /* 基础规则里的 `transform` 是移动端"抽屉藏在屏幕外"的默认位,
         * 常驻列必须清掉。 */
        transform: none;
        /* 基础规则里的定宽和投影都是给移动端抽屉的;宽屏下这一栏是 grid
         * 里的一格,宽度交给 grid,投影会糊在正文边上,都清掉。 */
        width: auto;
        box-shadow: none;
        /* 基础规则里上下那圈留白是给抽屉的:常驻列的 `top` 是
         * calc(var(--header-h) + 16px),这 12px 叠上去会让它比左边目录树
         * 低一大截。 */
        padding-top: 0;
        padding-bottom: 0;
        /* 同理 z-index:抽屉要压在遮罩(z-index:1001)之上才需要它;常驻列
         * 带着它就会盖住遮罩 —— 768–1079 这档左栏还是抽屉,开出来时右边
         * 这一列会亮在遮罩外面,还能点。 */
        z-index: auto;
    }
    /* `.block` 是 Typst 的通用块级包装(`style.css`),`display: flex` 且
     * 没写 `flex-direction` —— 默认 row。正文里它每次只装一个子元素,
     * row 和 column 没差别,所以一直没暴露问题;目录把 535 个 `li` 塞进
     * 同一个 `.block`,row 就把它们全横着挤进 320px,压成一团糊字。
     * 限定在 `.outline` 里改,不去动全局 `.block`(那会影响正文公式)。 */
    .outline .block {
        flex-direction: column;
    }
    /* 全局 reset 的 `line-height` 比字号还小,目录继承了它,16px 的字
     * 被压进很窄的行里、上下互相叠。目录自己重设一个正常行距。 */
    .outline, .outline ul, .outline li {
        line-height: 1.4;
    }
}

@media (min-width: 1080px) {
    /* 左栏也恢复成常驻列。同 768 那档的理由:列数看谁真的在,不看视口。
     * 左栏和右栏各有各的开关(play 页关了两边,别的页可能只关一边),
     * 所以两段分开写,而不是「有 toc 就三列」一把梭。 */
    body:has(> toc-component) {
        grid-template-columns: minmax(auto, 240pt) minmax(0, 600pt);
    }
    body:has(> toc-component):has(> .outline) {
        /* 第一栏 160pt(213px)装不下目录树:树在 `li > .block { width: auto }`
         * 下自然宽度约 289px,右边距折叠按钮(right:0)会被推出可视区,
         * 只能靠 overflow-x: hidden 裁掉。放宽到 240pt。 */
        grid-template-columns: minmax(auto, 240pt) minmax(0, 600pt) minmax(0, auto);
    }
    toc-component {
        position: sticky;
        /* 顶栏也 sticky,占住视口顶上那一截;这一列从它下沿开始,高度相应
         * 扣掉,整列正好铺满余下的一屏。 */
        top: var(--header-h);
        height: calc(100vh - var(--header-h));
        /* 抽屉那套固定宽度 / 实底 / 投影 / 位移在常驻列里都不需要。 */
        width: auto;
        background-color: transparent;
        box-shadow: none;
        transform: none;
        z-index: auto;
    }
    /* 遮罩兜底:这档开不出抽屉,不该出现。 */
    .drawer-overlay {
        display: none !important;
    }
}

.outline a {
    color: inherit;
    text-decoration: none;
}
.outline a:hover {
    text-decoration: underline;
}
.outline li.current > :first-child * {
    color: var(--accent);
}
.outline ul {
    list-style: none;
    padding-inline-start: 12pt;
    display: block;
    margin-block-start: 0;
    margin-block-end: 0;
}
.outline > ul {
    padding-inline-start: 0;
}
