/* ------------------------------------------------------------------
   Fonts: self-hosted so the site does not depend on Google Fonts
   (which is slow or blocked for many visitors in China).
   Chinese text uses the system CJK fonts below (WenKai on /zh/ pages).
------------------------------------------------------------------ */
@font-face {
  font-family: "Neucha";
  src: url('/fonts/neucha-latin.woff2') format("woff2");
  font-display: swap;
}
/* Body text: Nunito, a rounded sans that keeps the friendly feel but reads
   comfortably at length. Headings and UI keep the hand-drawn fonts. */
@font-face {
  font-family: "Nunito";
  src: url('/fonts/nunito-latin.woff2') format("woff2");
  font-weight: 200 1000;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Nunito";
  src: url('/fonts/nunito-latin-italic.woff2') format("woff2");
  font-weight: 200 1000;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Patrick Hand SC";
  src: url('/fonts/patrick-hand-sc-latin.woff2') format("woff2");
  font-display: swap;
}

:root {
  --ink: #2f2e2c;
  --ink-soft: #5c5a56;
  --muted: #8f8d89;
  --line: #d9d6d0;
  --paper: #fffdf8;
  --accent: #2b6cb0;
  --highlight: #fff1a8;
  --highlight-soft: rgba(255, 234, 128, .45);
  --highlight-faint: rgba(255, 234, 128, .35);
  --selection: #cde3fb;
  --card: #fff;
  --card-shadow: rgba(47, 46, 44, .85);
  --placeholder: #f1eee7;
  --code-bg: #f3efe6;
  --code-ink: #8a3b12;
  /* colours shared with the interactive pages (layouts/shortcodes) */
  --pencil: #41403e;
  --gray: #868e96;
  --grid: #c9c9c9;
  --blue: #0071de;
  --red: #a7342d;
  --green: #86a361;
  --land: #f2efe6;
  --land-edge: #b9b4a8;
  --sea: #eaf4fb;
  --cjk: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", "Source Han Sans SC", sans-serif;
}

/* Chinese pages (/zh/): LXGW WenKai, a handwritten-style Kai font that suits the
   paper look. Self-hosted subset of just the characters on those pages
   (scripts/subset-zh-font.py); anything missing falls back to the system font. */
@font-face {
  font-family: "WenKai ZH";
  src: url('/fonts/wenkai-zh.woff2') format("woff2");
  font-display: swap;
}
html[lang="zh"] {
  --cjk: "WenKai ZH", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
}

/* base */
html {
  color: var(--ink);
  font-family: Nunito, var(--cjk);
  font-size: 19px;
}
a, input, option, p, select, table, tbody, td, textarea, th, thead, tr, li, blockquote {
  font-family: Nunito, var(--cjk);
}
/* hand-drawn font for the chrome: header, buttons, tags, badges, widgets */
.site-header, .site-header a, button, .paper-btn, .btn-small, .badge, .tag,
.post-meta, .post-meta a, .say-hi, .say-hi a, .site-footer, .to-top {
  font-family: Neucha, var(--cjk);
}
/* roomier reading rhythm for body copy */
main p, main li {
  font-size: 0.95rem;
  line-height: 1.85;
  letter-spacing: 0.005em;
}
main p { margin: 0 0 1.15em; }
main li { margin-bottom: 0.45em; }
h1, h2, h3, h4, h5, h6 {
  font-family: "Patrick Hand SC", var(--cjk);
  line-height: 1.25;
  margin: 1.6em 0 0.5em;
}
h1 { font-size: 2.9rem; }
h2 { font-size: 2.1rem; }
h3 { font-size: 1.6rem; }
h4 { font-size: 1.25rem; }

/* page titles get a highlighter-pen stroke so they stand out. It is a background
   on an inline span (cloned per line, so wrapped titles work) rather than an
   underline, because browsers repaint underlines in the selection colour (black). */
main h1 .hl {
  background: linear-gradient(transparent 58%, var(--highlight) 58%, var(--highlight) 90%, transparent 90%);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  padding: 0 0.08em;
}
::selection { background: var(--selection); color: var(--ink); }

body {
  background-image: url('/img/geometry2.png');
  line-height: 1.7;
}

.paper {
  background-color: var(--paper);
  padding: 2rem 3rem 3rem;
}
@media only screen and (max-width: 480px) {
  .paper { padding: 1rem 1rem 2rem; }
}

main {
  max-width: 44rem;
  margin: 0 auto;
  overflow-wrap: break-word;
}
main a { overflow-wrap: anywhere; }
main table a { overflow-wrap: normal; }
main td { vertical-align: middle; }
main > h1:first-child,
main > .post-title {
  margin-top: 1.2em;
}
p, li { line-height: 1.85; }

/* anchors: ink text with the hand-drawn underline, highlighter on hover */
a,
a:visited {
  color: var(--accent);
  text-decoration: none;
  transition: background-color .15s ease;
}
a:hover,
a:focus {
  background-color: var(--highlight);
}
a:focus-visible {
  outline: 2px dashed var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}
main:focus { outline: none; }

/* keyboard users: first Tab stop jumps past the header */
.skip-link,
.skip-link:visited {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 200;
  padding: 0.4rem 0.9rem;
  color: var(--ink);
  background: var(--highlight);
  border: 2px solid var(--ink);
  border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;
  transition: top .15s ease;
}
.skip-link:focus { top: 0.6rem; }


/* blockquote */
blockquote {
  font-style: italic;
  color: var(--ink-soft);
  border-left: 3px solid var(--line);
  margin: 1.2em 0;
  padding: 0.1em 0 0.1em 1.2em;
}
blockquote p { margin: 0.3em 0; }

/* images and embeds */
main img { margin: 1.2em auto; }
main iframe { max-width: 100%; }

/* tables scroll instead of overflowing on phones */
main table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
}

/* code */
pre, code { font-size: 0.85em; }
pre { overflow-x: auto; }

/* ------------------------------------------------------------------
   Post lists (home, section pages)
------------------------------------------------------------------ */
.post-list-wrap {
  margin-top: 1.5rem;
  display: grid;
  gap: 1.1rem;
}
/* each entry is a small hand-drawn paper card */
.post-item {
  position: relative;
  display: flex;
  gap: 1rem;
  align-items: flex-start;
  padding: 1rem 1.2rem 1.1rem;
  background: var(--card);
  border: 2px solid var(--ink);
  border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;
  box-shadow: 3px 4px 0 -1px var(--card-shadow);
  transition: transform .15s ease, box-shadow .15s ease;
}
.post-item:nth-child(even) {
  border-radius: 15px 225px 15px 255px / 255px 15px 225px 15px;
}
.post-item:hover {
  transform: translate(-1px, -2px);
  box-shadow: 5px 7px 0 -1px var(--card-shadow);
}
.post-item-body { flex: 1; min-width: 0; }
.post-list {
  font-size: 1.55rem;
  margin: 0 0 0.15em;
}
.post-list a,
.post-list a:visited {
  color: var(--ink);
  background-image: none;
}
/* the whole card is clickable via the title link */
.post-list a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
}
.post-list a:hover { background-color: transparent; }
.post-item:hover .post-list a { background-color: var(--highlight); }
.post-meta .tag { position: relative; z-index: 1; }
.post-summary {
  color: var(--ink-soft);
  margin: 0.2em 0 0;
  font-size: 0.95rem;
  line-height: 1.6;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.post-thumb {
  flex: 0 0 8.5rem;
  background-image: none;
}
.post-thumb img.thumbnail {
  width: 100%;
  height: 6.5rem;
  max-height: none;
  object-fit: cover;
  margin: 0;
  border-width: 1.5px;
}
@media only screen and (max-width: 480px) {
  .post-item { padding: 0.85rem 0.95rem 0.95rem; gap: 0.7rem; }
  .post-thumb { flex-basis: 5.5rem; }
  .post-thumb img.thumbnail { height: 5.5rem; }
  .post-summary { -webkit-line-clamp: 2; }
}

/* date + tags line, used in lists and on single pages */
.post-meta {
  color: var(--muted);
  font-size: 0.85rem;
  margin: 0.2em 0 0.4em;
}
.post-title + .post-meta { margin-bottom: 1.5em; }
.post-tags { margin-left: 0.4em; }
.meta-dot { margin: 0 0.35em; color: var(--line); }
.post-meta .tag,
.post-meta .tag:visited {
  display: inline-block;
  margin: 0.15em 0.2em;
  padding: 0 0.5em;
  color: var(--ink-soft);
  background-image: none;
  border: 1.5px solid var(--line);
  border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;
  font-size: 0.8rem;
  line-height: 1.6;
}
.post-meta .tag::before { content: "#"; color: var(--muted); }
.post-meta .tag:hover {
  border-color: var(--ink-soft);
  background-color: var(--highlight);
}

/* post single */
.post-title { margin-bottom: 0.1em; }

/* toc */
.toc {
  padding: 1em 1.2em;
  margin: 1em 0 2em;
  font-size: 0.9rem;
}
.toc h2 {
  font-size: 1.2em;
  margin-top: 0;
}

/* mathjax */
code.has-jax {
  -webkit-font-smoothing: antialiased;
  background: inherit !important;
  border: none !important;
  font-size: 100%;
}

img.thumbnail {
  max-height: 500px;
  max-width: 100%;
  height: auto !important;
}


@media only screen and (max-width: 768px) {
  /* paper fills the phone screen instead of leaving thin side strips */
  .container.paper {
    width: 100%;
    margin: 0;
    border-left: 0;
    border-right: 0;
    box-shadow: none;
    padding: 0.9rem 1.1rem 2.5rem;
  }
  /* flatter list indentation so nested text keeps a readable width */
  main ol, main ul { margin-left: 0; padding-left: 1.3rem; }
  main li > p { margin: 0.3em 0; }
  main blockquote { padding-left: 0.9em; }
  main iframe { max-height: 320px; }
  h1 { font-size: 2.2rem; }
  h2 { font-size: 1.7rem; }
  h3 { font-size: 1.35rem; }
  .post-list { font-size: 1.3rem; }
}

/* ------------------------------------------------------------------
   Homepage contact table (icon | label | icon | label in markdown)
   Rendered as a full-width grid of hand-drawn tiles, one per contact:
   3 across on desktop, 2 on tablets, 1 per row on phones.
------------------------------------------------------------------ */
main table:has(img[src*="feather"]) {
  display: block;
  width: 100%;
  margin: 1rem 0 2rem;
  overflow: visible;
  border: 0;
}
main table:has(img[src*="feather"]) thead { display: none; }
main table:has(img[src*="feather"]) tbody {
  display: grid;
  grid-template-columns: repeat(3, 3.2rem minmax(0, 1fr));
  row-gap: 0.9rem;
}
main table:has(img[src*="feather"]) tr { display: contents; }
main table:has(img[src*="feather"]) td {
  display: flex;
  align-items: center;
  min-height: 3.4rem;
  padding: 0;
  text-align: left !important;
  background: var(--card);
  border: 2px solid var(--ink);
  transition: background-color .15s ease, transform .1s ease;
}
main table:has(img[src*="feather"]) td:empty { display: none; }
/* icon cell: left half of a tile */
main table:has(img[src*="feather"]) td:nth-child(odd) {
  justify-content: center;
  border-right: 0;
  border-radius: 225px 0 0 15px / 15px 0 0 225px;
}
/* label cell: right half of a tile, with a gap before the next tile */
main table:has(img[src*="feather"]) td:nth-child(even) {
  margin-right: 0.9rem;
  border-left: 0;
  border-radius: 0 15px 255px 0 / 0 225px 15px 0;
  box-shadow: 3px 3px 0 -1px var(--ink);
}
main table:has(img[src*="feather"]) img {
  display: block;
  width: 1.6rem;
  height: 1.6rem;
  margin: 0;
  border: 0;
}
main table:has(img[src*="feather"]) td a {
  display: flex;
  align-items: center;
  align-self: stretch;
  width: 100%;
  padding: 0 0.8rem 0 0.2rem;
  color: var(--ink);
  font-size: 1.15rem;
  line-height: 1.3;
  background: none;
  text-decoration: none;
  overflow-wrap: normal;
}
main table:has(img[src*="feather"]) td:nth-child(odd) a { justify-content: center; padding: 0; }
/* hovering either half lights up the whole tile (and only that tile: a label cell
   is followed by the next tile's icon, so only icon cells light their neighbour) */
main table:has(img[src*="feather"]) td:hover,
main table:has(img[src*="feather"]) td:nth-child(odd):has(+ td:hover),
main table:has(img[src*="feather"]) td:nth-child(odd):hover + td { background: var(--highlight); }
main table:has(img[src*="feather"]) td:active,
main table:has(img[src*="feather"]) td:nth-child(odd):has(+ td:active),
main table:has(img[src*="feather"]) td:nth-child(odd):active + td { transform: translateY(1px); }
@media only screen and (max-width: 900px) {
  main table:has(img[src*="feather"]) tbody { grid-template-columns: repeat(2, 3rem minmax(0, 1fr)); }
}
@media only screen and (max-width: 560px) {
  main table:has(img[src*="feather"]) tbody { grid-template-columns: 3rem minmax(0, 1fr); row-gap: 0.7rem; }
  main table:has(img[src*="feather"]) td:nth-child(even) { margin-right: 3px; }
}

/* ------------------------------------------------------------------
   Language toggle (EN / 中) driving a hidden Google Translate widget
------------------------------------------------------------------ */
/* A two-option switch: each language is its own target. The current one is filled
   with the highlighter; only the option under the pointer reacts. */
.lang-toggle {
  display: inline-flex;
  align-items: stretch;
  flex: 0 0 auto;
  padding: 3px;
  gap: 2px;
  background: var(--card);
  border: 2px solid var(--ink);
  border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;
  box-shadow: 2px 3px 0 -1px var(--ink);
}
.lang-toggle .lang-opt,
.lang-toggle .lang-opt:hover,
.lang-toggle .lang-opt:focus {
  margin: 0;
  min-width: 2.4em;
  padding: 0.1em 0.55em;
  font-family: Neucha, var(--cjk);
  font-size: 1rem;
  line-height: 1.4;
  color: var(--muted);
  background: transparent;
  border: 0;
  border-radius: 15px 225px 15px 255px / 255px 15px 225px 15px;
  box-shadow: none;
  transform: none;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease, transform .1s ease;
  -webkit-tap-highlight-color: transparent;
}
.lang-toggle .lang-opt:hover {
  color: var(--ink);
  background: var(--highlight-soft);
}
.lang-toggle .lang-opt:active { transform: translateY(1px) scale(.96); }
.lang-toggle .lang-opt[aria-pressed="true"],
.lang-toggle .lang-opt[aria-pressed="true"]:hover {
  color: var(--ink);
  background: var(--highlight);
  cursor: default;
  transform: none;
}
.lang-toggle .lang-opt:focus-visible { outline: 2px dashed var(--accent); outline-offset: 1px; }
/* EN / 中 and the light / dark switch sit side by side */
.site-tools {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  gap: 0.6rem;
}
.is-snug .site-tools { gap: 0.45rem; }

/* Light / dark switch: a round hand-drawn button, moon in light mode, sun in dark */
.theme-toggle,
.theme-toggle:hover,
.theme-toggle:focus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 2.5rem;
  height: 2.5rem;
  margin: 0;
  padding: 0;
  color: var(--ink);
  background: var(--card);
  border: 2px solid var(--ink);
  border-radius: 50% 45% 55% 48% / 48% 55% 45% 52%;
  box-shadow: 2px 3px 0 -1px var(--ink);
  transform: none;
  cursor: pointer;
  transition: background-color .15s ease, transform .1s ease;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) { .theme-toggle:hover { background: var(--highlight); } }
.theme-toggle:active { transform: translate(1px, 2px); box-shadow: 0 0 0 -1px var(--ink); }
.theme-toggle:focus-visible { outline: 2px dashed var(--accent); outline-offset: 2px; }
.theme-toggle svg {
  width: 1.3rem;
  height: 1.3rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.theme-toggle .theme-sun { display: none; }
html[data-theme="dark"] .theme-toggle .theme-sun { display: block; }
html[data-theme="dark"] .theme-toggle .theme-moon { display: none; }

/* On pages with a real translation the other language is a plain link */
a.lang-opt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  background-image: none;
  border-bottom: 0;
}

/* "本页有中文版" hint for visitors whose browser prefers Chinese */
.zh-hint {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin: 0 0 1rem;
  padding: .45rem .8rem;
  font-size: .95rem;
  background: var(--highlight-faint);
  border: 2px dashed var(--ink-soft);
  border-radius: 15px 225px 15px 255px / 255px 15px 225px 15px;
}
.zh-hint[hidden] { display: none; }
.zh-hint a { font-weight: bold; }
.zh-hint button {
  margin: 0 0 0 auto;
  padding: 0 .45em;
  font-size: 1.1rem;
  line-height: 1.4;
  color: var(--muted);
  background: transparent;
  border: 0;
  box-shadow: none;
}

/* Keep Google's own gadget, banner, tooltips and highlights out of sight */
#google_translate_element {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.goog-te-banner-frame,
body > .skiptranslate,
iframe.skiptranslate,
#goog-gt-tt,
.goog-te-balloon-frame,
.VIpgJd-ZVi9od-ORHb-OEVmcd,
.VIpgJd-ZVi9od-aZ2wEe-wOHMyf { display: none !important; }
.goog-text-highlight {
  background: none !important;
  box-shadow: none !important;
}
body { top: 0 !important; position: static !important; }

/* Homepage template prints an empty <h1> when the page has no title */
main h1:empty,
main h1:has(> .hl:empty) { display: none; }

/* Buy Me a Coffee floating button would cover text on phones */
@media only screen and (max-width: 768px) {
  #bmc-wbtn, #bmc-iframe { display: none !important; }
}

/* Small touches for a smoother feel on phones */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
}
a, button { -webkit-tap-highlight-color: transparent; }
main img[loading="lazy"] { background: var(--placeholder); }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ------------------------------------------------------------------
   Post page extras: older/newer links, footer, back-to-top, TOC, tables, code
------------------------------------------------------------------ */
.post-nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin: 3rem 0 1rem;
}
.post-nav-link,
.post-nav-link:visited {
  display: block;
  padding: 0.8rem 1rem;
  color: var(--ink);
  background: var(--card);
  background-image: none;
  border: 2px solid var(--ink);
  border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;
  box-shadow: 3px 4px 0 -1px var(--ink);
}
.post-nav-link:hover { background: var(--highlight); }
.post-nav-link.next { grid-column: 2; text-align: right; }
.post-nav-label { display: block; font-size: 0.8rem; color: var(--muted); }
.post-nav-title { display: block; line-height: 1.35; }
@media only screen and (max-width: 480px) {
  .post-nav { grid-template-columns: 1fr; }
  .post-nav-link.next { grid-column: auto; }
}

.site-footer {
  max-width: 44rem;
  margin: 3rem auto 0;
  padding-top: 1rem;
  border-top: 2px dashed var(--line);
  text-align: center;
  font-size: 0.85rem;
  color: var(--muted);
}
.site-footer a, .site-footer a:visited { color: var(--ink-soft); }

.to-top,
.to-top:visited {
  position: fixed;
  right: 1rem;
  bottom: 1.2rem;
  z-index: 50;
  width: 2.6rem;
  height: 2.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
  color: var(--ink);
  background: var(--paper);
  background-image: none;
  border: 2px solid var(--ink);
  border-radius: 50% 45% 55% 48% / 48% 55% 45% 52%;
  box-shadow: 2px 3px 0 -1px var(--ink);
  opacity: 0;
  pointer-events: none;
  transform: translateY(0.5rem);
  transition: opacity .2s ease, transform .2s ease;
}
.to-top.visible { opacity: 1; pointer-events: auto; transform: none; }
.to-top:hover { background: var(--highlight); }
@media only screen and (min-width: 769px) {
  /* desktop: the Say hi widget owns the bottom-left corner and the Buy Me a Coffee
     button (64px, 18px from the edges) the bottom-right, so stack above the latter,
     centred on it */
  .to-top { right: 29px; bottom: 96px; }
}
@media only screen and (min-width: 1260px) {
  /* wide screens: tuck it against the paper column's bottom-right edge,
     well clear of both corner widgets */
  .to-top { right: auto; left: calc(50% + 480px + 14px); bottom: 1.6rem; }
}

details.toc > summary {
  list-style: none;
  cursor: pointer;
}
details.toc > summary::-webkit-details-marker { display: none; }
details.toc > summary h2 { display: inline; margin: 0; }
details.toc > summary::after {
  content: " ▾";
  color: var(--muted);
}
details.toc:not([open]) > summary::after { content: " ▸"; }
details.toc ol { margin-top: 0.6rem; margin-bottom: 0; }

main table {
  border-collapse: collapse;
  font-size: 0.9rem;
}
main th, main td { padding: 0.35rem 0.6rem; }
main thead th { border-bottom: 2px solid var(--ink); }
main tbody tr:nth-child(even) { background: rgba(0, 0, 0, .025); }

main pre {
  border: 2px solid var(--ink);
  border-radius: 15px 255px 15px 225px / 225px 15px 255px 15px;
  padding: 0.9rem 1rem;
  line-height: 1.5;
}
main :not(pre) > code {
  background: var(--code-bg);
  border: 0;
  border-radius: 4px;
  padding: 0.05em 0.35em;
  color: var(--code-ink);
}

/* ------------------------------------------------------------------
   Site header / navigation
   Desktop (>= 1000px): brand left, links + EN/中 right, current page highlighted.
   Narrower: brand + menu button; links slide down in a panel with big tap targets.
   The header sticks to the top, hides while scrolling down, returns on scroll up.
------------------------------------------------------------------ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  margin: -0.5rem -0.5rem 1.5rem;
  padding: 0.5rem 0.5rem 0;
  background: var(--paper);
  transition: transform .25s ease;
}
.site-header.is-hidden { transform: translateY(-110%); }
.site-nav {
  position: relative;
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 3.6rem;
  padding: 0.4rem 0.9rem 0.4rem 1.2rem;
  background: var(--card);
  border: 2px solid var(--ink);
  border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;
  transition: box-shadow .25s ease;
}
.site-header.is-scrolled .site-nav { box-shadow: 0 6px 14px -8px rgba(0, 0, 0, .35); }

.site-brand,
.site-brand:visited {
  flex: 0 0 auto;
  font-family: "Patrick Hand SC", var(--cjk);
  font-size: 1.7rem;
  line-height: 1.2;
  color: var(--ink);
  background-image: none;
  white-space: nowrap;
}
.site-brand:hover { background: none; color: var(--accent); }

.site-menu {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.9rem;
}
.site-menu-list {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.15rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.site-menu-list li { margin: 0; padding: 0; text-indent: 0; }
.site-menu-list li::before { content: none; }
.site-menu-link,
.site-menu-link:visited {
  position: relative;
  display: inline-block;
  padding: 0.25rem 0.55rem;
  font-size: 1.15rem;
  line-height: 1.3;
  color: var(--ink);
  background-image: none;
  border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;
  white-space: nowrap;
  transition: background-color .15s ease, transform .1s ease;
}
.site-menu-link:hover { background-color: var(--highlight); }
.site-menu-link:active { transform: translateY(1px) scale(.97); }
.site-menu-link:focus-visible,
.menu-toggle:focus-visible {
  outline: 2px dashed var(--accent);
  outline-offset: 2px;
}
/* current section: a highlighter stroke under the word */
.site-menu-link.is-active {
  background: linear-gradient(transparent 55%, var(--highlight) 55%, var(--highlight) 92%, transparent 92%);
}
.site-menu-link .ext { font-size: 0.7em; margin-left: 0.15em; color: var(--muted); }

/* menu button (hidden on desktop) */
.menu-toggle {
  display: none;
  margin: 0 0 0 auto;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  align-items: center;
  justify-content: center;
  background: var(--card);
  border: 2px solid var(--ink);
  border-radius: 15px 225px 15px 255px / 255px 15px 225px 15px;
  box-shadow: 2px 3px 0 -1px var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.menu-toggle:hover,
.menu-toggle:focus { background: var(--card); border-color: var(--ink); transform: none; box-shadow: 2px 3px 0 -1px var(--ink); }
.menu-toggle:active { transform: translate(1px, 2px); box-shadow: 0 0 0 -1px var(--ink); }
.menu-toggle-bars {
  position: relative;
  display: block;
  width: 1.3rem;
  height: 1rem;
}
.menu-toggle-bars span {
  position: absolute;
  left: 0;
  width: 100%;
  height: 2.5px;
  border-radius: 2px;
  background: var(--ink);
  transition: transform .25s ease, opacity .2s ease, top .25s ease;
}
.menu-toggle-bars span:nth-child(1) { top: 0; }
.menu-toggle-bars span:nth-child(2) { top: calc(50% - 1.25px); }
.menu-toggle-bars span:nth-child(3) { top: calc(100% - 2.5px); }
.menu-open .menu-toggle-bars span:nth-child(1) { top: calc(50% - 1.25px); transform: rotate(45deg); }
.menu-open .menu-toggle-bars span:nth-child(2) { opacity: 0; }
.menu-open .menu-toggle-bars span:nth-child(3) { top: calc(50% - 1.25px); transform: rotate(-45deg); }

.menu-backdrop { display: none; }

/* Snug mode: a tighter single row when the links almost fit */
.is-snug .site-nav { gap: 0.6rem; padding-left: 1rem; padding-right: 0.7rem; }
.is-snug .site-brand { font-size: 1.45rem; }
.is-snug .site-menu { gap: 0.6rem; }
.is-snug .site-menu-list { gap: 0; }
.is-snug .site-menu-link,
.is-snug .site-menu-link:visited { font-size: 1.05rem; padding: 0.25rem 0.4rem; }
.is-snug .lang-toggle .lang-opt { font-size: 0.92rem; padding: 0.05em 0.45em; }

/* Compact mode: brand + menu button, links in a drop-down panel. The script in nav.html
   switches it on for narrow screens and whenever the links don't fit on one row
   (so adding menu entries in hugo.yaml never breaks the header). */
.is-compact .site-nav { padding: 0.35rem 0.45rem 0.35rem 1rem; min-height: 3.4rem; }
.is-compact .site-brand { font-size: 1.45rem; }
.is-compact .menu-toggle { display: inline-flex; }

/* the panel drops down under the header card */
.is-compact .site-menu {
  position: absolute;
  top: calc(100% + 0.5rem);
  left: 0;
  right: 0;
  flex-direction: column;
  align-items: stretch;
  gap: 0.6rem;
  padding: 0.6rem;
  background: var(--card);
  border: 2px solid var(--ink);
  border-radius: 15px 225px 15px 255px / 255px 15px 225px 15px;
  box-shadow: 4px 6px 0 -1px var(--ink);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-0.6rem) scale(.98);
  transform-origin: top right;
  max-height: calc(100vh - 6rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  transition: opacity .2s ease, transform .22s ease, visibility 0s linear .22s;
}
.site-header.is-compact.menu-open .site-menu {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity .2s ease, transform .22s ease, visibility 0s;
}
.is-compact .site-menu-list {
  flex-direction: column;
  align-items: stretch;
  gap: 0.1rem;
}
.is-compact .site-menu-link,
.is-compact .site-menu-link:visited {
  display: flex;
  align-items: center;
  min-height: 2.9rem;
  padding: 0.35rem 0.9rem;
  font-size: 1.25rem;
}
.is-compact .site-menu-link.is-active { background: var(--highlight); }
.is-compact .site-tools {
  align-self: flex-start;
  margin: 0.2rem 0 0.2rem 0.9rem;
  gap: 0.8rem;
}
.is-compact .theme-toggle { width: 2.9rem; height: 2.9rem; }
.is-compact .lang-toggle .lang-opt { font-size: 1.1rem; min-width: 2.75rem; min-height: 2.4rem; }
.menu-backdrop:not([hidden]) {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(47, 46, 44, .18);
  animation: fade-in .2s ease;
}
@media only screen and (max-width: 480px) {
  .site-header { margin: -0.4rem -0.4rem 1.2rem; padding: 0.4rem 0.4rem 0; }
  .site-brand { font-size: 1.3rem; }
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .site-header, .site-menu, .menu-toggle-bars span { transition: none !important; }
}

/* ------------------------------------------------------------------
   "Say hi" corner widget (bottom-left, desktop only)
------------------------------------------------------------------ */
.say-hi { display: none; }
@media only screen and (min-width: 769px) {
  .say-hi {
    display: block;
    position: fixed;
    left: 18px;
    bottom: 18px;
    z-index: 60;
    font-family: Neucha, var(--cjk);
  }
  .say-hi-btn,
  .say-hi-btn:hover,
  .say-hi-btn:focus {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3.2rem;
    height: 3.2rem;
    margin: 0;
    padding: 0;
    background: var(--card);
    border: 2px solid var(--ink);
    border-radius: 50% 45% 55% 48% / 48% 55% 45% 52%;
    box-shadow: 2px 3px 0 -1px var(--ink);
    cursor: pointer;
    transform: none;
    transition: background-color .15s ease, transform .1s ease;
  }
  .say-hi-btn:hover, .say-hi.is-open .say-hi-btn { background: var(--highlight); }
  .say-hi-btn:active { transform: translate(1px, 2px); box-shadow: 0 0 0 -1px var(--ink); }
  .say-hi-btn img { width: 1.4rem; height: 1.4rem; margin: 0; border: 0; }
  .say-hi-card {
    position: absolute;
    left: 0;
    bottom: calc(100% + 0.7rem);
    width: 13.5rem;
    padding: 0.8rem 0.7rem 0.6rem;
    background: var(--card);
    border: 2px solid var(--ink);
    border-radius: 15px 225px 15px 255px / 255px 15px 225px 15px;
    box-shadow: 4px 5px 0 -1px var(--ink);
    animation: say-hi-in .18s ease;
    max-height: calc(100vh - 6rem);
    overflow-y: auto;
  }
  .say-hi-card[hidden] { display: none; }
  @keyframes say-hi-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
  .say-hi-title { margin: 0 0 0.4rem 0.5rem; font-size: 1.2rem; color: var(--ink); }
  .say-hi-list { margin: 0; padding: 0; list-style: none; }
  .say-hi-list li { margin: 0; padding: 0; text-indent: 0; }
  .say-hi-list li::before { content: none; }
  .say-hi-list a,
  .say-hi-list a:visited,
  .say-hi-list button,
  .say-hi-list button:hover,
  .say-hi-list button:focus {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    margin: 0;
    padding: 0.35rem 0.5rem;
    font: inherit;
    font-size: 1.05rem;
    color: var(--ink);
    text-align: left;
    background: none;
    border: 0;
    border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;
    box-shadow: none;
    transform: none;
    cursor: pointer;
  }
  .say-hi-list a:hover,
  .say-hi-list button:hover,
  .say-hi-list button[aria-expanded="true"] { background: var(--highlight); }
  .say-hi-list img { width: 1.15rem; height: 1.15rem; margin: 0; border: 0; }
  .say-hi-qr { margin: 0.5rem 0 0.2rem; text-align: center; }
  .say-hi-qr[hidden] { display: none; }
  .say-hi-qr img { width: 100%; height: auto; margin: 0 auto; border: 0; border-radius: 6px; }
  .say-hi-qr figcaption { font-size: 0.85rem; color: var(--muted); }
}

/* ------------------------------------------------------------------
   Dark mode: chalk on a slate board. html[data-theme="dark"] is set in
   head.html from the system setting or the header switch. Most of the site
   reads the colour variables above, so this block mostly swaps them; the
   rest re-colours the parts of paper.css that use fixed colours.
------------------------------------------------------------------ */
html[data-theme="dark"] {
  color-scheme: dark;
  --ink: #ebe7dd;
  --ink-soft: #c2bdb1;
  --muted: #959086;
  --line: #4b5355;
  --paper: #23292b;
  --card: #2b3235;
  --card-shadow: rgba(235, 231, 221, .55);
  --accent: #8ec5ff;
  --highlight: rgba(242, 201, 76, .38);
  --highlight-soft: rgba(242, 201, 76, .22);
  --highlight-faint: rgba(242, 201, 76, .14);
  --selection: #36597d;
  --placeholder: #2f3639;
  --code-bg: #323a3d;
  --code-ink: #f4b183;
  --pencil: #ebe7dd;
  --gray: #959086;
  --grid: #4b5355;
  --blue: #6fb3ff;
  --red: #ff8a7a;
  --green: #a6c47f;
  --land: #364043;
  --land-edge: #5d686b;
  --sea: #1d2a33;
}
html[data-theme="dark"] body {
  background-color: #181c1d;
  background-blend-mode: multiply;
}
html[data-theme="dark"] .paper { border-color: #3a4245; }

/* paper.css's hand-drawn link underline, redrawn in the lighter blue. :where keeps
   this as weak as paper.css's own rule, so the site's "no underline" spots still win. */
:where(html[data-theme="dark"]) a {
  background-image: linear-gradient(5deg,transparent 65%,#6fb3ff 80%,transparent 90%),linear-gradient(165deg,transparent 5%,#6fb3ff 15%,transparent 25%),linear-gradient(165deg,transparent 45%,#6fb3ff 55%,transparent 65%),linear-gradient(15deg,transparent 25%,#6fb3ff 35%,transparent 50%);
}

/* line icons are black SVGs: flip them to chalk */
html[data-theme="dark"] img[src*="/feather/"]:not([src$=".jpg"]) { filter: invert(.92); }
/* photos and screenshots: take the glare off a little */
html[data-theme="dark"] main img:not([src*="/feather/"]) { filter: brightness(.9); }
html[data-theme="dark"] img { border-color: var(--line); }

/* buttons, form controls, code */
:where(html[data-theme="dark"]) :is(.paper-btn, [type=button], button, input, select, textarea) {
  color: var(--ink);
  border-color: var(--ink);
}
html[data-theme="dark"] .paper-btn.btn-primary,
html[data-theme="dark"] button.btn-primary { background-color: #4b5355; color: var(--ink); }
html[data-theme="dark"] .paper-btn.btn-secondary,
html[data-theme="dark"] button.btn-secondary,
html[data-theme="dark"] .btn-small.btn-secondary { background-color: #24405e; border-color: #6fb3ff; color: var(--ink); }
html[data-theme="dark"] .paper-btn.btn-success,
html[data-theme="dark"] button.btn-success { background-color: #34452a; border-color: #a6c47f; color: var(--ink); }
html[data-theme="dark"] .badge { border-color: transparent; }
html[data-theme="dark"] .badge.secondary { background-color: #2f6cb3; }
html[data-theme="dark"] code { background-color: var(--code-bg); color: var(--code-ink); }
html[data-theme="dark"] pre { background-color: #1e2426; border-color: var(--ink); color: var(--ink); }
html[data-theme="dark"] pre code { background: none; color: inherit; }
html[data-theme="dark"] kbd { background-color: var(--ink); color: var(--paper); }
html[data-theme="dark"] table tbody tr td { border-top-color: var(--line); }
html[data-theme="dark"] main tbody tr:nth-child(even) { background: rgba(255, 255, 255, .03); }
html[data-theme="dark"] .alert,
html[data-theme="dark"] .border { border-color: var(--ink); }
html[data-theme="dark"] .card { border-color: var(--line); }
html[data-theme="dark"] .site-header.is-scrolled .site-nav { box-shadow: 0 6px 14px -8px rgba(0, 0, 0, .8); }
html[data-theme="dark"] .menu-backdrop:not([hidden]) { background: rgba(0, 0, 0, .45); }
/* Article pages: thin reading-progress bar and related posts */
.read-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 1000;
  pointer-events: none;
}
.read-progress span {
  display: block;
  height: 100%;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: 0 50%;
}
.related-posts { margin: 1.5rem 0 1rem; }
.related-posts h3 { margin: 0 0 0.4rem; font-size: 1.2rem; }
.related-posts ul { margin: 0; }
/* R Markdown nests sections; only the innermost ones draw the ~~~ divider */
.section:has(> .section)::after { content: none; }
/* Play gallery previews are drawn in fixed light colours: flip them, keeping the hues */
html[data-theme="dark"] .play-thumb svg { filter: invert(.88) hue-rotate(180deg); }
