/* =============================================================================
   JULIJANA CVJETINOVIĆ — a descent into a diatom cell
   -----------------------------------------------------------------------------
   The WebGL canvas is fixed behind everything; content scrolls over it. Every
   text block carries its own soft scrim so it stays readable no matter what the
   scene is doing underneath.
   ============================================================================= */

/* ---------------------------------------------------------------- tokens -- */
:root {
  /* depth */
  --abyss:      #02060c;
  --deep:       #061a2e;
  --mid:        #0b3a5c;
  --water:      #1179a8;

  /* life */
  --cyan:       #28f0d8;
  --aqua:       #5affe0;
  --chloro:     #6ef060;
  --green:      #27c96a;

  /* energy */
  --ember:      #ff3b4a;
  --rust:       #ff6a2c;
  --amber:      #ffb347;

  /* silica */
  --silica:     #dff4ff;
  --pearl:      #f2fbff;

  --ink:        #eaf6ff;
  --ink-dim:    rgba(234, 246, 255, .68);
  --ink-faint:  rgba(234, 246, 255, .42);
  --hair:       rgba(160, 220, 255, .18);
  --hair-soft:  rgba(160, 220, 255, .09);

  --display: 'Unbounded', 'Manrope', system-ui, sans-serif;
  --text:    'Manrope', system-ui, -apple-system, sans-serif;
  --mono:    'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --gutter:  clamp(1.25rem, 5vw, 6rem);
  --measure: 62ch;

  --ease:     cubic-bezier(.22, 1, .36, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: auto;
}

body {
  margin: 0;
  background: var(--abyss);
  color: var(--ink);
  font-family: var(--text);
  font-size: clamp(1rem, .55vw + .86rem, 1.125rem);
  line-height: 1.65;
  font-weight: 300;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body.is-loading { overflow: hidden; height: 100vh; }
body.lb-open    { overflow: hidden; }

h1, h2, h3, p, ol, ul, figure { margin: 0; }
ol, ul { padding: 0; list-style: none; }
img { display: block; max-width: 100%; height: auto; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }

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

::selection { background: var(--cyan); color: #04121a; }

/* ------------------------------------------------------------ the world -- */
#gl {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  height: 100svh;
  display: block;
  z-index: 0;
  /* No transform / will-change here on purpose. Promoting the canvas by hand
     makes the browser render it through an extra intermediate surface, which
     costs memory on a layer that is already composited — the opposite of what
     is wanted when the compositor is short of it. */
}

/* There is deliberately NO full-viewport overlay element above the canvas.
   An #atmosphere layer used to live here for vignette and film grain. Every
   extra full-coverage layer stacked over a fixed WebGL canvas is another
   surface the compositor has to keep in step with it while the page scrolls,
   and the failure mode is a black rectangle. Depth is carried by the scene's
   own fog instead. */

/* ---------------------------------------------------------------- loader -- */
#loader {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  background:
    radial-gradient(70% 60% at 50% 42%, #08243a 0%, #030a13 55%, #010408 100%);
  color: var(--aqua);
  transition: opacity .9s var(--ease), visibility .9s;
}
#loader.is-done { opacity: 0; visibility: hidden; pointer-events: none; }

/* Take it out of the page entirely once it is done.
   An ID rule setting `display: grid` outranks the browser's own
   `[hidden] { display: none }`, so without this the loader stays a
   full-viewport fixed layer parked over the canvas for the life of the page —
   invisible, but still a surface the compositor has to blend every frame. */
#loader[hidden] { display: none; }

.loader__inner { display: grid; justify-items: center; gap: 1.5rem; padding: 2rem; }

.loader__mark { width: clamp(84px, 16vw, 128px); height: auto; overflow: visible; }
.loader__mark circle { vector-effect: non-scaling-stroke; }
.loader__sweep {
  transform: rotate(-90deg);
  transform-origin: 60px 60px;
  transition: stroke-dashoffset .5s var(--ease);
  filter: drop-shadow(0 0 6px currentColor);
}
#loaderPores circle { opacity: .5; }

.loader__line {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-dim);
  min-height: 1.2em;
  text-align: center;
}

.loader__bar {
  width: min(260px, 60vw);
  height: 1px;
  background: var(--hair);
  overflow: hidden;
}
.loader__bar span {
  display: block;
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--cyan), var(--aqua));
  box-shadow: 0 0 12px var(--cyan);
  transition: width .35s var(--ease);
}

.loader__enter {
  margin-top: .5rem;
  padding: .85rem 2.4rem;
  border: 1px solid var(--hair);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: .74rem;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--ink);
  transition: background .4s var(--ease), border-color .4s var(--ease), letter-spacing .4s var(--ease);
}
.loader__enter:hover {
  background: rgba(40, 240, 216, .12);
  border-color: var(--cyan);
  letter-spacing: .38em;
}

/* -------------------------------------------------------------- fallback -- */
#nofx {
  position: relative;
  z-index: 5;
  margin: 6rem var(--gutter) 0;
  padding: 1.4rem 1.6rem;
  border: 1px solid var(--hair);
  border-left: 2px solid var(--amber);
  background: rgba(4, 14, 24, .7);
  max-width: 52ch;
}
#nofx h2 { font-family: var(--mono); font-size: .78rem; letter-spacing: .2em; text-transform: uppercase; }
#nofx p { margin-top: .6rem; color: var(--ink-dim); font-size: .95rem; }

.skip {
  position: fixed;
  top: -100px; left: 1rem;
  z-index: 100;
  padding: .7rem 1.2rem;
  background: var(--aqua);
  color: #04121a;
  font-family: var(--mono);
  font-size: .78rem;
  transition: top .25s var(--ease);
}
.skip:focus { top: 1rem; }

/* ------------------------------------------------------------------ nav -- */
#nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: clamp(1rem, 2.2vw, 1.9rem) var(--gutter);
  pointer-events: none;
}
#nav > * { pointer-events: auto; }

.nav__id { display: grid; gap: .12rem; }
.nav__name {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(.82rem, 1.1vw, .98rem);
  letter-spacing: .01em;
}
.nav__role {
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.nav__right { display: flex; align-items: center; gap: clamp(.6rem, 1.6vw, 1.4rem); }

/* The three links live up here rather than at the foot of the page, because
   at the foot nobody found them. They are solid pills with icons so they read
   as things to press even against a moving 3D scene. */
.nav__cta-group { display: flex; align-items: center; gap: .5rem; }

.nav__cta {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .62rem 1.05rem;
  border: 1px solid var(--hair);
  border-radius: 999px;
  background: rgba(6, 20, 34, .82);
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
  transition: background .3s var(--ease), border-color .3s var(--ease),
              color .3s, transform .3s var(--ease);
}
.nav__cta svg { flex: none; opacity: .85; }
.nav__cta:hover,
.nav__cta:focus-visible {
  background: rgba(40, 240, 216, .14);
  border-color: var(--cyan);
  color: var(--aqua);
  transform: translateY(-1px);
}
.nav__cta:hover svg { opacity: 1; }

/* Scholar is the one most people actually want, so it is the accented one. */
.nav__cta--primary {
  border-color: rgba(90, 255, 224, .5);
  background: rgba(40, 240, 216, .13);
  color: var(--aqua);
}
.nav__cta--primary:hover,
.nav__cta--primary:focus-visible {
  background: rgba(40, 240, 216, .22);
  border-color: var(--aqua);
}

.nav__lang {
  width: 2.9rem; height: 2.9rem;
  display: grid; place-items: center;
  border: 1px solid var(--hair);
  border-radius: 50%;
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .08em;
  color: var(--ink-dim);
  transition: border-color .3s, color .3s, background .3s;
}
.nav__lang:hover { border-color: var(--cyan); color: var(--aqua); background: rgba(40, 240, 216, .08); }

/* ----------------------------------------------------------------- rail -- */
#rail {
  position: fixed;
  right: clamp(.9rem, 2vw, 1.9rem);
  top: 50%;
  transform: translateY(-50%);
  z-index: 40;
}
#rail ol { display: grid; gap: .95rem; }

#rail li { position: relative; display: flex; align-items: center; justify-content: flex-end; }

.rail__btn {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .25rem 0;
}
.rail__label {
  font-family: var(--mono);
  font-size: .6rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  white-space: nowrap;
  opacity: 0;
  transform: translateX(6px);
  transition: opacity .35s var(--ease), transform .35s var(--ease), color .35s;
  max-width: 40vw;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rail__tick {
  width: 22px; height: 1px;
  background: var(--hair);
  transition: width .4s var(--ease), background .4s var(--ease), box-shadow .4s;
}
.rail__btn:hover .rail__label { opacity: 1; transform: none; }
.rail__btn:hover .rail__tick { width: 30px; background: var(--ink-dim); }

#rail li[aria-current='true'] .rail__tick {
  width: 38px;
  background: var(--aqua);
  box-shadow: 0 0 10px var(--cyan);
}
#rail li[aria-current='true'] .rail__label { opacity: 1; transform: none; color: var(--aqua); }

/* ---------------------------------------------------------------- depth -- */
#depth {
  position: fixed;
  left: var(--gutter);
  bottom: clamp(1rem, 2.4vw, 1.9rem);
  z-index: 40;
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .12em;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
#depthValue { color: var(--aqua); }
.depth__unit { margin-left: .25em; opacity: .6; }

/* -------------------------------------------------------------- chapters -- */
#main { position: relative; z-index: 3; }

.chapter {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: clamp(7rem, 14vh, 12rem) var(--gutter);
}

.wrap { width: 100%; max-width: 1320px; margin-inline: auto; }

/* A soft pool of shade behind each block of copy — the render stays visible,
   the words stay legible. */
.chapter::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(90% 70% at var(--scrim-x, 30%) 50%, rgba(2, 9, 16, .78) 0%, rgba(2, 9, 16, .42) 45%, transparent 78%);
}
.chapter--hero::before   { --scrim-x: 34%; }
.chapter--gallery::before,
.chapter--contact::before { --scrim-x: 50%; }
#ch3::before, #ch6::before { --scrim-x: 50%; }

/* ---------------------------------------------------------- typography --- */
.index {
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .3em;
  color: var(--aqua);
  margin-bottom: .9rem;
}
.index span::before { content: '['; opacity: .45; margin-right: .5em; }
.index span::after  { content: ']'; opacity: .45; margin-left: .5em; }

.label {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin-bottom: clamp(1rem, 2.5vw, 1.8rem);
}

.display {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2.6rem, 7.4vw, 7rem);
  line-height: .94;
  letter-spacing: -.03em;
  text-wrap: balance;
  padding-bottom: .08em;
  /* Visible fallback. The gradient lives on .ln below — see the note there. */
  color: var(--silica);
}
.display--wide { font-size: clamp(2.4rem, 6.4vw, 6rem); }
.display--huge { font-size: clamp(3rem, 9.5vw, 10rem); }

/* Split headings — each line rides up out of its own mask.
   The gradient has to sit on .ln, the DIRECT parent of the text. With
   background-clip:text on .display instead, the clip has to reach through
   .ln's overflow:hidden and the transformed span inside it, and the text
   paints as nothing at all. */
.ln {
  display: block;
  overflow: hidden;
  padding-bottom: .04em;
  background: linear-gradient(168deg, var(--pearl) 8%, var(--silica) 38%, var(--aqua) 96%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
/* No will-change: these animate once and then never again, and pinning a
   compositor layer per heading line for the life of the page costs more than
   it saves. GSAP promotes them for the duration of the tween by itself. */
.ln > span { display: block; }

.sub {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: .9rem;
}

.lead {
  font-size: clamp(1.05rem, 1.5vw, 1.35rem);
  line-height: 1.55;
  color: var(--ink);
  max-width: var(--measure);
  font-weight: 300;
}
.lead--center { margin-inline: auto; text-align: center; }

.body {
  color: var(--ink-dim);
  max-width: var(--measure);
  margin-top: 1.15rem;
}

.chapter__head { text-align: center; margin-bottom: clamp(2.6rem, 6vw, 5rem); }
.chapter__head--left { text-align: left; }
.chapter__head .lead { margin-top: 1.6rem; }

/* ----------------------------------------------------------------- hero -- */
.hero { max-width: 1180px; }

.hero__name {
  font-family: var(--display);
  font-weight: 700;
  /* Starting size only — fitHeroName() in main.js measures the rendered line
     and scales down if the surname would run off the edge. Cyrillic and Latin
     forms of the name are very different widths, so this cannot be a fixed
     clamp. */
  font-size: clamp(2.4rem, 9.6vw, 9.5rem);
  line-height: .9;
  letter-spacing: -.045em;
  margin: clamp(.6rem, 1.6vw, 1.2rem) 0 clamp(1.6rem, 4vw, 2.8rem);
}
.hero__line {
  display: block;
  overflow: hidden;
  padding-bottom: .06em;
  background: linear-gradient(158deg, var(--pearl) 0%, var(--silica) 30%, var(--aqua) 72%, var(--cyan) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  padding-bottom: .05em;
}
.hero__line:nth-child(2) {
  background: linear-gradient(158deg, var(--aqua) 0%, var(--cyan) 34%, var(--water) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.eyebrow {
  font-family: var(--mono);
  font-size: clamp(.66rem, .9vw, .78rem);
  letter-spacing: .32em;
  text-transform: uppercase;
  color: var(--aqua);
}

.hero__meta { display: grid; gap: .3rem; max-width: 46ch; }
.hero__role { font-size: clamp(1rem, 1.4vw, 1.25rem); color: var(--ink); }
.hero__org  { color: var(--ink-faint); font-size: .95rem; }

.hero__cue {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin-top: clamp(2.4rem, 6vw, 4.5rem);
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.cue__line {
  width: 54px; height: 1px;
  background: linear-gradient(90deg, var(--aqua), transparent);
  position: relative;
  overflow: hidden;
}
.cue__line::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--aqua);
  box-shadow: 0 0 8px var(--cyan);
  animation: cueRun 2.6s var(--ease) infinite;
}
@keyframes cueRun {
  0%   { transform: translateX(-100%); }
  60%  { transform: translateX(100%); }
  100% { transform: translateX(100%); }
}

.cue {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin-top: 2rem;
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--aqua);
}
.cue__dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--aqua);
  box-shadow: 0 0 0 0 rgba(90, 255, 224, .6);
  animation: pulse 2.4s var(--ease) infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(90, 255, 224, .55); }
  70%  { box-shadow: 0 0 0 14px rgba(90, 255, 224, 0); }
  100% { box-shadow: 0 0 0 0 rgba(90, 255, 224, 0); }
}

/* ---------------------------------------------------------------- split -- */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 6rem);
  align-items: start;
}
.split__body { padding-top: clamp(0rem, 4vw, 3.5rem); }

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: 1.8rem;
}
.tags li {
  padding: .42rem .95rem;
  border: 1px solid var(--hair);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-dim);
  background: rgba(8, 24, 40, .62);
}

/* ---------------------------------------------------------------- about -- */
.about {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
  gap: clamp(2rem, 6vw, 5.5rem);
  align-items: start;
}
.about__side { display: grid; gap: clamp(1.8rem, 4vw, 3rem); }

.portrait { position: relative; }
.portrait img {
  width: 100%;
  border-radius: 2px;
  filter: saturate(.92) contrast(1.04);
}
.portrait::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 45%, rgba(2, 12, 20, .5) 100%);
  pointer-events: none;
}
.portrait figcaption {
  margin-top: .8rem;
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.edu__list { display: grid; gap: 1.4rem; }
.edu__list li {
  display: grid;
  grid-template-columns: 3.6rem 1fr;
  gap: .2rem 1rem;
  padding-bottom: 1.3rem;
  border-bottom: 1px solid var(--hair-soft);
}
.edu__list li:last-child { border-bottom: 0; padding-bottom: 0; }
.edu__year {
  grid-row: 1 / span 3;
  font-family: var(--mono);
  font-size: .72rem;
  color: var(--aqua);
  padding-top: .2rem;
}
.edu__deg   { font-weight: 500; font-size: 1rem; }
.edu__where { color: var(--ink-dim); font-size: .92rem; }
.edu__note  { color: var(--ink-faint); font-size: .82rem; line-height: 1.45; }
.edu__note:empty { display: none; }

/* -------------------------------------------------------------- pillars -- */
.pillars {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: clamp(1rem, 2.4vw, 2rem);
  margin-bottom: clamp(2.6rem, 6vw, 4.5rem);
}
.pillar {
  position: relative;
  padding: clamp(1.6rem, 2.6vw, 2.4rem);
  border: 1px solid var(--hair-soft);
  background: linear-gradient(165deg, rgba(9, 28, 44, .80), rgba(3, 12, 20, .58));
  overflow: hidden;
  transition: border-color .5s var(--ease), transform .5s var(--ease);
}
.pillar::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--accent, var(--cyan));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .7s var(--ease);
}
.pillar[data-accent='cyan']  { --accent: var(--cyan); }
.pillar[data-accent='green'] { --accent: var(--chloro); }
.pillar[data-accent='ember'] { --accent: var(--rust); }
.pillar.is-in::before { transform: scaleX(1); }
.pillar:hover { border-color: var(--hair); transform: translateY(-4px); }

.pillar h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.15rem, 1.8vw, 1.5rem);
  letter-spacing: -.01em;
  margin-bottom: .8rem;
  color: var(--accent, var(--aqua));
}
.pillar p { color: var(--ink-dim); font-size: .95rem; }

.focus { border-top: 1px solid var(--hair-soft); padding-top: clamp(1.8rem, 3vw, 2.6rem); }
.focus__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: .1rem 2.5rem;
}
.focus__list li {
  position: relative;
  padding: .8rem 0 .8rem 1.6rem;
  border-bottom: 1px solid var(--hair-soft);
  color: var(--ink-dim);
  font-size: .95rem;
}
.focus__list li::before {
  content: '';
  position: absolute;
  left: 0; top: 1.45em;
  width: 6px; height: 1px;
  background: var(--aqua);
}

/* ----------------------------------------------------------- directions -- */
/*
 * A numbered ladder, not a card grid.
 *
 * These were five equal cards in an auto-fit grid, which on a wide screen laid
 * out as four across and one below — leaving three empty cells of dead space,
 * and squeezing each title into a column too narrow for Russian compounds like
 * "микроструктурированной", which then overflowed its card.
 *
 * Full-width rows fix both at once: no layout can leave a hole, and every title
 * gets a column wide enough to set properly. It also suits the chapter, which
 * is about a progression — the rail down the left reads as one.
 */
.directions {
  position: relative;
  border-top: 1px solid var(--hair-soft);
  margin-bottom: clamp(2.4rem, 5vw, 3.6rem);
}

/* The rail the numbers sit on. */
.directions::before {
  content: '';
  position: absolute;
  left: clamp(1.4rem, 2.6vw, 2.2rem);
  top: 0;
  bottom: 0;
  width: 1px;
  background: linear-gradient(180deg,
    transparent, rgba(255, 106, 44, .34) 6%, rgba(255, 106, 44, .34) 94%, transparent);
  pointer-events: none;
}

.dir {
  position: relative;
  display: grid;
  grid-template-columns: clamp(3.2rem, 6vw, 5rem) minmax(0, 1fr) minmax(0, 1.3fr);
  gap: clamp(.9rem, 2.6vw, 2.6rem);
  align-items: start;
  padding: clamp(1.4rem, 3vw, 2.3rem) 0;
  border-bottom: 1px solid var(--hair-soft);
  transition: background .5s var(--ease);
}
.dir:hover { background: linear-gradient(90deg, rgba(40, 14, 12, .5), transparent 70%); }

.dir__n {
  position: relative;
  z-index: 1;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.15rem, 2vw, 1.6rem);
  line-height: 1;
  color: rgba(255, 106, 44, .62);
  font-variant-numeric: tabular-nums;
  transition: color .4s var(--ease);
}
/* A cap behind the numeral so the rail does not run through it. */
.dir__n::before {
  content: '';
  position: absolute;
  left: -.55rem; right: -.55rem;
  top: -.5rem; bottom: -.5rem;
  background: var(--abyss);
  z-index: -1;
}
.dir:hover .dir__n { color: var(--rust); }

.dir h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.02rem, 1.5vw, 1.3rem);
  line-height: 1.25;
  letter-spacing: -.01em;
  /* Russian sets long. Let it hyphenate, and break it rather than let it
     escape the column if there is nowhere to hyphenate. */
  hyphens: auto;
  overflow-wrap: break-word;
}
.dir p {
  color: var(--ink-dim);
  font-size: .94rem;
  hyphens: auto;
  overflow-wrap: break-word;
}

@media (max-width: 860px) {
  /* Number keeps its rail; title and body stack beside it. */
  .dir { grid-template-columns: clamp(2.6rem, 9vw, 3.4rem) minmax(0, 1fr); gap: .5rem .9rem; }
  .dir h3 { grid-column: 2; }
  .dir p  { grid-column: 2; margin-top: .45rem; }
  .dir__n { grid-row: span 2; }
}

.grant {
  padding: clamp(1.6rem, 3vw, 2.4rem);
  border: 1px solid rgba(255, 106, 44, .3);
  border-left: 2px solid var(--rust);
  background: linear-gradient(120deg, rgba(38, 12, 10, .78), rgba(6, 12, 20, .6));
  max-width: 74ch;
}
.grant__label {
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--amber);
}
.grant__org {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.15rem, 2vw, 1.6rem);
  margin: .5rem 0 .7rem;
  letter-spacing: -.01em;
}
.grant__body { color: var(--ink-dim); font-size: .95rem; }

/* -------------------------------------------------------------- teaching -- */
.teaching__level {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--aqua);
  margin-top: 1.4rem;
}
.courses {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: clamp(1rem, 2.4vw, 2rem);
}
.course {
  padding: clamp(1.5rem, 2.6vw, 2.2rem);
  border: 1px solid var(--hair-soft);
  background: linear-gradient(165deg, rgba(7, 22, 38, .80), rgba(3, 10, 18, .58));
}
.course--lead { border-color: rgba(90, 255, 224, .28); }
.course h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  line-height: 1.3;
  letter-spacing: -.01em;
}
.course--lead h3 { color: var(--aqua); font-weight: 700; }
.course h3 + h3 { margin-top: .9rem; padding-top: .9rem; border-top: 1px solid var(--hair-soft); }
.course .body { margin-top: 0; font-size: .93rem; }

/* --------------------------------------------------------- publications -- */
.pubs {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, .78fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
.pubs__list { border-top: 1px solid var(--hair-soft); }
.pubs__list li {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: .3rem 1.5rem;
  padding: clamp(1rem, 1.8vw, 1.4rem) 0;
  border-bottom: 1px solid var(--hair-soft);
  transition: padding-left .45s var(--ease);
}
.pubs__list li:hover { padding-left: .7rem; }
.pub__t {
  font-size: clamp(.96rem, 1.15vw, 1.06rem);
  line-height: 1.4;
  font-weight: 400;
}
.pub__meta {
  grid-column: 1;
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .1em;
  color: var(--ink-faint);
  text-transform: uppercase;
}
.pub__venue { color: var(--aqua); }
.pubs__side { display: grid; gap: clamp(1.8rem, 4vw, 2.8rem); }
.journals li, .confs li {
  padding: .62rem 0;
  border-bottom: 1px solid var(--hair-soft);
  color: var(--ink-dim);
  font-size: .92rem;
}
.journals li { font-style: italic; }

/* Conferences carry a name, a date-and-place line, and occasionally a note. */
.confs li { display: grid; gap: .22rem; padding: .8rem 0; }
.conf__n { color: var(--ink); line-height: 1.35; }
.conf__m {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.conf__note {
  font-size: .84rem;
  font-style: italic;
  color: var(--aqua-dim, var(--ink-dim));
  line-height: 1.4;
}

/* The live feed's provenance line — quiet, but it should be readable. */
.pubs__note {
  margin: -.4rem 0 clamp(2.4rem, 5vw, 3.6rem);
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.sub--spaced { margin-top: clamp(2.6rem, 5vw, 4rem); }

/* Publication titles become links once the feed supplies a DOI. */
.pub__t a { color: inherit; text-decoration: none; border-bottom: 1px solid transparent; }
.pub__t a:hover,
.pub__t a:focus-visible { border-bottom-color: var(--aqua); color: var(--aqua); }

/* ------------------------------------------------------------- awards ---- */
.awards { margin-top: clamp(3rem, 7vw, 5.5rem); }
.awards__list {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--hair-soft);
}
.awards__list li {
  display: grid;
  grid-template-columns: 5.5rem 1fr;
  gap: clamp(1rem, 3vw, 2.2rem);
  align-items: baseline;
  padding: clamp(.9rem, 2vw, 1.3rem) 0;
  border-bottom: 1px solid var(--hair-soft);
}
.award__y {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .1em;
  color: var(--aqua);
  font-variant-numeric: tabular-nums;
}
.award__b { display: grid; gap: .3rem; }
.award__t { color: var(--ink); line-height: 1.4; }
.award__p {
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
@media (max-width: 560px) {
  .awards__list li { grid-template-columns: 1fr; gap: .35rem; }
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  padding: .9rem 1.9rem;
  border: 1px solid var(--hair);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink);
  background: rgba(8, 26, 42, .7);
  transition: background .4s var(--ease), border-color .4s var(--ease), color .4s, transform .4s var(--ease);
}
.btn:hover {
  background: rgba(40, 240, 216, .14);
  border-color: var(--cyan);
  color: var(--aqua);
  transform: translateY(-2px);
}
.btn--ghost { background: transparent; }
#pubScholar { margin-top: clamp(1.6rem, 3vw, 2.4rem); }

/* -------------------------------------------------------------- gallery -- */
.gallery {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(.5rem, 1.2vw, 1rem);
}
.shot {
  position: relative;
  grid-column: span 4;
  overflow: hidden;
  background: #061420;
  cursor: pointer;
  aspect-ratio: 3 / 2;
}
.shot--feature { grid-column: span 6; }
.shot--tall { grid-column: span 3; aspect-ratio: 3 / 4; }

.shot img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: saturate(.86) contrast(1.05) brightness(.92);
  transform: scale(1.02);
  transition: transform 1.1s var(--ease), filter .7s var(--ease);
}
.shot::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(4, 16, 26, .1) 0%, rgba(3, 12, 20, .72) 100%);
  opacity: .85;
  transition: opacity .6s var(--ease);
  pointer-events: none;
}
.shot:hover img { transform: scale(1.07); filter: saturate(1) contrast(1.02) brightness(1); }
.shot:hover::after { opacity: .5; }

.shot figcaption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  padding: clamp(.8rem, 1.6vw, 1.2rem);
  font-family: var(--mono);
  font-size: .6rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink);
  transform: translateY(6px);
  opacity: 0;
  transition: transform .6s var(--ease), opacity .6s var(--ease);
}
.shot:hover figcaption, .shot:focus-visible figcaption { transform: none; opacity: 1; }

/* -------------------------------------------------------------- contact -- */
.contact { text-align: center; max-width: 900px; }
.contact .index, .contact .label { text-align: center; }
.totop {
  display: inline-flex;
  align-items: center;
  gap: .8rem;
  margin-top: clamp(3rem, 7vw, 5rem);
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: color .35s;
}
.totop:hover { color: var(--aqua); }
.totop__arrow {
  width: 1px; height: 34px;
  background: linear-gradient(0deg, transparent, var(--aqua));
  position: relative;
}
.totop__arrow::before {
  content: '';
  position: absolute;
  top: 0; left: -3px;
  width: 7px; height: 7px;
  border-left: 1px solid var(--aqua);
  border-top: 1px solid var(--aqua);
  transform: rotate(45deg);
}

.foot {
  margin-top: clamp(3rem, 8vw, 6rem);
  padding-top: 1.6rem;
  border-top: 1px solid var(--hair-soft);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .4rem 2rem;
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------- lightbox -- */
#lightbox {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 1rem;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(1, 5, 10, .97);
  opacity: 0;
  transition: opacity .45s var(--ease);
}
#lightbox.is-open { opacity: 1; }
#lightbox[hidden] { display: none; }

.lb__stage { display: grid; place-items: center; gap: 1rem; min-width: 0; }
.lb__stage img {
  max-width: 100%;
  max-height: 78vh;
  object-fit: contain;
  border-radius: 2px;
}
.lb__stage figcaption {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-dim);
  text-align: center;
}

.lb__close {
  position: absolute;
  top: clamp(.8rem, 2.4vw, 1.8rem);
  right: clamp(.8rem, 2.4vw, 1.8rem);
  width: 2.8rem; height: 2.8rem;
  font-size: 1.6rem; line-height: 1;
  border: 1px solid var(--hair);
  border-radius: 50%;
  color: var(--ink-dim);
  transition: border-color .3s, color .3s;
}
.lb__close:hover { border-color: var(--cyan); color: var(--aqua); }

.lb__nav {
  width: 3rem; height: 3rem;
  font-size: 1.8rem; line-height: 1;
  border: 1px solid var(--hair);
  border-radius: 50%;
  color: var(--ink-dim);
  transition: border-color .3s, color .3s, background .3s;
}
.lb__nav:hover { border-color: var(--cyan); color: var(--aqua); background: rgba(40, 240, 216, .08); }

/* --------------------------------------------------------------- reveal -- */
/* Only applied once JS confirms it can animate — if scripting fails, the
   content is simply there. */
html[data-anim='on'] .reveal { opacity: 0; }
html[data-anim='on'] .reveal-mask { opacity: 0; }

/* ----------------------------------------------------------- responsive -- */
@media (max-width: 1080px) {
  .split, .about, .pubs { grid-template-columns: 1fr; }
  .split__body { padding-top: 0; }
  .about__side { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
  .shot--feature, .shot { grid-column: span 6; }
  .shot--tall { grid-column: span 6; aspect-ratio: 3 / 2; }
}

@media (max-width: 860px) {
  #rail { display: none; }
  .chapter { padding-top: clamp(6rem, 16vh, 9rem); padding-bottom: clamp(4rem, 10vh, 7rem); }
  .chapter::before { background: linear-gradient(180deg, rgba(2, 9, 16, .5) 0%, rgba(2, 9, 16, .82) 30%, rgba(2, 9, 16, .82) 70%, rgba(2, 9, 16, .5) 100%); }
  .about__side { grid-template-columns: 1fr; }
  #depth { font-size: .6rem; }

  /* Icons only — the labels are the first thing to go, never the buttons.
     They are the only route to her Scholar, Telegram and email now. */
  .nav__cta span { display: none; }
  .nav__cta { width: 2.6rem; height: 2.6rem; padding: 0; justify-content: center; }
  .nav__cta-group { gap: .4rem; }
}

@media (max-width: 560px) {
  .shot, .shot--feature, .shot--tall { grid-column: span 12; aspect-ratio: 3 / 2; }
  .pubs__list li { grid-template-columns: 1fr; }
  .foot { justify-content: flex-start; text-align: left; }
  .contact { text-align: left; }
  .contact .index, .contact .label, .lead--center { text-align: left; margin-inline: 0; }
}

/* ------------------------------------------------- reduced motion / perf -- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  html[data-anim='on'] .reveal,
  html[data-anim='on'] .reveal-mask { opacity: 1; }
}

/* ---------------------------------------------------------- a note on blur --
   Nothing on this page uses backdrop-filter, deliberately.

   A backdrop-filtered element has to sample everything painted beneath it,
   which here includes the fixed WebGL canvas. The browser services that by
   copying backdrop tiles, and any tile that misses its deadline composites as
   transparent black — which showed up as black rectangles drifting over the
   background during scroll while the foreground text stayed perfectly intact.

   The panels use slightly more opaque backgrounds instead. If you ever add a
   frosted panel over the canvas, expect the flicker to come back with it. */

@media print {
  #gl, #rail, #depth, #loader, #lightbox { display: none !important; }
  body { background: #fff; color: #000; }
  .display, .hero__line { color: #000 !important; -webkit-text-fill-color: #000; }
}
