/* ==========================================================================
   Omid Ardalani — personal site
   Design system: "Modern Dark" (dark primary, light supported), Portfolio Grid
   pattern, Exo / Roboto Mono, Expo.out easing. Generated with the
   ui-ux-pro-max design skill and hand-tuned for contrast and motion.
   ========================================================================== */

/* ---------- tokens ---------- */
:root {
  --ease: cubic-bezier(0.16, 1, 0.3, 1);   /* Expo.out */
  --ease-in: cubic-bezier(0.7, 0, 0.84, 0);
  --t-fast: 160ms;
  --t-mid: 260ms;
  --t-slow: 420ms;

  --sp-1: 4px;  --sp-2: 8px;   --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px;  --sp-7: 48px; --sp-8: 64px;
  --sp-9: 96px; --sp-10: 128px;

  --r-sm: 8px; --r-md: 14px; --r-lg: 20px; --r-full: 999px;
  --wrap: 1140px;

  --font-sans: 'Exo', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'Roboto Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --z-nav: 100;
}

/* dark = primary mode. Deep navy, never pure black (OLED smear). */
[data-theme='dark'] {
  --bg:        #0B1220;
  --bg-elev:   #111C2E;
  --surface:   rgba(255, 255, 255, 0.035);
  --surface-2: rgba(255, 255, 255, 0.06);
  --border:    rgba(255, 255, 255, 0.10);
  --border-2:  rgba(255, 255, 255, 0.18);
  --fg:        #E9EEF6;
  --fg-mute:   #9CACC2;
  --primary:   #5B9BFF;
  --primary-2: #2563EB;
  --accent:    #F5A524;
  --bad:       #F87171;
  --ring:      #7FB4FF;
  --shadow:    0 18px 50px -18px rgba(0, 0, 0, 0.75);
  --glow:      0 0 0 1px rgba(91, 155, 255, 0.30), 0 14px 44px -16px rgba(91, 155, 255, 0.35);
  --blob-1: rgba(37, 99, 235, 0.30);
  --blob-2: rgba(245, 165, 36, 0.14);
  --blob-3: rgba(91, 155, 255, 0.20);
  --veil: rgba(255, 255, 255, 0.035);
  --nav-bg: rgba(11, 18, 32, 0.72);
}

/* light = institutional navy + research accent (from the design system) */
[data-theme='light'] {
  --bg:        #F8FAFC;
  --bg-elev:   #FFFFFF;
  --surface:   #FFFFFF;
  --surface-2: #F1F5F9;
  --border:    #D8E0EA;
  --border-2:  #B9C6D6;
  --fg:        #0F172A;
  --fg-mute:   #4A5A70;
  --primary:   #1E3A5F;
  --primary-2: #2563EB;
  --accent:    #A16207;
  --bad:       #B91C1C;
  --ring:      #1E3A5F;
  --shadow:    0 14px 40px -18px rgba(15, 23, 42, 0.22);
  --glow:      0 0 0 1px rgba(30, 58, 95, 0.22), 0 14px 40px -18px rgba(30, 58, 95, 0.25);
  --blob-1: rgba(37, 99, 235, 0.13);
  --blob-2: rgba(161, 98, 7, 0.09);
  --blob-3: rgba(30, 58, 95, 0.10);
  --veil: rgba(15, 23, 42, 0.028);
  --nav-bg: rgba(248, 250, 252, 0.80);
}

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  transition: background var(--t-mid) var(--ease), color var(--t-mid) var(--ease);
}

h1, h2, h3 { line-height: 1.14; font-weight: 600; letter-spacing: -0.015em; margin: 0; }
h1 { font-size: clamp(2.4rem, 6.2vw, 4.4rem); font-weight: 700; letter-spacing: -0.03em; }
h2 { font-size: clamp(1.75rem, 3.6vw, 2.6rem); }
h3 { font-size: 1.2rem; }
p  { margin: 0 0 var(--sp-4); }
em { font-style: italic; }
.mono { font-family: var(--font-mono); }

a { color: var(--primary); text-decoration: none; transition: color var(--t-fast) var(--ease); }
a:hover { color: var(--fg); }

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

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 var(--sp-5); }

.skip-link {
  position: absolute; left: -9999px; top: var(--sp-2); z-index: 1000;
  background: var(--primary); color: #fff; padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-sm); font-weight: 600;
}
.skip-link:focus { left: var(--sp-4); }

/* ---------- ambient background ---------- */
.ambient { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.blob {
  position: absolute; display: block; border-radius: 50%;
  filter: blur(90px); will-change: transform;
}
.blob-1 { width: 46vw; height: 46vw; top: -12vw; left: -8vw;  background: var(--blob-1); animation: drift1 26s ease-in-out infinite; }
.blob-2 { width: 34vw; height: 34vw; top: 34vh; right: -8vw;  background: var(--blob-2); animation: drift2 32s ease-in-out infinite; }
.blob-3 { width: 40vw; height: 40vw; bottom: -14vw; left: 22vw; background: var(--blob-3); animation: drift3 38s ease-in-out infinite; }

.grid-veil {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--veil) 1px, transparent 1px),
    linear-gradient(90deg, var(--veil) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, #000 40%, transparent 100%);
  -webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, #000 40%, transparent 100%);
}

@keyframes drift1 { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(6vw, 5vh) scale(1.12); } }
@keyframes drift2 { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(-7vw, -4vh) scale(1.08); } }
@keyframes drift3 { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(4vw, -6vh) scale(1.15); } }

main, .nav, .footer { position: relative; z-index: 1; }

/* ---------- nav ---------- */
.nav {
  position: sticky; top: 0; z-index: var(--z-nav);
  background: var(--nav-bg);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-mid) var(--ease), background var(--t-mid) var(--ease);
}
.nav.is-stuck { border-bottom-color: var(--border); }
.nav-inner { display: flex; align-items: center; gap: var(--sp-5); height: 66px; }

.brand { display: inline-flex; align-items: center; gap: var(--sp-3); color: var(--fg); font-weight: 600; }
.brand-mark { color: var(--primary); flex: none; transition: transform var(--t-slow) var(--ease); }
.brand:hover .brand-mark { transform: rotate(180deg); }
.brand-text { font-size: 1rem; letter-spacing: -0.01em; }

.nav-links { display: flex; gap: var(--sp-5); margin-left: auto; }
.nav-links a {
  position: relative; color: var(--fg-mute); font-size: 0.94rem; font-weight: 500;
  padding: var(--sp-2) 0;
}
.nav-links a::after {
  content: ''; position: absolute; left: 0; bottom: 2px; height: 1.5px; width: 100%;
  background: var(--primary); transform: scaleX(0); transform-origin: left;
  transition: transform var(--t-mid) var(--ease);
}
.nav-links a:hover, .nav-links a.is-active { color: var(--fg); }
.nav-links a:hover::after, .nav-links a.is-active::after { transform: scaleX(1); }

.nav-actions { display: flex; align-items: center; gap: var(--sp-3); }

.icon-btn {
  display: inline-grid; place-items: center;
  width: 44px; height: 44px; padding: 0;
  border: 1px solid var(--border); border-radius: var(--r-full);
  background: var(--surface); color: var(--fg-mute); cursor: pointer;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.icon-btn:hover { color: var(--fg); border-color: var(--border-2); background: var(--surface-2); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn svg { position: absolute; transition: opacity var(--t-mid) var(--ease), transform var(--t-mid) var(--ease); }
.icon-btn { position: relative; }
[data-theme='dark']  .i-sun  { opacity: 0; transform: rotate(-90deg) scale(0.6); }
[data-theme='dark']  .i-moon { opacity: 1; transform: none; }
[data-theme='light'] .i-moon { opacity: 0; transform: rotate(90deg) scale(0.6); }
[data-theme='light'] .i-sun  { opacity: 1; transform: none; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 46px; padding: 0 var(--sp-5);
  border-radius: var(--r-full); border: 1px solid transparent;
  font-family: var(--font-sans); font-size: 0.95rem; font-weight: 600;
  cursor: pointer; white-space: nowrap;
  transition: transform var(--t-fast) var(--ease), box-shadow var(--t-mid) var(--ease),
              background var(--t-fast) var(--ease), color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
.btn:active { transform: scale(0.97); }

.btn-primary { background: var(--primary-2); color: #fff; box-shadow: 0 8px 24px -10px rgba(37, 99, 235, 0.7); }
.btn-primary:hover { background: var(--primary); color: #fff; box-shadow: var(--glow); transform: translateY(-2px); }
[data-theme='light'] .btn-primary { background: var(--primary); }
[data-theme='light'] .btn-primary:hover { background: #16304F; color: #fff; }

.btn-ghost { background: var(--surface); color: var(--fg); border-color: var(--border); }
.btn-ghost:hover { border-color: var(--border-2); background: var(--surface-2); transform: translateY(-2px); }

.nav-cv { min-height: 40px; padding: 0 var(--sp-4); font-size: 0.9rem; }

/* ---------- hero ---------- */
.hero { padding: clamp(72px, 12vh, 132px) 0 var(--sp-9); }

.eyebrow {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-family: var(--font-mono); font-size: 0.8rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--fg-mute);
  border: 1px solid var(--border); border-radius: var(--r-full);
  padding: var(--sp-2) var(--sp-4); background: var(--surface);
  margin: 0 0 var(--sp-6);
}
.dot {
  width: 7px; height: 7px; border-radius: 50%; background: #22C55E;
  box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.18);
  animation: pulse 2.4s var(--ease) infinite;
}
@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.18); }
  50%      { box-shadow: 0 0 0 6px rgba(34, 197, 94, 0.05); }
}

.grad {
  background: linear-gradient(105deg, var(--primary) 0%, var(--accent) 92%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

.lede {
  max-width: 62ch; margin: var(--sp-6) 0 var(--sp-7);
  font-size: clamp(1.02rem, 1.5vw, 1.19rem); color: var(--fg-mute);
}

.cta-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

.social { display: flex; gap: var(--sp-5); list-style: none; margin: var(--sp-8) 0 0; padding: 0; }
.social a {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  color: var(--fg-mute); font-size: 0.9rem; font-weight: 500;
  min-height: 44px;
}
.social a:hover { color: var(--fg); }
.social svg { transition: transform var(--t-mid) var(--ease); }
.social a:hover svg { transform: translateY(-2px); }

/* ---------- metrics ---------- */
.metrics { padding: var(--sp-7) 0; border-block: 1px solid var(--border); background: var(--surface); }
.metric-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-5); }
.metric { display: flex; flex-direction: column; gap: var(--sp-2); }
.metric-num {
  font-family: var(--font-mono); font-weight: 700;
  font-size: clamp(1.7rem, 3.4vw, 2.5rem); color: var(--fg);
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em; line-height: 1;
}
.metric-label { font-size: 0.86rem; color: var(--fg-mute); line-height: 1.45; }

/* ---------- scrollytelling: binary -> DNA -> pangenome -> metabolism ---------- */
.scrolly {
  position: relative;
  height: 840vh;                 /* the runway that scrubs all seven acts */
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}
.scrolly-sticky {
  position: sticky; top: 0;
  height: 100vh; height: 100svh;
  overflow: hidden;
  display: grid;
  place-items: center;
}
#scene {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
}

.scrolly-copy {
  position: relative;
  z-index: 2;
  width: min(38ch, 90vw);
  margin-left: clamp(var(--sp-5), 6vw, 96px);
  justify-self: start;
  padding: var(--sp-6);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.scrolly-copy h2 { margin-bottom: var(--sp-3); font-size: clamp(1.6rem, 3vw, 2.3rem); }
/* Reserve the tallest act's body. Without it the card swings 140px between acts and
   snaps as you scrub, because nothing transitions height. Measured: the longest body is
   11 lines on every breakpoint, which is 18.2em at both the desktop and the phone size. */
.act-body {
  color: var(--fg-mute); margin-bottom: var(--sp-5); min-height: 16.5em;
  transition: opacity var(--t-mid) var(--ease);
}
.act-stats {
  display: flex; gap: var(--sp-6); margin: 0;
  padding-top: var(--sp-4); border-top: 1px solid var(--border);
}
.act-stats dt {
  font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--fg-mute); margin-bottom: 2px;
}
.act-stats dd {
  margin: 0; font-size: 0.98rem; font-weight: 700; color: var(--accent);
  font-variant-numeric: tabular-nums;
}

/* The act that shows a tool links to it. min-height reserves the row on the acts that
   have none, so the card does not grow and shrink as you scrub past them. */
.act-link {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin: var(--sp-4) 0 0; min-height: 2.1em;
}
.act-link a {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px;
  font-size: 0.73rem; letter-spacing: 0.04em;
  color: var(--fg); text-decoration: none;
  border: 1px solid var(--border-2); border-radius: 999px;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease);
}
.act-link a::after { content: '↗'; opacity: 0.55; font-size: 0.9em; }
.act-link a:hover, .act-link a:focus-visible {
  color: var(--accent); border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}

.scrolly-rail {
  position: absolute; right: clamp(16px, 3vw, 40px); top: 50%;
  transform: translateY(-50%);
  width: 2px; height: 180px; border-radius: 2px;
  background: var(--border); z-index: 2;
}
.scrolly-bar {
  display: block; width: 100%; height: 0%;
  background: linear-gradient(180deg, var(--primary), var(--accent));
  border-radius: 2px;
}

.scrolly-steps {
  position: absolute; bottom: clamp(20px, 4vh, 44px); left: 50%;
  transform: translateX(-50%);
  display: flex; gap: var(--sp-5); z-index: 2;
  list-style: none; margin: 0; padding: 0;
  font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase;
}
.scrolly-steps li {
  color: var(--fg-mute); opacity: 0.45;
  padding-bottom: 5px; border-bottom: 1.5px solid transparent;
  transition: opacity var(--t-mid) var(--ease), color var(--t-mid) var(--ease),
              border-color var(--t-mid) var(--ease);
}
.scrolly-steps li.is-on {
  opacity: 1; color: var(--fg); border-bottom-color: var(--accent);
}

/* On a phone the copy card is 92vw, so an absolutely-positioned full-pane canvas draws
   entirely underneath it. That was survivable with three acts — a sliver of the network
   peeked past the edges — but with seven it means the whole sequence is invisible on the
   device most people will open this on. So the pane splits: scene on top, copy beneath,
   and the canvas gets a region of its own instead of the card's shadow. */
@media (max-width: 860px) {
  .scrolly { height: 620vh; }          /* seven acts need a runway, 320vh was for three */
  .scrolly-sticky {
    display: flex; flex-direction: column;
    justify-content: flex-start; align-items: center;
    padding: var(--sp-3) 0;
  }
  /* The card is a fixed block of type. Give the SCENE the remainder rather than a fixed
     share, or on a short phone (an SE is 667px) there is no scene height that fits and the
     copy gets clipped by the pane. It shrinks, the text always survives. */
  #scene {
    position: relative; inset: auto;
    width: 100%; flex: 1 1 auto; min-height: 130px;
  }
  .scrolly-copy {
    flex: none;
    justify-self: center; margin: var(--sp-3) 0 0;
    width: min(46ch, 92vw); padding: var(--sp-4);
  }
  /* measured: the tallest body is 14.9em at this font and card width, not the 16.5em
     the desktop needs, so the phone reserved 40px of dead air under every act. */
  .act-body { font-size: 0.88rem; min-height: 14.9em; }
  /* act VI's edit list wraps to two lines here and nothing else does, so the row is
     reserved as well: otherwise that one card is 26px taller than the other six. */
  .act-stats { min-height: 5.3em; }
  /* The kicker already names the act, and seven identical copies of this heading cost a
     phone 74px it has not got. Hidden to the eye, kept in the a11y tree, since the section
     is labelled by it. (The comment goes ABOVE the block: put it after the brace and it
     swallows every declaration up to its closing star-slash, which is what happened here.) */
  .scrolly-copy h2 {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden; white-space: nowrap;
    clip-path: inset(50%);
  }
  .scrolly-rail { display: none; }
  .scrolly-steps { display: none; }    /* seven chips will not fit; the card names the act */
}

/* No motion: no pinned scrub, no runway. Show the finished network and its story. */
@media (prefers-reduced-motion: reduce) {
  .scrolly { height: auto; }
  .scrolly-sticky { position: static; height: auto; min-height: 78vh; padding: var(--sp-8) 0; }
  #scene { position: relative; height: 52vh; }
  .scrolly-rail, .scrolly-steps { display: none; }
}

/* ---------- sections ---------- */
.section { padding: var(--sp-10) 0; }
.section.alt { background: var(--surface); border-block: 1px solid var(--border); }

.sec-head { max-width: 62ch; margin-bottom: var(--sp-7); }
.kicker {
  font-family: var(--font-mono); font-size: 0.78rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--accent); margin: 0 0 var(--sp-3);
}
.sec-sub { color: var(--fg-mute); margin-top: var(--sp-4); margin-bottom: 0; }

/* ---------- filters ---------- */
.filters { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-6); }
.chip {
  min-height: 40px; padding: 0 var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-full);
  background: transparent; color: var(--fg-mute);
  font-family: var(--font-mono); font-size: 0.82rem; font-weight: 500;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.chip:hover { color: var(--fg); border-color: var(--border-2); }
.chip:active { transform: scale(0.96); }
.chip.is-active { background: var(--fg); color: var(--bg); border-color: var(--fg); }

/* ---------- cards ---------- */
.cards {
  display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--sp-5);
  grid-auto-flow: dense; /* filters hide cards; keep the grid from leaving holes */
}
.card {
  grid-column: span 2;
  display: flex; flex-direction: column;
  padding: var(--sp-6);
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--bg-elev);
  transition: transform var(--t-mid) var(--ease), box-shadow var(--t-mid) var(--ease),
              border-color var(--t-mid) var(--ease), opacity var(--t-mid) var(--ease);
}
.card.is-feature { grid-column: span 3; }
.card.is-wide { grid-column: span 6; }
.card.is-wide .card-org { margin-bottom: var(--sp-3); }
.card.is-wide p:not(.card-org) { max-width: 78ch; }
.card:hover {
  transform: translateY(-4px);
  border-color: var(--border-2);
  box-shadow: var(--shadow);
}
.card.is-hidden { display: none; }

.card-top { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.tag {
  font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.06em;
  text-transform: uppercase; font-weight: 500;
  padding: 4px var(--sp-3); border-radius: var(--r-full);
  border: 1px solid var(--border); color: var(--fg-mute); background: var(--surface);
}
.tag-accent { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }

.card h3 { margin-bottom: var(--sp-1); font-size: 1.32rem; }
.card.is-feature h3 { font-size: 1.6rem; }
.card-org {
  font-family: var(--font-mono); font-size: 0.8rem; color: var(--accent);
  margin: 0 0 var(--sp-4); word-break: break-word;
}
.card p:not(.card-org) { font-size: 0.95rem; color: var(--fg-mute); margin-bottom: var(--sp-4); }
.card p:not(.card-org) strong { color: var(--fg); font-weight: 600; }

.card-links { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4); margin-top: auto; }
.link-out {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.9rem; font-weight: 600; color: var(--primary); min-height: 32px;
}
.link-out svg { transition: transform var(--t-mid) var(--ease); }
.link-out:hover svg { transform: translate(2px, -2px); }
.link-out.subtle { color: var(--fg-mute); font-weight: 500; }
.link-out.subtle:hover { color: var(--fg); }
.pill {
  font-family: var(--font-mono); font-size: 0.75rem; color: var(--fg-mute);
  padding: 3px var(--sp-3); border-radius: var(--r-full); background: var(--surface-2);
}

/* ---------- research cards that carry a real figure ---------- */
.card.is-figure {
  display: grid;
  grid-template-columns: minmax(0, 0.46fr) minmax(0, 1fr);
  gap: var(--sp-6);
  align-items: start;
}
/* A landscape screenshot squeezed into the narrow portrait column becomes an
   unreadable strip. Give it the full card width and put the copy underneath. */
.card.is-figure.is-shot { grid-template-columns: 1fr; gap: var(--sp-5); }

.figbody { display: flex; flex-direction: column; min-width: 0; }
.figbody .card-links { margin-top: auto; padding-top: var(--sp-3); }

/* The plate stays white in both themes: it is a journal figure, and journal
   figures are drawn on white. Inverting it would wreck the science. */
.figplate {
  position: relative; display: block; width: 100%; padding: 0;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: #fff; cursor: pointer; overflow: hidden;
  transition: transform var(--t-mid) var(--ease), box-shadow var(--t-mid) var(--ease),
              border-color var(--t-mid) var(--ease);
}
.figplate img { display: block; width: 100%; height: auto; }
.figplate:hover { transform: translateY(-2px); box-shadow: var(--shadow); border-color: var(--border-2); }
.figplate:active { transform: scale(0.99); }

.figplate-cue {
  position: absolute; left: 50%; bottom: var(--sp-4);
  transform: translateX(-50%) translateY(6px);
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px var(--sp-4); border-radius: var(--r-full);
  background: rgba(11, 18, 32, 0.86); color: #fff;
  font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.04em;
  white-space: nowrap;
  opacity: 0; transition: opacity var(--t-mid) var(--ease), transform var(--t-mid) var(--ease);
}
.figplate:hover .figplate-cue,
.figplate:focus-visible .figplate-cue { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ---------- lightbox ---------- */
.lightbox {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; flex-direction: column; align-items: center;
  padding: clamp(16px, 4vh, 48px) var(--sp-4);
  background: rgba(6, 10, 18, 0.92);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  overflow-y: auto; overscroll-behavior: contain;
  animation: lbIn var(--t-mid) var(--ease);
}
.lightbox[hidden] { display: none; }
@keyframes lbIn { from { opacity: 0; } to { opacity: 1; } }

.lb-fig { margin: 0; max-width: min(940px, 100%); }
.lb-fig img {
  display: block; width: 100%; height: auto;
  background: #fff; border-radius: var(--r-md);
  box-shadow: 0 30px 90px -30px rgba(0, 0, 0, 0.8);
}
.lb-fig figcaption {
  margin-top: var(--sp-4); padding-bottom: var(--sp-6);
  color: #cbd5e1; font-size: 0.88rem; line-height: 1.5; text-align: center;
}
.lb-close {
  position: sticky; top: 0; align-self: flex-end;
  display: inline-grid; place-items: center;
  width: 44px; height: 44px; flex: none; margin-bottom: var(--sp-3);
  border: 1px solid rgba(255, 255, 255, 0.22); border-radius: var(--r-full);
  background: rgba(11, 18, 32, 0.9); color: #fff; cursor: pointer;
  transition: transform var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.lb-close:hover { background: rgba(255, 255, 255, 0.14); }
.lb-close:active { transform: scale(0.94); }
body.lb-open { overflow: hidden; }

/* ---------- publications ---------- */
.pubs { list-style: none; margin: 0; padding: 0; }
.pub {
  display: grid; grid-template-columns: 92px 1fr; gap: var(--sp-5);
  padding: var(--sp-5) 0;
  border-top: 1px solid var(--border);
  transition: background var(--t-mid) var(--ease);
}
.pub:last-child { border-bottom: 1px solid var(--border); }
.pub:hover { background: color-mix(in srgb, var(--fg) 3%, transparent); }
.pub-year {
  font-family: var(--font-mono); font-size: 0.82rem; font-weight: 500;
  color: var(--fg-mute); padding-top: 4px; line-height: 1.35;
}
.pub h3 { font-size: 1.08rem; font-weight: 600; margin-bottom: var(--sp-2); line-height: 1.4; }
.pub h3 a { color: var(--fg); }
.pub h3 a:hover { color: var(--primary); }
.pub-meta { font-size: 0.88rem; color: var(--fg-mute); margin-bottom: var(--sp-1); }
.pub-meta .mono { font-size: 0.8rem; }
.pub-role {
  display: inline-block; margin: 0;
  font-family: var(--font-mono); font-size: 0.74rem; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--accent);
}
.pub.is-highlight { position: relative; }
.pub.is-highlight .pub-year { color: var(--accent); font-weight: 700; }
.pub.is-highlight h3 { font-size: 1.22rem; }
.pub.is-patent .pub-year { color: var(--primary); }

/* ---------- about ---------- */
.about-wrap { display: grid; grid-template-columns: 1fr 1.5fr; gap: var(--sp-8); align-items: start; }
.about-wrap .sec-head { margin-bottom: 0; position: sticky; top: 100px; }
.prose { max-width: 68ch; font-size: 1.04rem; }
.prose .pull {
  font-size: 1.3rem; line-height: 1.5; color: var(--fg); font-weight: 500;
  padding-left: var(--sp-5); border-left: 2px solid var(--accent);
  margin-bottom: var(--sp-6);
}
.prose p { color: var(--fg-mute); }
.prose strong { color: var(--fg); font-weight: 600; }
.signature { margin-top: var(--sp-6); padding-top: var(--sp-5); border-top: 1px solid var(--border); }
.signature .mono { font-size: 0.82rem; color: var(--fg-mute); }

/* ---------- timeline ---------- */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li {
  display: grid; grid-template-columns: 150px 1fr; gap: var(--sp-6);
  padding: var(--sp-6) 0; border-top: 1px solid var(--border); position: relative;
}
.timeline li:last-child { border-bottom: 1px solid var(--border); }
.tl-when { font-size: 0.84rem; color: var(--fg-mute); padding-top: 3px; }
.tl-body h3 { margin-bottom: var(--sp-1); }
.tl-org { font-size: 0.9rem; color: var(--accent); margin-bottom: var(--sp-3); }
.tl-body p:last-child { font-size: 0.95rem; color: var(--fg-mute); margin: 0; }

/* ---------- contact ---------- */
.contact { text-align: center; padding-block: var(--sp-10); }
.contact-inner { max-width: 60ch; margin: 0 auto; }
.contact .sec-sub { margin-bottom: var(--sp-7); }
.contact .cta-row { justify-content: center; }

/* ---------- footer ---------- */
.footer { border-top: 1px solid var(--border); padding: var(--sp-6) 0; background: var(--surface); }
.footer-inner { display: flex; flex-wrap: wrap; gap: var(--sp-4); align-items: center; justify-content: space-between; }
.footer p { margin: 0; font-size: 0.8rem; color: var(--fg-mute); }
.footer-links { display: flex; flex-wrap: wrap; gap: var(--sp-5); }
.footer-links a { font-size: 0.85rem; color: var(--fg-mute); min-height: 32px; display: inline-flex; align-items: center; }
.footer-links a:hover { color: var(--fg); }

/* ---------- reveal animation ---------- */
[data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
}
[data-reveal].is-in { opacity: 1; transform: none; }

/* ---------- responsive ---------- */
@media (max-width: 1024px) {
  .cards { grid-template-columns: repeat(4, 1fr); }
  .card, .card.is-feature { grid-column: span 2; }
  .card.is-wide { grid-column: span 4; }
  .about-wrap { grid-template-columns: 1fr; gap: var(--sp-6); }
  .about-wrap .sec-head { position: static; }
}

@media (max-width: 860px) {
  .nav-links { display: none; }
  .metric-grid { grid-template-columns: repeat(2, 1fr); gap: var(--sp-6); }
}

@media (max-width: 720px) {
  body { font-size: 16px; }
  .section { padding: var(--sp-8) 0; }
  .cards { grid-template-columns: 1fr; }
  .card, .card.is-feature, .card.is-wide { grid-column: span 1; }
  .card.is-figure { grid-template-columns: 1fr; gap: var(--sp-5); }
  .figplate-cue { opacity: 1; transform: translateX(-50%); }  /* no hover on touch */
  .pub { grid-template-columns: 1fr; gap: var(--sp-2); }
  .pub-year { padding-top: 0; }
  .timeline li { grid-template-columns: 1fr; gap: var(--sp-2); }
  .hero { padding-top: var(--sp-8); }
  .social { gap: var(--sp-4); flex-wrap: wrap; }
  .footer-inner { flex-direction: column; align-items: flex-start; }
  .blob { filter: blur(60px); }
}

@media (max-width: 400px) {
  .cta-row { flex-direction: column; align-items: stretch; }
  .btn { width: 100%; }
}

/* ---------- reduced motion: honor it completely ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  [data-reveal] { opacity: 1; transform: none; }
  .blob { animation: none; }
}

@media print {
  .ambient, .nav, .filters, .contact, .footer { display: none; }
  body { background: #fff; color: #000; }
}

/* ═══════════════════════ margin rails ═══════════════════════════════════════
   The pipeline scrollytelling stopped at "01 — Work". From there down, the page has
   two empty margins and 256px of clear space between every section, and all of it
   carries it on: bits building a double helix on the left, a metabolic network
   turning on the right, and at each section boundary the two converge on the middle,
   fuse, and separate again.

   ONE canvas, spanning the viewport, because the material has to be able to travel
   from the margins to the centre. It only draws in the margins and in the empty band
   between sections; the reading column is never touched.

   Rails exist ONLY where there IS an empty margin. The column is --wrap wide, so each
   margin is (100vw - --wrap)/2, and below about 1400px that is too thin to hold
   anything — so they are not rendered rather than squeezed against the text.

   z-index 1 puts them ABOVE the section backgrounds (.section.alt paints an opaque
   white full-bleed background in the light theme, and anything behind it would be
   visible in dark and invisible in light) and below the nav. pointer-events: none. */
.rails {
  display: none;
  position: fixed; inset: 0;
  z-index: 1;
  pointer-events: none;
}
#rails-canvas { display: block; width: 100%; height: 100%; }

@media (min-width: 1400px) {
  .rails { display: block; }
}

/* A rail that never moves is clutter, so under reduced motion rails.js draws one
   still frame and stops the loop; this dials it back to a watermark. */
@media (prefers-reduced-motion: reduce) {
  #rails-canvas { opacity: 0.5; }
}
