/* Site customizations for shijie's homepage */

/* ===== Publications: research-list style =====
   After wenlonghuang.com: no card, just rows divided by hairlines. A fixed
   width teaser on the left; on the right the title as a link in serif, the
   full author list with my name in bold, the venue in bold with the year,
   an award line in red, a row of slash-separated text links, and a short
   grey description. Markup comes from the local override in
   `_layouts/bib.liquid`. */

.publications ol.bibliography {
  list-style: none;
  margin: 0;
  padding: 0;
}
.publications ol.bibliography > li {
  padding: 1.5rem 0;
  margin: 0;
  border-bottom: 1px solid var(--global-divider-color);
}
.publications ol.bibliography > li:last-child {
  border-bottom: 0;
}
/* Section headings: publication years / experience sections */
div.publications h2.bibliography,
h2.exp-section {
  padding-top: 0;
  padding-bottom: 0.5rem;
  margin-top: 3rem;
  margin-bottom: 0.5rem;
  text-align: left;
  border-top: 0;
  border-bottom: 1px solid var(--global-divider-color);
}
div.publications h2.bibliography:first-of-type,
section:first-child > h2.exp-section {
  margin-top: 1rem;
}

/* Teaser left at a fixed width, text right filling the rest */
.publications {
  --pub-meta-color: #4a4a4a;
  --pub-teaser-width: 250px;
  --pub-teaser-ratio: 8 / 5;
}
@media (min-width: 576px) {
  ol.bibliography > li > .row {
    align-items: center;
    flex-wrap: nowrap;
  }
  ol.bibliography > li > .row > .col-sm-2 {
    flex: 0 0 var(--pub-teaser-width);
    max-width: var(--pub-teaser-width);
  }
  ol.bibliography > li > .row > .col-sm-8 {
    flex: 1 1 auto;
    max-width: none;
    min-width: 0;
    padding-left: 1.6rem;
  }
}

/* The teaser: a hand-cropped detail of the figure filling an 8:5 plate.
   Crop teasers to roughly this shape before adding them (see
   assets/img/publication_preview/). On desktop, hovering the plate floats
   the full figure in a white card over the entry; clicking zooms it. */
ol.bibliography img.preview,
ol.bibliography video.preview {
  display: block;
  width: 100%;
  aspect-ratio: var(--pub-teaser-ratio, 8 / 5);
  object-fit: cover;
  background: #fff;
  border-radius: 4px;
  box-shadow: none !important;
  cursor: zoom-in;
}
ol.bibliography > li .abbr {
  margin-bottom: 0;
}
ol.bibliography .thumbnail-hover-wrapper {
  position: relative;
  display: block;
}
ol.bibliography .thumbnail-hover-overlay {
  display: none;
  position: absolute;
  top: -8px;
  left: -8px;
  z-index: 300;
  width: min(880px, calc(100vw - 3rem));
  padding: 8px;
  background: #fff;
  border: 1px solid var(--global-divider-color);
  border-radius: 10px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.22);
  pointer-events: none;
}
ol.bibliography .thumbnail-hover-overlay img,
ol.bibliography .thumbnail-hover-overlay video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 6px;
}
/* Video teasers (real-robot clips): a dark plate with a soft lift, and a
   smaller dark hover card so the footage plays at a readable size */
ol.bibliography video.preview {
  background: #000;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16) !important;
}
/* Pills over a video plate: a live-recording dot with the label, and the
   playback speed */
@keyframes preview-live {
  0% {
    box-shadow: 0 0 0 0 rgba(255, 77, 77, 0.6);
  }
  70% {
    box-shadow: 0 0 0 6px rgba(255, 77, 77, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(255, 77, 77, 0);
  }
}
ol.bibliography .thumbnail-hover-wrapper--video .thumbnail-hover-overlay {
  width: min(640px, calc(100vw - 3rem));
  padding: 6px;
  background: #0b0b0b;
  border-color: #222;
}
@media (min-width: 992px) and (hover: hover) {
  ol.bibliography .thumbnail-hover-wrapper:hover .thumbnail-hover-overlay {
    display: block;
    animation: pub-overlay-in 0.18s ease-out;
  }
  /* Lift the hovered row above its siblings so the overlay is never clipped */
  .publications ol.bibliography > li:hover {
    position: relative;
    z-index: 20;
  }
}
@keyframes pub-overlay-in {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
/* Lightbox opened by clicking a teaser (assets/js/pub-figure.js): the full
   figure centred in a white card over the blurred page */
.pub-lightbox {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  background: rgba(246, 243, 236, 0.86);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: zoom-out;
  opacity: 0;
  transition: opacity 0.2s ease;
}
.pub-lightbox.is-open {
  opacity: 1;
}
.pub-lightbox__card {
  margin: 0;
  padding: 10px;
  background: #fff;
  border: 1px solid var(--global-divider-color);
  border-radius: 12px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.28);
  transform: scale(0.96);
  transition: transform 0.22s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.pub-lightbox.is-open .pub-lightbox__card {
  transform: none;
}
.pub-lightbox__card video {
  display: block;
  max-width: min(1200px, 94vw);
  max-height: 86vh;
  width: auto;
  height: auto;
  border-radius: 8px;
  background: #000;
}
.pub-lightbox__card img {
  display: block;
  max-width: min(1200px, 94vw);
  max-height: 86vh;
  width: auto;
  height: auto;
  border-radius: 8px;
}
html.pub-lightbox-open {
  overflow: hidden;
}

/* Phones: the row stacks, so cap the plate rather than letting it fill */
@media (max-width: 575px) {
  ol.bibliography > li .abbr {
    max-width: 18rem;
    margin-bottom: 0.9rem;
  }
}

/* Keep the venue badge compact above the wider preview */
ol.bibliography abbr.badge {
  max-width: 6rem;
}

/* Title: the anchor of each entry, a link to the project page. The theme
   sets the title's weight with a more specific selector, so this one is
   deeper too. */
.publications ol.bibliography > li .row .title,
.publications ol.bibliography > li .row .title a {
  font-family: var(--site-font-serif);
  font-size: 1.12rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: -0.005em;
  margin-bottom: 0.35rem;
  color: var(--site-heading-color);
}
.publications ol.bibliography .title a {
  color: inherit;
}

/* Authors: everyone listed in a quieter grey, each name kept on one line;
   my name in bold near-black; the equal-contribution note on its own
   line, small and grey */
.publications ol.bibliography .author {
  font-size: 0.93rem;
  line-height: 1.65;
  color: var(--pub-meta-color);
  margin-bottom: 0.1rem;
}
.publications ol.bibliography .author .author-name {
  white-space: nowrap;
}
.publications ol.bibliography .author .author-self {
  font-weight: 600;
  color: var(--site-heading-color);
}
ol.bibliography .author .author-note {
  display: block;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--global-text-color-light);
}

/* Venue: bold name, then the year */
.publications ol.bibliography .periodical {
  font-size: 0.93rem;
  font-weight: 400;
  line-height: 1.65;
  color: var(--pub-meta-color);
  margin: 0;
}
.publications ol.bibliography .periodical .venue {
  font-weight: 600;
  color: var(--site-heading-color);
}
.publications ol.bibliography .periodical:empty {
  display: none;
}

/* Award line: the award itself in red, the rest plain */

/* Links: Project Page / Paper / Code / ... as plain underlined text */
.publications ol.bibliography .links {
  margin-top: 0.1rem;
  font-size: 0.95rem;
  line-height: 1.6;
}
.publications ol.bibliography .links a {
  cursor: pointer;
}
.publications ol.bibliography .links__sep {
  margin: 0 0.35em;
  color: var(--global-text-color-light);
}

/* Description: two quiet grey sentences under the links */

/* Abs / Bib panels that unfold under the links */
.publications ol.bibliography .hidden.open {
  margin-top: 0.6rem;
}
.publications ol.bibliography div.abstract.hidden.open {
  border-color: var(--global-divider-color);
  border-radius: 6px;
}
.publications ol.bibliography .hidden p {
  font-size: 0.86rem;
  line-height: 1.55;
  text-align: left;
}

/* Social icons under the profile photo: one compact centered row, Guandao-style */

/* ===== Full-screen home hero =====
   Swap the photo by editing the `background-image` URL below. */
.home-hero {
  position: relative;
  /* Break out of the centered content container to span the full viewport width */
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  /* Pull up under the fixed navbar so the image reaches the very top */
  margin-top: -2rem;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* Human and robot hand reaching for each other on studio black (the
     previous Milky Way is still at /assets/img/stars.jpg). The photo is split
     into two layers, each hand alone on black, pinned to opposite corners: the
     robot arm enters top right, the human arm bottom left, and the space
     between them belongs to the avatar and the tagline. Both hands get the
     same height so the composition stays point-symmetric about the content.
     The size is fitted, not guessed: for twelve viewports from 912x760 to
     2560x1440 the largest height that keeps every fingertip 45px from the
     avatar and the tagline was measured, and min() of the two lines below is
     the tightest formula that never exceeds it, then nudged 12px larger at
     Jerry's request (the gap now lands between about 33 and 70px). The height term rules on wide screens, the width term on
     squarer windows. Each layer is pushed 3vh past its corner, which clips a
     sliver of forearm and keeps the fingertips clear of the content. */
  background-color: #000;
  background-image: url("/assets/img/hand-robot.jpg"), url("/assets/img/hand-human.jpg");
  background-position:
    right top -3vh,
    left bottom -3vh;
  background-size: auto min(70vh - 238px, 37vw - 53px);
  background-repeat: no-repeat;
  overflow: hidden;
}
/* Stardust canvas: above the darkening overlay, below the content (z 1).
   Starts invisible; home-effects.js adds .is-on after the first frame so the
   stars fade in instead of popping. Decorative only — never catches clicks.
   Hidden while the hands image is in use — twinkling stars and meteors read
   as space, not a studio shot. Delete the `display: none` to bring them back;
   home-effects.js skips the animation while the canvas is hidden. */
.home-hero__fx {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 1.6s ease 0.25s;
  pointer-events: none;
}
.home-hero__fx.is-on {
  opacity: 1;
}
.home-hero__overlay {
  position: absolute;
  inset: 0;
  /* The image is already black; a scrim across the top keeps the navbar
     legible where the white robot arm enters the frame, and a light one at
     the bottom eases into the page fade. The middle stays untouched. */
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 24%, rgba(0, 0, 0, 0) 60%, rgba(0, 0, 0, 0.35) 100%);
}
.home-hero__content {
  position: relative;
  z-index: 1;
  padding: 2rem 1.5rem;
  /* A touch above true centre: the optical centre of the space between the
     two fingertips sits slightly high. */
  transform: translateY(-2vh);
  color: #fff;
}
.home-hero__avatar {
  /* Block, so the inline-block quote below starts on its own line */
  display: block;
  width: 150px;
  height: 150px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid rgba(255, 255, 255, 0.92);
  box-shadow:
    0 0 0 7px rgba(255, 255, 255, 0.07),
    0 12px 40px rgba(0, 0, 0, 0.45);
  margin: 0 auto 1.5rem;
}
/* Attribution under the tagline: quiet enough to read as a credit, clear
   enough that anyone who knows the song sees it is a quote, not a slogan. */
.home-hero__quote {
  display: inline-block;
  max-width: 44ch;
}
/* Portrait viewports (phones, tablets): the width is the scarce dimension,
   so the cap flips — size from the width, limited by the height. */
@media (max-aspect-ratio: 1/1) {
  .home-hero {
    background-size: auto min(32vh, 60vw);
  }
}
@media (max-width: 575px) {
  .home-hero {
    /* The phone hero is shorter (see the phone rules above), so the hands
       shrink a step further and the human hand is lifted only slightly out
       of the bottom fade. */
    background-size: auto min(30vh, 60vw);
    background-position:
      right top -3vh,
      left bottom 2vh;
  }
}
/* Landscape phones: a short hero, so the avatar shrinks to keep the stack
   clear of the navbar and the bottom fade. */
@media (max-height: 500px) {
  .home-hero {
    background-size: auto 36vh;
  }
  .home-hero__avatar {
    width: 100px;
    height: 100px;
  }
}
.home-hero__attrib {
  margin: 0.55rem 0 0;
  text-align: right;
  padding-right: 0.15em;
  font-family: var(--site-font-serif);
  font-size: clamp(0.72rem, 0.95vw, 0.86rem);
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.62);
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.5);
}
.home-hero__attrib cite {
  font-style: italic;
}

.home-hero__tagline {
  color: #fff;
  font-family: var(--site-font-serif);
  font-size: clamp(1.1rem, 1.9vw, 1.5rem);
  font-weight: 400;
  letter-spacing: 0.03em;
  margin: 0;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.55);
}

/* ===== SZ monogram beside the name in the navbar =====
   The same mark as the favicon (assets/img/sz-mark.svg): a seal-like rounded
   frame with an S and a red Z set as a tight serif ligature. Drawn with a
   ::before so the theme's header include stays untouched; over the hero the
   white variant is used until the navbar turns solid. */
#navbar .navbar-brand.title,
#navbar .navbar-brand.home-hero-brand {
  display: inline-flex;
  align-items: center;
  /* Space after the mark only: a flex gap would also widen the space
     between the first name and the surname. */
  column-gap: 0.28em;
}
#navbar .navbar-brand.title::before,
#navbar .navbar-brand.home-hero-brand::before {
  margin-right: 0.22em;
}
/* The theme sets the surname lighter than the bold first name; set the
   whole name in the first name's weight. Bootstrap's .font-weight-lighter
   is !important, hence the same here. */
#navbar .navbar-brand.title {
  font-weight: 700 !important;
}
#navbar .navbar-brand.title::before,
#navbar .navbar-brand.home-hero-brand::before {
  content: "";
  flex: 0 0 auto;
  width: 1.45em;
  height: 1.45em;
  background: url("/assets/img/sz-mark.svg") center / contain no-repeat;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.12));
  transition: transform 0.25s ease;
}
#navbar .navbar-brand:hover::before {
  transform: rotate(-6deg) scale(1.06);
}
html.home-hero-page:not(.nav-solid) #navbar .navbar-brand.home-hero-brand::before {
  background-image: url("/assets/img/sz-mark-light.svg");
  filter: drop-shadow(0 1px 8px rgba(0, 0, 0, 0.45));
}

/* ===== Home: transparent navbar over the hero, name top-left (zhou-xian style) ===== */
/* Let the hero reach the very top, under the fixed navbar */
html.home-hero-page body.fixed-top-nav {
  padding-top: 0 !important;
}
html.home-hero-page .container.mt-5 {
  margin-top: 0 !important;
}
/* tailwind.css ships `@layer components { .mt-5 { margin-top: 3rem !important } }`.
   A layered !important beats our unlayered !important regardless of specificity,
   so the rule above can't win and .mt-5 keeps its 48px top margin — that gap was
   showing a band of page background (white in light theme, near-black in dark)
   above the hero. Cancel the 48px by pulling the hero up the same amount so the
   image sits flush to the very top, under the transparent navbar. */
html.home-hero-page .home-hero {
  margin-top: -3rem !important;
}
/* Widen the navbar to full width so the name hugs the far left and the
   nav cluster the far right (content below stays in the 930px column). */
html.home-hero-page #navbar > .container {
  max-width: none;
  padding-left: 2.2rem;
  padding-right: 2.2rem;
}
/* Transparent navbar while sitting over the hero image */
html.home-hero-page #navbar {
  background: transparent !important;
  box-shadow: none !important;
  border-bottom: none !important;
  transition:
    background 0.3s ease,
    box-shadow 0.3s ease;
}
html.home-hero-page #navbar .nav-link,
html.home-hero-page #navbar .navbar-brand,
html.home-hero-page #navbar #light-toggle i,
html.home-hero-page #navbar #search-toggle .nav-link {
  color: #fff !important;
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.45);
}
/* Unify the navbar font with the serif brand + motto */
html.home-hero-page #navbar .nav-link,
html.home-hero-page #navbar .navbar-brand {
  font-family: var(--site-font-serif);
}
/* Nudge the whole navbar row up a touch */
html.home-hero-page #navbar > .container {
  transform: translateY(-3px);
}
html.home-hero-page #navbar .icon-bar {
  background-color: #fff !important;
}
/* The name, top-left, in an elegant serif; push the nav cluster to the far right */
html.home-hero-page #navbar .navbar-brand {
  margin-right: 0;
}
html.home-hero-page #navbar .navbar-collapse-main {
  margin-left: auto;
}
.home-hero-brand {
  font-family: var(--site-font-serif);
  font-size: 1.4rem;
  font-weight: 500;
  letter-spacing: 0.01em;
}
/* Once scrolled past the hero, restore the solid navbar */
html.home-hero-page.nav-solid #navbar {
  background: var(--global-bg-color) !important;
  box-shadow: 0 1px 0 var(--global-divider-color);
}
html.home-hero-page.nav-solid #navbar .nav-link,
html.home-hero-page.nav-solid #navbar .navbar-brand,
html.home-hero-page.nav-solid #navbar #light-toggle i,
html.home-hero-page.nav-solid #navbar #search-toggle .nav-link {
  color: var(--global-text-color) !important;
  text-shadow: none;
}
html.home-hero-page.nav-solid #navbar .icon-bar {
  background-color: var(--global-text-color) !important;
}
/* Melt the hero's bottom edge into the page background (both themes).
   The page colour on a long smootherstep ramp (t^3(6t^2-15t+10)): the alpha
   leaves zero and arrives at one with zero slope, so there is no visible
   line where the fade begins or where it meets the flat page. Kept short on
   purpose: the page should only just begin to show under the hero, with
   the hands and the black left alone. */
.home-hero::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 7rem;
  background: linear-gradient(
    180deg,
    rgb(var(--hero-fade-rgb) / 0) 0%,
    rgb(var(--hero-fade-rgb) / 0.001) 5%,
    rgb(var(--hero-fade-rgb) / 0.009) 10%,
    rgb(var(--hero-fade-rgb) / 0.027) 15%,
    rgb(var(--hero-fade-rgb) / 0.058) 20%,
    rgb(var(--hero-fade-rgb) / 0.104) 25%,
    rgb(var(--hero-fade-rgb) / 0.163) 30%,
    rgb(var(--hero-fade-rgb) / 0.235) 35%,
    rgb(var(--hero-fade-rgb) / 0.317) 40%,
    rgb(var(--hero-fade-rgb) / 0.407) 45%,
    rgb(var(--hero-fade-rgb) / 0.5) 50%,
    rgb(var(--hero-fade-rgb) / 0.593) 55%,
    rgb(var(--hero-fade-rgb) / 0.683) 60%,
    rgb(var(--hero-fade-rgb) / 0.765) 65%,
    rgb(var(--hero-fade-rgb) / 0.837) 70%,
    rgb(var(--hero-fade-rgb) / 0.896) 75%,
    rgb(var(--hero-fade-rgb) / 0.942) 80%,
    rgb(var(--hero-fade-rgb) / 0.973) 85%,
    rgb(var(--hero-fade-rgb) / 0.991) 90%,
    rgb(var(--hero-fade-rgb) / 0.999) 95%,
    rgb(var(--hero-fade-rgb) / 1) 100%
  );
  pointer-events: none;
  z-index: 1;
}
/* Film grain under the ramp: monochrome SVG turbulence that breaks up the
   banding a black-to-cream ramp shows on 8-bit panels. Masked to the middle
   of the band, where the ramp is half-transparent and the banding lives, so
   it never draws an edge of its own on the black above or the page below. */
.home-hero__overlay::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 7rem;
  background: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.09'/%3E%3C/svg%3E");
  -webkit-mask-image: linear-gradient(180deg, transparent 22%, #000 45%, #000 65%, transparent 95%);
  mask-image: linear-gradient(180deg, transparent 22%, #000 45%, #000 65%, transparent 95%);
  pointer-events: none;
  z-index: 1;
}
.home-hero__scroll {
  position: absolute;
  bottom: 1.75rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2; /* above the bottom fade */
  color: rgba(255, 255, 255, 0.85);
  display: inline-flex;
  animation: home-hero-bob 2s ease-in-out infinite;
}
.home-hero__scroll:hover {
  color: #fff;
}
@keyframes home-hero-bob {
  0%,
  100% {
    transform: translateX(-50%) translateY(0);
  }
  50% {
    transform: translateX(-50%) translateY(7px);
  }
}
@media (max-width: 576px) {
  .home-hero {
    background-attachment: scroll; /* `fixed` is janky on mobile */
    min-height: 88vh;
  }
  .home-hero__avatar {
    width: 130px;
    height: 130px;
  }
}

/* ===== Palette and type =====
   Warm cream ground, near-black text, quiet grey for secondary lines and a
   single caramel accent for hover states — the tone of wenlonghuang.com.
   Type is IBM Plex Sans for text and IBM Plex Serif for the name and motto
   (loaded through `google_fonts` in _config.yml).
   `:root:root` outspecifies the theme's own `:root` block, which loads later. */
:root:root {
  --global-bg-color: #f6f3ec;
  --hero-fade-rgb: 246 243 236; /* the page colour as bare channels, for the hero fade's alpha ramp */
  --global-text-color: #202020;
  --global-text-color-light: #666;
  --global-divider-color: #e3e3e3;
  --global-card-bg-color: #fff;
  --global-theme-color: #c58b5c;
  --global-hover-color: #c58b5c;
  --site-accent: #c58b5c;
  --site-heading-color: #111;
  --site-font-sans: "IBM Plex Sans", "Segoe UI", Helvetica, Arial, sans-serif;
  --site-font-serif: "IBM Plex Serif", Georgia, "Times New Roman", serif;
}
body {
  font-family: var(--site-font-sans);
  color: var(--global-text-color);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

/* ===== Dark mode =====
   The same warm register turned down: charcoal with a hint of brown for the
   ground, bone for text, the caramel accent unchanged. The theme's
   assets/js/theme.js sets html[data-theme] (the navbar toggle cycles system →
   light → dark and remembers the choice); `:root:root[data-theme="dark"]`
   outspecifies both the palette block above and the theme's own dark block.
   Figure plates and logo plates stay white in both modes: those images were
   made for white. */
:root:root[data-theme="dark"] {
  --global-bg-color: #161412;
  --hero-fade-rgb: 22 20 18;
  --global-text-color: #e6e1d8;
  --global-text-color-light: #9b958b;
  --global-divider-color: #2d2a26;
  --global-card-bg-color: #1e1b18;
  --global-code-bg-color: #23201c;
  --site-heading-color: #f3efe7;
  --global-footer-bg-color: #0f0e0d;
  --global-footer-text-color: #9b958b;
  --global-footer-link-color: #e6e1d8;
}
html[data-theme="dark"] .pub-lightbox {
  background: rgba(22, 20, 18, 0.86);
}
html[data-theme="dark"] .publications {
  --pub-meta-color: #c9c3b8;
}
html[data-theme="dark"] .post article a:not(.btn):not(.quicklink):not(.chat-cta):not(.thumbnail-hover-wrapper):not(h2 > a) {
  text-decoration-color: #57524b;
}
/* Solid button: bone ground, so the label goes dark */
html[data-theme="dark"] .chat-cta {
  color: var(--global-bg-color) !important;
}
html[data-theme="dark"] .experience__logo {
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08);
}
/* Navbar monogram: the light variant everywhere, not just over the hero */
html[data-theme="dark"] #navbar .navbar-brand.title::before,
html[data-theme="dark"] #navbar .navbar-brand.home-hero-brand::before {
  background-image: url("/assets/img/sz-mark-light.svg");
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
}

/* Links in running text: the text colour with a thin grey underline that
   darkens on hover, instead of coloured link text. Buttons and pills keep
   their own styling. */
.post article a:not(.btn):not(.quicklink):not(.chat-cta):not(.thumbnail-hover-wrapper):not(h2 > a) {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-color: #b7b7b7;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: text-decoration-color 0.15s ease;
}
.post article a:not(.btn):not(.quicklink):not(.chat-cta):not(.thumbnail-hover-wrapper):not(h2 > a):hover {
  color: inherit;
  text-decoration-color: currentColor;
}

/* Section headings: News, Selected Publications, Experience, and the
   year headings on the publications page. Set small
   and tight, in near-black, the way the reference sets its headings. */
.post article > h2,
.post article > h2 > a,
div.publications h2.bibliography,
h2.exp-section {
  color: var(--site-heading-color);
  font-size: 1.35rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.3;
}
.post article > h2 > a {
  text-decoration: none;
}

/* The current page in the navbar is a state, not a link: near-black, the
   rest of the items grey. Over the hero the navbar keeps its own rules. */
#navbar .navbar-nav .nav-item.active > .nav-link {
  color: var(--site-heading-color);
  font-weight: 600;
}

/* Breathing room between the hero and the intro text */
#about-content {
  padding-top: 3rem;
}

/* ===== Section rhythm on the home page ===== */
/* Clear air before each section heading (News, Selected Publications) */
.post article > h2 {
  margin-top: 4rem;
  margin-bottom: 1.4rem;
}
/* ===== News =====
   Compact dated rows, the way most academic homepages set it (after
   yaozhang.ai and etaoxing.com): a short month and year in a fixed column,
   the item beside it. On the home page the rows sit in a thin outlined box
   that scrolls once the list outgrows it; /news/ shows them unboxed.
   Markup comes from the local override in `_includes/news.liquid`. */
.news-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.news-entry {
  display: flex;
  gap: 1rem;
  padding: 0.32rem 0;
  line-height: 1.55;
}
.news-entry__date {
  flex: 0 0 5.2rem;
  padding-top: 0.06rem;
  font-size: 0.88rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--global-text-color-light);
}
.news-entry__text {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.95rem;
}

/* The home-page box: five rows tall, the rest reached by scrolling inside
   it. home-effects.js measures the fifth row and sets the exact height
   (rows wrap on narrow screens, so a fixed rem would cut one mid-line); the
   max-height here is only the no-JS fallback. The vertical padding sits on
   the frame, not the scroller, so the sixth row cannot peek through it.
   Wheel and trackpad scrolls settle on a row boundary; a slim scrollbar
   stays visible as the cue that there is more, and a short fade at each
   edge softens the cut without greying the last visible row. */
.news--scroll {
  position: relative;
  padding: 0.55rem 0;
  border: 1px solid var(--global-divider-color);
  border-radius: 8px;
}
.news--scroll .news__scroller {
  position: relative;
  max-height: 10.8rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 1rem;
  scroll-snap-type: y proximity;
}
.news--scroll .news__scroller::-webkit-scrollbar {
  width: 5px;
}
.news--scroll .news__scroller::-webkit-scrollbar-thumb {
  background: var(--global-divider-color);
  border-radius: 3px;
}
.news--scroll .news__scroller::-webkit-scrollbar-thumb:hover {
  background: var(--global-text-color-light);
}
.news--scroll .news-entry {
  scroll-snap-align: start;
}
@media (prefers-reduced-motion: no-preference) {
  .news--scroll .news__scroller {
    scroll-behavior: smooth;
  }
}
/* Edge fades: the frame's padding plus a few pixels of the row beside it,
   each faded in by a class the script toggles as the box scrolls. */
.news--scroll::before,
.news--scroll::after {
  content: "";
  position: absolute;
  left: 1px;
  right: 8px; /* clear of the scrollbar */
  height: 1rem;
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
  z-index: 1;
}
.news--scroll::before {
  top: 1px;
  background: linear-gradient(180deg, var(--global-bg-color) 40%, transparent);
}
.news--scroll::after {
  bottom: 1px;
  background: linear-gradient(0deg, var(--global-bg-color) 40%, transparent);
}
.news--scroll.news--more-above::before,
.news--scroll.news--more-below::after {
  opacity: 1;
}

/* Phones: the date moves above its item */
@media (max-width: 576px) {
  .news-entry {
    flex-direction: column;
    gap: 0;
    padding: 0.45rem 0;
  }
  .news-entry__date {
    flex-basis: auto;
    font-size: 0.8rem;
  }
}

/* ===== "Let's chat" invitation =====
   A white card that reads as an offer rather than another paragraph, with a
   single solid call to action that warms to the accent on hover. */
.chat-invite {
  margin-top: 1.8rem;
  padding: 1.15rem 1.3rem 1.25rem;
  border: 1px solid var(--global-divider-color);
  border-radius: 0.8rem;
  background: var(--global-card-bg-color);
}
.chat-invite__text {
  margin: 0 0 0.8rem;
  line-height: 1.6;
}
/* The closing line is a personal aside, so it is set quieter than the
   invitation above it and marked off with a short accent rule. */
.chat-invite__note {
  margin: 0 0 1.05rem;
  padding-left: 0.85rem;
  border-left: 2px solid rgba(197, 139, 92, 0.6);
  font-size: 0.92rem;
  font-style: italic;
  line-height: 1.55;
  opacity: 0.82;
}
.chat-invite__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem;
}
.chat-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.55rem 1.2rem;
  border-radius: 999px;
  border: 1px solid var(--global-text-color);
  background: var(--global-text-color);
  color: #fff !important;
  font-size: 0.92rem;
  font-weight: 600;
  text-decoration: none !important;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
  transition:
    background 0.18s ease,
    border-color 0.18s ease,
    transform 0.18s ease,
    box-shadow 0.18s ease;
}
.chat-cta:hover {
  background: var(--site-accent);
  border-color: var(--site-accent);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(197, 139, 92, 0.3);
}
.chat-cta > span,
.chat-cta > i {
  color: inherit;
}
.chat-cta__arrow {
  transition: transform 0.18s ease;
}
.chat-cta:hover .chat-cta__arrow {
  transform: translateX(3px);
}

/* ===== Quick links =====
   A row of outlined pills under the intro: CV, contact and profile links.
   An entry still waiting on a URL renders greyed out, holding its place. */
.quicklinks {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 1.6rem 0 0.4rem;
}
.quicklink {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 1rem;
  border: 1px solid var(--global-divider-color);
  border-radius: 999px;
  font-size: 0.9rem;
  line-height: 1.2;
  color: var(--global-text-color);
  text-decoration: none;
  background: var(--global-card-bg-color);
  transition:
    border-color 0.18s ease,
    color 0.18s ease,
    transform 0.18s ease;
}
.quicklink i,
.quicklink__glyph {
  color: var(--global-text-color-light);
  font-size: 0.95em;
  transition: color 0.18s ease;
}
.quicklink__glyph {
  font-size: 0.78em;
  letter-spacing: 0.02em;
}
a.quicklink:hover {
  color: var(--global-theme-color);
  border-color: var(--global-theme-color);
  transform: translateY(-1px);
}
a.quicklink:hover i,
a.quicklink:hover .quicklink__glyph {
  color: var(--global-theme-color);
}
/* Reserved slot: visible but plainly not yet clickable */
.quicklink--pending {
  color: var(--global-text-color-light);
  border-style: dashed;
  cursor: default;
}

/* ===== Photography =====
   A simple responsive grid; each frame keeps its own proportions and clicking
   one zooms it. Files are read straight out of assets/img/photography/. */
.photo-grid__empty {
  color: var(--global-text-color-light);
  margin-top: 1.5rem;
}

/* ===== Scroll reveal =====
   home-effects.js tags elements with .sr, so nothing is ever hidden without
   JS (or under prefers-reduced-motion, where the script skips tagging). */
.sr {
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity 0.65s ease var(--sr-delay, 0s),
    transform 0.7s cubic-bezier(0.22, 0.61, 0.36, 1) var(--sr-delay, 0s);
}
.sr--fade {
  transform: none;
}
.sr.sr-in {
  opacity: 1;
  transform: none;
}

/* ===== Experience =====
   After wenlonghuang.com: a white logo plate on the left; organisation in
   bold, then role, then advisors in grey; the dates set small to the far
   right of the organisation line. Rows are divided by hairlines, with no
   card around them. Data: _data/experience.yml, markup:
   _includes/experience.liquid. */
.experience {
  list-style: none;
  margin: 0.25rem 0 0;
  padding: 0;
}
.experience__entry {
  display: grid;
  grid-template-columns: 84px 1fr;
  column-gap: 18px;
  align-items: start;
  padding: 15px 0;
  border-top: 1px solid var(--global-divider-color);
}
.experience__entry:first-child {
  border-top: 0;
  padding-top: 4px;
}
.experience__logo {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 8px 10px;
  border-radius: 12px;
  background: #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.045);
}
.experience__logo img {
  display: block;
  max-width: 100%;
  max-height: 38px;
  width: auto;
  height: auto;
  object-fit: contain;
}
.experience__body {
  min-width: 0;
}
.experience__org {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.35;
}
.experience__entry:hover .experience__org a {
  color: var(--site-accent);
  text-decoration-color: currentColor;
}
.experience__dates {
  float: right;
  margin: 0.1rem 0 0.25rem 0.9rem;
  color: var(--global-text-color-light);
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.experience__role {
  margin-top: 0.2rem;
  font-weight: 600;
  line-height: 1.5;
}
.experience__note {
  margin-top: 0.15rem;
  max-width: 48rem;
  color: var(--global-text-color-light);
  font-size: 0.88rem;
  line-height: 1.55;
}

/* Section headings on /experience/ (and the year headings on /news/): the
   publications heading, with a small icon in the accent colour */
h2.exp-section {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.9rem;
}
h2.exp-section i {
  width: 1.1em;
  color: var(--site-accent);
  font-size: 0.92em;
  text-align: center;
}
.exp-group,
.news-year {
  scroll-margin-top: 5rem;
}
.experience-page .experience__entry:first-child {
  padding-top: 8px;
}

/* /news/: the year is in the heading, so the date column only needs the day */
.news--page .news-entry {
  padding: 0.45rem 0;
}
.news--page .news-entry__date {
  flex-basis: 4rem;
}

/* Phones: logo above the text, dates on their own line under the name
   (the dates sit before the name in the markup so they can float right on
   desktop; a flex column reorders them here). */
@media (max-width: 575px) {
  .experience__entry {
    grid-template-columns: 1fr;
    row-gap: 10px;
  }
  .experience__logo {
    width: min(13rem, 100%);
  }
  .experience__body {
    display: flex;
    flex-direction: column;
  }
  .experience__org {
    order: 0;
  }
  .experience__dates {
    order: 1;
    float: none;
    margin: 0.1rem 0 0.05rem;
  }
  .experience__role {
    order: 2;
  }
  .experience__note {
    order: 3;
  }
}
