
/* ══ 令牌 ══════════════════════════════════════════════════════════════════ */
:root{
  --paper:#faf9f7; --paper-2:#f3f2ef; --ink:#16161a; --ink-2:#3a3a42;
  --muted:#82828e; --rule:#e2e0db; --rule-2:#eceae5;
  --accent:#c0392b;              /* 朱红：唯一的强调色 */
  /* ⚠️ 双语站点的经典坑：**英文衬线必须排在中文字体之前**。
     中文字体（Songti SC / Noto Serif SC）**自带拉丁字形**，而浏览器是按字符
     逐个回退的——把中文字体写在前面，英文就会全部用宋体的拉丁部分渲染，
     又细又平（实测被吐槽"英文字体丑"就是这个原因）。
     现在：拉丁字符 → Iowan/Palatino/Charter，汉字 → Songti/Noto Serif SC。 */
  --serif:"Iowan Old Style","Palatino Linotype",Palatino,"Book Antiqua",
          Charter,"Bitstream Charter","Sitka Text",Constantia,Cambria,
          Georgia,"Songti SC","Noto Serif SC","Source Han Serif SC",serif;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",
         "Hiragino Sans GB","Microsoft YaHei",sans-serif;
  /* ⚠️ 等宽栈必须补上中文回退。
     ui-monospace / SF Mono / Menlo / Consolas **一个汉字都没有**，
     中文只能漫无目的地回退，且回退到的字体按**等宽栅格**排——
     于是「手工整理 · 持续更新」这种短句字距忽宽忽窄，看着很怪。
     现在：拉丁字符走真等宽（对齐月份、编号、句柄），汉字走正常中文字体。 */
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",
         "PingFang SC","Hiragino Sans GB","Microsoft YaHei",
         "Noto Sans CJK SC","Source Han Sans SC",monospace;
  --pad:clamp(20px,3.2vw,54px);
}
@media (prefers-color-scheme:dark){
  :root{
    --paper:#0d0d0f; --paper-2:#141417; --ink:#f0efe9; --ink-2:#c8c7c0;
    --muted:#8a8a93; --rule:#26262c; --rule-2:#1c1c21;
    --accent:#e0604f;
  }
}
*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--sans);font-size:16px;line-height:1.65;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  /* 新增索引条目后允许自然滚动，避免固定高度截断页脚。 */
  overflow-x:hidden;overflow-y:auto;
}
a{color:inherit;text-decoration:none}
code{font-family:var(--mono);font-size:.86em}

/* 只有真的放不下时才允许滚动（矮窗口 / 窄屏），而不是把内容压扁到看不清 */
@media (max-height:660px),(max-width:820px){
  body{overflow:auto}
  html,body{height:auto;min-height:100%}
}

/* ══ 骨架：一屏三行（页眉 / 主体 / 页脚）═════════════════════════════════ */
.shell{
  min-height:100dvh;height:auto;max-width:1240px;margin:0 auto;padding:0 var(--pad);
  display:grid;grid-template-rows:auto 1fr auto;gap:clamp(14px,2.4vh,32px);
}
@media (max-height:660px),(max-width:820px){ .shell{height:auto;padding-bottom:40px} }

/* ══ 页眉 ══════════════════════════════════════════════════════════════════ */
.top{
  display:flex;align-items:baseline;justify-content:space-between;gap:20px;
  padding:clamp(12px,1.9vh,24px) 0 clamp(9px,1.4vh,16px);
  border-bottom:1px solid var(--rule);
}
.brand{
  font-family:var(--serif);font-size:clamp(19px,1.7vw,23px);
  letter-spacing:.01em;font-weight:600;
}
.brand .seal{
  display:inline-block;width:.5em;height:.5em;background:var(--accent);
  margin-right:.42em;transform:translateY(-.06em);
}
.meta{
  font-family:var(--mono);font-size:11.5px;color:var(--muted);
  letter-spacing:.05em;white-space:nowrap;
}
/* 左上那句格言是**中文文学句子**，既不适用等宽、也不该用 uppercase。
   单列一个类，避免以后又被 .meta 的通用规则带回等宽。 */
.motto{
  font-family:var(--serif);font-size:clamp(12.5px,1.05vw,14.5px);
  color:var(--ink-2);letter-spacing:.02em;
}

/* ══ 主体 ══════════════════════════════════════════════════════════════════ */
main{display:grid;align-content:center;gap:clamp(12px,2.2vh,30px);padding:clamp(4px,1.2vh,16px) 0}

.lede-block{max-width:60ch}
/* 个人主页的主标题是**名字**，不是一句话口号。
   落地页才把价值主张放大；个人主页的主体是人。 */
h1{
  font-family:var(--serif);font-weight:600;
  font-size:clamp(30px,4.4vw,52px);line-height:1.08;
  letter-spacing:-.02em;margin:0 0 .34em;
}
h1 em{font-style:normal;color:var(--accent)}
.sub{
  margin:0;color:var(--ink-2);font-size:clamp(14.5px,1.15vw,16.5px);
  max-width:56ch;line-height:1.72;
}
/* ── 名言：随机轮换 + 逐字显现 + 手动切换 ──────────────────────────────
   ⚠️ 逐字**不能用「写 textContent」实现**。
      那样排版是跟着文字长度实时重算的：行尾还剩空间时 "wor" 停在第一行，
      再多一个字符这个词就装不下，**整词被挤到第二行**——就是"打到行尾突然闪到下一行"。
      占位层只能定住高度，定不住逐字过程中的换行点。

   ✅ 改成：**每个字符一个 <span>，从一开始就全部占位**，只切换透明度。
      排版自始至终就是最终形态，不可能重排、不可能跳词，也不需要占位层。

   字号是**动态**的：基准由 clamp() 给出，脚本在最长句仍超出目标行数时
   按 --q-scale 整体缩小（见 JS 的 tune()）——而不是按最长句定死高度，
   那样短句周围会留一大片空白。 */
.quotes{
  position:relative;
  font-size:calc(clamp(16.5px,1.85vw,23px) * var(--q-scale,1));
  font-family:var(--serif);line-height:1.5;letter-spacing:-.01em;
  padding-right:clamp(30px,3.6vw,46px);
}
.q-text{transition:opacity .42s ease,transform .42s ease}
.q-text.out{opacity:0;transform:translateY(-8px)}

.q-main,.q-sub{display:block;position:relative;white-space:pre-wrap}
.q-main{color:var(--ink)}
.c{opacity:0;position:relative;transition:opacity .07s linear}
.c.on{opacity:1}
/* 光标绝对定位——参与排版的话又会推动换行 */
.c.caret::after{
  content:"";position:absolute;left:100%;top:.06em;width:1px;height:1em;
  background:var(--accent);margin-left:.06em;
  animation:caret 1.15s ease-in-out infinite;
}
@keyframes caret{0%,100%{opacity:1}50%{opacity:.18}}

.q-sub{
  margin-top:.5em;color:var(--muted);font-size:.72em;line-height:1.6;
  opacity:0;transition:opacity .35s ease;
}
.q-sub.on{opacity:1}
/* ⚠️ 没有译文时**必须整块拿掉**，不能只 opacity:0。
   空元素仍然占着 margin-top，会让中文原句和署名之间凭空多出一段间距
   （实测被指出"中文名言离署名有一段距离"就是这个原因）。 */
.q-sub.off{display:none}
.q-by{
  /* 与上方正文拉开一点呼吸：中文句没有译文，署名直接跟在正文后，
     间距太小会挤在一起；双语句里它跟在译文后，同样需要留白。 */
  display:block;margin-top:1.05em;font-family:var(--mono);
  font-size:10.5px;letter-spacing:.05em;color:var(--muted);
  /* 不转大写：CARL SAGAN 这种全大写等宽看着像标签，不像署名 */
  opacity:0;transition:opacity .5s ease;
}
.q-by.show{opacity:1}

/* 手动切换：右下角两个小箭头，**刻意压到 0.28 透明度**，hover 才显出来。
   没有 JS 时按钮没有意义，直接不显示。 */
.q-nav{
  position:absolute;right:0;bottom:0;display:none;gap:2px;
  opacity:.28;transition:opacity .3s ease;
}
.quotes.js-on .q-nav{display:flex}
.quotes:hover .q-nav,.q-nav:focus-within{opacity:.78}
.q-nav button{
  all:unset;cursor:pointer;width:22px;height:22px;display:grid;place-items:center;
  color:var(--ink);font-family:var(--mono);font-size:13px;line-height:1;
  border-radius:5px;transition:background .2s ease,color .2s ease;
}
.q-nav button:hover{background:var(--paper-2);color:var(--accent)}
.q-nav button:focus-visible{outline:1.5px solid var(--accent);outline-offset:1px}

/* 归零必须瞬时：否则旧译文淡出会与新句淡入叠加，表现为灰字"出现→消失→再出现" */
.no-trans .q-sub,.no-trans .q-by,.no-trans .q-text{transition:none!important}

@media (prefers-reduced-motion:reduce){
  .q-text,.q-sub,.q-by,.c{transition:none}
  .c.caret::after{animation:none}
}

/* 一行引导语：比正文更淡，不抢注意力 */
.note{
  margin:.85em 0 0;color:var(--muted);
  font-family:var(--mono);font-size:11.5px;letter-spacing:.05em;
}

/* ══ 分类：索引式条目（不是方框卡片）═══════════════════════════════════
   结构：编号 — EN / 衬线标题 + 小号 EN / 描述 / 细线 / 条目行 / 查看全部
   没有边框、没有阴影、没有图标 —— 层级全靠细线、字号与留白。 */
.cats{display:grid;gap:clamp(18px,3vw,44px);grid-template-columns:1fr}
@media(min-width:768px){ .cats.two{grid-template-columns:1fr 1fr} }
/* ══ 其余分类：简洁卡片网格 ═══════════════════════════════════════════════
   上方两栏的索引式条目**不动**（那是门面）。
   其余分类做成小卡片并排，用 auto-fill —— **新加一个就自动进网格**，
   第 4 个、第 7 个都不会破坏上方的构图。
   minmax 保证窄屏时自动降到 1 列，不用写断点。 */
.more-cards{
  margin-top:clamp(10px,1.6vh,18px);
  display:grid;gap:clamp(10px,1.5vw,16px);
  grid-template-columns:repeat(auto-fill,minmax(min(100%,210px),1fr));
}
.scard{
  display:flex;flex-direction:column;
  padding:11px 14px 10px;background:var(--card);
  border:1px solid var(--line);border-radius:var(--r-m);
  /* 只用颜色与边框表达 hover —— 上方索引条目也是这个语言（颜色变化 + 下划线）。
     加位移会让这一块和整页的"细线排版"脱节。 */
  transition:border-color .24s ease,background .24s ease;
}
.scard:hover{
  border-color:color-mix(in srgb,var(--accent) 34%,var(--line));
  background:var(--card-2);
}
.scard:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.scard .idx{font-family:var(--mono);font-size:10.5px;color:var(--accent);letter-spacing:.1em}
.scard h3{
  font-family:var(--serif);font-weight:600;margin:.3em 0 0;
  font-size:clamp(14.5px,1.25vw,16.5px);letter-spacing:-.01em;line-height:1.28;
}
.scard h3 .en{
  font-family:var(--mono);font-size:.54em;color:var(--muted);
  letter-spacing:.06em;text-transform:uppercase;margin-left:.5em;font-weight:400;
}
/* 项目名与计数并成一行 —— 少一行就少约 30px，一屏能不能放下就看这几行 */
.scard .foot{
  margin:.42em 0 0;display:flex;align-items:baseline;
  justify-content:space-between;gap:.8em;
}
.scard .names{
  color:var(--muted);font-size:12.5px;line-height:1.4;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.scard .go{
  font-family:var(--mono);font-size:10.5px;color:var(--muted);letter-spacing:.04em;
  white-space:nowrap;transition:color .22s ease;
}
.scard:hover .go{color:var(--accent)}
.scard:hover h3{color:var(--accent)}

.cat{
  display:grid;grid-template-rows:auto auto 1fr auto;gap:.55em;
  padding-top:clamp(12px,1.8vh,20px);border-top:1px solid var(--ink);
  transition:opacity .22s ease;
}
.cat .idx{font-family:var(--mono);font-size:11.5px;color:var(--accent);letter-spacing:.1em}
.cat h2{
  font-family:var(--serif);font-weight:600;margin:0;
  font-size:clamp(20px,2.1vw,27px);letter-spacing:-.01em;line-height:1.25;
}
.cat h2 .en{
  font-family:var(--mono);font-size:.5em;color:var(--muted);
  letter-spacing:.06em;text-transform:uppercase;margin-left:.6em;font-weight:400;
}
.cat .desc{margin:0;color:var(--ink-2);font-size:clamp(13.5px,1.05vw,15px);line-height:1.62}
.cat .items{
  margin-top:.5em;padding-top:.7em;border-top:1px solid var(--rule-2);
  display:grid;gap:.45em;
}
.item{
  display:flex;align-items:baseline;justify-content:space-between;gap:14px;
  font-size:clamp(13px,1vw,14.5px);
}
.item .t{color:var(--ink);border-bottom:1px solid transparent;transition:border-color .22s ease}
.item .n{font-family:var(--mono);font-size:11.5px;color:var(--muted);white-space:nowrap}
.item .n.link{color:var(--accent)}
a.cat:hover .item .t{border-bottom-color:var(--accent)}
.cat .more{
  font-family:var(--mono);font-size:11.5px;color:var(--muted);letter-spacing:.04em;
  margin-top:.35em;transition:color .22s ease;
}
a.cat:hover .more{color:var(--accent)}
a.cat:focus-visible{outline:2px solid var(--accent);outline-offset:6px}

/* ══ 页脚 ══════════════════════════════════════════════════════════════════ */
.foot{
  border-top:1px solid var(--rule);
  padding:clamp(9px,1.4vh,16px) 0 clamp(10px,1.6vh,20px);
  display:flex;justify-content:space-between;gap:18px;flex-wrap:wrap;
  /* 页脚左侧是**中文短语**，用无衬线；只有右侧的句柄/邮箱才用等宽 */
  font-family:var(--sans);font-size:12.5px;color:var(--muted);letter-spacing:0;
}
.foot a:hover{color:var(--accent)}
.foot .links{display:flex;gap:16px;flex-wrap:wrap}
.foot .links a{
  display:inline-flex;align-items:center;gap:.5em;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.03em;
  transition:color .22s ease;
}
/* 图标与文字同色（currentColor），hover 时整体转到强调色 —— 不会出现"彩色图标配灰字" */
.foot .links svg{width:13px;height:13px;flex:none;opacity:.9}
/* 页脚右侧那句是纯拉丁短语，归到等宽体系里（与句柄、日期同一类）。
   --mono 已补中文回退，将来换成中文也不会崩。 */
.foot .stamp{
  font-family:var(--mono);font-size:11.5px;letter-spacing:.05em;
}
.foot .icp{flex-basis:100%;text-align:center;font-size:12px}
.foot .icp a:focus-visible{outline:2px solid var(--accent);outline-offset:4px}
/* 返回首页：显眼靠**颜色**，不靠形状。
   上一版做成描边胶囊按钮——圆角+边框在这套"细线排版"里很出戏（被指出过）。
   现在只是朱红纯文字，hover 加下划线：醒目但不出格。 */
.back{
  display:inline-flex;align-items:center;gap:.4em;
  font-family:var(--mono);font-size:12px;letter-spacing:.04em;
  color:var(--accent);
  border-bottom:1px solid transparent;
  transition:border-color .22s ease,opacity .22s ease;
}
.back:hover{border-bottom-color:var(--accent)}
.back svg{width:13px;height:13px}

/* ══ 分类页（内容多，允许滚动）════════════════════════════════════════════ */
/* ── /writing/ 这类「有线上动态源」的分类页：左专题 + 右最新文章 ───────── */
.cat-cols{display:grid;gap:clamp(22px,3vw,48px);align-items:start}
@media(min-width:981px){ .cat-cols{grid-template-columns:minmax(0,1.3fr) minmax(0,1fr)} }
/* 窄栏里 entry 要竖着排，横排会把标题和正文挤成两小条 */
.cat-cols .entry{grid-template-columns:1fr;gap:14px}
.cat-cols .entry h2{font-size:clamp(20px,2vw,26px)}
.cat-cols .entry .stats{grid-template-columns:repeat(auto-fit,minmax(88px,1fr))}
.quick{margin:1.1em 0 0;padding:0;list-style:none}
.quick li{
  display:flex;gap:.5em;align-items:baseline;
  font-family:var(--sans);font-size:13.5px;color:var(--ink-2);padding:.3em 0;
}
.quick li b{
  font-family:var(--mono);font-size:11.5px;color:var(--accent);font-weight:500;
  flex:none;min-width:2.4em;letter-spacing:.02em;
}
.quick-block{margin-top:1.5em;border-top:1px solid var(--rule-2);padding-top:12px}
.quick-block h3{
  margin:0 0 .3em;font-family:var(--serif);font-size:14px;font-weight:600;color:var(--ink);
}
.lede-actions{margin:1.15em 0 0;display:flex;gap:.6em;flex-wrap:wrap}
.act{
  display:inline-flex;align-items:center;gap:.4em;
  font-family:var(--sans);font-size:13.5px;letter-spacing:.01em;
  padding:.5em 1.05em;border-radius:999px;text-decoration:none;
  border:1px solid var(--rule);color:var(--ink-2);background:transparent;
  transition:border-color .18s,color .18s,background .18s;
}
.act:hover{border-color:var(--accent);color:var(--accent)}
.act.primary{background:var(--accent);border-color:var(--accent);color:#fff}
.act.primary:hover{filter:brightness(1.06);color:#fff}
.act svg{width:13px;height:13px;flex:none}
.feed-panel{border-top:1px solid var(--ink);padding-top:14px}
.feed-head{
  display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  margin-bottom:.4em;
}
.feed-head h2{
  margin:0;font-family:var(--serif);font-size:15px;font-weight:600;
  letter-spacing:.01em;color:var(--ink);
}
.feed-head .more{font-family:var(--sans);font-size:12.5px;color:var(--muted);text-decoration:none}
.feed-head .more:hover{color:var(--accent)}
.feed-list{list-style:none;margin:0;padding:0}
.feed-list li{border-bottom:1px solid var(--rule-2);padding:.62em 0}
.feed-list li:last-child{border-bottom:0}
.feed-list a{text-decoration:none;display:block}
.feed-list .t{
  display:block;font-family:var(--serif);font-size:15.5px;line-height:1.45;color:var(--ink);
  transition:color .18s;
}
.feed-list a:hover .t{color:var(--accent)}
.feed-list .m{
  display:flex;gap:.6em;align-items:baseline;flex-wrap:wrap;
  font-family:var(--mono);font-size:11.5px;color:var(--muted);margin-top:.22em;
}
.feed-list .x{
  margin:.18em 0 0;font-family:var(--sans);font-size:13px;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.feed-stamp{
  margin-top:.85em;font-family:var(--mono);font-size:11px;color:var(--muted);letter-spacing:.02em;
}
body.flow{overflow:auto}
body.flow .shell{height:auto;min-height:100dvh}
body.flow main{align-content:start;padding-top:clamp(20px,4vh,48px)}
.crumb{font-family:var(--mono);font-size:11.5px;color:var(--muted);letter-spacing:.05em}
.crumb a:hover{color:var(--accent)}
.crumb .sep{margin:0 .5em;opacity:.5}

.entries{display:grid;gap:clamp(26px,4vh,54px)}
.entry{
  display:grid;grid-template-columns:1fr;gap:1em;
  padding-top:clamp(14px,2vh,22px);border-top:1px solid var(--ink);
}
@media(min-width:821px){ .entry{grid-template-columns:minmax(0,1fr) minmax(0,1.9fr);gap:clamp(20px,3vw,56px)} }
.entry .idx{font-family:var(--mono);font-size:11.5px;color:var(--accent);letter-spacing:.1em}
.entry h2{
  font-family:var(--serif);font-weight:600;margin:.35em 0 0;
  font-size:clamp(21px,2.3vw,29px);letter-spacing:-.01em;line-height:1.25;
}
.entry .tags{margin:.9em 0 0;display:flex;flex-wrap:wrap;gap:.4em}
.tag{
  font-family:var(--mono);font-size:10.5px;color:var(--ink-2);
  border:1px solid var(--rule);padding:.2em .6em;letter-spacing:.03em;
}
.entry .body p{margin:0 0 1em;color:var(--ink-2);font-size:clamp(14px,1.1vw,16px)}
.stats{
  display:flex;flex-wrap:wrap;gap:clamp(18px,3vw,46px);margin:1.2em 0 1.4em;
  padding-top:1em;border-top:1px solid var(--rule-2);
}
.stats div b{
  display:block;font-family:var(--mono);font-weight:500;
  font-size:clamp(17px,1.8vw,23px);letter-spacing:-.02em;font-variant-numeric:tabular-nums;
}
.stats div span{font-family:var(--mono);font-size:10.5px;color:var(--muted);letter-spacing:.06em}
.enter{
  font-family:var(--mono);font-size:12px;color:var(--accent);letter-spacing:.05em;
  display:inline-block;border-bottom:1px solid transparent;transition:border-color .22s ease;
}
.enter:hover{border-bottom-color:var(--accent)}
.empty{
  color:var(--muted);font-size:15px;border:1px dashed var(--rule);
  padding:34px 26px;text-align:center;font-family:var(--mono);font-size:13px;
}

/* Public reading pages extend the existing portal; its theme remains intact. */
.top{flex-wrap:wrap}.home-name{font-size:.4em;font-weight:400;color:var(--muted);margin-left:.65em;letter-spacing:.02em}
.reading{max-width:780px;width:100%;margin:0 auto}.reading h1{font-size:clamp(28px,3.6vw,42px);line-height:1.4;letter-spacing:0}.reading .article-meta{font-family:var(--mono);font-size:12px;color:var(--muted);margin:18px 0 26px}.reading .article-summary{color:var(--ink-2);font-size:17px;padding-bottom:24px;border-bottom:1px solid var(--rule)}.article-body{font-size:16px;line-height:2;color:var(--ink-2)}.article-body p{margin:0 0 1.4em;overflow-wrap:anywhere}.note-sources{border-top:1px solid var(--rule);padding-top:18px;margin-top:32px;font-size:13px;color:var(--muted)}.note-sources h2{font-family:var(--serif);font-size:18px;color:var(--ink);font-weight:600;margin:0 0 12px}.note-sources a{display:block;margin:8px 0;text-decoration:underline;text-underline-offset:3px;overflow-wrap:anywhere}.article-nav{display:flex;justify-content:space-between;gap:24px;border-top:1px solid var(--rule);margin-top:32px;padding-top:20px;font-size:13px;color:var(--accent)}.article-nav a{max-width:48%}.article-nav span{display:block;color:var(--muted);font-family:var(--mono);font-size:11px;margin-bottom:4px}.source-cards{margin-top:0}.source-cards .scard{border:1px solid var(--rule);background:var(--paper);border-radius:0}.source-cards .scard:hover{border-color:var(--accent);background:var(--paper-2)}a:focus-visible{outline:2px solid var(--accent);outline-offset:4px}.skip{position:absolute;top:-80px;left:20px;background:var(--paper);padding:8px 16px;z-index:10}.skip:focus{top:10px}@media(max-width:600px){.article-body{font-size:15.5px}.reading .article-summary{font-size:15px}.item .t{min-width:0;overflow-wrap:anywhere}.item .n{font-size:10.5px}.top{gap:10px}.source-cards{grid-template-columns:1fr}}
