/* ==========================================================================
   Wenzhe Li — academic site
   Restrained academic serif. Light + dark. Print-optimised.
   ========================================================================== */

/* --- Design tokens ------------------------------------------------------- */
:root {
  --serif: "Source Serif 4", "Source Serif Pro", Charter, "Iowan Old Style",
           "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  /* The Latin serif is listed first so digits, brackets and punctuation come
     from it; the browser falls through to a CJK face only for the Chinese
     characters it cannot render. Without this, SimSun — the usual Windows
     fallback — sets Latin text full-width, which left odd gaps around
     figures like "(3), 91–100". */
  --cjk: "Source Serif 4", "Source Serif Pro", Charter, Georgia,
         "Source Han Serif SC", "Noto Serif CJK SC", "Songti SC",
         "Microsoft YaHei", SimSun, serif;

  /* Light theme */
  --bg:            #fdfcfa;
  --bg-raised:     #ffffff;
  --bg-subtle:     #f5f2ed;
  --ink:           #1a1a18;
  --ink-muted:     #57544e;
  --ink-faint:     #85817a;
  --rule:          #e2ddd4;
  --rule-strong:   #cdc7bb;
  --accent:        #7a2e2e;
  --accent-soft:   #f0e4e4;
  --accent-ink:    #5c2222;
  /* "New" badge. Was amber (#8a5a00 on #fdf3dd) — a third colour family
     beside the oxblood accent and the warm greys, and with seven badges on
     the page it read as a warning label competing with the paper titles.
     Now a tint of the accent, so the palette stays to two families. */
  --new:           var(--accent-ink);
  --new-bg:        var(--accent-soft);

  --measure: 34rem;
  /* Prose spans the full container by author preference. Typographic
     convention would cap this near 75 characters; set a value here (e.g.
     clamp(40rem, 46vw, 44rem)) to reinstate a reading column. */
  --measure-prose: none;
  --page: 76rem;
  --step: 1.6rem;
  --radius: 3px;
  --transition: 140ms ease;
}

/* --- Base --------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 5rem;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 1.0625rem;
  line-height: 1.65;
  font-feature-settings: "kern" 1, "liga" 1, "onum" 1;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; height: auto; display: block; }

a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 32%, transparent);
  transition: border-color var(--transition), color var(--transition), background var(--transition);
}
a:hover { border-bottom-color: var(--accent); }
a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

:lang(zh), .zh { font-family: var(--cjk); }

/* --- Layout ------------------------------------------------------------- */
.wrap {
  max-width: var(--page);
  margin: 0 auto;
  padding: 0 1.75rem;
}
.prose { max-width: var(--measure); }

/* The footer supplies its own top margin; 5rem here stacked with it for a
   ~160px void between the last content and the rule above the footer. */
main { padding-bottom: 0; }

section + section { margin-top: calc(var(--step) * 1.7); }
/* The profile is a header, not a peer of the sections below it, so the
   publications should follow it more closely than section-to-section. */
.profile + section { margin-top: calc(var(--step) * 1.6); }

/* --- Skip link ---------------------------------------------------------- */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: #fff;
  padding: 0.65rem 1.1rem;
  z-index: 100;
  border: 0;
  font-family: var(--sans);
  font-size: 0.875rem;
}
.skip:focus { left: 0.5rem; top: 0.5rem; }

/* --- Site header / nav -------------------------------------------------- */
.masthead {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--rule);
}
.masthead__inner {
  max-width: none;
  margin: 0 auto;
  padding: 0.75rem 1.75rem;
  display: flex;
  align-items: baseline;
  gap: 1.5rem;
  flex-wrap: wrap;
}
.brand {
  font-family: var(--serif);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--ink);
  border: 0;
  white-space: nowrap;
}
.brand:hover { color: var(--accent); border: 0; }

.nav {
  display: flex;
  gap: 1.35rem;
  margin-left: auto;
  align-items: baseline;
  flex-wrap: wrap;
  font-family: var(--sans);
  font-size: 0.8125rem;
  letter-spacing: 0.03em;
}
.nav a {
  color: var(--ink-muted);
  border: 0;
  padding-bottom: 2px;
  border-bottom: 1.5px solid transparent;
}
.nav a:hover { color: var(--ink); border-bottom-color: var(--rule-strong); }
.nav a[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
  border-bottom-color: var(--accent);
}

@media (max-width: 46rem) {
  .masthead__inner {
    display: block;
    padding: 0.7rem 1rem 0.65rem;
  }
  .brand { display: inline-block; margin-bottom: 0.55rem; }
  .nav {
    width: auto;
    max-width: 100%;
    margin-left: 0;
    display: grid;
    grid-template-columns: repeat(3, max-content);
    gap: 1.5rem;
    justify-content: start;
    flex-wrap: nowrap;
  }
}

/* --- Google Site profile composition ----------------------------------- */
/* Spacing above the publications is deliberately tighter than it looks it
   should be: at the earlier values the first paper sat 944px down, so a
   laptop visitor saw the profile and no work at all before scrolling. */
.profile {
  padding: 2.5rem 0 0;
  font-family: var(--sans);
}
.profile__grid {
  display: grid;
  /* The outer columns are deliberately equal, so the name block lands on
     the page's true centre line. Sizing them to their contents instead
     (portrait 16.625rem, logos 13.5rem) left the middle column shoved
     25px toward the narrower side — the header read as centred but the
     name was not. The logo stack is narrower than its column and simply
     centres within it. These three widths plus the gaps fill the page
     exactly. */
  grid-template-columns: 16.625rem 28rem 16.625rem;
  gap: 5.625rem;
  align-items: center;
  justify-content: center;
}
.profile__grid > * { min-width: 0; }
.profile__portrait .portrait {
  width: 16.625rem;
  max-width: none;
  aspect-ratio: 1 / 1;
  border-radius: 0;
}
.profile__details {
  text-align: center;
  color: var(--ink);
}
/* The name is the largest thing on the site — it was previously smaller than
   every page title. Set in the serif that carries the rest of the site, with
   small caps and open letter-spacing rather than plain uppercase. */
.profile__name {
  margin: 0 0 1.15rem;
  font-family: var(--serif);
  font-size: clamp(2.1rem, 4.4vw, 2.9rem);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  font-variant-numeric: lining-nums;
}
.profile__name .zh {
  display: inline-block;
  margin-left: 0.5rem;
  font-family: var(--cjk);
  font-size: 0.62em;
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--ink-muted);
  vertical-align: 0.06em;
  text-transform: none;
}
.profile__lines p {
  margin: 0 0 1rem;
  font-size: 0.9375rem;
  line-height: 1.6;
}
.profile__lines p:last-child { margin-bottom: 0; }
.profile__lines a { color: var(--ink); border-bottom-color: var(--ink-muted); }
.profile__logos {
  display: grid;
  align-items: center;
  gap: 2.1rem;
  /* Narrower than its column (which matches the portrait so the name block
     centres); the stack sits in the middle of the space it is given. */
  width: 13.5rem;
  margin-inline: auto;
}
.profile__logos a {
  display: block;
  border-bottom: 0;
  transition: opacity var(--transition);
}
.profile__logos a:hover { opacity: 0.75; }
/* The cap is a safety rail for a future mark with an odd aspect ratio, not
   a size control — width sets the size. It has to clear the tallest of the
   three (57px at this column width) or it would silently crop the
   official artwork. */
.profile__logos img {
  width: 100%;
  max-height: 4.25rem;
  object-fit: contain;
}

.profile__bio {
  margin-top: 2.5rem;
  font-size: 1.0625rem;
  line-height: 1.75;
  max-width: var(--measure-prose);
  margin-inline: auto;
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
}
.profile__bio p { margin: 0 0 1.15em; }
.profile__bio p:last-child { margin-bottom: 0; }
.profile__links {
  display: grid;
  /* The label column was a fixed 10rem with a 2rem gap — 192px reserved for
     the word "Links:", which squeezed the row below the width the buttons
     need and forced them onto a second line. */
  grid-template-columns: max-content 1fr;
  align-items: center;
  gap: 1.25rem;
  margin-top: 2rem;
  font-size: 0.875rem;
}
/* A quiet line of text rather than a row of buttons. Six outlined boxes read
   as a toolbar and left a wide gap trailing off to the right; separated text
   reads as one line and sits closer to how a journal lists profile links. */
.profile__links .linkrow {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0;
  margin: 0;
}
.profile__links .linkrow li { display: block; }
.profile__links .linkrow a {
  display: inline-block;
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font-weight: 500;
  transition: color var(--transition);
}
.profile__links .linkrow a:hover {
  color: var(--accent-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* The separator sits on the <li>, outside the <a>, so it is neither
   clickable nor underlined on hover. */
.profile__links .linkrow li:not(:last-child)::after {
  content: "·";
  margin: 0 1.15rem;
  color: var(--rule-strong);
  font-weight: 400;
}

@media (max-width: 68rem) {
  .profile__grid {
    /* Equal outer columns here too, so the name block stays centred. */
    grid-template-columns: 12rem minmax(0, 1fr) 12rem;
    gap: 2rem;
  }
  .profile__portrait .portrait { width: 12rem; }
  .profile__logos { width: 10rem; }
}

@media (max-width: 46rem) {
  .profile { padding-top: 4rem; }
  .profile__grid {
    grid-template-columns: 1fr;
    gap: 3.5rem;
    justify-items: center;
  }
  .profile__portrait .portrait { width: min(14rem, 72vw); }
  .profile__details {
    width: min(100%, calc(100vw - 3.5rem));
    min-width: 0;
  }
  .profile__name { letter-spacing: 0.04em; }
  .profile__lines p {
    max-width: 100%;
    font-size: 0.875rem;
    overflow-wrap: anywhere;
  }
  .profile__lines a {
    display: block;
    width: max-content;
    max-width: 100%;
    margin-inline: auto;
    overflow-wrap: anywhere;
  }
  .profile__logos { width: 13.5rem; }
  .profile__bio { margin-top: 4rem; }
  .profile__links {
    grid-template-columns: 1fr;
    gap: 1rem;
    margin-top: 2.5rem;
  }
  /* Centred under the centred header on narrow screens; the flex row above
     already handles wrapping. */
  .profile__links .linkrow {
    justify-content: center;
    gap: 0.5rem;
  }
}

/* --- Hero --------------------------------------------------------------- */
.hero { padding: 3.75rem 0 0; }
.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 12.5rem;
  gap: 3rem;
  align-items: start;
}
@media (max-width: 46rem) {
  .hero { padding-top: 2.5rem; }
  .hero__grid { grid-template-columns: 1fr; gap: 1.75rem; }
  .hero__aside { order: -1; }
}

h1.hero__name {
  font-size: clamp(2.1rem, 5.5vw, 3rem);
  line-height: 1.08;
  margin: 0 0 0.2em;
  font-weight: 600;
  letter-spacing: -0.02em;
}
.hero__name .zh {
  font-size: 0.55em;
  font-weight: 400;
  color: var(--ink-muted);
  letter-spacing: 0.06em;
  margin-left: 0.45em;
  white-space: nowrap;
}
.hero__tagline {
  font-family: var(--sans);
  font-size: 0.875rem;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  margin: 0 0 1.75rem;
}

.hero__lede {
  font-size: 1.1875rem;
  line-height: 1.55;
  margin: 0 0 1.5rem;
  max-width: var(--measure);
}
.hero__lede a { border-bottom-color: color-mix(in srgb, var(--accent) 45%, transparent); }

.portrait {
  border-radius: var(--radius);
  border: 1px solid var(--rule);
  background: var(--bg-subtle);
  aspect-ratio: 4 / 5;
  object-fit: cover;
  width: 100%;
}
.portrait--placeholder {
  display: grid;
  place-items: center;
  font-family: var(--sans);
  font-size: 0.6875rem;
  color: var(--ink-faint);
  text-align: center;
  padding: 1rem;
  line-height: 1.5;
}
@media (max-width: 46rem) {
  .portrait { max-width: 9rem; aspect-ratio: 1 / 1; border-radius: 50%; }
}

/* --- Affiliations ------------------------------------------------------- */
.affil {
  list-style: none;
  margin: 0 0 1.75rem;
  padding: 0;
  font-size: 0.9375rem;
  line-height: 1.5;
}
.affil li { margin-bottom: 0.4rem; padding-left: 0; }
.affil .role { color: var(--ink); }
.affil .org { color: var(--ink-muted); }
.affil .period {
  font-family: var(--sans);
  font-size: 0.75rem;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  margin-left: 0.35rem;
}

.edu-line {
  font-size: 0.9375rem;
  color: var(--ink-muted);
  margin: -0.9rem 0 1.75rem;
}

/* --- Article pages ------------------------------------------------------- */

/* An article page is a single column: title, byline, publication line and
   body all share one axis. */
.article-page .page-title,
.article-page .byline,
.article-page .article-meta {
  max-width: var(--measure-prose);
  margin-inline: auto;
}

/* Author line / Chinese subtitle under the article title. */
.byline {
  font-size: 1.0625rem;
  color: var(--ink-muted);
  margin: -0.35rem 0 1.9rem;
  max-width: var(--measure-prose);
}
.byline:lang(en) { font-family: var(--serif); }
.byline:lang(zh) { font-family: var(--cjk); }

.article-meta {
  font-family: var(--sans);
  font-size: 0.8125rem;
  color: var(--ink-faint);
  margin: 0 0 2.75rem;
  max-width: var(--measure-prose);
}

.article-body {
  max-width: var(--measure-prose);
  margin-inline: auto;
  font-size: 1.0625rem;
  line-height: 1.75;
  /* Justified to give the full-width column flush edges on both sides.
     Hyphenation is essential here: without it, justifying a wide measure
     opens ugly rivers of white space between words. */
  text-align: justify;
  text-justify: inter-word;
  hyphens: auto;
  -webkit-hyphens: auto;
}

/* Hyphenation needs the language declared, and CJK must not be hyphenated —
   it breaks anywhere already. */
.article-body:lang(zh-Hans),
.article-body:lang(zh) {
  hyphens: none;
  -webkit-hyphens: none;
}

/* Bare URLs and short lines justify badly. */
.article-body .reference,
.article-body .footnote,
.article-body pre { text-align: left; hyphens: none; }
.article-body h2 {
  margin-top: 2.25rem;
  text-transform: none;
  letter-spacing: 0.01em;
  font-family: var(--serif);
  font-size: 1.375rem;
  font-weight: 600;
  border-bottom: 0;
  padding-bottom: 0;
  display: block;
}
.article-body p { margin: 0 0 1.15em; }

/* CJK text has no spaces, so a whole paragraph is one unbreakable "word" and
   would otherwise force the page sideways on a phone. */
.article-body:lang(zh-Hans),
.article-body:lang(zh),
.article-body [lang="zh"] {
  line-break: normal;
  word-break: normal;
  overflow-wrap: anywhere;
}

/* A Latin passage inside a Chinese page inherits the CJK serif, whose Latin
   glyphs are uniform-width and read as monospace. Give it the Latin serif. */
.article-body [lang="en"] {
  font-family: var(--serif);
  overflow-wrap: break-word;
}

.article-body .footnote {
  font-size: 0.8125rem;
  color: var(--ink-faint);
  border-top: 1px solid var(--rule);
  padding-top: 0.9rem;
  margin-top: 2rem;
  /* Reference lists carry bare URLs of 100+ characters. */
  overflow-wrap: break-word;
  word-break: break-word;
}

/* Bibliography entries: smaller, hanging indent, and forced to wrap — several
   contain bare URLs over 100 characters that would otherwise push the page
   sideways on a phone. */
.article-body .reference {
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink-muted);
  margin: 0 0 0.65em;
  padding-left: 1.5rem;
  text-indent: -1.5rem;
  overflow-wrap: break-word;
  word-break: break-word;
}
.article-body .reference:lang(en) { font-family: var(--serif); }
.article-body .footnote + .footnote { border-top: 0; padding-top: 0; margin-top: 0; }

/* The closing citation was extracted as a preformatted block and inherited a
   monospace face; it is prose, so it should read as prose. */
.article-body pre {
  font-family: var(--serif);
  font-size: 0.875rem;
  color: var(--ink-faint);
  white-space: pre-wrap;
  overflow-wrap: break-word;
  border-top: 1px solid var(--rule);
  padding-top: 0.9rem;
  margin: 2rem 0 0;
}

/* --- Cities chips (running page) ---------------------------------------- */
/* --- Photo gallery (running page) ---------------------------------------- */
.gallery {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: 1.8rem;
  row-gap: 4rem;
}
.gallery figure { margin: 0; }
.gallery img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius);
  border: 1px solid var(--rule);
}
/* A place name, not a heading — it should sit quietly under its photo rather
   than out-shout the page title. */
.gallery figcaption {
  font-family: var(--sans);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  margin-top: 0.65rem;
  text-align: center;
}

/* Centred like the rest of this page, but at the same size as every other
   page title so the site reads as one thing. */
.running-page .page-title {
  margin: 0 auto;
  padding: 4rem 0 3.25rem;
  text-align: center;
  max-width: none;
}
.running-page .prose {
  max-width: var(--measure-prose);
  margin-inline: auto;
  font-size: 1.0625rem;
  line-height: 1.75;
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
}
.running-page .prose p { margin: 0 0 1.15em; }
.running-page .prose p:last-child { margin-bottom: 0; }
.running-page section { margin-top: 4rem; }
/* Text following a photo row needs room to read as its own passage rather
   than as an oversized caption. */
.running-page section + .prose { margin-top: 4rem; }

@media (max-width: 46rem) {
  .running-page .page-title { padding: 2.5rem 0 2rem; }
  .gallery {
    grid-template-columns: 1fr;
    row-gap: 2rem;
  }
}

/* --- Profile links row -------------------------------------------------- */
.linkrow {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  /* No gap: spacing comes from the separator's own margins. */
  gap: 0;
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--sans);
  font-size: 0.8125rem;
}
/* Separated text rather than boxes, matching the profile links: a row of
   outlined buttons reads as a toolbar and is heavier than these links
   deserve. */
.linkrow a {
  display: inline-block;
  padding: 0;
  border: 0;
  color: var(--ink-muted);
  letter-spacing: 0.02em;
}
.linkrow a:hover {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* On the <li>, not the <a>: inside the link the dot would be clickable and
   would pick up the hover underline. */
.linkrow li:not(:last-child)::after {
  content: "·";
  margin: 0 0.95rem;
  color: var(--rule-strong);
}

/* --- Headings ----------------------------------------------------------- */
h2 {
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-family: var(--sans);
  color: var(--ink);
  margin: 0 0 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--rule);
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  flex-wrap: wrap;
}
h2 .h2__aside {
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.03em;
  text-transform: none;
  color: var(--ink-faint);
  margin-left: auto;
}
h2 .h2__aside a { color: var(--ink-faint); border-bottom-color: var(--rule-strong); }
h2 .h2__aside a:hover { color: var(--accent); }

h3 {
  font-size: 1.125rem;
  font-weight: 600;
  margin: 0 0 0.4rem;
  line-height: 1.3;
  letter-spacing: -0.005em;
}

.page-title {
  font-size: clamp(1.85rem, 4.5vw, 2.4rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 3.25rem 0 0.9rem;
  line-height: 1.2;
  /* Slightly wider than the prose measure: a heading at this size can carry
     more characters per line without becoming hard to track. */
  max-width: 46rem;
  text-wrap: balance;
}
.page-intro {
  color: var(--ink-muted);
  max-width: var(--measure);
  margin: 0 0 2.75rem;
  font-size: 1.0625rem;
}

/* --- News --------------------------------------------------------------- */
.news { list-style: none; margin: 0; padding: 0; }
.news li {
  display: grid;
  grid-template-columns: 5rem 1fr;
  gap: 1rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--rule);
  font-size: 0.9375rem;
  line-height: 1.55;
}
.news li:last-child { border-bottom: 0; }
.news time {
  font-family: var(--sans);
  font-size: 0.75rem;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.03em;
  padding-top: 0.22rem;
  white-space: nowrap;
}
@media (max-width: 34rem) {
  .news li { grid-template-columns: 1fr; gap: 0.2rem; }
  .news time { padding-top: 0; }
}

/* --- Research themes ---------------------------------------------------- */
.themes { display: grid; gap: 1.5rem; }
.theme {
  border-left: 2px solid var(--rule-strong);
  padding: 0.1rem 0 0.1rem 1.25rem;
}
.theme:hover { border-left-color: var(--accent); }
.theme h3 { font-size: 1.0625rem; }
.theme p {
  color: var(--ink-muted);
  margin: 0.35rem 0 0.6rem;
  font-size: 0.9375rem;
  max-width: var(--measure);
}
.theme__count {
  font-family: var(--sans);
  font-size: 0.75rem;
  color: var(--ink-faint);
  letter-spacing: 0.03em;
}
.theme__count a { color: var(--ink-faint); border-bottom-color: var(--rule-strong); }
.theme__count a:hover { color: var(--accent); }

/* --- Publications ------------------------------------------------------- */
.pubgroup + .pubgroup { margin-top: 2.5rem; }
.pubgroup__title {
  font-family: var(--sans);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 0.9rem;
}

.pubs { list-style: none; margin: 0; padding: 0; counter-reset: pub; }

.pub {
  display: grid;
  grid-template-columns: 3.25rem 1fr;
  gap: 1.1rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--rule);
}
.pub:last-child { border-bottom: 0; }
@media (max-width: 34rem) {
  .pub { grid-template-columns: 1fr; gap: 0.3rem; }
}


.pub__year {
  font-family: var(--sans);
  font-size: 0.8125rem;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  padding-top: 0.28rem;
}

.pub__title {
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.38;
  margin: 0 0 0.22rem;
  letter-spacing: -0.004em;
}
.pub__title a { color: var(--ink); border-bottom-color: var(--rule-strong); }
.pub__title a:hover { color: var(--accent); border-bottom-color: var(--accent); }

/* Authors and venue share one line — as separate paragraphs each entry ran to
   five or six lines and the list to nearly 3,000px. The links and badges are
   pushed to the right edge so they form a column that can be scanned without
   reading the citations. */
.pub__cite {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 2rem;
  font-size: 0.9375rem;
  color: var(--ink-muted);
  margin: 0 0 0.1rem;
  line-height: 1.5;
}
/* Takes the space the links leave; without a flex basis a long citation
   wraps underneath them instead of stopping short. */
.pub__cite > .pub__citation-text { min-width: 0; flex: 1 1 auto; }
.pub__authors .self { color: var(--ink); font-weight: 600; }
.pub__venue em { color: var(--ink); font-style: italic; }
/* A second publication of the same article. It sits on the citation line
   beside the first venue and carries the same weight — a lighter colour here
   read as an inconsistency rather than a hierarchy. */
.pub__republished { color: inherit; }
.pub__republished em { color: var(--ink); font-style: italic; }

/* Secondary detail — Chinese title, republication note, conference — on one
   quieter line beneath the citation. */
.pub__aside {
  font-size: 0.8125rem;
  color: var(--ink-faint);
  margin: 0 0 0.1rem;
  line-height: 1.5;
}
.pub__aside .pub__zh { font-family: var(--cjk); }
.pub__aside [lang="zh"] { font-family: var(--cjk); }
.pub__sep { color: var(--rule-strong); margin: 0 0.15rem; }

/* Sits on the citation line rather than occupying a row of its own — boxed
   links were 26px tall against 22px of text, so the row cost a full extra
   line per entry — and is pushed to the right edge to form a scannable
   column. */
.pub__meta {
  font-family: var(--sans);
  font-size: 0.75rem;
  letter-spacing: 0.02em;
  white-space: nowrap;
  flex-shrink: 0;
  text-align: right;
}
.pub__links { display: inline; }
.pub__links a {
  padding: 0;
  border: 0;
  border-bottom: 1px solid var(--rule-strong);
  color: var(--ink-muted);
}
.pub__links a + a { margin-left: 0.55rem; }
.pub__links a:hover { color: var(--accent); border-bottom-color: var(--accent); }

.cites { color: var(--ink-faint); margin-left: 0.7rem; }
.cites a { color: var(--ink-faint); border-bottom-color: var(--rule-strong); }
.cites a:hover { color: var(--accent); }

.tag {
  display: inline-block;
  font-family: var(--sans);
  font-size: 0.6875rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 0.1rem 0.4rem;
  border-radius: var(--radius);
  background: var(--bg-subtle);
  color: var(--ink-faint);
  border: 1px solid var(--rule);
  white-space: nowrap;
}
/* Sits inline on the citation line, so it carries no box: padding and a
   border would push the whole line taller than the text around it. */
.tag--new {
  background: none;
  color: var(--new);
  border: 0;
  padding: 0;
  margin-left: 0.7rem;
  font-weight: 600;
  font-size: 0.6875rem;
}
.tag--theme { cursor: pointer; }
.tag--theme:hover { color: var(--accent); border-color: var(--accent); }

/* Below this width the citation and the links cannot share a line without
   pushing the page wider than the screen, so the links drop underneath and
   align left. Must come after the .pub__cite and .pub__meta rules above:
   equal specificity, so source order decides. */
@media (max-width: 60rem) {
  .pub__cite {
    display: block;
    gap: 0;
  }
  .pub__meta {
    display: block;
    white-space: normal;
    text-align: left;
    margin-top: 0.25rem;
  }
}

/* --- Filters ------------------------------------------------------------ */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin: 0 0 2rem;
  padding: 0;
  list-style: none;
}
.filter {
  font-family: var(--sans);
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  padding: 0.32rem 0.75rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: none;
  color: var(--ink-muted);
  cursor: pointer;
  transition: all var(--transition);
}
.filter:hover { color: var(--ink); border-color: var(--ink-faint); }
.filter[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 500;
}
/* Reserves its line whether or not a filter is active, so the first group
   heading does not jump when filtering. */
.filter-note {
  font-family: var(--sans);
  font-size: 0.8125rem;
  color: var(--ink-faint);
  margin: 0 0 1.75rem;
  min-height: 1.3em;
}

/* --- Notes / callouts --------------------------------------------------- */
.note {
  font-size: 0.875rem;
  color: var(--ink-faint);
  line-height: 1.6;
  background: var(--bg-subtle);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 0.9rem 1.1rem;
  margin: 2rem 0 0;
  max-width: none;
}

/* The note under the publication list: plain small text, as on the original
   site. A bordered panel gave a footnote about download conventions more
   weight than the papers it describes. */
.pub-note {
  font-size: 0.8125rem;
  color: var(--ink-faint);
  line-height: 1.65;
  margin: 2.25rem 0 0;
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
}
.pub-note strong { color: var(--ink-muted); font-weight: 600; }
.pub-note a { color: var(--ink-faint); border-bottom-color: var(--rule-strong); }
.pub-note a:hover { color: var(--accent); }
.note a { color: var(--ink-muted); }

/* --- Article cards ------------------------------------------------------ */
.articles { list-style: none; margin: 0; padding: 0; }
.articles li {
  padding: 1.35rem 0;
  border-bottom: 1px solid var(--rule);
}
.articles li:last-child { border-bottom: 0; }
.articles p {
  color: var(--ink-muted);
  margin: 0.35rem 0 0.65rem;
  font-size: 0.9375rem;
  max-width: var(--measure);
}
.articles .pub__zh { margin-top: 0.1rem; }
/* Both titles are links, but should read as titles rather than as links:
   each keeps its own colour (the heading dark, the Chinese line muted)
   and only picks up the accent on hover. */
.articles__link { color: inherit; border-bottom: 0; }
.articles__link:hover { color: var(--accent); }

/* --- CV ----------------------------------------------------------------- */
.cv-block { margin-bottom: 2rem; }
.cv-row {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: 1.25rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--rule);
  font-size: 0.9375rem;
}
.cv-row:last-child { border-bottom: 0; }
.cv-row__when {
  font-family: var(--sans);
  font-size: 0.75rem;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  padding-top: 0.25rem;
  letter-spacing: 0.02em;
}
@media (max-width: 34rem) {
  .cv-row { grid-template-columns: 1fr; gap: 0.15rem; }
  .cv-row__when { padding-top: 0; }
}
.print-hint {
  font-family: var(--sans);
  font-size: 0.8125rem;
  color: var(--ink-faint);
  background: var(--bg-subtle);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 0.7rem 1rem;
  margin-bottom: 2.25rem;
  max-width: var(--measure);
}

/* --- Footer ------------------------------------------------------------- */
.foot {
  border-top: 1px solid var(--rule);
  margin-top: 2.5rem;
  padding: 1.4rem 0 2rem;
  font-family: var(--sans);
  font-size: 0.8125rem;
  color: var(--ink-faint);
  line-height: 1.6;
}
.foot__grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2.5rem;
  align-items: baseline;
}
.foot a { color: var(--ink-faint); border-bottom-color: var(--rule); }
.foot a:hover { color: var(--accent); }
.foot__disclaimer { font-size: 0.75rem; }
.foot__bookmarks { display: flex; gap: 1rem; flex-wrap: wrap; }

/* MapMyVisitors widget — a plain image, so it needs no border or chrome. */
/* An unlabelled trailing widget, not a section in its own right — it does not
   need the full section gap above it. */
/* GoatCounter total, shown in the footer beside the copyright. */
.visits {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

.visitors { margin-top: 1.75rem !important; }
.visitors a { border-bottom: 0; display: inline-block; }
.visitors img {
  border-radius: var(--radius);
  max-width: 300px;
}

/* --- Utility ------------------------------------------------------------ */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
[hidden] { display: none !important; }
.scroll-x { overflow-x: auto; }

/* --- Print -------------------------------------------------------------- */
@media print {
  :root {
    --bg: #fff; --bg-raised: #fff; --bg-subtle: #fff;
    --ink: #000; --ink-muted: #333; --ink-faint: #555;
    --rule: #ccc; --rule-strong: #999;
    --accent: #000; --accent-soft: #fff;
  }
  @page { margin: 16mm 15mm; }

  body { font-size: 9.75pt; line-height: 1.4; background: #fff; color: #000; }

  .masthead, .nav, .skip, .filters, .filter-note,
  .print-hint, .foot__bookmarks, .portrait, .hero__aside, .visitors, .visits,
  .no-print { display: none !important; }

  .wrap { max-width: none; padding: 0; }
  .prose, .hero__lede, .page-intro, .note, .theme p, .articles p { max-width: none; }
  .hero { padding-top: 0; }
  .hero__grid { grid-template-columns: 1fr; gap: 0; }

  h1.hero__name, .page-title { font-size: 19pt; margin: 0 0 0.15em; }
  .page-title { margin-top: 0; }
  .page-title .zh, .hero__name .zh { margin-left: 0.4em; font-size: 0.6em; }
  h2 {
    font-size: 9.5pt; margin: 14pt 0 6pt; padding-bottom: 3pt;
    border-bottom: 0.75pt solid #000; break-after: avoid;
  }
  h3, .pub__title { font-size: 10pt; break-after: avoid; }

  section + section { margin-top: 0; }
  .pub, .news li, .cv-row, .articles li {
    padding: 4pt 0; border-bottom: 0.4pt solid #ddd;
    break-inside: avoid; page-break-inside: avoid;
  }
  .pubgroup { break-inside: auto; }
  .pubgroup + .pubgroup { margin-top: 12pt; }

  a { color: #000; border-bottom: 0; text-decoration: none; }
  /* Interface affordances carry no meaning on paper. */
  .pub__links, .cites, .tag, .pub__meta { display: none !important; }
  .foot { margin-top: 12pt; padding: 6pt 0 0; border-top: 0.5pt solid #999; font-size: 7.5pt; }
}
