/* Jinquan Hang — personal homepage.
   Single stylesheet, no external requests (system font stack only).

   Layout: a sticky left identity rail beside the content column — the pattern
   used by most peers in this field. The rail holds identity only: portrait,
   name, role, and the links needed to reach or verify the person. Navigation,
   if it is ever needed, belongs in a bar above the content, not in the rail. */

:root {
  --bg: #ffffff;
  --text: #23292f;
  --muted: #5f6873;
  --faint: #6b7580;
  --accent: #2b5d8a;
  --border: #e8ecf0;
  --venue-bg: #e9eef4;

  /* The rail column sizes itself to its content, so --rail-max is only a
     backstop: identity lines are short, and a fixed width would leave dead
     space inside the column that reads as a wider gap than --gap actually is. */
  --rail-max: 300px;
  --gap: 80px;
  --content: 752px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #15191e;
    --text: #dfe5ec;
    --muted: #a3aeba;
    --faint: #8b96a3;
    --accent: #7fb0da;
    --border: #29313a;
    --venue-bg: #262f3a;
  }
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.58 system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
}

a {
  color: var(--accent);
}

a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Anchors land clear of the top edge. If a sticky nav bar is ever added,
   this single value becomes its height plus a little. */
section[id] {
  scroll-margin-top: 1.5rem;
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

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

.layout {
  display: grid;
  grid-template-columns: max-content minmax(0, var(--content));
  column-gap: var(--gap);
  justify-content: center;
  padding: 52px 40px 72px;
}

/* ---------- left identity rail ---------- */

.rail {
  position: sticky;
  top: 52px;
  align-self: start; /* a stretched grid item cannot stick */
  max-width: var(--rail-max);
}

/* Width matches the role line below it, the rail's widest text, so photo and
   text end flush and the block reads as one unit. The match is measured on the
   macOS system font; a couple px of drift elsewhere is invisible, since no
   other element aligns to these right edges. The hairline border is for the
   photo's studio-gray backdrop, which otherwise bleeds into the light page
   background and glows against the dark one. */
.portrait {
  display: block;
  width: 248px;
  height: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
  margin: 0 0 18px;
}

.rail h1 {
  font-size: 24px;
  font-weight: 680;
  letter-spacing: -0.012em;
  margin: 0;
  text-wrap: balance;
}

.name-cn {
  display: block;
  margin-top: 1px;
  color: var(--faint);
  font-weight: 400;
  font-size: 18px;
}

.role {
  margin: 8px 0 14px;
  color: var(--muted);
  font-size: 14.5px;
  line-height: 1.45;
}

.profile-links {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 14.5px;
}

.profile-links a {
  text-decoration: none;
  font-weight: 550;
}

.profile-links a:hover {
  text-decoration: underline;
}

/* The address is the only place contact info lives now, so it is spelled out in
   full and is clickable rather than hidden behind the word "Email". It leads the
   list with a little extra space under it, since it is contact, not a profile. */
.email {
  font-size: 13.5px;
  margin-bottom: 4px;
  overflow-wrap: anywhere;
}

/* ---------- content column ---------- */

.content {
  min-width: 0;
}

.bio {
  margin: 0;
}

section {
  margin-top: 30px;
}

h2 {
  font-size: 17px;
  font-weight: 650;
  margin: 0 0 12px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}

/* Body prose inside a section, as opposed to the lists that make up the rest
   of the page. Same measure and size as the bio above it. */
.prose {
  margin: 0;
}

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

.pub {
  margin-bottom: 16px;
}

.pub-title {
  font-weight: 620;
  margin: 0;
}

.pub-authors {
  font-size: 14.5px;
  color: var(--muted);
  margin: 2px 0;
}

.pub-authors b {
  color: var(--text);
  font-weight: 620;
}

.pub-meta {
  font-size: 14px;
  line-height: 1.6;
  margin: 2px 0 0;
}

/* The venue is a filled tag at exactly the link size, so nothing on this line
   is smaller than anything else, and its ink is body-colored rather than accent
   so it never reads as clickable.

   padding-bottom is 2px more than padding-top on purpose. Equal padding centers
   the fill on the font's em box, which at 14px is 14.0 above the baseline and
   3.0 below; the box then lands ~1.25px above the optical center of the text
   beside it, which has descenders ("[Paper]") while "KDD 2024" does not. */
.venue {
  display: inline-block;
  vertical-align: baseline;
  max-width: 100%;
  margin-right: 7px;
  padding: 1px 7px 3px;
  border-radius: 3px;
  background: var(--venue-bg);
  color: var(--text);
  font-size: inherit;
  font-weight: 600;
  line-height: 1.42;
}

.pub-meta a {
  text-decoration: none;
  font-weight: 550;
}

.pub-meta a:hover {
  text-decoration: underline;
}

/* ---------- applications ---------- */

/* Deliberately the same shape as a publication entry: a bold title line with
   its detail beneath, so the two sections read as one page rather than two. */
.app {
  margin-bottom: 16px;
}

.app-title {
  font-weight: 620;
  margin: 0 0 2px;
}

.app-desc {
  margin: 0;
  font-size: 15px;
  color: var(--muted);
}

/* ---------- education ---------- */

.entry {
  margin-bottom: 14px;
  font-size: 15px;
}

.entry-name {
  font-weight: 620;
}

/* Dates and location form one muted line under the degree rather than a
   right-aligned column. A right column would have to hold both, and measured
   against the 752px content width the longest row overflows it by 15px — so the
   layout would break on wide screens and reflow on narrow ones. Stacked, it
   renders identically at every width and needs no breakpoint of its own. */
.entry-meta {
  margin-top: 1px;
  color: var(--faint);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}

/* ---------- narrow windows: rail unsticks and becomes a header ---------- */

@media (max-width: 1120px) {
  .layout {
    grid-template-columns: minmax(0, 780px);
    padding: 36px 28px 56px;
  }

  /* No longer a column, so the identity block spans the full measure and the
     rail-column cap has to come off with it. The portrait moves beside the
     text: kept above it at rail size, it would push the bio below the fold
     on a phone. */
  .rail {
    position: static;
    max-width: none;
    margin-bottom: 28px;
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    column-gap: 24px;
  }

  .portrait {
    grid-column: 1;
    grid-row: 1 / 4; /* spans the name, role, and links rows */
    width: 124px;
    margin: 0;
  }

  .rail h1,
  .role,
  .profile-links {
    grid-column: 2;
  }

  /* Wide enough for one line, so the links run across instead of down. */
  .profile-links {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 4px 14px;
  }

  .email {
    margin-bottom: 0;
  }
}

/* A sticky block taller than the window traps its own bottom. */
@media (max-height: 680px) {
  .rail {
    position: static;
  }
}

@media (max-width: 640px) {
  .layout {
    padding: 26px 20px 44px;
  }

  .rail h1 {
    font-size: 21px;
  }

  .name-cn {
    font-size: 17px;
  }

  .portrait {
    width: 104px;
  }
}

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

@media print {
  :root {
    --bg: #ffffff;
    --text: #000000;
    --muted: #333333;
    --faint: #555555;
    --accent: #00417a;
    --border: #cccccc;
  }

  .layout {
    display: block;
    padding: 0;
  }

  .rail {
    position: static;
  }

  /* A printed copy of this page is read like a CV, and CVs in this field
     carry no photo. */
  .portrait {
    display: none;
  }

  .venue {
    background: none;
    padding: 0;
    font-weight: 700;
  }

  a {
    text-decoration: none;
  }
}
