/* ==========================================================================
   Design tokens
   ========================================================================== */
:root {
  --color-bg: #ffffff;
  --color-bg-alt: #f5f6f8;
  --color-surface: #ffffff;
  --color-border: #e2e4e9;
  --color-text: #1a1d24;
  --color-text-muted: #5b6270;
  --color-accent: #1d5f8a;
  --color-accent-dark: #163f5c;
  --color-accent-bg: #e8f1f7;
  --color-link: var(--color-accent);

  --badge-patent-bg: #f4e9d8;
  --badge-patent-text: #8a5a1f;
  --badge-pub-bg: #dcefe3;
  --badge-pub-text: #1f6b45;
  --badge-biorxiv-bg: #eee0f7;
  --badge-biorxiv-text: #6a3494;
  --badge-dev-bg: #dfe7f5;
  --badge-dev-text: #2a4d8a;

  --tier-expert-bg: #1d5f8a;
  --tier-expert-text: #ffffff;
  --tier-proficient-bg: #cfe0eb;
  --tier-proficient-text: #163f5c;
  --tier-familiar-bg: #eceef1;
  --tier-familiar-text: #5b6270;

  --font-heading: Georgia, "Times New Roman", Times, serif;
  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;

  --fs-h1: clamp(2rem, 1.5rem + 2vw, 3rem);
  --fs-h2: clamp(1.5rem, 1.25rem + 1vw, 2rem);
  --fs-h3: 1.25rem;
  --fs-body: 1rem;
  --fs-small: 0.875rem;
  --lh-body: 1.6;
  --lh-heading: 1.25;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4.5rem;

  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 14px;
  --shadow-sm: 0 1px 2px rgba(20, 24, 33, 0.06);
  --shadow-md: 0 4px 16px rgba(20, 24, 33, 0.08);
  --shadow-lg: 0 12px 32px rgba(20, 24, 33, 0.12);

  --container-max: 1120px;
  --header-height: 64px;
  --transition: 150ms ease;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-bg: #14161b;
    --color-bg-alt: #1b1e25;
    --color-surface: #1e2129;
    --color-border: #2c303a;
    --color-text: #e8e9ec;
    --color-text-muted: #9aa1ad;
    --color-accent: #5fa8d3;
    --color-accent-dark: #8ec4e3;
    --color-accent-bg: #1c2c37;

    --badge-patent-bg: #3a2f1c;
    --badge-patent-text: #e3bd82;
    --badge-pub-bg: #1c3527;
    --badge-pub-text: #7fd6a4;
    --badge-biorxiv-bg: #2f2138;
    --badge-biorxiv-text: #d0a6ef;
    --badge-dev-bg: #1e2a41;
    --badge-dev-text: #9db8e8;

    --tier-expert-bg: #5fa8d3;
    --tier-expert-text: #0f1216;
    --tier-proficient-bg: #29414f;
    --tier-proficient-text: #bfe0f2;
    --tier-familiar-bg: #262a33;
    --tier-familiar-text: #9aa1ad;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.35);
    --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.45);
  }
}

/* ==========================================================================
   Reset
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body { min-height: 100vh; line-height: var(--lh-body); -webkit-font-smoothing: antialiased; }
img, picture, video, canvas, svg { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
p, h1, h2, h3, h4 { overflow-wrap: break-word; }

/* Body prose is justified so both edges line up, which reads more evenly in the
   narrow column on a phone. hyphens:auto is what makes that safe -- justifying
   a narrow column WITHOUT hyphenation opens ugly rivers of white space between
   words. Needs <html lang="en"> to pick the right hyphenation dictionary.
   Scoped deliberately: bare <p> and .card-body/.lead are running prose. Labels,
   author lists, dates and captions keep a ragged right. */
p:not([class]), .card-body, .lead {
  text-align: justify;
  -webkit-hyphens: auto;
  hyphens: auto;
}
ul, ol { list-style: none; padding: 0; }
a { color: inherit; text-decoration: none; }
table { border-collapse: collapse; width: 100%; }

/* ==========================================================================
   Global typography
   ========================================================================== */
body {
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--fs-body);
}

h1, h2, h3, h4 {
  font-family: var(--font-heading);
  line-height: var(--lh-heading);
  color: var(--color-text);
  font-weight: 700;
}
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); margin-bottom: var(--space-4); }
h3 { font-size: var(--fs-h3); margin-bottom: var(--space-2); }

p { color: var(--color-text); }
p + p { margin-top: var(--space-3); }

.text-muted { color: var(--color-text-muted); }
.text-small { font-size: var(--fs-small); }
.eyebrow {
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent);
}

a.link, .prose a {
  color: var(--color-link);
  text-decoration: underline;
  text-decoration-color: transparent;
  transition: text-decoration-color var(--transition);
}
a.link:hover, .prose a:hover { text-decoration-color: currentColor; }

/* ==========================================================================
   Layout system
   ========================================================================== */
.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--space-5);
}

.section {
  padding-block: var(--space-7);
}

.stack > * + * { margin-top: var(--space-4); }
.stack-sm > * + * { margin-top: var(--space-2); }
.stack-lg > * + * { margin-top: var(--space-6); }

.flex {
  display: flex;
  gap: var(--space-4);
}
.flex-center { align-items: center; justify-content: center; }
.flex-between { align-items: center; justify-content: space-between; }
.flex-wrap { flex-wrap: wrap; }
.flex-col { flex-direction: column; }

.grid {
  display: grid;
  gap: var(--space-5);
}
/* Grid items default to min-width:auto, meaning a track can never shrink below
   its widest unbreakable child. A long non-wrapping badge was therefore forcing
   whole cards wider than the page on phones. Let tracks shrink instead. */
.grid > * { min-width: 0; }
.grid-2col { grid-template-columns: repeat(2, 1fr); }
.grid-3col { grid-template-columns: repeat(3, 1fr); }
.grid-4col { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 900px) {
  .grid-3col, .grid-4col { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grid-2col, .grid-3col, .grid-4col { grid-template-columns: 1fr; }
  .section { padding-block: var(--space-6); }
}

/* ==========================================================================
   Header / nav
   ========================================================================== */
/* Cards that can be linked to directly (e.g. index.html capability cards point
   at a specific publication or invention). Without this, the sticky header
   would cover the top of the card when you arrive via the link. */
.card[id] { scroll-margin-top: calc(var(--header-height) + var(--space-4)); }

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  height: var(--header-height);
  display: flex;
  align-items: center;
  background: color-mix(in srgb, var(--color-bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--color-border);
}

.site-header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.brand {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.15rem;
  color: var(--color-text);
}
.brand span { color: var(--color-accent); }

.nav {
  display: flex;
  gap: var(--space-6);
}

/* Every nav item is the same box, so the highlight pill is one fixed shape that
   moves between them rather than resizing to fit each word. min-width is set by
   the longest label ("Publications"); change it if a longer one is ever added. */
.nav a {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--color-text-muted);
  min-width: 7.5rem;
  text-align: center;
  padding-block: var(--space-2);
  padding-inline: var(--space-3);
  border-bottom: 2px solid transparent;
  transition: color var(--transition), border-color var(--transition);
}

.nav a:hover,
.nav a[aria-current="page"] {
  color: var(--color-text);
  border-bottom-color: var(--color-accent);
}

.nav-toggle { display: none; }

@media (max-width: 640px) {
  /* The name and three nav items cannot share one line on a phone -- the name
     wrapped onto three lines and collided with the links. Stack them instead:
     name on top, nav underneath. --header-height is raised to match, so the
     sticky offset and card scroll-margin stay correct. */
  :root { --header-height: 92px; }

  .site-header .container {
    flex-direction: column;
    justify-content: center;
    gap: var(--space-2);
  }
  .brand { font-size: 1.05rem; white-space: nowrap; }

  .nav { gap: var(--space-3); }
  /* Three equal 7.5rem boxes won't fit a phone, so let the items shrink back
     to their text width here. */
  .nav a { min-width: 0; padding-inline: var(--space-2); padding-block: var(--space-1); }
}

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer {
  border-top: 1px solid var(--color-border);
  padding-block: var(--space-6);
  background: var(--color-bg-alt);
}

.site-footer .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.footer-links {
  display: flex;
  gap: var(--space-5);
}

.footer-links a {
  font-size: var(--fs-small);
  color: var(--color-text-muted);
}
.footer-links a:hover { color: var(--color-accent); }

/* ==========================================================================
   Components
   ========================================================================== */

/* Card */
.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--transition), transform var(--transition);
}
.card:hover { box-shadow: var(--shadow-md); }
.card-link { display: block; }
.card-link:hover { transform: translateY(-2px); }
/* White backing: some cropped figures are saved with a transparent background,
   which would otherwise let the dark page colour show through behind the axes
   and lettering. Harmless for figures that already carry their own white. */
/* width:100%, not just the global max-width:100%. Without it a figure narrower
   than its column sits at its natural size while the strip below spans the full
   column, so the two don't line up. */
.card img { width: 100%; border-radius: var(--radius-md); margin-bottom: var(--space-4); background: #fff; }
.card-title { font-size: var(--fs-h3); margin-bottom: var(--space-1); }
.card-meta { color: var(--color-text-muted); font-size: var(--fs-small); margin-bottom: var(--space-3); }
.card-body { color: var(--color-text-muted); }
.card-footer {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* Badge */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: var(--space-1) var(--space-3);
  border-radius: 999px;
  /* Not nowrap: the longest category badges run to ~48 characters, which is
     wider than a phone-width card and used to push the card off-screen. They
     stay on one line wherever there is room and wrap only when there is not. */
  text-align: center;
}
.badge-patent { background: var(--badge-patent-bg); color: var(--badge-patent-text); }
.badge-pub { background: var(--badge-pub-bg); color: var(--badge-pub-text); }
.badge-biorxiv { background: var(--badge-biorxiv-bg); color: var(--badge-biorxiv-text); }
.badge-dev { background: var(--badge-dev-bg); color: var(--badge-dev-text); }

.badge-tier-expert { background: var(--tier-expert-bg); color: var(--tier-expert-text); }
.badge-tier-proficient { background: var(--tier-proficient-bg); color: var(--tier-proficient-text); }
.badge-tier-familiar { background: var(--tier-familiar-bg); color: var(--tier-familiar-text); }

/* Button */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-small);
  font-weight: 600;
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.btn-primary { background: var(--color-accent); color: #ffffff; }
.btn-primary:hover { background: var(--color-accent-dark); }
.btn-secondary { background: transparent; border-color: var(--color-border); color: var(--color-text); }
.btn-secondary:hover { border-color: var(--color-accent); color: var(--color-accent); }

/* Check list (takeaways, key features) */
.check-list li {
  position: relative;
  padding-left: var(--space-5);
  color: var(--color-text-muted);
}
.check-list li + li { margin-top: var(--space-2); }
.check-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.5em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-accent);
}

/* Stats row: inline text stats (no cards), separated by vertical rules */
.stats-row {
  display: flex;
  margin-top: var(--space-7);
}
.stat-block {
  flex: 1;
  text-align: center;
  padding-inline: var(--space-4);
}
.stat-block + .stat-block { border-left: 1px solid var(--color-border); }
.stat-block .stat-label {
  font-size: var(--fs-small);
  color: var(--color-text-muted);
  margin-bottom: var(--space-1);
}
.stat-block .stat-number {
  font-family: var(--font-heading);
  font-size: 2rem;
  font-weight: 700;
  color: var(--color-accent-dark);
}
@media (max-width: 640px) {
  .stats-row { flex-direction: column; }
  .stat-block + .stat-block { border-left: none; border-top: 1px solid var(--color-border); padding-top: var(--space-3); margin-top: var(--space-3); }
}

/* Stat tile */
.stat-tile {
  text-align: center;
  padding: var(--space-5);
  border-radius: var(--radius-lg);
  background: var(--color-accent-bg);
}
.stat-tile .stat-number {
  font-family: var(--font-heading);
  font-size: 2.25rem;
  font-weight: 700;
  color: var(--color-accent-dark);
}
.stat-tile .stat-label {
  font-size: var(--fs-small);
  color: var(--color-text-muted);
  margin-top: var(--space-1);
}

/* ==========================================================================
   Hero / bio
   ========================================================================== */
.hero {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "head  photo"
    "body  photo";
  column-gap: var(--space-7);
  align-items: center;
  padding-block: var(--space-7);
}
.hero-head  { grid-area: head; }
.hero-body  { grid-area: body; }
.hero-photo { grid-area: photo; align-self: center; }

.avatar {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid var(--color-surface);
  box-shadow: var(--shadow-md);
  background: var(--color-accent-bg);
}

.contact-line {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  color: var(--color-text-muted);
  font-size: var(--fs-small);
  margin-top: var(--space-3);
}
.contact-line a:hover { color: var(--color-accent); }
.contact-line .sep { color: var(--color-border); }

@media (max-width: 720px) {
  /* Narrow screens: one column. To move the photo, reorder the three
     words below -- "head" is the name, "photo" the portrait, "body" the
     rest of the intro. */
  .hero {
    grid-template-columns: 1fr;
    grid-template-areas:
      "head"
      "photo"
      "body";
    row-gap: var(--space-4);
    text-align: center;
  }
  .hero-photo { justify-self: center; }
  .contact-line { justify-content: center; }
}

/* Badge, neutral variant for categories */
.badge-neutral { background: var(--color-bg-alt); color: var(--color-text-muted); border: 1px solid var(--color-border); }

/* ==========================================================================
   Timeline (research experience)
   ========================================================================== */
.timeline-item {
  position: relative;
  padding-left: var(--space-6);
  border-left: 2px solid var(--color-border);
  padding-bottom: var(--space-6);
}
.timeline-item:last-child { border-left-color: transparent; padding-bottom: 0; }
.timeline-item::before {
  content: "";
  position: absolute;
  left: -7px;
  top: 4px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--color-accent);
  border: 2px solid var(--color-bg);
}
.timeline-role { font-weight: 700; font-size: var(--fs-h3); }
.timeline-org { color: var(--color-accent); font-weight: 600; font-size: var(--fs-small); margin-bottom: var(--space-2); }
.timeline-dates { color: var(--color-text-muted); font-size: var(--fs-small); font-weight: 600; }

/* ==========================================================================
   Responsive media embeds
   ========================================================================== */

/* Generic aspect-ratio box; default 16:9, override with inline style or modifier */
.embed {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-bg-alt);
  border: 1px solid var(--color-border);
}
.embed iframe,
.embed video,
.embed object {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* PDF viewer: taller aspect ratio than 16:9 to fit a document page */
.embed-pdf { aspect-ratio: 8.5 / 11; }

/* Video stays widescreen */
.embed-video { aspect-ratio: 16 / 9; }

/* ==========================================================================
   Click-to-expand figures

   No JavaScript. Each figure is wrapped in a link pointing at a hidden
   full-screen block further down the page; the browser's :target rule makes
   that block visible when its id is in the address bar. Clicking the expanded
   figure (or pressing Back) points the address bar somewhere else and it
   hides again.
   ========================================================================== */
.zoom { display: block; cursor: zoom-in; }

.zoombox { display: none; }
.zoombox:target {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 100;
  align-items: center;
  justify-content: center;
  padding: 3vmin;
  background: rgba(10, 20, 18, 0.92);
  cursor: zoom-out;
}
/* ":target img" rather than plain ".zoombox img" so these win over the
   fixed 180px height that .gallery img sets on strip thumbnails. */
.zoombox:target img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  margin: 0;
  padding: 0;
  object-fit: contain;
  background: #fff;
  border-radius: var(--radius-md);
}

/* Autoplaying, muted, looping clip used in place of a still on some cards. */
.card-video {
  width: 100%;
  display: block;
  border-radius: var(--radius-md);
  margin-bottom: var(--space-4);
  background: #000;
}

/* Image gallery */
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--space-3);
}
.gallery img {
  width: 100%;
  height: 180px;
  /* "contain" not "cover": these are hand-cropped figures, so show all of each
     one rather than filling the tile and cutting the edges off. The white
     backing matches the figures' own background so they sit on a clean tile. */
  object-fit: contain;
  background: #fff;
  padding: 6px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
}

@media (max-width: 640px) {
  .gallery { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }
  .gallery img { height: 120px; }
}
