/* ---------------------------------------------------------------
   Qian Niu — personal site
   Academic minimal: one column, serif body, rules instead of boxes.
   --------------------------------------------------------------- */

:root {
  --bg:          #fdfdfc;
  --bg-subtle:   #f4f3f0;
  --text:        #1c1c1a;
  --text-muted:  #5f5e59;
  --text-faint:  #75736c;   /* 4.66:1 on --bg; #86847d failed WCAG AA at 3.68 */
  --accent:      #2f4a63;
  --accent-soft: #e4eaf0;
  --rule:        #e0dedA;
  --rule-strong: #c9c6bf;

  --serif: Charter, "Bitstream Charter", "Sitka Text", Cambria, Georgia, "Times New Roman", serif;
  --sans:  ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --mono:  ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --measure: 44rem;
  --gutter: clamp(1.25rem, 5vw, 2.5rem);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:          #16171a;
    --bg-subtle:   #1e2024;
    --text:        #e6e5e1;
    --text-muted:  #a5a49e;
    --text-faint:  #8a8983;   /* 5.11:1 on --bg; #7d7c76 failed WCAG AA at 4.28 */
    --accent:      #9fc0dd;
    --accent-soft: #24303c;
    --rule:        #2b2d32;
    --rule-strong: #3c3f45;
  }
}

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

html { scroll-behavior: smooth; scroll-padding-top: 4.5rem; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--serif);
  font-size: 1.0625rem;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }

.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--bg); padding: .6rem 1rem; z-index: 100;
}
.skip-link:focus { left: .5rem; top: .5rem; }

/* ---------- navigation ---------- */

#nav {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--rule);
}
.nav-inner {
  max-width: var(--measure);
  margin: 0 auto;
  padding: .7rem var(--gutter);
  display: flex; align-items: baseline; gap: 1rem;
}
.nav-brand {
  font-family: var(--sans);
  font-weight: 600; font-size: .82rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text); text-decoration: none; white-space: nowrap;
}
.nav-links {
  list-style: none; display: flex; gap: 1.05rem; flex-wrap: wrap;
  margin: 0 0 0 auto; padding: 0;
}
.nav-links a {
  font-family: var(--sans); font-size: .78rem; letter-spacing: .02em;
  color: var(--text-muted); text-decoration: none;
  padding-bottom: 2px; border-bottom: 1.5px solid transparent;
}
.nav-links a:hover { color: var(--text); }
.nav-links a.current { color: var(--text); border-bottom-color: var(--accent); }

@media (max-width: 48rem) {
  .nav-links { display: none; }
  .nav-inner { justify-content: space-between; }
}

/* ---------- layout ---------- */

main { max-width: var(--measure); margin: 0 auto; padding: 0 var(--gutter); }

section { padding: 2.75rem 0; border-top: 1px solid var(--rule); }
section:first-of-type { border-top: none; }

h2 {
  font-family: var(--sans);
  font-size: .78rem; font-weight: 650; letter-spacing: .13em; text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 1.4rem;
}

h3 { font-size: 1.05rem; font-weight: 600; margin: 0 0 .35rem; line-height: 1.35; }

h3.sub {
  font-family: var(--sans);
  font-size: .74rem; font-weight: 650; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-muted);
  margin: 2rem 0 .9rem;
}
h3.sub:first-of-type { margin-top: 0; }

p { margin: 0 0 1.05rem; }
p:last-child { margin-bottom: 0; }

/* ---------- masthead ---------- */

.masthead { padding: clamp(3rem, 9vw, 5rem) 0 2.75rem; border-top: none; }

.masthead-grid {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: clamp(1.5rem, 4vw, 2.75rem);
  align-items: start;
  margin-bottom: 1.6rem;
}

.portrait {
  width: clamp(7.5rem, 15vw, 10rem);
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 5px;
  border: 1px solid var(--rule);
  filter: saturate(.94);
  margin-top: .5rem;
}

@media (max-width: 40rem) {
  .masthead-grid { grid-template-columns: 1fr; gap: 1.5rem; }
  .portrait { order: -1; width: 7rem; margin-top: 0; }
}

.masthead h1 {
  font-size: clamp(2.4rem, 8vw, 3.7rem);
  line-height: 1.02;
  letter-spacing: -0.022em;
  font-weight: 400;
  margin: 0 0 .85rem;
}
/* Uppercase surname needs a touch of tracking back to sit evenly. */
.masthead h1 .surname { font-weight: 700; letter-spacing: 0; }

.role { font-size: 1.06rem; color: var(--text); margin-bottom: .5rem; line-height: 1.45; }
/* Affiliation sits under the role rather than wrapping mid-name. */
.affiliation { color: var(--text-muted); font-size: .97rem; }
.role a { color: inherit; text-decoration-color: var(--rule-strong); }
.role a:hover { color: var(--accent); }

.tagline {
  color: var(--text-muted);
  font-size: 1.02rem;
  max-width: 34rem;
  margin-bottom: 1.6rem;
}
/* Bold in muted grey reads as dirty; give the lead phrase full contrast too. */
.tagline b { font-weight: 650; color: var(--text); }

.contact {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: .35rem 1rem;
  font-family: var(--sans); font-size: .82rem;
}
.contact li { display: flex; align-items: center; }
/* Trailing separators, so a wrapped row never starts with a stray dot. */
.contact li:not(:last-child)::after {
  content: "·";
  color: var(--rule-strong);
  margin-left: 1rem;
}
.contact a { color: var(--text-muted); text-decoration: none; border-bottom: 1px solid var(--rule-strong); padding-bottom: 1px; }
.contact a:hover { color: var(--accent); border-bottom-color: var(--accent); }

/* ---------- research themes ---------- */

/* Coda to the lede, once the three questions have been named. Right-aligned:
   the one deliberate break from the page's left axis, which is what marks it
   as an aside rather than part of the argument. The rule sits on the right,
   where the ragged edge is flush and the two reinforce each other. */
.epigraph {
  text-align: right;
  margin: 0 0 2.2rem;
  padding-right: 1.1rem;
  border-right: 2px solid var(--rule-strong);
}
.epigraph blockquote { margin: 0; }
.epigraph p {
  font-style: italic;
  color: var(--text-muted);
  margin: 0 0 .25rem;
}
.epigraph figcaption {
  font-family: var(--sans); font-size: .78rem;
  color: var(--text-faint);
}
.epigraph cite { font-style: italic; }

/* Tighter than usual: the epigraph below belongs to this paragraph. */
.lede { color: var(--text-muted); margin-bottom: 1.25rem; }

.themes { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.9rem; }
.themes > li { padding-left: 0; }
.themes h3 { display: flex; gap: .55rem; align-items: baseline; }
.numeral {
  font-family: var(--sans);
  font-size: .72rem; font-weight: 700; letter-spacing: .08em;
  color: var(--accent);
  background: var(--accent-soft);
  padding: .18rem .42rem;
  border-radius: 3px;
  position: relative; top: -1px;
}
.themes p { color: var(--text-muted); margin: 0; }

/* Award names in prose: weight only. Italic is reserved for venues, and an
   underline would read as a link. */
.award { font-weight: 650; }

.mono {
  font-family: var(--mono); font-size: .88em;
  background: var(--bg-subtle); padding: .05em .25em; border-radius: 3px;
  color: var(--text);
}

/* ---------- publications ---------- */

/* The scrolling list below supplies its own top padding, so the note keeps only
   a small margin of its own. */
.note { font-size: .88rem; color: var(--text-faint); margin-bottom: .3rem; }

/* Symbol legend sits on its own line under the Scholar note. */
.note .legend { display: block; margin-top: .3rem; }

/* The list is capped at roughly five entries and scrolls for the rest, so the
   section stays short next to its neighbours. The height is a viewport-aware
   cap rather than a fixed count: entries wrap to different numbers of lines. */
.pubs-scroll {
  max-height: min(29rem, 68vh);
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--rule-strong) transparent;
  scrollbar-gutter: stable;
  /* Softens the cut at both edges, which also reads as "more below". The list
     carries matching padding, so at either end of the scroll the faded band
     covers empty space rather than the first or last entry. */
  -webkit-mask-image: linear-gradient(to bottom,
    transparent 0, #000 1.3rem,
    #000 calc(100% - 2.4rem), transparent 100%);
  mask-image: linear-gradient(to bottom,
    transparent 0, #000 1.3rem,
    #000 calc(100% - 2.4rem), transparent 100%);
}
.pubs-scroll:focus-visible { outline-offset: 1px; }

.pubs { margin: 0; padding-left: 1.6rem; display: grid; gap: .95rem; }
.pubs-scroll > .pubs { padding-top: 1.3rem; padding-bottom: 2.4rem; padding-right: .4rem; }
/* Title carries the default (brightest) colour; authors and venue recede. */
.pubs li {
  font-size: .96rem; line-height: 1.52;
  color: var(--text);
  padding-left: .2rem;
}
.pubs li::marker { color: var(--text-faint); font-size: .85em; }
.pubs .authors { color: var(--text-muted); }
.pubs .authors b { font-weight: 700; }
.venue { font-style: italic; color: var(--text-muted); }

.tag {
  display: inline-block;
  font-family: var(--sans); font-size: .68rem; font-weight: 600;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-faint);
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  padding: .06rem .48rem;
  white-space: nowrap;
  position: relative; top: -1px;
}

.pub-link { font-family: var(--sans); font-size: .8rem; white-space: nowrap; }

/* ---------- timelines ---------- */

.timeline { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.15rem; }
.timeline > li { display: grid; grid-template-columns: 7.5rem 1fr; gap: 1.1rem; align-items: baseline; }

.when {
  font-family: var(--sans); font-size: .78rem; letter-spacing: .02em;
  color: var(--text-faint);
  white-space: nowrap;
  padding-top: .18rem;
}
.what { font-size: .99rem; }
.what b { font-weight: 650; }
.where { color: var(--text-muted); font-size: .95rem; }
.detail { display: block; color: var(--text-faint); font-size: .89rem; margin-top: .3rem; line-height: 1.5; }
/* A quiet trailing row: no subheading of its own, but held to the list's columns.
   Baseline alignment does the work here, so the label needs no top padding. */
.langs {
  display: grid; grid-template-columns: 7.5rem 1fr; gap: 1.1rem;
  align-items: baseline;
  margin: 1.3rem 0 0;
  font-size: .95rem; color: var(--text-muted);
}
.langs .label {
  font-family: var(--sans); font-size: .78rem; letter-spacing: .02em;
  color: var(--text-faint);
}

@media (max-width: 34rem) {
  .timeline > li { grid-template-columns: 1fr; gap: .15rem; }
  .when { padding-top: 0; }
  .langs { grid-template-columns: 1fr; gap: .15rem; }
}

/* ---------- service ---------- */

.service-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem 2.5rem; }
@media (max-width: 34rem) { .service-grid { grid-template-columns: 1fr; } }

ul.plain { list-style: none; margin: 0; padding: 0; }
ul.plain li {
  font-size: .95rem; color: var(--text-muted);
  padding: .3rem 0; border-bottom: 1px solid var(--rule);
}
ul.plain li:last-child { border-bottom: none; }


/* ---------- footer ---------- */

footer {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 var(--gutter) 3.5rem;
  font-family: var(--sans); font-size: .78rem; color: var(--text-faint);
}
/* Rule sits on the inner text so it lines up with the section rules above. */
footer p:first-child { border-top: 1px solid var(--rule); padding-top: 2rem; }
footer p { margin: 0 0 .3rem; }
.colophon { opacity: .75; }

/* ---------- print ---------- */

@media print {
  #nav, .skip-link, footer .colophon { display: none; }
  body { font-size: 10.5pt; color: #000; background: #fff; }
  main { max-width: none; }
  section { padding: .9rem 0; break-inside: avoid; }
  a { color: #000; text-decoration: none; }
  .pubs li, .themes p, .where { color: #222; }
  /* Paper has no scrollbar: print every entry. */
  .pubs-scroll { max-height: none; overflow: visible; -webkit-mask-image: none; mask-image: none; }
  .pubs-scroll > .pubs { padding-top: 0; padding-bottom: 0; }
}
