/* ==========================================================================
   dgalandieguez.com — main stylesheet
   --------------------------------------------------------------------------
   The palette comes from the gravity-darkened star of the home page: the
   blue-to-red color scale of its surface (--gd) and two accents taken from
   it, a blue (--accent) and a warm orange (--warm). Sora is used for
   headings and Plus Jakarta Sans for body and interface text. Everything
   (fonts and icons) is self-hosted; nothing is loaded from other servers.

   CONTENTS
     1.  Fonts (@font-face)
     2.  Design tokens (custom properties)
     3.  Base elements and utilities
     4.  Site header and navigation
     5.  Page header (inner pages)
     6.  Sections, section tabs and section headings
     7.  Layouts: two columns, matched columns, sidebar (rail)
     8.  Buttons, link rows, pills and chips
     9.  Cards
     10. Card grids, filters and timeline
     11. Home page: hero and interactive star
     12. Stat cards and people
     13. Content blocks: figures, tables, steps, citations
     14. Software pages: sidebar lists, feature cards, examples
     15. Site footer
     16. Motion: entrance, scroll and hover animations
     17. Reduced motion
   ========================================================================== */


/* ==========================================================================
   1. FONTS
   Each weight is split into two files (latin / latin-ext) so that browsers
   only download the characters a page actually uses.
   ========================================================================== */

/* ---------- Sora (headings) ---------- */

/* Sora 600 normal, latin */
@font-face {
  font-family: "Sora";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../fonts/sora-latin-600-normal.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Sora 600 normal, latin-ext */
@font-face {
  font-family: "Sora";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../fonts/sora-latin-ext-600-normal.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Sora 700 normal, latin */
@font-face {
  font-family: "Sora";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/sora-latin-700-normal.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Sora 700 normal, latin-ext */
@font-face {
  font-family: "Sora";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/sora-latin-ext-700-normal.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- Plus Jakarta Sans (body and interface) ---------- */

/* Plus Jakarta Sans 400 normal, latin */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/plus-jakarta-sans-latin-400-normal.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Plus Jakarta Sans 400 normal, latin-ext */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/plus-jakarta-sans-latin-ext-400-normal.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Plus Jakarta Sans 500 normal, latin */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../fonts/plus-jakarta-sans-latin-500-normal.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Plus Jakarta Sans 500 normal, latin-ext */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../fonts/plus-jakarta-sans-latin-ext-500-normal.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Plus Jakarta Sans 600 normal, latin */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../fonts/plus-jakarta-sans-latin-600-normal.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Plus Jakarta Sans 600 normal, latin-ext */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../fonts/plus-jakarta-sans-latin-ext-600-normal.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Plus Jakarta Sans 700 normal, latin */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/plus-jakarta-sans-latin-700-normal.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Plus Jakarta Sans 700 normal, latin-ext */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/plus-jakarta-sans-latin-ext-700-normal.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Plus Jakarta Sans 400 italic, latin */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/plus-jakarta-sans-latin-400-italic.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Plus Jakarta Sans 400 italic, latin-ext */
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/plus-jakarta-sans-latin-ext-400-italic.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* ==========================================================================
   2. DESIGN TOKENS
   ========================================================================== */

:root {
  /* ---------- Colors: dark "night sky" surfaces ---------- */
  --night: #0a1033;
  --night-text: #dfe5f7;
  --night-muted: #9aa5c7;

  /* ---------- Colors: light surfaces and text ---------- */
  --paper: #f5f6f9;          /* page background */
  --surface: #ffffff;        /* cards, alternate sections */
  --ink: #1c2236;            /* main text */
  --muted: #596178;          /* secondary text */
  --rule: #dce0ea;           /* borders and dividers */

  /* ---------- Colors: accents ---------- */
  --accent: #2459e8;         /* links, primary buttons, icons */
  --accent-hover: #1a45c4;   /* primary buttons on hover */
  --accent-soft: #e6eeff;    /* light backgrounds (ghost buttons, portraits) */
  --accent-line: #9db8ff;    /* border of a hovered card */
  --warm: #d9480f;           /* focus ring */

  /* Space between an icon (Font Awesome <i>) and the text next to it */
  --icon-gap: .25em;

  /* Gravity-darkening color scale: the same one as the rotating star
     (star.js, section 2) and its color bar. Every gradient bar of the site
     uses it, so change it here only (and in star.js for the star). */
  --gd-stops: #1e50c8 0%, #7cc4ff 25%, #f2f7ff 50%, #ffd84d 67%, #ff8c1a 83%, #aa1e14 100%;
  --gd: linear-gradient(90deg, var(--gd-stops));

  /* ---------- Colors: pills ----------
     ("In progress" and "Upcoming" use the yellow and gray pills, section 8) */
  --ok: #2e7d4f;             /* green: completed, published, public talks */
  --ok-soft: #e5f4ea;
  --rev: #1f63c6;            /* blue: contributed talks, TV */
  --rev-soft: #e3eefc;
  --prep: #c2410c;           /* orange: posters, podcasts, courses */
  --prep-soft: #fff1e6;
  --vio: #a3195b;            /* magenta: invited talks, schools, boards, ERC */
  --vio-soft: #fce7f1;

  /* ---------- Typography ---------- */
  --display: "Sora", "Plus Jakarta Sans", system-ui, sans-serif;            /* headings */
  --sans: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;   /* everything else */
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* ---------- Type scale ----------
     Every font-size of the site is one of the tokens below (no loose values
     in the rules), so the same kind of text has exactly the same size on
     every page. To make, say, all the card texts larger, change the token
     once here. Pixel values assume the browser default of 16px = 1rem.

     a) Headings (display font, Sora) */
  --step-0: 1.0625rem;                      /* 17px  small titles */
  --step-1: 1.3125rem;                      /* 21px  h3, page-header intro (.lede) */
  --step-2: 1.6875rem;                      /* 27px  h2 */
  --step-3: 2.25rem;                        /* 36px  section titles */
  --step-4: clamp(2.4rem, 4.6vw, 3.6rem);   /* 38-58px  page titles (h1), fluid */

  /*  b) Text and interface, from smallest to largest (body font) */
  --fs-label: .72rem;     /* 11.5px  UPPERCASE labels: pills, section tabs, mobile menu groups */
  --fs-xs: .8rem;         /* 12.8px  small controls: chip buttons, "Copy" buttons, color key */
  --fs-sm: .875rem;       /* 14px    secondary text: meta lines, dates, captions, chips, filters,
                                     people roles, stat labels, table headers, footer fine print */
  --fs-ui: .9375rem;      /* 15px    compact text: card paragraphs, sidebars, tables, buttons,
                                     navigation, link rows, footer */
  --fs-body: 1rem;        /* 16px    running text (biography, software pages, steps), names */
  --fs-title: var(--step-0);  /* 17px  small titles: card titles, sidebar box titles */
  --fs-lead: 1.125rem;    /* 18px    one-line section intros (.section-intro), brand, profile name */

  /*  c) Code (monospace looks larger than the body font at the same size) */
  --fs-code: .8rem;       /* 12.8px  code blocks in the text */
  --fs-code-sm: .75rem;   /* 12px    code blocks inside cards and sidebars (BibTeX, examples) */
  /* Inline <code> uses .85em instead: it follows the size of the text around it */

  /*  d) Special cases, not running text */
  --fs-icon: 1.25rem;                       /* 20px  icon glyphs (feature-card squares, hero social links) */
  --fs-stat: clamp(2rem, 3vw, 2.6rem);      /* 32-42px  big numbers of the stat cards, fluid */

  /* ---------- Layout ---------- */
  --wrap: 88rem;             /* maximum page width */
  --measure: 46rem;          /* comfortable reading width */
  --radius: 6px;             /* small elements (code, figures) */
  --card-r: 14px;            /* cards and boxes */

  /* ---------- Shadows ---------- */
  --shadow-1: 0 1px 2px rgba(18, 28, 70, .06), 0 2px 8px rgba(18, 28, 70, .04);   /* resting */
  --shadow-2: 0 22px 45px -20px rgba(18, 28, 70, .38);                            /* hover */
}


/* ==========================================================================
   3. BASE ELEMENTS AND UTILITIES
   ========================================================================== */

/* ---------- Reset and document ---------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: 5rem;  /* anchors are not hidden under the sticky header */
}

/* The body font is inherited by every element; only headings (--display)
   and form controls (which do not inherit fonts, so they set "font") change it */
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.72;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

/* ---------- Links and focus ---------- */

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
}

a:hover {
  text-decoration-thickness: 2px;
}

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

/* ---------- Headings ---------- */

h1,
h2,
h3 {
  font-family: var(--display);
  font-weight: 600;
  line-height: 1.2;
  margin: 0 0 .5em;
  letter-spacing: -.02em;
}

h2 {
  font-size: var(--step-2);
}

h3 {
  font-size: var(--step-1);
}

/* ---------- Running text ---------- */

/* Justified, hyphenated text by default... */
p,
li {
  text-align: justify;
  hyphens: auto;
  -webkit-hyphens: auto;
}

p {
  margin: 0 0 1em;
}

/* ...except in interface elements, where it would look odd */
.nav li,
.social,
.actions li,
.pill-row,
.card-foot,
.star-readout,
.site-footer li,
.site-footer p,
.stat-cards li,
.person {                    /* names, roles and affiliations of people */
  text-align: left;
  hyphens: manual;
  -webkit-hyphens: manual;
}

/* ---------- Code ---------- */

code {
  font-family: var(--mono);
  font-size: .85em;          /* relative: inline code follows the size of its text */
  background: #eef0f5;
  padding: .1em .35em;
  border-radius: 3px;
}

pre {
  font-family: var(--mono);
  font-size: var(--fs-code);
  line-height: 1.55;
  background: var(--night);
  color: #e4e9f8;
  padding: 1rem 1.15rem;
  border-radius: var(--radius);
  overflow-x: auto;
  margin: 0 0 1.25rem;
}

pre code {
  background: none;
  padding: 0;
  color: inherit;
  font-size: inherit;
}

/* ---------- Accessibility helpers ---------- */

/* "Skip to content" link: off-screen until focused with the keyboard */
.skip {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--surface);
  padding: .5rem 1rem;
  z-index: 100;
}

.skip:focus {
  left: 1rem;
  top: 1rem;
}

/* ---------- Layout and text utilities ---------- */

/* Centered page container */
.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 clamp(1rem, 3.5vw, 3rem);
}

/* Long-form text at a comfortable line length */
.prose {
  max-width: var(--measure);
}

/* Next to a sidebar the text fills its column, as on the About page */
.two-col > .prose,
.two-col > .stack > .prose {
  max-width: none;
}

/* Section titles inside a text column (software pages) */
.prose .section-title:not(:first-child) {
  margin-top: 3.5rem;
}

.prose li {
  margin-bottom: .45em;
}

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

.small {
  font-size: var(--fs-sm);
}

/* Introductory paragraph next to the stat cards (Publications, Supervision,
   Outreach): same size and weight as the running text of About and the
   software pages, so every section opens with the same text style */
.intro-row > div > p {
  font-size: var(--fs-body);
  color: var(--ink);
}


/* ==========================================================================
   4. SITE HEADER AND NAVIGATION
   ========================================================================== */

/* ---------- Header bar (sticky, translucent) ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(12, 19, 48, .94);
  backdrop-filter: saturate(140%) blur(8px);
  -webkit-backdrop-filter: saturate(140%) blur(8px);
  color: var(--night-text);
}

/* Thin gravity-darkening line under the header */
.site-header::after {
  content: "";
  display: block;
  height: 2px;
  background: var(--gd);
  opacity: .85;
}

.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 4rem;
}

/* ---------- Brand (logo + name) ---------- */

.brand {
  color: #fff;
  text-decoration: none;
  font-family: var(--display);
  font-size: var(--fs-lead);
  font-weight: 600;
  letter-spacing: -.01em;
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: .6rem;
}

.brand img {
  width: 40px;
  height: 40px;
  flex: none;
  display: block;
}

.brand:hover {
  text-decoration: none;
  color: #fff;
}

/* ---------- Navigation links ---------- */

.nav {
  display: flex;
  align-items: center;
  gap: .25rem;
}

.nav > ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  gap: .15rem;
  align-items: center;
}

.nav a,
.nav button {
  color: var(--night-text);
  text-decoration: none;
  font: 500 var(--fs-ui)/1 var(--sans);
  padding: .65rem .75rem;
  border-radius: 4px;
  background: none;
  border: 0;
  cursor: pointer;
  display: block;
}

.nav a:hover,
.nav button:hover,
.nav li.open > button {
  background: rgba(255, 255, 255, .08);
  color: #fff;
}

/* Gradient underline of the top-level items.
   It marks the current page (or the menu that contains it); while the mouse
   is over the bar it moves to the hovered item, and comes back on leaving. */
.nav a[aria-current="page"] {
  color: #fff;
}

.nav > ul > li > a,
.nav > ul > li > button {
  position: relative;
}

.nav > ul > li > a:not(.cv-link)::before,
.nav > ul > li > button::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--gd);
  transform: scaleX(0);
  transition: transform .25s ease;
}

/* current page, or the dropdown that holds it */
.nav > ul > li > a[aria-current="page"]::before,
.nav > ul > li:where(:has([aria-current="page"])) > button::before {
  transform: scaleX(1);
}

/* hovering the bar hides it... */
.nav > ul:hover > li > :is(a, button)::before {
  transform: scaleX(0);
}

/* ...and draws it under the hovered item */
.nav > ul > li:hover > :is(a, button)::before,
.nav > ul > li.open > button::before {
  transform: scaleX(1);
}

/* ---------- Dropdown menus (Software, Theses) ---------- */

.nav .has-sub {
  position: relative;
}

/* Chevron after the dropdown button; flips when the menu is open */
.nav .has-sub > button::after {
  content: "";
  display: inline-block;
  margin-left: .45rem;
  width: .38rem;
  height: .38rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-3px) rotate(45deg);
  transition: transform .25s ease;
}

.nav li.open > button::after {
  transform: translateY(1px) rotate(-135deg);
}

/* Parent button of the current page: white text */
.nav .has-sub:has([aria-current="page"]) > button {
  color: #fff;
}

/* The panel: always rendered, faded and slid in when its item gets .open */
.nav .sub {
  list-style: none;
  margin: 0;
  padding: .45rem;
  position: absolute;
  /* (header height 4rem - button 2.25rem) / 2 + 2px line = flush under the line */
  top: calc(100% + .875rem + 2px);
  left: 50%;
  min-width: 13.5rem;
  z-index: 10;
  background: rgba(22, 32, 74, .92);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, .1);
  border-top: 0;
  border-radius: 0 0 12px 12px;
  box-shadow: 0 24px 50px -12px rgba(0, 0, 0, .55), 0 0 0 1px rgba(0, 0, 0, .15);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translate(-50%, -6px);
  transform-origin: top center;
  transition: opacity .2s ease, transform .25s cubic-bezier(.2, .7, .2, 1), visibility 0s linear .25s;
}

/* Invisible bridge over the gap, so moving the mouse down keeps the menu open */
.nav .sub::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -1.1rem;
  height: 1.1rem;
}

/* site.js adds .open on hover / click; keyboard focus also opens it */
.nav li.open > .sub,
.nav .has-sub:has(:focus-visible) > .sub {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: translate(-50%, 0);
  transition: opacity .2s ease, transform .25s cubic-bezier(.2, .7, .2, 1), visibility 0s;
}

.nav .sub a {
  position: relative;
  padding: .65rem .85rem .65rem 1.2rem;
  line-height: 1.3;
  border-radius: 4px;
  white-space: nowrap;
}

/* Vertical gradient bar before the name: it marks the current page, moves to
   the hovered item while the mouse is in the panel, and comes back on leaving */
.nav .sub a::before {
  content: "";
  position: absolute;
  left: .45rem;
  top: 20%;
  bottom: 20%;
  width: 3px;
  border-radius: 2px;
  background: linear-gradient(var(--gd-stops));
  transform: scaleY(0);
  transition: transform .25s ease;
}

.nav .sub a[aria-current="page"]::before {
  transform: scaleY(1);
}

.nav .sub:hover a::before {
  transform: scaleY(0);
}

.nav .sub a:hover::before,
.nav .sub a:focus-visible::before {
  transform: scaleY(1);
}

.nav .sub a:focus-visible {
  background: rgba(255, 255, 255, .08);
  color: #fff;
}

/* CV link drawn as an outlined button */
.nav .cv-link {
  border: 1px solid rgba(255, 255, 255, .28);
  margin-left: .4rem;
}

.nav .cv-link i {
  margin-right: var(--icon-gap);
}

/* ---------- Mobile menu button (hidden on desktop) ---------- */

.nav-toggle {
  display: none;
  background: none;
  border: 1px solid rgba(255, 255, 255, .3);
  color: #fff;
  border-radius: 4px;
  padding: .45rem .7rem;
  font: 500 var(--fs-ui) var(--sans);
  cursor: pointer;
}

/* ---------- Mobile navigation (≤ 900px): full-width panel ---------- */

@media (max-width: 900px) {
  .nav-toggle {
    display: block;
  }

  .nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--night);
    display: none;
    padding: .5rem 1rem 1.25rem;
    border-top: 1px solid rgba(255, 255, 255, .08);
    max-height: calc(100vh - 4rem);
    overflow: auto;
  }

  .nav.open {
    display: block;
  }

  .nav > ul {
    flex-direction: column;
    align-items: stretch;
  }

  .nav a,
  .nav button {
    width: 100%;
    text-align: left;
    padding: .85rem .5rem;
    font-size: var(--fs-body);
  }

  /* Submenus are always open and indented */
  .nav .sub {
    position: static;
    display: block;
    background: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border: 0;
    border-left: 2px solid rgba(255, 255, 255, .12);
    border-radius: 0;
    box-shadow: none;
    margin: 0 0 .5rem .5rem;
    padding: 0 0 0 .5rem;
    min-width: 0;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
    transition: none;
  }

  .nav .sub::after {
    display: none;
  }

  .nav .sub a {
    white-space: normal;
  }

  /* Dropdown buttons become plain group labels */
  .nav .has-sub > button {
    pointer-events: none;
    color: var(--night-muted);
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
    padding-bottom: .35rem;
  }

  .nav .has-sub:has([aria-current="page"]) > button {
    color: var(--night-muted);
  }

  .nav .has-sub > button::before,
  .nav .has-sub > button::after {
    display: none;
  }

  .nav .cv-link {
    margin: .5rem 0 0;
    text-align: center;
  }
}


/* ==========================================================================
   5. PAGE HEADER (inner pages)
   Dark banner with a background photo, title, intro and buttons.
   ========================================================================== */

.page-head {
  position: relative;
  background: var(--night);
  color: var(--night-text);
  overflow: hidden;
}

/* Background photo (set inline on each page) */
.page-head .bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: .38;
}

/* Dark gradient over the photo so the text stays readable */
.page-head::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(12, 19, 48, .96) 0%, rgba(12, 19, 48, .72) 55%, rgba(12, 19, 48, .35) 100%);
  z-index: 1;
}

.page-head .wrap {
  position: relative;
  z-index: 2;
  padding-top: 3.5rem;
  padding-bottom: 3rem;
}

.page-head h1 {
  font-size: var(--step-4);
  color: #fff;
  margin: 0 0 .35em;
  max-width: 22ch;
  font-weight: 700;
  letter-spacing: -.035em;
  line-height: 1.05;
}

.page-head .lede {
  font-size: var(--step-1);
  line-height: 1.5;
  max-width: 52rem;
  color: var(--night-text);
  margin: 0;
}

.page-head .actions {
  margin-top: 1.5rem;
}


/* ==========================================================================
   6. SECTIONS, SECTION TABS AND SECTION HEADINGS
   ========================================================================== */

/* ---------- Page sections ---------- */

.section {
  position: relative;
  padding: 4.5rem 0;
}

/* Alternate (white) sections */
.section.alt {
  background: var(--surface);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}

/* ---------- Section tab: label centered on the top edge of a section ---------- */

.tab {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 3;
  background: var(--surface);
  color: var(--ink);
  font: 600 var(--fs-label)/1 var(--display);
  letter-spacing: .22em;
  text-transform: uppercase;
  padding: 1rem 2.2rem;
  border-radius: 10px;
  box-shadow: 0 10px 30px -12px rgba(12, 19, 48, .45);
  white-space: nowrap;
}

.section.alt .tab {
  background: var(--paper);
}

/* Phones: same text size, less padding and tracking so long tabs such as
   "Scientific portfolio" still fit */
@media (max-width: 600px) {
  .tab {
    padding: .8rem 1.4rem;
    letter-spacing: .16em;
  }
}

/* ---------- Section headings ---------- */

.section-title {
  font-size: var(--step-3);
  margin-bottom: .4em;
}

.section-intro {
  color: var(--muted);
  max-width: var(--measure);
  font-size: var(--fs-lead);
  margin-bottom: 2.25rem;
}

/* Title + intro on the left, optional extras on the right */
.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-bottom: 2rem;
}

.section-head .section-intro {
  margin: 0;
}

.section-head h2 {
  margin: 0 0 .35rem;
}

/* A second heading inside the same section gets space above it */
.section-head:not(:first-child) {
  margin-top: 3.5rem;
}


/* ==========================================================================
   7. LAYOUTS: TWO COLUMNS, MATCHED COLUMNS, SIDEBAR (RAIL)
   ========================================================================== */

/* ---------- Two columns: content + 22rem sidebar ---------- */

.two-col {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 22rem;
  gap: clamp(2rem, 4vw, 4rem);
  align-items: start;
}

/* Intro paragraph + stat cards (Publications, Supervision, Outreach) */
.two-col.intro-row {
  align-items: center;
  margin-bottom: 3rem;
}

/* No margin under the last paragraph, so the text itself (not text plus
   margin) is centered against the stat cards */
.intro-row > div > p:last-child {
  margin-bottom: 0;
}

/* Two flexible columns, the first one wider (About: telescope table + stats) */
.two-col.split {
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
}

/* .split is listed too: its own column rule is more specific than .two-col */
@media (max-width: 900px) {
  .two-col,
  .two-col.split {
    grid-template-columns: minmax(0, 1fr);
    gap: 2.5rem;
  }
}

/* Paragraph under the stat cards */
.stat-cards + p {
  margin-top: 1.25rem;
}

/* ---------- Matched columns (About: education / fellowships) ----------
   Both columns have the same height and their blocks share top and bottom. */

.match-cols {
  align-items: stretch;
  grid-template-rows: auto 1fr;
}

/* Each column shares the parent's two rows (heading, content), so the
   headings get the same height even when one wraps onto two lines */
.match-cols > div {
  display: grid;
  grid-row: span 2;
  grid-template-rows: subgrid;
  row-gap: 0;
}

.match-cols > div > .section-head {
  align-items: start;
}

.match-cols > div > .timeline,
.match-cols > div > .cards {
  grid-auto-rows: 1fr;
  gap: 1rem;
}

.match-cols > div > .timeline > li > .card {
  height: 100%;
}

@media (max-width: 900px) {
  .match-cols {
    grid-template-rows: none;
  }

  .match-cols > div {
    grid-row: auto;
    grid-template-rows: auto 1fr;
  }
}

/* ---------- Biography in two text columns (About) ---------- */

.bio {
  columns: 2 22rem;
  column-gap: 3rem;
}

.bio p {
  break-inside: avoid-column;
}

/* ---------- Sidebar (rail): stacked boxes ---------- */

.rail {
  font-size: var(--fs-ui);
  line-height: 1.55;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Each <section> of the rail is a white box */
.rail section {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--card-r);
  padding: 1.25rem 1.35rem;
  box-shadow: var(--shadow-1);
}

/* Profile box (About): round portrait, name, role and profile links */
.rail .profile {
  text-align: center;
}

.profile img {
  width: 8.5rem;
  height: 8.5rem;
  border-radius: 50%;
  object-fit: cover;
  margin: 0 auto 1rem;
  border: 4px solid var(--accent-soft);
}

.profile .name {
  display: block;
  font-size: var(--fs-lead);
}

.profile .link-row {
  justify-content: center;
  margin-top: .9rem;
}

.rail h2 {
  font-family: var(--sans);
  font-size: var(--fs-title);
  font-weight: 600;
  margin: 0 0 .6rem;
  color: var(--ink);
}

.rail ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.rail li {
  margin: 0 0 .45rem;
}

/* Term / value pairs (e.g. Languages) */
.rail dl {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .3rem 1rem;
}

.rail dt {
  color: var(--muted);
}

.rail dd {
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
}

.rail p {
  margin: 0 0 .6rem;
}

/* Figure centered in its column, image at most 90% of the width */
.fig-center img {
  display: block;
  width: 90%;
  height: auto;
  margin: 0 auto;
}

/* Tall figures (e.g. the PRISMAS grid coverage) are capped in width */
.fig-center img.fig-narrow {
  max-width: 42rem;
}

.fig-center figcaption {
  max-width: 90%;
  margin-left: auto;
  margin-right: auto;
}

/* Main column whose blocks are stacked (software pages: steps, then figure / code) */
.stack {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  min-width: 0;
}

.stack > * {
  margin: 0;
}

/* Sticky columns (desktop only): a .rail.sticky or .stat-cards.sticky and
   the text next to it both follow the page while scrolling, so whichever
   column is shorter stays in view while the longer one scrolls. site.js 1.4
   lowers "top" for a column taller than the window. */
@media (min-width: 901px) {
  .two-col:has(> .rail.sticky, > .stat-cards.sticky) > * {
    position: sticky;
    top: 5.5rem;
  }

  /* Rail layouts start at the top; intro rows (.intro-row) keep both
     columns centered on each other until the page scrolls */
  .two-col:has(> .rail.sticky) > * {
    align-self: start;
  }
}


/* ==========================================================================
   8. BUTTONS, LINK ROWS, PILLS AND CHIPS
   ========================================================================== */

/* ---------- Button row ---------- */

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ---------- Buttons: solid (default) and ghost (outlined) ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--icon-gap);
  font: 600 var(--fs-ui)/1 var(--sans);
  text-decoration: none;
  padding: .8rem 1.15rem;
  border-radius: 4px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}

.btn:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: #fff;
}

.btn.ghost {
  background: transparent;
  color: var(--accent);
}

.btn.ghost:hover {
  background: var(--accent-soft);
}

/* Buttons on dark backgrounds (hero, page header) */
.on-dark .btn.ghost,
.page-head .btn.ghost {
  background: transparent;
  color: #fff;
  border-color: rgba(255, 255, 255, .45);
}

.on-dark .btn.ghost:hover,
.page-head .btn.ghost:hover {
  background: rgba(255, 255, 255, .1);
}

.on-dark .btn,
.page-head .btn {
  background: #fff;
  color: var(--night);
  border-color: #fff;
}

.on-dark .btn:hover,
.page-head .btn:hover {
  background: #ffd84d;
  border-color: #ffd84d;
}

/* ---------- Row of text links with icons ---------- */

.link-row {
  font-size: var(--fs-ui);
  display: flex;
  flex-wrap: wrap;
  gap: .35rem 1.1rem;
  margin-top: .5rem;
}

.link-row a {
  text-decoration: none;
  font-weight: 600;
}

.link-row a:hover {
  text-decoration: underline;
}

.link-row i {
  margin-right: var(--icon-gap);
}

/* ---------- Chips: small tags (e.g. research interests) ---------- */

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  list-style: none;
  padding: 0;
  margin: 0;
}

.chips li {
  font-size: var(--fs-sm);
  border: 1px solid var(--rule);
  background: var(--surface);
  border-radius: 3px;
  padding: .2rem .55rem;
}

/* ---------- Pills: status / type labels on cards ---------- */

.pill {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  align-self: flex-start;
  font: 600 var(--fs-label)/1 var(--sans);
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: .38rem .65rem;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  margin-bottom: .75rem;
}

.pill.ok {
  background: var(--ok-soft);
  color: var(--ok);
}

.pill.rev {
  background: var(--rev-soft);
  color: var(--rev);
}

.pill.prep {
  background: var(--prep-soft);
  color: var(--prep);
}

.pill.vio {
  background: var(--vio-soft);
  color: var(--vio);
}

/* Yellow: "In progress" status (site.js 2.2), always with a pulsing dot */
.pill.yel {
  background: #fff4c7;
  color: #8a5a00;
}

/* Gray: "Upcoming" status (site.js 2.2) */
.pill.gray {
  background: #e9ecf2;
  color: var(--muted);
}

.pill.dark {
  background: linear-gradient(90deg, #0a1033, #26307a);
  color: #fff;
}

.pill[data-status]:empty {
  display: none;
}

.pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
}

/* ---------- Chip buttons: small actions inside cards ---------- */

.chip-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--icon-gap);
  font: 600 var(--fs-xs)/1 var(--sans);
  text-decoration: none;
  padding: .5rem .75rem;
  border-radius: 8px;
  background: #eef1f8;
  color: var(--ink);
  border: 1px solid transparent;
  transition: background .2s, color .2s;
}

.chip-btn:hover {
  background: var(--accent);
  color: #fff;
  text-decoration: none;
}

.chip-btn.primary {
  background: var(--accent);
  color: #fff;
}

.chip-btn.primary:hover {
  background: var(--accent-hover);
}


/* ==========================================================================
   9. CARDS
   White boxes used for papers, talks, stays, projects... A card can be an
   <article> or a whole clickable <a>. On hover it lifts and shows a thin
   gravity-darkening line on top.
   ========================================================================== */

/* ---------- Base card ---------- */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--card-r);
  padding: 1.5rem 1.5rem 1.25rem;
  box-shadow: var(--shadow-1);
  color: inherit;
  text-decoration: none;
  transition: transform .3s cubic-bezier(.2, .7, .2, 1), box-shadow .3s, border-color .3s;
  overflow: hidden;
}

/* Gradient line on the top edge, visible on hover */
.card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--gd);
  opacity: 0;
  transition: opacity .3s;
}

.card:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-2);
  border-color: var(--accent-line);
}

.card:hover::before {
  opacity: 1;
}

a.card:hover {
  text-decoration: none;
}

a.card:hover h3 {
  color: var(--accent);
}

/* Cards inside white sections use the page background color */
.section.alt .card {
  background: var(--paper);
}

/* ---------- Card content ---------- */

.card h3 {
  font-size: var(--fs-title);
  line-height: 1.38;
  margin: .15rem 0 .55rem;
  letter-spacing: -.015em;
}

.card p {
  font-size: var(--fs-ui);
  line-height: 1.62;
  margin: 0 0 .75rem;
  color: #3a4157;
}

/* Small details line (venue, host, dates...) */
.card .meta {
  font-size: var(--fs-sm);
  color: var(--muted);
  margin: 0 0 .6rem;
  line-height: 1.45;
}

.card .meta b {
  color: var(--ink);
  font-weight: 600;
}

/* Footer pushed to the bottom of the card: date + buttons */
.card-foot {
  margin-top: auto;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
}

/* Calendar icon before the dates */
.when i {
  margin-right: var(--icon-gap);
}

.card-foot .when {
  font-size: var(--fs-sm);
  color: var(--muted);
  margin-right: auto;
}

/* Card whose title link makes the whole card clickable (Latest, site.js 2.7);
   its own buttons stay above the link and keep working */
.card-link {
  color: inherit;
  text-decoration: none;
}

.card-link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

.card:has(.card-link) a:not(.card-link) {
  position: relative;
  z-index: 2;
}

/* ---------- Icon square (feature cards) ---------- */

.card .icon {
  width: 3rem;
  height: 3rem;
  border-radius: 12px;
  display: grid;
  place-items: center;
  font-size: var(--fs-icon);
  margin-bottom: 1rem;
  color: #fff;
  background: linear-gradient(135deg, var(--accent), #4cc9f0);
}

.card .icon.warm {
  background: linear-gradient(135deg, #e8361e, #ffb02e);
}

.card .icon.ink {
  background: linear-gradient(135deg, #5b0f6e, #d6246e);
}

/* ---------- Card variants ---------- */

/* Feature card (home overview) */
.card.feature {
  padding: 1.6rem;
}

/* Highlighted card (first-author papers, own proposals...): warm gradient
   bar on the left */
.card.highlight-first::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  background: linear-gradient(#ffd84d, #ff8c1a, #aa1e14);
}

/* Cards hidden by the filters (the animation when a filter shows them
   again is in section 16) */
.card[hidden] {
  display: none;
}

/* ---------- Horizontal thesis card (My theses) ----------
   Details on the left, text on the right; stacked on small screens. */

.card.thesis {
  display: grid;
  grid-template-columns: minmax(0, 19rem) minmax(0, 1fr);
  gap: 0 2.5rem;
}

.card.thesis .thesis-info {
  display: flex;
  flex-direction: column;
}

.card.thesis .thesis-body p:last-child {
  margin-bottom: 0;
}

@media (max-width: 760px) {
  .card.thesis {
    grid-template-columns: minmax(0, 1fr);
  }

  .card.thesis .thesis-body {
    margin-top: 1.25rem;
  }
}

/* ---------- Table inside a card-like box ---------- */

.table-card {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--card-r);
  padding: .25rem 1.25rem;
  box-shadow: var(--shadow-1);
  overflow-x: auto;
}

.table-card .spec {
  margin: 0;
}

.table-card .spec tr:last-child td {
  border-bottom: 0;
}


/* ==========================================================================
   10. CARD GRIDS, FILTERS AND TIMELINE
   ========================================================================== */

/* ---------- Responsive card grid (as many columns as fit) ---------- */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
  gap: clamp(1rem, 1.6vw, 1.5rem);
}

.cards.wide {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 24rem), 1fr));
}

/* Cards whose labels need a bit more room to stay on one line */
.cards.roomy {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 21rem), 1fr));
}

.cards.narrow {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
}

/* ---------- Fixed column grids ----------
   They drop to fewer columns on smaller screens instead of leaving a
   single orphan card on the last row. */

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

.cards.cols-4 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* One card per row (My theses; About: fellowships) */
.cards.cols-1,
.cards.thesis-list {
  grid-template-columns: minmax(0, 1fr);
}

@media (max-width: 1200px) {
  .cards.cols-4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 1000px) {
  .cards.cols-3,
  .people-grid.cols-3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 700px) {
  .cards.cols-3,
  .cards.cols-4,
  .people-grid.cols-3 {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---------- Synced rows ----------
   The four parts of each card (label, title, details, footer) line up with
   the cards next to it, using CSS subgrid. */

.cards.rows-sync > .card {
  display: grid;
  grid-row: span 4;
  grid-template-rows: subgrid;
  row-gap: 0;
}

/* Footer fills its row, so its top line matches cards with buttons */
.cards.rows-sync > .card > .card-foot {
  margin-top: 0;
}

/* (display: grid above would otherwise win over .card[hidden]) */
.cards.rows-sync > .card[hidden] {
  display: none;
}

/* ---------- Filter buttons above a card grid (see site.js) ---------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin: 0 0 1.75rem;
  padding: 0;
  list-style: none;
}

.filters button {
  font: 600 var(--fs-sm)/1 var(--sans);
  padding: .65rem 1rem;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  transition: all .2s;
}

.filters button:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.filters button[aria-pressed="true"] {
  background: var(--night);
  border-color: var(--night);
  color: #fff;
}

/* Categories with no cards yet are hidden by site.js */
.filters li[hidden] {
  display: none;
}

/* Number of cards in each category (added by site.js) */
.filters button .n {
  opacity: .6;
  margin-left: .35rem;
  font-variant-numeric: tabular-nums;
}

/* ---------- Timeline: cards joined by a vertical gradient line ---------- */

.timeline {
  position: relative;
  display: grid;
  gap: 1rem;
  padding-left: 1.75rem;
  margin: 0;
  list-style: none;
}

/* The vertical line */
.timeline::before {
  content: "";
  position: absolute;
  left: .45rem;
  top: .5rem;
  bottom: .5rem;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(var(--gd-stops));
}

.timeline > li {
  position: relative;
}

/* The dot of each item, in the color of the line at its height
   (--dot, set by site.js 1.5) */
.timeline > li::before {
  content: "";
  position: absolute;
  left: -1.75rem;
  top: 1.6rem;
  width: .95rem;
  height: .95rem;
  border-radius: 50%;
  background: var(--surface);
  border: 3px solid var(--dot, var(--accent));
}


/* ==========================================================================
   11. HOME PAGE: HERO AND INTERACTIVE STAR
   ========================================================================== */

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

.hero {
  background: radial-gradient(120% 90% at 78% 40%, #1c2c8a 0%, var(--night) 55%, #060a22 100%);
  color: var(--night-text);
  overflow: hidden;
}

/* Text on the left, star on the right */
.hero .wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 3rem;
  align-items: center;
  padding-top: 4rem;
  padding-bottom: 4rem;
}

.hero h1 {
  font-size: var(--step-4);
  color: #fff;
  margin: 0 0 .75rem;
  letter-spacing: -.035em;
  line-height: 1.02;
  font-weight: 700;
}

.hero .role {
  color: var(--night-muted);
  font-size: var(--fs-body);
  margin: 0 0 1.75rem;
}

.hero .statement {
  /* Fluid: from --fs-lead on phones up to 1.4rem on wide screens (the only
     text that grows with the window, apart from the titles and stat numbers) */
  font-size: clamp(var(--fs-lead), 1.8vw, 1.4rem);
  line-height: 1.5;
  font-weight: 500;
  color: #eef2fc;
  max-width: 30rem;
  margin: 0 0 2rem;
}

/* Profile icons (ORCID, ADS, GitHub...) */
.hero .social {
  display: flex;
  gap: 1.1rem;
  margin-top: 2rem;
  font-size: var(--fs-icon);
}

.hero .social a {
  color: var(--night-muted);
}

.hero .social a:hover {
  color: #fff;
}

/* Single column: text, then the star, then the profile icons */
@media (max-width: 960px) {
  .hero .wrap {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
    padding-top: 2.5rem;
  }

  .hero .wrap > div:first-child {
    display: contents;
  }

  .hero .star-lab {
    order: 1;
    margin-top: 2.5rem;
  }

  .hero .social {
    order: 2;
  }
}

/* ---------- Interactive star: layout ---------- */

.star-lab {
  position: relative;
}

.star-lab figure {
  margin: 0;
}

/* Star canvas next to the vertical sliders */
.star-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  max-width: 640px;
  margin: 0 auto;
}

.star-stage {
  position: relative;
  aspect-ratio: 1 / 1;
  max-width: 520px;
  margin: 0 auto;
}

.star-stage canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.star-row .star-stage {
  flex: 1;
  min-width: 0;
  margin: 0;
}

/* Values under the star (R_eq/R_pole, T_pole, T_eq, v sin i) */
.star-readout {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  gap: .4rem 1.4rem;
  max-width: 520px;
  margin: 1rem auto .75rem;
  position: relative;
  font-size: var(--fs-sm);
  color: var(--night-muted);
  line-height: 1.5;
}

.star-readout b {
  color: #fff;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Synthetic line profile under the readout */
.star-profile {
  max-width: 520px;
  margin: .25rem auto 0;
}

.star-profile canvas {
  width: 100%;
  height: 96px;
  display: block;
}

/* ---------- Interactive star: vertical sliders ---------- */

.star-controls {
  flex: none;
  display: flex;
  gap: 1rem;
  height: 60%;
  align-self: center;
  --bar-h: clamp(140px, 40vw, 260px);   /* slider and color bar length */
}

/* Each control: label / slider / value */
.star-controls > div {
  display: grid;
  grid-template-rows: 1.5rem var(--bar-h) 1.5rem;
  justify-items: center;
  align-items: center;
  gap: .5rem;
  width: 3.5rem;
}

.star-controls sub,
.star-readout sub,
.star-readout sup {
  line-height: 0;
}

.star-controls label {
  font-size: var(--fs-sm);
  color: var(--night-muted);
  white-space: nowrap;
}

.star-controls output {
  color: #fff;
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}

/* A horizontal range input rotated by -90° */
.vslider {
  position: relative;
  width: 1.25rem;
  height: var(--bar-h);
}

.star-controls input[type=range] {
  -webkit-appearance: none;
  appearance: none;
  background: none;
  margin: 0;
  padding: 0;
  cursor: pointer;
}

.vslider input[type=range] {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--bar-h);
  height: 1.25rem;
  transform: translate(-50%, -50%) rotate(-90deg);
}

/* Track (WebKit / Firefox) */
.star-controls input[type=range]::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, .22);
}

.star-controls input[type=range]::-moz-range-track {
  height: 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, .22);
}

.star-controls input[type=range]::-moz-range-progress {
  height: 6px;
  border-radius: 3px;
  background: #ffd84d;
}

/* Thumb (WebKit / Firefox) */
.star-controls input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  margin-top: -5px;
  border-radius: 50%;
  background: #ffd84d;
  border: 0;
}

.star-controls input[type=range]::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #ffd84d;
  border: 0;
}

.star-controls input[type=range]:focus-visible {
  outline: 2px solid #ffd84d;
  outline-offset: 3px;
}

/* ---------- Interactive star: temperature color key ---------- */

.gd-key {
  display: flex;
  align-items: center;
  gap: .6rem;
  font-size: var(--fs-xs);
  color: var(--night-muted);
}

.star-controls .gd-key {
  gap: .5rem;
  width: auto;
}

/* Vertical bar next to the sliders */
.star-controls .gd-key span.bar {
  flex: none;
  width: 6px;
  height: var(--bar-h);
  background: linear-gradient(to top, var(--gd-stops));
}

/* Horizontal bar (anywhere else) */
.gd-key span.bar {
  flex: 1;
  height: 6px;
  border-radius: 3px;
  background: var(--gd);
}

/* ---------- Interactive star: phones (≤ 520px) ----------
   Sliders become horizontal and sit under the star. */

@media (max-width: 520px) {
  .star-row {
    flex-direction: column;
  }

  .star-controls {
    height: auto;
    width: 100%;
    max-width: 520px;
    flex-wrap: wrap;
    column-gap: 1.5rem;
    row-gap: .75rem;
  }

  .star-controls > div {
    display: flex;
    flex: 1;
    flex-direction: row;
    align-items: center;
    gap: .5rem;
    width: auto;
  }

  .vslider {
    flex: 1;
    width: auto;
    height: 1.25rem;
  }

  .vslider input[type=range] {
    position: static;
    width: 100%;
    transform: none;
  }

  .star-controls .gd-key {
    order: 3;
    flex: 1 1 100%;
    flex-direction: row-reverse;
    width: 100%;
  }

  .star-controls .gd-key span.bar {
    flex: 1;
    width: auto;
    height: 6px;
    background: var(--gd);
  }
}


/* ==========================================================================
   12. STAT CARDS AND PEOPLE
   ========================================================================== */

/* ---------- Stat cards: boxed big numbers with gradient text ---------- */

.stat-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9.5rem), 1fr));
  gap: 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.stat-cards li {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--card-r);
  padding: 1.25rem 1.3rem;
  box-shadow: var(--shadow-1);
}

.stat-cards b {
  display: block;
  font-family: var(--display);
  font-size: var(--fs-stat);
  line-height: 1;
  font-weight: 600;
  background: linear-gradient(90deg, var(--accent), #e8361e);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.stat-cards span {
  display: block;
  font-size: var(--fs-sm);
  color: var(--muted);
  margin-top: .5rem;
  line-height: 1.35;
}

/* ---------- People: photo (or initials) + name and role ---------- */

.people {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
}

.person {
  display: flex;
  gap: .9rem;
  align-items: center;
}

.person img,
.person .mono {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
  background: var(--accent-soft);
}

/* Initials when there is no photo */
.person .mono {
  display: grid;
  place-items: center;
  font: 600 var(--fs-body) var(--sans);
  color: var(--accent);
}

.person b {
  display: block;
  font-size: var(--fs-body);
  font-weight: 600;
  line-height: 1.3;
}

.person span {
  display: block;
  font-size: var(--fs-sm);
  color: var(--muted);
  line-height: 1.35;
}

.person a {
  font-size: var(--fs-sm);
  text-decoration: none;
}

/* Sidebar list with more than two people (Developers of the software
   pages): site.js 1.6 limits its height to the first two (--people-h) and
   the rest is reached with a scroll bar */
.rail .people.scroll {
  max-height: var(--people-h, none);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-right: .5rem;
  scrollbar-width: thin;
  scrollbar-color: var(--rule) transparent;
}

/* People shown as cards (same hover effect as .card) */
.people-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
  gap: 1rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.people-grid .person {
  position: relative;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--card-r);
  padding: 1rem;
  box-shadow: var(--shadow-1);
  transition: transform .3s cubic-bezier(.2, .7, .2, 1), box-shadow .3s, border-color .3s;
}

.people-grid .person::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--gd);
  opacity: 0;
  transition: opacity .3s;
}

.people-grid .person:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-2);
  border-color: var(--accent-line);
}

.people-grid .person:hover::before {
  opacity: 1;
}


/* ==========================================================================
   13. CONTENT BLOCKS: FIGURES, TABLES, STEPS, CITATIONS
   ========================================================================== */

/* ---------- Figures ---------- */

figure {
  margin: 2rem 0;
}

figure img {
  border-radius: var(--radius);
  background: #fff;
}

/* Figure captions are centered under their figure */
figcaption {
  text-align: center;
  hyphens: auto;
  -webkit-hyphens: auto;
  font-size: var(--fs-sm);
  color: var(--muted);
  margin-top: .6rem;
  line-height: 1.5;
}

/* ---------- Specification / definition tables ---------- */

.spec {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-ui);
  margin: 1rem 0 2rem;
}

.spec th,
.spec td {
  text-align: left;
  padding: .65rem .75rem .65rem 0;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}

/* Row headers: as narrow as their content */
.spec th {
  font-weight: 600;
  white-space: nowrap;
  color: var(--ink);
  width: 1%;
}

.spec td code {
  white-space: nowrap;
}

/* Wide tables scroll sideways on small screens */
.table-scroll {
  overflow-x: auto;
  margin: 1rem 0 2rem;
}

.table-scroll .spec {
  margin: 0;
  min-width: 34rem;
}

/* Module table of the software pages (<colgroup> with four <col>):
   narrow first column for the module names, a status column only as wide
   as its symbol, a documentation column only as wide as its longest link
   (on one line), and the description taking the rest */
.spec.modules col:first-child {
  width: 16%;
}

.spec.modules col.status,
.spec.modules col:last-child {
  width: 1%;
}

.spec.modules th:last-child,
.spec.modules td:last-child {
  white-space: nowrap;
}

.spec.modules .status {
  text-align: center;
  white-space: nowrap;
}

/* Symbol key under a table: small, right after it */
.table-scroll:has(+ .table-note) {
  margin-bottom: 0;
}

.table-note {
  margin: .5rem 0 2rem;
  font-size: var(--fs-xs);
  color: var(--muted);
}

/* Column headers */
.spec thead th {
  color: var(--muted);
  font-weight: 600;
  font-size: var(--fs-sm);
  width: auto;
}

/* ---------- Numbered steps ---------- */

.steps {
  list-style: none;
  padding: 0;
  margin: 1.5rem 0;
  counter-reset: s;
}

.steps li {
  counter-increment: s;
  position: relative;
  padding: 0 0 1.1rem 2.75rem;
}

/* Number in a circle */
.steps li::before {
  content: counter(s);
  position: absolute;
  left: 0;
  top: .1rem;
  width: 1.8rem;
  height: 1.8rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font: 600 var(--fs-sm) var(--sans);
  color: var(--accent);
  background: var(--accent-soft);
}

.steps li strong {
  display: block;
}

/* ---------- BibTeX citation with a copy button (see site.js 1.3) ---------- */

.cite {
  position: relative;
}

.cite pre {
  padding-right: 3.5rem;
  white-space: pre;
  font-size: var(--fs-code-sm);
  max-height: 14rem;
}

.cite button {
  position: absolute;
  top: .5rem;
  right: .5rem;
  font: 600 var(--fs-xs) var(--sans);
  background: rgba(255, 255, 255, .12);
  color: #fff;
  border: 0;
  border-radius: 3px;
  padding: .35rem .55rem;
  cursor: pointer;
}

.cite button:hover {
  background: rgba(255, 255, 255, .22);
}

/* Compact variant (sidebar box): reference name + button, BibTeX hidden */
.cite-compact {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  margin: 0 0 .45rem;
}

.cite-compact span {
  font: inherit;
  color: inherit;
}

.cite-compact button {
  position: static;
  flex: none;
  background: var(--accent);
  white-space: nowrap;
}

.cite-compact button:hover {
  background: var(--ink);
}


/* ==========================================================================
   14. SOFTWARE PAGES: SIDEBAR LISTS, FEATURE CARDS, EXAMPLES
   Shared by PANORAMA.html, SPAMMS.html and PRISMAS.html.
   ========================================================================== */

/* ---------- Developers box: role and ORCID under each name ---------- */

.person .role {
  display: block;
}

.person a.orcid {
  display: inline-flex;
  align-items: center;
  gap: var(--icon-gap);
}

.person a.orcid i {
  color: #a6ce39;            /* ORCID brand green */
}

/* ---------- Icon lists in the sidebar (requirements, references, resources) ---------- */

.rail .icon-list {
  list-style: none;
  padding-left: 0;
}

.rail .icon-list li {
  display: flex;
  align-items: baseline;
  gap: .5rem;
}

.rail .icon-list i {
  width: 1.15em;
  text-align: center;
  flex: none;
  color: var(--muted);
}

/* Last paragraph of a sidebar box (e.g. "How to cite" without BibTeX) */
.rail section > p:last-child {
  margin: 0;
}

/* ---------- "Main features" card grid ---------- */

.cards.sw-features {
  margin: 1.25rem 0 2rem;
}

/* ---------- Examples: three cards with images of the same size ---------- */

.ex-grid {
  display: grid;
  /* up to 3 columns, each wide enough for its row of labels on one line */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18.5rem), 1fr));
  gap: 1.5rem;
  align-items: stretch;
  margin-top: 1.25rem;
}

/* Default: each card is a column; a code block is pushed to the bottom */
.ex-grid .card {
  display: flex;
  flex-direction: column;
  margin: 0;
}

.ex-grid .card img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: contain;
  border: 1px solid var(--rule);
  border-radius: .5rem;
  margin-bottom: 1rem;
}

.ex-grid .card h3 {
  margin-top: .5rem;
}

.ex-grid .card pre {
  margin: auto 0 0;
  overflow-x: auto;
  font-size: var(--fs-code-sm);
}

/* .sync: cards with exactly four blocks share the rows of the grid (subgrid),
   so label, title, text and image / code start at the same height */
.ex-grid.sync .card {
  display: grid;
  grid-row: span 4;
  grid-template-rows: subgrid;
  row-gap: 0;
}

.ex-grid.sync .card pre {
  margin: 0;
  align-self: stretch;
}

/* Buttons on the label row, with the same size as the label (.pill) */
.pill-btn {
  text-decoration: none;
  background: transparent;
  color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
  transition: background .2s, color .2s;
}

.pill-row .pill.dark + .pill-btn {
  margin-left: auto;
}

/* Informative label with the look of the outlined button, not clickable */
.pill-note,
.pill-note:hover {
  background: transparent;
  color: var(--accent);
  cursor: default;
}

.pill-btn.primary {
  background: var(--accent);
  color: #fff;
}

.pill-btn:hover {
  background: var(--accent);
  color: #fff;
  text-decoration: none;
}

.pill-btn.primary:hover {
  background: var(--ink);
}

@media (max-width: 900px) {
  .ex-grid {
    grid-template-columns: minmax(0, 1fr);
    max-width: 26rem;
    margin-inline: auto;
  }
}


/* ==========================================================================
   15. SITE FOOTER
   ========================================================================== */

.site-footer {
  background: var(--night);
  color: var(--night-muted);
  font-size: var(--fs-ui);
  padding: 1.75rem 0 1rem;
}

/* Gradient line on top (pulled up over the padding) */
.site-footer::before {
  content: "";
  display: block;
  height: 2px;
  background: var(--gd);
  opacity: .7;
  margin-top: -1.75rem;
  margin-bottom: 1.75rem;
}

/* ---------- Columns: about / research profiles / contact ---------- */

.site-footer .cols {
  display: grid;
  grid-template-columns: repeat(3, max-content);
  justify-content: space-between;
  gap: 1.5rem 2rem;
}

/* The address keeps its lines (phones excepted, see below) */
.site-footer p {
  white-space: nowrap;
}

.site-footer h2 {
  font-family: var(--sans);
  font-size: var(--fs-body);
  color: #fff;
  font-weight: 600;
  margin: 0 0 .75rem;
}

.site-footer ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.site-footer li,
.site-footer p {
  margin: 0;
}

/* Research profiles in two columns */
.site-footer ul.two-cols {
  display: grid;
  grid-template-columns: repeat(2, max-content);
  gap: 0 1.75rem;
}

.site-footer a {
  color: var(--night-text);
  text-decoration: none;
}

.site-footer a:hover {
  color: #fff;
  text-decoration: underline;
}

/* Icon before the text of the profile links */
.site-footer a i {
  margin-right: var(--icon-gap);
}

/* ---------- Bottom line: copyright and image credits ---------- */

.site-footer .fine {
  border-top: 1px solid rgba(255, 255, 255, .1);
  margin-top: 1rem;
  padding-top: .85rem;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 2rem;
  justify-content: space-between;
  font-size: var(--fs-sm);
}

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

/* Tablets: name on its own row, then two columns */
@media (max-width: 1000px) {
  .site-footer .cols {
    grid-template-columns: repeat(2, max-content);
    justify-content: start;
    column-gap: 4rem;
  }

  .site-footer .cols > div:first-child {
    grid-column: 1 / -1;
  }
}

/* Phones: one column, text can wrap */
@media (max-width: 560px) {
  .site-footer .cols {
    grid-template-columns: 1fr;
  }

  .site-footer p {
    white-space: normal;
  }
}


/* ==========================================================================
   16. MOTION: ENTRANCE, SCROLL AND HOVER ANIMATIONS
   Everything here applies only under <html class="motion">, which site.js
   (PART 3) sets when the system does not ask for reduced motion. Without it
   (reduced motion, or no JavaScript) the site is shown as written, without
   animations.
   site.js marks each animated element with data-reveal="kind" and adds the
   class "in" when it scrolls into view; --d is its delay.
   ========================================================================== */

/* ---------- Keyframes ---------- */

@keyframes m-up {
  from { opacity: 0; transform: translateY(22px); }
  to { opacity: 1; transform: none; }
}

@keyframes m-nudge {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

@keyframes m-wipe {
  from { opacity: 1; clip-path: inset(0 100% 0 0); }
  to { opacity: 1; clip-path: inset(0 -5% 0 0); }
}

@keyframes m-tab {
  from { opacity: 0; letter-spacing: .55em; transform: translate(-50%, -20%); }
  to { opacity: 1; letter-spacing: .22em; transform: translate(-50%, -50%); }
}

@keyframes m-drawx {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

@keyframes m-drawy {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}

@keyframes m-pop {
  0% { transform: scale(0); }
  65% { transform: scale(1.35); }
  100% { transform: scale(1); }
}

@keyframes m-letter {
  from { opacity: 0; transform: translateY(.45em) rotate(4deg); }
  to { opacity: 1; transform: none; }
}

@keyframes m-twinkle {
  0%, 100% { opacity: .35; }
  50% { opacity: 1; }
}

@keyframes m-kenburns {
  from { transform: scale(1.04) translate(0, 0); }
  to { transform: scale(1.16) translate(-2.5%, -1.5%); }
}

/* Ring around the dot of the yellow "In progress" pills (#8a5a00, section 8) */
@keyframes m-pulse {
  from { box-shadow: 0 0 0 0 rgba(138, 90, 0, .45); }
  to { box-shadow: 0 0 0 8px rgba(138, 90, 0, 0); }
}

@keyframes m-caret {
  50% { opacity: 0; }
}

@keyframes m-reappear {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

/* ---------- Before site.js runs ----------
   The inline script in <head> adds "motion motion-wait" before the first
   paint; site.js removes "motion-wait" once the entrances are ready. Until
   then the content is hidden, so it does not show and then vanish. If the
   script never runs, it appears anyway after 2.5 s. */
.motion-wait main .wrap {
  visibility: hidden;
  animation: m-unhide 0s 2.5s forwards;
}

@keyframes m-unhide {
  to { visibility: visible; }
}

/* ---------- Generic entrances (hidden until "in") ---------- */

.motion [data-reveal="up"]:not(.in),
.motion [data-reveal="nudge"]:not(.in),
.motion [data-reveal="step"]:not(.in) {
  opacity: 0;
}

.motion [data-reveal="up"].in,
.motion [data-reveal="step"].in {
  animation: m-up .7s cubic-bezier(.2, .7, .2, 1) var(--d, 0ms) both;
}

.motion [data-reveal="nudge"].in {
  animation: m-nudge .5s ease-out var(--d, 0ms) both;
}

/* Already passed when checked (anchor link, reload half-way, very fast
   scroll): shown in its final state at once, lines already drawn */
.motion .in-now:not(.reveal),
.motion .in-now:not(.reveal)::before,
.motion .in-now:not(.reveal)::after,
.motion .in-now .ch {
  animation-duration: 0s !important;
  animation-delay: 0s !important;
}

/* Cards shown again by a filter: quick pop, one after another (site.js 2.3) */
.motion .cards .card.reveal {
  animation: m-reappear .45s cubic-bezier(.2, .7, .2, 1) var(--fd, 0ms) both;
}

/* ---------- 16.1 Home page hero ---------- */

/* Twinkling stars behind the hero (two layers with different rhythms) */
.motion .hero {
  position: relative;
}

.motion .hero > .wrap {
  position: relative;
  z-index: 1;
}

.motion .hero::before,
.motion .hero::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-repeat: repeat;
}

.motion .hero::before {
  background-image:
    radial-gradient(1px 1px at 12% 18%, #fff, transparent),
    radial-gradient(1px 1px at 38% 72%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 64% 30%, #fff, transparent),
    radial-gradient(1px 1px at 82% 84%, #fff, transparent),
    radial-gradient(1px 1px at 92% 12%, #cfe0ff, transparent);
  background-size: 340px 260px;
  animation: m-twinkle 4.5s ease-in-out infinite;
}

.motion .hero::after {
  background-image:
    radial-gradient(1px 1px at 22% 58%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 48% 14%, #ffe9a8, transparent),
    radial-gradient(1px 1px at 72% 62%, #fff, transparent),
    radial-gradient(1px 1px at 6% 88%, #fff, transparent);
  background-size: 420px 300px;
  animation: m-twinkle 6.5s ease-in-out 1.5s infinite;
}

/* Name letter by letter (letters wrapped by site.js 3.2) */
.motion .hero h1.letters .w {
  display: inline-block;
  white-space: nowrap;
}

.motion .hero h1.letters .ch {
  display: inline-block;
  animation: m-letter .6s cubic-bezier(.2, .7, .2, 1) var(--d, 0ms) both;
}

/* Line drawn under the name */
.motion .hero h1::after {
  content: "";
  display: block;
  width: 7.5rem;
  height: 3px;
  margin-top: .3em;
  border-radius: 2px;
  background: var(--gd);
  transform: scaleX(0);
  transform-origin: left;
}

.motion .hero h1.in::after {
  animation: m-drawx .9s cubic-bezier(.65, 0, .35, 1) var(--d, 0ms) both;
}

/* Buttons: a light sweep crosses them on hover */
.motion .btn {
  position: relative;
  overflow: hidden;
  transition: transform .2s, box-shadow .2s, background .2s, border-color .2s, color .2s;
}

.motion .btn::after {
  content: "";
  position: absolute;
  top: 0;
  left: -60%;
  width: 40%;
  height: 100%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .35), transparent);
  transform: skewX(-20deg);
  transition: left .6s;
  pointer-events: none;
}

.motion .btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 24px -12px rgba(36, 89, 232, .8);
}

.motion .btn:hover::after {
  left: 120%;
}

/* ---------- 16.2 Section tabs, headings and timeline ---------- */

.motion .tab[data-reveal]:not(.in) {
  opacity: 0;
}

.motion .tab.in {
  animation: m-tab .9s ease var(--d, 0ms) both;
}

/* Short gradient line drawn under each section title */
.motion .section-title::after,
.motion .section-head h2::after {
  content: "";
  display: block;
  width: 4.5rem;
  height: 3px;
  margin-top: .4em;
  border-radius: 2px;
  background: var(--gd);
  transform: scaleX(0);
  transform-origin: left;
}

.motion .section-title.in::after,
.motion .section-head h2.in::after {
  animation: m-drawx .8s cubic-bezier(.65, 0, .35, 1) calc(var(--d, 0ms) + 250ms) both;
}

/* Timeline: the line is drawn downward, then each dot pops */
.motion .timeline[data-reveal]::before {
  transform: scaleY(0);
  transform-origin: top;
}

.motion .timeline.in::before {
  animation: m-drawy 1.4s cubic-bezier(.65, 0, .35, 1) both;
}

.motion .timeline > li[data-reveal]::before {
  transform: scale(0);
}

.motion .timeline > li.in::before {
  animation: m-pop .5s cubic-bezier(.3, 1.6, .5, 1) var(--d, 0ms) both;
}

/* ---------- 16.3 Cards: "In progress" labels with a pulsing dot ---------- */

.motion .pill.live::before {
  content: "";
  width: 7px;
  height: 7px;
  margin-right: .45em;
  border-radius: 50%;
  background: currentColor;
  display: inline-block;
  vertical-align: .05em;
  animation: m-pulse 1.6s ease-out infinite;
}

/* ---------- 16.4 Filters: dark pill sliding behind the pressed button ---------- */

.motion .filters.has-ind {
  position: relative;
}

/* (the highlight itself is an <li> too, so it is left out here) */
.motion .filters.has-ind > li:not(.filter-ind) {
  position: relative;
  z-index: 1;
}

.motion .filters .filter-ind {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 0;
  border-radius: 999px;
  background: var(--night);
  box-shadow: 0 8px 18px -8px rgba(10, 16, 51, .6);
  pointer-events: none;
}

.motion .filters.ind-ready .filter-ind {
  transition: transform .45s cubic-bezier(.65, 0, .35, 1), width .45s cubic-bezier(.65, 0, .35, 1), height .45s, opacity .2s;
}

.motion .filters.has-ind button[aria-pressed="true"] {
  background: transparent;
  border-color: transparent;
}

/* ---------- 16.5 Page headers: slowly moving photo, title uncovered ---------- */

.motion .page-head .bg {
  transform-origin: 60% 40%;
  animation: m-kenburns 26s ease-in-out infinite alternate;
  will-change: transform;
}

/* Hidden with opacity until it comes in; the wipe then uncovers it from
   left to right with clip-path */
.motion .page-head h1[data-reveal]:not(.in) {
  opacity: 0;
}

.motion .page-head h1.in {
  animation: m-wipe 1s cubic-bezier(.65, 0, .35, 1) var(--d, 0ms) both;
}

/* ---------- 16.6 How it works: steps light up, joined by a line; typed code ---------- */

.motion .steps > li::after {
  content: "";
  position: absolute;
  left: calc(.9rem - 1px);
  top: 2.15rem;
  bottom: .25rem;
  width: 2px;
  border-radius: 2px;
  /* Full color scale of the site (--gd-stops, like the timeline) in each segment */
  background: linear-gradient(var(--gd-stops));
  transform: scaleY(0);
  transform-origin: top;
}

.motion .steps > li:last-child::after {
  display: none;
}

.motion .steps > li.in::after {
  animation: m-drawy .6s cubic-bezier(.65, 0, .35, 1) calc(var(--d, 0ms) + 250ms) both;
}

.motion .steps > li.in::before {
  background: var(--accent);
  color: #fff;
  animation: m-pop .5s cubic-bezier(.3, 1.6, .5, 1) var(--d, 0ms) both;
}

/* Blinking caret while a code example is typed (site.js 3.4) */
.motion pre.typing code::after {
  content: "";
  display: inline-block;
  width: .55em;
  height: 1.05em;
  margin-left: 1px;
  vertical-align: -.15em;
  background: #7cc4ff;
  animation: m-caret 1s step-end infinite;
}

/* ---------- 16.7 Copy buttons of the BibTeX citations and their message ---------- */

/* Button turns green with a tick after copying (site.js 1.3) */
.cite button {
  transition: background .3s, color .3s;
}

.cite button.copied,
.cite button.copied:hover {
  background: var(--ok);
}

.cite button.copied::before {
  content: "\2713";
  display: inline-block;
  margin-right: .35em;
  font-weight: 700;
}

.motion .cite button.copied::before {
  animation: m-pop .45s cubic-bezier(.3, 1.6, .5, 1) both;
}

/* Message at the bottom of the window ("BibTeX copied to the clipboard") */
.copy-toast {
  position: fixed;
  left: 50%;
  bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
  z-index: 100;
  transform: translate(-50%, 1rem);
  opacity: 0;
  pointer-events: none;
  font: 600 var(--fs-sm)/1 var(--sans);
  background: var(--ink);
  color: #fff;
  padding: .85rem 1.1rem;
  border-radius: 999px;
  box-shadow: 0 14px 30px -12px rgba(18, 28, 70, .5);
  transition: opacity .3s, transform .4s cubic-bezier(.2, .7, .2, 1);
}

.copy-toast.show {
  opacity: 1;
  transform: translate(-50%, 0);
}


/* ==========================================================================
   17. REDUCED MOTION
   Respect the "reduced motion" setting of the operating system.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  * {
    scroll-behavior: auto !important;
    transition: none !important;
    animation: none !important;
  }

  .card:hover,
  .people-grid .person:hover {
    transform: none;
  }
}
