/* minxia-chen.com — single hand-written stylesheet, no frameworks.
   Typography follows netywu.com sizes/hierarchy (2026-08-05 readability
   refresh, supersedes the tonycookson.com reference): Inter body kept (her
   call — she prefers it over Plex Sans), Newsreader for the name, section
   headings, and paper titles, IBM Plex Mono for micro-labels (nav, badge,
   chips, dates, toggles). Headings stay INSEAD green (her call — identity
   colors unchanged, type only). */

:root {
  --ink: #1e1e1e;
  --muted: #565650;        /* warm dark gray for meta text (was #636363; darker = readable at small sizes) */
  --faint: #8a8a80;        /* separators, in-text link underlines */
  --accent: #0d8a60;      /* brightened INSEAD-family green: headings/rules (deep #00684b read near-black) */
  --accent-dark: #0b7a55;  /* link/text green, 5.3:1 on white */
  --deep: #004f39;         /* header/footer bars only — white text keeps it clearly green */
  --rule: #d4d4c8;         /* warm hairline (was #dedad3) */
  --bg: #faf9f6;
  --maxw: 950px;    /* centered content column = portrait (250) + hero gap (5rem) + intro (38.75rem),
                       so every section ends where the bio text ends. Holds only at a 250px
                       portrait — see the note above .hero .intro before changing that width */
  --header-h: 52px; /* live value published by the inline script in index.html */
  --sidepad: clamp(1.25rem, 5vw, 2.5rem);
  --mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
section[id] { scroll-margin-top: calc(var(--header-h) + 12px); }
main > section { margin-top: 4.5rem; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--ink);
  font: 400 16px/1.7 "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

header.site {
  position: sticky; top: 0; z-index: 100;
  background: var(--deep);
  padding: 0 var(--sidepad);
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.18);
}
.header-inner {
  min-height: 52px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 1.5rem;
}
.site-name {
  font-family: "Newsreader", Georgia, serif;
  font-size: 1.15rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.92);
  text-decoration: none;
  margin-right: auto;
}
nav.site a {
  color: rgba(255, 255, 255, 0.72);
  text-decoration: none;
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  margin-left: 1.6rem;
  transition: color 0.18s;
}
nav.site a:hover { color: #ffffff; }
nav.site a[aria-current="page"] {
  color: #ffffff;
  border-bottom: 2px solid rgba(255, 255, 255, 0.85);
  padding-bottom: 2px;
}

main {
  width: 100%;
  max-width: calc(var(--maxw) + 2 * var(--sidepad));
  margin: 0 auto;
  padding: 3rem var(--sidepad) 4rem;
  flex: 1;
}
/* running text is justified (her call 2026-08-05); hyphenation keeps the
   word spacing even in the narrow abstract column. Captions stay ragged
   (.sig figcaption is not a <p>); .cloud-label keeps its centering via
   higher specificity. */
main p { text-align: justify; hyphens: auto; -webkit-hyphens: auto; }

h1 {
  font-family: "Newsreader", Georgia, serif;
  font-size: 2.5rem;
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--accent-dark);
  margin: 0 0 0.35rem;
}
h2 {
  font-family: "Newsreader", Georgia, serif;
  font-size: 1.75rem;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--accent-dark);
  margin: 3rem 0 0;
}
h2::after {
  content: "";
  display: block;
  width: 40px;
  height: 3px;
  border-radius: 2px;
  background: var(--accent);
  margin: 0.75rem 0 1.5rem;
}
h2:first-child { margin-top: 0; }

/* subpage titles: h1 for the document outline, rendered like a section h2 */
/* one-page hierarchy (her pick C, 2026-08-05): top-level sections = larger
   green serif + full-width hairline (echoes the CV's section rules);
   subsection heads = smaller, ink, short dash */
h1.page-title, h2.page-title-h2, .news h2 {
  font-size: 2.2rem;
  color: var(--accent);
  border-bottom: 1px solid var(--rule);
  padding-bottom: 0.6rem;
  margin: 0 0 1.4rem;
}
h1.page-title::after, h2.page-title-h2::after, .news h2::after { display: none; }
#research h2:not(.page-title-h2) {
  font-size: 1.5rem;    /* stays above the 1.375rem paper titles in the hierarchy */
  color: var(--deep);   /* deep INSEAD green (her call: darker than accent-dark) */
  margin-top: 2.6rem;
}
#research h2:not(.page-title-h2)::after {
  width: 34px;
  height: 2.5px;
  margin: 0.5rem 0 1.1rem;
}

a { color: var(--accent); }
a:hover { color: var(--accent-dark); }
/* in-text links: quiet faint underline that turns green on hover (netywu.com detail) */
p a {
  text-decoration: underline;
  text-decoration-color: var(--faint);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
p a:hover { text-decoration-color: var(--accent); }
/* clickable but unhighlighted names (her call — same as the CV's black links) */
a.quiet-link { color: inherit; text-decoration: none; }
a.quiet-link:hover { color: var(--accent); text-decoration: underline; }

/* home */
.hero {
  display: flex;
  gap: 5rem;
  align-items: center;
  flex-wrap: wrap;
}
.hero > picture { flex: 0 0 auto; display: block; line-height: 0; }
.hero img {
  width: 250px;   /* Back to 250 on 2026-09-06 after seeing 160 live: the evening went
                     250 -> 200 -> 160 -> 250, and the last step is her call with the
                     published page in front of her, which beats every measurement
                     below. What 160 was solving is real and is kept here for whoever
                     revisits it: the masthead block (name top to contact-row bottom)
                     is 191px and does not vary with width, the visible figure is
                     width x (666-62)/500 = 1.208 x width, so 191/1.208 = 158 is the
                     width at which photo and masthead are the same height. At 250 the
                     figure is 302 against 191 -- the photo leads, deliberately.
                     Changing this REQUIRES changing BOTH the .hero .intro margin-top
                     below AND the mobile breakpoint -- see the notes on each. */
  height: auto;
  display: block;
}
/* 38.75rem ≈ 81 characters a line, and 250px + 5rem gap + 38.75rem = the 950px
   column, so the bio ends exactly where every section rule below it ends. This
   derivation only holds while the portrait is 250px: at the 200 and 160 tried on
   2026-09-06 the sum fell to 900 and 860 and the hero row left its tail unused
   (invisibly -- the intro holds only the name, role, badge and contact line, the
   longest ~295px, so the 620px cap is never reached, and .bio carries the column
   measure regardless). Worth knowing before changing the width again. */
/* photo.png carries 62 fully transparent rows at its top and none at its bottom,
   so the box is always taller than the figure by width x 62/500 = 0.124 x width
   — 24.8px at 200px, 31px at the old 250px. align-items centres the BOX, so the
   figure's visible centre sits strip/2 BELOW the box centre. A top margin on the
   intro is halved by that same centring, so the rule is simply:

       margin-top = 0.124 x (portrait width)

   which is why 250px takes 1.9375rem (31px), where 200px took 1.55rem and 160px
   took 1.24rem. Verified in headless Chrome at five widths, comparing the
   figure's visible centre against the centre of the name-to-contacts block:
   offset 0.0px at 160/170/180/200/220. NOTE the pre-2026-09-06 pairing was
   250px with a round 2rem, which measured 0.5px off; the rule value is kept
   here instead. Re-measure if the portrait is ever recropped -- a different
   alpha top strip changes the 62. */
.hero .intro { flex: 1 1 20rem; max-width: 38.75rem; margin-top: 1.9375rem; }
.hero .intro > p { font-size: 1rem; line-height: 1.75; }
/* the bio left the masthead once it outgrew the portrait (2026-09-02): a 250px
   photo cannot balance 380 words. It takes the full content column, because that
   is the page's measure — .paper-text and .has-fig carry no width rules, so every
   abstract already runs the full 950px. A narrower bio was the odd block out. */
.bio { margin-top: 2.5rem; }
.bio p { font-size: 1rem; line-height: 1.75; }
/* name + credentials share the first line (baseline-aligned), badge on the
   second (her call, 2026-08-05) */
.name-line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 1.1rem;
  margin: 0 0 0.7rem;
}
.name-line h1 { margin: 0; }
.role {
  font-family: "Newsreader", Georgia, serif;
  font-style: italic;
  font-size: 1.12rem;
  color: var(--muted);
  flex: 0 0 100%;       /* own line under the name */
  margin: 0.2rem 0 0;
}
.pron {                 /* pronunciation hint: an annotation on the name, not part of it */
  font-size: 0.46em;
  font-weight: 400;
  font-style: italic;
  color: var(--muted);
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.market-badge {
  display: inline-block;
  background: #e8f1ed;
  color: var(--accent-dark);
  border: 1px solid #b9d4c9;
  border-radius: 2px;
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.28rem 0.7rem;
  margin-bottom: 1.2rem;
}
/* once the hero stacks, the portrait sits above the text and the masthead
   reads as one centred unit; on wide screens the intro is an off-centre
   column, so centring there would fight the left-aligned prose below */
@media (max-width: 46.125rem) {  /* = 738px, the width at which .hero wraps the portrait above the
                                   intro. This MUST track the portrait width: across 2026-09-06's
                                   250 -> 200 -> 160 -> 250 the wrap ran 738 -> 683 -> 638 -> 738,
                                   and leaving a stale value behind opens a band where the masthead
                                   alignment disagrees with the layout. The value is not derivable
                                   from the flex basis -- the intro shrinks below its basis, so the
                                   wrap is set by its min-content (the badge and contact line). It
                                   is found by bisection in headless Chrome with this query
                                   disabled: wrapped at 738, side by side at 739.
                                   NOTE this is 46.125rem, not the 45rem that stood here before
                                   2026-09-06. That value was 18px short of the real wrap, so
                                   721-738px viewports stacked the hero while leaving the masthead
                                   left-aligned -- a small pre-existing defect, found by bisecting
                                   rather than by trusting the comment. Re-bisect if the portrait
                                   width, the badge text or the contact line changes. */
  .hero > picture { margin-inline: auto; }
  .name-line { justify-content: center; }
  .role { text-align: center; }
  .market-badge { display: block; width: fit-content; margin-inline: auto; }
  .hero .intro { margin-top: 0; }   /* stacked: nothing to centre against */
}
.update-note {
  color: var(--faint);
  font-style: italic;
  font-size: 0.85rem;
  margin: 0 0 1.1rem;
}
/* dense SVG keyword cloud, computed from the papers' full texts (replaces the
   interests line; generator + data: notes/plans/keyword-cloud-data/, method:
   notes/plans/2026-08-04_keyword-cloud.md). Inlined in index.html so it uses
   the page webfonts. Wide 45-term variant on desktop/tablet; portrait 24-term
   variant with larger minimum type on phones. */
/* homepage news: compact dated list under the standard section heading */
.news { margin-top: 3rem; }
.news-list { list-style: none; margin: 0; padding: 0; }
.news-list li {
  display: flex;
  gap: 1.1rem;
  align-items: baseline;
  font-size: 1rem;
  line-height: 1.65;
  margin-bottom: 0.7rem;
}
.news-date {
  flex: 0 0 4.9rem;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.cloud-band { max-width: 46rem; margin: 3rem auto 0; }
.cloud-band svg { display: block; width: 100%; height: auto; opacity: 0.85; }
.cloud-band svg.cloud-tall { display: none; }
.cloud-label {
  text-align: center;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin: 0 0 0.4rem;
}
@media (max-width: 34rem) {
  .cloud-band { margin-top: 1.8rem; max-width: 19rem; }
  .cloud-band svg.cloud-wide { display: none; }
  .cloud-band svg.cloud-tall { display: block; }
}
.contact {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  text-align: left;   /* opt out of main p justification: a link row, not prose */
  /* the separating rule went when the bio left the masthead (2026-09-02) — it
     had divided links from prose above them, and now nothing sits above but the
     badge. It also overhung the bio's right edge, which reads as two grids. */
  margin-top: 1.3rem;
  margin-bottom: 0;   /* the UA default 1em sat inside .intro as dead space, and
                         the hero's align-items:center counted it — visible text
                         rode ~8px high against the portrait. */
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.82rem;
}
.contact a, .contact span { white-space: nowrap; }  /* break at separators, never mid-item */
/* separators are drawn, not typed, so a wrapped row never strands a dot at a
   line end; inline-block keeps them outside the links' underline */
.contact a + a::before {
  content: "·";
  display: inline-block;
  margin: 0 0.95rem;
  color: var(--faint);
}
/* phones: stack the three links centred under the centred masthead, with no
   separators to strand. Must follow the rule above — same specificity. */
@media (max-width: 45rem) {
  .contact { flex-direction: column; align-items: center; gap: 0.55rem; }
  .contact a + a::before { content: none; margin: 0; }
}
/* profile-link glyphs: drawn, not brand logos — monochrome, inherit link colour */
.contact .ico {
  width: 1.05em; height: 1.05em;
  vertical-align: -0.18em;
  margin-right: 0.35em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
}

/* research: statement-on-request line (swap for a PDF chip when the
   statement is ready) */
.stmt-note { color: var(--muted); font-size: 0.95rem; margin: 0 0 1.2rem; }

/* research: expand/collapse-all control — sticky below the header while
   the Research section is on screen, gone once you scroll past it */
.abs-toggle {
  position: sticky; top: calc(var(--header-h) + 8px); z-index: 50;
  text-align: right; margin: -0.5rem 0 1rem;
  pointer-events: none;   /* the full-width strip must not block clicks; the button re-enables */
}
.abs-toggle button {
  pointer-events: auto;
  touch-action: manipulation;
  background: #e8f1ed;             /* market-badge tints: reads as a control */
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.09);
  border: 1px solid #b9d4c9;
  border-radius: 2px;
  color: var(--accent-dark);
  font: 500 0.8rem/1 var(--mono);
  letter-spacing: 0.04em;
  padding: 0.65rem 1rem;           /* ~40px tall tap target */
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.abs-toggle button:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: #ffffff;
}
.abs-toggle button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* research: foldable subsections (Work in Progress, Earlier Work) — closed by
   default; the heading is the toggle, with a green chevron in place of the
   default marker. abstracts.js's expand/collapse-all includes these. */
details.sec-fold {
  /* undo the abstract-card look the generic details rule applies */
  background: none;
  box-shadow: none;
  border-radius: 0;
  padding: 0;
  margin-top: 0;
}
.sec-fold > summary {
  list-style: none;
  cursor: pointer;
  /* undo the mono/uppercase abstract-summary treatment */
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: normal;
  text-transform: none;
  color: inherit;
}
.sec-fold[open] > summary { color: inherit; }
.sec-fold > summary::-webkit-details-marker { display: none; }
.sec-fold > summary h2 { display: inline-block; }
.sec-fold > summary h2::before {
  content: "▸";
  color: var(--accent);
  font-family: var(--mono);
  font-size: 0.8em;
  margin-right: 0.55rem;
  vertical-align: 0.1em;
}
.sec-fold[open] > summary h2::before { content: "▾"; }
.sec-fold > summary:hover h2 { color: var(--accent); }

/* research: papers as a hairline-separated list */
.paper {
  padding: 1.4rem 0;
  margin: 0;
  border-bottom: 1px solid var(--rule);
}
h2 + .paper, h2 + article.paper { border-top: 1px solid var(--rule); }
.paper h3 {
  font-family: "Newsreader", Georgia, serif;
  font-size: 1.375rem;    /* 22px, netywu.com paper-title size */
  font-weight: 500;
  line-height: 1.35;
  margin: 0 0 0.3rem;
}
.paper h3 a { color: inherit; text-decoration: none; transition: color 0.15s; }
.paper h3 a:hover { color: var(--accent); }
.paper-links { margin: 0.15rem 0 0.5rem; }
.paper-links a {
  display: inline-block;
  border: 1px solid var(--rule);
  border-radius: 2px;
  color: var(--accent-dark);
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 0.22rem 0.55rem;
  margin-right: 0.35rem;
  transition: color 0.15s, border-color 0.15s;
}
.paper-links a:hover { color: var(--accent); border-color: var(--accent); }
/* paper-link chips — LOCKED color scheme (site rule, 2026-08-04):
     .pl-paper  green (same tints as .market-badge) — our own files: Paper (PDF), Slides (PDF)
     .pl-ssrn   SSRN navy                           — SSRN links
     .pl-pub    burgundy                            — publisher / published-version links
   Order within a row: Paper · Slides · SSRN · Published version.
   Reuse these classes for every paper; do not invent new chip colors. */
.paper-links a.pl-paper { color: var(--accent-dark); border-color: #b9d4c9; background: #e8f1ed; }
.paper-links a.pl-paper:hover { border-color: var(--accent); color: var(--accent); }
.paper-links a.pl-ssrn { color: #1d3c6e; border-color: #b6c4dd; background: #e9eef6; }
.paper-links a.pl-ssrn:hover { border-color: #1d3c6e; color: #16305a; }
/* journal-name chips italic — journal titles/abbreviations are italic by
   citation convention, and the CV's \chippub macro already matches */
.paper-links a.pl-pub { color: #722f37; border-color: #d6b6ba; background: #f6edee; font-style: italic; }
.paper-links a.pl-pub:hover { border-color: #722f37; color: #5d262d; }
/* inactive-paper marker (her call 2026-08-06: the early syndicated-loan WP
   sits under Work in Progress, flagged as dormant) */
.status-tag {
  display: inline-block;
  font: 500 0.65rem/1 var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 0.18rem 0.45rem;
  margin-left: 0.45rem;
  vertical-align: 0.1em;
}
.paper .meta {
  color: var(--muted);
  font-size: 1rem;    /* netywu.com author-line size — faculty can read who wrote it */
  margin: 0 0 0.35rem;
}
.paper p.blurb { color: #4b6b5b; font-size: 1rem; line-height: 1.7; margin: 0.4rem 0 0.6rem; }
/* unfolded abstract: text in the left column; the right column is reserved
   for a future headline figure from each paper (drop a .sig figure in). */
.abs-cols { display: flex; flex-wrap: wrap; gap: 1rem 2.5rem; align-items: flex-start; }
.abs-cols > p, .abs-cols > .blurb { flex: 1 1 26rem; max-width: 48rem; margin: 0.4rem 0 0; }
.abs-cols > .sig { flex: 1 1 22rem; max-width: 30rem; margin: 0.4rem 0 0; }
details {
  margin-top: 0.5rem;
  border-radius: 8px;
  background: #ffffff;   /* white reading panel: cream made long text hard */
  box-shadow: 0 1px 4px rgba(30, 30, 30, 0.07);
  padding: 0.85rem 1.25rem 0.95rem;
}
details summary {
  cursor: pointer;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
details[open] summary { color: var(--accent-dark); }
details p { font-size: 1rem; line-height: 1.75; color: var(--ink); }
.sig { margin: 1rem auto 0; max-width: 30rem; }
.sig img {
  width: 100%;
  height: auto;   /* the width/height ATTRIBUTES only feed the aspect ratio;
                     without this, attr height=1000px stretches the image */
  display: block;
  /* figures render with their white background multiplied away, so charts
     sit directly on the cream page — no card, no border */
  mix-blend-mode: multiply;
}
.sig figcaption {
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.5;
  margin-top: 0.45rem;
}

/* figure carousel inside the .sig slot (assets/carousel.js).
   Progressive enhancement: the markup is a plain stack of .fc-slide
   figures, each with its own caption — with JS off they simply stack.
   carousel.js adds .fc-ready (collapse to one slide) and builds the
   controls row. Slides swap by display toggling, never by transform or
   opacity: a transformed/faded ancestor would create a stacking context
   and break the imgs' mix-blend-mode: multiply against the cream page
   (white chart backgrounds would reappear as white boxes). */
.fc-slide { margin: 0; }
.fc-slide + .fc-slide { margin-top: 1.2rem; }   /* no-JS stack spacing */
.fig-carousel.fc-ready .fc-slide { display: none; margin-top: 0; }
.fig-carousel.fc-ready .fc-slide.is-active { display: block; }
/* fixed-ratio frame: house figures are 1600x1000 (8:5); locking the frame
   means captions/controls never jump between slides */
.fig-carousel.fc-ready .fc-slide a { display: block; aspect-ratio: 8 / 5; }
.fig-carousel.fc-ready .fc-slide img { height: 100%; object-fit: contain; }
/* reserve caption lines so the controls row does not jitter */
.fig-carousel.fc-ready .fc-slide figcaption { min-height: 5.5em; }
/* vertical page scroll stays native; only horizontal swipes are ours */
.fig-carousel .fc-slides { touch-action: pan-y; position: relative; }

/* hover edge arrows over the image (inline carousels AND the popup).
   Positioned buttons are siblings of the imgs, never ancestors, so the
   multiply blend is untouched. Hidden where hover doesn't exist (touch
   devices swipe instead). */
.fc-edge {
  position: absolute; top: calc((100% - 6rem) / 2);  /* center of the image
             box: the caption below reserves ~6rem inside the slide (rem,
             not em — em would scale with the arrow glyph size) */
  transform: translateY(-50%);
  width: 3.2rem; height: 6rem;     /* generous transparent hit area */
  display: flex; align-items: center; justify-content: center;
  background: transparent;
  border: none;
  color: rgba(30, 30, 30, 0.3);    /* alpha ink: the figure reads through it */
  font: 400 3.6rem/1 "Helvetica Neue", Helvetica, Arial, sans-serif;
  padding: 0;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s, color 0.15s;
  z-index: 5;
  touch-action: manipulation;
}
.fc-edge:hover { color: var(--accent); }
.fc-edge-prev { left: 2px; }
.fc-edge-next { right: 2px; }
.fc-slides:hover .fc-edge,
.fc-lb-imgwrap:hover .fc-edge,
.fc-edge:focus-visible { opacity: 1; }
.fc-edge:hover { color: var(--accent); border-color: var(--accent); }
.fc-lb-imgwrap { position: relative; }
.fc-lb-imgwrap .fc-edge { top: 50%; font-size: 4.4rem; width: 3.6rem; }  /* wrapper holds only the image */
@media (hover: none) { .fc-edge { display: none; } }

.fc-controls { display: flex; align-items: center; gap: 0.6rem; margin-top: 0.55rem; }
.fc-controls button {
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: 2px;
  color: var(--accent-dark);
  font: 500 0.8rem/1 var(--mono);
  padding: 0.3rem 0.6rem;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.fc-controls button:hover { color: var(--accent); border-color: var(--accent); }
.fc-count {
  font: 500 0.72rem/1 var(--mono);
  letter-spacing: 0.08em;
  color: var(--muted);
  white-space: nowrap;
}
.fc-dots { display: flex; gap: 7px; margin-right: auto; }
.fc-dots button {
  width: 9px; height: 9px; padding: 0; border-radius: 50%;
  border: 1.5px solid #b9c7bf; background: var(--bg);
  transition: background 0.2s, border-color 0.2s;
}
.fc-dots button:hover { border-color: var(--accent); }
.fc-dots button[aria-current="true"] { background: var(--accent); border-color: var(--accent); }
/* first-visit affordance: the next arrow pulses twice when the abstract
   first opens; animating the button is blend-safe (not an img ancestor) */
@keyframes fc-nudge {
  0%, 100% { transform: none; }
  50% { transform: translateX(3px); }
}
.fc-next.fc-hint { animation: fc-nudge 1.1s ease 0.6s 2; }
@media (prefers-reduced-motion: reduce) { .fc-next.fc-hint { animation: none; } }

/* lightbox: click any .fig-carousel slide (multi-slide carousels AND
   single-figure entries wrapped in the same markup) to enlarge it in a
   centered popup card over a dimmed backdrop; multi-slide instances keep
   their navigation inside the popup. The card is white, so the imgs'
   multiply blend renders as on paper. */
.fig-carousel .fc-slide img { cursor: zoom-in; }
.fc-lightbox {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(30, 30, 26, 0.45);
  display: flex; align-items: center; justify-content: center;
  padding: clamp(1rem, 4vw, 3rem);
}
.fc-lightbox[hidden] { display: none; }
.fc-lb-panel {
  position: relative;
  background: #ffffff;
  border-radius: 10px;
  box-shadow: 0 14px 48px rgba(20, 20, 16, 0.3);
  padding: 1.5rem 1.7rem 1.1rem;
  max-width: min(960px, 94vw);
  max-height: 92vh;
  overflow: auto;
}
.fc-lb-fig { margin: 0; }
.fc-lb-fig img {
  display: block; width: 100%; max-height: 66vh;
  object-fit: contain; mix-blend-mode: multiply;
}
.fc-lb-fig figcaption {
  font-size: 0.92rem; color: var(--muted); line-height: 1.55;
  margin: 0.7rem auto 0; max-width: 44rem;
}
.fc-lb-controls { margin-top: 0.9rem; justify-content: center; }
.fc-lb-close {
  position: absolute; top: 10px; right: 10px;
  z-index: 6;      /* above the image, which is later in the DOM — without
                      this the img overlap made part of the button dead */
  width: 2.5rem; height: 2.5rem;           /* 40px tap target */
  display: flex; align-items: center; justify-content: center;
  background: #ffffff;
  border: 1px solid var(--rule);
  border-radius: 2px;
  color: var(--muted);
  font: 500 1.3rem/1 var(--mono);
  padding: 0;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}
.fc-lb-close:hover { color: var(--accent); border-color: var(--accent); }
/* no 300ms double-tap-zoom delay on any carousel/popup control */
.fc-controls button, .fc-dots button, .fc-lb-close { touch-action: manipulation; }
.fc-controls button:focus-visible, .fc-dots button:focus-visible,
.fc-lb-close:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}

/* teaching */
.teach-block { margin-bottom: 2rem; }
.teach-block h3 {
  font-family: "Newsreader", Georgia, serif;
  font-size: 1.25rem;
  font-weight: 500;
  margin: 0 0 0.6rem;
}
.teach-block ul { margin: 0; padding-left: 1.2rem; }
.teach-block li { margin-bottom: 0.45rem; font-size: 1rem; }
.teach-note { color: var(--muted); font-size: 0.9rem; }
/* teaching rows: text left, year right — mirrors the CV layout */
.teach-row { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; margin-bottom: 0.7rem; }
.teach-main { font-size: 1rem; }
.teach-eval { font-style: italic; color: var(--muted); }
.teach-year { font-size: 1rem; white-space: nowrap; }

footer.site {
  margin-top: auto;
  background: var(--deep);
  color: rgba(255, 255, 255, 0.6);
  text-align: center;
  font-family: var(--mono);
  font-size: 0.75rem;
  padding: 2rem var(--sidepad);
}
footer.site a { color: rgba(255, 255, 255, 0.85); }
footer.site .footer-inner { margin: 0 auto; }

@media (max-width: 34rem) {
  .hero { gap: 1.4rem; }
  h1 { font-size: 2rem; }
  h2 { font-size: 1.5rem; }
  .paper h3 { font-size: 1.25rem; }
}

/* right-edge section rail: a miniature table of contents in the margin.
   Dots sit on a faint hairline spine; section names are set like the header
   nav (letterspaced small caps). Every section in view shows its name; the
   one under the reading line gets the accent treatment. */
.spy-rail {
  position: fixed; right: 20px; top: 50%;
  transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 18px; z-index: 90;
}
.spy-rail::before {
  content: ""; position: absolute; top: 5px; bottom: 5px; right: 4px;
  width: 1px; background: var(--rule);
}
.spy-rail a {
  position: relative;
  display: block; width: 9px; height: 9px;
}
.spy-rail a::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  border: 1.5px solid #b9c7bf; background: var(--bg);
  transition: background 0.2s, border-color 0.2s, transform 0.2s;
}
.spy-rail a:hover::before,
.spy-rail a.in-view::before { border-color: var(--accent); }
.spy-rail a.in-view::before { background: rgba(13, 138, 96, 0.22); }
.spy-rail a[aria-current="page"]::before {
  background: var(--accent); border-color: var(--accent); transform: scale(1.25);
}
.spy-rail a::after {
  content: attr(data-label);
  position: absolute; right: calc(100% + 14px); top: 50%;
  transform: translate(6px, -50%);
  font: 500 0.6rem/1 var(--mono);
  text-transform: uppercase; letter-spacing: 0.16em;
  white-space: nowrap;
  color: var(--muted);
  background: var(--bg);
  padding: 3px 2px 3px 6px; border-radius: 3px;
  opacity: 0; pointer-events: none;
  transition: opacity 0.2s, transform 0.2s;
}
.spy-rail a:hover::after,
.spy-rail a.in-view::after,
.spy-rail a[aria-current="page"]::after {
  opacity: 1; transform: translate(0, -50%);
}
.spy-rail a[aria-current="page"]::after { color: var(--accent-dark); }
@media (prefers-reduced-motion: reduce) {
  .spy-rail a::before, .spy-rail a::after { transition: none; }
}
@media (max-width: 64rem) { .spy-rail { display: none; } }
