/* ==========================================================================
   ONE Lab — Optimization and Estimation Lab
   Design system ported from the Insect-scale Autonomy workshop site,
   retinted to the ONE Lab brand blue (#5869BB).

   PALETTE SWAP — to try the original amber/honey accent instead of blue,
   replace the --link / --link-hover values in each :root block with the
   values listed in the "Amber alternative" comments below.
   ========================================================================== */

:root{
  /* Light theme */
  --bg: #ffffff;
  --panel: rgba(45,60,130,.055);
  --panel2: rgba(45,60,130,.032);
  --text: #12151f;
  --muted: rgba(18,21,31,.68);
  --line: rgba(45,60,130,.16);

  --link: #4a5bb0;              /* Amber alternative: #9b6500 */
  --link-hover: #37468f;        /* Amber alternative: #754b00 */
  --link-text: #ffffff;

  /* Flat brand blue used by every logo SVG in /headimage */
  --brand: #5869bb;

  /* University of New Mexico's brand red ("Cherry") */
  --unm-red: #ba0c2f;

  /* "Open" green, for the live-status dot beside current openings */
  --ok-green: #1f8a4d;

  --max: 736px;   /* 700px of content + 2x18px padding, as the old site */
  --r: 18px;

  /* Dark-mode lift for the flat-blue logo SVGs; none needed in light */
  --logo-filter: none;

  /* Linux Libertine, as the lab has always used. Faces are served from /fonts
     and registered below. */
  --font-body:
    'Linux Libertine', Georgia, 'Times New Roman', Times, serif;

  /* Headings use the display cut (LinLibertine_aBS), matching the old site. */
  --font-display:
    'Linux Libertine Display', 'Linux Libertine', Georgia,
    'Times New Roman', Times, serif;

  /* SANS OPTION — to switch the whole site to the system sans-serif the
     workshop site uses, set --font-body and --font-display both to:
     ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica,
     Arial, sans-serif;  */
}

:root[data-theme="dark"]{
  /* Dark theme */
  --bg: #08090b;
  --panel: rgba(255,255,255,.06);
  --panel2: rgba(255,255,255,.04);
  --text: #eef1f8;
  --muted: rgba(238,241,248,.72);
  --line: rgba(238,241,248,.14);

  --link: #93a4e6;              /* Amber alternative: #e6ad35 */
  --link-hover: #b4c0ef;        /* Amber alternative: #f4c45f */
  --link-text: #0d1020;

  --brand: #8fa0e0;
  --unm-red: #ee5a72;   /* lifted so it reads on near-black */
  --ok-green: #56d08a;  /* likewise */

  --logo-filter: brightness(1.32) saturate(.9);
}

/* --------------------------------------------------------------------------
   Linux Libertine

   Four text cuts plus the display cut used for headings. Paths are relative to
   this stylesheet, which lives at the site root, so they resolve the same way
   from every page.
   -------------------------------------------------------------------------- */

@font-face{
  font-family: 'Linux Libertine';
  src: url('fonts/LinLibertine_R.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face{
  font-family: 'Linux Libertine';
  src: url('fonts/LinLibertine_RI.woff') format('woff');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

@font-face{
  font-family: 'Linux Libertine';
  src: url('fonts/LinLibertine_RB.woff') format('woff');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face{
  font-family: 'Linux Libertine';
  src: url('fonts/LinLibertine_RBI.woff') format('woff');
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}

/* LinLibertine_aBS — the display cut the old site used for h1/h2/h3. It only
   ships a bold weight, so it is declared across the whole bold-and-up range to
   stop the browser synthesising one. */
@font-face{
  font-family: 'Linux Libertine Display';
  src: url('fonts/LinLibertine_aBS.woff') format('woff');
  font-weight: 600 900;
  font-style: normal;
  font-display: swap;
}

*{
  box-sizing: border-box;
}

html,
body{
  margin: 0;
  padding: 0;
}

html{
  min-height: 100%;
  scroll-behavior: smooth;
}

body{
  min-height: 100vh;
  display: flex;
  flex-direction: column;

  font-family: var(--font-body);

  background: var(--bg);

  color: var(--text);
  font-size: 17px;
  line-height: 1.7;
}

/* Page and section headings take the small-caps display cut, as on the
   previous site. Small caps want a little tracking to breathe. h3 — card
   titles, people's names, project names — stays in the text face, bold. */
h1, h2{
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: .015em;
}

h3{
  font-family: var(--font-body);
  font-weight: 700;
}

body > main{
  width: 100%;
  flex: 1 0 auto;
}

a{
  color: var(--link);
  text-decoration: none;
}

a:hover{
  text-decoration: underline;
}

/* Trailing mark on an inline link that leaves the site: drawn in the link's
   own colour with the same round strokes as the icon links, sized to the
   text so it sits on the line rather than pushing it apart. */
.ext-icon{
  width: .78em;
  height: .78em;
  margin-left: .18em;
  vertical-align: -.04em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Read by screen readers, invisible on screen. */
.sr-only{
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

code{
  padding: 1px 5px;
  border-radius: 5px;
  background: var(--panel);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .92em;
}

hr{
  height: 1px;
  margin: 22px 0;
  border: 0;
  background: var(--line);
}

.container{
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 18px;
}

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */

.header{
  position: sticky;
  top: 0;
  z-index: 20;

  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);

  background: color-mix(in srgb, var(--bg) 72%, transparent);
}

/* Rules under the header and over the footer run the width of the content
   column, not the viewport. --rule-w is the content width: the container's
   max, or the viewport minus its side padding, whichever is narrower. */
:root{
  --rule-w: min(calc(var(--max) - 36px), calc(100% - 36px));
}

.header::after,
.footer::before{
  content: "";
  display: block;
  width: var(--rule-w);
  height: 1px;
  margin: 0 auto;
  background: var(--line);
}

.navbar{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 13px 18px;
}

/* The wordmark is the ONE Lab logo itself, the same file the footer uses. */
/* The brand links home but stays plain — no glass, no hover state; the
   "Home" pill in the nav carries the active state. Left-aligned. */
.brand{
  grid-area: brand;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  text-align: left;
  text-decoration: none;
}

.brand:hover{
  text-decoration: none;
}

/* Hover: the tagline's first line ("Optimization and Estimation Laboratory")
   takes the theme blue and the second ("University of New Mexico") takes UNM
   red. The whole <small> goes red, then ::first-line overrides line one — the
   <br /> in the tagline makes that exactly the lab's name. */
.brand:hover small{
  color: var(--unm-red);
}

.brand:hover small::first-line{
  color: var(--link);
}

.brandLogo{
  display: block;
  width: 132px;
  height: auto;
  filter: var(--logo-filter);
}

.brand small{
  color: var(--muted);
  font-size: 13.5px;
  line-height: 1.45;
}

.nav{
  grid-area: nav;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 3px;
}

.nav a{
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;

  padding: 8px 9px;
  border: 1px solid transparent;
  border-radius: 999px;

  /* Resting state matches the projects seg-nav: muted rather than full text
     colour, a size down, and semi-bold so the weight does not jump as much
     when a pill becomes active. Padding stays tighter here - five items share
     the bar with the wordmark and the theme toggle. */
  color: var(--muted);
  font-size: 15px;
  font-weight: 620;
  white-space: nowrap;
  text-decoration: none;

  transition:
    background-color 200ms ease,
    border-color 200ms ease,
    box-shadow 200ms ease,
    color 200ms ease;
}

/* Every pill is as wide as its label would be in bold, always: a hidden bold
   copy of the label sits beneath the real one at zero height. So making the
   active pill bold changes nothing — no wrap, and no pills shifting sideways
   as you move between pages. */
.nav a::after{
  content: attr(data-label);
  height: 0;
  overflow: hidden;
  visibility: hidden;
  font-weight: 700;
  pointer-events: none;
}

/* The rim the cards carry, sized for a pill: brightest at the two ends, where
   the surface curves away fastest. It stays mounted at zero opacity so it
   fades in with the fill instead of popping on hover. */
.nav a::before{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;

  background: linear-gradient(90deg,
    rgba(255,255,255,1)   0%,
    rgba(255,255,255,.58) 11%,
    rgba(255,255,255,.12) 33%,
    rgba(255,255,255,.06) 50%,
    rgba(255,255,255,.12) 67%,
    rgba(255,255,255,.58) 89%,
    rgba(255,255,255,1)   100%);

  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;

  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none;
}

.nav a:hover::before{ opacity: .7; }

.nav a.active::before,
.nav a[aria-current="page"]::before{ opacity: 1; }

:root[data-theme="dark"] .nav a::before{
  background: linear-gradient(90deg,
    rgba(255,255,255,.82) 0%,
    rgba(255,255,255,.42) 11%,
    rgba(255,255,255,.09) 33%,
    rgba(255,255,255,.04) 50%,
    rgba(255,255,255,.09) 67%,
    rgba(255,255,255,.42) 89%,
    rgba(255,255,255,.82) 100%);
}

/* ---------------------------------------------------------------------------
   Liquid glass

   The hover and active pills are a translucent material rather than a flat
   grey wash: the backdrop is blurred and its colour pushed, a bright specular
   line sits on the top edge, and a soft shadow lifts the pill off the bar. The
   tint is the brand blue, not neutral — a grey veil over a warm page reads as
   dirt. Without backdrop-filter the tinted fill alone still looks deliberate.
   --------------------------------------------------------------------------- */

.nav a:hover{
  border-color: color-mix(in srgb, var(--link) 16%, transparent);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 62%, transparent),
      color-mix(in srgb, #fff 24%, transparent)),
    color-mix(in srgb, var(--link) 3%, transparent);
  backdrop-filter: blur(10px) saturate(150%);
  -webkit-backdrop-filter: blur(10px) saturate(150%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.6),
    inset 5px 0 10px -8px rgba(255,255,255,.95),
    inset -5px 0 10px -8px rgba(255,255,255,.95),
    0 1px 4px color-mix(in srgb, var(--link) 10%, transparent);
  text-decoration: none;
}

/* Tint kept light, as on the seg-nav: mixed much above this it shows through
   the white gradient as a muddy lavender instead of reading as clear glass.
   The colour lives in the border, the rim and the label. */
.nav a.active,
.nav a[aria-current="page"]{
  border-color: color-mix(in srgb, var(--link) 32%, transparent);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 82%, transparent),
      color-mix(in srgb, #fff 40%, transparent)),
    color-mix(in srgb, var(--link) 5%, transparent);
  backdrop-filter: blur(16px) saturate(185%);
  -webkit-backdrop-filter: blur(16px) saturate(185%);
  color: var(--link);
  font-weight: 700;
  text-decoration: none;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 -1px 2px color-mix(in srgb, var(--link) 6%, transparent),
    inset 6px 0 11px -8px rgba(255,255,255,1),
    inset -6px 0 11px -8px rgba(255,255,255,1),
    0 2px 9px color-mix(in srgb, var(--link) 12%, transparent);
  border-left-color: color-mix(in srgb, var(--link) 46%, transparent);
  border-right-color: color-mix(in srgb, var(--link) 46%, transparent);
}

/* Dark mode inverts the material: the glass is lit from a dim page, so the
   specular edge is much weaker and the fill leans on the tint. */
:root[data-theme="dark"] .nav a:hover{
  border-color: color-mix(in srgb, var(--link) 22%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.1), rgba(255,255,255,.03)),
    color-mix(in srgb, var(--link) 10%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.14),
    inset 5px 0 10px -8px rgba(255,255,255,.5),
    inset -5px 0 10px -8px rgba(255,255,255,.5),
    0 1px 5px rgba(0,0,0,.3);
}

:root[data-theme="dark"] .nav a.active,
:root[data-theme="dark"] .nav a[aria-current="page"]{
  border-color: color-mix(in srgb, var(--link) 34%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.15), rgba(255,255,255,.05)),
    color-mix(in srgb, var(--link) 18%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.24),
    inset 0 -1px 2px rgba(0,0,0,.25),
    inset 6px 0 11px -8px rgba(255,255,255,.6),
    inset -6px 0 11px -8px rgba(255,255,255,.6),
    0 2px 11px rgba(0,0,0,.38);
}

.navLabelMobile{
  display: none;
}

/* Theme toggle */

.themeBtn{
  grid-area: theme;
  align-self: center;

  width: 64px;
  height: 36px;

  display: inline-flex;
  align-items: center;
  justify-content: center;

  flex: 0 0 auto;

  padding: 0;
  border: 0;
  border-radius: 999px;

  background: transparent;
  color: var(--text);

  cursor: pointer;
}

/* Glass toggle: the track is a recessed groove (inset shading, tinted rather
   than grey) and the thumb a raised bead. No overflow clipping, so the bead's
   drop shadow can actually read as lift. */
.themeTrack{
  position: relative;
  width: 62px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 8px;
  border: 1px solid color-mix(in srgb, var(--link) 20%, transparent);
  border-radius: 999px;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 32%, transparent),
      color-mix(in srgb, #fff 6%, transparent)),
    color-mix(in srgb, var(--link) 9%, transparent);
  backdrop-filter: blur(12px) saturate(170%);
  -webkit-backdrop-filter: blur(12px) saturate(170%);
  box-shadow:
    inset 0 1px 2px color-mix(in srgb, var(--link) 18%, transparent),
    inset 0 -1px 0 rgba(255,255,255,.55),
    inset 6px 0 11px -8px rgba(255,255,255,.9),
    inset -6px 0 11px -8px rgba(255,255,255,.9);
  border-left-color: color-mix(in srgb, var(--link) 40%, transparent);
  border-right-color: color-mix(in srgb, var(--link) 40%, transparent);
  transition:
    background-color 180ms ease,
    border-color 180ms ease,
    box-shadow 180ms ease;
}

.themeIcon{
  position: relative;
  z-index: 2;
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: color 180ms ease, opacity 180ms ease;
}

.themeIconSun{
  color: #c08a1d;
}

.themeIconMoon{
  color: var(--muted);
}

.themeThumb{
  position: absolute;
  z-index: 1;
  top: 3px;
  left: 3px;
  width: 26px;
  height: 26px;
  border: 1px solid rgba(255,255,255,.8);
  border-radius: 50%;
  background: linear-gradient(180deg, rgba(255,255,255,.97), rgba(255,255,255,.7));
  backdrop-filter: blur(6px) saturate(160%);
  -webkit-backdrop-filter: blur(6px) saturate(160%);
  box-shadow:
    inset 0 1px 0 #fff,
    0 2px 6px color-mix(in srgb, var(--link) 28%, transparent),
    0 1px 2px rgba(0,0,0,.14);
  transition:
    transform 260ms cubic-bezier(.34, 1.56, .5, 1),
    background 180ms ease,
    box-shadow 180ms ease;
}

:root[data-theme="dark"] .themeThumb{
  transform: translateX(28px);
}

:root[data-theme="dark"] .themeIconSun{
  color: var(--muted);
}

:root[data-theme="dark"] .themeIconMoon{
  color: #b4c0ef;
}

.themeBtn:hover .themeTrack{
  border-color: color-mix(in srgb, var(--link) 34%, transparent);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 46%, transparent),
      color-mix(in srgb, #fff 12%, transparent)),
    color-mix(in srgb, var(--link) 13%, transparent);
}

.themeBtn:hover .themeThumb{
  box-shadow:
    inset 0 1px 0 #fff,
    0 3px 9px color-mix(in srgb, var(--link) 34%, transparent),
    0 1px 2px rgba(0,0,0,.16);
}

/* Dark mode: the groove darkens and the bead becomes frosted rather than
   white, so it does not glare against the near-black bar. */
:root[data-theme="dark"] .themeTrack{
  border-color: color-mix(in srgb, var(--link) 26%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.1), rgba(255,255,255,.02)),
    color-mix(in srgb, var(--link) 12%, transparent);
  box-shadow:
    inset 0 1px 3px rgba(0,0,0,.5),
    inset 0 -1px 0 rgba(255,255,255,.1),
    inset 6px 0 11px -8px rgba(255,255,255,.45),
    inset -6px 0 11px -8px rgba(255,255,255,.45);
}

:root[data-theme="dark"] .themeBtn:hover .themeTrack{
  border-color: color-mix(in srgb, var(--link) 40%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.15), rgba(255,255,255,.05)),
    color-mix(in srgb, var(--link) 18%, transparent);
}

:root[data-theme="dark"] .themeThumb{
  border-color: rgba(255,255,255,.3);
  background: linear-gradient(180deg, rgba(255,255,255,.32), rgba(255,255,255,.16));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.5),
    0 2px 8px rgba(0,0,0,.55);
}

:root[data-theme="dark"] .themeBtn:hover .themeThumb{
  background: linear-gradient(180deg, rgba(255,255,255,.4), rgba(255,255,255,.22));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.6),
    0 3px 10px rgba(0,0,0,.6);
}

.themeBtn:focus-visible{
  outline: 2px solid var(--link);
  outline-offset: 3px;
}

.themeBtn:active{
  transform: translateY(1px);
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

/* Banner across the top of every page, as on the previous site. There are two
   files — the original on its light ground, and a dark-ground version made
   from it — and the theme decides which one shows. Both are in the markup so
   the switch is instant and needs no JavaScript. */
/* --------------------------------------------------------------------------
   Banner

   The glass treatment the cards carry, applied to the masthead image. An
   <img> cannot host it directly: inset shadows and generated content paint
   under a replaced element's content, so the edge would be buried beneath the
   photograph. The wrapper supplies both - ::before for the light gathered
   along the vertical edges, ::after for the 1px specular rim - and each paints
   over the image.
   -------------------------------------------------------------------------- */

.banner-wrap{
  position: relative;
  margin: 26px 0 0;

  border: 1px solid color-mix(in srgb, var(--link) 18%, transparent);
  border-left-color: color-mix(in srgb, var(--link) 26%, transparent);
  border-right-color: color-mix(in srgb, var(--link) 26%, transparent);

  /* Square, unlike the cards: the masthead reads as a pane of glass laid over
     the page rather than a rounded panel sitting on it. */
  border-radius: 0;
  overflow: hidden;

  box-shadow:
    0 10px 28px color-mix(in srgb, var(--link) 10%, transparent),
    0 1px 3px color-mix(in srgb, var(--link) 8%, transparent);
}

.banner{
  display: block;
  width: 100%;
  height: auto;
  border: 0;
}

.banner-wrap::before,
.banner-wrap::after{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 0;
  pointer-events: none;
}

.banner-wrap::before{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.92),
    inset 9px 0 16px -12px rgba(255,255,255,.95),
    inset -9px 0 16px -12px rgba(255,255,255,.95);
}

.banner-wrap::after{
  padding: 1px;   /* rim thickness */
  background: linear-gradient(90deg,
    rgba(255,255,255,.98) 0%,
    rgba(255,255,255,.62) 5%,
    rgba(255,255,255,.14) 24%,
    rgba(255,255,255,.07) 50%,
    rgba(255,255,255,.14) 76%,
    rgba(255,255,255,.62) 95%,
    rgba(255,255,255,.98) 100%);

  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}

:root[data-theme="dark"] .banner-wrap{
  border-color: color-mix(in srgb, var(--link) 24%, transparent);
  box-shadow:
    0 10px 30px rgba(0,0,0,.45),
    0 1px 3px rgba(0,0,0,.3);
}

:root[data-theme="dark"] .banner-wrap::before{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.14),
    inset 9px 0 16px -12px rgba(255,255,255,.55),
    inset -9px 0 16px -12px rgba(255,255,255,.55);
}

:root[data-theme="dark"] .banner-wrap::after{
  background: linear-gradient(90deg,
    rgba(255,255,255,.80) 0%,
    rgba(255,255,255,.44) 5%,
    rgba(255,255,255,.10) 24%,
    rgba(255,255,255,.05) 50%,
    rgba(255,255,255,.10) 76%,
    rgba(255,255,255,.44) 95%,
    rgba(255,255,255,.80) 100%);
}

.banner--dark{
  display: none;
}

:root[data-theme="dark"] .banner--light{
  display: none;
}

:root[data-theme="dark"] .banner--dark{
  display: block;
}

/* Whatever follows the banner sits a fixed distance below it, rather than
   using the larger top padding meant for a page that opens on the header. */
.banner-wrap + .welcome{
  margin-top: 20px;
}

.banner-wrap + .hero{
  padding-top: 26px;
}

.banner-wrap + .section{
  padding-top: 26px;
}

/* Centred greeting above the hero, as on the previous site. */
.welcome{
  margin: 30px 0 0;
  color: var(--text);
  font-size: 20px;
  line-height: 1.5;
  text-align: center;
}

.welcome + .hero{
  padding-top: 24px;
}

.hero{
  padding: 52px 0 22px;
}

/* The 52px above is the drop from the banner to a page's opening hero. A hero
   further down, after a section, keeps the section-to-section rhythm instead. */
.section + .hero{
  padding-top: 18px;
}

.hero-grid{
  display: grid;
  grid-template-columns: 1.1fr .9fr;
  gap: 18px;
  align-items: start;
}

.hero h1{
  margin: 0 0 10px;
  font-size: clamp(28px, 4.4vw, 38px);
  line-height: 1.06;
  letter-spacing: .2px;
}

/* A hero further down a page, below the page's own heading, titles itself
   with an h2 at the section-heading size rather than a second h1. */
.hero h2{
  margin: 0 0 10px;
  font-size: 26px;
  line-height: 1.15;
}

.hero p{
  margin: 0 0 14px;
  color: var(--muted);
}

.badges{
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Badges are the small, non-interactive pills — the nav's resting-glass
   weight, since nothing happens on hover. */
.badge{
  display: inline-flex;
  align-items: center;

  padding: 6px 10px;
  border: 1px solid color-mix(in srgb, var(--link) 16%, transparent);
  border-radius: 999px;

  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 52%, transparent),
      color-mix(in srgb, #fff 14%, transparent)),
    color-mix(in srgb, var(--link) 7%, transparent);
  backdrop-filter: blur(10px) saturate(150%);
  -webkit-backdrop-filter: blur(10px) saturate(150%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.72),
    0 1px 4px color-mix(in srgb, var(--link) 10%, transparent);
  color: var(--muted);

  font-size: 13px;
}

:root[data-theme="dark"] .badge{
  border-color: color-mix(in srgb, var(--link) 22%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.09), rgba(255,255,255,.03)),
    color-mix(in srgb, var(--link) 10%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.13),
    0 1px 4px rgba(0,0,0,.3);
}

/* --------------------------------------------------------------------------
   Cards, sections, prose
   -------------------------------------------------------------------------- */

/* Glass panel — the same material as the nav pills, scaled up. A large area
   wants a gentler tint and a softer, wider shadow than a small pill, or it
   reads as a heavy slab rather than a sheet of glass. Shared by .card,
   .prose and .project-card so they stay identical. */
.card,
.prose,
.project-card,
.person-card,
.pi-card,
.news-card,
.alum-row,
.pub-item,
.faq-item,
.callout{
  border: 1px solid color-mix(in srgb, var(--link) 18%, transparent);
  border-radius: var(--r);

  /* On a light page a white specular line has nothing to read against, so the
     two sides carry a denser outer contour than the top and bottom: the
     refracted dark edge real glass shows just outside its highlight. Dark mode
     resets all four sides below, where the rim alone already separates the
     card from the page. */
  border-left-color: color-mix(in srgb, var(--link) 26%, transparent);
  border-right-color: color-mix(in srgb, var(--link) 26%, transparent);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 74%, transparent),
      color-mix(in srgb, #fff 42%, transparent)),
    color-mix(in srgb, var(--link) 6%, transparent);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.92),
    inset 0 -1px 0 color-mix(in srgb, var(--link) 8%, transparent),
    /* Light gathered along the two vertical edges and bleeding inward, the
       way a thick glass slab lenses whatever sits behind it. */
    inset 9px 0 16px -12px rgba(255,255,255,.95),
    inset -9px 0 16px -12px rgba(255,255,255,.95),
    0 10px 28px color-mix(in srgb, var(--link) 10%, transparent),
    0 1px 3px color-mix(in srgb, var(--link) 8%, transparent);

  position: relative;
}

/* --------------------------------------------------------------------------
   Liquid-glass rim

   Glass throws its brightest specular line where the surface curves away
   fastest -- the left and right sides -- and that highlight falls off across
   the flat face. A single top border cannot show this, so the rim is painted
   as a masked gradient ring: a horizontal gradient clipped to a 1px band
   around the edge, near-white at both sides and almost clear across the
   middle. The mask keeps only the band, leaving the card's own backdrop
   untouched.
   -------------------------------------------------------------------------- */

.card::after,
.prose::after,
.project-card::after,
.person-card::after,
.pi-card::after,
.news-card::after,
.alum-row::after,
.pub-item::after,
.faq-item::after,
.callout::after{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: calc(var(--r) - 1px);
  padding: 1px;   /* rim thickness */

  background: linear-gradient(90deg,
    rgba(255,255,255,.98) 0%,
    rgba(255,255,255,.62) 5%,
    rgba(255,255,255,.14) 24%,
    rgba(255,255,255,.07) 50%,
    rgba(255,255,255,.14) 76%,
    rgba(255,255,255,.62) 95%,
    rgba(255,255,255,.98) 100%);

  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;

  pointer-events: none;
}

.card{
  padding: 16px;
}

:root[data-theme="dark"] .card,
:root[data-theme="dark"] .prose,
:root[data-theme="dark"] .project-card,
:root[data-theme="dark"] .person-card,
:root[data-theme="dark"] .pi-card,
:root[data-theme="dark"] .news-card,
:root[data-theme="dark"] .alum-row,
:root[data-theme="dark"] .pub-item,
:root[data-theme="dark"] .faq-item,
:root[data-theme="dark"] .callout{
  border-color: color-mix(in srgb, var(--link) 24%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.085), rgba(255,255,255,.03)),
    color-mix(in srgb, var(--link) 9%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.14),
    inset 0 -1px 0 rgba(0,0,0,.25),
    inset 9px 0 16px -12px rgba(255,255,255,.55),
    inset -9px 0 16px -12px rgba(255,255,255,.55),
    0 10px 30px rgba(0,0,0,.45),
    0 1px 3px rgba(0,0,0,.3);
}

/* On near-black the rim is the only thing separating card from page, so the
   sides stay bright while the top and bottom drop back further than in light
   mode -- the same falloff, pushed harder. */
:root[data-theme="dark"] .card::after,
:root[data-theme="dark"] .prose::after,
:root[data-theme="dark"] .project-card::after,
:root[data-theme="dark"] .person-card::after,
:root[data-theme="dark"] .pi-card::after,
:root[data-theme="dark"] .news-card::after,
:root[data-theme="dark"] .alum-row::after,
:root[data-theme="dark"] .pub-item::after,
:root[data-theme="dark"] .faq-item::after,
:root[data-theme="dark"] .callout::after{
  background: linear-gradient(90deg,
    rgba(255,255,255,.80) 0%,
    rgba(255,255,255,.44) 5%,
    rgba(255,255,255,.10) 24%,
    rgba(255,255,255,.05) 50%,
    rgba(255,255,255,.10) 76%,
    rgba(255,255,255,.44) 95%,
    rgba(255,255,255,.80) 100%);
}

.card h3{
  margin: 0 0 8px;
}

/* Card header row: title on the left, action link pushed to the far right.
   Wraps to two lines on narrow cards rather than squeezing the title. */
.card-head{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin: 0 0 8px;
}

.card-head h3{
  margin: 0;
}

.card p{
  margin: 0 0 6px;
  color: var(--muted);
}

.card p strong{
  color: var(--text);
}

.section{
  padding: 18px 0 10px;
}

/* The last section on a page has nothing below it, so its 10px of padding put
   the content almost against the footer's divider. Only the final one needs
   the gap - between siblings the 18px top padding already does the work. The
   value matches .people-section:last-child so both page types agree. */
.section:last-child{
  padding-bottom: 34px;
}

/* A section heading with an action on its right. The h2 is listed for both
   positions so it keeps exactly the margins and size it has as a direct child
   of .section - the label -> heading -> intro rhythm is unchanged by the
   wrapper. */
.section > h2,
.section > .section-head > h2{
  margin: 0 0 4px;
  font-size: 26px;
}

/* Beside a button, the heading's gap below moves to the row, so the button
   centres on the heading; the space under the row is the same 4px. */
.section > .section-head{
  margin: 0 0 4px;
}

.section > .section-head > h2{
  margin: 0;
}

.section-head{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

/* A button with no heading beside it still sits at the right. */
.section-head > :only-child{
  margin-left: auto;
}

/* A list of rows (the home page's courses) with its button beside the
   heading: the heading's gap below moves to the row, so the button centres
   on the heading rather than on the heading and its margin. */
.people-section > .section-head{
  margin: 0 0 12px;
}

.people-section > .section-head > h2{
  margin: 0;
}

.section-label{
  margin: 0 0 2px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 750;
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* "All projects" / "All news" link at the foot of a home-page section. */
.section-more{
  margin: 18px 0 0;
  text-align: right;
}

.section-intro{
  margin: 0 0 18px;
  color: var(--muted);
  max-width: 68ch;
}

.prose{
  min-width: 0;
  padding: 22px;
  /* material: see the shared .card, .prose glass rule above */
}

.prose > :first-child{
  margin-top: 0;
}

.prose > :last-child{
  margin-bottom: 0;
}

.prose h2{
  margin: 26px 0 10px;
  font-size: 23px;
}

.prose h3{
  margin: 20px 0 8px;
  font-size: 18px;
}

.prose p,
.prose li{
  color: var(--muted);
}

.prose strong{
  color: var(--text);
}

.prose img{
  display: block;
  max-width: 100%;
  height: auto;
  margin: 0 0 1.4rem;
  border-radius: 14px;
}

/* Full column width - unless the Markdown gave the image a width. */
.prose img:not([width]){
  width: 100%;
}

.prose h2,
.prose h3,
.section > h2{
  scroll-margin-top: 110px;
}

/* Home-page intro: text beside the director's photo — the old site's
   78% / 22% table, as a grid. */
/* The text column is sized so the opening paragraph wraps on four lines in
   Libertine at 17px (it needs 486-525px). The panel's padding is trimmed a
   little so that width and a ~160px photo both fit with a gap between. */
.prose.intro{
  padding: 20px 16px;

  /* Lifts on hover like the news and project cards. Scoped to .intro: plain
     .prose is the body copy on the project and news detail pages, where a
     whole article rising under the cursor would be wrong. */
  transition:
    transform 160ms ease,
    box-shadow 160ms ease,
    border-color 160ms ease;
}

.intro{
  display: grid;
  grid-template-columns: 496px minmax(0, 1fr);
  column-gap: 14px;
  row-gap: 8px;
  align-items: center;
}

.intro-text > :first-child{
  margin-top: 0;
}

.intro-text > :last-child{
  margin-bottom: 0;
}

.intro-sign{
  margin: 6px 0 0;
  text-align: right;
  line-height: 1.5;
}

.intro-sign strong{
  color: var(--link);
}

.intro-pi{
  justify-self: end;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.intro-pi img{
  display: block;
  width: 158px;
  height: 158px;
  border: 1px solid var(--line);
  border-radius: 14px;
  object-fit: cover;
  object-position: center top;
}

/* Website, LinkedIn and email, centred under the portrait. Three across also
   keeps the block inside the 160px photo above it. The rest of the director's
   profiles live on his People card. */
.intro-links{
  display: grid;
  grid-template-columns: repeat(3, auto);
  gap: 8px;
  justify-content: center;
}

/* --------------------------------------------------------------------------
   Buttons and pill links
   -------------------------------------------------------------------------- */

.btn{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;

  margin-top: 12px;
  padding: 9px 16px;

  border: 1px solid color-mix(in srgb, var(--link) 72%, transparent);
  border-radius: 999px;

  background: var(--link);
  color: var(--link-text);

  font-size: 15px;
  font-weight: 650;
  line-height: 1.2;
  text-decoration: none;

  box-shadow: 0 6px 18px color-mix(in srgb, var(--link) 22%, transparent);

  transition:
    transform 150ms ease,
    background-color 150ms ease,
    box-shadow 150ms ease;
}

.btn:hover{
  background: var(--link-hover);
  color: var(--link-text);
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 9px 24px color-mix(in srgb, var(--link) 30%, transparent);
}

.btn:active{
  transform: translateY(0);
}

.btn span{
  transition: transform 160ms ease;
}

.btn:hover span{
  transform: translateX(3px);
}

.btn-ghost,
.ref-link{
  display: inline-flex;
  align-items: center;
  gap: 8px;

  padding: 8px 14px;
  border: 1px solid color-mix(in srgb, var(--link) 45%, var(--line));
  border-radius: 999px;

  background: color-mix(in srgb, var(--link) 9%, transparent);
  color: var(--link);

  font-size: 14.5px;
  font-weight: 650;
  line-height: 1.2;
  text-decoration: none;

  transition:
    transform 160ms ease,
    background-color 160ms ease,
    box-shadow 160ms ease;
}

.btn-ghost:hover,
.ref-link:hover{
  transform: translateY(-1px);
  background: color-mix(in srgb, var(--link) 16%, transparent);
  box-shadow: 0 8px 20px color-mix(in srgb, var(--link) 15%, transparent);
  text-decoration: none;
}

/* The ghost button's look at the pill's own size: these sit inline under a
   news card's body copy, not at the foot of a section, so they keep the
   smaller metrics they have always had. Listed after the shared rule above -
   same specificity, so order decides. */
.ref-link{
  gap: 5px;
  padding: 3px 9px;
  font-size: 13px;
}

.back-link{
  margin-top: 26px;
}

/* At the top of a panel (the research project pages) the link needs no gap
   above it - the panel's own padding is the space, matching the inset on the
   left - and a short one below. Flex makes the paragraph exactly as tall as
   the button, with no extra line height above or below it. */
.prose > p:first-child:has(> .back-link){
  display: flex;
  margin: 0 0 14px;
}

.prose > p:first-child > .back-link{
  margin-top: 0;
}

.back-link span{
  transition: transform 160ms ease;
}

.back-link:hover span{
  transform: translateX(-3px);
}

/* --------------------------------------------------------------------------
   Inline pill link

   A link inside a sentence dressed as the nav's active pill: the same light
   fill, the denser contour at each end and the same specular rim, scaled down
   to sit on a line of body copy rather than in a bar.
   -------------------------------------------------------------------------- */

.pill-link{
  position: relative;
  display: inline-flex;
  align-items: center;
  vertical-align: baseline;

  /* Sized in em so it tracks whatever copy it sits in rather than fixing a
     px size that only suits one paragraph. */
  padding: 0 8px;
  font-size: .88em;
  border: 1px solid color-mix(in srgb, var(--link) 32%, transparent);
  border-left-color: color-mix(in srgb, var(--link) 46%, transparent);
  border-right-color: color-mix(in srgb, var(--link) 46%, transparent);
  border-radius: 999px;

  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 82%, transparent),
      color-mix(in srgb, #fff 40%, transparent)),
    color-mix(in srgb, var(--link) 5%, transparent);
  backdrop-filter: blur(14px) saturate(180%);
  -webkit-backdrop-filter: blur(14px) saturate(180%);

  color: var(--link);
  font-weight: 650;
  text-decoration: none;

  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 6px 0 11px -8px rgba(255,255,255,1),
    inset -6px 0 11px -8px rgba(255,255,255,1),
    0 2px 8px color-mix(in srgb, var(--link) 11%, transparent);

  transition:
    transform 150ms ease,
    background-color 150ms ease,
    border-color 150ms ease,
    box-shadow 150ms ease;
}

.pill-link::before{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(90deg,
    rgba(255,255,255,1)   0%,
    rgba(255,255,255,.58) 11%,
    rgba(255,255,255,.12) 33%,
    rgba(255,255,255,.06) 50%,
    rgba(255,255,255,.12) 67%,
    rgba(255,255,255,.58) 89%,
    rgba(255,255,255,1)   100%);

  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
}

.pill-link:hover{
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--link) 46%, transparent);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 88%, transparent),
      color-mix(in srgb, #fff 48%, transparent)),
    color-mix(in srgb, var(--link) 9%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,1),
    inset 6px 0 11px -8px rgba(255,255,255,1),
    inset -6px 0 11px -8px rgba(255,255,255,1),
    0 3px 11px color-mix(in srgb, var(--link) 16%, transparent);
  text-decoration: none;
}

:root[data-theme="dark"] .pill-link{
  border-color: color-mix(in srgb, var(--link) 34%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.15), rgba(255,255,255,.05)),
    color-mix(in srgb, var(--link) 18%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.24),
    inset 6px 0 11px -8px rgba(255,255,255,.6),
    inset -6px 0 11px -8px rgba(255,255,255,.6),
    0 2px 10px rgba(0,0,0,.36);
}

:root[data-theme="dark"] .pill-link::before{
  background: linear-gradient(90deg,
    rgba(255,255,255,.82) 0%,
    rgba(255,255,255,.42) 11%,
    rgba(255,255,255,.09) 33%,
    rgba(255,255,255,.04) 50%,
    rgba(255,255,255,.09) 67%,
    rgba(255,255,255,.42) 89%,
    rgba(255,255,255,.82) 100%);
}

/* Inline reference pills — [Slides], [Project page], [SoE News] … */

.ref-links{
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}

/* Reference pills — [Slides], [Project page], [Early Access]… — use the
   ghost-button look above verbatim, so the two never drift apart. Only the
   outward-arrow icon is specific to them. */
/* The outward arrow comes from the class, not the markup, so every reference
   pill carries one without the icon being repeated in every page. Masked over
   currentColor so it takes the pill's colour and its hover change. */
.ref-link::after{
  content: "";
  width: 12px;
  height: 12px;
  flex: 0 0 12px;

  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 4h6v6'/%3E%3Cpath d='M20 4 10 14'/%3E%3Cpath d='M18 13v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 4h6v6'/%3E%3Cpath d='M20 4 10 14'/%3E%3Cpath d='M18 13v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5'/%3E%3C/svg%3E") center / contain no-repeat;

  opacity: .75;
  transition: opacity 150ms ease;
}

.ref-link:hover::after{
  opacity: 1;
}

/* --------------------------------------------------------------------------
   Segmented sub-navigation (Projects tabs)
   -------------------------------------------------------------------------- */

/* Bare row of pills — no tray behind them. */
.seg-nav{
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 7px;
  margin: 0 0 22px;
}

.seg-nav a{
  position: relative;
  flex: 0 0 auto;

  display: inline-flex;
  align-items: center;
  justify-content: center;

  padding: 8px 16px;
  border: 1px solid transparent;
  border-radius: 999px;

  color: var(--muted);
  font-size: 15px;
  font-weight: 620;
  text-decoration: none;
  white-space: nowrap;

  transition:
    background-color 150ms ease,
    border-color 150ms ease,
    color 150ms ease;
}

/* Same glass material as the primary nav — these are the same idea. */
.seg-nav a:hover{
  border-color: color-mix(in srgb, var(--link) 14%, transparent);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 42%, transparent),
      color-mix(in srgb, #fff 12%, transparent)),
    color-mix(in srgb, var(--link) 6%, transparent);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.55);
  color: var(--text);
  text-decoration: none;
}

/* The blue tint is kept light here. Mixed much above this, it shows through
   the white gradient as a muddy lavender rather than reading as clear glass;
   the border and the text carry the colour instead. */
.seg-nav a[aria-current="page"]{
  border-color: color-mix(in srgb, var(--link) 32%, transparent);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 82%, transparent),
      color-mix(in srgb, #fff 40%, transparent)),
    color-mix(in srgb, var(--link) 5%, transparent);
  backdrop-filter: blur(14px) saturate(180%);
  -webkit-backdrop-filter: blur(14px) saturate(180%);
  color: var(--link);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 -1px 2px color-mix(in srgb, var(--link) 6%, transparent),
    /* Light gathered along the two ends, where the surface curves away. */
    inset 6px 0 11px -8px rgba(255,255,255,1),
    inset -6px 0 11px -8px rgba(255,255,255,1),
    0 2px 8px color-mix(in srgb, var(--link) 11%, transparent);

  /* The ends carry a denser contour than the top and bottom, so the pill has
     an edge to read against on a light page. */
  border-left-color: color-mix(in srgb, var(--link) 46%, transparent);
  border-right-color: color-mix(in srgb, var(--link) 46%, transparent);
}

/* The specular rim the cards and the header pills carry: a 1px ring that is
   near-white at both ends and almost clear across the face. */
.seg-nav a[aria-current="page"]::before{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;

  background: linear-gradient(90deg,
    rgba(255,255,255,1)   0%,
    rgba(255,255,255,.58) 11%,
    rgba(255,255,255,.12) 33%,
    rgba(255,255,255,.06) 50%,
    rgba(255,255,255,.12) 67%,
    rgba(255,255,255,.58) 89%,
    rgba(255,255,255,1)   100%);

  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;

  pointer-events: none;
}

:root[data-theme="dark"] .seg-nav a[aria-current="page"]::before{
  background: linear-gradient(90deg,
    rgba(255,255,255,.82) 0%,
    rgba(255,255,255,.42) 11%,
    rgba(255,255,255,.09) 33%,
    rgba(255,255,255,.04) 50%,
    rgba(255,255,255,.09) 67%,
    rgba(255,255,255,.42) 89%,
    rgba(255,255,255,.82) 100%);
}

:root[data-theme="dark"] .seg-nav a:hover{
  background:
    linear-gradient(180deg, rgba(255,255,255,.09), rgba(255,255,255,.03)),
    color-mix(in srgb, var(--link) 9%, transparent);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.12);
}

:root[data-theme="dark"] .seg-nav a[aria-current="page"]{
  border-color: color-mix(in srgb, var(--link) 34%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.15), rgba(255,255,255,.05)),
    color-mix(in srgb, var(--link) 18%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.24),
    inset 0 -1px 2px rgba(0,0,0,.25),
    inset 6px 0 11px -8px rgba(255,255,255,.6),
    inset -6px 0 11px -8px rgba(255,255,255,.6),
    0 2px 10px rgba(0,0,0,.36);
}

/* --------------------------------------------------------------------------
   Project cards
   -------------------------------------------------------------------------- */

.project-grid{
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
  margin: 0 0 16px;
}

/* Home page: compact tiles (image + title), three to a row inside the 700px
   column. 5px gaps leave each tile ~230px, so a 13px title gets ~204px of line
   before it wraps. The phone rule under "Responsive" drops this to one column. */
.project-grid--home{
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 5px;
}

/* --------------------------------------------------------------------------
   Project rows

   The projects page lays each card out the way the old site did: artwork on
   the left, title and description on the right, with an arrow at the far edge
   of the title line. One per row rather than a two-column grid. The card
   itself keeps the material, top bar and hover it has elsewhere.
   -------------------------------------------------------------------------- */

.project-grid--list{
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
}

/* The class is doubled so these win over .project-card, which sets
   display:flex at the same specificity but later in the file. */
.project-card.project-card--row{
  display: grid;
  grid-template-columns: 160px minmax(0, 1fr);
  column-gap: 22px;
  align-items: center;

  padding: 18px 22px;
  text-align: left;
}

/* The tile version centres the artwork above its title and reserves a fixed
   height; in a row it simply fills its column. */
.project-card.project-card--row .project-thumb{
  max-width: 160px;
  height: auto;
  margin: 0;
  padding: 4px;
}


.project-body{
  min-width: 0;
}

/* No top bar on a row: it belongs to the tile, where it caps a column of
   centred content. Across a wide row it reads as a rule, not an accent. */
.project-card.project-card--row::before{
  display: none;
}

.project-card.project-card--row h3{
  margin: 0;
  /* .project-card h3 centres itself, which beats the row's inherited left. */
  text-align: left;
  color: var(--link);

  /* The display cut, as the old projects page uses for its project titles:
     it is the small-caps face, so the heading reads in caps. The global h3
     rule sets the body face, which is why these looked different. */
  font-family: var(--font-display);
  letter-spacing: .015em;
}

.project-card.project-card--row p{
  margin: 7px 0 0;
  color: var(--muted);
  font-style: italic;
}

/* The tile pins its button to the card's foot with margin-top:auto; in a row
   the button follows the description directly. */
.project-card.project-card--row .btn-ghost{
  margin-top: 12px;
}

/* Square tiles, as tall as they are wide (~230px). The stack inside must fit:
   2 x 14px padding + 150px picture + 8px + a two-line title (2 x 21px) + 2px
   border = 230px. Anything taller stretches the square. */
.project-grid--home .project-card{
  aspect-ratio: 1 / 1;
  padding: 14px 12px;
}

/* The illustrations have transparent grounds, so here they drop the white
   plate and sit straight on the card. Dark mode keeps its light plate (the
   more specific rule under "Artwork treatment"): these drawings need a light
   ground to stay legible there. */
.project-grid--home .art-illus{
  background: none;
}

/* Bigger pictures than on the Projects page: the square drawings render at
   136px (150px less the 7px padding) instead of 82px. */
.project-grid--home .project-thumb{
  height: 150px;
  margin: 0 auto 8px;
}

/* Titles in the small-caps display cut the old site used for project names,
   so each word opens on a full capital; grey as .section-intro. Centred. */
.project-grid--home h4{
  margin: 0;
  line-height: 1.4;
  color: var(--muted);
  font-family: var(--font-display);
  font-size: 15px;   /* the most a two-line title allows in the square */
  font-weight: 700;
  letter-spacing: .015em;
  text-align: center;
}

.project-card{
  position: relative;
  min-width: 0;
  display: flex;
  flex-direction: column;

  padding: 22px;
  /* material: see the shared .card, .prose, .project-card glass rule */

  transition:
    transform 180ms ease,
    box-shadow 180ms ease,
    border-color 180ms ease,
    background-color 180ms ease;
}

.project-card::before{
  content: "";
  position: absolute;
  top: 0;
  left: 22px;
  right: 22px;
  height: 3px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--link) 48%, transparent);
}

/* The compact home-page tiles go without the accent bar. */
.project-grid--home .project-card::before{
  content: none;
}

.project-card:hover{
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--link) 30%, transparent);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 82%, transparent),
      color-mix(in srgb, #fff 52%, transparent)),
    color-mix(in srgb, var(--link) 9%, transparent);
  box-shadow:
    inset 0 1px 0 #fff,
    inset 0 -1px 0 color-mix(in srgb, var(--link) 10%, transparent),
    0 16px 36px color-mix(in srgb, var(--link) 16%, transparent),
    0 2px 5px color-mix(in srgb, var(--link) 10%, transparent);
}

:root[data-theme="dark"] .project-card:hover{
  border-color: color-mix(in srgb, var(--link) 34%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.12), rgba(255,255,255,.045)),
    color-mix(in srgb, var(--link) 13%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.2),
    inset 0 -1px 0 rgba(0,0,0,.25),
    0 16px 38px rgba(0,0,0,.55),
    0 2px 5px rgba(0,0,0,.35);
}

.project-thumb{
  display: block;
  width: 100%;
  max-width: 172px;
  height: 96px;
  margin: 4px auto 14px;   /* centred in the card */
  padding: 7px;
  border: 0;
  border-radius: 11px;
  object-fit: contain;

  /* Artwork, not content to be pulled out of the page: dragging a project
     thumbnail produced a ghost image and a drop target. -webkit-user-drag
     covers Chrome, Edge and Safari; Firefox ignores it, so the markup also
     carries draggable="false". */
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
}

/* The .art-illus plate is a hard-edged rectangle a shade brighter than the
   card, and it is what you can see around the artwork. On a light page the
   illustrations carry themselves, so the plate goes. In dark mode it has to
   stay - four of the six are drawn in near-blacks (#2f2e41, #3f3d56) that
   vanish against the card - but only its outer band is feathered, by
   intersecting a horizontal and a vertical fade, so it dissolves into the
   card on all four sides instead of ending in a line.

   Scoped through .project-card so it outranks .art-illus, which is declared
   later in this file. The illustration at the head of a project page gets the
   same treatment, so it has no visible edge there either. */
.project-card .project-thumb,
.detail-head img.art-illus{
  background: transparent;
}

:root[data-theme="dark"] .project-card .project-thumb,
:root[data-theme="dark"] .detail-head img.art-illus{
  background: #eef1f8;
  -webkit-mask-image:
    linear-gradient(to right, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
  -webkit-mask-composite: source-in;
          mask-image:
    linear-gradient(to right, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
          mask-composite: intersect;
}

.project-card h3{
  margin: 0 0 10px;
  font-size: 19px;
  line-height: 1.3;
  text-align: center;
}

.project-card h3 a{
  color: var(--text);
}

.project-card h3 a:hover{
  color: var(--link);
  text-decoration: none;
}

.project-card p{
  margin: 0 0 14px;
  color: var(--muted);
  font-size: 15.5px;
}

.project-card .btn-ghost{
  margin-top: auto;
  align-self: flex-start;
}

/* Detail-page hero for a single project or news item */

.detail-head{
  margin: 0 0 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--line);
  text-align: center;
}

.detail-eyebrow{
  margin: 0 0 8px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 750;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.detail-head h1{
  margin: 0 auto 16px;
  max-width: 30ch;
  font-size: clamp(25px, 3vw, 34px);
  line-height: 1.2;
}

.detail-head img{
  display: block;
  width: auto;
  max-width: min(100%, 240px);
  max-height: 150px;
  margin: 0 auto;
  object-fit: contain;
}

.detail-head img.art-photo{
  max-width: min(100%, 300px);
  max-height: 220px;
  border: 1px solid var(--line);
  border-radius: 14px;
}

/* --------------------------------------------------------------------------
   Artwork treatment

   Three kinds of image live on this site and each needs different handling
   in dark mode:

   .art-mark   flat single-colour ONE Lab logos — lifted with a filter so the
               brand blue stays legible against the near-black background.
   .art-illus  full-colour illustrations that carry their own white ground —
               filtering blows out the whites, so they sit on a light plate.
   .art-photo  photographs — left completely alone.
   -------------------------------------------------------------------------- */

.art-mark{
  filter: var(--logo-filter);
}

.art-illus{
  background: rgba(255,255,255,.66);
}

:root[data-theme="dark"] .art-illus{
  background: #eef1f8;
}

:root[data-theme="dark"] .detail-head img.art-illus,
:root[data-theme="dark"] .news-thumb.art-illus{
  border-radius: 12px;
}

.detail-head img.art-illus{
  padding: 10px;
  border-radius: 12px;
}

/* --------------------------------------------------------------------------
   News cards
   -------------------------------------------------------------------------- */

/* News items are horizontal rows: square picture on the left, text on the
   right, one item per row. */
.news-grid{
  display: grid;
  grid-template-columns: 1fr;
  gap: 4px;
}

.news-card{
  min-width: 0;
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  gap: 18px;
  align-items: center;
  padding: 12px;

  border-radius: 16px;
  /* material: see the shared glass rule (.card, .prose, …) */

  transition:
    transform 180ms ease,
    box-shadow 180ms ease,
    border-color 180ms ease;
}

.news-card:hover{
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--link) 30%, transparent);
  box-shadow:
    inset 0 1px 0 #fff,
    inset 0 -1px 0 color-mix(in srgb, var(--link) 10%, transparent),
    0 14px 32px color-mix(in srgb, var(--link) 15%, transparent),
    0 2px 5px color-mix(in srgb, var(--link) 9%, transparent);
}

:root[data-theme="dark"] .news-card:hover{
  border-color: color-mix(in srgb, var(--link) 34%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.2),
    inset 0 -1px 0 rgba(0,0,0,.25),
    0 14px 34px rgba(0,0,0,.55),
    0 2px 5px rgba(0,0,0,.35);
}

/* The picture is not a link - news items have no pages of their own - so
   it has no hover state. */
.news-pic{
  display: block;
  line-height: 0;
  border-radius: 12px;
}

/* News artwork is authored square by convention — the picture stays a true
   square whatever the row's height, so nothing is cropped away. */
.news-thumb{
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  height: auto;
  border: 1px solid var(--line);
  border-radius: 12px;
  object-fit: cover;
  background: color-mix(in srgb, var(--link) 6%, var(--panel));
}

/* Logo and diagram thumbnails are artwork, not photography — letterbox them
   rather than cropping into the middle of the mark. */
.news-thumb--contain{
  object-fit: contain;
  padding: 14px;
}

.news-body{
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 2px 8px 2px 0;
}

/* The date is metadata, not an affordance. A tinted pill in link blue is the
   same shape and colour as .ref-link and .btn-ghost right below it, so it read
   as something to click. It is now plain muted text, lightly tracked, with no
   pill and no link colour. The short rule gives it presence at the card's
   right edge without a border. */
.news-date{
  display: inline-flex;
  align-self: flex-end;   /* date sits at the right edge of the text column */
  align-items: center;
  gap: 8px;

  margin-bottom: 10px;
  color: var(--muted);

  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .04em;
}

.news-date::before{
  content: "";
  width: 18px;
  height: 1px;
  background: color-mix(in srgb, var(--muted) 50%, transparent);
}

.news-body p{
  margin: 0;
  color: var(--muted);
  font-size: 15px;
  line-height: 1.55;
}


/* --------------------------------------------------------------------------
   People — speaker-style cards, as on the workshop site's Speakers page.

   One grid per section, no collapsible groups. Each card is a circular
   portrait, name, department, and a coloured "meta" pill naming the person's
   category (Director, PhD Student, …) where the workshop site put the talk
   type (Keynote, Rising Star…). Cards share the site's glass material.
   -------------------------------------------------------------------------- */

.people-section{
  margin-top: 18px;
}

/* Unlike .section, this has no bottom padding, so the last group on the page
   ran straight into the footer's divider. Only the final one needs the gap -
   between siblings the 18px top margin already does the work. */
.people-section:last-child{
  margin-bottom: 34px;
}

.people-section h2{
  margin: 0 0 12px;
  text-align: left;
}

.people-grid{
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}

.person-card{
  display: flex;
  min-height: 300px;
  flex-direction: column;
  align-items: center;

  padding: 16px 12px;
  border-radius: 16px;
  /* material: see the shared glass rule (.card, .prose, …) */

  text-align: center;

  transition:
    transform 160ms ease,
    box-shadow 160ms ease,
    border-color 160ms ease;
}

.person-card:hover,
.alum-row:hover,
.prose.intro:hover,
.pub-item:hover,
.faq-item:hover{
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--link) 30%, transparent);
  box-shadow:
    inset 0 1px 0 #fff,
    inset 0 -1px 0 color-mix(in srgb, var(--link) 10%, transparent),
    0 14px 32px color-mix(in srgb, var(--link) 15%, transparent),
    0 2px 5px color-mix(in srgb, var(--link) 9%, transparent);
}

:root[data-theme="dark"] .person-card:hover,
:root[data-theme="dark"] .alum-row:hover,
:root[data-theme="dark"] .prose.intro:hover,
:root[data-theme="dark"] .pub-item:hover,
:root[data-theme="dark"] .faq-item:hover{
  border-color: color-mix(in srgb, var(--link) 34%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.2),
    inset 0 -1px 0 rgba(0,0,0,.25),
    0 14px 34px rgba(0,0,0,.55),
    0 2px 5px rgba(0,0,0,.35);
}

.person-avatar{
  display: block;
  width: 120px;
  height: 120px;
  margin: 8px auto 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  object-fit: cover;
  object-position: center top;
  background: var(--panel);
}

/* Recruiting card: the same shape as a member card with the portrait left
   vacant, so an empty slot reads as an invitation rather than a gap. */
.person-avatar.is-empty{
  background: color-mix(in srgb, var(--link) 7%, var(--panel));
}

.join-card .person-name{
  color: var(--muted);
}

.join-card .person-actions{
  /* The button carries its own 12px top margin. */
  padding-top: 2px;
}

.person-name{
  margin: 0 0 6px;
  color: var(--text);
  font-size: 18px;
  font-weight: 700;
  line-height: 1.25;
}

.person-role{
  margin: 0;
  color: var(--muted);
  font-size: 13.5px;
  line-height: 1.5;
}

/* PI card — the site's original design: a large square portrait beside name,
   title and email, the bio beneath, and the icon links along the foot. */
.pi-card{
  display: flex;
  flex-direction: column;
  padding: 18px;
  border-radius: 18px;
  /* material: see the shared glass rule (.card, .prose, …) */
  transition:
    transform 160ms ease,
    box-shadow 160ms ease,
    border-color 160ms ease;
}

.pi-card:hover{
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--link) 30%, transparent);
  box-shadow:
    inset 0 1px 0 #fff,
    inset 0 -1px 0 color-mix(in srgb, var(--link) 10%, transparent),
    0 14px 32px color-mix(in srgb, var(--link) 15%, transparent),
    0 2px 5px color-mix(in srgb, var(--link) 9%, transparent);
}

:root[data-theme="dark"] .pi-card:hover{
  border-color: color-mix(in srgb, var(--link) 34%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.2),
    inset 0 -1px 0 rgba(0,0,0,.25),
    0 14px 34px rgba(0,0,0,.55),
    0 2px 5px rgba(0,0,0,.35);
}

.pi-profile{
  display: grid;
  grid-template-columns: 168px minmax(0, 1fr);
  gap: 22px;
  align-items: center;
}

.pi-photo{
  display: block;
  width: 168px;
  height: 168px;
  border: 1px solid var(--line);
  border-radius: 16px;
  object-fit: cover;
  object-position: center top;
  background: var(--panel);
}

.pi-identity{
  min-width: 0;
}

.pi-identity h3{
  margin: 0 0 5px;
  color: var(--text);
  font-size: 22px;
  line-height: 1.22;
}

.pi-affiliation{
  margin: 0;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.55;
}

.pi-bio{
  margin: 14px 0 0;
  color: var(--muted);
  font-size: 15px;
  line-height: 1.6;
}

/* The links sit in the identity column beside the portrait, under the title
   and department - not at the foot of the card - so they no longer need the
   margin-top:auto that pushed them to the bottom of the flex column. */
.pi-actions{
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
}

/* Small lines beneath the role: an honour, research interests, where an alum
   went next. */
.person-honor,
.person-next{
  margin: 9px 0 0;
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.45;
}

.person-honor{
  display: inline-flex;
  align-items: center;
  gap: 6px;

  color: var(--link);
  font-weight: 700;
}

/* An award rosette leading the honour, masked over currentColor so it takes
   the link colour with the text - and follows it when dark mode lifts it. */
.person-honor::before{
  content: "";
  width: 13px;
  height: 13px;
  flex: 0 0 13px;

  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8.5' r='5.5'/%3E%3Cpath d='M8.6 12.9 7 21l5-2.8L17 21l-1.6-8.1'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8.5' r='5.5'/%3E%3Cpath d='M8.6 12.9 7 21l5-2.8L17 21l-1.6-8.1'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* --------------------------------------------------------------------------
   Alumni row

   A full-width alternative to the grid card, for alumni whose story is one
   line: who they were here, then where they went. The destination is pushed
   to the far edge so a column of rows reads as from -> to.
   -------------------------------------------------------------------------- */

/* Stacked rows need air between them; the first sits flush under the heading. */
.alum-row + .alum-row{
  margin-top: 10px;
}

/* Fixed tracks rather than flex, so the five fields line up as columns down
   the whole list - each row is its own grid, and they only agree because the
   track sizes are the same.

   Degree and department share one cell, so there are four tracks, not five.
   Name and arrow are fixed at their measured maximums; the combined cell and
   the destination share what is left. */
.alum-row{
  display: grid;
  grid-template-columns:
    100px minmax(0, 1.2fr) minmax(0, 1.15fr);
  align-items: baseline;
  gap: 10px;
  padding: 14px 18px;

  transition:
    transform 160ms ease,
    box-shadow 160ms ease,
    border-color 160ms ease;
}

/* The whole row sits in grey; the name keeps its weight so the hierarchy
   survives without a second colour. */
/* Each field is pinned to its own track. Without this, grid auto-placement
   walks the children left to right, so a row missing one field (an alum with
   no arrow, say) shifts every later field into the wrong column. */
.alum-name{ grid-column: 1; }
.alum-meta{ grid-column: 2; }
.alum-next{ grid-column: 3; }

.alum-name{
  color: var(--muted);
  font-size: 16px;
  font-weight: 750;
}

.alum-meta{
  color: var(--muted);
  font-size: 13.5px;
}

/* Pushes itself and the destination to the right edge of the row. On a narrow
   screen the row wraps and the arrow simply leads the last line. */
.alum-next{
  color: var(--muted);
  font-size: 14px;
}

/* The arrow leads the destination instead of occupying a column of its own. */
.alum-next::before{
  content: "\2192";
  margin-right: 9px;
}

/* 700px is where the rest of the site drops to one column, and it is also
   where the three tracks stop fitting - below it the combined degree/department
   cell wraps and the row reads worse than a stack. */
@media (max-width: 700px){
  .alum-row{
    grid-template-columns: minmax(0, 1fr);
    gap: 3px;
  }

  /* The fields are pinned to tracks 1-3 above. Those pins survive a narrower
     template and would conjure the columns back as implicit tracks, crushing
     the name, so every field is put back into the single column. */
  .alum-row > *{
    grid-column: 1;
  }
}

/* An alumni line that continues from the role above it gets a downward arrow
   on its own line, so "B.S. '25" and where they went read as one sequence
   rather than two separate facts. */
/* The arrow belongs to the role line above it, so it sits closer than the
   9px the standalone next-step lines use. */
.person-next.is-step{
  margin-top: 2px;
}

.person-next.is-step::before{
  content: "\2193";
  display: block;
  margin-bottom: 3px;
  font-size: 15px;
  line-height: 1;
  opacity: .7;
}

/* The research-interest badge, carried over from the Speakers grid on the
   insect-autonomy site: a pill in link colour with a leading dot, sitting
   under the department. --badge-accent is a hook for tinting a variant later,
   the way that page colours keynote and industry talks differently. */
.person-interest{
  --badge-accent: var(--link);

  display: inline-flex;
  align-items: center;
  gap: 6px;

  /* Sinks to the foot of the card: this absorbs the column's free space so the
     badge sits directly above the icon row, whatever the card above it holds.
     .person-actions gives up its own auto margin below, or the two would split
     the space between them and leave a gap in the middle. */
  margin-top: auto;
  padding: 5px 11px;
  border: 1px solid color-mix(in srgb, var(--badge-accent) 42%, var(--line));
  border-radius: 999px;

  /* Mixed into transparent rather than --panel, so the card's own material
     shows through instead of a tinted plate sitting on top of it. */
  background: color-mix(in srgb, var(--badge-accent) 6%, transparent);
  color: var(--badge-accent);

  /* Small and italic: the longest interests only clear the card's ~197px of
     inner width at this size, and italic sets the label apart from the
     upright text above it. */
  font-size: 13px;
  font-style: italic;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.2;
}

/* A magnifier rather than a dot: the badge marks what the person is looking
   into. Drawn as a mask over currentColor so it takes --badge-accent with the
   rest of the badge instead of carrying a hard-coded fill. */
.person-interest::before{
  content: "";
  width: 11px;
  height: 11px;
  flex: 0 0 11px;

  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M15.4 15.4 21 21'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M15.4 15.4 21 21'/%3E%3C/svg%3E") center / contain no-repeat;
}

.person-actions{
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: auto;
  padding-top: 14px;
}

.person-interest + .person-actions{
  margin-top: 0;
  padding-top: 10px;
}

/* The badge sinks on `margin-top: auto`, which collapses to nothing once a
   card is full - an honour line or two and it ends up flush against the text
   above. The gap therefore lives on whatever sits directly before it: a fixed
   margin that is honoured when the card is tight, and simply eats into the
   auto space when it is not, so roomier cards look unchanged. */
.person-role:has(+ .person-interest),
.person-honor:has(+ .person-interest),
.person-next:has(+ .person-interest){
  margin-bottom: 12px;
}

.social-links{
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

/* Round icon buttons, shared by person cards and the footer */

.icon-link{
  display: inline-flex;
  align-items: center;
  justify-content: center;

  width: 33px;
  height: 33px;

  border: 1px solid color-mix(in srgb, var(--link) 16%, transparent);
  border-radius: 999px;

  /* Glass bead: resting weight matches the badges, hover steps up to the
     nav's active weight. */
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 52%, transparent),
      color-mix(in srgb, #fff 14%, transparent)),
    color-mix(in srgb, var(--link) 7%, transparent);
  backdrop-filter: blur(10px) saturate(150%);
  -webkit-backdrop-filter: blur(10px) saturate(150%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.72),
    0 1px 4px color-mix(in srgb, var(--link) 10%, transparent);
  color: var(--muted);

  transition:
    color 150ms ease,
    border-color 150ms ease,
    background-color 150ms ease,
    box-shadow 150ms ease,
    transform 150ms ease;
}

.icon-link:hover{
  color: var(--link);
  border-color: color-mix(in srgb, var(--link) 30%, transparent);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 66%, transparent),
      color-mix(in srgb, #fff 24%, transparent)),
    color-mix(in srgb, var(--link) 13%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.9),
    0 3px 9px color-mix(in srgb, var(--link) 20%, transparent);
  text-decoration: none;
  transform: translateY(-1px);
}

:root[data-theme="dark"] .icon-link{
  border-color: color-mix(in srgb, var(--link) 22%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.09), rgba(255,255,255,.03)),
    color-mix(in srgb, var(--link) 10%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.13),
    0 1px 4px rgba(0,0,0,.3);
}

:root[data-theme="dark"] .icon-link:hover{
  border-color: color-mix(in srgb, var(--link) 34%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.15), rgba(255,255,255,.05)),
    color-mix(in srgb, var(--link) 18%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.24),
    0 3px 10px rgba(0,0,0,.4);
}

.icon-link svg{
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.icon-link.is-solid svg{
  fill: currentColor;
  stroke: none;
}

/* --------------------------------------------------------------------------
   Publications
   -------------------------------------------------------------------------- */

.pub-list{
  display: grid;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: pub;
}

/* Material, edge rim and side glow come from the shared glass rule above.
   The 3px link-coloured left border this used to carry is gone: it sat exactly
   where the rim puts its brightest highlight, so the two fought each other. */
.pub-item{
  padding: 14px 18px;
  /* material: see the shared glass rule (.card, .prose, …) */

  transition:
    transform 160ms ease,
    box-shadow 160ms ease,
    border-color 160ms ease;
}



/* Same size as .pub-authors below it; the weight and the link colour are what
   separate the title from the rest of the entry, not the scale.

   Scoped through .pub-item so it outranks `.prose p { color: var(--muted) }`.
   On the publications page the list is not inside .prose, but on the project
   and news detail pages it is, and a bare .pub-title lost to it there. */
.pub-item .pub-title{
  margin: 0 0 5px;
  color: var(--link);
  font-size: 14.5px;
  font-weight: 680;
  line-height: 1.45;
}

.pub-authors{
  margin: 0 0 3px;
  color: var(--muted);
  font-size: 14.5px;
  line-height: 1.45;
}

.pub-venue{
  margin: 0;
  color: var(--muted);
  font-size: 14px;
  font-style: italic;
  line-height: 1.45;
}

.pub-venue b{
  color: var(--link);
  font-style: normal;
  font-weight: 700;
}

/* --------------------------------------------------------------------------
   FAQ
   -------------------------------------------------------------------------- */

.faq-list{
  display: grid;
  gap: 10px;
}

/* Material, edge rim and side glow come from the shared glass rule above,
   so an FAQ entry reads as the same sheet of glass as a publication entry. */
/* Anything a fragment link can target needs to clear the sticky header, or
   the jump tucks it underneath. */
.faq-item,
.section > h2[id]{
  scroll-margin-top: 104px;
}

.faq-item{
  /* material: see the shared glass rule (.card, .prose, …) */
  overflow: hidden;

  transition:
    transform 160ms ease,
    box-shadow 160ms ease,
    border-color 160ms ease;
}

/* An open entry keeps the glass but takes a firmer contour, the way the
   active seg-nav tab does, so the expanded answer is easy to find again. */
.faq-item[open]{
  border-color: color-mix(in srgb, var(--link) 32%, transparent);
}

:root[data-theme="dark"] .faq-item[open]{
  border-color: color-mix(in srgb, var(--link) 40%, transparent);
}

.faq-item > summary{
  display: flex;
  align-items: flex-start;
  gap: 11px;

  padding: 14px 17px;

  /* Questions sit in the muted gray and darken on hover. */
  color: var(--muted);
  font-size: 16.5px;
  font-weight: 660;
  line-height: 1.45;

  cursor: pointer;
  list-style: none;

  transition: color 150ms ease;
}

.faq-item > summary::-webkit-details-marker{
  display: none;
}

.faq-item > summary:hover{
  color: var(--text);
}

.faq-item > summary .chev{
  width: 15px;
  height: 15px;
  margin-top: 4px;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 220ms ease;
}

.faq-item[open] > summary .chev{
  transform: rotate(90deg);
}

.faq-answer{
  padding: 0 17px 16px 43px;
  color: var(--muted);
  font-size: 15.5px;
  line-height: 1.62;
}

.faq-answer > :first-child{
  margin-top: 0;
}

.faq-answer > :last-child{
  margin-bottom: 0;
}

.faq-answer p{
  margin: 0 0 9px;
}

.faq-answer dl{
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 5px 14px;
  margin: 0;
}

.faq-answer dt{
  color: var(--link);
  font-size: 11.5px;
  font-weight: 750;
  letter-spacing: .05em;
  padding-top: 3px;
  text-transform: uppercase;
}

.faq-answer dd{
  margin: 0;
}

/* Glass like the FAQ entries around it, with a firmer contour so it still
   stands out as the call to action between them. */
.callout{
  margin: 0 0 18px;
  padding: 16px 18px;
  /* material: see the shared glass rule (.card, .prose, …) */
  border-color: color-mix(in srgb, var(--link) 34%, transparent);
}

:root[data-theme="dark"] .callout{
  border-color: color-mix(in srgb, var(--link) 42%, transparent);
}

.callout h3{
  margin: 0 0 6px;
  font-size: 16px;
}

.callout p,
.callout li{
  color: var(--muted);
  font-size: 14.5px;
}

.callout p{
  margin: 0 0 8px;
}

/* A list reads as part of the paragraph run around it: same spacing below
   as a paragraph, and a hanging indent just deep enough for the bullet. */
.callout ul,
.callout ol{
  margin: 0 0 8px;
  padding-left: 20px;
}

.callout li + li{
  margin-top: 2px;
}

.callout > :last-child{
  margin-bottom: 0;
}

/* --------------------------------------------------------------------------
   Current openings

   Plain content on the page - no panel, border or shadow - so it lines up with
   the section headings below it. Only the status pill and its pulsing dot set
   it apart; the pulse stops under prefers-reduced-motion.
   -------------------------------------------------------------------------- */

/* The status label: a small pill, the same weight as the badges. */
.opening .opening-status{
  display: flex;
  align-items: center;
  gap: 8px;

  /* Shrink to its content, at the left edge of the column. */
  width: fit-content;
  margin: 0 0 8px;
  padding: 4px 11px 4px 9px;

  border: 1px solid color-mix(in srgb, var(--link) 28%, transparent);
  border-radius: 999px;
  background: color-mix(in srgb, #fff 62%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    0 2px 8px color-mix(in srgb, var(--link) 12%, transparent);

  color: var(--link);
  font-size: 12px;
  font-weight: 750;
  letter-spacing: .08em;
  line-height: 1.3;
  text-transform: uppercase;
}

.opening-dot{
  /* One value drives the dot, its halo and the pulse. */
  --dot: var(--ok-green);

  /* inline-block, not the span's default inline: an inline box ignores width
     and height, so without this the dot collapses to nothing anywhere except
     inside the summary, whose flex layout happens to blockify its children. */
  display: inline-block;
  /* vertical-align centres it on the text's midline; the nudge corrects the
     ~2px the glyph metrics leave it sitting low. Both are ignored on a flex
     item, so the summary below is unaffected by them. */
  vertical-align: middle;
  margin-right: 8px;

  position: relative;
  top: -2px;
  width: 8px;
  height: 8px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--dot);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--dot) 22%, transparent);
}

/* In the summary the dot is a flex item on a row aligned to flex-start, so it
   would ride at the top of the line like a superscript. Half the leading puts
   it back on the text's midline, and unlike align-self:center it stays on the
   first line if the question ever wraps. */
.faq-item > summary .opening-dot{
  /* The summary supplies its own 11px flex gap and does its own alignment. */
  margin-right: 0;
  top: 0;

  align-self: flex-start;
  margin-top: calc((1.45em - 8px) / 2);
}

.opening-dot::after{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--dot);
  animation: opening-pulse 2.2s ease-out infinite;
}

@keyframes opening-pulse{
  from{
    opacity: .55;
    transform: scale(1);
  }

  to{
    opacity: 0;
    transform: scale(2.8);
  }
}

/* One line per open role, with a plain bullet. Text is set like an FAQ
   answer (.faq-answer), grey included; the lines stay tight so the roles read
   as one short block under the status pill. */
.opening ul{
  display: grid;
  gap: 1px;
  margin: 0;
  padding-left: 20px;
  list-style: disc;
}

.opening li{
  color: var(--muted);
  font-size: 15.5px;
  line-height: 1.45;
}

/* .btn already spaces its children with gap. */
.btn .ext-icon{
  margin-left: 0;
}

:root[data-theme="dark"] .opening .opening-status{
  border-color: color-mix(in srgb, var(--link) 36%, transparent);
  background: rgba(255,255,255,.07);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.16),
    0 2px 8px rgba(0,0,0,.3);
}

/* --------------------------------------------------------------------------
   Gallery + lightbox
   -------------------------------------------------------------------------- */

.gallery-grid{
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(215px, 1fr));
  gap: 12px;
}

.gallery-grid img{
  display: block;
  width: 100%;
  height: 168px;
  border: 1px solid var(--line);
  border-radius: 13px;
  object-fit: cover;
  cursor: zoom-in;

  transition: transform 220ms ease, box-shadow 220ms ease, border-color 220ms ease;
}

.gallery-grid img:hover{
  transform: scale(1.02);
  border-color: color-mix(in srgb, var(--link) 40%, var(--line));
  box-shadow: 0 12px 28px rgba(0,0,0,.18);
}

.lightbox{
  position: fixed;
  inset: 0;
  z-index: 100;

  display: none;
  align-items: center;
  justify-content: center;

  padding: 24px;
  background: rgba(6,8,14,.86);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);

  cursor: zoom-out;
}

.lightbox[data-open="true"]{
  display: flex;
}

.lightbox img{
  max-width: min(100%, 1100px);
  max-height: 88vh;
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0,0,0,.55);
}

.lightbox-close{
  position: absolute;
  top: 18px;
  right: 18px;

  width: 40px;
  height: 40px;

  display: inline-flex;
  align-items: center;
  justify-content: center;

  border: 1px solid rgba(255,255,255,.28);
  border-radius: 999px;
  background: rgba(255,255,255,.1);
  color: #fff;

  font-size: 20px;
  line-height: 1;

  cursor: pointer;
}

.lightbox-close:hover{
  background: rgba(255,255,255,.2);
}

/* --------------------------------------------------------------------------
   Tables
   -------------------------------------------------------------------------- */

table{
  width: 100%;
  max-width: 100%;
  border-collapse: collapse;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel2);
}

th,
td{
  padding: 10px;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}

th{
  background: var(--panel);
  color: var(--muted);
  font-weight: 650;
}

tr:last-child td{
  border-bottom: 0;
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.footer{
  margin-top: auto;
  padding: 0 0 30px;
  color: var(--muted);
  font-size: 14px;
}

.footer::before{
  margin-bottom: 24px;   /* the top padding the border used to sit above */
}

/* Address and copyright on the left, icons on the right. The copyright comes
   straight after the address in the markup, so when the footer stacks on a
   phone it stays with the address and the icons go last. */
.footer-inner{
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "contact social"
    "copy    copy";
  align-items: center;
  column-gap: 16px;
}

.footer-contact{ grid-area: contact; }
.footer-copy{ grid-area: copy; }
.footer-inner > .footer-social{ grid-area: social; }

.footer-logo img{
  display: block;
  width: 108px;
  height: auto;
  filter: var(--logo-filter);
}

.footer-meta{
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 13.5px;
  line-height: 1.6;
}

.footer-social{
  display: flex;
  align-items: center;
  gap: 8px;
}

/* --------------------------------------------------------------------------
   Motion + focus
   -------------------------------------------------------------------------- */

a:focus-visible,
summary:focus-visible,
.icon-link:focus-visible,
.gallery-grid img:focus-visible{
  outline: 2px solid var(--link);
  outline-offset: 3px;
  border-radius: 6px;
}

.prose > h1,
.prose > h2,
.prose > h3,
.prose > p,
.prose > ul,
.prose > hr{
  animation: fade-up 420ms ease both;
}

@keyframes fade-up{
  from{
    opacity: 0;
    transform: translateY(8px);
  }

  to{
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce){
  html{
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after{
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }

  .card:hover,
  .news-card:hover,
  .person-card:hover,
  .alum-row:hover,
  .prose.intro:hover,
  .project-card:hover,
  .pub-item:hover,
  .faq-item:hover,
  .gallery-grid img:hover,
  .btn:hover,
  .btn-ghost:hover,
  .ref-link:hover,
  .pill-link:hover{
    transform: none;
  }
}

/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 700px){
  .hero-grid{
    grid-template-columns: 1fr;
  }
}

@media (max-width: 700px){
  .project-grid{
    grid-template-columns: 1fr;
  }

  /* One tile across a phone is far too wide to be square. */
  .project-grid--home .project-card{
    aspect-ratio: auto;
  }

  .people-grid{
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }


}

/* --------------------------------------------------------------------------
   Narrow header

   Below ~740px the brand, five pills and the toggle no longer fit on one line
   (they need about 717px). Rather than moving the nav somewhere else — a fixed
   bottom bar reads as "the nav vanished" in a squeezed desktop window — the
   header simply becomes two rows: brand and toggle, then the pills centred
   beneath. The nav stays in the header at every width.
   -------------------------------------------------------------------------- */

@media (max-width: 740px){
  .navbar{
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "brand theme"
      "nav   nav";
    gap: 10px 16px;
    padding: 13px 18px 11px;
  }

  .brand{
    grid-area: brand;
    min-width: 0;
  }

  .themeBtn{
    grid-area: theme;
    align-self: center;
  }

  .nav{
    grid-area: nav;
    justify-content: center;
    gap: 4px;
  }
}

@media (max-width: 700px){
  .header{
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--bg);
  }

  .brandLogo{
    width: 118px;
  }

  .brand small{
    font-size: 11.5px;
    line-height: 1.4;
  }

  .nav a{
    padding: 6px 9px;
    font-size: 14px;
  }

  /* Short labels ("Pubs") so five pills clear a phone-width row. */
  .navLabelDesktop{
    display: none;
  }

  .navLabelMobile{
    display: inline;
  }

  .nav a::after{
    content: attr(data-short);
  }

  .hero{
    padding-top: 36px;
  }

  .welcome{
    margin-top: 22px;
    font-size: 18px;
  }

  .welcome + .hero{
    padding-top: 20px;
  }

  .hero-grid > div:first-child{
    text-align: center;
  }

  .intro{
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
  }

  .prose.intro{
    padding: 18px;
  }

  .intro-pi{
    justify-self: center;
  }

  .intro-sign{
    text-align: center;
  }

  .badges{
    justify-content: center;
  }

  .news-card{
    grid-template-columns: 110px minmax(0, 1fr);
    gap: 14px;
    align-items: start;
  }

  .news-thumb--contain{
    padding: 10px;
  }

  .prose{
    padding: 18px;
  }

  .seg-nav a{
    font-size: 13px;
  }




  .faq-answer{
    padding-left: 17px;
  }

}

@media (max-width: 520px){

  /* Project rows stack on a phone - artwork, title, description, button,
     all centred - instead of squeezing the text into a column beside the
     artwork too narrow to read. */
  .project-card.project-card--row{
    grid-template-columns: minmax(0, 1fr);
    row-gap: 12px;
    text-align: center;
  }

  .project-card.project-card--row .project-thumb{
    margin: 0 auto;
  }

  .project-card.project-card--row h3{
    text-align: center;
  }

  /* News items stack the same way: picture, date, text, pills - centred. */
  .news-card{
    grid-template-columns: minmax(0, 1fr);
    row-gap: 12px;
    text-align: center;
  }

  .news-pic{
    width: 160px;
    margin: 0 auto;
  }

  .news-body{
    padding: 0;
  }

  .news-body .ref-links{
    justify-content: center;
  }

  /* Centred, the date gets a matching rule on its other side. */
  .news-date{
    align-self: center;
  }

  .news-date::after{
    content: "";
    width: 18px;
    height: 1px;
    background: color-mix(in srgb, var(--muted) 50%, transparent);
  }

  .footer-inner{
    grid-template-columns: 1fr;
    grid-template-areas:
      "contact"
      "copy"
      "social";
  }

  .footer-inner > .footer-social{
    margin-top: 16px;
  }


  .people-grid{
    grid-template-columns: 1fr;
  }

  .person-card{
    min-height: 0;
  }

  .pi-profile{
    grid-template-columns: 1fr;
    justify-items: center;
    text-align: center;
  }

  .pi-actions{
    justify-content: center;
  }

  .gallery-grid{
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .gallery-grid img{
    height: 132px;
  }
}


/* ==========================================================================
   wenbinwan.com

   Everything above is the ONE Lab stylesheet, shared as it is. The rules
   below add what the personal site needs on top of it.
   ========================================================================== */

/* The name is the wordmark, set in the small-caps display face. */
/* The ww mark, then the name, on one line. */
.brand{
  flex-direction: row;
  align-items: center;
  gap: 10px;
}

.brandMark{
  display: block;
  width: 30px;
  height: 30px;
}

.brandName{
  color: var(--link);
  font-family: var(--font-display);
  font-size: 26px;
  line-height: 1;
  letter-spacing: .02em;
}

/* The ww mark, then the name. */
.footer-name{
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--link);
  font-family: var(--font-display);
  font-size: 20px;
  text-decoration: none;
}

.footer-mark{
  display: block;
  width: 28px;
  height: 28px;
}

/* The footer's contents sit 8px higher than on the lab site: 8px off the gap
   under the rule, 8px onto the bottom padding, so its height is unchanged. */
.footer{ padding-bottom: 38px; }
.footer::before{ margin-bottom: 16px; }

/* Copyright on the left, the mark and name on the right, on one line. On a
   phone the lab rule above stacks them instead. */
@media (min-width: 521px){
  .footer-inner{ grid-template-areas: "copy contact"; }
  .footer-copy{ margin: 0; }
}

/* No banner here. The page itself starts below the name card and the menu,
   closer than the 52px the lab site leaves under its banner. */
.site-nav + .hero,
.site-nav + .section{
  padding-top: 22px;
}

/* --- Name card: at the top of every page ------------------------------- */

/* Proportions from the old site's profile block: a 180px photo, 16px to the
   text, and seven lines of body text (name, email, three lines of position,
   interests, links) about 25px apart - as tall as the photo. */
.namecard{
  display: grid;
  grid-template-columns: 180px minmax(0, 1fr);
  gap: 18px;
  align-items: center;
  margin-top: 16px;
  padding: 18px 20px;
}

.namecard-photo{
  display: block;
  width: 180px;
  height: 180px;
  border: 1px solid var(--line);
  border-radius: 14px;
  object-fit: cover;
  object-position: center top;
  background: var(--panel);
}

.namecard-body{
  min-width: 0;
}

/* Doubled class: on most pages the name is a <p>, and .card p would set it
   in the muted colour. */
.namecard .namecard-name{
  margin: 0;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16.5px;
  font-weight: 700;
  line-height: 1.55;
  letter-spacing: 0;
}

.namecard-lines{
  margin: 0;
  color: var(--muted);
  font-size: 15.5px;
  line-height: 1.6;
}

.namecard-interests{
  margin: 0;
  color: var(--muted);
  font-size: 15.5px;
  line-height: 1.6;
}

/* .card p would add its paragraph margin under each block; the old site's
   lines sit an even 25px apart. */
.namecard .namecard-lines,
.namecard .namecard-interests{
  margin: 0;
}

/* The monospace face is taller than Libertine; at its own line height it
   pushed the interests and email lines apart. */
.namecard code{
  line-height: 1;
}

/* The profile links as the old site drew them: solid glyphs in the link
   colour, separated by thin bars - not the round buttons used elsewhere. */
.namecard-links{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
}

.fa-link{
  display: inline-flex;
  color: var(--link);
  transition: color 150ms ease, transform 150ms ease;
}

.fa-link:hover{
  color: var(--link-hover);
  transform: translateY(-1px);
}

.fa-link svg{
  display: block;
  width: auto;
  height: 18px;
  fill: currentColor;
}

.fa-sep{
  color: var(--muted);
  opacity: .6;
  font-size: 14px;
}

/* The menu, under the name card. */
.site-nav{
  justify-content: center;
  gap: 4px;
  margin-top: 16px;
}

/* --- Home ---------------------------------------------------------------- */

/* The bio is plain text on the page - no glass panel. */
.home-bio p{
  margin: 0 0 12px;
}

.home-bio p:last-child{
  margin-bottom: 0;
}

/* The home page's lists - publications, people, courses - stand a little
   further from what is above them than sections elsewhere (40px, not 28px),
   so each reads as its own part of the page. The same gap whichever kind of
   list it is: .section has a top padding, .people-section a top margin. */
.section.home-list{
  padding-top: 30px;
}

.people-section.home-list{
  margin-top: 30px;
}

/* An icon written into Markdown text (:shiba orange:, :tennis:): a solid
   glyph a little larger than the text, sitting on the line. Its colour -
   black unless the code gives one - is the same in both themes. */
.text-icon{
  display: inline-block;
  height: 1.5em;
  margin: 0 .15em;
  vertical-align: -.35em;
  line-height: 0;
}

.text-icon svg{
  height: 100%;
  width: auto;
  fill: currentColor;
}

.text-icon.is-orange{
  color: #d9822b;
}

.text-icon.is-black{
  color: #262626;
}

/* Brass, and forest green: CSS's own gold is too bright on the white page. */
.text-icon.is-gold{
  color: #c29a22;
}

.text-icon.is-green{
  color: #228b22;
}

/* In dark mode a black icon stays black, with a thin light edge so it
   still shows on the dark page. */
:root[data-theme="dark"] .text-icon.is-black{
  filter: drop-shadow(0 0 .6px rgba(255, 255, 255, .9)) drop-shadow(0 0 .6px rgba(255, 255, 255, .6));
}

/* After a home-page list, the link to the whole page ("All publications ->"):
   plain link text at the right, where the button used to sit beside the
   heading. */
.more-link{
  margin: 10px 0 0;
  text-align: right;
  font-size: 14px;
}

/* The lab's logo, centred, with "Research group at UNM: one.unm.edu" under
   it. The link shrinks to the width of the line of text; the logo then fills
   that width - width 0 with min-width 100% keeps the picture from widening
   the link itself - so the two are always the same width. */
.section.group{
  text-align: center;
}

.group-link{
  display: inline-block;
  color: var(--muted);
  text-decoration: none;
}

.group-text strong{
  color: var(--link);
}

.group-link:hover .group-text strong{
  text-decoration: underline;
}

/* 75% of the line's width, centred over it. */
.group-logo{
  display: block;
  width: 0;
  min-width: 75%;
  height: auto;
  margin: 0 auto 10px;
}

/* --- Research ------------------------------------------------------------ */

.group-logo img{
  display: block;
  width: 140px;
  height: auto;
  margin: 4px 0 16px;
}

.project-card.project-card--row .project-sponsor{
  margin: 5px 0 0;
  color: var(--muted);
  font-size: 12px;
  font-style: normal;
  font-weight: 750;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.detail-next{
  margin: 28px 0 0;
  text-align: right;
}

/* --- Publications: Figure and BibTeX open in place ------------------------ */

.ref-more > summary{
  list-style: none;
  cursor: pointer;
}

.ref-more > summary::-webkit-details-marker{
  display: none;
}

/* A pill that opens in place, so a chevron rather than the outward arrow. */
.ref-more > summary.ref-link::after{
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  transition: transform 200ms ease, opacity 150ms ease;
}

.ref-more[open] > summary.ref-link::after{
  transform: rotate(180deg);
}

/* Open, it takes a row of its own: the pill, then what it shows. */
.ref-more[open]{
  flex-basis: 100%;
}

.ref-more[open] > summary{
  display: inline-flex;
}

.ref-more-body{
  margin-top: 8px;
}

.ref-more-body img{
  display: block;
  width: 100%;
  max-width: 380px;
  height: auto;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: #fff;
}

.ref-more-body pre,
.prose pre{
  margin: 0;
  padding: 12px 14px;
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  font-size: 12.5px;
  line-height: 1.55;
}

.ref-more-body pre code,
.prose pre code{
  padding: 0;
  background: none;
  font-size: inherit;
}

.prose pre{
  margin: 0 0 1.2rem;
}

/* --- Teaching ------------------------------------------------------------ */

.course-level{
  margin: 16px 0 8px;
  color: var(--muted);
  font-size: 15px;
  font-weight: 750;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.course-item .pub-title a{
  color: var(--link);
  text-decoration: none;
}

.course-item .pub-title a:hover{
  text-decoration: underline;
}

.course-mark{
  margin-left: 2px;
  color: var(--muted);
}

.course-role{
  display: inline-block;
  margin-right: 6px;
  padding: 0 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
  font-size: 12px;
  font-style: normal;
  font-weight: 700;
}

.course-note{
  margin: 12px 0 0;
  color: var(--muted);
  font-size: 13.5px;
  text-align: right;
}

/* --- Markdown inside a text panel ---------------------------------------- */

.prose figure{
  margin: 0 0 1.4rem;
  text-align: center;
}

.prose figure img,
.prose center img{
  margin-left: auto;
  margin-right: auto;
}

.prose figure img{
  margin-bottom: 6px;
}

.prose figcaption{
  color: var(--muted);
  font-size: 13.5px;
}

.prose img[align="left"]{
  float: left;
  margin: 4px 18px 10px 0;
}

.prose table{
  display: block;
  width: 100%;
  max-width: max-content;
  margin: 0 auto 1.4rem;
  overflow-x: auto;
  border-collapse: collapse;
  font-size: 14.5px;
}

.prose th,
.prose td{
  padding: 7px 12px;
  border-bottom: 1px solid var(--line);
  color: var(--muted);
}

.prose th{
  color: var(--text);
}

.prose blockquote{
  margin: 0 0 1.2rem;
  padding: 2px 0 2px 16px;
  border-left: 3px solid color-mix(in srgb, var(--link) 45%, transparent);
}

.prose ul,
.prose ol{
  padding-left: 1.3rem;
}

/* The course pages open with the MkDocs-era stack of h1s. */
.syllabus h1{
  margin: 20px 0 6px;
  font-size: clamp(24px, 3.6vw, 30px);
  line-height: 1.15;
}

.syllabus h1 + h1{
  margin-top: 0;
}

/* The People page's mentoring line is one line at full width: at the panels'
   16.5px it is a word too long for the column. It is set in the regular
   weight, not the panels' bold. */
.faq-item.mentoring > summary{
  font-size: 15px;
  font-weight: 400;
}

/* Panels written in the Markdown (???) inside a text panel. */
.prose .faq-item{
  margin: 0 0 10px;
}

/* The header is one row - the name and the theme switch - at every width:
   the menu is below the name card, not in the header. This overrides the lab
   site's two-row narrow layout, which made room for the menu. */
.navbar{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  /* 10px more above than below, so the name and switch sit lower in the
     bar; the name card's margin gives the 10px back, so it stays put. */
  padding: 22px 18px 12px;
}

/* Bold text is set in the text colour; a bold link keeps the link colour. */
.prose a strong,
.faq-answer a strong{
  color: inherit;
}

/* An open BibTeX block scrolls inside its entry; without these, its longest
   line set the width of the whole publication list. */
.pub-item,
.ref-links,
.ref-more,
.ref-more-body{
  min-width: 0;
  max-width: 100%;
}

/* Figures and quotes inside a collapsible panel get the same treatment as
   in a text panel. */
.faq-answer figure{
  margin: 4px 0 12px;
  text-align: center;
}

.faq-answer figure img{
  display: block;
  max-width: 100%;
  height: auto;
  margin: 0 auto 6px;
  border-radius: 10px;
}

.faq-answer figcaption{
  font-size: 13.5px;
}

.faq-answer blockquote{
  margin: 0 0 12px;
  padding: 2px 0 2px 16px;
  border-left: 3px solid color-mix(in srgb, var(--link) 45%, transparent);
}

/* On a phone the six menu items fit on one row with a size down and less
   padding, instead of leaving "Openings" alone on a second line. */
@media (max-width: 520px){
  .nav{
    gap: 0;
  }

  .nav a{
    padding: 6px 4px;
    font-size: 13px;
  }
}

/* On a phone the name card stacks: photo, then the text, centred. */
@media (max-width: 520px){
  .namecard{
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    gap: 14px;
    text-align: center;
  }

  .namecard-links{
    justify-content: center;
  }
}

/* The rule that sat under the header moves below the menu: header, name
   card, menu - then the line, then the page. Same weight and colour as the
   footer's rule (.footer::before). */
.header::after{
  display: none;
}

.site-nav{
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}

/* --------------------------------------------------------------------------
   Name card - Liquid Glass, light mode

   On a white page the shared glass (white rim, white-tinted fill) has nothing
   to read against, so the card looked flat. Apple's light Liquid Glass gets
   its body from: a hairline outline, a bright specular edge along the top
   and left, a soft sheen falling across the face, a faint darkening towards
   the bottom that gives the slab thickness, and a lifted, diffuse shadow.
   Dark mode keeps the shared glass unchanged.
   -------------------------------------------------------------------------- */

:root:not([data-theme="dark"]) .namecard{
  /* No border at all: the hairline shadow outlines the card. A border - even
     a transparent one - left a 1px band outside the inset shading that read
     as a light stripe along the bottom edge. The padding takes back its 1px
     so the card keeps its size. */
  border: 0;
  padding: 19px 21px;
  background:
    linear-gradient(135deg,
      rgba(255,255,255,.80) 0%,
      rgba(255,255,255,.34) 42%,
      rgba(255,255,255,.18) 62%,
      rgba(255,255,255,.52) 100%),
    linear-gradient(180deg, #fcfcfe 0%, #f4f5f9 100%);
  backdrop-filter: blur(24px) saturate(180%);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  box-shadow:
    0 0 0 .5px rgba(28, 32, 44, .15),              /* hairline outline */
    inset 0 1.5px 0 rgba(255,255,255,1),           /* top specular edge */
    inset 1.5px 0 0 rgba(255,255,255,.85),         /* left specular edge */
    inset 0 -1px 0 rgba(28, 32, 44, .06),          /* refracted bottom edge */
    inset 0 -26px 36px -30px rgba(28, 32, 44, .07), /* thickness */
    0 22px 44px -18px rgba(20, 24, 36, .22),       /* lift */
    0 3px 8px rgba(20, 24, 36, .07);
}

/* The rim: light catches the top edge and runs a little way down the sides,
   then fades out - the bottom edge sits in the glass's own shadow, so it
   carries no highlight. */
:root:not([data-theme="dark"]) .namecard::after{
  padding: 1.5px;
  background: linear-gradient(172deg,
    rgba(255,255,255,1) 0%,
    rgba(255,255,255,.6) 20%,
    rgba(255,255,255,.14) 48%,
    rgba(255,255,255,0) 72%);
}

/* A soft sheen across the upper half of the face, under the content. */
.namecard > *{
  position: relative;
  z-index: 1;
}

:root:not([data-theme="dark"]) .namecard::before{
  content: "";
  position: absolute;
  inset: 1px;
  z-index: 0;
  border-radius: calc(var(--r) - 2px);
  background:
    radial-gradient(120% 70% at 18% -10%, rgba(255,255,255,.85), rgba(255,255,255,0) 60%),
    linear-gradient(180deg, rgba(255,255,255,.35), rgba(255,255,255,0) 38%);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Name card - hover, as the research cards do: it lifts 3px, its outline
   takes the link colour and the shadow deepens with a hint of blue. Light
   mode keeps its glass edges while it lifts; dark mode matches the research
   card's dark hover exactly.
   -------------------------------------------------------------------------- */

.namecard{
  transition:
    transform 180ms ease,
    box-shadow 180ms ease,
    border-color 180ms ease,
    background-color 180ms ease;
}

.namecard:hover{
  transform: translateY(-3px);
}

:root:not([data-theme="dark"]) .namecard:hover{
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--link) 30%, transparent),  /* outline */
    inset 0 1.5px 0 rgba(255,255,255,1),
    inset 1.5px 0 0 rgba(255,255,255,.85),
    inset 0 -1px 0 rgba(28, 32, 44, .06),
    inset 0 -26px 36px -30px rgba(28, 32, 44, .07),
    0 16px 36px color-mix(in srgb, var(--link) 16%, transparent),
    0 2px 5px color-mix(in srgb, var(--link) 10%, transparent);
}

:root[data-theme="dark"] .namecard:hover{
  border-color: color-mix(in srgb, var(--link) 34%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.12), rgba(255,255,255,.045)),
    color-mix(in srgb, var(--link) 13%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.2),
    inset 0 -1px 0 rgba(0,0,0,.25),
    0 16px 38px rgba(0,0,0,.55),
    0 2px 5px rgba(0,0,0,.35);
}

@media (prefers-reduced-motion: reduce){
  .namecard,
  .namecard:hover{
    transition: none;
    transform: none;
  }
}

/* --------------------------------------------------------------------------
   People - every member is one compact line: level badge, name, department
   (with the degree, for an alum), then research interests or an arrow to
   where they went. Plain lines split by hairlines, not the lab's glass
   .alum-row cards, only a little taller than the badge. The fields reuse the lab's
   .alum-name / .alum-meta / .alum-next text styles.
   -------------------------------------------------------------------------- */

/* Fixed tracks, so the fields line up down each section. The badge fits
   "Intern", the widest label. A current member's "name (dept)" fits
   "Isaiah Candelaria (ECE)" (159px); then honours (Abel's two, the longest)
   and interests ("Distributional Robustness", 141px). An alum's name, "dept,
   degree" ("AIMS@UNM, Intern '25", 133px) and destination (252px) each take
   a track of their own, which .is-alum sizes below. */
.member-row{
  display: grid;
  grid-template-columns:
    64px 164px 262px minmax(0, 1fr);
  align-items: baseline;
  gap: 10px;
  padding: 5px 0;
  line-height: 1.4;
}

/* Every member sits between two hairlines: each row draws the line under
   it, and the first row of a section also the line above it. */
.member-row{
  border-bottom: 1px solid var(--line);
}

.people-section > h2 + .member-row,
.people-section > .section-head + .member-row{
  border-top: 1px solid var(--line);
}

.member-row.is-alum{
  grid-template-columns:
    64px 164px 140px minmax(0, 1fr);
}

.member-row > .alum-level{ grid-column: 1; }
.member-row > .alum-name{ grid-column: 2; }
.member-row > .alum-meta{ grid-column: 3; }
.member-row > .alum-next,
.member-row > .alum-interest{ grid-column: 4; }

.member-row > .member-honors{ grid-column: 3; white-space: nowrap; }

.member-row > .alum-name{
  white-space: nowrap;
}

/* A current member's department, in brackets after the name. */
.member-dept{
  color: var(--muted);
  font-size: 13.5px;
  font-weight: 400;
}

/* Honours line up in their own column: bold, in UNM red, each led
   by the award rosette the lab site gives .person-honor. */
.member-honor + .member-honor{
  margin-left: 8px;
}

.member-honor{
  color: var(--unm-red);   /* UNM red; the lighter red in dark mode */
  font-size: 12.5px;
  font-weight: 700;
  white-space: nowrap;
  /* A label, not text to copy: it cannot be selected. */
  -webkit-user-select: none;
          user-select: none;
}

.member-honor::before{
  content: "";
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-right: 4px;
  vertical-align: -2px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8.5' r='5.5'/%3E%3Cpath d='M8.6 12.9 7 21l5-2.8L17 21l-1.6-8.1'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8.5' r='5.5'/%3E%3Cpath d='M8.6 12.9 7 21l5-2.8L17 21l-1.6-8.1'/%3E%3C/svg%3E") center / contain no-repeat;
}

.alum-interest{
  color: var(--muted);
  font-size: 14px;
  font-style: italic;
}

/* The level badge: a tinted chip led by a dot in the level's colour. Every
   badge fills the column, so they are all one width. */
.alum-level{
  --level: var(--link);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 1px 8px;
  border-radius: 6px;
  background: var(--level-bg, color-mix(in srgb, var(--level) 14%, transparent));
  color: var(--text);
  font-size: 13.5px;
  line-height: 1.5;
  white-space: nowrap;
}

.alum-level::before{
  content: "";
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--level);
}

/* Matte pastels, one family each: the lightest shade fills the badge and the
   deepest is the dot. Flat colours, not tints mixed into the page. Ph.D. is
   the theme blue: the dot is the link colour, on a flat light blue. */
.level-phd{ --level: var(--link); --level-bg: #dde1f3; }  /* theme blue */
.level-ms{ --level: #9ca5d4; --level-bg: #eceef9; }       /* theme blue, lighter than Ph.D. */
.level-bs{ --level: #97af94; --level-bg: #deefdc; }       /* sage */
.level-alum{ --level: #7b97ac; --level-bg: #cce0f0; }     /* dusty blue */
.level-intern{ --level: #bbcbb9; --level-bg: #eef7ed; }   /* sage, lighter than B.S. */

/* On the dark page a solid pastel glares, so the fill drops to a faint wash
   of it and the pastel moves into the text: the same family, kept quiet. */
:root[data-theme="dark"] .alum-level{
  background: color-mix(in srgb, var(--level-bg, var(--level)) 20%, transparent);
  color: var(--level-bg, var(--text));
}

/* On a phone the badge and name share the first line and the rest of the
   row stacks under them. */
@media (max-width: 700px){
  .member-row,
  .member-row.is-alum{
    grid-template-columns: 64px minmax(0, 1fr);
    row-gap: 2px;
    padding: 6px 0;
  }

  /* Honours take a line of their own here, and may wrap. The space between
     two honours is a gap, not a margin, so one that wraps to the next line
     starts right under the first instead of indented. */
  .member-row > .member-honors{
    display: flex;
    flex-wrap: wrap;
    gap: 3px 10px;
    white-space: normal;
  }

  .member-row .member-honor + .member-honor{
    margin-left: 0;
  }

  /* The badge is a bullet: everything else lines up under the name, and
     nothing sits below the badge. */
  .member-row > .member-honors,
  .member-row > .alum-meta,
  .member-row > .alum-next,
  .member-row > .alum-interest{
    grid-column: 2;
  }

  .member-row > .alum-level{
    align-self: start;
  }
}

/* Every section heading in the theme grey, whichever .md file it comes
   from: People's groups, Teaching's universities, the home page's lists, and
   any "## Heading" written in a page's Markdown (home, openings, a project
   page, a panel). Page titles are h1 and keep the text colour; the course
   pages have their own stylesheet. One size too; a heading inside a text
   panel (.prose) keeps its smaller one. */
main h2{
  color: var(--muted);
  font-size: 26px;
}


/* --------------------------------------------------------------------------
   People - levels. Rows are grouped by level, with the same hairline between
   every two rows; the badge colour shows where a level changes. An alum's badge
   names the level they finished at, with a graduation cap - the same Font
   Awesome glyph as the Scholar link on the name card - in place of the dot.
   -------------------------------------------------------------------------- */

.member-row.is-alum > .alum-level::before{
  width: 14px;
  height: 11px;
  border-radius: 0;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'%3E%3Cpath d='M320 32c-8.1 0-16.1 1.4-23.7 4.1L15.8 137.4C6.3 140.9 0 149.9 0 160s6.3 19.1 15.8 22.6l57.9 20.9C57.3 229.3 48 259.8 48 291.9V320c0 28.4-10.8 57.7-22.3 80.8-6.5 13-13.9 25.8-22.5 37.6-3.2 4.3-4.1 9.9-2.3 15s6 8.9 11.2 10.2l64 16c4.2 1.1 8.7.3 12.4-2s6.3-6.1 7.1-10.4c8.6-42.8 4.3-81.2-2.1-108.7-3.2-14.2-7.5-28.7-13.5-42v-24.6c0-30.2 10.2-58.7 27.9-81.5 12.9-15.5 29.6-28 49.2-35.7l157-61.7c8.2-3.2 17.5.8 20.7 9s-.8 17.5-9 20.7l-157 61.7c-12.4 4.9-23.3 12.4-32.2 21.6l159.6 57.6c7.6 2.7 15.6 4.1 23.7 4.1s16.1-1.4 23.7-4.1l280.6-101c9.5-3.4 15.8-12.5 15.8-22.6s-6.3-19.1-15.8-22.6L343.7 36.1c-7.6-2.7-15.6-4.1-23.7-4.1M128 408c0 35.3 86 72 192 72s192-36.7 192-72l-15.3-145.4L354.5 314c-11.1 4-22.8 6-34.5 6s-23.5-2-34.5-6l-142.2-51.4z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'%3E%3Cpath d='M320 32c-8.1 0-16.1 1.4-23.7 4.1L15.8 137.4C6.3 140.9 0 149.9 0 160s6.3 19.1 15.8 22.6l57.9 20.9C57.3 229.3 48 259.8 48 291.9V320c0 28.4-10.8 57.7-22.3 80.8-6.5 13-13.9 25.8-22.5 37.6-3.2 4.3-4.1 9.9-2.3 15s6 8.9 11.2 10.2l64 16c4.2 1.1 8.7.3 12.4-2s6.3-6.1 7.1-10.4c8.6-42.8 4.3-81.2-2.1-108.7-3.2-14.2-7.5-28.7-13.5-42v-24.6c0-30.2 10.2-58.7 27.9-81.5 12.9-15.5 29.6-28 49.2-35.7l157-61.7c8.2-3.2 17.5.8 20.7 9s-.8 17.5-9 20.7l-157 61.7c-12.4 4.9-23.3 12.4-32.2 21.6l159.6 57.6c7.6 2.7 15.6 4.1 23.7 4.1s16.1-1.4 23.7-4.1l280.6-101c9.5-3.4 15.8-12.5 15.8-22.6s-6.3-19.1-15.8-22.6L343.7 36.1c-7.6-2.7-15.6-4.1-23.7-4.1M128 408c0 35.3 86 72 192 72s192-36.7 192-72l-15.3-145.4L354.5 314c-11.1 4-22.8 6-34.5 6s-23.5-2-34.5-6l-142.2-51.4z'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Lavender, in the same matte family, for a postdoc when there is one. */
.level-postdoc{ --level: #a79ad1; --level-bg: #e6e1f4; }


/* --------------------------------------------------------------------------
   People - hover. The row lights up as a whole and zooms in slightly: a
   soft band behind it,
   reaching a little past the ends of its lines, in a flat neutral (not a
   tint mixed into the page) - lighter again in dark mode.
   -------------------------------------------------------------------------- */

.member-row{
  position: relative;
  transition: transform 150ms ease;
}

/* ...and zooms in a touch. */
.member-row:hover{
  transform: scale(1.015);
}

.member-row::before{
  content: "";
  position: absolute;
  inset: 0 -10px;
  z-index: -1;
  border-radius: 8px;
  background: transparent;
  transition: background-color 150ms ease;
  pointer-events: none;
}

.member-row:hover::before{
  background: #f1f2f5;
}

:root[data-theme="dark"] .member-row:hover::before{
  background: rgba(255,255,255,.06);
}

@media (prefers-reduced-motion: reduce){
  .member-row,
  .member-row::before{
    transition: none;
  }

  .member-row:hover{
    transform: none;
  }
}


/* A button that leaves the site ("Check our lab website") ends in the same
   outward-arrow icon as the reference pills, instead of the arrow. */
.btn-external::after{
  content: "";
  width: 12px;
  height: 12px;
  flex: 0 0 12px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 4h6v6'/%3E%3Cpath d='M20 4 10 14'/%3E%3Cpath d='M18 13v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 4h6v6'/%3E%3Cpath d='M20 4 10 14'/%3E%3Cpath d='M18 13v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5'/%3E%3C/svg%3E") center / contain no-repeat;
  opacity: .75;
  transition: opacity 150ms ease;
}

.btn-external:hover::after{
  opacity: 1;
}

/* --------------------------------------------------------------------------
   Teaching - one line per course, the People rows again (hairlines, hover):
   "code: name" in plain text, any honours (award icon + name, as on People),
   then role and terms.
   -------------------------------------------------------------------------- */

/* Three fixed tracks, so each field starts at the same x on every row:
   "code: name"; honours 200px, one per line (fits the widest, "SoE Teaching
   Innovation Award", 198px); role and terms 116px, right-aligned. The name
   gets the rest - 374px, room for the longest beside an honour, "ME 400/500:
   Numerical Methods in Mechanical Engineering" (368px). A row with no
   honours lets its name run on across the honours column. */
.member-row.course-row{
  grid-template-columns: minmax(0, 1fr) 200px 116px;
  column-gap: 5px;
}

.course-row:not(.has-honors) > .course-title{
  grid-column: 1 / 3;
}

.course-row > .course-title{
  grid-column: 1;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;   /* a name too long for its space ends in "…" */
  font-size: 15px;
}

/* An honour with a full name shows it at once on hover, in a small label
   above it - the browser's own title tooltip waited a second and rarely
   appeared on a row that zooms under the pointer. */
.member-honor[data-full]{
  position: relative;
  cursor: help;
}

.member-honor[data-full]:hover::after{
  font-style: normal;
  content: attr(data-full);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 7px);
  z-index: 5;
  transform: translateX(-50%);
  padding: 4px 9px;
  border-radius: 7px;
  background: var(--text);
  color: var(--bg);
  box-shadow: 0 6px 18px rgba(0,0,0,.18);
  font-size: 12.5px;
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
}

/* A course name that links is a standard site link: theme blue, no
   underline, underlined on hover (the base a / a:hover rules). */

/* Several honours stack, one per line, so each keeps its full name. */
.course-row > .member-honors{
  grid-column: 2;
  justify-self: start;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
  line-height: 1;   /* the award icon no longer makes its row taller */
}

.course-row .member-honor + .member-honor{
  margin-left: 0;
}

.course-row > .course-when{
  grid-column: 3;
  justify-self: end;
  color: var(--muted);
  font-size: 13.5px;
  white-space: nowrap;
  text-align: right;
}

/* In a row made two lines tall by stacked honours, the name and the terms
   sit halfway down rather than on the first line. */
.course-row.stacked > .course-title,
.course-row.stacked > .course-when{
  align-self: center;
}

/* That row has two lines to use, so its terms take one season per line
   ("Spring 24, 26;" / "Summer 25, 26"), which keeps a clear gap after the
   longest honour instead of running up against it. */
.course-row.stacked .course-terms{
  display: inline-block;
  line-height: 1.35;
  vertical-align: middle;
}

.course-row.stacked .term-group{
  display: block;
}

/* One season per line needs no ";" between them. */
.course-row.stacked .term-sep{
  display: none;
}

/* A season and its years ("Sp 24, 26") never break apart. */
.term-group{
  white-space: nowrap;
}

.course-when .course-role{
  margin-right: 8px;
  font-style: normal;
}

/* Graduate courses in the UNM red - the dot is the theme's red, on a flat
   light red - and undergraduate ones in the People page's B.S. sage. */
.level-grad{ --level: var(--unm-red); --level-bg: #f3d3da; }
.level-ug{ --level: #97af94; --level-bg: #deefdc; }

/* The key: the level badges on one line, above the first university, at
   the right edge. */
.level-key{
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 26px;
}

@media (max-width: 700px){
  .member-row.course-row{
    grid-template-columns: minmax(0, 1fr);
  }

  .course-row > .course-title,
  .course-row:not(.has-honors) > .course-title{
    grid-column: 1;
    white-space: normal;
  }

  /* Honours, role and terms stack under the name, the terms at the left. A
     two-line row's name and terms go back to the top here. */
  .course-row > .member-honors,
  .course-row > .course-when,
  .course-row.stacked > .course-when{
    grid-column: 1;
    justify-self: start;
    text-align: left;
  }

  .course-row.stacked > .course-title{
    align-self: start;
  }

  /* On one line again: the terms have the width to themselves. */
  .course-row.stacked .term-group{
    display: inline;
  }

  .course-row.stacked .term-sep{
    display: inline;
  }
}

/* A course name linking to another site (the UIUC course pages) ends in the
   outward-arrow icon the reference pills use. It follows the text colour, so
   it turns blue with the name on hover. */
.course-title a.is-external::after,
.more-link a.is-external::after{
  content: "";
  display: inline-block;
  width: 11px;
  height: 11px;
  margin-left: 5px;
  vertical-align: -1px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 4h6v6'/%3E%3Cpath d='M20 4 10 14'/%3E%3Cpath d='M18 13v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 4h6v6'/%3E%3Cpath d='M20 4 10 14'/%3E%3Cpath d='M18 13v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5'/%3E%3C/svg%3E") center / contain no-repeat;
  opacity: .7;
}

.course-title a.is-external:hover::after,
.more-link a.is-external:hover::after{
  opacity: 1;
}

/* --------------------------------------------------------------------------
   People - an alum's honours: the award rosette after the name, in UNM
   red, with a small count when there is more than one ("×2"). Pointing at
   it shows the honours' names, like the honour labels on Teaching.
   -------------------------------------------------------------------------- */

/* Icon, "×" and number are three pieces spaced by one gap, so the space
   between icon and × matches the space between × and number. */
.alum-honor{
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-left: 10px;
  color: var(--unm-red);   /* UNM red; the lighter red in dark mode */
  vertical-align: -1px;
  cursor: help;
  position: relative;
  -webkit-user-select: none;
          user-select: none;
}

.alum-honor::before{
  content: "";
  width: 14px;
  height: 14px;
  /* The rosette is drawn narrower than its 14px box, with about 3px blank
     on each side; this takes back the blank on the right, so the visible
     gap from icon to "×" equals the one from "×" to the number. */
  margin-right: -2.75px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8.5' r='5.5'/%3E%3Cpath d='M8.6 12.9 7 21l5-2.8L17 21l-1.6-8.1'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8.5' r='5.5'/%3E%3Cpath d='M8.6 12.9 7 21l5-2.8L17 21l-1.6-8.1'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* The count sits a little apart from the icon, at about the name's size,
   bold, so "×2" reads clearly as part of the mark. */
.alum-honor-count{
  font-family: var(--font-body);
  font-size: 14.5px;
  font-weight: 700;
  line-height: 1;
}

/* One honour per line: the build puts a line break between them. */
.alum-honor:hover::after{
  content: attr(data-full);
  white-space: pre;
  text-align: left;
  line-height: 1.5;
  position: absolute;
  left: 50%;
  bottom: calc(100% + 7px);
  z-index: 5;
  transform: translateX(-50%);
  padding: 4px 9px;
  border-radius: 7px;
  background: var(--text);
  color: var(--bg);
  box-shadow: 0 6px 18px rgba(0,0,0,.18);
  font-size: 12.5px;
  font-weight: 600;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   People and Teaching - hover as Liquid Glass. The hovered row sits on a
   small sheet of the site's panel glass, the same as the mentoring panel on
   People. The hairlines above and below it step
   aside while it is hovered, so the glass stands on its own.
   -------------------------------------------------------------------------- */

.member-row{
  transition: transform 150ms ease, border-color 150ms ease;
}

.member-row::before{
  inset: -1px -10px;
  border-radius: 14px;
  transition: background-color 150ms ease, box-shadow 150ms ease, opacity 150ms ease;
}

/* The lines around the hovered row: its own, and the one the row above it
   draws along its bottom. */
.member-row:hover,
.people-section > h2 + .member-row:hover,
.people-section > .section-head + .member-row:hover{
  border-top-color: transparent;
  border-bottom-color: transparent;
}

.member-row:has(+ .member-row:hover){
  border-bottom-color: transparent;
}

/* The glass is the site's shared panel material - exactly what the "I am a
   faculty mentor" panel above wears, in both themes: its outline (stronger
   down the sides in light mode), fill, edge light, shadow and the white rim
   that is brightest at the left and right edges (drawn by ::after). */
.member-row:hover::before{
  box-sizing: border-box;
  border-width: 1px;
  border-style: solid;
  border-color:
    color-mix(in srgb, var(--link) 18%, transparent)
    color-mix(in srgb, var(--link) 26%, transparent);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, #fff 74%, transparent),
      color-mix(in srgb, #fff 42%, transparent)),
    color-mix(in srgb, var(--link) 6%, transparent);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.92),
    inset 0 -1px 0 color-mix(in srgb, var(--link) 8%, transparent),
    inset 9px 0 16px -12px rgba(255,255,255,.95),
    inset -9px 0 16px -12px rgba(255,255,255,.95),
    0 10px 28px color-mix(in srgb, var(--link) 10%, transparent),
    0 1px 3px color-mix(in srgb, var(--link) 8%, transparent);
}

:root[data-theme="dark"] .member-row:hover::before{
  border-color: color-mix(in srgb, var(--link) 24%, transparent);
  background:
    linear-gradient(180deg, rgba(255,255,255,.085), rgba(255,255,255,.03)),
    color-mix(in srgb, var(--link) 9%, transparent);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.14),
    inset 0 -1px 0 rgba(0,0,0,.25),
    inset 9px 0 16px -12px rgba(255,255,255,.55),
    inset -9px 0 16px -12px rgba(255,255,255,.55),
    0 10px 30px rgba(0,0,0,.45),
    0 1px 3px rgba(0,0,0,.3);
}

/* The rim, as on the panels: a white ring, brightest at the two sides. */
/* 1px inside the glass's outline, as on the panels, so both show. */
.member-row:hover::after{
  content: "";
  position: absolute;
  inset: 0 -9px;
  z-index: -1;
  border-radius: 13px;
  padding: 1px;
  background: linear-gradient(90deg,
    rgba(255,255,255,.98) 0%,
    rgba(255,255,255,.62) 5%,
    rgba(255,255,255,.14) 24%,
    rgba(255,255,255,.07) 50%,
    rgba(255,255,255,.14) 76%,
    rgba(255,255,255,.62) 95%,
    rgba(255,255,255,.98) 100%);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
}

:root[data-theme="dark"] .member-row:hover::after{
  background: linear-gradient(90deg,
    rgba(255,255,255,.80) 0%,
    rgba(255,255,255,.44) 5%,
    rgba(255,255,255,.10) 24%,
    rgba(255,255,255,.05) 50%,
    rgba(255,255,255,.10) 76%,
    rgba(255,255,255,.44) 95%,
    rgba(255,255,255,.80) 100%);
}

/* An email link given class="mail-link" ends in a small envelope, in the
   link's own colour - the same mark as the email icon - so it reads as
   "this writes an email". Opt-in: used on the Openings page's postdoc line. */
.mail-link::after{
  content: "";
  display: inline-block;
  width: .95em;
  height: .95em;
  margin-left: .25em;
  vertical-align: -.12em;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='14' rx='2.5'/%3E%3Cpath d='m3.5 7 8.5 6 8.5-6'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='14' rx='2.5'/%3E%3Cpath d='m3.5 7 8.5 6 8.5-6'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* A paragraph that starts with an opening dot reads as a bullet point: the
   dot sits in the left margin, centred on the first line, and every line of
   the text - wrapped ones too - starts at the same indent after it. */
p:has(> .opening-dot:first-child){
  position: relative;
  padding-left: 18px;   /* the 8px dot + a 10px gap */
}

p:has(> .opening-dot:first-child) > .opening-dot:first-child{
  position: absolute;
  left: 0;
  top: .62em;            /* fallback where lh is not supported */
  top: calc(.5lh - 4px); /* the middle of the first line */
  margin-right: 0;
}
