/* ==========================================================================
   liqinye.github.io — site stylesheet
   Palette "Xuan paper & ink": warm ivory paper, warm ink, Tiffany-blue
   links, one vermilion seal. Type: Newsreader (serif) + Inter (UI); Lusitana for the name only; Forum for the hidden motto.
   ========================================================================== */

/* ---------- Fonts (self-hosted Google latin subsets; Newsreader/Inter variable, Lusitana static) ---------- */
@font-face { font-family: "Newsreader"; font-style: normal; font-weight: 200 800; font-display: swap;
  src: url(../fonts/newsreader-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Newsreader"; font-style: normal; font-weight: 200 800; font-display: swap;
  src: url(../fonts/newsreader-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Newsreader"; font-style: italic; font-weight: 200 800; font-display: swap;
  src: url(../fonts/newsreader-italic-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Newsreader"; font-style: italic; font-weight: 200 800; font-display: swap;
  src: url(../fonts/newsreader-italic-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url(../fonts/inter-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url(../fonts/inter-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Inter"; font-style: italic; font-weight: 100 900; font-display: swap;
  src: url(../fonts/inter-italic-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Lusitana"; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/lusitana-latin-400.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Forum"; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/forum-latin-400.woff2) format("woff2"); unicode-range: U+0000-00FF, U+2018-201D, U+2026; }   /* the hidden motto only (OFL, LICENSE-forum.txt) */
@font-face { font-family: "HanWang LiSu"; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/hanwang-lisu-name.woff2) format("woff2");
  unicode-range: U+8449, U+5229, U+6B3D; }   /* 葉利欽 only: the header name in 王漢宗中隸書 (GPL v2, see fonts/LICENSE-wangfonts.txt), ~2 KB */
@font-face { font-family: "LXGW WenKai TC"; font-style: normal; font-weight: 400; font-display: swap;
  src: url(../fonts/lxgw-wenkai-tc-name.woff2) format("woff2");
  unicode-range: U+8449, U+5229, U+6B3D; }   /* 葉利欽 only: the header name in 霞鷺文楷 (OFL), ~2 KB */

/* ---------- Tokens ---------- */
:root {
  color-scheme: light;
  --paper: #FAF8F2;
  --surface: #F3F0E8;
  --sunken: #ECE8DE;
  --hairline: #E6E2D8;
  --rule: #CFC9BC;
  --faint: #ADA79A;          /* motif axes / ticks: visible but quiet (≈2.1:1 on surface) */
  --ink: #1F1D1A;
  --ink-2: #57544E;
  --ink-3: #6D6961;
  /* links are Tiffany blue. The old site's #0ABAB5 is only 2.3:1 on paper, so the hue is kept and the text darkened: body links
     #0B8F8A (3.7:1), 13px Inter links (.meta a, .more) a step deeper, #0A857F (4.2:1), hover #0A7A75 (4.9:1); the pure Tiffany is
     the underline. Dark: #3CC6C0 (8.7:1), meta #5FD3CE, hover lighter, the underline a muted Tiffany. */
  --accent: #0B8F8A;
  --accent-hover: #0A7A75;
  --accent-meta: #0A807A;   /* 13px meta links: the smallest same-hue step that passes 4.5:1 on paper */
  --underline: #0ABAB5;
  --seal: #AE3A30;
  --seal-cut: #FAF8F2;        /* the carved parts of the 白文 seal: paper in light mode, warm ivory in dark (never the dark paper) */
  --selection: #CDEBE9;
  --notice-bg: #DFF2F0;        /* the temporary notice's highlighter tint (a shade lighter than the selection colour) */
  --media-edge: rgb(0 0 0 / .07);
  --figure-filter: none;       /* paper figures on the cards; dark: brightness(.88) — a paper-matte figure glares on dark paper, so it is dimmed like a print under glass */
  --media-blend: multiply;     /* animated media (GIF) in the card frame is multiplied onto the matte so its white letterboxes as paper; dark: normal */
  --media-matte: var(--surface);   /* …and the matte behind it; dark: the GIF's own off-white at brightness(.88), so the letterbox bars vanish */
  --wordmark-filter: none;     /* the Amazon wordmark is black type: dark mode inverts it (invert + hue-rotate keeps the smile orange) */
  --seal-plate: transparent;   /* dark: a paper-toned disc behind the two seals (the GT ring's interior is transparent, so the navy vanished on dark paper) */
  /* publication link buttons: a soft tint of each link type's colour on paper (bg) and the colour itself for the icon (fg);
     every pair ≥ 3:1 (non-text contrast). arXiv = cinnabar, Code = slate (softer than the ink so the GitHub glyph weighs like
     the outline glyphs), Project page = Tiffany, Hugging Face = a neutral warm tint under the full-colour logo (its fg only tints
     the hover), PDF = grey, Abstract = ochre. */
  --chip-arxiv-fg: #AE3A30;    --chip-arxiv-bg: #EFDBD5;
  --chip-code-fg: #4F4B45;     --chip-code-bg: #E6E4DF;
  --chip-website-fg: #0A857F;  --chip-website-bg: #DCEEEC;
  --chip-data-fg: #947318;     --chip-data-bg: #ECE9E1;
  --chip-pdf-fg: #6D6961;      --chip-pdf-bg: #EAE8E2;
  --chip-abstract-fg: #A86D36; --chip-abstract-bg: #EDE2D4;

  --font-serif: "Newsreader", Georgia, "Iowan Old Style", "Songti SC", "Noto Serif SC", "Noto Serif CJK SC", serif;
  --font-display: "Lusitana", var(--font-serif);   /* the hero name only */
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Noto Sans SC", Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --shell: 60rem;      /* page shell */
  --measure: 38rem;    /* prose measure */
  --col: 8.25rem;      /* ledger left column (dates, venues, periods) */
  --radius: 4px;
}
:root[data-theme="dark"] { color-scheme: dark;
  --paper: #161513; --surface: #1E1D1A; --sunken: #252320; --hairline: #2E2C28; --rule: #3D3A34; --faint: #5A564E;
  --ink: #ECE8DF; --ink-2: #B3AEA3; --ink-3: #8A857B;
  --accent: #3CC6C0; --accent-hover: #6FDAD5; --accent-meta: #5FD3CE; --underline: #2B8683;
  --seal: #C65A4C; --seal-cut: #ECE8DF; --selection: #1F3F3E; --notice-bg: #1C3A39; --media-edge: rgb(255 255 255 / .08);
  --figure-filter: brightness(.88); --media-blend: normal; --media-matte: #DEDBD7; --wordmark-filter: invert(1) hue-rotate(180deg); --seal-plate: #DCDAD5;
  --chip-arxiv-fg: #D98B81;    --chip-arxiv-bg: #412F2B;
  --chip-code-fg: #C9C4BA;     --chip-code-bg: #32302E;
  --chip-website-fg: #5FD3CE;  --chip-website-bg: #243B3A;
  --chip-data-fg: #D9BE6E;     --chip-data-bg: #33302B;
  --chip-pdf-fg: #B3AEA3;      --chip-pdf-bg: #2F2D2A;
  --chip-abstract-fg: #D7A472; --chip-abstract-bg: #403428;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color-scheme: dark;
    --paper: #161513; --surface: #1E1D1A; --sunken: #252320; --hairline: #2E2C28; --rule: #3D3A34; --faint: #5A564E;
    --ink: #ECE8DF; --ink-2: #B3AEA3; --ink-3: #8A857B;
    --accent: #3CC6C0; --accent-hover: #6FDAD5; --accent-meta: #5FD3CE; --underline: #2B8683;
    --seal: #C65A4C; --seal-cut: #ECE8DF; --selection: #1F3F3E; --notice-bg: #1C3A39; --media-edge: rgb(255 255 255 / .08);
    --figure-filter: brightness(.88); --media-blend: normal; --media-matte: #DEDBD7; --wordmark-filter: invert(1) hue-rotate(180deg); --seal-plate: #DCDAD5;
    --chip-arxiv-fg: #D98B81;    --chip-arxiv-bg: #412F2B;
    --chip-code-fg: #C9C4BA;     --chip-code-bg: #32302E;
    --chip-website-fg: #5FD3CE;  --chip-website-bg: #243B3A;
    --chip-data-fg: #D9BE6E;     --chip-data-bg: #33302B;
    --chip-pdf-fg: #B3AEA3;      --chip-pdf-bg: #2F2D2A;
    --chip-abstract-fg: #D7A472; --chip-abstract-bg: #403428;
  }
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { font-size: 17px; background: var(--paper); color: var(--ink); -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }   /* 17px root: every rem-based size (type, measure, shell, spacing) runs ≈ 6% larger than the 16px default; phones go back to 16px (≤680px block) */
html:has(dialog[open]) { overflow: hidden; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } *, *::before, *::after { transition: none !important; animation: none !important; } }
body { margin: 0; font: 400 1.0625rem/1.6 var(--font-serif); font-kerning: normal; font-optical-sizing: auto;
  text-rendering: optimizeLegibility; min-height: 100vh; display: flex; flex-direction: column; }
::selection { background: var(--selection); color: var(--ink); }
img, svg, video { display: block; max-width: 100%; }
[id] { scroll-margin-top: 5.5rem; }   /* the pinned header (≈ 4rem) + 1.5rem of air above a jumped-to heading */
a { color: var(--accent); text-decoration: underline; text-decoration-thickness: 1px; text-decoration-color: var(--underline);
  text-underline-offset: 0.18em; transition: color .15s ease, text-decoration-color .15s ease; }
a:hover { color: var(--accent-hover); text-decoration-color: var(--accent-hover); }
a:focus-visible, button:focus-visible, summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
p { margin: 0; max-width: var(--measure); text-wrap: pretty; hyphens: manual; -webkit-hyphens: manual; }
p + p { margin-top: .8em; }
p, li, dd { font-variation-settings: "opsz" 24; }
.hero__bio p { hyphens: auto; -webkit-hyphens: auto; hyphenate-limit-chars: 7 3 3; }
h1, h2, h3, h4 { font-family: var(--font-serif); font-weight: 500; line-height: 1.2; margin: 0; text-wrap: balance; letter-spacing: -0.01em; }
h1 { font-size: clamp(2rem, 1.45rem + 1.8vw, 2.5rem); line-height: 1.1; letter-spacing: -0.014em; }
h2 { font-size: 1.75rem; }
h3 { font-size: 1.3rem; line-height: 1.3; }
strong, b { font-weight: 600; }
em { font-style: italic; }
code, kbd { font-family: var(--font-mono); font-size: .86em; background: var(--surface); padding: .1em .35em; border-radius: 3px; }
hr { border: 0; border-top: 1px solid var(--hairline); margin: 2.5rem 0; }
abbr[title] { text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
.visually-hidden { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.skip { position: absolute; left: 1rem; top: -3rem; background: var(--paper); padding: .5rem .75rem; z-index: 30; font: 500 .8125rem var(--font-sans); }
.skip:focus { top: 1rem; }

/* UI text helpers */
.meta { font-family: var(--font-sans); font-size: .8125rem; line-height: 1.5; color: var(--ink-3); font-variation-settings: normal; font-variant-numeric: tabular-nums lining-nums; letter-spacing: .005em; }
.label { font-family: var(--font-sans); font-size: .75rem; line-height: 1.4; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); font-variation-settings: normal; }
.meta a { color: var(--accent-meta); text-decoration-color: var(--underline); }
.meta a:hover { color: var(--accent-hover); text-decoration-color: var(--accent-hover); }
.sep { color: var(--ink-3); opacity: .55; padding: 0 .35em; }
.nowrap { white-space: nowrap; }
.more { white-space: nowrap; color: var(--accent-meta); text-decoration-color: var(--underline); }
.more:hover { color: var(--accent-hover); text-decoration-color: var(--accent-hover); }
.more .arrow { display: inline-block; width: .75em; height: .75em; margin-left: .3em; vertical-align: -0.05em; stroke: currentColor; fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- Shell ---------- */
.shell { width: 100%; max-width: var(--shell); margin: 0 auto; padding: 0 1.5rem; }
main { flex: 1 0 auto; }

/* ---------- Header / nav ---------- */
.site-header { position: sticky; top: 0; z-index: 20; background: var(--paper); padding: .8125rem 0; border-bottom: 1px solid var(--rule); }   /* 13px above and below the ~37px nav row: the header is ≈ 64px with its rule; it stays pinned while the page scrolls (solid paper, so text never shows through) */
.site-header .shell { display: flex; align-items: center; gap: 1rem 2rem; }
/* brand: a small "Liqin Ye" in Lusitana (the hero name's face) as the home link at the far left of every page except the home page,
   which has no brand — the hero carries the name and the seal. Ink at rest, seal red on hover. */
.brand { display: inline-flex; align-items: center; font: 400 1.125rem/1 var(--font-display); letter-spacing: .01em; color: var(--ink); text-decoration: none; padding: .25rem 0; margin: -.25rem auto -.25rem 0; transition: color .15s ease; white-space: nowrap; }
.brand:hover, .brand:focus-visible { color: var(--seal); }
.site-nav { display: flex; align-items: center; gap: 1.5rem; min-width: 0; }
.site-header--home .site-nav { margin-left: auto; }   /* no brand on the home page: the nav still sits at the right */
.site-nav a { font-family: var(--font-sans); font-size: .75rem; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2); text-decoration: none; padding: .5rem 0; border-bottom: 1.5px solid transparent; transition: color .15s ease, border-color .15s ease; }
.site-nav a:hover { color: var(--accent-hover); }
.site-nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--accent); }   /* the current page: ink label on a Tiffany bar */
.theme-toggle { display: inline-grid; place-items: center; width: 2.5rem; height: 2.5rem; margin: -.375rem -.8rem -.375rem -.25rem; color: var(--ink-3); border-radius: 50%; transition: color .15s ease, background .15s ease; }
.theme-toggle:hover { color: var(--ink); background: var(--surface); }
.theme-toggle svg { width: 1rem; height: 1rem; }
.theme-toggle .icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: none; }
}

/* ---------- Seal (印) ---------- */
/* 葉利欽 白文 seal beside the name: a 400×1089 face (the owner's impression, 1:2.72) shown 1.3em tall (em of the h1), centred on the
   cap band. The h1 is a baseline-aligned flex row and an SVG's synthesised baseline is its bottom edge, so the seal first stands on the
   baseline, its margin box is clipped to cap height (margin-top: .714em − H) so the line box keeps its 1.1 line-height, and it is then
   shifted down by (H − .714em)/2 with position: relative so its centre meets the cap-band centre (.357em above the baseline). At 1.3em — the
   face's full ascender-to-descender span — it overhangs the h1's top edge by ≈ .15em and reaches ≈ .29em below the baseline, short of the
   bio, which starts 1.6rem under the h1; on phones the portrait's bottom margin grows by that .15em (≤680px block). Verified in Chrome and Firefox; the flex baseline of an SVG is
   synthesised from its border box, so the negative margin never moves it. */
.seal { --h: 1.3em; width: calc(var(--h) * 400 / 1089); height: var(--h); margin-top: calc(.714em - var(--h)); position: relative; top: calc((var(--h) - .714em) / 2); flex: none; user-select: none; }

/* ---------- Hero ---------- */
/* Three grid items in named areas. Desktop: the text block (name + bio) sits beside the portrait, the profile icons take row 2
   under the text column — centred on the prose measure like the old site; the photo column spans both rows, so the portrait
   (which starts lower than the text, see below) can run past the bio beside the icons without pushing them down.
   ≤680px restacks the same items in one column: photo → name/bio → icons. */
.hero { --name-size: clamp(2.375rem, 1.8rem + 2vw, 3rem);
  padding: 3.5rem 0 0; display: grid; grid-template-columns: minmax(0, var(--measure)) 14rem; justify-content: start;
  grid-template-rows: auto auto auto; grid-template-areas: "text photo" "notice photo" "links photo"; column-gap: 2.5rem; align-items: start; }   /* the text column is the prose measure and the portrait follows 2.5rem after it, anchored to the text rather than the page edge */
.hero__text { grid-area: text; }
.hero__name { display: flex; align-items: baseline; gap: .5em; flex-wrap: nowrap; font: 400 var(--name-size)/1.1 var(--font-display); letter-spacing: 0; }
.hero__name-zh { font-family: "Noto Serif SC", "Songti SC", serif; font-weight: 400; font-size: 1.25rem; color: var(--ink-3); letter-spacing: .08em; }
.hero__bio { margin-top: 1.6rem; }
/* Temporary notice (profile.notice): one sentence under the bio, run through a highlighter — the tint wraps each line (box-decoration-break)
   like a marker pen, so it reads as a note on the page rather than a box. Delete the config line and it is gone. */
.notice { grid-area: notice; justify-self: center; margin: 1.5rem 0 0; max-width: none; text-align: center; font-size: 1.0625rem; line-height: 1.75; text-wrap: balance; }   /* one centred line between the bio and the icon row; the sentence is kept short enough to fit the text column on one line */
.notice__text { background: var(--notice-bg); color: var(--ink); padding: .12em .4em; margin: 0 -.1em; border-radius: 3px; -webkit-box-decoration-break: clone; box-decoration-break: clone; }
.hero__bio strong { font-weight: 500; color: var(--ink); hyphens: manual; -webkit-hyphens: manual; white-space: nowrap; }   /* the three short research terms never split across lines */
.email { font-family: var(--font-mono); font-size: .86em; color: var(--chip-website-fg); background: var(--chip-website-bg); padding: .1em .3em; margin-right: -.1em; border-radius: 3px; white-space: nowrap; }   /* "liqiny at gatech dot edu": a set-off monospace span, deliberately not a mailto link. The negative right margin lets the sentence's full stop tuck against the last glyph instead of trailing the tinted box. */
/* Portrait top on the name's BASELINE (the cap-line alignment read too high). Lusitana 400: ascender .956 + descender .341 =
   content area 1.297em; with line-height 1.1 the half-leading is (1.1 − 1.297)/2 = −.0985em, so the baseline sits
   .956 − .0985 = .8575em below the h1's top edge (= the top of the text block and of this grid row): the name stands on the
   photo's top edge, 2.1rem lower than before. */
.portrait { grid-area: photo; margin: calc(var(--name-size) * .8575) 0 0; }
.portrait img { width: 100%; height: auto; aspect-ratio: 593 / 640; object-fit: cover; border-radius: var(--radius); outline: 1px solid var(--media-edge); outline-offset: -1px; background: var(--surface); }
/* Hidden motto under the portrait: "Focus on Yourself" + a crossed-fingers glyph (profile.motto; _includes/icons/fingers-crossed.svg,
   the Noto Emoji line glyph, OFL). The text is transparent and surfaces only when selected (::selection paints it ink on the selection tint);
   the glyph cannot be selected as text, so footer.html toggles .is-selected on the paragraph whenever the selection touches it. */
.motto { margin: .75rem 0 0; text-align: center; font: 400 1rem/1.4 "Forum", var(--font-serif); letter-spacing: .02em; color: transparent; white-space: nowrap; }   /* Forum: a light Roman display face, the owner's pick from the typeface boards */
.motto::selection, .motto *::selection { color: var(--ink); background: var(--selection); }
.motto__icon { display: inline-block; height: 1.15em; width: auto; vertical-align: -.2em; margin-left: .3em; color: transparent; transition: color .15s ease; }   /* the Noto line glyph */
.motto.is-selected .motto__icon { color: var(--ink); }
/* Profile row: 48px outline glyphs (stroke thinned to 1.5 on the 24-unit grid = 3px here) in 64px round hit areas, 4.5rem apart
   (136px centre to centre; the row spans 472px ≈ 78% of the 38rem measure), centred on the prose measure under the bio, and set
   tight: .75rem above the discs (the glyphs start 20px under the bio's last line box) and −1.5rem below (News measures from the glyphs). */
.social { grid-area: links; display: flex; justify-content: center; gap: 4.5rem; max-width: var(--measure); margin: .75rem 0 -1.5rem; padding: 0; list-style: none; }
.social a { display: grid; place-items: center; width: 4rem; height: 4rem; color: var(--ink-2); border-radius: 50%; transition: color .15s ease, background .15s ease; }
.social a:hover { color: var(--ink); background: var(--surface); }
.social .icon { width: 3rem; height: 3rem; }
.social .icon [stroke] { stroke-width: 1.5; }

/* ---------- Sections ---------- */
.section { margin-top: 3.25rem; }   /* sections sit 52px apart (was 64) */
.hero + .section { margin-top: 2.75rem; }   /* News follows the profile row, whose discs overhang the hero by 1.5rem: 3.25rem puts the "News" heading box 36px under the glyph boxes — 44px from the glyphs' ink to the N's */
.section__head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding-bottom: .8rem; border-bottom: 1px solid var(--rule); }

/* ---------- Featured project cards ---------- */
.project { display: grid; grid-template-columns: 13.75rem minmax(0, 1fr); gap: 1.25rem 2rem; padding: 1.75rem 0; border-bottom: 1px solid var(--hairline); align-items: center; }   /* the text block is centred on the figure */
.project:last-child { border-bottom: 0; }
/* the figure as a photograph: a fixed 3:2 frame (so a replaced file cannot reflow the card), hairline edge, radius, paper matte */
.project__media { display: block; aspect-ratio: 3 / 2; border-radius: var(--radius); background: var(--surface); outline: 1px solid var(--media-edge); outline-offset: -1px; overflow: hidden; color: inherit; text-decoration: none; }
.project__media svg { width: 100%; height: 100%; }
.project__media img { width: 100%; height: 100%; object-fit: cover; filter: var(--figure-filter); }
/* animated media (`media:` in publications.yml): a 16:9 GIF letterboxed in the 3:2 frame, multiplied onto the matte (light) so its
   off-white background becomes the paper; `isolation` keeps the blend inside the frame */
.project__media--contain { isolation: isolate; background: var(--media-matte); }
.project__media--contain img { object-fit: contain; mix-blend-mode: var(--media-blend); }
.project__figure { position: relative; }
.project__title { font-size: 1.3rem; line-height: 1.3; }
.project__title a { color: inherit; text-decoration: none; }
.project__title a:hover { color: var(--accent-hover); text-decoration: underline; text-decoration-thickness: 1px; text-decoration-color: var(--underline); }
.project__authors { margin-top: .45rem; max-width: none; }
/* Elided author lists expand on request: each "…" is a quiet button (ink-2 like the names, Tiffany on hover with a faint pill) that
   swaps in the full list (one-way: the reveal stays until the page reloads). Without JS the short list simply shows. */
.authors__more { font: inherit; color: inherit; background: none; border: 0; padding: 0 .3em; margin: 0 -.15em; line-height: 1; letter-spacing: .08em; border-radius: 3px; cursor: pointer; transition: color .15s ease, background .15s ease; }
.authors__more:hover, .authors__more:focus-visible { color: var(--accent-meta); background: var(--chip-website-bg); }
.project__meta { margin-top: .25rem; max-width: none; }
.project__meta .venue { color: var(--ink-2); font-weight: 500; }
.project__links { margin-top: .9rem; display: flex; flex-wrap: wrap; gap: .5rem; max-width: none; }
/* link buttons (links.html): 28px icon-only tiles, one soft tint per link type (tokens --chip-*-bg / -fg, set per theme),
   4px radius, the label as tooltip (title) and accessible name. Shared by the home cards and /publications/. */
.chip { display: inline-grid; place-items: center; width: 1.75rem; height: 1.75rem; border-radius: var(--radius); color: var(--chip-fg); background: var(--chip-bg); text-decoration: none; transition: background .15s ease; }
.chip:hover { background: color-mix(in srgb, var(--chip-bg), var(--chip-fg) 14%); }
.chip:focus-visible { border-radius: var(--radius); outline-offset: 2px; }
.chip .icon { width: 1.125rem; height: 1.125rem; }
.chip .icon [stroke] { stroke-width: 2; }   /* the set's 1.7 reads wispy at 18px on a tint; 2 ≈ 1.5px */
.chip .icon--hf { width: 1.25rem; height: 1.25rem; }   /* the full-colour Hugging Face logo: 20px so its face matches the 18px glyphs' mass */
.chip--arxiv { --chip-fg: var(--chip-arxiv-fg); --chip-bg: var(--chip-arxiv-bg); }
.chip--code { --chip-fg: var(--chip-code-fg); --chip-bg: var(--chip-code-bg); }
.chip--website { --chip-fg: var(--chip-website-fg); --chip-bg: var(--chip-website-bg); }
.chip--data { --chip-fg: var(--chip-data-fg); --chip-bg: var(--chip-data-bg); }
.chip--pdf { --chip-fg: var(--chip-pdf-fg); --chip-bg: var(--chip-pdf-bg); }
.chip--abstract { --chip-fg: var(--chip-abstract-fg); --chip-bg: var(--chip-abstract-bg); }
.self { color: var(--ink); font-weight: 500; }
sup.eq { font-size: .75em; line-height: 0; vertical-align: .35em; }

/* motif drawing classes (used inside the inline SVGs) */
.m-ink { stroke: var(--ink-2); fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.m-faint { stroke: var(--faint); fill: none; stroke-width: 1.5; stroke-linecap: round; }
.m-accent { stroke: var(--accent); fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.m-accent-fill { fill: var(--accent); }
.m-ink-fill { fill: var(--ink-2); }
.m-faint-fill { fill: var(--faint); }
.m-paper-fill { fill: var(--surface); }
.m-seal-fill { fill: var(--seal); }
.m-dash { stroke-dasharray: 3 4; }
.m-dot { stroke-dasharray: 1 5; stroke-width: 2; }

/* ---------- Ledger rows (news, CV-like lists) ---------- */
.ledger { margin: 0; padding: 0; list-style: none; }
.ledger > li, .row { display: grid; grid-template-columns: var(--col) minmax(0, 1fr); gap: .25rem 1.5rem; padding: 1rem 0; border-bottom: 1px solid var(--hairline); align-items: baseline; }
.ledger > li:last-child, .row:last-child { border-bottom: 0; }
.row__key { font-family: var(--font-sans); font-size: .8125rem; line-height: 1.6; color: var(--ink-3); font-variant-numeric: tabular-nums lining-nums; font-variation-settings: normal; letter-spacing: .005em; }
.row__key .venue { color: var(--ink-2); font-weight: 500; }
.row__title { font-size: 1.0625rem; line-height: 1.4; font-weight: 500; }
.row__title a { color: inherit; text-decoration: none; }
.row__title a:hover { color: var(--accent-hover); text-decoration: underline; text-decoration-color: var(--underline); }
.row__detail { margin-top: .2rem; color: var(--ink-2); font-size: 1rem; max-width: none; }
.row__detail--flush { margin-top: 0; }
.row__note { margin-top: .3rem; max-width: none; }
/* Experience / Education rows (.ledger--org): mark | text. The organisation's mark sits in a fixed 7rem column at the page's
   left text edge; after a 2rem gap the text block starts (so every title begins on one vertical line, 9rem in); each line's
   period or place is right-aligned at the far right of the text block, forming one narrow column at the shell's edge. The mark
   is the logo in its own colours, hugging the left edge of its column, at ONE SIZE for every row: the seals (both PNGs are
   trimmed to the seal's outer edge, so GT and UCI share one scale) are 6rem discs (96px), the Amazon wordmark
   (.org__logo--wide), wide and short, is 7rem wide (112 × 34px) — the column's width. The logo cell stretches to the row
   (align-self: stretch) and the image is absolutely positioned inside it, centred on the row's height; the cell also sets the
   row's floor (min-height 6rem), so a text block shorter than a seal (UCI, three lines ≈ 76px) does not let the disc crowd the
   hairlines — its row grows to the disc and the text is centred on it (align-items: center); taller blocks (GT and Amazon,
   four lines ≈ 97–104px) centre the mark on themselves. Dark mode puts a paper-toned disc behind the seals (--seal-plate;
   transparent in light mode — the GT ring's interior is transparent, so its navy vanished on dark paper) and inverts the black
   wordmark (--wordmark-filter). The mark precedes the text in the source, so the grid auto-places both. Phones (≤680px) keep a
   small fixed box — see below. */
.ledger--org > li { grid-template-columns: 7rem minmax(0, 1fr); gap: 0 2rem; align-items: center; }
.org__line { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0 1.5rem; }
.org__line > :first-child { min-width: 0; }
.org__line .row__detail { margin-top: .15rem; }
.org__when { flex: none; margin-left: auto; white-space: nowrap; text-align: right; }
.degrees { margin: 0; padding: 0; list-style: none; }
.org__body .row__note + .row__note { margin-top: .1rem; }
.org__logo { position: relative; display: block; align-self: stretch; min-height: 6rem; }   /* the row is never shorter than a seal */
.org__logo img { position: absolute; top: 50%; left: 0; translate: 0 -50%; object-fit: contain; object-position: left center; }
.org__logo:not(.org__logo--wide) img { width: 6rem; height: 6rem; border-radius: 50%; background: var(--seal-plate); }   /* every seal a 96px disc (the dark-mode plate is the same disc) */
.org__logo--wide img { width: 7rem; height: auto; filter: var(--wordmark-filter); }   /* the wordmark fills the 7rem column */

/* news */
.news > li { padding: .8rem 0; }
.news .row__text { font-size: 1rem; line-height: 1.55; max-width: var(--measure); }
.news .row__text strong { font-weight: 500; }
/* a project's own mark in place of the emoji (`icon:` in news.yml): the box is the emoji's ink box — Apple Color Emoji at the
   16px news size draws 20 × 20px, from 1em above the baseline to .25em below — so the mark takes the same room and the text after
   it starts on the same x as in the emoji rows. The SVGs keep ~6% air inside the box (the dojo swirl spans 56/64 of its viewBox,
   the α 25.5/29), so they read a touch lighter than a full-bleed emoji. The marks are inlined (_includes/news-icons/), so the
   AlphaBet α is stroked in currentColor and follows the text ink in both themes; the Forecast-Dojo swirl keeps its own orange. No tile. */
.news__icon { display: inline-block; width: 1.25em; height: 1.25em; vertical-align: -.25em; }
/* year headings (news and publications pages): a quiet divider one step below the 1.75rem section titles */
.year { margin-top: 2.5rem; padding-bottom: .5rem; border-bottom: 1px solid var(--rule); font-size: 1.25rem; color: var(--ink-2); }
.year:first-of-type { margin-top: 2rem; }

/* publications page: one stacked entry per paper (title / authors / venue line / chips) under its year */
.publist { margin: 0; padding: 0; list-style: none; }
.pub { padding: 1.2rem 0; border-bottom: 1px solid var(--hairline); }
.pub:last-child { border-bottom: 0; }
.pub__title { font-size: 1.125rem; line-height: 1.35; }
.pub__title a { color: inherit; text-decoration: none; }
.pub__title a:hover { color: var(--accent-hover); text-decoration: underline; text-decoration-thickness: 1px; text-decoration-color: var(--underline); }
.pub__authors { margin-top: .35rem; max-width: none; }
.pub__meta { margin-top: .2rem; max-width: none; }
.pub__meta .venue { color: var(--ink-2); font-weight: 500; }
.pub__links { margin-top: .75rem; display: flex; flex-wrap: wrap; gap: .5rem; max-width: none; }

/* compact two-column blocks (teaching / honors + service) */
.cols { --col: 6.5rem; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 2.5rem; }
.cols .section { margin-top: 3.25rem; }
/* Honors + Service = Teaching in height. Both columns stretch to the row; whichever is shorter fills in: the right column
   keeps Honors at its natural height and pushes Service to the column's end (auto 1fr); the left column lets its list fill
   the same height as a flex column whose rows share the slack. So that the two columns' INK starts and ends on the same lines
   too (not only their boxes), the first and last Teaching rows take half a share each and keep their text at the ledger's
   outer edges (1rem in, exactly like the Honors and Service rows beside them), the rows between take a full share with their
   text centred: every hairline sits midway between the texts above and below it, and both lists end on the same pixel. */
.cols > .section:first-child { display: grid; grid-template-rows: auto 1fr; }
.cols > .section:first-child .ledger { display: flex; flex-direction: column; }
.cols > .section:first-child .row { flex: 2 0 auto; align-content: center; }
.cols > .section:first-child .row:first-child { flex-grow: 1; align-content: start; }
.cols > .section:first-child .row:last-child { flex-grow: 1; align-content: end; }
.cols__stack { display: grid; grid-template-rows: auto 1fr; }
.cols__stack > .section:last-child { align-self: end; }

/* ---------- Footer ---------- */
.site-footer { margin-top: 5rem; border-top: 1px solid var(--rule); padding: 1.4rem 0 2.5rem; }
.site-footer .shell { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem 2rem; flex-wrap: wrap; }
.site-footer p { max-width: none; }
.site-footer p + p { margin-top: 0; }

/* ---------- Page (news / misc / publications) ---------- */
.page-head { padding-top: 3.25rem; }
.page-head--row { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem 1rem; flex-wrap: wrap; }   /* title left, one quiet link right (publications: Google Scholar) */
.page-head h1 { font-size: clamp(1.9rem, 1.4rem + 1.5vw, 2.25rem); }
.page-head .lede { margin-top: 1rem; color: var(--ink-2); font-size: 1.0625rem; }

/* ---------- Misc (photo collections) ---------- */
.lede--full { max-width: none; }   /* the Misc lede runs the full content width, like the photo rows */
.photoset { margin-top: 3.5rem; }
.photoset:first-of-type { margin-top: 2.75rem; }
.photoset__head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; }
.photoset__head h2 { font-size: 1.375rem; }
.photoset__head .meta { max-width: none; }
.photoset__row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; width: 100%; }   /* three equal tiles per collection */
.frame { aspect-ratio: 1 / 1; min-width: 0; display: block; border-radius: 3px; overflow: hidden; background: var(--sunken); position: relative; }   /* every photo the same square; the lightbox shows the full frame */
.frame img { width: 100%; height: 100%; object-fit: cover; object-position: var(--pos, 50% 50%); transition: opacity .25s ease; }
.frame:hover img { opacity: .92; }
.frame:focus-visible { outline-offset: 2px; }
@media (min-width: 1100px) { .photoset__row { width: 60rem; max-width: calc(100vw - 3rem); margin-inline: calc((100% - 60rem) / 2); } }

/* lightbox */
.lb { border: 0; padding: 0; margin: 0; background: transparent; max-width: 100vw; max-height: 100dvh; width: 100vw; height: 100dvh; color: #fff; }
.lb::backdrop { background: rgb(20 19 17 / .95); }
.lb figure { margin: 0; height: 100%; display: grid; grid-template-rows: minmax(0, 1fr) auto; place-items: center; padding: 2.5rem 3.5rem 1.5rem; pointer-events: none; }
.lb picture { display: block; width: 100%; height: 100%; min-height: 0; }
.lb img { width: 100%; height: 100%; min-height: 0; object-fit: contain; border-radius: 2px; pointer-events: auto; }
.lb figcaption { font: 400 .8125rem/1.5 var(--font-sans); color: rgb(255 255 255 / .72); letter-spacing: .01em; text-align: center; padding-top: .9rem; font-variant-numeric: tabular-nums; pointer-events: auto; }
.lb button { position: absolute; color: rgb(255 255 255 / .7); padding: .75rem; border-radius: 50%; line-height: 0; transition: color .15s ease, background .15s ease; }
.lb button:hover { color: #fff; background: rgb(255 255 255 / .08); }
.lb button svg { width: 1.5rem; height: 1.5rem; stroke: currentColor; fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.lb-close { top: .75rem; right: .9rem; }
.lb-prev { left: .5rem; top: 50%; translate: 0 -50%; }
.lb-next { right: .5rem; top: 50%; translate: 0 -50%; }
.lb button:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* ---------- Responsive ---------- */
@media (max-width: 959px) {
  .cols { grid-template-columns: minmax(0, 1fr); gap: 0; --col: 8.25rem; }
  .cols > .section:first-child .ledger { display: block; }   /* stacked: the Teaching rows keep their natural height */
}
@media (max-width: 860px) {
  .social { gap: 2.5rem; }   /* two-column hero on a narrow screen: 4 × 64px discs + 3 × 40px fit the text column down to 681px */
  .hero { grid-template-columns: minmax(0, 1fr) 12.75rem; column-gap: 2.5rem; }
}
@media (max-width: 680px) {
  html { font-size: 16px; }
  .ledger--org .row__note .sep { display: none; }   /* phones: Mentor and Manager on their own lines instead of a dot stranded at a line end */
  .ledger--org .row__note > .nowrap { display: block; }
  .site-header { padding: .875rem 0; }   /* 14px around the 30px name and the tighter nav */
  .site-header .shell { gap: .5rem 1rem; }   /* still one row — brand left, nav + toggle right — with a tighter nav */
  .site-nav { gap: .35rem 1.25rem; }
  .site-nav a { font-size: .6875rem; letter-spacing: .04em; padding: .35rem 0; }
  .hero { grid-template-columns: minmax(0, 1fr); grid-template-rows: repeat(4, auto); grid-template-areas: "photo" "text" "notice" "links"; padding-top: 2.25rem; }
  .notice { margin-top: 1.25rem; }
  .portrait { width: 10rem; margin: 0 0 calc(2rem + .15 * var(--name-size)); position: relative; }   /* 2rem to the h1 box (room for the revealed motto line) + the seal's .15em overhang */
  .motto { position: absolute; left: 0; right: 0; top: 100%; margin: .25rem 0 0; font-size: .9375rem; }   /* one centred line in the gap under the photo */   /* overlays the gap below the photo instead of widening it */
  .portrait img { aspect-ratio: 1; }
  .social { margin-top: 1rem; gap: 1.5rem; }   /* 4 × 64px discs + 3 × 24px = 328px: fits the 342px column at 390px */
  .section { margin-top: 2.5rem; }
  .project { grid-template-columns: minmax(0, 1fr); gap: 1rem; padding: 1.4rem 0; }
  .ledger > li, .row { grid-template-columns: minmax(0, 1fr); gap: .15rem; }
  .row__key { order: -1; }
  /* organisation rows on phones: the mark keeps its left column, narrowed to 3.5rem + .75rem gap, as a small fixed box
     (seals 44px, the wordmark 56px wide; the image flows normally again instead of stretching with the row) top-aligned with
     the title — the text block stays indented for the whole row, so its left edge is straight and nothing wraps under the
     mark; each period / place sits on its own line directly under its text, left-aligned, instead of a right-aligned column */
  .ledger--org > li { grid-template-columns: 3.5rem minmax(0, 1fr); gap: 0 .75rem; align-items: start; }
  .org__logo { align-self: start; width: 3.5rem; height: 2.75rem; min-height: 0; margin-top: .1rem; }
  .org__logo img { position: static; translate: none; width: 100%; height: 100%; }
  .org__logo:not(.org__logo--wide) img { width: 2.75rem; height: 2.75rem; }
  .org__logo--wide img { width: 3.5rem; height: 100%; object-position: left top; margin-top: .3rem; }   /* the 17px-tall wordmark sits on the title's x-height band rather than mid-box */
  .org__line { display: block; }
  .org__line > * { display: block; }
  .org__when { margin-left: 0; text-align: left; white-space: normal; }
  .org__line .row__detail { margin-top: .4rem; }
  .photoset__head { display: block; }
  .photoset__head .meta { margin-top: .15rem; }
  .photoset__row { grid-template-columns: minmax(0, 1fr); }   /* one square per row on phones */
  .frame { flex: none; width: 100%; }
  .lb figure { padding: 2.5rem 1rem 3.75rem; }
  .lb-prev, .lb-next { top: auto; bottom: .5rem; translate: none; }
}
@media (max-width: 560px) {
  /* two rows: brand left + toggle right, then the nav on its own line (the five labels stay on one row down to ~350px) */
  .site-header { padding: .875rem 0; }
  [id] { scroll-margin-top: 7rem; }   /* two header rows (≈ 91px) + air */
  .site-header .shell { flex-wrap: wrap; row-gap: .3rem; }
  .theme-toggle { order: 1; }
  .site-nav { order: 2; flex: 1 1 100%; flex-wrap: wrap; justify-content: flex-start; }
  /* home page (no brand): the nav and the toggle share the single header row (58px); the nav wraps to two rows below ~340px */
  .site-header--home .shell { flex-wrap: nowrap; }
  .site-header--home .site-nav { order: 1; flex: 1 1 auto; margin: 0; }
  .site-header--home .theme-toggle { order: 2; }
}
@media (max-width: 440px) {
  .site-nav { justify-content: space-between; gap: .35rem; }   /* five links on one row down to ~350px; wrap is the fallback below */
  .section__head { flex-wrap: wrap; }   /* a long title ("Selected Publications") keeps its line; the "All … →" link drops under it, right-aligned */
  .section__head .more { margin-left: auto; }
}
@media (max-width: 390px) {
  .site-nav a { font-size: .65rem; letter-spacing: .03em; }   /* keeps visible gaps between the five labels at 390–360px */
  .social { gap: 1rem; }   /* 4 × 64px + 3 × 16px = 304px: fits the 312px column at 360px */
}
@media (max-width: 350px) {
  .site-nav { justify-content: flex-start; gap: .35rem 1rem; }   /* when the nav must wrap, the second row packs left instead of spreading */
  .social { gap: .75rem; }   /* 56px discs with 40px glyphs again: 4 × 56px + 3 × 12px = 260px fits the 272px column at 320px */
  .social a { width: 3.5rem; height: 3.5rem; }
  .social .icon { width: 2.5rem; height: 2.5rem; }
}

/* ---------- Print ---------- */
@media print {
  :root, :root[data-theme="dark"], :root:not([data-theme="light"]) {
    color-scheme: light;
    --paper: #fff; --surface: #fff; --sunken: #fff; --hairline: #ddd; --rule: #bbb; --faint: #999;
    --ink: #000; --ink-2: #333; --ink-3: #555; --accent: #000; --accent-hover: #000; --accent-meta: #000;
    --underline: #999; --seal: #AE3A30; --seal-cut: #fff; --notice-bg: #eee; --media-edge: rgb(0 0 0 / .15);
    --figure-filter: none; --media-blend: normal; --media-matte: #fff; --wordmark-filter: none; --seal-plate: transparent;
  }
  .site-header, .skip, .more, .lb, .social, .motto { display: none !important; }   /* the e-mail prints inside the bio */
  .chip { background: #fff; color: #333; box-shadow: inset 0 0 0 1px #bbb; }   /* the tinted buttons print as outlined glyphs */
  a { color: inherit; text-decoration: none; }
  h2, h3 { break-after: avoid; }
  .project, .ledger > li, .row, .pub { break-inside: avoid; }
  .site-footer { margin-top: 2rem; }
}
