/* 由 scripts/fonts.py 生成；新增文章后重跑脚本。字体为 SIL Open Font License。 */
@font-face {
  font-family: 'Noto Serif SC';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/noto-serif-sc-normal.woff2') format('woff2');
  unicode-range: U+a, U+20-7e, U+a5, U+a9, U+b7, U+2013-2014, U+201c-201d, U+2192, U+2605, U+3001-3002, U+300a-300d, U+4e00, U+4e07, U+4e09-4e0b, U+4e0d-4e0e, U+4e13-4e14, U+4e1a, U+4e1c, U+4e22, U+4e24, U+4e2a, U+4e2d, U+4e32, U+4e3a-4e3b, U+4e48-4e49, U+4e4b, U+4e50, U+4e5f-4e60, U+4e66, U+4e86, U+4e8b-4e8c, U+4e8e, U+4e91-4e92, U+4e9b, U+4ea4, U+4ea7, U+4eab, U+4eae, U+4eba, U+4ec0, U+4ec5, U+4eca-4ecb, U+4ecd-4ece, U+4ed3, U+4ed6, U+4ed8, U+4ee3-4ee5, U+4eec, U+4ef6-4ef7, U+4efb, U+4efd, U+4f11, U+4f1a, U+4f20, U+4f30, U+4f3c, U+4f46, U+4f4d, U+4f4f, U+4f53, U+4f55, U+4f59, U+4f5c, U+4f60, U+4f7f, U+4f8b, U+4f9b, U+4f9d, U+4fbf, U+4fdd, U+4fe1, U+4fee, U+5019, U+5047, U+504f, U+505a, U+505c, U+5065, U+50a8, U+50cf, U+513f, U+5143, U+5148-5149, U+514d, U+515c, U+5165, U+5168, U+516c, U+5171, U+5173, U+5176-5177, U+517b-517c, U+5185, U+518d, U+5199, U+51b3, U+51b5, U+51bb, U+51c0, U+51c6, U+51cf, U+51e0, U+51ed, U+51fa-51fb, U+5206-5207, U+5212, U+5217, U+5219, U+521b, U+521d, U+5220, U+5224, U+522b, U+5230, U+5236-5237, U+524d, U+5267, U+526a, U+5272, U+529b, U+529f-52a1, U+52a8-52a9, U+52e4, U+5305, U+5316, U+5339-533a, U+533f, U+5341, U+5347, U+534a, U+534f, U+5355, U+535a, U+5374, U+5382, U+5386, U+539f, U+53bb, U+53c2, U+53c8, U+53ca, U+53cd, U+53d1, U+53d6-53d8, U+53e3, U+53e5-53e6, U+53ea, U+53ef-53f0, U+53f2, U+53f7-53f8, U+5404, U+5408, U+540c-540e, U+5411, U+5426, U+542b, U+542f, U+544a, U+5468, U+547d, U+548c, U+54cd, U+54ea, U+552e, U+5546, U+5584, U+5668, U+56db, U+56de, U+56e2, U+56fd-56fe, U+5706, U+5728, U+5730, U+573a, U+5740, U+574f, U+5751, U+5757, U+578b, U+57fa, U+5806, U+585e, U+586b, U+5883, U+589e, U+5904, U+5907, U+590d, U+5916, U+591a, U+5927, U+5929-592a, U+5931, U+5934, U+594f, U+5957, U+597d, U+5982, U+5986, U+59cb, U+5b50, U+5b57-5b58, U+5b63, U+5b66, U+5b83, U+5b89, U+5b8c, U+5b98, U+5b9a, U+5b9e, U+5ba1-5ba2, U+5bb6, U+5bb9, U+5bbd, U+5bc6, U+5bcc, U+5bdf, U+5bf8-5bf9, U+5bfc, U+5c04, U+5c06, U+5c0f, U+5c11, U+5c16, U+5c31, U+5c3a, U+5c3d, U+5c40, U+5c42, U+5c4f, U+5c55, U+5d4c, U+5de5-5de6, U+5dee, U+5df1-5df2, U+5e01, U+5e03, U+5e26-5e27, U+5e38, U+5e55, U+5e72-5e74, U+5e76, U+5e8f, U+5e93-5e95, U+5ea6, U+5eb7, U+5efa, U+5f00, U+5f02-5f03, U+5f0f, U+5f15, U+5f20, U+5f53, U+5f55, U+5f62;
}
@font-face {
  font-family: 'Noto Serif SC';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/noto-serif-sc-normal-1.woff2') format('woff2');
  unicode-range: U+5f71, U+5f84-5f85, U+5f88, U+5f8b, U+5f97, U+5fb7, U+5fc3, U+5fc5-5fc6, U+5feb, U+6001, U+600e, U+601d, U+6027, U+603b, U+6062, U+606f, U+6084, U+60c5, U+60ef, U+60f3, U+610f, U+611f, U+6162, U+6210-6211, U+6216, U+622a, U+6237, U+6240, U+624b, U+624d, U+6253, U+6263, U+6267, U+626b, U+6279, U+627e, U+6280, U+628a, U+6296, U+6298, U+62a0, U+62a4-62a5, U+62c6, U+62c9, U+62cd, U+62e2, U+62e6, U+62e8-62e9, U+62ec, U+62fc, U+62ff, U+6301, U+6307, U+6309, U+6362, U+636e, U+6389, U+6392, U+63a5, U+63a7-63a8, U+63aa, U+63d0, U+641c, U+642d, U+6444, U+6458, U+64ad, U+64ce, U+652f, U+6536, U+6539, U+653e, U+6548, U+655b, U+6563, U+6570, U+6574, U+6587, U+6599, U+659c, U+65ad, U+65b0, U+65b9, U+65c5, U+65d7, U+65e0, U+65e5, U+65e7, U+65f6, U+660e, U+6613, U+661f-6620, U+662f, U+663e, U+666e-666f, U+667a, U+6682, U+66f4, U+66fe-6700, U+6708-6709, U+670d, U+671f, U+672a, U+672c, U+672f, U+673a, U+6743, U+6750, U+675f, U+6761, U+6765, U+677f, U+6784, U+6790, U+679c, U+67b6, U+67d0, U+67d3, U+67e5, U+6807-6808, U+680f, U+6821, U+6837-6838, U+683c, U+6846, U+6848, U+684c, U+6863, U+68c0, U+695a, U+6982, U+6a21, U+6a2a, U+6b21, U+6b62-6b63, U+6b65, U+6b96, U+6bb5, U+6bcf, U+6bd4, U+6c11, U+6c38, U+6c42, U+6c60, U+6ca1, U+6cd5, U+6ce2, U+6ce8, U+6d3b, U+6d3e, U+6d41, U+6d45, U+6d4b, U+6d4f, U+6d88, U+6df1, U+6df7, U+6e05, U+6e20, U+6e32, U+6e38, U+6e90, U+6eaf, U+6ed1, U+6eda, U+6ee1, U+6ee4, U+6f14, U+6f2b, U+701a, U+7070, U+70b9, U+7126, U+7136, U+7167, U+7247-7248, U+7269, U+7279, U+72b6, U+72ec, U+731c, U+7387, U+73af-73b0, U+7406, U+751f, U+7528, U+7531, U+7533, U+7535, U+753b, U+754c, U+7559, U+7591, U+767b, U+767d, U+7684, U+76d1, U+76d6, U+76d8, U+76ee, U+76f4, U+76f8, U+7701, U+770b, U+771f, U+7740, U+77ac, U+77e5, U+77ed, U+7801, U+7834, U+786e, U+788d, U+793a, U+795e, U+7968, U+79c1, U+79cd, U+79d2, U+79df, U+79f0, U+79fb, U+7a0b, U+7a0d-7a0e, U+7a33, U+7a3f, U+7a79-7a7a, U+7a81, U+7a97, U+7acb, U+7ad6, U+7ad9, U+7ae0, U+7aef, U+7b14, U+7b2c, U+7b49, U+7b54, U+7b56, U+7b5b, U+7b79, U+7b7e, U+7b80, U+7b97, U+7ba1, U+7bb1, U+7bc7, U+7c7b, U+7c92, U+7c97, U+7cfb, U+7d20, U+7d22, U+7ea6-7ea7, U+7eaf, U+7eb2-7eb3, U+7ebf, U+7ec4, U+7ec6-7ec8, U+7ecd, U+7ecf, U+7ed3, U+7ed8-7ed9, U+7edf, U+7ee7, U+7ee9-7eea, U+7eed, U+7ef4, U+7eff, U+7f13, U+7f16, U+7f18, U+7f1d, U+7f3a, U+7f51, U+7f6e, U+7f72, U+7fa4, U+8003, U+8005, U+800c, U+8017, U+8054, U+805a, U+80fd, U+8111, U+811a, U+817e, U+81ea, U+81f3-81f4, U+8212, U+821e, U+822a, U+8230, U+8272, U+8282, U+82b1, U+82cd, U+82f1, U+8349, U+8350, U+83dc, U+843d, U+85aa, U+85cf, U+8651, U+8776, U+884c, U+8854, U+8861, U+8865, U+8868, U+88ab, U+88c5, U+897f, U+8981, U+8986, U+89c1-89c2, U+89c6, U+89c8-89c9, U+89d2, U+89e3, U+8b66, U+8ba1-8ba2, U+8ba4, U+8ba9, U+8bae, U+8bb0, U+8bb8, U+8bba, U+8bbe-8bbf, U+8bc1, U+8bc4, U+8bc6, U+8bc9, U+8bcd, U+8bd5, U+8bdd, U+8be5, U+8bef, U+8bf4, U+8bf7, U+8bfb, U+8c03, U+8d1f, U+8d22-8d23, U+8d25-8d28, U+8d2d, U+8d2f, U+8d34, U+8d39, U+8d41, U+8d44, U+8d56, U+8d70, U+8d77, U+8d85, U+8db3, U+8dd1, U+8ddd, U+8ddf, U+8de8, U+8def, U+8df3, U+8e29-8e2a, U+8e48;
}
@font-face {
  font-family: 'Noto Serif SC';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/noto-serif-sc-normal-2.woff2') format('woff2');
  unicode-range: U+8eab, U+8f66, U+8f6c, U+8f6e-8f6f, U+8f7b, U+8f7d, U+8f91, U+8f93, U+8f9e, U+8fb9, U+8fbe, U+8fc1, U+8fc7, U+8fd0-8fd1, U+8fd4, U+8fd8-8fd9, U+8fdb-8fdc, U+8fde, U+8ffd, U+9000-9002, U+9006, U+9009, U+9010, U+9014, U+901a, U+901f-9020, U+903c, U+9053, U+907f, U+90a3, U+90bb, U+90e8, U+90fd, U+914d, U+916c, U+9192, U+91c7, U+91ca, U+91cc-91cd, U+91cf, U+91d1, U+949f, U+94a5, U+94ae, U+94fa, U+94fe, U+9500, U+9519, U+952e, U+955c, U+957f, U+95ea, U+95ee, U+95f4, U+9605, U+961f, U+9632, U+9636, U+9645, U+964d, U+9650, U+9664, U+9669, U+968f-9690, U+969c, U+96c6, U+9700, U+9759, U+975e, U+9760, U+9762, U+97f3, U+9875-9876, U+9879-987b, U+9884, U+9891, U+9898, U+989d, U+98ce, U+9988, U+9996, U+9a7b, U+9a8c, U+9aa4, U+9ad8, U+9ed8, U+9f13, U+9f20, U+9f50, U+ff08-ff09, U+ff0c, U+ff1a-ff1b, U+ff1f;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/ibm-plex-sans-italic.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/fonts/ibm-plex-sans-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url('/fonts/jetbrains-mono-normal.woff2') format('woff2');
}
/* 字体文件在构建时自托管并按实际用字做子集化，这里只声明字体名。 */

/* ---------- Tokens ---------- */
:root {
  --paper:   #EDF0EC;
  --paper-2: #E3E7E2;
  --ink:     #18201D;
  --ink-2:   #56625D;
  --ink-3:   #646D69;   /* 4.65:1 on paper */
  --code-muted: #5C6561; /* 4.81:1 on paper-2 (code comments) */
  --rule:    #CDD3CD;
  --accent:  #2D47B5;
  --accent-soft: #B7C1E6;
  --dot-empty: #D9DED9;

  --serif: "Noto Serif SC", "Songti SC", "STSong", serif;
  --sans:  "IBM Plex Sans", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  --mono:  "JetBrains Mono", "SF Mono", Menlo, monospace;

  /* 1.25 scale from 17px */
  --t-xs: 0.8125rem;  /* 13 */
  --t-sm: 0.9375rem;  /* 15 */
  --t-md: 1.0625rem;  /* 17 */
  --t-lg: 1.3125rem;  /* 21 */
  --t-xl: 1.625rem;   /* 26 */
  --t-2xl: 2.0625rem; /* 33 */
  --t-3xl: 2.75rem;   /* 44 */

  --measure: 37em;
  color-scheme: light;
}
:root[data-theme="dark"] {
  --paper:   #131816;
  --paper-2: #1B221F;
  --ink:     #E2E7E3;
  --ink-2:   #9BA7A1;
  --ink-3:   #77847E;   /* 4.60:1 on paper */
  --code-muted: #808D87; /* 4.69:1 on paper-2 */
  --rule:    #29312D;
  --accent:  #93A6F6;
  --accent-soft: #34416F;
  --dot-empty: #222A26;
  color-scheme: dark;
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 var(--t-md)/1.85 var(--sans);
  font-feature-settings: "tnum" 0;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background-color .3s ease, color .3s ease;
}
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
::selection { background: var(--accent-soft); color: var(--ink); }

.skip { position: absolute; left: -9999px; }
.skip:focus { left: 1rem; top: 1rem; background: var(--paper); padding: .5rem 1rem; z-index: 10; }
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

kbd {
  font-family: var(--mono);
  font-size: .8em;
  line-height: 1;
  padding: .2em .45em .15em;
  border: 1px solid var(--rule);
  border-bottom-width: 2px;
  border-radius: 4px;
  background: var(--paper);
  color: var(--ink);
  white-space: nowrap;
}

/* ---------- Shell ---------- */
.shell {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 48px;
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  column-gap: 112px;
}
.rail {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  padding: 120px 0 48px;
  display: flex;
  flex-direction: column;
}
.brand {
  font-family: var(--serif);
  font-weight: 600;
  font-size: var(--t-lg);
  letter-spacing: .04em;
  line-height: 1.3;
}
.brand-sub { margin-top: 6px; font-size: var(--t-sm); color: var(--ink-3); line-height: 1.5; }

.nav { margin-top: 56px; display: flex; flex-direction: column; gap: 10px; }
.nav a {
  font-size: var(--t-sm);
  white-space: nowrap;
  color: var(--ink-2);
  width: fit-content;
  position: relative;
  padding-left: 16px;
}
.nav a::before {
  content: "";
  position: absolute; left: 0; top: 50%;
  width: 6px; height: 6px; margin-top: -3px;
  border-radius: 50%;
  background: transparent;
  transition: background-color .2s ease;
}
.nav a:hover { color: var(--ink); }
.nav a[aria-current="true"] { color: var(--ink); }
.nav a[aria-current="true"]::before { background: var(--accent); }

.toc { margin-top: 56px; display: none; }
.toc-title { font-size: var(--t-xs); color: var(--ink-3); margin-bottom: 12px; }
.toc ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.toc a { font-size: var(--t-xs); line-height: 1.6; color: var(--ink-3); display: block; transition: color .2s ease; }
.toc a:hover, .toc a.is-active { color: var(--ink); }
.toc a.is-active { color: var(--accent); }
body[data-view="post"] .toc { display: block; }

.rail-foot { margin-top: auto; font-size: var(--t-xs); color: var(--ink-3); }
.theme-btn { color: var(--ink-3); font-size: var(--t-xs); }
.theme-btn:hover { color: var(--ink); }

main { padding: 120px 0 0; min-width: 0; }
.col { max-width: 640px; }

/* ---------- Home: intro ---------- */
.intro h1 {
  margin: 0;
  font-family: var(--serif);
  font-weight: 600;
  font-size: var(--t-3xl);
  line-height: 1.38;
  letter-spacing: .02em;
}
.intro p {
  margin: 32px 0 0;
  max-width: 30em;
  color: var(--ink-2);
}
.intro p a { color: var(--ink); border-bottom: 1px solid var(--rule); transition: border-color .2s; }
.intro p a:hover { border-color: var(--accent); }

/* ---------- Home: writing calendar ---------- */
.calendar { margin-top: 112px; }
.calendar-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 24px; flex-wrap: wrap;
  margin-bottom: 20px;
}
.calendar-head h2 { margin: 0; font-family: var(--serif); font-weight: 600; font-size: var(--t-lg); line-height: 1.4; }
.legend { display: flex; gap: 18px; font-size: var(--t-xs); color: var(--ink-3); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.legend i { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }

.grid-wrap { overflow-x: auto; scrollbar-width: none; padding: 4px 0; }
.grid-wrap::-webkit-scrollbar { display: none; }
.grid-wrap > div { width: max-content; }
.grid {
  --d: 8px; --g: 3.6px;
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(7, var(--d));
  grid-auto-columns: var(--d);
  gap: var(--g);
  width: max-content;
}
.dot {
  width: var(--d); height: var(--d);
  border-radius: 50%;
  background: var(--dot-empty);
  padding: 0;
}
.dot.post { background: var(--accent); }
.dot.future { background: transparent; box-shadow: inset 0 0 0 1px var(--dot-empty); }
.dot.post { transition: transform .15s ease; }
.dot.post:hover, .dot.post.is-on { transform: scale(1.6); }
.months {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc(8px + 3.6px);
  font-size: 11px; color: var(--ink-3);
  white-space: nowrap;
  margin-top: 10px;
  width: max-content;
  line-height: 1;
}
.calendar-cap {
  margin-top: 20px;
  min-height: 1.85em;
  font-size: var(--t-sm);
  color: var(--ink-2);
}
.calendar-cap a { color: var(--ink); border-bottom: 1px solid var(--accent); }

@media (prefers-reduced-motion: no-preference) {
  .grid.animate .dot { opacity: 0; animation: dot-in .5s ease forwards; animation-delay: calc(var(--i) * 4ms); }
  @keyframes dot-in { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: none; } }
}

/* ---------- Home: posts ---------- */
.posts { margin-top: 128px; }
.posts-head h2 { margin: 0; font-family: var(--serif); font-weight: 600; font-size: var(--t-lg); line-height: 1.4; }
.filters { margin-top: 20px; display: flex; flex-wrap: wrap; gap: 6px 22px; }
.filters button {
  font-size: var(--t-sm);
  color: var(--ink-3);
  padding: 2px 0;
  border-bottom: 1px solid transparent;
  transition: color .2s, border-color .2s;
}
.filters button sup { font-size: 10px; margin-left: 2px; color: var(--ink-3); vertical-align: 4px; }
.filters button:hover { color: var(--ink); }
.filters button[aria-pressed="true"] { color: var(--ink); border-bottom-color: var(--ink); }

.year { margin-top: 64px; }
.year:first-of-type { margin-top: 56px; }
.year-label {
  font-family: var(--serif);
  font-weight: 500;
  font-size: var(--t-sm);
  color: var(--ink-3);
  margin: 0 0 8px;
}
.entry {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  column-gap: 24px;
  padding: 26px 0;
  border-top: 1px solid var(--rule);
}
.year .entry:last-child, .results .entry:last-child { border-bottom: 1px solid var(--rule); }
.entry time {
  font-size: var(--t-sm);
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  padding-top: 3px;
  white-space: nowrap;
}
.entry-title { margin: 0; font-family: var(--serif); font-weight: 600; font-size: var(--t-lg); line-height: 1.5; }
.entry-title a { background-image: linear-gradient(var(--accent), var(--accent)); background-size: 0 1px; background-position: 0 100%; background-repeat: no-repeat; transition: background-size .35s ease, color .2s; }
.entry-title a:hover { background-size: 100% 1px; }
.entry p { margin: 8px 0 0; font-size: var(--t-sm); line-height: 1.8; color: var(--ink-2); }
.entry .meta { margin-top: 10px; font-size: var(--t-xs); color: var(--ink-3); }

/* ---------- Home: about ---------- */
.about { margin-top: 144px; }
.about h2 { margin: 0 0 24px; font-family: var(--serif); font-weight: 600; font-size: var(--t-lg); line-height: 1.4; }
.about p { margin: 0 0 1.1em; color: var(--ink-2); max-width: var(--measure); }
.about dl { margin: 40px 0 0; display: grid; grid-template-columns: 88px 1fr; gap: 10px 24px; font-size: var(--t-sm); }
.about dt { color: var(--ink-3); }
.about dd { margin: 0; }
.about dd a { border-bottom: 1px solid var(--rule); transition: border-color .2s; }
.about dd a:hover { border-color: var(--accent); }

.site-foot {
  margin: 144px 0 0;
  padding: 32px 0 64px;
  border-top: 1px solid var(--rule);
  font-size: var(--t-xs);
  color: var(--ink-3);
}

/* ---------- Page titles (article, search, 404) ---------- */
.article-head h1, .page-title {
  margin: 0;
  font-family: var(--serif); font-weight: 700;
  font-size: var(--t-2xl);
  line-height: 1.45;
  letter-spacing: .015em;
}

/* ---------- Article ---------- */
.back { font-size: var(--t-sm); color: var(--ink-3); transition: color .2s; }
.back:hover { color: var(--ink); }
.article-head { margin-top: 56px; }
.article-head .meta { margin-top: 20px; font-size: var(--t-sm); color: var(--ink-3); font-variant-numeric: tabular-nums; }

.prose { margin-top: 64px; max-width: var(--measure); }
.prose > * { margin: 0 0 1.25em; }
.prose .lead { font-size: var(--t-lg); line-height: 1.8; color: var(--ink); font-family: var(--serif); font-weight: 500; margin-bottom: 2em; }
.prose h2 {
  font-family: var(--serif); font-weight: 600;
  font-size: var(--t-xl); line-height: 1.5;
  margin: 2.6em 0 .9em;
  scroll-margin-top: 48px;
}
.prose h3 {
  font-family: var(--serif); font-weight: 600;
  font-size: var(--t-lg); line-height: 1.55;
  margin: 2.1em 0 .6em;
  scroll-margin-top: 48px;
}
.prose h4 {
  font-family: var(--sans); font-weight: 600;
  font-size: var(--t-md); line-height: 1.6;
  margin: 1.9em 0 .4em;
  scroll-margin-top: 48px;
}
.prose h2 + h3 { margin-top: 1.2em; }
.prose h3 + h4 { margin-top: 1em; }
.prose p { text-align: justify; text-justify: inter-ideograph; }
.prose a { color: var(--accent); border-bottom: 1px solid var(--accent-soft); }
.prose strong { font-weight: 600; }
.prose del, .prose s { color: var(--ink-2); text-decoration-thickness: 1px; }
.prose code:not(pre code) {
  font-family: var(--mono); font-size: .86em;
  background: var(--paper-2);
  padding: .12em .4em; border-radius: 4px;
  overflow-wrap: anywhere;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}

/* lists */
.prose ul, .prose ol { padding-left: 1.4em; }
.prose li { margin-bottom: .4em; }
.prose li::marker { color: var(--ink-3); }
.prose ol > li::marker { font-variant-numeric: tabular-nums; }
.prose li > ul, .prose li > ol { margin: .45em 0 .2em; padding-left: 1.3em; }
.prose li > ul > li, .prose li > ol > li { margin-bottom: .25em; }
.prose li > p { margin: 0 0 .5em; }

.prose ol.timeline { list-style: none; padding: 0; margin: 1.6em 0 2em; }
.prose ol.timeline li {
  display: grid; grid-template-columns: 64px 1fr; gap: 16px;
  padding: 10px 0;
  margin: 0;
  position: relative;
}
.prose ol.timeline time { font-variant-numeric: tabular-nums; color: var(--ink-3); font-size: var(--t-sm); padding-top: 2px; }

.prose blockquote {
  margin: 2.2em 0;
  padding: 0 0 0 28px;
  border-left: 2px solid var(--accent);
  font-family: var(--serif);
  font-size: var(--t-lg);
  line-height: 1.75;
  color: var(--ink);
}
.prose blockquote cite { display: block; margin-top: 10px; font: normal var(--t-sm)/1.6 var(--sans); color: var(--ink-3); }

.prose pre {
  margin: 2em 0 2.2em;
  padding: 24px 28px;
  background: var(--paper-2);
  border-radius: 6px;
  overflow-x: auto;
  font: 400 .84rem/1.75 var(--mono);
  color: var(--ink);
  tab-size: 2;
}
.prose pre .c { color: var(--code-muted); }
.prose pre .k { color: var(--accent); }
.prose pre .s { color: var(--ink-2); }

/* images & figures */
.prose img { display: block; max-width: 100%; height: auto; }
.prose picture { display: block; }
.prose figure { margin: 2.4em 0 2.6em; }
.prose figcaption {
  margin-top: 14px;
  font-size: var(--t-xs);
  line-height: 1.7;
  color: var(--ink-3);
  text-align: left;
}
.prose .dark-only { display: none; }
:root[data-theme="dark"] .prose .dark-only { display: block; }
:root[data-theme="dark"] .prose .light-only { display: none; }

/* tables */
.prose .table-wrap { overflow-x: auto; margin: 2em 0 2.2em; }
.prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-sm);
  line-height: 1.6;
}
.prose th, .prose td {
  text-align: left;
  vertical-align: top;
  padding: 11px 20px 11px 0;
  border-bottom: 1px solid var(--rule);
}
.prose th:last-child, .prose td:last-child { padding-right: 0; }
.prose thead th {
  font-weight: 600;
  color: var(--ink);
  border-bottom-color: var(--ink-3);
  white-space: nowrap;
}
.prose td { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.prose td:first-child { color: var(--ink); }
.prose td.nowrap { white-space: nowrap; }

/* rule */
.prose hr { border: 0; border-top: 1px solid var(--rule); margin: 3em 0; height: 0; }
.prose hr.footnotes-sep { display: none; }

/* footnotes (GFM / markdown-it / goldmark markup) */
.prose sup { font-size: .72em; line-height: 0; vertical-align: super; }
.prose sup a { border: 0; padding: 0 .15em; font-variant-numeric: tabular-nums; }
.prose .footnotes {
  margin-top: 4em;
  padding-top: 1.6em;
  border-top: 1px solid var(--rule);
  font-size: var(--t-sm);
  line-height: 1.75;
  color: var(--ink-2);
}
.prose .footnotes ol { margin: 0; padding-left: 1.4em; }
.prose .footnotes li { margin-bottom: .7em; scroll-margin-top: 48px; }
.prose .footnotes p { margin: 0; text-align: left; }
.prose [data-footnote-backref], .prose .footnote-backref { border: 0; margin-left: .3em; }

.placeholder { color: var(--ink-3); font-size: var(--t-sm); }

.article-foot {
  margin-top: 96px; padding-top: 32px;
  border-top: 1px solid var(--rule);
  display: grid; grid-template-columns: 1fr 1fr; gap: 32px;
  max-width: var(--measure);
}
.article-foot a { display: block; }
.article-foot small { display: block; font-size: var(--t-xs); color: var(--ink-3); margin-bottom: 6px; }
.article-foot span { font-family: var(--serif); font-weight: 600; font-size: var(--t-md); line-height: 1.6; transition: color .2s; }
.article-foot a:hover span { color: var(--accent); }
.article-foot .next { text-align: right; }

/* ---------- Search ---------- */
.search-form { margin-top: 48px; }
.search-input {
  -webkit-appearance: none; appearance: none;
  width: 100%;
  padding: 6px 0 12px;
  border: 0;
  border-bottom: 1px solid var(--ink-3);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font: 500 var(--t-xl)/1.4 var(--serif);
  transition: border-color .2s, box-shadow .2s;
}
.search-input::placeholder { color: var(--ink-3); opacity: 1; }
.search-input:focus { outline: none; border-bottom-color: var(--accent); box-shadow: 0 1px 0 var(--accent); }
.search-status {
  margin: 20px 0 0;
  min-height: 1.85em;
  font-size: var(--t-sm);
  color: var(--ink-2);
}
.search-status a { color: var(--ink); border-bottom: 1px solid var(--rule); }
.search-status a:hover { border-color: var(--accent); }
.results { margin-top: 40px; }
.results .entry { grid-template-columns: minmax(0, 1fr); }
.results mark, .entry mark {
  background: var(--accent-soft);
  color: var(--ink);
  border-radius: 2px;
  padding: 0 .08em;
}

/* ---------- 404 ---------- */
.nf-text { margin: 28px 0 0; max-width: var(--measure); color: var(--ink-2); }
.nf-text code {
  font-family: var(--mono); font-size: .86em;
  background: var(--paper-2); color: var(--ink);
  padding: .12em .4em; border-radius: 4px;
  overflow-wrap: anywhere;
}
.nf-actions { margin: 40px 0 0; display: flex; flex-wrap: wrap; gap: 12px 32px; }
.nf-actions a { border-bottom: 1px solid var(--rule); transition: border-color .2s; }
.nf-actions a:hover { border-color: var(--accent); }

[hidden] { display: none !important; }

/* ---------- Responsive ---------- */
@media (max-width: 960px) {
  .shell { grid-template-columns: 160px minmax(0, 1fr); column-gap: 56px; padding: 0 32px; }
}
@media (max-width: 760px) {
  :root { --t-3xl: 2.125rem; --t-2xl: 1.75rem; --t-xl: 1.375rem; }
  .shell { display: block; padding: 0 22px; }
  .rail {
    position: static; height: auto;
    padding: 28px 0 0;
    flex-direction: row; flex-wrap: wrap; align-items: baseline;
    gap: 12px 16px;
  }
  .brand-block { margin-right: auto; }
  .brand-sub, .toc, body[data-view="post"] .toc { display: none; }
  .nav { margin: 0; flex-direction: row; gap: 18px; }
  .nav a { padding-left: 0; }
  .nav a::before { display: none; }
  .nav a[aria-current="true"] { border-bottom: 1px solid var(--ink); }
  /* the theme toggle joins the nav row, set apart by a short hairline */
  .rail-foot { margin: 0; display: flex; align-items: baseline; }
  .rail-foot::before {
    content: "";
    align-self: center;
    width: 1px; height: .95em;
    margin-right: 16px;
    background: var(--rule);
  }
  .theme-btn { font-size: var(--t-sm); color: var(--ink-2); }
  .theme-verb { display: none; }
  main { padding-top: 72px; }
  .calendar { margin-top: 80px; }
  .posts, .about { margin-top: 96px; }
  .entry { grid-template-columns: 1fr; row-gap: 4px; }
  .entry time { padding: 0; }
  .grid-wrap { direction: rtl; }       /* start scrolled to the latest weeks */
  .grid-wrap > * { direction: ltr; }
  .prose p { text-align: left; }
  .article-foot { grid-template-columns: 1fr; }
  .article-foot .next { text-align: left; }
  .search-form { margin-top: 36px; }
}
@media (max-width: 360px) {
  .rail { column-gap: 12px; }
  .nav { gap: 14px; }
  .rail-foot::before { margin-right: 12px; }
}


/* =====================================================================
   接入补充（Codex）：设计稿之外的最小补充 + 动效层。
   设计稿新版到了以后，这一段会随新版调整。
   ===================================================================== */

/* 写作日历：代码提交点（设计稿只有文章点） */
.dot.note { background: var(--accent-soft); transition: transform .18s cubic-bezier(.2, 0, 0, 1); }
@media (hover: hover) { .dot.note:hover { transform: scale(1.6); } }

/* 代码高亮：把 Shiki 的 css-variables 主题映射到设计变量 */
:root {
  --astro-code-foreground: var(--ink);
  --astro-code-background: var(--paper-2);
  --astro-code-token-keyword: var(--accent);
  --astro-code-token-comment: var(--code-muted);
  --astro-code-token-string: var(--ink-2);
  --astro-code-token-string-expression: var(--ink-2);
  --astro-code-token-constant: var(--ink);
  --astro-code-token-function: var(--ink);
  --astro-code-token-parameter: var(--ink);
  --astro-code-token-punctuation: var(--ink-2);
  --astro-code-token-link: var(--accent);
}

/* 列表左侧的小字：项目类型、skill 使用次数 */
.entry .entry-side {
  font-size: var(--t-sm);
  color: var(--ink-3);
  padding-top: 3px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* 徽标、标签、更多链接 */
.badge {
  display: inline-block;
  margin-left: 10px;
  padding: 0 6px;
  font: 400 var(--t-xs)/1.6 var(--sans);
  color: var(--ink-3);
  border: 1px solid var(--rule);
  border-radius: 3px;
  vertical-align: 3px;
}
.chips { display: flex; flex-wrap: wrap; gap: 4px 16px; }
.chips a { border-bottom: 1px solid var(--rule); transition: border-color .2s; }
.chips a:hover { border-color: var(--accent); }
.more { margin-top: 20px; font-size: var(--t-sm); }
.more a { border-bottom: 1px solid var(--rule); transition: border-color .2s; }
.more a:hover { border-color: var(--accent); }

/* 「本文相关」及其他相关区块 */
.related {
  margin-top: 72px; padding-top: 28px;
  border-top: 1px solid var(--rule);
  max-width: var(--measure);
}
.related-title { margin: 0 0 16px; font-family: var(--serif); font-weight: 600; font-size: var(--t-md); }
.related dl { margin: 0; display: grid; grid-template-columns: 64px 1fr; gap: 10px 20px; font-size: var(--t-sm); }
.related dt { color: var(--ink-3); }
.related dd { margin: 0; }
.related-posts { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.related-posts a { border-bottom: 1px solid var(--rule); }
.related-posts a:hover { border-color: var(--accent); }
.related-posts small { margin-left: 10px; color: var(--ink-3); font-size: var(--t-xs); }

/* 页首的说明文字 */
.page-sub { margin: 28px 0 0; max-width: 32em; color: var(--ink-2); }

/* 工作项目：可展开的列表（details） */
.work-list { margin-top: 56px; }
.work-item { border-top: 1px solid var(--rule); }
.work-item:last-child { border-bottom: 1px solid var(--rule); }
.work-item > summary {
  display: grid; grid-template-columns: 132px minmax(0, 1fr);
  column-gap: 24px; padding: 24px 0;
  cursor: pointer; list-style: none;
}
.work-item > summary::-webkit-details-marker { display: none; }
.work-item .work-period {
  font-size: var(--t-sm); color: var(--ink-3); padding-top: 3px;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.work-item .work-title {
  margin: 0; display: flex; align-items: baseline; gap: 12px;
  font-family: var(--serif); font-weight: 600; font-size: var(--t-lg); line-height: 1.5;
}
.work-item .work-title::after {
  content: "+"; margin-left: auto; color: var(--ink-3);
  font-family: var(--sans); font-weight: 400;
  transition: rotate .2s cubic-bezier(.2, 0, 0, 1);
}
.work-item[open] .work-title::after { rotate: 45deg; }
.work-item .work-role { margin-top: 6px; font-size: var(--t-xs); color: var(--ink-3); }
.work-item .work-body { padding: 0 0 26px 156px; }
.work-item ul { margin: 12px 0 0; padding-left: 1.2em; color: var(--ink-2); font-size: var(--t-sm); line-height: 1.8; }
.work-item .stack { margin-top: 14px; font-size: var(--t-xs); color: var(--ink-3); }

/* Sam code 价格表：宽表格在手机内横向滚动 */
.table-wrap { overflow-x: auto; margin: 2em 0 2.2em; }
.model-table { min-width: 660px; }
.model-table td { white-space: nowrap; }
.model-table td small { color: var(--ink-3); font-size: var(--t-xs); }
.prose .data-note { font-size: var(--t-sm); color: var(--ink-2); }
.prose .links { display: flex; flex-wrap: wrap; gap: 6px 24px; }

/* 问答：搜索 + 对话 */
.ask-section { margin-top: 96px; }
.ask-title { margin: 0 0 8px; font-family: var(--serif); font-weight: 600; font-size: var(--t-xl); line-height: 1.5; }
.ask-lead { margin: 0 0 28px; color: var(--ink-2); max-width: 34em; }
.chat { display: flex; flex-direction: column; }
.chat-msg { border-top: 1px solid var(--rule); padding: 20px 0; }
.chat-msg:last-child { border-bottom: 1px solid var(--rule); }
.chat-role { margin-bottom: 8px; font-size: var(--t-xs); color: var(--ink-3); }
.chat-text { white-space: pre-wrap; overflow-wrap: anywhere; color: var(--ink); }
.chat-text.is-streaming::after {
  content: ""; display: inline-block; width: .5em; height: 1em;
  margin-left: 2px; vertical-align: -0.15em; background: var(--accent);
  animation: caret-blink 1s steps(1) infinite;
}
.chat-empty { color: var(--ink-3); font-size: var(--t-sm); padding: 16px 0; }
.ask-form { display: grid; grid-template-columns: 1fr auto; gap: 12px; align-items: end; margin-top: 24px; }
.ask-input {
  width: 100%; min-height: 48px; max-height: 180px; resize: vertical;
  padding: 12px 14px; border: 1px solid var(--rule); border-radius: 6px;
  background: var(--paper-2); color: var(--ink); font: inherit; line-height: 1.6;
}
.ask-input::placeholder { color: var(--ink-3); }
.ask-input:focus { outline: 2px solid var(--accent); outline-offset: 2px; }
.ask-send {
  padding: 12px 18px; border: 1px solid var(--ink); border-radius: 6px;
  background: var(--ink); color: var(--paper); font-size: var(--t-sm);
  transition: scale .15s ease-out, opacity .2s;
}
.ask-send:disabled { opacity: .45; cursor: default; }
.ask-send:not(:disabled):active { scale: .96; }
.ask-note { margin-top: 12px; font-size: var(--t-xs); color: var(--ink-3); }
.suggestions { display: flex; flex-wrap: wrap; gap: 8px 18px; margin-top: 20px; }
.suggestions button {
  font-size: var(--t-sm); color: var(--ink-2);
  padding: 2px 0; border-bottom: 1px solid var(--rule);
  transition: color .2s, border-color .2s;
}
.suggestions button:hover { color: var(--ink); border-color: var(--accent); }

@media (max-width: 760px) {
  .related dl { grid-template-columns: 1fr; gap: 4px; }
  .related dd { margin-bottom: 10px; }
  .work-item > summary { grid-template-columns: 1fr; row-gap: 4px; }
  .work-item .work-body { padding-left: 0; }
  .ask-form { grid-template-columns: 1fr; }
  .ask-send { width: 100%; }
}

/* =====================================================================
   动效层（design-taste-frontend + better-ui）
   - 只做低频、可逆、有静止反馈的动效；高频交互保持即时
   - 全部动效都在 prefers-reduced-motion 下降级
   ===================================================================== */

/* 跨文档页面转场（Chrome / Edge / Safari 新版本；不支持时是普通跳转） */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: vt-out .16s ease both; }
::view-transition-new(root) { animation: vt-in .28s cubic-bezier(.2, 0, 0, 1) both; }
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; } }
.brand { view-transition-name: site-brand; }
::view-transition-group(site-brand) { animation-duration: .35s; }

/* 阅读进度：滚动驱动，不支持时隐藏 */
.reading-progress {
  position: fixed; inset: 0 0 auto 0; height: 2px;
  background: var(--accent); transform-origin: 0 50%; transform: scaleX(0);
  pointer-events: none; z-index: 30;
}

@keyframes rise-in {
  from { opacity: 0; translate: 0 14px; filter: blur(4px); }
  to   { opacity: 1; translate: 0 0;    filter: blur(0); }
}
@keyframes progress-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes caret-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

@media (prefers-reduced-motion: no-preference) {
  /* 首屏：标题与介绍分两拍进场 */
  .intro > * { animation: rise-in .55s cubic-bezier(.2, 0, 0, 1) both; }
  .intro > *:nth-child(2) { animation-delay: .07s; }

  /* 低频区块：滚到视口时轻轻抬起（纯 CSS 滚动驱动，无 JS 监听） */
  @supports (animation-timeline: view()) {
    .reveal {
      animation: rise-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 30%;
    }
  }

  /* 文章阅读进度 */
  @supports (animation-timeline: scroll()) {
    .reading-progress { animation: progress-grow linear both; animation-timeline: scroll(root); }
  }

  .theme-btn:active { scale: .96; }
  .toc a { transition: color .2s ease, translate .2s cubic-bezier(.2, 0, 0, 1); }
  .toc a.is-active { translate: 3px 0; }
}

/* 主题切换：从按钮位置圆形展开（View Transition），同时禁掉颜色过渡避免糊成一片 */
html.theme-changing *,
html.theme-changing *::before,
html.theme-changing *::after { transition: none !important; }
html.theme-changing::view-transition-old(root) { animation: none; }
html.theme-changing::view-transition-new(root) {
  clip-path: circle(0 at var(--theme-x, 100%) var(--theme-y, 0%));
  animation: theme-reveal .5s cubic-bezier(.2, 0, 0, 1) forwards;
}
@keyframes theme-reveal {
  to { clip-path: circle(var(--theme-r, 100vmax) at var(--theme-x, 100%) var(--theme-y, 0%)); }
}

/* 工作项目展开：新版 Chrome 支持 details 内容高度过渡，旧浏览器直接展开 */
.work-item { interpolate-size: allow-keywords; }
@supports selector(details::details-content) {
  .work-item::details-content {
    block-size: 0;
    overflow: hidden;
    transition: block-size .3s cubic-bezier(.2, 0, 0, 1), content-visibility .3s allow-discrete;
  }
  .work-item[open]::details-content { block-size: auto; }
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none !important; }
  .reading-progress { display: none; }
  .chat-text.is-streaming::after { animation: none; }
}

/* 手机头部：导航加主题按钮放不下一行。
   隐藏「关于」（首页关于区仍可到达），让主题按钮留在同一行。 */
@media (max-width: 760px) {
  .nav a[data-nav="about"] { display: none; }
  .rail { flex-wrap: nowrap; }
  .brand-block { margin-right: 0; flex: none; }
  .brand { font-size: var(--t-md); }
  .nav {
    flex: 1 1 auto; min-width: 0;
    overflow-x: auto; scrollbar-width: none;
    gap: 12px;
  }
  .nav a { flex: none; }
  .nav::-webkit-scrollbar { display: none; }
  .rail-foot { flex: none; }
  /* 手机上只显示一个字：深 / 浅，省出宽度给导航 */
  #themeWord { display: none; }
  .theme-btn::after { content: "深"; font-size: var(--t-sm); }
  :root[data-theme="dark"] .theme-btn::after { content: "浅"; }
}
