/* ===== Theme tokens ===== */
:root {
  --bg: #f2f0ea;
  --bg-raised: #ffffff;
  --bg-raised-soft: rgba(255,255,255,0.5);
  --bg-raised-soft-2: rgba(255,255,255,0.6);

  --ink: #14130f;
  --ink-72: rgba(20,19,15,0.72);
  --ink-68: rgba(20,19,15,0.68);
  --ink-6: rgba(20,19,15,0.60);
  --ink-55: rgba(20,19,15,0.55);
  --ink-5: rgba(20,19,15,0.50);
  --ink-45: rgba(20,19,15,0.45);
  --ink-4: rgba(20,19,15,0.40);
  --ink-35: rgba(20,19,15,0.35);

  --border-18: rgba(20,19,15,0.18);
  --border-16: rgba(20,19,15,0.16);
  --border-14: rgba(20,19,15,0.14);
  --border-12: rgba(20,19,15,0.12);
  --border-08: rgba(20,19,15,0.08);

  --accent: oklch(0.68 0.15 45);
  --accent-light: oklch(0.78 0.13 45);
  --accent-dark: oklch(0.58 0.15 45);
}

[data-theme="dark"] {
  --bg: #121210;
  --bg-raised: #1c1c19;
  --bg-raised-soft: rgba(255,255,255,0.04);
  --bg-raised-soft-2: rgba(255,255,255,0.07);

  --ink: #f2f0ea;
  --ink-72: rgba(242,240,234,0.76);
  --ink-68: rgba(242,240,234,0.72);
  --ink-6: rgba(242,240,234,0.64);
  --ink-55: rgba(242,240,234,0.58);
  --ink-5: rgba(242,240,234,0.52);
  --ink-45: rgba(242,240,234,0.48);
  --ink-4: rgba(242,240,234,0.42);
  --ink-35: rgba(242,240,234,0.36);

  --border-18: rgba(242,240,234,0.2);
  --border-16: rgba(242,240,234,0.18);
  --border-14: rgba(242,240,234,0.16);
  --border-12: rgba(242,240,234,0.14);
  --border-08: rgba(242,240,234,0.1);
}

/* ===== Reset & base ===== */
* { box-sizing: border-box; }
html {
  scroll-behavior: smooth;
  /* "proximity", not "mandatory": sections that are taller than the viewport
     still scroll freely, but when you stop near a boundary the browser settles
     on the section start instead of leaving it half-cut by the fold. */
  scroll-snap-type: y proximity;
}
/* The stage itself is not a target: it is taller than the viewport, so as a
   snap area it produces odd resting positions halfway through the hero. */
.about-intro,
.about-section,
.references-section,
.projects-section,
.contact-section { scroll-snap-align: start; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: Archivo, Helvetica, sans-serif;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  transition: background .3s ease, color .3s ease;
}
a { color: inherit; text-decoration: none; }
a:hover { color: var(--accent); }
img { max-width: 100%; display: block; }

/* ===== Accessibility utilities ===== */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.visually-hidden-anchor { position: absolute; top: 0; left: 0; }
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 100;
  background: var(--bg-raised); color: var(--ink); padding: 12px 18px; border-radius: 8px;
  font: 500 13px/1 'JetBrains Mono', monospace; transition: top .2s ease;
}
.skip-link:focus {
  top: 12px; color: var(--ink); outline: 2px solid var(--accent); outline-offset: 2px;
}

a:focus-visible,
button:focus-visible,
.terminal-bar:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .marquee-wrap { overflow-x: auto; }
  /* Exempt the recognitions ticker from the blanket animation kill above:
     a slow, linear horizontal scroll is low vestibular-risk, and visitors
     with this setting on were seeing it as permanently frozen/broken
     instead of just calmer. Everything else on the page (zoom, reveals)
     still stops as intended. */
  .marquee-track { animation-duration: 34s !important; animation-iteration-count: infinite !important; }
  [data-reveal] { animation: none !important; opacity: 1 !important; transform: none !important; }
}

@keyframes blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes mq { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes face { 0%, 100% { opacity: .16; } 40% { opacity: .3; } 65% { opacity: .19; } }
@keyframes rise { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: none; } }

@supports (animation-timeline: view()) {
  [data-reveal] {
    animation: rise .01s linear both;
    animation-timeline: view();
    animation-range: entry 4% cover 20%;
  }
}
[data-reveal].js-reveal { opacity: 0; transform: translateY(22px); transition: opacity .6s ease, transform .6s cubic-bezier(.22,.8,.2,1); }
[data-reveal].js-reveal.is-visible { opacity: 1; transform: none; }

/* ===== Progress bar ===== */
.progress-bar {
  position: fixed; top: 0; left: 0; height: 2px;
  background: var(--accent); z-index: 60; width: 0%;
}

/* ===== Header ===== */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 16px 28px;
  color: #f4f2ec;
  background: rgba(13,13,11,0.32);
  border-bottom: 1px solid rgba(244,242,236,0.14);
  backdrop-filter: blur(14px);
  transition: background .45s ease, color .45s ease, border-color .45s ease;
}
.site-header.light {
  color: #14130f;
  background: rgba(242,240,234,0.78);
  border-bottom-color: var(--border-08);
}
.logo { flex: 0 0 auto; font: 600 17px/1 Archivo, sans-serif; letter-spacing: -0.02em; display: flex; align-items: center; gap: 1px; }
.logo .accent { color: var(--accent); }
.nav {
  flex: 1 1 auto; min-width: 0;
  display: flex; justify-content: center; gap: 22px; font: 400 12px/1 'JetBrains Mono', monospace; opacity: .72;
  overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; white-space: nowrap;
}
.nav::-webkit-scrollbar { display: none; }
.nav a { flex: 0 0 auto; padding: 4px 2px; }
.pill-btn {
  flex: 0 0 auto;
  font: 500 12px/1 'JetBrains Mono', monospace; padding: 9px 14px; border-radius: 999px;
  white-space: nowrap; border: 1px solid rgba(244,242,236,0.32);
  transition: background .25s ease, border-color .25s ease, color .25s ease;
}
.site-header.light .pill-btn { border-color: rgba(20,19,15,0.2); }
.header-pill:hover { background: var(--accent); border-color: var(--accent); color: #fff; }

.header-controls { flex: 0 0 auto; display: flex; align-items: center; gap: 10px; }
.theme-toggle {
  flex: none; width: 36px; height: 36px; border-radius: 50%;
  border: 1px solid rgba(244,242,236,0.32); background: transparent; color: #f4f2ec;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: background .2s ease, border-color .2s ease, color .2s ease;
}
.site-header.light .theme-toggle { border-color: rgba(20,19,15,0.2); color: #14130f; }
.theme-toggle:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
/* Icons show the mode you'd SWITCH TO, not the current one: moon (go dark)
   while in light mode, sun (go light) while in dark mode. */
.icon-sun { display: none; }
[data-theme="dark"] .icon-moon { display: none; }
[data-theme="dark"] .icon-sun { display: block; }

.lang-toggle {
  flex: none; min-width: 36px; height: 36px; padding: 0 10px; border-radius: 999px;
  border: 1px solid rgba(244,242,236,0.32); background: transparent; color: #f4f2ec;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  font: 500 11px/1 'JetBrains Mono', monospace; letter-spacing: 0.04em;
  transition: background .2s ease, border-color .2s ease, color .2s ease;
}
.site-header.light .lang-toggle { border-color: rgba(20,19,15,0.2); color: #14130f; }
.lang-toggle:hover { background: var(--accent); border-color: var(--accent); color: #fff; }

.nav-toggle {
  display: none; flex: none; width: 36px; height: 36px; border-radius: 50%;
  border: 1px solid rgba(244,242,236,0.32); background: transparent; color: #f4f2ec;
  align-items: center; justify-content: center; cursor: pointer; gap: 4px;
  flex-direction: column; transition: background .2s ease, border-color .2s ease;
}
.nav-toggle-bar { display: block; width: 15px; height: 1.5px; background: currentColor; border-radius: 1px; transition: transform .25s ease, opacity .25s ease; }
.site-header.light .nav-toggle { border-color: rgba(20,19,15,0.2); color: #14130f; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

.mobile-nav {
  display: none;
  position: absolute; top: 100%; left: 0; right: 0;
  flex-direction: column;
  background: #0d0d0b;
  border-bottom: 1px solid rgba(244,242,236,0.14);
  padding: 6px clamp(24px,6vw,110px) 14px;
  transform: translateY(-8px); opacity: 0; pointer-events: none;
  transition: transform .2s ease, opacity .2s ease;
}
.site-header.light .mobile-nav { background: #f2f0ea; border-bottom-color: var(--border-08); }
.mobile-nav.open { transform: translateY(0); opacity: 1; pointer-events: auto; }
.mobile-nav a {
  padding: 13px 2px; font: 500 14px/1 'JetBrains Mono', monospace; letter-spacing: 0.02em;
  color: #f4f2ec; border-bottom: 1px solid rgba(244,242,236,0.12);
}
.site-header.light .mobile-nav a { color: #14130f; border-bottom-color: var(--border-08); }
.mobile-nav a:last-child { border-bottom: none; }

/* ===== Stage (hero + about email share one pinned photo) =====
   .stage is the sticky containing block, so .stage-media stays pinned for the
   whole hero runway AND the About email on top of it. Layout height is
   100svh (media) + runway + About, and the media releases exactly when the
   About section's last screen scrolls past — so the photo always sits behind
   the email, never behind the sections after it. */
.stage { position: relative; background: #0d0d0b; }
.stage-media {
  position: sticky; top: 0; height: 100vh; height: 100svh;
  overflow: hidden; background: #0d0d0b; z-index: 0;
}
/* Scroll distance over which the hero copy fades out and the photo zooms in,
   before the About email arrives. Drives --stage-progress in main.js. */
.hero-runway { height: 70vh; }

.stage-grade { position: absolute; inset: 0; pointer-events: none; }

/* Veil that fades in over the zoomed photo so the About email reads cleanly
   on both themes. Opacity is set from the scroll handler. */
.stage-veil {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: var(--bg);
  transition: background .3s ease;
}
/* The flat veil stops at 0.88 so the photo still reads behind the email, which
   left a seam where the stage ends and the flat page colour of the next section
   begins. This second layer carries the bottom of the frame all the way to the
   page colour, so the photo dissolves into Experience instead of cutting. */
.stage-fade {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: linear-gradient(to bottom, transparent 46%, var(--bg) 96%);
}

.photo-wrap {
  position: absolute; right: 0; top: 0; bottom: 0; width: min(62%, 940px);
  /* Scroll-driven zoom. --zoom is written by main.js; the origin sits on her
     face so the push-in reads as moving toward her, not toward the frame. */
  transform: scale(var(--zoom, 1));
  transform-origin: 58% 38%;
  will-change: transform;
}
.hero-photo {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 30% 40%;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 34%);
  mask-image: linear-gradient(90deg, transparent, #000 34%);
}
.glow-face {
  position: absolute; left: 53.5%; top: 12%; width: 28%; height: 38%; pointer-events: none; mix-blend-mode: screen;
  background: radial-gradient(ellipse at 50% 60%, rgba(140,210,255,0.55), transparent 70%);
  animation: face 3.6s ease-in-out infinite;
}

.grade { position: absolute; inset: 0; }
.grade-1 { background: linear-gradient(95deg, rgba(11,11,9,0.94) 0%, rgba(11,11,9,0.86) 34%, rgba(11,11,9,0.4) 54%, rgba(11,11,9,0.06) 74%, rgba(11,11,9,0.12) 100%); }
.grade-2 { background: linear-gradient(to top, rgba(11,11,9,0.4), transparent 34%); }
.hero-copy {
  position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: flex-start;
  padding: clamp(104px,15vh,150px) clamp(24px,5vw,96px) clamp(80px,12vh,120px);
  color: #f4f2ec;
  opacity: 1;
  transform: translateY(0px);
}
.hero-copy-inner { max-width: min(100%, 560px); }
.hero-h1 {
  font: 700 clamp(40px,6.6vw,96px)/0.96 Archivo, sans-serif; letter-spacing: -0.045em; margin: 0 0 20px;
  min-height: 1.05em; text-wrap: balance; transform-origin: 0% 50%;
  transform: scale(1); transition: transform 1.15s cubic-bezier(.22,.8,.2,1), font-size .3s ease;
}
.caret {
  display: inline-block; width: 0.4em; height: 0.8em; background: var(--accent-light);
  margin-left: 0.06em; transform: translateY(0.05em); animation: blink 1.05s steps(1) infinite;
}
.hero-subtitle { margin: 0 0 8px; }
.hero-role {
  font: 500 13px/1 'JetBrains Mono', monospace; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--accent-light); margin-bottom: 12px;
}
.hero-tagline {
  font: 400 clamp(15px,1.3vw,19px)/1.55 Archivo, sans-serif; color: rgba(244,242,236,0.72);
  max-width: 40ch; text-wrap: pretty;
}

.hero-status {
  display: flex; align-items: center; gap: 9px; margin-top: 30px;
  font: 500 12px/1 'JetBrains Mono', monospace; letter-spacing: 0.06em; color: rgba(244,242,236,0.68);
}
.status-dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: oklch(0.78 0.16 145); box-shadow: 0 0 9px oklch(0.78 0.16 145);
  animation: statusPulse 2.2s ease-in-out infinite;
}
@keyframes statusPulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

.hero-flow {
  margin-top: 10px; font: 400 italic clamp(14px,1.15vw,16.5px)/1.4 Archivo, sans-serif;
  color: rgba(244,242,236,0.56);
}

.hero-skills {
  display: flex; flex-wrap: wrap; gap: 9px; margin: 18px 0 0; padding: 0; list-style: none; max-width: 440px;
}
.skill-pill {
  font: 400 11.5px/1 'JetBrains Mono', monospace; letter-spacing: 0.02em; color: rgba(244,242,236,0.78);
  border: 1px solid rgba(244,242,236,0.2); border-radius: 999px; padding: 8px 14px;
}

.hero-icon-links { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
.hero-cta-btn {
  display: inline-flex; align-items: center; gap: 10px; padding: 14px 24px; border-radius: 999px;
  font: 500 14px/1 'JetBrains Mono', monospace; letter-spacing: 0.01em; white-space: nowrap;
  transition: background .2s ease, border-color .2s ease, color .2s ease;
}
.hero-cta-solid { background: #f4f2ec; color: #14130f; }
.hero-cta-solid:hover { background: var(--accent); color: #fff; }
.hero-cta-outline { border: 1px solid rgba(244,242,236,0.3); color: #f4f2ec; }
.hero-cta-outline:hover { border-color: #f4f2ec; background: rgba(244,242,236,0.1); color: #f4f2ec; }

.hero-hint {
  position: absolute; bottom: 22px; left: clamp(24px,5vw,96px);
  font: 400 11px/1 'JetBrains Mono', monospace; letter-spacing: 0.16em; color: rgba(244,242,236,0.5);
  white-space: nowrap; opacity: 0; transition: opacity .6s ease;
}
.hero-hint.show { opacity: 1; }

/* ===== About email composer (full-screen) ===== */
.about-intro {
  /* svh (small viewport height) stays fixed as mobile browser toolbars show/hide on
     scroll; vh would resize this box on every scroll tick, reflowing everything below
     it (References included) and making the page feel like it's jumping around. */
  min-height: 100vh;
  min-height: 100svh;
  display: flex; align-items: center; justify-content: center;
  /* Sits on top of the pinned photo, so no background of its own — the veil
     inside .stage-media provides the readable ground. */
  position: relative; z-index: 2; background: transparent;
  --email-pad-top: clamp(84px,11vh,116px);
  --email-pad-bottom: clamp(28px,5vh,52px);
  padding: var(--email-pad-top) clamp(16px,4vw,48px) var(--email-pad-bottom);
}
.email-window {
  position: relative; z-index: 5; width: 100%; max-width: 980px;
  /* Never taller than the screen. On a roomy desktop the letter fits as-is and
     this does nothing; on a short or narrow one the body scrolls inside the
     window — like a real mail client — instead of the section running past the
     fold and getting cut. */
  max-height: calc(100svh - var(--email-pad-top) - var(--email-pad-bottom));
  display: flex; flex-direction: column;
  border: 1px solid var(--border-16); border-radius: 14px;
  background: var(--bg-raised);
  box-shadow: 0 26px 60px rgba(0,0,0,0.22); overflow: hidden;
  opacity: 0; pointer-events: none; transform: translateY(12px);
  transition: opacity .35s ease, transform .35s ease, background .3s ease, border-color .3s ease;
}
.email-window.show { opacity: 1; pointer-events: auto; transform: translateY(0); }
/* The letter can be much taller than the window on short/narrow phones —
   .email-body scrolls internally, but with no visible scrollbar on touch
   there was nothing telling people more text existed below; it just read as
   cut off mid-sentence. This fade hints at it regardless of theme/overflow. */
.email-window::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 34px;
  background: linear-gradient(to bottom, transparent, var(--bg-raised));
  pointer-events: none;
}
.email-bar {
  display: flex; align-items: center; gap: 7px; padding: 11px 18px;
  border-bottom: 1px solid var(--border-12); user-select: none; flex: none;
}
.email-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.email-dot-red { background: #ec6a5e; }
.email-dot-yellow { background: #f4bf4f; }
.email-dot-green { background: #61c454; }
.email-bar-label {
  margin-left: auto; font: 500 11px/1 'JetBrains Mono', monospace; letter-spacing: 0.1em;
  color: var(--ink-45); text-transform: uppercase;
}
.email-fields { padding: 11px 20px; border-bottom: 1px solid var(--border-12); display: grid; gap: 5px; flex: none; }
.email-field { display: flex; gap: 10px; font: 400 13px/1.4 Archivo, sans-serif; color: var(--ink-68); }
.email-field-label {
  flex: none; width: 52px; font: 500 11px/1.4 'JetBrains Mono', monospace; letter-spacing: 0.04em; color: var(--ink-4);
}
.email-body {
  flex: 1; min-height: 0; overflow-y: auto;
  -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  padding: clamp(20px,2.4vw,30px) clamp(22px,3vw,34px);
  font: 400 clamp(14px,1vw,15.5px)/1.58 Archivo, sans-serif;
  color: var(--ink-68); white-space: pre-wrap;
}
.email-body p { margin: 0 0 11px; }
.email-body p:last-child { margin-bottom: 0; }
.email-body ul { list-style: none; margin: 0 0 11px; padding: 0; display: grid; gap: 6px; }
.email-list-dot li, .email-list-arrow li { position: relative; padding-left: 22px; }
.email-list-dot li::before { content: '•'; position: absolute; left: 2px; color: var(--ink-4); }
.email-list-arrow li::before { content: '→'; position: absolute; left: 0; color: var(--accent-dark); }
.email-sign { color: var(--ink-5); margin-top: 16px; font-weight: 600; }
.email-sign .accent { color: var(--accent); }

/* Emphasis reveals in as an animated pass over the already-visible text,
   instead of a character-by-character typewriter. */
.email-emphasis { transition: font-weight .3s ease, font-size .35s ease, color .35s ease, background-size .45s ease; }
.email-lede { display: inline-block; font-size: 1em; font-weight: 400; color: inherit; }
.email-lede.on { font-size: 1.22em; font-weight: 600; color: var(--ink); }
.email-subhead { display: block; font-weight: 400; color: var(--ink-68); margin-top: 16px; }
.email-subhead.on { font-weight: 600; color: var(--ink); }
.email-emph-strong { font-weight: 400; color: inherit; }
.email-emph-strong.on { font-weight: 600; color: var(--ink); }
.email-emph-underline {
  background-image: linear-gradient(var(--accent), var(--accent));
  background-repeat: no-repeat; background-position: 0 100%; background-size: 0% 2px;
}
.email-emph-underline.on { background-size: 100% 2px; }

/* ===== Marquee ===== */
/* Closes the About block (experience + education) rather than introducing it. */
.marquee-wrap {
  position: relative;
  border-block: 1px solid var(--border-12); background: #14130f; color: #f2f0ea;
  overflow: hidden; padding: 18px 0;
}
/* Fade the ticker into the bar's own background at both edges instead of
   hard-clipping mid-word — a real mask would let the page's own background
   show through instead, which jumps between light/dark themes. */
.marquee-wrap::before, .marquee-wrap::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: clamp(28px,8vw,72px); z-index: 1; pointer-events: none;
}
.marquee-wrap::before { left: 0; background: linear-gradient(to right, #14130f, transparent); }
.marquee-wrap::after { right: 0; background: linear-gradient(to left, #14130f, transparent); }
.marquee-label {
  text-align: center; font: 500 10.5px/1 'JetBrains Mono', monospace; letter-spacing: 0.18em;
  color: rgba(242,240,234,0.4); margin-bottom: 12px;
}
.marquee-track {
  display: flex; width: max-content; animation: mq 34s linear infinite;
  font: 500 13px/1 'JetBrains Mono', monospace; letter-spacing: 0.1em; white-space: nowrap;
}
/* Let people stop the auto-scrolling ticker to read it (WCAG 2.2.2). Gated to
   devices with a real pointer: on touch, tapping the bar leaves :hover stuck
   "on" forever (no mouseleave ever fires), which froze the ticker permanently
   on mobile Safari/Chrome after the first touch anywhere near it. */
@media (hover: hover) and (pointer: fine) {
  .marquee-wrap:hover .marquee-track { animation-play-state: paused; }
}
.marquee-wrap:focus-within .marquee-track { animation-play-state: paused; }
.marquee-group { display: flex; gap: 44px; padding-right: 44px; flex: none; }
.accent-star { color: var(--accent); }

/* ===== Section eyebrow ===== */
.section-eyebrow {
  font: 500 11px/1 'JetBrains Mono', monospace; letter-spacing: 0.16em; color: var(--ink-45);
  margin-bottom: clamp(22px,3.5vh,38px);
}
.eyebrow-dark { color: rgba(242,240,234,0.45); }

/* ===== About ===== */
/* Vertical padding is keyed off min(height, width): on a wide but short laptop
   screen, width-only clamps kept desktop-sized gutters the viewport had no room
   for, which is what pushed these sections past the fold. The top value also
   clears the fixed header once the section snaps to the top. */
.about-section {
  padding: clamp(70px,min(9vh,7vw),100px) clamp(24px,6vw,110px) clamp(30px,min(5vh,5vw),72px);
  max-width: 1400px; margin: 0 auto;
}

.experience-list { margin-top: 16px; border-top: 1px solid var(--border-12); }
.exp-row {
  display: grid; grid-template-columns: 78px minmax(0,1fr) auto; gap: 18px; align-items: center;
  padding: 22px 6px; border-bottom: 1px solid var(--border-12);
  transition: background .2s ease;
}
.exp-row:hover { background: var(--bg-raised-soft-2); }
.exp-org { display: flex; align-items: center; min-width: 0; }
.exp-years { padding-top: 0.2em; }
.exp-logo { flex: none; height: 30px; width: 62px; object-fit: contain; object-position: left center; }
/* Several partner logos use dark text meant for a white background — on the
   dark theme they'd disappear against the dark card, so give them a light
   chip to sit on regardless of their own colors. */
[data-theme="dark"] .exp-logo {
  background: #f2f0ea; border-radius: 6px; padding: 4px 6px; height: 26px; width: 58px;
}
.exp-role-wrap { display: grid; gap: 4px; min-width: 0; }
.exp-role { font: 600 clamp(16px,1.4vw,20px)/1.35 Archivo, sans-serif; letter-spacing: -0.015em; color: var(--ink); }
.exp-sector { font: 500 12px/1.3 'JetBrains Mono', monospace; letter-spacing: 0.01em; color: var(--ink-45); }
.dim2 { color: var(--ink-35); }
.exp-years { font: 400 12px/1 'JetBrains Mono', monospace; color: var(--ink-45); text-align: right; }

.edu-grid {
  margin-top: clamp(48px,6vw,86px); display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%,300px),1fr)); gap: clamp(28px,4vw,56px);
}
.edu-label { font: 500 11px/1 'JetBrains Mono', monospace; letter-spacing: 0.14em; color: var(--ink-4); margin-bottom: 16px; }
.edu-title { font: 600 15px/1.4 Archivo, sans-serif; margin-bottom: 4px; }
.edu-sub { font: 400 12.5px/1.6 'JetBrains Mono', monospace; color: var(--ink-55); margin-bottom: 18px; }
.also-list { display: grid; gap: 12px; font: 400 13.5px/1.5 Archivo, sans-serif; color: var(--ink-68); }

/* ===== References ===== */
.references-section { padding: clamp(44px,min(8.5vh,7vw),104px) clamp(24px,6vw,110px); max-width: 1120px; margin: 0 auto; }
.references-h2 { font: 600 clamp(26px,2.8vw,40px)/1.1 Archivo, sans-serif; letter-spacing: -0.035em; margin: 0 0 clamp(22px,3.6vh,34px); max-width: 24ch; text-wrap: balance; }
/* 270px, not 300px: at 300 the three cards no longer fit once the section's own
   horizontal padding grows on a wide screen, and auto-fit silently dropped to a
   two-row layout that ran past the fold. */
.references-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%,270px),1fr)); gap: 20px; margin-bottom: clamp(20px,3vh,30px); align-items: stretch; }
.ref-card {
  position: relative; overflow: hidden;
  border: 1px solid var(--border-14); border-radius: 18px; padding: clamp(24px,3vw,32px);
  background: var(--bg-raised-soft-2); display: grid; gap: 20px; align-content: start;
  transition: border-color .2s ease, background .2s ease, transform .25s ease, box-shadow .25s ease;
}
.ref-card:hover {
  border-color: var(--ink); background: var(--bg-raised);
  transform: translateY(-3px); box-shadow: 0 16px 32px rgba(20,19,15,0.08);
}
.ref-card::before {
  content: '\201C'; position: absolute; top: -6px; right: 18px;
  font: 700 84px/1 Georgia, 'Times New Roman', serif; color: var(--accent);
  opacity: 0.1; pointer-events: none;
}
.ref-person { position: relative; display: flex; align-items: center; gap: 14px; }
.ref-avatar {
  width: 52px; height: 52px; flex: none; border-radius: 50%; object-fit: cover;
  border: 1px solid var(--border-16); background: var(--bg-raised-soft-2);
  transition: border-color .2s ease;
}
.ref-card:hover .ref-avatar { border-color: var(--accent); }
.ref-name { font: 600 14.5px/1.3 Archivo, sans-serif; }
.ref-role { font: 400 11.5px/1.4 'JetBrains Mono', monospace; color: var(--ink-55); margin-top: 2px; }
/* Quotes vary a lot in length (one is three paragraphs). Clamping them to the
   same number of lines keeps the three cards the same height and the whole
   section inside one screen; the toggle below opens the full text. */
.ref-quote {
  position: relative; font: 400 italic 14.5px/1.62 Archivo, sans-serif;
  letter-spacing: -0.005em; color: var(--ink-72); text-wrap: pretty;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 8; overflow: hidden;
}
.ref-card.is-expanded .ref-quote { display: block; -webkit-line-clamp: unset; overflow: visible; }
.ref-quote p { margin: 0 0 12px; }
.ref-quote p:last-child { margin-bottom: 0; }
.ref-more {
  justify-self: start; margin-top: -8px; padding: 0; border: 0; background: none; cursor: pointer;
  font: 500 11.5px/1 'JetBrains Mono', monospace; letter-spacing: 0.04em;
  color: var(--accent-dark); font-family: 'JetBrains Mono', monospace;
}
.ref-more:hover { color: var(--accent); }
.references-link {
  display: inline-flex; align-items: center; gap: 10px;
  border: 1px solid var(--border-14); border-radius: 999px; padding: 18px 28px;
  font: 500 14px/1.3 'JetBrains Mono', monospace; color: var(--ink);
  transition: border-color .2s ease, background .2s ease, color .2s ease;
}
.references-link:hover { border-color: var(--accent); background: var(--bg-raised-soft-2); color: var(--accent-dark); }

/* ===== Projects ===== */
.projects-section { background: var(--bg); color: var(--ink); padding: clamp(44px,min(7vh,7vw),104px) clamp(24px,6vw,110px); transition: background .3s ease, color .3s ease; }
.projects-inner { max-width: 820px; margin: 0 auto; }
.projects-h2 { font: 600 clamp(28px,3.2vw,46px)/1.08 Archivo, sans-serif; letter-spacing: -0.035em; margin: 0 0 clamp(28px,5vh,46px); max-width: 26ch; text-wrap: balance; }

.case-study {
  border: 1px solid var(--border-14); border-radius: 18px; margin-bottom: 16px;
  background: var(--bg-raised-soft); overflow: hidden; transition: border-color .2s ease, background .3s ease;
}
.case-study:last-child { margin-bottom: 0; }

.case-toggle {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: clamp(22px,3vw,30px); background: none; border: none; cursor: pointer; text-align: left;
  color: inherit; font-family: inherit;
}
.case-toggle-head { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.case-category {
  font: 500 11px/1 'JetBrains Mono', monospace; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--accent-dark);
}
.case-title { font: 600 clamp(20px,2.4vw,30px)/1.2 Archivo, sans-serif; letter-spacing: -0.03em; color: var(--ink); }

.case-toggle-icon {
  flex: none; width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--border-16);
  position: relative; transition: border-color .2s ease, background .2s ease;
}
.case-toggle-icon::before, .case-toggle-icon::after {
  content: ''; position: absolute; background: var(--ink-6); transition: transform .3s ease, opacity .3s ease;
}
.case-toggle-icon::before { left: 9px; right: 9px; top: 14px; height: 1.5px; }
.case-toggle-icon::after { top: 9px; bottom: 9px; left: 14px; width: 1.5px; }
.case-toggle:hover .case-toggle-icon { border-color: var(--accent); }
.case-toggle[aria-expanded="true"] .case-toggle-icon::after { transform: rotate(90deg); opacity: 0; }

.case-content-wrap { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .4s cubic-bezier(.22,.8,.2,1); }
.case-content-wrap.open { grid-template-rows: 1fr; }
.case-content-inner {
  /* Only horizontal padding here — any top/bottom padding or border on the element
     being sized by the 0fr/1fr grid row still renders a sliver when "collapsed",
     since the row track controls height but padding/border are part of this box's
     own geometry. Vertical spacing instead lives on the children below. */
  overflow: hidden; min-height: 0; padding: 0 clamp(22px,3vw,30px);
}
.case-content-inner > .case-block:first-child {
  border-top: 1px solid var(--border-12); margin-top: 0;
  padding-top: clamp(20px,2.6vw,26px);
}
.case-content-inner > *:last-child { padding-bottom: clamp(22px,3vw,30px); }

.case-block { margin-bottom: 24px; }
.case-block:last-child { margin-bottom: 0; }
.case-label {
  font: 600 12px/1 'JetBrains Mono', monospace; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--ink-4); margin-bottom: 10px;
}
.case-block p { font: 400 15px/1.72 Archivo, sans-serif; color: var(--ink-68); margin: 0; text-wrap: pretty; }
.case-list { display: grid; gap: 11px; margin: 0; padding: 0; list-style: none; }
.case-list li { position: relative; padding-left: 22px; font: 400 15px/1.72 Archivo, sans-serif; color: var(--ink-68); text-wrap: pretty; }
.case-list li::before { content: '•'; position: absolute; left: 2px; color: var(--ink-4); }
.case-stats { display: flex; flex-wrap: wrap; gap: 10px 26px; }
.result-stat { font: 600 13.5px/1.3 'JetBrains Mono', monospace; color: var(--accent-dark); }
.case-link {
  display: inline-flex; gap: 8px; align-items: center; margin-top: 28px;
  font: 500 13px/1 'JetBrains Mono', monospace; color: var(--accent-dark);
}
.case-link:hover { color: var(--accent); }

/* ===== Contact ===== */
.contact-section {
  /* The footer now lives inside this section (see index.html) so the two
     share one viewport-tall block with no gap between them: column flex
     with auto margins centers .contact-inner in the leftover space while
     the footer keeps its own natural height at the bottom. Previously the
     footer was a separate element after this section, so the vertical
     centering left a large dead gap between the buttons and the footer at
     the very end of the page. */
  position: relative; overflow: hidden; background: #14130f; color: #f2f0ea;
  padding: clamp(56px,min(10vh,11vw),150px) clamp(24px,6vw,110px) 0;
  min-height: 100vh; min-height: 100svh;
  display: flex; flex-direction: column;
}
.contact-glow {
  position: absolute; width: 520px; height: 520px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, oklch(0.58 0.15 45 / 0.35), transparent 70%);
  left: 50%; top: 50%; transform: translate(-50%, -50%); filter: blur(10px);
}
.contact-inner { position: relative; width: 100%; max-width: 1400px; margin: auto auto; }
.contact-h2 { font: 700 clamp(40px,7vw,104px)/0.98 Archivo, sans-serif; letter-spacing: -0.05em; margin: 0 0 26px; text-wrap: balance; }
.contact-p { font: 400 clamp(15px,1.3vw,19px)/1.6 Archivo, sans-serif; color: rgba(242,240,234,0.66); max-width: 48ch; margin: 0 0 12px; text-wrap: pretty; }
.contact-availability { font: 400 13px/1.5 'JetBrains Mono', monospace; color: rgba(242,240,234,0.42); margin: 0 0 40px; }
.contact-buttons { display: flex; flex-wrap: wrap; gap: 12px; }
.contact-pill-solid { padding: 16px 26px; background: #f2f0ea; color: #14130f; }
.contact-pill-solid:hover { background: var(--accent); color: #fff; }
.contact-pill-outline { padding: 16px 26px; border: 1px solid rgba(242,240,234,0.25); }
.contact-pill-outline:hover { border-color: #f2f0ea; background: rgba(242,240,234,0.08); color: #f2f0ea; }

/* ===== Footer ===== */
.site-footer {
  display: flex; flex-wrap: wrap; gap: 14px; justify-content: space-between; align-items: center;
  padding: 26px clamp(24px,6vw,110px); font: 400 12px/1 'JetBrains Mono', monospace;
  /* Lives inside .contact-section now, which is always dark regardless of
     site theme — var(--ink-5) flips to a near-black in light mode and would
     be nearly invisible here, so this is a fixed light tone, not themed. */
  color: rgba(242,240,234,0.45);
}

/* ===== Responsive ===== */
@media (max-width: 860px) {
  .exp-row { grid-template-columns: 1fr; gap: 6px; }
  .exp-years { text-align: left; }
  .site-header { padding: 14px 16px; gap: 10px; }
  /* The scrollable text nav was undiscoverable (no scrollbar, "projects" sat
     off-screen) — collapse it behind a hamburger that opens a full-width
     dropdown instead. */
  .nav { display: none; }
  .nav-toggle { display: flex; }
  .mobile-nav { display: flex; }
  .pill-btn { flex-shrink: 0; }
  .header-pill { padding: 9px 12px; }
  .header-controls { gap: 6px; }
  .theme-toggle, .lang-toggle { width: 32px; height: 32px; min-width: 32px; }

  /* Hero photo: switch from a right-side strip to a full-width band across
     the bottom, so both her face and the laptop show without empty margins,
     and pull the text block up close to it instead of leaving a dead gap.
     Band is taller than on desktop so the face has room to clear the copy
     block above it (was getting cut by the skill pills/CTA buttons). */
  .photo-wrap { left: 0; right: 0; top: auto; bottom: 0; width: 100%; height: 58vh; transform-origin: 50% 74%; }
  /* This glow is positioned by percentage to sit on her face in the desktop
     right-side strip crop — on the mobile full-width band it lands over a
     different part of the photo (her forehead), reading as a hazy blur
     layer over the face. Not essential; simplest fix is to drop it here. */
  .glow-face { display: none; }
  .hero-photo {
    /* Lower Y shows more of the office ceiling/windows above her head
       instead of cropping tight to the face. */
    object-position: 38% 20%;
    /* Stays fully clear until well past her face (~80% up the band) — the
       previous fade started at 78%, which landed squarely on her forehead
       and read as a shadow across the face. Only the sliver above her head
       (80-100%) blends into the dark hero-copy block above. */
    -webkit-mask-image: linear-gradient(to top, #000 70%, transparent 100%);
    mask-image: linear-gradient(to top, #000 70%, transparent 100%);
  }
  /* Lighter than before and spread over a longer run, so the photo reads
     through the top of the band (office windows visible above her head)
     instead of being blacked out — while still easing gradually into the
     dark hero-copy block above instead of a hard seam. */
  .grade-1 {
    background: linear-gradient(to top, rgba(11,11,9,0) 0%, rgba(11,11,9,0) 78%, rgba(11,11,9,0.4) 92%, rgba(11,11,9,0.75) 100%);
  }
  .grade-2 { background: none; }
  /* Anchor the copy to the top rather than centring it: when the block is
     taller than the space left above the photo, centring pushed the H1 up
     under the header and clipped it. Overflow now runs downward instead, into
     the darkest part of the gradient, where it stays readable. */
  .hero-copy {
    padding-top: clamp(76px,9vh,100px); padding-bottom: calc(47vh + 8px);
    justify-content: flex-start;
  }
  .hero-h1 { margin-bottom: 12px; }
  .hero-tagline { max-width: 34ch; }
  .hero-status { margin-top: 14px; }
  /* Secondary flourish line — the tagline above already carries the message,
     and every line here competes with the photo for the same tight band. */
  .hero-flow { display: none; }
  .hero-skills { margin-top: 10px; gap: 7px; max-width: 100%; }
  .skill-pill { font-size: 10.5px; padding: 6.5px 11px; }
  .hero-icon-links { margin-top: 16px; gap: 10px; }
  .hero-cta-btn { padding: 12px 20px; }
  .hero-hint {
    background: rgba(13,13,11,0.55); backdrop-filter: blur(6px);
    padding: 7px 12px; border-radius: 999px; bottom: 18px;
  }
}

@media (max-width: 400px) {
  .hero-skills li:nth-child(n+4) { display: none; }
}
