/* ╔═══════════════════════════════════════════════════════════
   ║  CHERY/LAB - Research Console
   ║  Modern dark UI · cutting-edge bento layouts · Geist family
   ╚═══════════════════════════════════════════════════════════ */

/* ─── TOKENS ─── */
:root {
  --bg:           #07080A;
  --bg-1:         #0C0D11;
  --bg-2:         #14151B;
  --bg-3:         #1A1B23;
  --bg-card:      #0E0F13;
  --bg-card-hov:  #15171E;

  --line:         rgba(255,255,255,.10);
  --line-strong:  rgba(255,255,255,.12);
  --line-glow:    rgba(190,242,100,.22);

  --text:         #E8E7E3;
  --text-2:       #C5C4C0;
  --text-mute:    #8A8A86;
  --text-dim:     #5A5A56;

  --lime:         #BEF264;
  --lime-deep:    #84CC16;
  --lime-glow:    rgba(190,242,100,.18);

  --amber:        #FCD34D;
  --amber-deep:   #F59E0B;
  --sky:          #7DD3FC;
  --sky-deep:     #38BDF8;
  --rose:         #FDA4AF;
  --rose-deep:    #E11D48;

  --good:         var(--lime);
  --warn:         var(--amber);
  --bad:          #FB7185;

  /* ── SPACING SCALE ────────────────────────────────────────
     8px base, geometric progression. Every padding/margin/gap
     in the system MUST resolve to one of these. No 7px, no 13px. */
  --s-1:   4px;   /* hairline gap (icon-to-text inside chips) */
  --s-2:   8px;   /* tight gap                                  */
  --s-3:  12px;   /* close gap, small padding                   */
  --s-4:  16px;   /* default card padding (compact)             */
  --s-5:  24px;   /* default card padding (comfortable)         */
  --s-6:  32px;   /* between major card groups                  */
  --s-7:  48px;   /* small section padding                      */
  --s-8:  64px;   /* default section padding                    */
  --s-9:  96px;   /* hero / display whitespace                  */

  /* ── TYPE SCALE ───────────────────────────────────────────
     Modular scale, 1.25 ratio (major third), anchored at 1rem.
     The 6 named sizes cover everything from pill-caps to display. */
  --fs-2xs:  0.6875rem;   /* 11px – pill-caps, micro labels     */
  --fs-xs:   0.75rem;     /* 12px – mono labels, captions       */
  --fs-sm:   0.8125rem;   /* 13px – secondary body, meta lines  */
  --fs-md:   0.9375rem;   /* 15px – default body                */
  --fs-base: 1.0625rem;   /* 17px – emphasized body, lead        */
  --fs-lg:   1.25rem;     /* 20px – card values, sub-headings   */
  --fs-xl:   1.5625rem;   /* 25px – section sub-titles          */
  --fs-2xl:  2rem;        /* 32px – stat values (e.g. 9.2)      */
  --fs-3xl:  2.5rem;      /* 40px – section H2 base             */
  --fs-4xl:  clamp(2.6rem, 4vw, 3.6rem);   /* lab-titles        */
  --fs-display: clamp(3rem, 6vw, 4.6rem);  /* hero name         */

  /* ── LINE-HEIGHTS (only 4 allowed) ────────────────────── */
  --lh-tight:    1.1;     /* hero, display                       */
  --lh-snug:     1.3;     /* large titles                        */
  --lh-normal:   1.5;     /* body                                */
  --lh-relaxed:  1.7;     /* long-form prose                     */

  /* ── BORDER RADII (proportional ladder) ──────────────── */
  --r-xs:   2px;          /* hairline pills, chip dots          */
  --r-sm:   4px;          /* status pills, small buttons        */
  --r-md:   6px;          /* chips, badges                      */
  --r-lg:   12px;         /* cards                              */
  --r-xl:   18px;         /* portrait card, large surfaces      */
  --r-pill: 100px;        /* fully-rounded pills                */
  --r-full: 50%;          /* circles (avatars, dots)            */

  /* ── ELEVATION & MOTION ──────────────────────────────── */
  --shadow-1:  0 1px 0 rgba(255,255,255,.04) inset, 0 0 0 1px var(--line);
  --shadow-2:  0 1px 0 rgba(255,255,255,.05) inset, 0 0 0 1px var(--line-strong),
               0 16px 48px rgba(0,0,0,.5);

  --ease:      cubic-bezier(.22,.61,.36,1);
  --ease-out:  cubic-bezier(.16,1,.3,1);

  --font-sans:  'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono:  'Geist Mono', 'SF Mono', Menlo, Consolas, monospace;
  --font-serif: 'Instrument Serif', 'Times New Roman', serif;
}

/* ─── RESET ─── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { font-family: var(--font-sans); -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
body {
  background: var(--bg);
  color: var(--text);
  font-size: 15px;
  line-height: var(--lh-normal);
  font-feature-settings: 'kern','liga','ss01','tnum';
  min-height: 100vh;
  overflow-x: hidden;
  letter-spacing: -0.005em;
}

/* GRID BACKGROUND */
body::before {
  content: '';
  position: fixed; inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,.022) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.022) 1px, transparent 1px);
  background-size: 40px 40px;
  -webkit-mask: radial-gradient(ellipse at 50% 0%, black 30%, transparent 75%);
          mask: radial-gradient(ellipse at 50% 0%, black 30%, transparent 75%);
  pointer-events: none;
  z-index: 0;
}
/* Soft accent glow at top */
body::after {
  content: '';
  position: fixed; inset: 0;
  background: radial-gradient(ellipse 800px 500px at 50% -10%, rgba(190,242,100,.06), transparent 70%);
  pointer-events: none;
  z-index: 0;
}

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
input, button, textarea, select { font-family: inherit; font-size: inherit; color: inherit; }
::selection { background: rgba(190,242,100,.30); color: var(--text); }
*:focus-visible { outline: 2px solid var(--lime); outline-offset: 2px; border-radius: var(--r-sm); }

main { position: relative; z-index: 1; }

.mono { font-family: var(--font-mono); letter-spacing: 0; }
.dim  { color: var(--text-dim); }

/* ════════════════════════════════════════════════════════════
   TOP BAR
   ════════════════════════════════════════════════════════════ */
.topbar {
  position: sticky;
  top: 0;
  z-index: 100;
  height: 56px;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  padding: 0 var(--s-5);
  background: rgba(7,8,10,.72);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  border-bottom: 1px solid var(--line);
}
.brand {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 500;
  letter-spacing: .03em;
}
/* ─── Pure typographic logo ─── */
.logo-type {
  display: inline-flex;
  flex-direction: column;
  line-height: 0.92;
  gap: var(--s-1);
  padding: var(--s-1) 0;
  flex-shrink: 0;
}
.logo-row-1 {
  display: inline-flex;
  align-items: baseline;
  font-family: 'Instrument Serif', serif;
  font-style: italic;
  font-weight: 400;
  color: var(--text);
}
.logo-c {
  font-size: 2.1rem;
  letter-spacing: -0.04em;
  line-height: 0.85;
  background: linear-gradient(180deg, #FFFFFF 0%, #C5C4C0 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  margin-right: -1px;
}
.logo-rest {
  font-size: 1.45rem;
  letter-spacing: -0.02em;
  margin-left: -1px;
  margin-bottom: 1px;
  position: relative;
  top: -1px;
}
.logo-dot {
  font-family: 'Instrument Serif', serif;
  font-style: italic;
  font-size: 2.2rem;
  font-weight: 400;
  color: var(--lime);
  line-height: 0.85;
  margin-left: 0;
  text-shadow: 0 0 10px rgba(190,242,100, 0.4);
}
.logo-row-2 {
  font-family: var(--font-mono);
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.32em;
  color: var(--lime);
  text-transform: uppercase;
  padding-left: var(--s-1);
  margin-top: -4px;
  border-top: 1px solid rgba(190,242,100, 0.18);
  padding-top: var(--s-1);
  align-self: stretch;
}

/* hover: invert color treatment */
.brand:hover .logo-c {
  background: linear-gradient(180deg, var(--lime) 0%, var(--lime-deep) 100%);
  -webkit-background-clip: text;
          background-clip: text;
  transition: all 0.4s var(--ease);
}
.brand:hover .logo-dot {
  color: var(--text);
  text-shadow: none;
  transition: all 0.4s var(--ease);
}

/* keep old class as fallback */
.brand-text em { color: var(--lime); font-style: normal; font-weight: 600; }
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  margin-left: var(--s-3);
  padding: var(--s-1) var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: .08em;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-1);
  color: var(--text-mute);
  transition: color .25s, border-color .25s, background .25s;
}
.status-pill .status-dot {
  width: 6px; height: 6px; border-radius: var(--r-full);
  background: var(--text-dim);
  box-shadow: 0 0 0 0 transparent;
}
.status-pill.online {
  color: var(--lime);
  border-color: rgba(190,242,100,.3);
}
.status-pill.online .status-dot {
  background: var(--lime);
  box-shadow: 0 0 8px var(--lime-glow);
  animation: pulse 1.8s var(--ease) infinite;
}
.status-pill.offline {
  color: var(--rose);
  border-color: rgba(253,164,175,.3);
}
.status-pill.offline .status-dot { background: var(--rose); }
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .55; transform: scale(.85); }
}

.topnav {
  display: flex;
  justify-self: center;
  gap: var(--s-1);
  padding: var(--s-1);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
}
.topnav a {
  padding: var(--s-2) var(--s-4);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-mute);
  border-radius: var(--r-pill);
  transition: color .2s, background .2s;
}
.topnav a:hover { color: var(--text); background: var(--bg-2); }

.topbar-cta {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}
.kbd {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  padding: var(--s-1) var(--s-2);
  border: 1px solid var(--line-strong);
  background: var(--bg-1);
  border-radius: var(--r-sm);
  color: var(--text-mute);
}
@media (max-width: 880px) { .kbd { display: none; } }
@media (max-width: 720px) { .topnav { display: none; } }

/* ════════════════════════════════════════════════════════════
   BUTTONS
   ════════════════════════════════════════════════════════════ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 9px var(--s-4);
  font-size: var(--fs-sm);
  font-weight: 500;
  letter-spacing: -.005em;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--bg-2);
  color: var(--text);
  cursor: pointer;
  transition: background .18s var(--ease), border-color .18s, transform .12s, box-shadow .18s;
  white-space: nowrap;
}
.btn:hover { background: var(--bg-3); border-color: rgba(255,255,255,.18); }
.btn:active { transform: translateY(1px); }
.btn.full { width: 100%; justify-content: center; }
.btn-primary {
  background: var(--lime);
  color: #0A0A0A;
  border-color: var(--lime);
  font-weight: 600;
}
.btn-primary:hover {
  background: #D9F99D;
  border-color: #D9F99D;
  box-shadow: 0 4px 16px var(--lime-glow);
}
.btn-ghost {
  background: transparent;
  border-color: var(--line);
  color: var(--text-2);
}
.btn-ghost:hover { color: var(--text); border-color: var(--line-strong); }
.btn-tiny {
  padding: var(--s-1) var(--s-3);
  font-size: var(--fs-xs);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--bg-1);
  color: var(--text-mute);
}
.btn-tiny:hover { color: var(--text); border-color: var(--line-strong); background: var(--bg-2); }

/* ════════════════════════════════════════════════════════════
   HERO BENTO
   ════════════════════════════════════════════════════════════ */
.hero {
  padding: var(--s-8) var(--s-5) var(--s-6);
  max-width: 1320px;
  margin: 0 auto;
}

.bento {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-auto-rows: minmax(140px, auto);
  gap: var(--s-4);
}

.card {
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s-5);
  position: relative;
  overflow: hidden;
  transition: border-color .25s, background .25s;
}
.card:hover { border-color: var(--line-strong); }

/* sheen */
.card::after {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(ellipse 600px 200px at 0% 0%, rgba(255,255,255,.025), transparent 60%);
  pointer-events: none;
}

/* IDENTITY */
.card-id {
  grid-column: span 4;
  grid-row: span 2;
  padding: var(--s-6) var(--s-6);
  background:
    radial-gradient(ellipse 600px 200px at 100% 0%, rgba(190,242,100,.05), transparent 60%),
    var(--bg-card);
}
.card-meta {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  margin-bottom: var(--s-6);
}
.meta-tag {
  padding: var(--s-1) var(--s-2);
  background: rgba(190,242,100,.08);
  color: var(--lime);
  border: 1px solid rgba(190,242,100,.18);
  border-radius: var(--r-sm);
  font-weight: 600;
  letter-spacing: .04em;
}
.meta-dot { width: 4px; height: 4px; background: var(--text-dim); border-radius: var(--r-full); }

.hero-name {
  font-size: clamp(2.6rem, 5vw, 4.2rem);
  font-weight: 600;
  letter-spacing: -.04em;
  line-height: var(--lh-tight);
  margin-bottom: var(--s-4);
  background: linear-gradient(180deg, #FFFFFF 0%, #B8B8B0 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
.hero-roles {
  font-size: var(--fs-md);
  color: var(--text-2);
  margin-bottom: 22px;
  letter-spacing: -.005em;
}
.hero-roles em {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--lime);
  font-size: 1.05em;
}
.hero-roles .sep { color: var(--text-dim); margin: 0 var(--s-2); }

.hero-deck {
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
  color: var(--text-2);
  max-width: 540px;
  margin-bottom: var(--s-5);
}
.hero-deck em {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--text);
  font-size: 1.05em;
}

.hero-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
  margin-bottom: var(--s-6);
}
.kv {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  padding: var(--s-2) var(--s-3);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  color: var(--text-mute);
}
.kv b { color: var(--text); font-weight: 600; }

.hero-cta { display: flex; gap: var(--s-3); flex-wrap: wrap; }

/* PORTRAIT */
.card-portrait {
  grid-column: span 2;
  grid-row: span 2;
  padding: 0;
  position: relative;
}
.card-portrait img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 18%;
  filter: contrast(1.05) saturate(.9) brightness(.85);
}
.card-portrait::before {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 40%, rgba(7,8,10,.92) 100%);
  z-index: 1;
}
.portrait-overlay {
  position: absolute;
  inset: auto 16px 16px 16px;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  z-index: 2;
}
.portrait-name {
  font-size: var(--fs-base);
  font-weight: 600;
  letter-spacing: -.01em;
}
.portrait-loc {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  margin-top: var(--s-1);
}
.portrait-tag {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  padding: var(--s-1) var(--s-2);
  background: rgba(0,0,0,.5);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  color: var(--lime);
  letter-spacing: .06em;
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}

/* STAT CARDS */
.card-stat {
  grid-column: span 2;
}
.stat-label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  text-transform: uppercase;
  letter-spacing: .12em;
  margin-bottom: var(--s-3);
}
.stat-value {
  font-size: var(--fs-3xl);
  font-weight: 500;
  letter-spacing: -.04em;
  line-height: var(--lh-tight);
  font-feature-settings: 'tnum';
}
.stat-suffix {
  font-size: var(--fs-sm);
  color: var(--text-mute);
  margin-left: var(--s-2);
  font-weight: 400;
  letter-spacing: 0;
}
.stat-sub {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  margin-top: var(--s-2);
}
.stat-spark {
  position: absolute;
  bottom: 12px;
  left: 24px;
  right: 24px;
  width: calc(100% - 48px);
  height: 32px;
  pointer-events: none;
}
.stat-spark path { fill: none; stroke: var(--lime); stroke-width: 1.5; opacity: .85; }
.stat-spark .area { fill: var(--lime-glow); stroke: none; opacity: .55; }

.stat-bars {
  display: flex;
  gap: var(--s-1);
  height: 4px;
  margin-top: var(--s-4);
}
.stat-bars span {
  flex: 1;
  height: 100%;
  background: rgba(190,242,100,.10);
  border-radius: var(--r-xs);
  overflow: hidden;
  position: relative;
  box-shadow: inset 0 0 0 1px rgba(190,242,100,.18);
}
.stat-bars b {
  display: block;
  height: 100%;
  width: var(--w);
  background: var(--c, var(--lime));
  border-radius: inherit;
}

/* Scale ticks beneath the bar -- anchor 0 / 5 / 10 so the empty
   portion reads as "remaining toward 10", not as background.    */
.stat-scale {
  display: flex;
  justify-content: space-between;
  margin-top: var(--s-2);
  font-family: var(--font-mono);
  font-size: .58rem;
  letter-spacing: .14em;
  color: var(--text-mute);
  user-select: none;
}
.stat-scale .stat-scale-mid { opacity: .55; }

.stat-link {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  align-self: flex-start;
  margin-top: var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .08em;
  color: var(--lime);
  border-bottom: 1px solid rgba(190,242,100,.3);
  padding-bottom: 1px;
  transition: border-color .2s, gap .2s var(--ease);
}
.stat-link:hover { border-color: var(--lime); gap: var(--s-2); }

/* ── GPA card reveal animation ───────────────────────────────
   bars start empty, fill in stagger, then a soft lime glow
   pulse celebrates completion. JS toggles .is-revealed when
   the card scrolls into view (see app.js).                   */
.card-stat[data-anim="gpa"] .stat-bars b {
  width: 0;
  transition: width 1.05s cubic-bezier(.2,.7,.2,1);
}
.card-stat[data-anim="gpa"].is-revealed .stat-bars b { width: var(--w); transition-delay: .10s; }

@keyframes gpa-bar-celebrate {
  0%   { filter: brightness(1)    saturate(1);   }
  25%  { filter: brightness(1.55) saturate(1.3); }
  60%  { filter: brightness(1.2)  saturate(1.1); }
  100% { filter: brightness(1)    saturate(1);   }
}
.card-stat[data-anim="gpa"].is-revealed .stat-bars b {
  animation: gpa-bar-celebrate 1.6s ease-out 1.4s 2;
}

@keyframes gpa-number-celebrate {
  0%   { text-shadow: 0 0 0 transparent; transform: scale(1); }
  35%  { text-shadow: 0 0 28px rgba(190,242,100,.75), 0 0 56px rgba(190,242,100,.35); transform: scale(1.045); }
  100% { text-shadow: 0 0 0 transparent; transform: scale(1); }
}
.card-stat[data-anim="gpa"] .stat-value {
  display: inline-block;
  transform-origin: left center;
  will-change: transform, text-shadow;
}
.card-stat[data-anim="gpa"].is-revealed .stat-value {
  animation: gpa-number-celebrate 1.4s ease-out 1.65s;
}

/* Reset hatch: snap bars/number back to start without animating between loops. */
.card-stat[data-anim="gpa"].is-resetting .stat-bars b,
.card-stat[data-anim="gpa"].is-resetting .stat-value {
  transition: none !important;
  animation: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .card-stat[data-anim="gpa"] .stat-bars b { width: var(--w); transition: none; animation: none; }
  .card-stat[data-anim="gpa"] .stat-value  { animation: none; }
}

/* STACK CARD */
.card-stack {
  grid-column: span 2;
  display: flex;
  flex-direction: column;
}
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-top: var(--s-3);
  flex: 1;                    /* fill remaining card height       */
  align-content: center;      /* center wrapped rows vertically   */
}
.chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  padding: var(--s-1) var(--s-3);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  color: var(--text-2);
  flex: 1 1 auto;             /* grow to fill its row            */
  min-width: max-content;     /* never clip the text             */
  white-space: nowrap;
}
.chip-dot { width: 6px; height: 6px; border-radius: var(--r-full); }
.chip-logo {
  width: 14px;
  height: 14px;
  object-fit: contain;
  flex-shrink: 0;
  display: block;
  filter: saturate(.55) brightness(.95);
  transition: filter .25s var(--ease);
}
.chip:hover .chip-logo { filter: saturate(1) brightness(1); }

/* ── Language flags (small inline SVG markers) ── */
.lang-flag {
  display: inline-block;
  width: 13px;
  height: 9px;
  margin-right: var(--s-1);
  vertical-align: -1px;
  border-radius: var(--r-xs);
  object-fit: cover;
  box-shadow: 0 0 0 1px rgba(255,255,255,.08);
}
.lang-list {
  font-size: var(--fs-2xs);
  letter-spacing: .02em;
  line-height: var(--lh-snug);
}
.lang-list .lang { white-space: nowrap; }

/* ── Publication affiliation logo (Harvard, etc.) ── */
.pub-affil-logo {
  float: right;
  display: block;
  margin: var(--s-1) 0 var(--s-3) var(--s-5);
  max-width: 170px;
  opacity: .85;
  transition: opacity .25s, transform .25s var(--ease);
}
.pub-affil-logo img {
  display: block;
  width: auto;
  height: auto;
  max-width: 170px;
  max-height: 42px;
  object-fit: contain;
  object-position: right center;
}
.pub-row:hover .pub-affil-logo { opacity: 1; transform: translateY(-1px); }

/* API STATUS CARD */
.card-api {
  grid-column: span 2;
}
.api-header {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: var(--s-3);
}
.api-title {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  text-transform: uppercase;
  letter-spacing: .12em;
}
.api-host {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--lime);
}
.api-list { list-style: none; }
.api-list li {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-1) 0;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-2);
}
.api-list code { font-size: inherit; flex: 1; color: var(--text-2); }
.api-method {
  padding: 1px var(--s-2);
  font-size: .58rem;
  font-weight: 700;
  background: rgba(190,242,100,.1);
  color: var(--lime);
  border-radius: var(--r-sm);
  letter-spacing: .06em;
}
.api-state {
  width: 6px; height: 6px;
  border-radius: var(--r-full);
  background: var(--text-dim);
  flex-shrink: 0;
}
.api-state.ok   { background: var(--lime); box-shadow: 0 0 6px var(--lime-glow); }
.api-state.err  { background: var(--rose); }

/* ════════════════════════════════════════════════════════════
   LAB SECTIONS
   ════════════════════════════════════════════════════════════ */
.lab {
  max-width: 1320px;
  margin: 0 auto;
  padding: var(--s-8) var(--s-5);
}
.lab-head { margin-bottom: var(--s-6); max-width: 760px; }
.lab-tag {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  text-transform: uppercase;
  letter-spacing: .12em;
  margin-bottom: var(--s-4);
}
.lab-num {
  display: inline-block;
  padding: var(--s-1) var(--s-3);
  background: rgba(190,242,100,.08);
  color: var(--lime);
  border: 1px solid rgba(190,242,100,.18);
  border-radius: var(--r-sm);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.lab-title {
  font-size: clamp(1.8rem, 3.4vw, 2.6rem);
  font-weight: 500;
  letter-spacing: -.03em;
  line-height: var(--lh-tight);
  margin-bottom: var(--s-4);
}
.lab-title em {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--text);
  font-weight: 400;
}
.lab-deck {
  font-size: var(--fs-md);
  color: var(--text-2);
  line-height: var(--lh-relaxed);
}
.lab-deck a { color: var(--lime); border-bottom: 1px solid rgba(190,242,100,.4); }
.lab-deck em { font-family: var(--font-serif); font-style: italic; color: var(--text); }

.lab-grid { display: grid; gap: var(--s-4); }
.lab-grid.two { grid-template-columns: 1fr 1.4fr; }
.lab-grid.wqi { grid-template-columns: 1fr 1.2fr; }

@media (max-width: 1024px) {
  .lab-grid.two,
  .lab-grid.wqi { grid-template-columns: 1fr; }
}

/* ════════════════════════════════════════════════════════════
   PANELS
   ════════════════════════════════════════════════════════════ */
.panel {
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s-5);
  position: relative;
}
.panel-head {
  display: flex; justify-content: space-between; align-items: center;
  padding-bottom: var(--s-5);
  margin-bottom: var(--s-5);
  border-bottom: 1px solid var(--line);
}
.panel-title {
  display: flex; align-items: center; gap: var(--s-3);
  font-size: var(--fs-md);
  font-weight: 500;
}
.panel-route {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-dim);
  background: var(--bg-1);
  padding: var(--s-1) var(--s-2);
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
}
.panel-status {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  padding: var(--s-1) var(--s-2);
  background: var(--bg-1);
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
}

.dot {
  width: 8px; height: 8px;
  border-radius: var(--r-full);
}
.dot.lime  { background: var(--lime);  box-shadow: 0 0 8px var(--lime-glow); }
.dot.amber { background: var(--amber); box-shadow: 0 0 8px rgba(252,211,77,.25); }
.dot.sky   { background: var(--sky);   box-shadow: 0 0 8px rgba(125,211,252,.3); }

/* ─── form rows ─── */
.control-row {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: var(--s-3);
  align-items: center;
  margin-bottom: var(--s-3);
}
.control-row label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  letter-spacing: .04em;
}
.control-row input[type="text"] {
  height: 36px;
  padding: 0 var(--s-3);
  background: var(--bg-1);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  letter-spacing: .04em;
  transition: border-color .2s, box-shadow .2s;
}
.control-row input[type="text"]:focus {
  outline: none;
  border-color: var(--lime);
  box-shadow: 0 0 0 4px var(--lime-glow);
}

/* ─── Punnett output ─── */
.panel-result {
  margin-top: var(--s-5);
  padding-top: var(--s-5);
  border-top: 1px solid var(--line);
  min-height: 100px;
}
.placeholder {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-dim);
}

.punnett-grid {
  display: grid;
  grid-template-columns: 40px repeat(2, 1fr);
  grid-template-rows: 32px repeat(2, 1fr);
  gap: var(--s-1);
  max-width: 280px;
  margin: 0 auto var(--s-5);
}
.punnett-grid > div {
  background: var(--bg-1);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  display: grid; place-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-base);
  font-weight: 500;
  min-height: 56px;
}
.punnett-grid .punnett-h,
.punnett-grid .punnett-v {
  background: transparent;
  border: none;
  color: var(--lime);
  font-size: var(--fs-md);
  min-height: 0;
}
.punnett-grid .punnett-corner {
  background: transparent;
  border: none;
  min-height: 0;
}
.punnett-grid .punnett-cell.dom {
  background: rgba(190,242,100,.08);
  border-color: rgba(190,242,100,.3);
  color: var(--lime);
}
.punnett-grid .punnett-cell.rec {
  background: rgba(252,211,77,.06);
  border-color: rgba(252,211,77,.2);
  color: var(--amber);
}

.freq-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-2);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}
.freq-list .freq-row {
  display: flex;
  justify-content: space-between;
  padding: var(--s-1) var(--s-2);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}
.freq-list .freq-row b { color: var(--lime); font-weight: 500; }

.ratio-line {
  margin-top: var(--s-3);
  padding: var(--s-2) var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-2);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  text-align: center;
}

/* ─── slider grid ─── */
.slider-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-4) var(--s-5);
  margin-bottom: var(--s-5);
}
.slider { }
.slider-row {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: var(--s-2);
}
.slider-row label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
}
.slider-row .mono {
  font-family: var(--font-mono);
  color: var(--lime);
  margin-left: var(--s-1);
}
.slider-row em {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--text-2);
}
.slider-row output {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text);
  font-weight: 500;
}
.slider input[type="range"] {
  width: 100%;
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  height: 4px;
  background: var(--bg-2);
  border-radius: var(--r-xs);
  outline: none;
  cursor: pointer;
}
.slider input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px; height: 14px;
  border-radius: var(--r-full);
  background: var(--lime);
  border: 2px solid var(--bg-card);
  box-shadow: 0 0 0 1px var(--lime-deep), 0 4px 8px rgba(0,0,0,.4);
  cursor: pointer;
  transition: transform .15s var(--ease), box-shadow .15s;
}
.slider input[type="range"]::-webkit-slider-thumb:hover {
  transform: scale(1.2);
  box-shadow: 0 0 0 1px var(--lime), 0 0 12px var(--lime-glow), 0 4px 8px rgba(0,0,0,.4);
}
.slider input[type="range"]::-moz-range-thumb {
  width: 14px; height: 14px;
  border-radius: var(--r-full);
  background: var(--lime);
  border: 2px solid var(--bg-card);
  cursor: pointer;
}

/* ─── chart ─── */
.chart-wrap {
  margin-top: var(--s-5);
  position: relative;
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s-5) var(--s-4) var(--s-6);
  overflow: hidden;
}
.chart-wrap canvas {
  width: 100%;
  height: 280px;
  display: block;
}
.chart-axis {
  position: absolute;
  top: 10px; left: 16px;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .08em;
}

/* ─── kv grid ─── */
.kv-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--s-3);
  margin-top: var(--s-4);
}
.kv-grid > div {
  padding: var(--s-3) var(--s-3);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.kv-label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--text-mute);
  text-transform: uppercase;
  letter-spacing: .1em;
  margin-bottom: var(--s-1);
}
.kv-value {
  display: block;
  font-size: var(--fs-md);
  color: var(--text);
  font-weight: 500;
}
.kv-value.fixed { color: var(--lime); }
.kv-value.lost  { color: var(--rose); }

@media (max-width: 720px) {
  .kv-grid { grid-template-columns: repeat(2, 1fr); }
  .slider-grid { grid-template-columns: 1fr; }
}

/* ════════════════════════════════════════════════════════════
   LAB 02 - COFFEE
   ════════════════════════════════════════════════════════════ */
.coffee-upload .dropzone {
  display: block;
  position: relative;
  height: 320px;
  background: var(--bg-1);
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-lg);
  cursor: pointer;
  transition: border-color .2s, background .2s;
  overflow: hidden;
}
.coffee-upload .dropzone:hover,
.coffee-upload .dropzone.dragover {
  border-color: var(--amber);
  background: rgba(252,211,77,.04);
}
.drop-prompt {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: var(--s-3);
  color: var(--text-mute);
}
.drop-prompt p { font-family: var(--font-mono); font-size: var(--fs-sm); }
.drop-prompt p.dim { font-size: var(--fs-xs); color: var(--text-dim); }
#leafPreview {
  width: 100%; height: 100%;
  object-fit: contain;
}

.example-row {
  margin-top: var(--s-4);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
}

/* coffee result */
.coffee-output { min-height: 320px; }
.coffee-output.loading {
  display: flex; align-items: center; justify-content: center;
}
.severity-block {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-4);
  margin-bottom: var(--s-5);
  padding: var(--s-4);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.severity-num {
  font-size: 3rem;
  font-weight: 500;
  letter-spacing: -.04em;
  line-height: var(--lh-tight);
  font-feature-settings: 'tnum';
}
.severity-num .pct {
  font-size: 1.2rem;
  color: var(--text-mute);
  margin-left: var(--s-1);
  font-weight: 400;
}
.severity-cat {
  display: inline-block;
  padding: var(--s-1) var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .08em;
  text-transform: uppercase;
  font-weight: 600;
  border-radius: var(--r-sm);
  margin-bottom: var(--s-2);
}
.severity-cat.healthy  { background: rgba(190,242,100,.12); color: var(--lime); border: 1px solid rgba(190,242,100,.3); }
.severity-cat.mild     { background: rgba(252,211,77,.12);  color: var(--amber); border: 1px solid rgba(252,211,77,.3); }
.severity-cat.moderate { background: rgba(251,146,60,.12);  color: #FB923C; border: 1px solid rgba(251,146,60,.3); }
.severity-cat.severe   { background: rgba(253,164,175,.12); color: var(--rose); border: 1px solid rgba(253,164,175,.3); }
.severity-info {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: var(--lh-normal);
}
.severity-info em {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--text);
}

.pixel-bars { margin-top: var(--s-3); }
.pixel-bar {
  margin-bottom: var(--s-2);
}
.pixel-bar-row {
  display: flex; justify-content: space-between;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  margin-bottom: var(--s-1);
}
.pixel-bar-row .label { color: var(--text-mute); }
.pixel-bar-row .value { color: var(--text); font-weight: 500; }
.pixel-bar-track {
  height: 6px;
  background: var(--bg-2);
  border-radius: var(--r-sm);
  overflow: hidden;
}
.pixel-bar-fill {
  height: 100%;
  background: var(--lime);
  border-radius: var(--r-sm);
  transition: width .8s var(--ease-out);
}

/* ════════════════════════════════════════════════════════════
   LAB 03 - AQUAPONICS
   ════════════════════════════════════════════════════════════ */
.wqi-slider {
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--line);
}
.wqi-slider:last-child { border-bottom: none; }
.wqi-row {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: var(--s-2);
}
.wqi-row label {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text);
}
.wqi-row output {
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  color: var(--sky);
  font-weight: 600;
}
.wqi-target {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--text-dim);
  margin-top: var(--s-2);
  letter-spacing: .04em;
}
.wqi-slider input[type="range"] {
  width: 100%;
  -webkit-appearance: none; appearance: none;
  height: 4px;
  background: var(--bg-2);
  border-radius: var(--r-xs);
  outline: none;
}
.wqi-slider input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px; height: 14px;
  border-radius: var(--r-full);
  background: var(--sky);
  border: 2px solid var(--bg-card);
  box-shadow: 0 0 0 1px var(--sky-deep);
  cursor: pointer;
  transition: transform .15s var(--ease);
}
.wqi-slider input[type="range"]::-webkit-slider-thumb:hover {
  transform: scale(1.2);
  box-shadow: 0 0 0 1px var(--sky), 0 0 12px rgba(125,211,252,.4);
}
.wqi-slider.warn input[type="range"]::-webkit-slider-thumb { background: var(--amber); box-shadow: 0 0 0 1px var(--amber-deep); }
.wqi-slider.bad  input[type="range"]::-webkit-slider-thumb { background: var(--rose); box-shadow: 0 0 0 1px var(--rose-deep); }

/* gauge */
.gauge-wrap {
  position: relative;
  text-align: center;
  margin-bottom: var(--s-5);
}
.gauge { width: 100%; max-width: 320px; height: auto; color: var(--bg-2); }
.gauge-track  { color: var(--bg-2); }
.gauge-arc {
  stroke: var(--lime);
  stroke-dashoffset: 0;
  transition: stroke .4s, stroke-dasharray .8s var(--ease-out);
  filter: drop-shadow(0 0 6px var(--lime-glow));
}
.gauge-arc.warn { stroke: var(--amber); filter: drop-shadow(0 0 6px rgba(252,211,77,.35)); }
.gauge-arc.bad  { stroke: var(--rose);  filter: drop-shadow(0 0 6px rgba(253,164,175,.35)); }
.gauge-center {
  position: absolute;
  bottom: 6px;
  left: 50%;
  transform: translateX(-50%);
  text-align: center;
}
.gauge-value {
  font-size: 2.4rem;
  font-weight: 500;
  letter-spacing: -.04em;
  line-height: var(--lh-tight);
}
.gauge-label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  text-transform: uppercase;
  letter-spacing: .1em;
  margin-top: var(--s-1);
}

/* dual bars */
.dual-bars { margin-bottom: var(--s-5); }
.dual-bar { margin-bottom: var(--s-3); }
.dual-row {
  display: flex; justify-content: space-between;
  font-size: var(--fs-sm);
  margin-bottom: var(--s-2);
}
.dual-row .mono { font-family: var(--font-mono); color: var(--text); font-weight: 600; }
.bar-track {
  height: 6px;
  background: var(--bg-2);
  border-radius: var(--r-sm);
  overflow: hidden;
}
.bar-fill {
  height: 100%;
  background: var(--lime);
  border-radius: var(--r-sm);
  transition: width .8s var(--ease-out), background .3s;
}
.bar-fill.amber { background: var(--amber); }

/* recommendations */
.recs {
  border-top: 1px solid var(--line);
  padding-top: var(--s-4);
}
.recs-head {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  text-transform: uppercase;
  letter-spacing: .12em;
  margin-bottom: var(--s-3);
}
.rec-item {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-3);
  margin-bottom: var(--s-2);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-left: 3px solid var(--amber);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
}
.rec-item.critical { border-left-color: var(--rose); }
.rec-item .rec-key {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  letter-spacing: .04em;
  text-transform: uppercase;
}
.rec-item .rec-val {
  font-family: var(--font-mono);
  color: var(--amber);
  font-size: var(--fs-xs);
}
.rec-item.critical .rec-val { color: var(--rose); }
.rec-item .rec-advice {
  grid-column: 1 / -1;
  color: var(--text-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  margin-top: var(--s-1);
}

/* ════════════════════════════════════════════════════════════
   VITA
   ════════════════════════════════════════════════════════════ */
.vita-section {
  max-width: 1320px;
  margin: 0 auto;
  padding: var(--s-8) var(--s-5);
}
.vita-table {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--line);
}
.vita-row {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: var(--s-5);
  padding: var(--s-5) 0;
  border-bottom: 1px solid var(--line);
  align-items: baseline;
  transition: padding .2s var(--ease);
}
.vita-row:hover { padding-left: var(--s-2); }
.vita-year {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-mute);
  letter-spacing: .04em;
}
.vita-title {
  font-size: var(--fs-base);
  font-weight: 500;
  margin-bottom: var(--s-1);
  letter-spacing: -.005em;
}
.vita-org {
  font-size: var(--fs-sm);
  color: var(--text-mute);
}
.badge {
  display: inline-block;
  margin-left: var(--s-2);
  padding: var(--s-1) var(--s-3);
  background: rgba(190,242,100,.1);
  color: var(--lime);
  border: 1px solid rgba(190,242,100,.3);
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: .12em;
  vertical-align: middle;
}

@media (max-width: 720px) {
  .vita-row { grid-template-columns: 1fr; gap: var(--s-2); }
}

/* ════════════════════════════════════════════════════════════
   FOOTER
   ════════════════════════════════════════════════════════════ */
.foot {
  margin-top: var(--s-6);
  border-top: 1px solid var(--line);
  background: var(--bg-1);
  padding: var(--s-8) var(--s-5) var(--s-6);
}
.foot-grid {
  max-width: 1320px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--s-6);
}
.foot-label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .12em;
  margin-bottom: var(--s-4);
}
.foot-link {
  display: inline-block;
  font-size: var(--fs-md);
  color: var(--text);
  margin-bottom: var(--s-2);
  border-bottom: 1px solid transparent;
  transition: color .2s, border-color .2s;
}
.foot-link:hover { color: var(--lime); border-bottom-color: var(--lime); }
.foot-line {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: var(--lh-relaxed);
}
.foot-line code {
  font-family: var(--font-mono);
  color: var(--lime);
}
.foot-meta { text-align: right; }
@media (max-width: 720px) {
  .foot-grid { grid-template-columns: 1fr 1fr; }
  .foot-meta { text-align: left; }
}

/* ════════════════════════════════════════════════════════════
   TOAST
   ════════════════════════════════════════════════════════════ */
.toast {
  position: fixed;
  bottom: 28px; left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--bg-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  padding: var(--s-3) var(--s-5);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text);
  box-shadow: 0 16px 48px rgba(0,0,0,.6);
  z-index: 1000;
  opacity: 0;
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.toast.visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.toast.error { border-color: rgba(253,164,175,.35); color: var(--rose); }

/* ════════════════════════════════════════════════════════════
   GALLERY (Harvard HPAIR photos)
   ════════════════════════════════════════════════════════════ */
.gallery {
  margin-top: 22px;
  padding-top: var(--s-5);
  border-top: 1px dashed var(--line);
}
.gallery-caption {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .12em;
  color: var(--text-mute);
  margin-bottom: var(--s-4);
  text-transform: uppercase;
}
.gallery-label {
  display: inline-block;
  padding: var(--s-1) var(--s-3);
  background: rgba(190,242,100,.08);
  color: var(--lime);
  border: 1px solid rgba(190,242,100,.22);
  border-radius: var(--r-sm);
  margin-right: var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: .12em;
  font-weight: 700;
  text-transform: uppercase;
}
/* infinite-loop marquee carousel */
.carousel {
  position: relative;
  overflow: hidden;
  -webkit-mask: linear-gradient(90deg, transparent, black 4%, black 96%, transparent);
          mask: linear-gradient(90deg, transparent, black 4%, black 96%, transparent);
}
.carousel-track {
  display: flex;
  width: max-content;
  gap: var(--s-3);
  animation: carousel-scroll 38s linear infinite;
  will-change: transform;
}
.carousel:hover .carousel-track,
.carousel:focus-within .carousel-track {
  animation-play-state: paused;
}
@keyframes carousel-scroll {
  0%   { transform: translate3d(0, 0, 0); }
  100% { transform: translate3d(calc(-50% - 5px), 0, 0); }
}
.gallery-item {
  display: block;
  flex: 0 0 auto;
  width: 240px;
  height: 240px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--bg-2);
  overflow: hidden;
  cursor: zoom-in;
  position: relative;
  transition: transform .25s var(--ease), border-color .25s, box-shadow .25s;
}
@media (max-width: 600px) {
  .gallery-item { width: 180px; height: 180px; }
}
.gallery-item:hover {
  transform: translateY(-2px) scale(1.02);
  border-color: rgba(190,242,100,.4);
  box-shadow: 0 8px 24px rgba(0,0,0,.4), 0 0 0 1px rgba(190,242,100,.15);
  z-index: 2;
}
.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: saturate(.92) contrast(1.02);
  transition: filter .3s var(--ease), transform .4s var(--ease);
}
.gallery-item:hover img {
  filter: saturate(1.08) contrast(1.05);
  transform: scale(1.04);
}
.gallery-item::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 60%, rgba(7,8,10,.5) 100%);
  pointer-events: none;
  opacity: 0;
  transition: opacity .25s;
}
.gallery-item:hover::after { opacity: 1; }

/* ════════════════════════════════════════════════════════════
   LIGHTBOX
   ════════════════════════════════════════════════════════════ */
.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(7,8,10,.95);
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5vh 6vw;
  cursor: zoom-out;
  animation: lb-fade-in .3s var(--ease);
}
.lightbox[hidden] { display: none; }
@keyframes lb-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.lightbox img {
  max-width: 100%;
  max-height: 90vh;
  object-fit: contain;
  border-radius: var(--r-md);
  box-shadow: 0 30px 80px rgba(0,0,0,.6);
  animation: lb-pop .35s var(--ease-out);
}
@keyframes lb-pop {
  from { opacity: 0; transform: scale(.96); }
  to { opacity: 1; transform: scale(1); }
}

.lightbox-close,
.lightbox-prev,
.lightbox-next {
  position: absolute;
  background: rgba(20,21,27,.7);
  border: 1px solid var(--line-strong);
  color: var(--text);
  width: 44px;
  height: 44px;
  border-radius: var(--r-full);
  display: grid;
  place-items: center;
  cursor: pointer;
  font-size: 1.4rem;
  line-height: var(--lh-tight);
  font-family: var(--font-mono);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  transition: background .2s, border-color .2s, transform .15s;
}
.lightbox-close:hover,
.lightbox-prev:hover,
.lightbox-next:hover {
  background: var(--bg-3);
  border-color: var(--lime);
  color: var(--lime);
}
.lightbox-close { top: 24px; right: 24px; }
.lightbox-prev  { left: 24px; top: 50%; transform: translateY(-50%); font-size: 1.8rem; }
.lightbox-next  { right: 24px; top: 50%; transform: translateY(-50%); font-size: 1.8rem; }
.lightbox-prev:hover { transform: translateY(-50%) scale(1.08); }
.lightbox-next:hover { transform: translateY(-50%) scale(1.08); }

.lightbox-caption {
  position: absolute;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .14em;
  color: var(--text-mute);
  background: rgba(20,21,27,.7);
  padding: var(--s-2) var(--s-4);
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  white-space: nowrap;
}

@media (max-width: 600px) {
  .lightbox-prev { left: 12px; width: 38px; height: 38px; }
  .lightbox-next { right: 12px; width: 38px; height: 38px; }
  .lightbox-close { top: 14px; right: 14px; width: 38px; height: 38px; }
}

/* ════════════════════════════════════════════════════════════
   PROJECTS - feature rows (replaces lab demos)
   ════════════════════════════════════════════════════════════ */
.proj-list {
  display: grid;
  gap: 0;
  border-top: 2px solid var(--ink);
  border-top-color: var(--line-strong);
}
.proj-row {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: var(--s-8);
  padding: var(--s-7) 0;
  border-bottom: 1px solid var(--line);
  align-items: start;
}
.proj-row:last-child { border-bottom: 2px solid var(--line-strong); }
.proj-side {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
.proj-side-num {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  font-size: 4.6rem;
  color: var(--lime);
  line-height: var(--lh-tight);
  letter-spacing: -.04em;
}
.proj-side-meta {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-mute);
  line-height: var(--lh-relaxed);
}
.proj-side-meta strong {
  display: block;
  color: var(--lime);
  letter-spacing: .15em;
  margin-top: var(--s-3);
  margin-bottom: var(--s-1);
  font-weight: 600;
  font-size: var(--fs-2xs);
}
.proj-side-meta strong:first-of-type { margin-top: var(--s-2); }
.proj-side-meta em { font-style: normal; color: var(--text); }

.proj-side-logo {
  display: inline-flex;
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px dashed var(--line);
  align-self: flex-start;
  transition: opacity .25s, transform .25s var(--ease);
  opacity: .65;
}
.proj-side-logo img {
  display: block;
  width: auto;
  height: auto;
  max-width: 180px;
  max-height: 96px;
  object-fit: contain;
  object-position: left center;
  filter: saturate(.92);
  transition: filter .25s;
}
.proj-row:hover .proj-side-logo { opacity: 1; transform: translateY(-1px); }
.proj-row:hover .proj-side-logo img { filter: saturate(1.08); }

.proj-tag-pill {
  display: inline-block;
  align-self: flex-start;
  padding: var(--s-1) var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  border-radius: var(--r-sm);
}
.proj-tag-pill.software { background: rgba(190,242,100,.1); color: var(--lime); border: 1px solid rgba(190,242,100,.3); }
.proj-tag-pill.thesis   { background: rgba(252,211,77,.1); color: var(--amber); border: 1px solid rgba(252,211,77,.3); }
.proj-tag-pill.research { background: rgba(125,211,252,.1); color: var(--sky); border: 1px solid rgba(125,211,252,.3); }

.proj-body { max-width: 760px; }
.proj-row-title {
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  font-weight: 500;
  line-height: var(--lh-snug);
  letter-spacing: -.02em;
  color: var(--text);
  margin-bottom: var(--s-4);
}
.proj-row-title em {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--text);
  font-weight: 400;
}
.proj-row-byline {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-mute);
  margin-bottom: var(--s-5);
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--line);
}
.proj-row-byline a { color: var(--lime); border-bottom: 1px solid rgba(190,242,100,.3); }
.proj-row-byline a:hover { border-color: var(--lime); }

.proj-row-lead {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--fs-lg);
  line-height: var(--lh-normal);
  color: var(--text);
  font-weight: 300;
  margin-bottom: var(--s-5);
}
.proj-row-lead em { color: var(--text); }

.proj-row-text {
  font-size: var(--fs-base);
  line-height: var(--lh-relaxed);
  color: var(--text-2);
  margin-bottom: var(--s-5);
}
.proj-row-text strong { color: var(--text); font-weight: 600; }
.proj-row-text em {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--text);
}

.proj-row-keywords {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .04em;
  color: var(--text-mute);
  padding-top: var(--s-4);
  border-top: 1px dashed var(--line);
  line-height: var(--lh-relaxed);
}
.proj-row-keywords strong {
  color: var(--lime);
  font-weight: 600;
  letter-spacing: .15em;
  margin-right: var(--s-3);
  text-transform: uppercase;
  font-size: var(--fs-2xs);
}

.proj-row-link {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-5);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--lime);
  border-bottom: 1.5px solid var(--lime);
  padding-bottom: var(--s-1);
  transition: gap .2s var(--ease);
}
.proj-row-link:hover { gap: var(--s-3); }

/* ── Video / media block (Mi Salvador demo) ── */
.proj-media {
  position: relative;
  margin: var(--s-5) 0;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  background: #000;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.4);
  transition: border-color .25s, box-shadow .25s;
}
.proj-media:hover {
  border-color: rgba(190,242,100, 0.3);
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(190,242,100, 0.15);
}
.proj-video {
  display: block;
  width: 100%;
  height: auto;
  max-height: 540px;
  object-fit: contain;
  background: #000;
}
.proj-media-caption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-3) var(--s-4);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .12em;
  color: var(--text-mute);
  text-transform: uppercase;
  border-top: 1px solid var(--line);
  background: var(--bg-1);
}
.proj-media-tag {
  display: inline-block;
  padding: var(--s-1) var(--s-3);
  background: rgba(190,242,100, 0.1);
  color: var(--lime);
  border: 1px solid rgba(190,242,100, 0.25);
  border-radius: var(--r-sm);
  font-weight: 700;
  letter-spacing: .15em;
}

/* ── Module grid (Mi Salvador feature breakdown) ── */
.proj-modules {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin: 22px 0 var(--s-2);
}
.proj-module {
  flex: 1 1 220px;        /* base 220px wide; grow to share remaining row width */
  padding: var(--s-4);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-left: 3px solid var(--lime);
  border-radius: var(--r-md);
  transition: background .25s, border-color .25s, transform .25s var(--ease);
}
.proj-module:hover {
  background: var(--bg-2);
  border-left-color: var(--lime);
  transform: translateY(-2px);
}
.proj-module-h {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--lime);
  margin-bottom: var(--s-2);
  font-weight: 700;
}
.proj-module-b {
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--text-2);
}

@media (max-width: 980px) {
  .proj-row { grid-template-columns: minmax(0, 1fr); gap: var(--s-5); }
  .proj-side-num { font-size: 3rem; }
}
/* Globally: proj-row grid items must shrink-fit, never overflow.
   Prevents the .carousel-track (width: max-content) inside .proj-body
   from forcing the column wider than the viewport at tablet widths. */
.proj-row > * { min-width: 0; }
.proj-body { min-width: 0; }

/* ════════════════════════════════════════════════════════════
   RESEARCH STATEMENT
   ════════════════════════════════════════════════════════════ */
.statement-section { padding-top: 80px; padding-bottom: var(--s-6); }

.statement-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: var(--s-8);
  align-items: start;
}
@media (max-width: 1024px) {
  .statement-grid { grid-template-columns: 1fr; gap: var(--s-6); }
}

.statement-prose {
  font-size: var(--fs-base);
  line-height: var(--lh-relaxed);
  color: var(--text-2);
  max-width: 720px;
}
.statement-prose p + p,
.statement-prose ol + p,
.statement-prose p + ol { margin-top: 22px; }
.statement-prose em {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--text);
  font-size: 1.05em;
}
.statement-prose strong {
  color: var(--text);
  font-weight: 600;
}
.statement-lead {
  font-size: var(--fs-lg);
  line-height: var(--lh-relaxed);
  color: var(--text);
  font-weight: 400;
  padding-bottom: var(--s-5);
  margin-bottom: var(--s-5);
  border-bottom: 1px solid var(--line);
}
.statement-lead em { color: var(--text); }

.statement-list {
  list-style: none;
  counter-reset: research;
  margin-top: var(--s-2);
}
.statement-list li {
  counter-increment: research;
  position: relative;
  padding: var(--s-5) 0 var(--s-5) var(--s-8);
  border-top: 1px dashed var(--line);
  font-size: var(--fs-md);
}
.statement-list li:last-child { border-bottom: 1px dashed var(--line); }
.statement-list li::before {
  content: counter(research, decimal-leading-zero);
  position: absolute;
  left: 0; top: 22px;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--lime);
  letter-spacing: .08em;
  padding: var(--s-1) var(--s-2);
  background: rgba(190,242,100,.08);
  border: 1px solid rgba(190,242,100,.2);
  border-radius: var(--r-sm);
}
.statement-list strong { color: var(--text); display: inline-block; margin-right: var(--s-1); }

.statement-pull {
  margin-top: var(--s-6);
  padding: var(--s-5);
  border-left: 3px solid var(--lime);
  background: linear-gradient(90deg, rgba(190,242,100,.04), transparent);
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--fs-lg);
  line-height: var(--lh-normal);
  color: var(--text);
  border-radius: 0 8px 8px 0;
}

/* sidebar meta blocks */
.statement-side {
  position: sticky;
  top: 80px;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
@media (max-width: 1024px) {
  .statement-side { position: static; }
}
.statement-meta-block {
  padding: var(--s-5) var(--s-5);
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.statement-meta-block.highlight {
  border-color: rgba(190,242,100,.25);
  background: linear-gradient(180deg, rgba(190,242,100,.04), var(--bg-card));
}
.meta-block-label {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-mute);
  margin-bottom: var(--s-3);
}
.meta-block-value {
  font-size: var(--fs-base);
  font-weight: 500;
  color: var(--text);
  margin-bottom: var(--s-1);
  letter-spacing: -.01em;
}
.meta-block-sub {
  font-size: var(--fs-sm);
  color: var(--text-mute);
  line-height: var(--lh-normal);
  margin-top: var(--s-2);
}
.meta-block-link {
  display: block;
  font-size: var(--fs-md);
  color: var(--lime);
  padding: var(--s-2) 0;
  border-top: 1px dashed rgba(190,242,100,.2);
  margin-top: var(--s-2);
  transition: padding-left .2s var(--ease);
}
.meta-block-link:first-of-type { border-top: 0; margin-top: var(--s-1); }
.meta-block-link:hover { padding-left: var(--s-1); }
.meta-list {
  list-style: none;
  display: grid;
  gap: var(--s-1);
}
.meta-list li {
  font-size: var(--fs-sm);
  color: var(--text-2);
  font-family: var(--font-mono);
  padding: var(--s-1) 0;
  border-bottom: 1px dashed var(--line);
}
.meta-list li:last-child { border-bottom: none; }
.meta-list li::before { content: '· '; color: var(--lime); }

/* ════════════════════════════════════════════════════════════
   RESEARCH SIGNIFICANCE FOOTERS (per lab)
   ════════════════════════════════════════════════════════════ */
.significance {
  margin-top: var(--s-5);
  padding: var(--s-5) var(--s-6);
  background: linear-gradient(180deg, rgba(190,242,100,.025), transparent 60%), var(--bg-card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--lime);
  border-radius: var(--r-md);
}
.sig-label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--lime);
  margin-bottom: var(--s-4);
}
.sig-body {
  font-size: .96rem;
  color: var(--text-2);
  line-height: var(--lh-relaxed);
}
.sig-body em {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--text);
}
.sig-body strong { color: var(--text); }
.sig-questions {
  list-style: none;
  margin: var(--s-4) 0;
  display: grid;
  gap: var(--s-3);
}
.sig-questions li {
  padding: var(--s-3) var(--s-4);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
}
.sig-questions strong {
  color: var(--lime);
  font-family: var(--font-mono);
  font-weight: 600;
  margin-right: var(--s-2);
  font-size: .82em;
  letter-spacing: .04em;
}
.sig-refs {
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px dashed var(--line);
  font-size: var(--fs-sm);
  color: var(--text-mute);
  line-height: var(--lh-relaxed);
}
.sig-refs strong {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--lime);
  letter-spacing: .1em;
  text-transform: uppercase;
  margin-right: var(--s-2);
}
.sig-refs em {
  color: var(--text-2);
  font-family: var(--font-serif);
  font-style: italic;
}

/* ════════════════════════════════════════════════════════════
   PUBLICATIONS
   ════════════════════════════════════════════════════════════ */
.pubs {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--line);
}
.pub-row {
  display: grid;
  grid-template-columns: 100px minmax(0, 1fr);
  gap: var(--s-6);
  padding: var(--s-5) 0;
  border-bottom: 1px solid var(--line);
  align-items: baseline;
  transition: padding .2s var(--ease);
}
.pub-row > * { min-width: 0; }
.pub-row:hover { padding-left: var(--s-2); }
.pub-year {
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--text);
  letter-spacing: .04em;
}
.pub-status {
  display: inline-block;
  padding: var(--s-1) var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  border-radius: var(--r-sm);
  margin-bottom: var(--s-3);
}
.status-prep      { background: rgba(252,211,77,.1);  color: var(--amber); border: 1px solid rgba(252,211,77,.25); }
.status-presented { background: rgba(190,242,100,.1); color: var(--lime);  border: 1px solid rgba(190,242,100,.3); }
.status-internal  { background: rgba(125,211,252,.1); color: var(--sky);   border: 1px solid rgba(125,211,252,.3); }
.status-software  { background: rgba(255,255,255,.05); color: var(--text-2); border: 1px solid var(--line-strong); }

/* ── Symbol prefixes on status pills ─────────────────────────
   Adds redundant non-color signals so colorblind reviewers can
   distinguish prep / presented / internal / software at a glance. */
.pub-status::before {
  margin-right: var(--s-2);
  font-weight: 700;
  display: inline-block;
  transform: translateY(-.5px);
}
.status-prep::before      { content: '◐'; }
.status-presented::before { content: '●'; }
.status-internal::before  { content: '○'; }
.status-software::before  { content: '⌬'; }

.proj-tag-pill::before {
  margin-right: var(--s-2);
  font-weight: 700;
  display: inline-block;
  transform: translateY(-.5px);
}
.proj-tag-pill.thesis::before   { content: '◐'; }
.proj-tag-pill.software::before { content: '⌬'; }
.proj-tag-pill.research::before { content: '○'; }

.pub-title {
  font-size: var(--fs-base);
  font-weight: 500;
  line-height: var(--lh-snug);
  letter-spacing: -.005em;
  margin-bottom: var(--s-2);
  color: var(--text);
  overflow-wrap: anywhere;
}
.pub-title em {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--text);
  font-weight: 400;
}
.pub-authors {
  font-size: var(--fs-sm);
  color: var(--text-2);
  margin-bottom: var(--s-1);
}
.pub-venue {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-mute);
  line-height: var(--lh-normal);
}
.pub-venue strong { color: var(--text); font-weight: 600; }
.pub-link {
  display: inline-block;
  margin-left: var(--s-2);
  font-size: var(--fs-sm);
  color: var(--lime);
  border-bottom: 1px solid rgba(190,242,100,.3);
  transition: border-color .2s;
}
.pub-link:hover { border-color: var(--lime); }

@media (max-width: 720px) {
  .pub-row { grid-template-columns: 1fr; gap: var(--s-2); }
}

/* ════════════════════════════════════════════════════════════
   DOCUMENTS GRID
   ════════════════════════════════════════════════════════════ */
.docs-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--s-3);
}
@media (max-width: 1100px) { .docs-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 760px)  { .docs-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px)  { .docs-grid { grid-template-columns: 1fr; } }

.doc-card {
  display: grid;
  grid-template-columns: 56px 1fr auto;
  gap: var(--s-4);
  align-items: center;
  padding: var(--s-4);
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: border-color .2s, transform .15s var(--ease), background .2s;
}
.doc-card:hover {
  border-color: var(--line-strong);
  background: var(--bg-card-hov);
  transform: translateY(-2px);
}
.doc-card.primary {
  border-color: rgba(190,242,100,.3);
  background: linear-gradient(180deg, rgba(190,242,100,.04), var(--bg-card));
  grid-column: span 2;
}
.doc-card.primary:hover {
  border-color: var(--lime);
  box-shadow: 0 4px 24px var(--lime-glow);
}
@media (max-width: 760px) { .doc-card.primary { grid-column: span 1; } }

.doc-icon {
  width: 48px; height: 48px;
  display: grid; place-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  font-weight: 700;
  letter-spacing: .04em;
  background: var(--bg-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  color: var(--lime);
}
.doc-card.primary .doc-icon {
  background: rgba(190,242,100,.1);
  border-color: rgba(190,242,100,.3);
  color: var(--lime);
}
.doc-meta { min-width: 0; }
.doc-title {
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--text);
  margin-bottom: var(--s-1);
  letter-spacing: -.005em;
}
.doc-sub {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  line-height: var(--lh-normal);
}
.doc-action {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color .2s;
}
.doc-card:hover .doc-action { color: var(--lime); }

/* ════════════════════════════════════════════════════════════
   REFERENCES & MENTORS
   ════════════════════════════════════════════════════════════ */
.refs-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s-4);
}
@media (max-width: 1180px) { .refs-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .refs-grid { grid-template-columns: 1fr; } }

.ref-card {
  padding: var(--s-5);
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  transition: border-color .2s, transform .2s var(--ease);
}
.ref-card:hover {
  border-color: var(--line-strong);
  transform: translateY(-3px);
}
.ref-tag {
  display: inline-block;
  align-self: flex-start;
  padding: var(--s-1) var(--s-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--lime);
  background: rgba(190,242,100,.08);
  border: 1px solid rgba(190,242,100,.22);
  border-radius: var(--r-sm);
}
.ref-photo {
  width: 84px;
  height: 84px;
  border-radius: var(--r-full);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--bg);
  margin-top: var(--s-2);
  flex-shrink: 0;
  transition: border-color .2s, transform .2s var(--ease);
}
.ref-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: grayscale(.15) contrast(1.02);
  transition: filter .25s;
}
.ref-card:hover .ref-photo {
  border-color: rgba(190,242,100,.45);
  transform: scale(1.03);
}
.ref-card:hover .ref-photo img { filter: grayscale(0) contrast(1.05); }
.ref-photo-initials {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 1.6rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--lime);
  background: linear-gradient(140deg, rgba(190,242,100,.10), rgba(190,242,100,.02));
}
.ref-name {
  font-size: var(--fs-lg);
  font-weight: 500;
  color: var(--text);
  letter-spacing: -.01em;
  line-height: var(--lh-snug);
  margin-top: var(--s-1);
}
.ref-role {
  font-size: var(--fs-sm);
  color: var(--text-2);
  font-style: italic;
  font-family: var(--font-serif);
}
.ref-org {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  letter-spacing: .04em;
  padding-bottom: var(--s-3);
  border-bottom: 1px dashed var(--line);
}
.ref-context {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: var(--lh-relaxed);
  flex-grow: 1;
}
.ref-email {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--lime);
  border-bottom: 1px solid rgba(190,242,100,.3);
  align-self: flex-start;
  transition: border-color .2s;
}
.ref-email:hover { border-color: var(--lime); }
.ref-phone {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mute);
  letter-spacing: .04em;
  margin-top: -4px;
}

/* ════════════════════════════════════════════════════════════
   RESPONSIVE BENTO
   ════════════════════════════════════════════════════════════ */
@media (max-width: 1100px) {
  .card-id       { grid-column: span 6; grid-row: auto; }
  .card-portrait { grid-column: span 6; grid-row: auto; min-height: 300px; }
  .card-stat,
  .card-stack,
  .card-api      { grid-column: span 3; }
}
@media (max-width: 700px) {
  .card-stat,
  .card-stack,
  .card-api,
  .card-id,
  .card-portrait { grid-column: span 6; }
  .bento { gap: var(--s-3); }
  .lab { padding: var(--s-7) var(--s-4); }
  .hero { padding: var(--s-6) var(--s-4) var(--s-4); }
}

/* ════════════════════════════════════════════════════════════
   PHONE FIX PASS  (320 - 480 px)
   Addresses issues found by 3-agent mobile audit.
   Organized by breakpoint, then by section.
   Appended to override earlier rules via cascade order.
   ════════════════════════════════════════════════════════════ */

/* ── Section anchor offset so sticky nav doesn't hide headings ── */
section[id] { scroll-margin-top: 72px; }

/* ── Long URLs / emails should never overflow on any width ── */
.proj-row-byline,
.pub-venue,
.ref-email,
.ref-context,
.foot-line {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* ════════════════════════════════════════════════════════════
   <= 580 px -- collapse the topnav (was 720 px, too late)
   At 580 px the 6 nav links get crushed against the CV button.
   ════════════════════════════════════════════════════════════ */
/* Hide topnav at <=880 (6 links + brand + CTA need ~900 to fit) */
@media (max-width: 880px) {
  .topnav { display: none; }
}
@media (max-width: 580px) {
  .topbar { gap: var(--s-3); padding: 0 var(--s-3); }
  .status-pill { display: none; }
}

/* ════════════════════════════════════════════════════════════
   <= 480 px -- broad mobile (most phones in landscape, big phones)
   ════════════════════════════════════════════════════════════ */
@media (max-width: 480px) {

  /* Hero -- calmer scaling */
  .hero-name { font-size: clamp(2rem, 9vw, 2.8rem); line-height: 1.05; }
  .hero-deck { max-width: 100%; }
  .hero-meta { gap: 6px 10px; }
  .kv { font-size: var(--fs-2xs); padding: 3px 8px; }

  /* Brand logo shrink */
  .logo-c    { font-size: 1.6rem; }
  .logo-rest { font-size: 1.1rem; }
  .logo-row-2 { font-size: 0.5rem; letter-spacing: 0.2em; }

  /* CV button -- meet 44 px touch target */
  .btn { min-height: 44px; padding: 12px var(--s-4); }

  /* Section padding -- was 48px / 16px at 700px, tighten further */
  .lab { padding: var(--s-7) var(--s-3); }
  .vita-section { padding: var(--s-7) var(--s-3); }   /* vita not in .lab class */

  /* Bento cards -- tighter padding */
  .card { padding: var(--s-4); }
  .card-id { padding: var(--s-5) var(--s-4); }
  .card-portrait { min-height: 280px; }

  /* Working Stack chips -- tighter */
  .chip { padding: 4px 8px; font-size: var(--fs-2xs); }

  /* Project sidebar -- shrink the giant italic number */
  .proj-side-num { font-size: 2.4rem; }
  .proj-side-logo img { max-width: 120px; max-height: 64px; }
  .proj-row { gap: var(--s-4); padding: var(--s-6) 0; }

  /* Project title and lead -- tighten on phone */
  .proj-row-title { font-size: 1.35rem; }
  .proj-row-lead { font-size: var(--fs-md); }

  /* Statement pull-quote -- was eating 25% of viewport in padding */
  .statement-pull { padding: var(--s-3) var(--s-4); border-left-width: 2px; font-size: var(--fs-base); }
  .statement-prose { padding: 0; }

  /* Publication rows: kill the float so Harvard logo doesn't overlap title */
  .pub-affil-logo {
    float: none;
    display: block;
    margin: var(--s-3) 0 var(--s-4) 0;
    max-width: 130px;
  }
  .pub-affil-logo img { max-height: 32px; }

  /* Reference cards -- tight padding */
  .ref-card { padding: var(--s-4); }
  .ref-name { line-height: 1.2; overflow-wrap: break-word; hyphens: auto; }
  .ref-email {
    display: inline-block;
    padding: 10px 0;       /* fat touch target without changing visual weight too much */
    min-height: 40px;
  }
  .ref-phone { margin-top: 0; }

  /* Vita -- stack badge below title so it doesn't break the title line */
  .vita-title { display: flex; flex-wrap: wrap; gap: var(--s-1); align-items: baseline; }
  .badge { margin-left: 0; align-self: flex-start; }
  .vita-year { font-size: var(--fs-xs); }

  /* Footer -- single column at this width (was still 2-col until 720 px) */
  .foot-grid { grid-template-columns: 1fr; gap: var(--s-5); }
  .foot-meta, .foot-disclaimer { text-align: left; }

  /* Lightbox -- bigger tap targets, tighter image padding */
  .lightbox { padding: 5vh 4vw; }
  .lightbox-prev, .lightbox-next {
    width: 44px; height: 44px; font-size: 1.4rem;
  }
  .lightbox-prev { left: 8px; }
  .lightbox-next { right: 8px; }
  .lightbox-close { top: 12px; right: 12px; width: 44px; height: 44px; }

  /* Doc cards -- tighter on small screens */
  .doc-card { padding: var(--s-4); gap: var(--s-3); }

  /* Background grid -- bigger cells = fewer paints on cheap phones */
  body::before { background-size: 80px 80px; }
}

/* ════════════════════════════════════════════════════════════
   <= 390 px -- narrow phones (iPhone 13/14 default = 390)
   ════════════════════════════════════════════════════════════ */
@media (max-width: 390px) {
  .lab { padding: var(--s-7) var(--s-3); }
  .hero { padding: var(--s-6) var(--s-3) var(--s-3); }
  .gallery-item { width: 140px; height: 140px; }   /* was 180 px */
  .proj-side-num { font-size: 2rem; }
  .ref-card { padding: var(--s-3); }
  .ref-name { font-size: var(--fs-base); }
}

/* ════════════════════════════════════════════════════════════
   <= 360 px -- very narrow (older Androids, iPhone SE = 375 borderline)
   ════════════════════════════════════════════════════════════ */
@media (max-width: 360px) {
  .hero-name { font-size: 1.75rem; }
  .lab-title { font-size: clamp(1.4rem, 6vw, 1.8rem); }
  .stat-value { font-size: 2rem; }
  .ref-name { font-size: var(--fs-md); line-height: 1.18; }
  .doc-card { padding: var(--s-3); font-size: var(--fs-sm); }
}

/* ── PHONE FIX v2: gallery overflow + caption wrapping ─────────
   Reported visible bug: Auburn carousel pushed off-screen right
   on iPhone 13/14, leaving empty left half. Caption text crammed.
   Defensive fixes: enforce overflow:hidden on carousel, make
   caption wrap cleanly, prevent proj-body from being wider than
   its container due to grid min-width:auto behavior.            */
@media (max-width: 480px) {
  /* Hard-clip the carousel so the marquee animation can't bleed
     past the viewport. The track inside is intentionally wider. */
  .gallery, .carousel {
    max-width: 100%;
    overflow: hidden;
  }
  .carousel-track { will-change: transform; }

  /* Caption was crammed: "GALLERY * AUBURN UNIVERSITY * E.W. SHELL
     FISHERIES CENTER * SEP-DEC 2025 * HOVER TO PAUSE * CLICK TO ENLARGE"
     forced the parent wider on phone. Allow proper wrap. */
  .gallery-caption {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 8px;
    line-height: var(--lh-snug);
    font-size: var(--fs-2xs);
    margin-bottom: var(--s-3);
  }
  .gallery-label { white-space: nowrap; }

  /* Belt-and-braces: every flex/grid child in the project & pub rows
     gets min-width:0 so it can never push past its column. */
  .proj-row > *, .pub-row > *, .ref-card > *, .doc-card > * {
    min-width: 0;
  }
  .proj-body { max-width: 100%; }

  /* Mid-row carousel images: if 180px (the 600px breakpoint)
     still applies, force smaller here regardless. */
  .gallery-item { width: 140px; height: 140px; flex-shrink: 0; }
}

/* Even tighter for sub-380px phones */
@media (max-width: 380px) {
  .gallery-item { width: 120px; height: 120px; }
  .gallery-caption { font-size: 0.625rem; }
}

/* ── PHONE FIX v3: pill wrap-on-2-lines bug ─────────────────────
   Found via preview inspection at 320 + 390 + 414 px:
     .lab-num "§ 03" → wraps "§" to one line, "03" to next
     .badge "GPA 9.2/10" → wraps similarly
   Both should always be a single horizontal token.            */
.lab-num,
.badge,
.proj-tag-pill,
.pub-status,
.gallery-label {
  white-space: nowrap;
}

/* "Hover to pause" caption text is misleading on touch devices.
   Hide it on phones; touch users tap to enlarge instead.         */
@media (max-width: 720px) and (hover: none) {
  .gallery-caption .hover-hint { display: none; }
}

/* ── PHONE FIX v4: edge cases from 3-agent verification ─────── */

/* Wrap-protection on more compact labels */
.status-label,
.portrait-loc,
.hero-roles .sep {
  white-space: nowrap;
}

/* Long compound terms in body emphasis ("knowledge-distilled",
   "Hemileia vastatrix") shouldn't auto-hyphenate mid-word.    */
.statement-prose em,
.proj-row-text em,
.proj-row-lead em,
.pub-title em {
  hyphens: manual;
}

/* Compound nouns in meta sub lines shouldn't break across words */
.meta-block-sub { word-break: keep-all; }

/* ── Touch targets for inline body-text links ──────────────────
   Every inline lime link gets enough vertical hit area for thumbs
   without changing visual weight (kept inline-block + padding).  */
@media (max-width: 480px) {
  .lab-deck a,
  .proj-row-byline a,
  .pub-link,
  .proj-row-link,
  .meta-block-link,
  .foot-link,
  .doc-action,
  .stat-link,
  .ref-email {
    display: inline-block;
    padding: 10px 0;
    min-height: 44px;
    line-height: 1.4;
  }
}

/* ── Section header rhythm + pub-row stacking gap ───────────── */
@media (max-width: 480px) {
  .lab-head { margin-bottom: var(--s-5); }   /* was --s-6 = too tall on phone */
  .pub-row > .pub-year { margin-bottom: var(--s-3); }
}

/* ════════════════════════════════════════════════════════════
   LOCATION MAP (§ 07)
   MapLibre GL with OpenFreeMap dark vector tiles + a glassmorphism
   info card and a pulsing lime marker.
   ════════════════════════════════════════════════════════════ */

.map-wrap {
  position: relative;
  width: 100%;
  height: 480px;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line-strong);
  box-shadow:
    0 0 0 1px rgba(190,242,100,.06),
    0 24px 60px rgba(0,0,0,.55),
    inset 0 1px 0 rgba(255,255,255,.04);
  background: var(--bg-card);
}

.location-map {
  width: 100%;
  height: 100%;
  position: relative;
}

/* CRITICAL: dark-mode the light "liberty" tiles via CSS filter.
   invert flips light to dark, hue-rotate restores colour, then we
   tone down saturation and slightly tint to harmonize with the
   lime accent. Roads, labels, water, building outlines all stay
   readable -- much more visible than the prebaked dark style.    */
.location-map .maplibregl-canvas {
  filter: invert(1) hue-rotate(180deg) saturate(.65) brightness(1.12) contrast(1.0);
}
/* Markers are HTML overlays, NOT on the canvas. Counter-invert them
   so the lime stays lime instead of getting flipped to magenta.   */
.location-map .maplibregl-marker { filter: invert(1) hue-rotate(180deg); }

/* MapLibre default canvas tweaks for dark theme */
.maplibregl-canvas { outline: none; }
.maplibregl-ctrl-group {
  background: rgba(20,21,27,.75) !important;
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border: 1px solid var(--line-strong) !important;
  box-shadow: 0 8px 24px rgba(0,0,0,.5) !important;
}
.maplibregl-ctrl-group button { background-color: transparent !important; }
.maplibregl-ctrl-group button span { filter: invert(1) brightness(.95); }
.maplibregl-ctrl-group button:hover { background-color: rgba(190,242,100,.08) !important; }

/* ── Glassmorphism info card overlaying the top-left of the map ── */
.map-card {
  position: absolute;
  top: 20px;
  left: 20px;
  max-width: 290px;
  padding: 18px 20px;
  background: rgba(14,15,19,.72);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  backdrop-filter: blur(20px) saturate(1.4);
  border: 1px solid rgba(190,242,100,.22);
  border-radius: var(--r-md);
  box-shadow:
    0 1px 0 rgba(255,255,255,.05) inset,
    0 8px 32px rgba(0,0,0,.45);
  z-index: 2;
  transition: transform .25s var(--ease), border-color .25s;
}
.map-card:hover {
  transform: translateY(-2px);
  border-color: rgba(190,242,100,.4);
}

.map-card-tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--lime);
  margin-bottom: var(--s-3);
  white-space: nowrap;
}
.map-card-dot {
  width: 8px;
  height: 8px;
  border-radius: var(--r-full);
  background: var(--lime);
  box-shadow: 0 0 8px var(--lime-glow);
  animation: map-pulse-dot 1.8s ease-in-out infinite;
}
@keyframes map-pulse-dot {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .55; transform: scale(.85); }
}

.map-card-name {
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--text);
  letter-spacing: -.01em;
  line-height: var(--lh-snug);
}
.map-card-sub {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--fs-sm);
  color: var(--text-2);
  margin-top: 4px;
}
.map-card-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px dashed var(--line);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-2);
}
.map-card-coords {
  margin-top: var(--s-2);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--text-mute);
  letter-spacing: .04em;
}
.map-card-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px dashed var(--line);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--lime);
  text-decoration: none;
  transition: gap .2s var(--ease), color .2s;
  width: 100%;
}
.map-card-link:hover { gap: 8px; color: var(--lime-deep); }

.map-attribution {
  position: absolute;
  bottom: 8px;
  right: 12px;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  color: rgba(255,255,255,.55);
  background: rgba(14,15,19,.55);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  padding: 3px 8px;
  border-radius: var(--r-sm);
  z-index: 1;
  pointer-events: auto;
}
.map-attribution a { color: rgba(190,242,100,.85); text-decoration: none; }
.map-attribution a:hover { color: var(--lime); }

/* ── Custom pulsing lime marker over the EARTH coordinates ── */
.map-marker {
  position: relative;
  width: 22px;
  height: 22px;
  pointer-events: none;
}
.map-marker-dot {
  position: absolute;
  inset: 50% 50% auto auto;
  transform: translate(50%, -50%);
  width: 14px;
  height: 14px;
  border-radius: var(--r-full);
  background: var(--lime);
  border: 2px solid var(--bg);
  box-shadow:
    0 0 0 1px var(--lime),
    0 0 14px rgba(190,242,100,.85),
    0 4px 12px rgba(0,0,0,.55);
  z-index: 2;
}
.map-marker-pulse {
  position: absolute;
  inset: 0;
  border-radius: var(--r-full);
  background: rgba(190,242,100,.35);
  animation: map-marker-pulse 1.8s ease-out infinite;
  z-index: 1;
}
@keyframes map-marker-pulse {
  0%   { transform: scale(.6); opacity: .9; }
  70%  { transform: scale(2.6); opacity: 0;  }
  100% { transform: scale(2.6); opacity: 0;  }
}

/* ── Phone tweaks ── */
@media (max-width: 480px) {
  .map-wrap { height: 360px; border-radius: var(--r-md); }
  .map-card {
    top: 12px;
    left: 12px;
    right: 12px;
    max-width: none;
    padding: 14px 16px;
  }
  .map-card-name { font-size: var(--fs-base); }
  .map-card-meta, .map-card-link { font-size: var(--fs-2xs); }
}

@media (prefers-reduced-motion: reduce) {
  .map-marker-pulse, .map-card-dot { animation: none; }
}

/* ════════════════════════════════════════════════════════════
   LIGHT / DARK MODE
   Default palette (in :root above) is the dark theme.
   [data-theme="light"] overrides every visible token with
   light-mode equivalents tuned for WCAG-AA text contrast.
   ════════════════════════════════════════════════════════════ */

[data-theme="light"] {
  /* Backgrounds: warm off-white ladder. Cards are pure white. */
  --bg:           #FAFAF7;
  --bg-1:         #F2F1EB;
  --bg-2:         #E8E7E0;
  --bg-3:         #DDDCD3;
  --bg-card:      #FFFFFF;
  --bg-card-hov:  #F6F5EE;

  /* Lines: dark on light = inverted opacity logic */
  --line:         rgba(0,0,0,.10);
  --line-strong:  rgba(0,0,0,.18);
  --line-glow:    rgba(77,124,15,.22);

  /* Text: near-black -> dim gray. All pass WCAG AA on white. */
  --text:         #16181C;
  --text-2:       #3A3D43;
  --text-mute:    #6A6D73;
  --text-dim:     #9A9DA3;

  /* Lime accent shifts deeper so it reads on white (4.5:1 min). */
  --lime:         #4D7C0F;
  --lime-deep:    #365314;
  --lime-glow:    rgba(77,124,15,.18);

  /* Status colours: deeper variants for light bg. */
  --amber:        #B45309;
  --amber-deep:   #92400E;
  --sky:          #075985;
  --sky-deep:     #0C4A6E;
  --rose:         #BE123C;
  --rose-deep:    #9F1239;
}

/* ── Theme-toggle button ────────────────────────────────────── */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  margin-right: var(--s-2);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  color: var(--text-2);
  cursor: pointer;
  transition: background .2s, border-color .2s, color .2s, transform .2s var(--ease);
}
.theme-toggle:hover {
  background: var(--bg-2);
  border-color: var(--line-strong);
  color: var(--lime);
  transform: translateY(-1px);
}
.theme-toggle:focus-visible {
  outline: 2px solid var(--lime);
  outline-offset: 2px;
}
.theme-icon { display: block; }
/* Default (dark mode): show the SUN (= "switch to light"). Hide moon. */
.theme-icon-sun  { display: block; }
.theme-icon-moon { display: none; }
[data-theme="light"] .theme-icon-sun  { display: none; }
[data-theme="light"] .theme-icon-moon { display: block; }

/* ── Light-mode component-level adjustments ─────────────────── */

/* Body grid pattern + accent glow: invert tint for light bg */
[data-theme="light"] body::before {
  background-image:
    linear-gradient(rgba(0,0,0,.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0,0,0,.045) 1px, transparent 1px);
}
[data-theme="light"] body::after {
  background:
    radial-gradient(ellipse 60% 40% at 50% 0%, rgba(77,124,15,.10), transparent 70%);
}

/* Topbar: keep glass-blur but light tint */
[data-theme="light"] .topbar {
  background: rgba(255,255,255,.78);
  border-bottom: 1px solid var(--line);
}

/* Selection: subtle lime tint on light */
[data-theme="light"] ::selection {
  background: rgba(77,124,15,.20);
  color: var(--text);
}

/* MAP: in dark mode we invert the light "liberty" tiles. In light
   mode the natural light tiles ARE what we want - remove the filter. */
[data-theme="light"] .location-map .maplibregl-canvas { filter: none; }
[data-theme="light"] .location-map .maplibregl-marker { filter: none; }
/* Adjust the map info card for light bg */
[data-theme="light"] .map-card {
  background: rgba(255,255,255,.85);
  border-color: rgba(77,124,15,.30);
}
[data-theme="light"] .map-attribution {
  background: rgba(255,255,255,.7);
  color: rgba(0,0,0,.6);
}
[data-theme="light"] .maplibregl-ctrl-group {
  background: rgba(255,255,255,.85) !important;
  border-color: var(--line-strong) !important;
}
[data-theme="light"] .maplibregl-ctrl-group button span {
  filter: none;   /* default icons are dark, which we want on light bg */
}

/* INSTITUTION LOGOS: Auburn cream wordmark, EARTH white marks,
   Harvard cream wordmark all become invisible on white.
   Invert them to dark for light mode. Skip Cenfotec (blue reads on both). */
/* Multi-color institutional logos (Harvard, Auburn) have their own
   brand colours and an SVG-embedded `prefers-color-scheme` style for
   the wordmark text. No CSS filter — let them render natively in both
   modes so the shield / lettering keep their proper hues. */

/* HERO portrait card: the radial-gradient hint at top-right has
   a lime tint baked in. The light card colour reveals it as washed
   yellow - soften further. */
[data-theme="light"] .card-id {
  background:
    radial-gradient(ellipse 600px 200px at 100% 0%, rgba(77,124,15,.06), transparent 60%),
    var(--bg-card);
}

/* CHIP backgrounds (Working Stack): the default bg-1 is too pale on
   light. Add a subtle border emphasis. */
[data-theme="light"] .chip { border-color: var(--line-strong); }

/* GPA bar empty track: lime-tinted at low opacity (visible on dark).
   On light bg the lime tint is washed-out - bump opacity. */
[data-theme="light"] .stat-bars span {
  background: rgba(77,124,15,.10);
  box-shadow: inset 0 0 0 1px rgba(77,124,15,.22);
}

/* Pub-status pills + proj-tag-pills: backgrounds use rgba(190,242,100,...)
   from the old lime. Override at content level for light mode. */
[data-theme="light"] .status-presented,
[data-theme="light"] .proj-tag-pill.software {
  background: rgba(77,124,15,.10);
  border-color: rgba(77,124,15,.35);
}
[data-theme="light"] .badge,
[data-theme="light"] .lab-num,
[data-theme="light"] .gallery-label,
[data-theme="light"] .ref-tag {
  background: rgba(77,124,15,.08);
  border-color: rgba(77,124,15,.25);
}

/* Print: force light + dark text so a Dr. who prints the page can read */
@media print {
  :root, [data-theme="dark"], [data-theme="light"] {
    --bg: #fff; --bg-1: #fafafa; --bg-2: #f3f3f3; --bg-3: #ebebeb;
    --bg-card: #fff;
    --text: #000; --text-2: #1f1f1f; --text-mute: #555; --text-dim: #888;
    --line: rgba(0,0,0,.20); --line-strong: rgba(0,0,0,.35);
    --lime: #365314;
  }
  body::before, body::after, .topbar, .theme-toggle, .map-wrap { display: none !important; }
  a { text-decoration: underline; }
}

/* ── Light mode: flip the text-gradient titles ─────────────────
   .logo-c (brand "Carly.") and .hero-name use a white-to-light-gray
   gradient clipped to text. Invisible on light bg. Re-gradient them
   in dark colours so contrast stays sharp. */
[data-theme="light"] .logo-c {
  background: linear-gradient(180deg, #16181C 0%, #3A3D43 100%);
  -webkit-background-clip: text;
          background-clip: text;
}
[data-theme="light"] .hero-name {
  background: linear-gradient(180deg, #16181C 0%, #3A3D43 100%);
  -webkit-background-clip: text;
          background-clip: text;
}

/* ── View Transitions API styling ───────────────────────────────
   When the user clicks the theme toggle, the JS triggers a
   document.startViewTransition. The browser snapshots the page
   before + after the theme swap, then we ANIMATE the NEW layer
   into view via clipPath. The CSS below removes the default
   cross-fade so our clip-circle wipe is the only motion. */
::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}
::view-transition-old(root) {
  z-index: 1;       /* old palette stays under */
}
::view-transition-new(root) {
  z-index: 999;     /* new palette flood from above */
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none !important; }
}

/* ── Sun ↔ Moon icon morph (works in every browser, no API needed) */
.theme-toggle {
  position: relative;
  overflow: hidden;
}
.theme-toggle .theme-icon {
  display: block;
  position: absolute;
  inset: 0;
  margin: auto;
  width: 18px;
  height: 18px;
  transition:
    transform .55s cubic-bezier(.5,1.6,.4,1),
    opacity   .25s ease;
}
/* Default = LIGHT (so we see the MOON, meaning "switch to dark") */
.theme-icon-sun {
  transform: rotate(0deg) scale(0);
  opacity: 0;
}
.theme-icon-moon {
  transform: rotate(0deg) scale(1);
  opacity: 1;
}
/* When in dark mode, swap them */
[data-theme="dark"] .theme-icon-sun {
  transform: rotate(0deg) scale(1);
  opacity: 1;
}
[data-theme="dark"] .theme-icon-moon {
  transform: rotate(90deg) scale(0);
  opacity: 0;
}

/* Press feedback for the toggle (depth on click) */
.theme-toggle:active { transform: scale(0.92); }

/* Subtle glow on the toggle that pulses once on hover to invite click */
.theme-toggle::before {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: inherit;
  background: radial-gradient(circle, var(--lime-glow), transparent 70%);
  opacity: 0;
  transition: opacity .3s ease;
  pointer-events: none;
}
.theme-toggle:hover::before { opacity: 1; }

/* ── Portrait: gentle lift so the headshot doesn't read as too dark
   on the new lighter default page. Subtle: only +6% brightness and
   a touch of warmth. Works in both themes. */
.card-portrait img,
.portrait-img {
  filter: brightness(1.06) contrast(1.02) saturate(1.04);
}

/* ── Topbar phone-size polish: keep toggle + CV roomy, drop the
   keyboard-only ⌘K hint on touch screens. ────────────────────── */

/* Hide the ⌘K kbd hint on anything narrower than a tablet - it's
   keyboard-shortcut documentation and irrelevant on touch.        */
@media (max-width: 720px) {
  .kbd { display: none; }
}

/* Slim the toggle + tighten the right cluster on phones */
@media (max-width: 480px) {
  .theme-toggle {
    width: 32px;
    height: 32px;
    margin-right: var(--s-1);
  }
  .theme-toggle .theme-icon {
    width: 16px;
    height: 16px;
  }
  .topbar-cta {
    gap: var(--s-1);
  }
  .btn-primary {
    padding: 6px 10px;
    font-size: var(--fs-2xs);
  }
}

/* Even tighter on the smallest phones (iPhone SE-era 320 px) */
@media (max-width: 360px) {
  .theme-toggle { width: 30px; height: 30px; margin-right: 2px; }
  .theme-toggle .theme-icon { width: 14px; height: 14px; }
  .topbar { padding: 0 var(--s-2); }
  .btn-primary { padding: 6px 8px; gap: 4px; }
}

/* Make the icons hit-area still 44 px (touch guideline) without
   making the visual chrome bigger - invisible padding around it. */
@media (max-width: 720px) {
  .theme-toggle::after {
    content: '';
    position: absolute;
    inset: -6px;
  }
}

/* ── Light mode: lightbox + gallery overlay overrides ──────────
   The lightbox modal + its controls have hardcoded dark colours
   (rgba(7,8,10,.95) backdrop, rgba(20,21,27,.7) buttons). Those
   look correct in dark mode but become an opaque dark blob in
   light mode. Same for the .gallery-item hover gradient. Replace
   with light-tinted equivalents. */
[data-theme="light"] .lightbox {
  background: rgba(20, 22, 26, 0.85);   /* still mostly dark for image focus,
                                            but slightly lighter than dark mode */
}
[data-theme="light"] .lightbox-close,
[data-theme="light"] .lightbox-prev,
[data-theme="light"] .lightbox-next {
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.25);
}
[data-theme="light"] .lightbox-close:hover,
[data-theme="light"] .lightbox-prev:hover,
[data-theme="light"] .lightbox-next:hover {
  background: rgba(255, 255, 255, 0.30);
  color: var(--lime);
  border-color: var(--lime);
}
[data-theme="light"] .lightbox-caption {
  background: rgba(0, 0, 0, 0.55);
  color: #f5f5f4;
  border-color: rgba(255, 255, 255, 0.15);
}

/* Gallery thumbnail hover overlay - was rgba(7,8,10,.5) (near-black);
   in light mode use a softer dark mask. */
[data-theme="light"] .gallery-item::after {
  background: linear-gradient(180deg, transparent 60%, rgba(0,0,0,0.18) 100%);
}

/* Mi Salvador demo video frame: was #000 hardcoded. Keep dark-ish
   in light mode (videos need a dark frame anyway) but warmer. */
[data-theme="light"] .proj-media,
[data-theme="light"] .proj-video {
  background: #1a1c20;
}

/* Toast popup (the ⌘K hint) - was hardcoded dark with light text.
   In light mode flip to light bg with dark text. */
[data-theme="light"] .toast {
  background: rgba(20, 22, 26, 0.92);
  color: #f5f5f4;
  border-color: rgba(0, 0, 0, 0.15);
}

/* ── Design audit fixes (Oct 2025): typography + spacing polish ─

   1. .ref-role inherited 1.5 line-height where the title + sub use
      1.3. Snap it to lh-snug so the title/role/org trio aligns. */
.ref-role { line-height: var(--lh-snug); }

/* 2. .proj-side-meta strong was lime → 4 stripes of bright lime
      next to each "Type / Stack / Status / Period" label felt
      neon. Mute the labels; let only the values carry weight. */
.proj-side-meta strong { color: var(--text-mute); }

/* 3. .hero-roles had no explicit line-height - inherited 1.5 from
      body, which made the `·` separators feel adrift between
      role spans. Tighten to snug for stable baseline. */
.hero-roles { line-height: var(--lh-snug); }
.hero-roles .sep { display: inline-block; }

/* 4. .meta-list bullets were a ::before content '· ' that could
      hang at the start of a wrapped line. Convert to a flex layout
      so the bullet stays glued to its label, never alone. */
.meta-list li {
  display: flex;
  align-items: baseline;
  gap: var(--s-1);
}
.meta-list li::before {
  content: '·';
  color: var(--lime);
  flex-shrink: 0;
}

/* 5. .pub-affil-logo float created text-orphan tension at tablet
      widths (1024–1280). Reduce its left margin so the title has
      more room before wrapping. */
@media (min-width: 481px) and (max-width: 1280px) {
  .pub-affil-logo {
    max-width: 130px;
    margin-left: var(--s-3);
  }
  .pub-affil-logo img { max-width: 130px; max-height: 34px; }
}

/* ── i18n: language switcher + FOUC guard ─────────────────────
   Compact EN/ES/FR/PT pill sits between the ⌘K hint and the
   theme toggle. Visually matches .theme-toggle / .btn-ghost. */
.lang-switcher {
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  height: 36px;
  padding: 2px;
  margin-right: var(--s-2);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.lang-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  padding: 0 6px;
  font-family: var(--ff-mono, inherit);
  font-size: var(--fs-2xs, 11px);
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1;
  color: var(--text-2);
  background: transparent;
  border: 0;
  border-radius: calc(var(--r-md) - 3px);
  cursor: pointer;
  transition: background .18s ease, color .18s ease;
}
.lang-btn:hover {
  color: var(--text);
  background: var(--bg-2);
}
.lang-btn:focus-visible {
  outline: 2px solid var(--lime);
  outline-offset: 1px;
}
.lang-btn.is-active {
  color: var(--bg);
  background: var(--lime);
}
.lang-btn.is-active:hover {
  background: var(--lime);
  color: var(--bg);
}

/* Compact on narrow screens. */
@media (max-width: 720px) {
  .lang-switcher {
    height: 32px;
    margin-right: var(--s-1);
  }
  .lang-btn {
    min-width: 24px;
    padding: 0 4px;
    font-size: 10px;
  }
}
@media (max-width: 480px) {
  .lang-switcher { height: 30px; padding: 1px; }
  .lang-btn { min-width: 22px; padding: 0 3px; font-size: 9px; }
}

/* FOUC guard for non-English first paint. The inline <head> script
   adds .i18n-pending to <html> when the resolved language is not 'en';
   i18n.js removes it once translations are applied. */
html.i18n-pending body {
  visibility: hidden;
}

/* ── Responsive hardening for i18n (audit fixes, 2026-05-16) ──────────
   Five-agent responsive audit surfaced a set of layout pressures that
   only show up in ES/FR/PT, where translations run 15-50% longer than
   the EN strings the original CSS was tuned against. The block below
   addresses the highest-impact findings. */

/* 1. Touch targets for the new language switcher. Extend the hit
      area vertically only (top/bottom -8px) — horizontal extension
      would contribute to the page's scrollWidth at narrow viewports
      and force a phantom horizontal scroll. */
.lang-btn {
  position: relative;
}
.lang-btn::after {
  content: '';
  position: absolute;
  top: -8px;
  bottom: -8px;
  left: 0;
  right: 0;
}
/* 2. Don't shrink lang-btn type below the 10px legibility floor.
      Override the prior 9px-at-480 rule by stealing horizontal padding
      instead. */
@media (max-width: 480px) {
  .lang-btn { font-size: 10px; padding: 0 2px; }
}

/* 3. Hide the .status-pill at 1100px. The topbar is already crowded
      at 881-1280px with brand + 6 nav links + ⌘K + lang-switcher (4
      buttons) + theme-toggle + CV button; adding the status pill on
      top forces the topbar to overflow horizontally even in EN.
      The pill is decorative and can drop out earlier than the nav. */
@media (max-width: 1100px) {
  .status-pill { display: none; }
}

/* 3b. Compact topnav links between 881-1280px so 6 links + the
       lang-switcher fit alongside the brand and CV button in EN/ES/FR/PT. */
@media (max-width: 1280px) and (min-width: 881px) {
  .topnav { gap: 0; }
  .topnav a { padding: var(--s-1) var(--s-2); font-size: var(--fs-sm); }
}

/* 4. When the nav is hidden, the .topbar's 1fr middle column would
      eat horizontal space. Collapse to flex for tighter cluster
      packing. */
@media (max-width: 880px) {
  .topbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--s-2);
  }
  .topbar > .brand { flex: 0 0 auto; }
  .topbar > .topbar-cta { flex: 0 0 auto; }
}

/* 5. Hero deck: long ES/FR/PT decks contain compound emphases ("ciencia
      computacional de plantas", "innovation des systèmes alimentaires")
      that don't break at narrow widths. Enable hyphenation + safe
      word-wrap. */
.hero-deck,
.hero-deck em,
.hero-deck strong {
  overflow-wrap: anywhere;
  word-wrap: break-word;
  hyphens: auto;
}
/* same protection for hero-meta pills (kv) where ES/PT add ~50% */
@media (max-width: 720px) {
  .kv { overflow-wrap: anywhere; word-break: break-word; }
}

/* 6. The proj-side and vita-year columns are 200px fixed with uppercase
      + heavy letter-spacing. EN labels ("2024 – now", "Keywords") fit;
      ES/FR/PT ("2024 – atualidade", "Palabras clave") overflow. For
      non-EN locales, drop the uppercase styling so the labels read at
      normal width. */
:lang(es) .proj-side-meta strong,
:lang(fr) .proj-side-meta strong,
:lang(pt) .proj-side-meta strong,
:lang(es) .proj-side-meta em,
:lang(fr) .proj-side-meta em,
:lang(pt) .proj-side-meta em,
:lang(es) .vita-year,
:lang(fr) .vita-year,
:lang(pt) .vita-year {
  text-transform: none;
  letter-spacing: 0.02em;
}

/* 7. Statement-grid: shift breakpoint by 1 so 1024px viewport keeps
      its two-column layout (1024 is exact iPad-landscape). */
@media (max-width: 1023px) {
  .statement-grid { grid-template-columns: 1fr; }
}
@media (min-width: 1024px) {
  .statement-grid { grid-template-columns: minmax(0, 1fr) 320px; gap: var(--s-7); }
}

/* 8. Statement side panel: use horizontal space at tablet widths
      with a 2-column grid for its meta blocks. The highlight block
      ("Quick contact") always spans the full width. */
@media (min-width: 600px) and (max-width: 1023px) {
  .statement-side {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--s-3);
  }
  .statement-meta-block.highlight { grid-column: 1 / -1; }
}

/* 9. Docs grid: equalize row heights so paired cards don't render at
      wildly different heights when ES doc-sub strings wrap. Also stop
      the primary card from spanning 2 cols at tablet — with 7 cards
      this leaves an awkward orphan cell. */
.docs-grid { grid-auto-rows: 1fr; }
@media (min-width: 481px) and (max-width: 1100px) {
  .doc-card.primary { grid-column: auto; }
}
/* At narrow widths, drop the "Download" label and keep only the arrow,
   reclaiming horizontal space for the title/sub. */
@media (max-width: 600px) {
  .doc-action {
    font-size: 0;
  }
  .doc-action::after {
    content: '↓';
    font-size: var(--fs-sm);
  }
}

/* 10. Pub-title: switch from `overflow-wrap: anywhere` (which can
       mid-break "transformers" → "transform-ers") to `break-word`,
       which only breaks at word boundaries. */
.pub-title { overflow-wrap: break-word; word-break: normal; }

/* 11. Ref cards: pin the email to the bottom so cards with longer
       ES/FR ref-context strings don't show a mid-card email with
       trailing whitespace. */
.ref-email { margin-top: auto; }

/* 12. Refs grid: drop to 1 column earlier on narrow screens so ES/FR
       role/context don't compress to unreadably narrow widths. */
@media (max-width: 720px) {
  .refs-grid { grid-template-columns: 1fr; }
}

/* 13. Hero CTA: shrink button type at narrow widths so the FR/ES
       "Read research statement →" doesn't force the row to wrap thrice. */
@media (max-width: 700px) {
  .hero-cta .btn { font-size: var(--fs-sm); padding: 8px 12px; }
}

/* 14. Proj-body: when the row collapses to single column on tablet,
       remove the 760px cap so content uses the full available width. */
@media (max-width: 980px) {
  .proj-body { max-width: none; }
}

/* 15. Stat suffix: FR "couramment" (10 chars) is 167% of EN "fluent";
       allow it to wrap below the number instead of pushing the row. */
.stat-suffix { display: inline-block; max-width: 100%; overflow-wrap: anywhere; }

/* ─── Project §02 thesis deep-dive: methodology pipeline + result charts ─── */

.thesis-deepdive {
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--line);
}
.thesis-section-label {
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-2);
  margin: var(--s-4) 0 var(--s-3);
}
.thesis-section-label:first-child { margin-top: 0; }

/* ── 3D rig render (animated GIF) ── */
.rig-render {
  margin: 0 0 var(--s-5);
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--bg-1);
  overflow: hidden;
}
.rig-render img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 70vh;
  object-fit: contain;
  background:
    linear-gradient(45deg, rgba(255,255,255,0.02) 25%, transparent 25%),
    linear-gradient(-45deg, rgba(255,255,255,0.02) 25%, transparent 25%),
    var(--bg-2);
  background-size: 20px 20px;
}
.rig-render-caption {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  border-top: 1px solid var(--line);
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--text-2);
}
.rig-render-tag {
  flex-shrink: 0;
  padding: 2px 8px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text);
}

/* ── Methodology flow diagram (SVG, desktop horizontal) ── */
.method-flow {
  display: block;
  width: 100%;
  height: auto;
  margin: 0 0 var(--s-6);
  font-family: var(--font-mono, monospace);
}
.method-flow .flow-rect {
  fill: var(--bg-1);
  stroke: var(--line);
  stroke-width: 1.2;
  transition: fill .22s var(--ease), stroke .22s var(--ease);
}
.method-flow .flow-step:hover .flow-rect {
  fill: var(--bg-2);
  stroke: var(--lime);
}
.method-flow .flow-step.highlight .flow-rect {
  fill: color-mix(in oklab, var(--lime) 8%, var(--bg-1));
  stroke: var(--lime);
}
.method-flow .flow-step-num {
  font-family: var(--font-mono, monospace);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .14em;
  fill: var(--text-2);
  text-transform: uppercase;
}
.method-flow .flow-step-title {
  font-family: var(--font-serif, Georgia, serif);
  font-size: 18px;
  font-weight: 500;
  font-style: italic;
  fill: var(--text);
}
.method-flow .flow-step-line {
  font-family: var(--font-sans, system-ui, sans-serif);
  font-size: 11px;
  fill: var(--text-2);
}
.method-flow .flow-step.highlight .flow-step-line { fill: var(--text); }
.method-flow .flow-arrow-line {
  stroke: var(--text-2);
  stroke-width: 2;
  fill: none;
}
@media (prefers-reduced-motion: no-preference) {
  .method-flow .flow-step {
    opacity: 0;
    animation: flowIn .55s cubic-bezier(.4,.0,.2,1) forwards;
    animation-delay: calc(var(--i, 0) * 90ms);
  }
  .method-flow .flow-arrow-line {
    stroke-dasharray: 60;
    stroke-dashoffset: 60;
    animation: arrowIn .35s linear forwards;
    animation-delay: calc(var(--i, 0) * 90ms + 250ms);
  }
  @keyframes flowIn { to { opacity: 1; } }
  @keyframes arrowIn { to { stroke-dashoffset: 0; } }
}

/* Vertical stacked flow on narrow screens */
.method-flow-mobile {
  display: none;
  list-style: none;
  padding: 0;
  margin: 0 0 var(--s-6);
  position: relative;
}
.method-flow-mobile::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 20px;
  width: 1px;
  background: linear-gradient(180deg, var(--line) 0%, var(--lime) 100%);
  opacity: 0.6;
}
.flow-step-mobile {
  position: relative;
  display: flex;
  gap: var(--s-3);
  padding: var(--s-3) 0 var(--s-3) 0;
}
.flow-step-mobile-num {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--bg);
  background: var(--lime);
  border-radius: 50%;
  z-index: 1;
}
.flow-step-mobile-name {
  margin: 8px 0 var(--s-1);
  font-family: var(--font-serif, Georgia, serif);
  font-size: var(--fs-md);
  font-weight: 500;
  line-height: 1.2;
  color: var(--text);
}
.flow-step-mobile-desc {
  margin: 0;
  font-size: var(--fs-xs);
  line-height: 1.55;
  color: var(--text-2);
}
@media (max-width: 880px) {
  .method-flow { display: none; }
  .method-flow-mobile { display: block; }
}

/* ── Result charts (4 inline SVGs, 2x2 grid) ── */
.result-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--s-4);
  margin: 0 0 var(--s-5);
}
@media (max-width: 720px) {
  .result-grid { grid-template-columns: 1fr; }
}
.result-chart {
  margin: 0;
  padding: var(--s-4);
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.result-chart-title {
  margin: 0 0 var(--s-1);
  font-family: var(--font-serif, Georgia, serif);
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--text);
}
.result-chart-caption {
  margin: 0 0 var(--s-3);
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: var(--text-2);
}
.result-chart svg {
  display: block;
  width: 100%;
  height: auto;
  font-family: var(--font-mono, monospace);
}
/* shared chart token styles */
.result-chart .grid line   { stroke: var(--line); stroke-dasharray: 2 4; opacity: .55; }
.result-chart .axis        { stroke: var(--text-2); stroke-width: 0.8; }
.result-chart .axis-label  { fill: var(--text-2); font-size: 9px; }
.result-chart .axis-title-x, .result-chart .axis-title-y {
  fill: var(--text-2); font-size: 10px; font-style: italic;
}
/* Chart 1 — scatter */
.result-chart .pt circle { stroke: var(--bg); stroke-width: 1.5; }
.result-chart .pt text   { fill: var(--text-2); font-size: 9px; }
.result-chart .pt.baseline circle { fill: var(--text-2); opacity: .6; }
.result-chart .pt.highlight circle { fill: var(--lime); }
.result-chart .pt.highlight text   { fill: var(--text); font-weight: 700; }
.result-chart .pt .lbl-strong { font-weight: 700; }
.result-chart .equiv-link {
  stroke: var(--lime); stroke-width: 1.5; stroke-dasharray: 3 3; opacity: .8;
}
.result-chart .equiv-tag {
  fill: var(--lime); font-size: 9px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase;
}
/* Chart 2 — horizontal bars */
.result-chart .bar {
  fill: var(--lime); opacity: .8;
  transform-origin: left center;
}
@media (prefers-reduced-motion: no-preference) {
  .result-chart .bar {
    transform: scaleX(0);
    animation: barFill .85s cubic-bezier(.4,.0,.2,1) forwards;
  }
  .result-chart .bar:nth-of-type(1) { animation-delay: 0ms; }
  .result-chart .bar:nth-of-type(2) { animation-delay: 80ms; }
  .result-chart .bar:nth-of-type(3) { animation-delay: 160ms; }
  .result-chart .bar:nth-of-type(4) { animation-delay: 240ms; }
  .result-chart .bar:nth-of-type(5) { animation-delay: 320ms; }
  @keyframes barFill { to { transform: scaleX(1); } }
}
.result-chart .bar-label {
  fill: var(--text); font-size: 10px;
}
.result-chart .bar-value {
  fill: var(--text-2); font-size: 9px; font-weight: 700;
}
/* Chart 3 — forest plot */
.result-chart .equiv-zone {
  fill: var(--lime); opacity: .12;
}
.result-chart .zero-line {
  stroke: var(--text-2); stroke-width: 0.8; stroke-dasharray: 2 3;
}
.result-chart .bound {
  stroke: var(--lime); stroke-width: 1; opacity: .7;
}
.result-chart .bound-label, .result-chart .zero-label {
  fill: var(--text-2); font-size: 9px; font-weight: 700;
}
.result-chart .ci-line {
  stroke: var(--text); stroke-width: 2;
}
.result-chart .ci-tip {
  stroke: var(--text); stroke-width: 2;
}
.result-chart .ci-point {
  fill: var(--lime); stroke: var(--text); stroke-width: 1.5;
}
.result-chart .ci-label {
  fill: var(--text); font-size: 10px; font-weight: 700;
}
/* Chart 4 — power curve */
.result-chart .power-curve {
  fill: none;
  stroke: var(--lime);
  stroke-width: 2.4;
  stroke-linecap: round;
}
@media (prefers-reduced-motion: no-preference) {
  .result-chart .power-curve {
    stroke-dasharray: 900;
    stroke-dashoffset: 900;
    animation: drawPower 1.6s cubic-bezier(.4,.0,.2,1) forwards;
  }
  @keyframes drawPower { to { stroke-dashoffset: 0; } }
}
.result-chart .peak {
  fill: var(--lime); stroke: var(--text); stroke-width: 1.5;
}
.result-chart .peak-label {
  fill: var(--text); font-size: 9px; font-weight: 700;
}
.result-chart .floor-line {
  stroke: var(--text-2); stroke-width: 0.8; stroke-dasharray: 4 4; opacity: .6;
}
.result-chart .floor-label {
  fill: var(--text-2); font-size: 9px; font-style: italic;
}

/* "View bibliography" link at the end of §02 */
.thesis-bib-link {
  display: inline-block;
  margin-top: var(--s-3);
  padding: 10px 18px;
  background: var(--bg-1);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-sm);
  text-decoration: none;
  color: var(--text);
  transition: background .22s var(--ease), border-color .22s var(--ease), transform .22s var(--ease);
}
.thesis-bib-link:hover {
  background: var(--lime);
  border-color: var(--lime);
  color: var(--bg);
  transform: translateY(-1px);
}

/* ── §07 BIBLIOGRAPHY section ── */
.bib-list {
  list-style: decimal;
  list-style-position: outside;
  padding-left: 1.6em;
  margin: var(--s-4) 0;
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--text);
  max-width: 880px;
}
.bib-list li {
  margin-bottom: var(--s-3);
  overflow-wrap: break-word;
  padding-left: var(--s-1);
}
.bib-list li::marker {
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-xs);
}
.bib-list a {
  color: var(--text-2);
  text-decoration: none;
  border-bottom: 1px dotted var(--line-strong);
  word-break: break-all;
  transition: color .15s var(--ease), border-bottom-color .15s var(--ease);
}
.bib-list a:hover {
  color: var(--lime);
  border-bottom-color: var(--lime);
}
.bib-back-link {
  display: inline-block;
  margin-top: var(--s-3);
  font-family: var(--font-mono, monospace);
  font-size: var(--fs-sm);
  text-decoration: none;
  color: var(--text-2);
  transition: color .15s var(--ease);
}
.bib-back-link:hover {
  color: var(--lime);
}
@media (max-width: 600px) {
  .bib-list { padding-left: 1.3em; font-size: var(--fs-xs); }
}

/* 16. .pub-status: drop nowrap on narrow viewports — the FR
       "Manuscrit en préparation · premier auteur" badge is 369px wide
       and forces 60px+ of horizontal scroll at phone widths. */
@media (max-width: 720px) {
  .pub-status {
    white-space: normal;
    overflow-wrap: anywhere;
    word-break: break-word;
    max-width: 100%;
  }
}

/* 17. .topbar still has its grid `1fr` middle column on desktop, where
       the topnav uses it correctly. The flex override at <=880px
       (rule #4 above) handles narrower widths. No change needed here,
       but the lang-switcher's `margin-right: var(--s-2)` (8px) reads
       cramped at desktop; bump to a thin separator instead. */
@media (min-width: 881px) {
  .lang-switcher {
    margin-right: var(--s-3);
  }
}
