/* 木纹印记 · 公开作品集
   配色沿用后台视觉变量（--paper/--wood/--ink/--accent），布局类全部新写：
   后台的 .panel/.tabbar 绑定控制台结构，不可复用。 */

:root {
    --paper: #f6f0e4;
    --paper-2: #fdf8ee;
    --wood: #b08a52;
    --wood-mid: #c19a63;
    --wood-dark: #8b6b43;
    --ink: #4a3a2c;
    --muted: #9a8b76;
    --accent: #cf5139;
    --line: #e7dcc6;
    --shadow: rgba(120, 90, 50, 0.14);
    --radius-lg: 18px;
    --radius-md: 14px;
    --radius-sm: 10px;
    /* 诗句用衬线体，与正文无衬线拉开层次 */
    --serif: "Songti SC", "STSong", "SimSun", "Noto Serif CJK SC", serif;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* 平滑滚动目前只有「回到顶部」一个触发者（页内没有锚点链接）。
   开了「减少动态效果」的人不该被一段长距离滑动晃到，直接瞬移。 */
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
}

body {
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
    background: var(--paper);
    color: var(--ink);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

/* ============ 页头 ============ */
.hero {
    position: relative;
    padding: 26px 20px 24px;
    background:
        linear-gradient(180deg, rgba(176, 138, 82, 0.10), rgba(176, 138, 82, 0) 70%),
        var(--paper);
    border-bottom: 1px solid var(--line);
    overflow: hidden;
}
/* 这里原本有一道 4px 的「木纹压条」(.hero::before)，已删（2026-09-21）。
   它是纯装饰，但占的是**页面最顶端那一行** —— 在浏览器里紧贴地址栏，
   看着就像一条不知从哪来的粗边框，用户报「网址栏和网站之间有根粗线」。
   木色在页头和卡片上已经够多了，不缺这一笔。别再往回加。 */
/* 页头一律「头像+文字 | 二维码」横排。
   竖排（头像居中、二维码在下）更气派，但要吃掉约 500px 首屏——
   读者得划过整个窗口才见得到第一张卡片，作品集不该这样开场。 */
.hero-inner {
    max-width: 1180px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 28px;
}
.hero-id { display: flex; align-items: center; gap: 16px; min-width: 0; }
.hero-text { min-width: 0; text-align: left; }

/* 页头主图＝公众号头像。二维码别放这儿：它是块方正饱满、要够大才扫得动的图，
   跟墨圈抢重心，摆左边、摆右边、顶掉头像都试过，怎么调都别扭。
   分工改成「开头认人、结尾关注」——二维码挪去页脚当收尾（见 footer .foot-qr）。 */
.hero-avatar {
    /* 头像原图是「白底 + 居中墨圈」，实测 272px 图里墨圈 bbox 约 212×192，
       只占边长 78%。外层裁圆、内层放大 1.28 倍切掉白边，
       于是「盒子多大墨圈就多大」，尺寸数字所见即所得。 */
    width: 76px; height: 76px;
    flex: 0 0 auto;
    border-radius: 50%;
    overflow: hidden;
    border: 3px solid var(--paper-2);
    box-shadow: 0 4px 18px var(--shadow);
    background: var(--paper-2);
}
.hero-avatar img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
    transform: scale(1.28);
}
.hero-name {
    margin: 0 0 4px;
    font-size: 23px;
    font-weight: 600;
    letter-spacing: 3px;
    color: var(--wood-dark);
}
.hero-sign {
    margin: 0;
    font-family: var(--serif);
    font-size: 15px;
    color: var(--ink);
    letter-spacing: 1px;
}
.hero-stat {
    margin: 7px 0 0;
    font-size: 12px;
    color: var(--muted);
    letter-spacing: 1px;
}
/* 微信号：页头不放二维码之后的「关注入口」。比签名再轻一档，只是备查信息 */
.hero-id {
    margin: 4px 0 0;
    font-size: 11.5px;
    color: var(--muted);
    letter-spacing: .5px;
    opacity: .85;
}
.hero-id:empty { display: none; }


/* 窄屏只收尺寸，横排结构不动。
   必须放在上面所有 .hero-* 基础规则**之后** —— media query 不提升优先级，
   写在前面会被后面的同名规则整段盖掉（踩过）。 */
@media (max-width: 760px) {
    .hero { padding: 18px 16px 16px; }
    .hero-inner { gap: 14px; }
    .hero-id { flex: 1 1 auto; gap: 12px; }
    .hero-avatar { width: 54px; height: 54px; border-width: 2px; }
    .hero-name { margin: 0 0 3px; font-size: 20px; letter-spacing: 2px; }
    .hero-sign { font-size: 13.5px; letter-spacing: 0; }
    .hero-stat { margin-top: 5px; font-size: 11.5px; letter-spacing: 0; }
    .hero-id { margin-top: 2px; font-size: 11px; }
    footer .foot-qr { margin-bottom: 16px; }
    footer .foot-qr img { width: 88px; height: 88px; padding: 4px; }
}

/* ============ 筛选栏 ============ */
.filters {
    position: sticky;
    top: 0;
    z-index: 20;
    padding: 14px 20px 10px;
    background: rgba(246, 240, 228, 0.94);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--line);
    transition: transform .28s cubic-bezier(.2, .7, .3, 1);
}
.search-wrap { max-width: 1180px; margin: 0 auto 10px; }
#search {
    width: 100%;
    padding: 11px 16px;
    font-size: 15px;
    font-family: inherit;
    color: var(--ink);
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: 999px;
    outline: none;
    transition: border-color .2s, box-shadow .2s;
}
#search:focus {
    border-color: var(--wood);
    box-shadow: 0 0 0 3px rgba(176, 138, 82, 0.14);
}
#search::placeholder { color: var(--muted); }

/* 一组筛选芯片：换行排布，超过两行就折起来，末尾给一个「展开」。
   三组（年份/栏目/作者）走同一套 —— 之前作者组用横滚，桌面端会拖出一条灰滚动条，
   跟旁边换行的两组也不是一个风格。折到第几行、要不要出按钮，由内联脚本按真实行高算。 */
.cg { max-width: 1180px; margin: 0 auto 8px; }
.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
}
.cg.is-folded .chips { overflow: hidden; }   /* max-height 由 JS 设 */
/* 展开后得有个上限：手机上任一组展开都可能比屏幕还高
   （作者 107 位，实测筛选栏会涨到视口 134%），那就把整块屏吃掉了。
   超出的部分在组内滚，不动页面。 */
.cg.is-open .chips { max-height: 52vh; overflow-y: auto; }
.cg-more {
    display: block;
    margin: 6px 0 0 auto;   /* 右对齐，像「查看更多」 */
    padding: 0;
    font-family: inherit;
    font-size: 12.5px;
    color: var(--wood-dark);
    background: none;
    border: 0;
    cursor: pointer;
}
.cg-more:hover { text-decoration: underline; }
.cg-more::after { content: " ▾"; }
.cg.is-open .cg-more::after { content: " ▴"; }
/* 类选择器会盖掉浏览器默认的 [hidden]{display:none}，得自己写一条 */
.cg-more[hidden] { display: none; }

.chip {
    padding: 4px 13px;
    font-size: 13px;
    font-family: inherit;
    color: var(--muted);
    background: transparent;
    border: 1px solid var(--line);
    border-radius: 999px;
    cursor: pointer;
    transition: all .18s;
    white-space: nowrap;
}.chip:hover { color: var(--wood-dark); border-color: var(--wood-mid); }
.chip.is-on {
    color: var(--paper-2);
    background: var(--wood);
    border-color: var(--wood);
}

/* 「转载」标记。作者名**不动** —— 探的是「这不是本刊原创」，不是「换了个人」。
   压在名字后面而不是单独占一格：卡片元信息行本来就挤（作者名自己还会省略号
   截断），多一个独立元素会把日期挤没。 */
.rp {
    margin-left: 4px;
    padding: 0 4px;
    font-size: 10px;
    font-style: normal;
    line-height: 1.6;
    vertical-align: 1px;
    color: var(--muted);
    border: 1px solid var(--line);
    border-radius: 3px;
}
/* 选中的芯片底色是木色、文字是浅色木纸色，标记得跟着翻过来，否则糊成一片 */
.chip.is-on .rp {
    color: var(--paper-2);
    border-color: rgba(253, 248, 238, .5);
    opacity: .75;
}

/* 手机上往下滑时把筛选栏收走，往上滑再放出来（滚动逻辑在 template.html 的内联脚本里）。
   用 transform 而不是 height/max-height：位移不触发重排，卡片不会跟着跳（CLS 不受影响）；
   sticky 元素是贴顶浮着的，滑走时下面也不留空档。滚回顶部必露出，见脚本。
   只在小屏生效 —— 桌面屏高够，筛选栏并不挡事，没必要动。 */
@media (max-width: 760px) {
    .filters.is-hidden { transform: translateY(-100%); }
}
@media (prefers-reduced-motion: reduce) {
    .filters { transition: none; }
}

/* ============ 卡片墙 ============ */
main { max-width: 1180px; margin: 0 auto; padding: 26px 20px 60px; }

.wall {
    /* 多列瀑布流：图文卡与文字卡高度天然不同，交错排布形成节奏 */
    column-count: 4;
    column-gap: 18px;
}
@media (max-width: 1080px) { .wall { column-count: 3; } }
@media (max-width: 760px)  { .wall { column-count: 2; column-gap: 12px; } }
@media (max-width: 460px)  { .wall { column-count: 1; } }

.card {
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
    page-break-inside: avoid;
    margin: 0 0 18px;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    overflow: hidden;
    box-shadow: 0 1px 3px var(--shadow);
    transition: transform .28s cubic-bezier(.2, .7, .3, 1), box-shadow .28s;
    /* 1148 张卡片：离屏的跳过 layout/paint，实际开销约等于视口内那十几张。
       实测把 LCP 从 476ms 降到 264ms，且不引起布局位移（封面有 aspect-ratio 占位）。 */
    content-visibility: auto;
    contain-intrinsic-size: auto 380px;
}
@media (max-width: 760px) { .card { margin-bottom: 12px; } }

.card > a { display: block; }

.card:hover {
    transform: translateY(-5px);
    box-shadow: 0 12px 26px var(--shadow);
}
.card:focus-within {
    outline: 2px solid var(--wood-mid);
    outline-offset: 2px;
}

/* 封面：固定比例占位，图未到时不留白跳（CLS=0） */
.card .cv {
    aspect-ratio: 4 / 3;
    overflow: hidden;
    background: linear-gradient(135deg, rgba(176,138,82,.14), rgba(176,138,82,.05));
}
.card .cv img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
    transition: transform .5s cubic-bezier(.2, .7, .3, 1);
}
.card:hover .cv img { transform: scale(1.045); }

.card .bd { padding: 13px 15px 15px; }

.card .t {
    margin: 0 0 7px;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.45;
    color: var(--ink);
    /* 少数文章标题本身就是整首诗（含换行），必须截断，避免一张卡占满整屏 */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.card .d {
    margin: 0;
    font-family: var(--serif);
    font-size: 13.5px;
    line-height: 1.75;
    color: #6d5c49;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.card .m {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 11px;
    font-size: 11.5px;
    color: var(--muted);
    letter-spacing: .5px;
}
.card .m .c {
    padding: 1px 8px;
    color: var(--wood-dark);
    background: rgba(176, 138, 82, .13);
    border-radius: 999px;
}
/* 作者名可能很长（「爱吃糖的小橘子」），让步给日期、超出省略 */
.card .m .a {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.card .m .c,
.card .m time { flex: 0 0 auto; }
.card .m time { margin-left: auto; }

/* —— 文字卡：无真封面（微信只给了头像，或本就没有）——
   不摆灰框，改用木纹纸底 + 放大诗句，让文字本身成为视觉重心。 */
.card--text {
    background:
        linear-gradient(160deg, rgba(176, 138, 82, .09), rgba(253, 248, 238, 0) 60%),
        var(--paper-2);
}
.card--text .bd { padding: 22px 18px 18px; }
.card--text .d {
    font-size: 15.5px;
    line-height: 1.95;
    color: var(--ink);
    -webkit-line-clamp: 6;
    line-clamp: 6;
    margin-bottom: 12px;
}
.card--text .t {
    font-size: 14px;
    font-weight: 500;
    color: var(--wood-dark);
    -webkit-line-clamp: 2;
    line-clamp: 2;
}
/* 既无封面又无摘要：只剩标题，居中留白，避免显得残缺 */
.card--bare .bd {
    padding: 34px 18px;
    text-align: center;
}
.card--bare .t {
    font-family: var(--serif);
    font-size: 17px;
    font-weight: 500;
    color: var(--ink);
    letter-spacing: 1px;
}

/* ============ 滚动淡入（渐进增强）============ */
/* 默认可见；只有 JS 正常执行（html.js）才隐藏待淡入，避免 JS 出错导致全站白屏 */
.js .card {
    opacity: 0;
    transform: translateY(10px);
}
.js .card.in {
    opacity: 1;
    transform: none;
    transition: opacity .5s ease, transform .5s cubic-bezier(.2, .7, .3, 1);
}
@media (prefers-reduced-motion: reduce) {
    .js .card { opacity: 1; transform: none; }
    .card, .card .cv img { transition: none; }
}

/* ============ 其他 ============ */
.empty {
    padding: 60px 0;
    text-align: center;
    color: var(--muted);
    font-family: var(--serif);
    font-size: 16px;
}

footer {
    padding: 34px 20px 46px;
    text-align: center;
    color: var(--muted);
    font-size: 13px;
    border-top: 1px solid var(--line);
    background: var(--paper-2);
}
footer p { margin: 0 0 6px; }
/* 页脚的二维码：桌面读者扫它关注，手机读者在微信里本来就能直接关注，
   所以放在收尾处、尺寸克制 —— 它的职责是「兜底入口」，不是页头的主角。 */
footer .foot-qr { margin: 0 0 20px; }
footer .foot-qr img {
    width: 104px; height: 104px;
    display: inline-block;
    border-radius: var(--radius-sm);
    background: #fff;
    padding: 5px;
    box-shadow: 0 3px 14px var(--shadow);
}
footer .foot-qr p {
    margin: 7px 0 0;
    font-size: 12px;
    color: var(--muted);
    letter-spacing: 2px;
}
footer .foot-dim { font-size: 12px; opacity: .78; }
footer .beian { margin-top: 14px; font-size: 12px; }
footer .beian a { color: var(--muted); border-bottom: 1px solid var(--line); }
footer .beian a:hover { color: var(--wood-dark); }

/* ============ 回到顶部 ============ */
/* 固定在右下角，翻过一屏半才出现（时机在 template.html 的内联脚本里）。
   用 opacity + visibility 而不是 display：不进布局、不触发重排，
   淡入淡出也比「啪」地冒出来安静。visibility 是离散过渡，显示时立刻可见、
   隐藏时等淡出结束才生效 —— 正好；顺带保证隐藏期间不可点、不进 Tab 序。 */
.to-top {
    position: fixed;
    right: 20px;
    bottom: calc(20px + env(safe-area-inset-bottom, 0px));   /* 让开 iPhone 底部横条 */
    z-index: 15;                /* 低于筛选栏(20)：筛选栏展开时铺满屏，按钮该让位 */
    width: 44px; height: 44px;  /* 触控目标不小于 44px */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    color: var(--wood-dark);
    background: rgba(253, 248, 238, .92);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid var(--line);
    border-radius: 50%;
    box-shadow: 0 3px 14px var(--shadow);
    cursor: pointer;
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    transition: opacity .24s, transform .24s, visibility .24s, color .18s, border-color .18s;
}
.to-top.is-on { opacity: 1; visibility: visible; transform: none; }
/* :active 必须写在 .is-on 之后 —— 同优先级(0,2,0)，靠源码顺序取胜 */
.to-top:hover { color: var(--accent); border-color: var(--wood-mid); }
.to-top:active { transform: scale(.94); }

@media (max-width: 760px) {
    .to-top { right: 14px; bottom: calc(14px + env(safe-area-inset-bottom, 0px)); }
}
@media (prefers-reduced-motion: reduce) {
    .to-top { transition: none; }
}

/* ============ 卡片：站内入口（V2b）============
   整卡原本是一个 <a>，而 <a> 不能嵌套 —— 元信息行里要塞第二个链接，就得把
   「元信息行」从那个 <a> 里搬出来，让它自己带内边距（原来是 .bd 给的）。
   搬出来之后行为**完全不变**：作者名/栏目/日期仍然跳微信（各自包在 .m-hit 里），
   只有 .insite-link 例外。没有正文的篇目不输出 .insite-link，结构回落到原样。 */
.mwrap { padding: 0 15px 15px; }
.mwrap .m { margin-top: 0; }
.m-hit {
    display: flex; align-items: center; gap: 8px;
    flex: 1 1 auto; min-width: 0;          /* min-width:0 才能让长作者名省略号生效 */
    color: inherit; text-decoration: none;
}
.m-hit time { margin-left: auto; }
/* 虚线边框是为了跟实心的栏目 chip 区分：这是个「站内的」入口，不是分类标签 */
.insite-link {
    flex: 0 0 auto;
    padding: 1px 8px;
    border-radius: 999px;
    color: var(--wood-dark);
    border: 1px dashed rgba(176, 138, 82, .55);
    text-decoration: none;
    white-space: nowrap;
    transition: border-style .2s, background .2s;
}
.insite-link:hover { border-style: solid; background: rgba(176, 138, 82, .13); }

/* ============ 文章独立页 /p/{slug}/ ============ */
/* 页头在文章页里是 <a>（要能回首页），而首页是 <h1>；块级得补回来，否则
   下边距失效、标题跟签名挤在一行。 */
a.hero-name { display: block; }

.art { max-width: 720px; margin: 0 auto; padding: 26px 20px 60px; }
.crumb { margin: 0 0 20px; font-size: 13px; color: var(--muted); }
.crumb a:hover { color: var(--wood-dark); }

.art-title {
    margin: 0 0 10px;
    font-family: var(--serif);          /* 与卡片墙的标题观感一致 */
    font-size: 25px;
    font-weight: 600;
    line-height: 1.5;
    letter-spacing: 1px;
    color: var(--ink);
}
.art-meta { margin: 0 0 28px; font-size: 12.5px; color: var(--muted); letter-spacing: .5px; }
.art-meta .c {
    margin: 0 6px;
    padding: 1px 8px;
    color: var(--wood-dark);
    background: rgba(176, 138, 82, .13);
    border-radius: 999px;
}

/* —— 正文 ——
   微信正文是「一行一个 <p>」，换行信息在标签边界里、不在文本里，所以**不能**用
   white-space:pre-line 去还原换行：清洗后文本节点里还剩着从源 HTML 带下来的缩进空白，
   pre-* 会把它如实画出来，诗句前会出现忽宽忽窄的空隙。块级 <p> 本来就换行，
   行距交给 line-height 就够。
   段间距取 .45em 而不是常见的 1em：诗是一行一段，1em 会让每一行看着都像独立段落，
   节奏就散了。缩进由 white-space:pre 冻成的 NBSP 自己带（见 fetch_bodies.py）。 */
.art-body { font-size: 16.5px; line-height: 2.05; color: #3f3225; }
.art-body p { margin: 0 0 .45em; }
.art-body strong, .art-body b { font-weight: 600; color: var(--ink); }
.art-body blockquote {
    margin: 1.3em 0;
    padding: 2px 0 2px 14px;
    border-left: 3px solid var(--line);
    font-family: var(--serif);
    color: #6d5c49;
}
.art-body h1, .art-body h2, .art-body h3, .art-body h4 {
    margin: 1.6em 0 .6em;
    font-size: 17px;
    letter-spacing: 1px;
    color: var(--wood-dark);
}
.art-body ul, .art-body ol { margin: .8em 0; padding-left: 1.6em; }
/* 背景是渐变而不是灰块：图未到时不留白洞（正文图没有固定尺寸可用，CLS 防不了，
   但至少别闪一下白）。圆角跟卡片墙的 --radius-sm 对齐。 */
.art-body img {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 1.3em auto;
    border-radius: var(--radius-sm);
    background: linear-gradient(135deg, rgba(176, 138, 82, .14), rgba(176, 138, 82, .05));
}

.art-acts { display: flex; flex-wrap: wrap; gap: 10px; margin: 36px 0 0; }
.act {
    padding: 9px 18px;
    font-size: 14px;
    color: var(--wood-dark);
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: 999px;
    transition: all .18s;
}
.act:hover { border-color: var(--wood-mid); color: var(--accent); }
.act--src { color: var(--paper-2); background: var(--wood); border-color: var(--wood); }
.act--src:hover { color: var(--paper-2); }

@media (max-width: 760px) {
    .art { padding: 18px 16px 46px; }
    .art-title { font-size: 21px; }
    .art-body { font-size: 16px; line-height: 2; }
}

/* 键盘可达性 */
:focus-visible { outline: 2px solid var(--wood-mid); outline-offset: 2px; }
