/* =============================================
   FONTS — self-hosted Neue Machina
============================================= */
@font-face {
  font-family: 'NeueMachina';
  src: url('assets/fonts/NeueMachina-Regular.otf') format('opentype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'NeueMachina';
  src: url('assets/fonts/NeueMachina-Ultrabold.otf') format('opentype');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}


/* =============================================
   DESIGN TOKENS
============================================= */
:root {
  --color-bg: #FFFFFF;
  --color-fg: #000000;
  --font-primary: 'NeueMachina', sans-serif;
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.76, 0, 0.24, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --duration-fast: 0.3s;
  --duration-base: 0.6s;
  --duration-slow: 1.0s;
  --max-width: 1280px;
  --gutter: 80px;
}


/* =============================================
   RESET
============================================= */
*, *::before, *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html { scroll-behavior: smooth; }

body {
  font-family: var(--font-primary);
  background: var(--color-bg);
  color: var(--color-fg);
  line-height: 1.65;
  font-size: 16px;
}


/* =============================================
   INTRO LOADER
============================================= */
#loader {
  position: fixed;
  inset: 0;
  background: var(--color-fg);
  z-index: 9000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 28px;
  transition: opacity 0.9s var(--ease-out-expo), visibility 0.9s;
}
#loader.loader-exit {
  opacity: 0;
  visibility: hidden;
}

/* Bouncing white dot */
#loader-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-bg);
  animation: loaderBounce 0.7s var(--ease-in-out) infinite alternate;
}
@keyframes loaderBounce {
  from { transform: translateY(-20px); }
  to   { transform: translateY(20px);  }
}

/* Logo — compresses when hit by dot */
#loader-logo {
  transition: transform 0.15s var(--ease-in-out);
}
#loader-logo.compressed {
  transform: scaleY(0.72);
}
#loader-logo-svg {
  width: 52px;
  height: 52px;
  display: block;
}

/* Counter */
#loader-counter {
  font-family: var(--font-primary);
  font-size: clamp(14px, 2vw, 18px);
  font-weight: 400;
  letter-spacing: 0.2em;
  color: var(--color-bg);
  opacity: 0.7;
  min-width: 3ch;
  text-align: center;
}

/* Dot expands to fill screen on reveal */
#loader-dot.loader-expand {
  animation: none;
  transform: none;
  transition:
    width    0.7s var(--ease-out-expo),
    height   0.7s var(--ease-out-expo),
    border-radius 0.7s var(--ease-out-expo);
  width: 300vmax;
  height: 300vmax;
  border-radius: 50%;
}

/* Skip loader if user prefers reduced motion */
@media (prefers-reduced-motion: reduce) {
  #loader { display: none; }
}


/* =============================================
   SCROLL-TO-TOP BUTTON
============================================= */
#scroll-top {
  position: fixed;
  bottom: 40px;
  right: 40px;
  z-index: 90;
  width: 44px;
  height: 44px;
  border: 1px solid var(--color-fg);
  background: var(--color-bg);
  color: var(--color-fg);
  font-size: 16px;
  font-family: var(--font-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity    var(--duration-fast) var(--ease-out-expo),
    transform  var(--duration-fast) var(--ease-out-expo),
    background var(--duration-fast) var(--ease-out-expo),
    color      var(--duration-fast) var(--ease-out-expo);
  pointer-events: none;
}
#scroll-top.visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
#scroll-top:hover {
  background: var(--color-fg);
  color: var(--color-bg);
}
@media (max-width: 768px) {
  #scroll-top {
    bottom: 24px;
    right: 24px;
    width: 40px;
    height: 40px;
  }
}


/* =============================================
   SKIP LINK — accessibility
============================================= */
.skip-link {
  position: absolute;
  top: -48px;
  left: var(--gutter);
  background: var(--color-fg);
  color: var(--color-bg);
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-decoration: none;
  z-index: 200;
  transition: top var(--duration-fast) var(--ease-out-expo);
}
.skip-link:focus { top: 8px; }


/* =============================================
   CUSTOM CURSOR DOT
============================================= */
#cursor-dot {
  width: 8px;
  height: 8px;
  background: var(--color-fg);
  border-radius: 50%;
  position: fixed;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 9999;
  transform: translate(-50%, -50%);
  transition:
    width  var(--duration-fast) var(--ease-spring),
    height var(--duration-fast) var(--ease-spring);
}
#cursor-dot.expanded {
  width: 24px;
  height: 24px;
}
/* Hide on touch devices */
@media (hover: none) {
  #cursor-dot { display: none; }
}

/* Global cursor:none on hover-capable devices so every interactive
   element uses the custom dot — including dynamically revealed ones */
@media (hover: hover) {
  body,
  a, button, label, summary,
  input, textarea, select,
  [role="button"], [tabindex],
  .expertise-card, .achievement-item {
    cursor: none !important;
  }
}


/* =============================================
   NAVIGATION
============================================= */
#site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px var(--gutter);
  background: var(--color-bg);
  border-bottom: 1px solid transparent;
  transition: border-color var(--duration-fast) var(--ease-out-expo);
}

#site-nav.scrolled {
  border-bottom-color: var(--color-fg);
}

.nav-logo {
  display: flex;
  align-items: center;
  color: var(--color-fg);
  text-decoration: none;
}

.nav-links {
  list-style: none;
  display: flex;
  gap: 40px;
}

/* Nav links start hidden — JS adds .nav-visible at 1.4s */
.nav-link {
  opacity: 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-fg);
  text-decoration: none;
  transition: opacity 0.4s var(--ease-out-expo);
}
.nav-link.nav-visible {
  opacity: 1;
}
.nav-link.nav-visible:hover {
  opacity: 0.5;
}
/* Active link — full opacity; dim siblings when one is active */
.nav-link.nav-active {
  opacity: 1 !important;
}
.nav-links:has(.nav-active) .nav-link:not(.nav-active) {
  opacity: 0.35;
}

/* ---- Hamburger button (mobile only) ---- */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  background: none;
  border: none;
  padding: 8px;
  cursor: none;
  z-index: 101;
  position: relative;
}
.nav-toggle span {
  display: block;
  width: 22px;
  height: 1.5px;
  background: var(--color-fg);
  transition:
    transform var(--duration-fast) var(--ease-out-expo),
    opacity  var(--duration-fast) var(--ease-out-expo);
}
.nav-toggle.open span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav-toggle.open span:nth-child(2) { opacity: 0; transform: scaleX(0); }
.nav-toggle.open span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }
@media (hover: none) { .nav-toggle { cursor: auto; } }

/* ---- Full-screen mobile overlay ---- */
.nav-mobile-menu {
  position: fixed;
  inset: 0;
  background: var(--color-bg);
  z-index: 99;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 36px;
  padding: 0 40px;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-base) var(--ease-out-expo);
}
.nav-mobile-menu.open {
  opacity: 1;
  pointer-events: auto;
}
.nav-mobile-link {
  font-size: clamp(28px, 8vw, 42px);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--color-fg);
  text-decoration: none;
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity   0.4s var(--ease-out-expo),
    transform 0.4s var(--ease-out-expo),
    color     var(--duration-fast) var(--ease-out-expo);
}
.nav-mobile-menu.open .nav-mobile-link {
  opacity: 1;
  transform: translateY(0);
}
/* Stagger link entrances */
.nav-mobile-menu.open .nav-mobile-link:nth-child(1) { transition-delay: 0.04s; }
.nav-mobile-menu.open .nav-mobile-link:nth-child(2) { transition-delay: 0.08s; }
.nav-mobile-menu.open .nav-mobile-link:nth-child(3) { transition-delay: 0.12s; }
.nav-mobile-menu.open .nav-mobile-link:nth-child(4) { transition-delay: 0.16s; }
.nav-mobile-menu.open .nav-mobile-link:nth-child(5) { transition-delay: 0.20s; }
.nav-mobile-link:hover { opacity: 0.45; }

@media (max-width: 768px) {
  .nav-links  { display: none; }
  .nav-toggle { display: flex; }
}


/* =============================================
   HERO SECTION
============================================= */
#hero {
  position: relative;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  overflow: hidden;
  padding-top: 68px; /* clears fixed nav */
}

/* --- Background illustration wrap --- */
.hero-bg-wrap {
  position: absolute;
  inset: 0;
  opacity: 0.08;           /* 8% per spec */
  pointer-events: none;
  will-change: transform;  /* parallax target */
  color: var(--color-fg);  /* SVG currentColor inherits from here */
}

.hero-bg-svg {
  width: 100%;
  height: 100%;
}

/* --- Node drift animations ---
   Each group translates on a slow, looping path.
   transform-origin: center of SVG viewport.
   Using translate only (no rotation) keeps the grid
   feeling structured rather than chaotic. */

.bg-nodes-slow {
  animation: nodeDriftA 18s var(--ease-in-out) infinite alternate;
}
.bg-nodes-mid {
  animation: nodeDriftB 24s var(--ease-in-out) infinite alternate;
  animation-delay: -6s; /* offset phase so groups don't move in unison */
}
.bg-nodes-fast {
  animation: nodeDriftC 14s var(--ease-in-out) infinite alternate;
  animation-delay: -4s;
}

@keyframes nodeDriftA {
  0%   { transform: translate(0px,  0px); }
  33%  { transform: translate(6px, -4px); }
  66%  { transform: translate(-4px, 7px); }
  100% { transform: translate(8px,  3px); }
}
@keyframes nodeDriftB {
  0%   { transform: translate(0px,   0px); }
  25%  { transform: translate(-7px,  5px); }
  50%  { transform: translate(5px,  -6px); }
  75%  { transform: translate(-3px,  8px); }
  100% { transform: translate(7px,  -3px); }
}
@keyframes nodeDriftC {
  0%   { transform: translate(0px,  0px); }
  40%  { transform: translate(5px, -8px); }
  100% { transform: translate(-6px, 4px); }
}

/* --- Line pulse animations ---
   Three groups pulse opacity on staggered durations so the
   network feels alive without reading as a uniform blink. */
.bg-lines-a {
  animation: linePulse 5s var(--ease-in-out) infinite;
}
.bg-lines-b {
  animation: linePulse 7s var(--ease-in-out) infinite;
  animation-delay: -2s;
}
.bg-lines-c {
  animation: linePulse 6s var(--ease-in-out) infinite;
  animation-delay: -4s;
}

@keyframes linePulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.25; }
}

/* --- Ring slow rotation ---
   Dashed stroke-dasharray makes the rotation visible. */
.bg-rings {
  transform-origin: 720px 450px; /* centre of SVG viewport */
  animation: ringRotate 40s linear infinite;
}
@keyframes ringRotate {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* --- Accent node breathe ---
   Hollow circles scale subtly to create a heartbeat effect. */
.bg-accents {
  transform-origin: center;
  animation: accentBreathe 4s var(--ease-in-out) infinite alternate;
}
@keyframes accentBreathe {
  from { transform: scale(1);   opacity: 0.6; }
  to   { transform: scale(1.6); opacity: 1;   }
}

/* Pause all background animations when user prefers reduced motion */
@media (prefers-reduced-motion: reduce) {
  .bg-nodes-slow,
  .bg-nodes-mid,
  .bg-nodes-fast,
  .bg-lines-a,
  .bg-lines-b,
  .bg-lines-c,
  .bg-rings,
  .bg-accents {
    animation: none;
  }
}

/* --- Main content area --- */
.hero-content {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 96px var(--gutter) 80px;
}

/* --- Location label --- */
.hero-location {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.55);
  margin-bottom: 24px;
  opacity: 0;
  transition: opacity 0.9s var(--ease-out-expo);
}
#hero.hero-visible .hero-location {
  opacity: 0.45;
}

/* --- Name — text mask reveal --- */
.hero-name-wrap {
  margin-bottom: 20px;
  overflow: visible;
}

.hero-name {
  font-size: clamp(72px, 9vw, 120px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.25em;
}

/* Mask container — clips child so text appears to rise into view */
.mask-parent {
  display: inline-block;
  overflow: hidden;
  line-height: 1.05;
  vertical-align: bottom;
}

/* Text child — starts below clip boundary, slides up on .name-revealed.
   No base delay here — JS controls exactly when .name-revealed is added.
   --stagger adds 60ms per word so "Lexy" leads "Khoo" by one beat. */
.mask-child {
  display: inline-block;
  transform: translateY(105%);
  opacity: 0;
  transition:
    transform 0.7s var(--ease-out-expo) calc(var(--stagger, 0) * 60ms),
    opacity   0.3s var(--ease-out-expo) calc(var(--stagger, 0) * 60ms);
}
.mask-child.name-revealed {
  transform: translateY(0);
  opacity: 1;
}

/* --- Title / subtitle --- */
.hero-title {
  font-size: clamp(16px, 1.6vw, 20px);
  font-weight: 400;
  letter-spacing: 0.01em;
  color: rgba(0, 0, 0, 0.75);
  line-height: 1.5;
  margin-bottom: 28px;
}

/* --- Summary paragraph --- */
.hero-summary {
  font-size: clamp(16px, 1.4vw, 18px);
  font-weight: 400;
  line-height: 1.7;
  color: rgba(0, 0, 0, 0.85);
  max-width: 580px;
  margin-bottom: 64px;
}

/* --- Generic hero fade-in
   Triggered by #hero.hero-visible (JS adds the class when loader exits).
   All elements appear simultaneously — no staggered delays. --- */
.hero-fade-in {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity   0.9s var(--ease-out-expo),
    transform 0.9s var(--ease-out-expo);
}
#hero.hero-visible .hero-fade-in {
  opacity: 1;
  transform: translateY(0);
}

/* --- Keyframes --- */
@keyframes heroFadeUp {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes heroLocationIn {
  from { opacity: 0; }
  to   { opacity: 0.45; }
}

/* --- Stat blocks row --- */
.hero-stats {
  display: flex;
  align-items: flex-start;
  gap: 0;
}

.stat-block {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-right: 56px;
}
.stat-block:last-child { padding-right: 0; }

.stat-number {
  font-size: clamp(48px, 5.5vw, 68px);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1;
}

.stat-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.60);
  max-width: 180px;
  line-height: 1.45;
}

/* Thin vertical divider between stat blocks */
.stat-divider {
  width: 1px;
  height: 56px;
  background: rgba(0, 0, 0, 0.15);
  align-self: center;
  flex-shrink: 0;
  margin-right: 56px;
}

/* --- Scroll hint --- */
.hero-scroll-hint {
  position: absolute;
  bottom: 40px;
  left: var(--gutter);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.scroll-line {
  display: block;
  width: 1.5px;
  height: 48px;
  background: rgba(0, 0, 0, 0.5);
  animation: scrollPulse 2s var(--ease-in-out) 2.2s infinite;
  transform-origin: top;
}

@keyframes scrollPulse {
  0%   { transform: scaleY(1);   opacity: 1; }
  50%  { transform: scaleY(0.3); opacity: 0.3; }
  100% { transform: scaleY(1);   opacity: 1; }
}

.scroll-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.5);
  writing-mode: vertical-rl;
  text-orientation: mixed;
}



/* =============================================
   REDUCED MOTION — respect system preference
============================================= */
@media (prefers-reduced-motion: reduce) {
  .mask-child,
  .hero-fade-in,
  .scroll-line,
  .nav-link {
    animation: none !important;
    transition: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  .hero-location {
    transition: none !important;
    opacity: 0.45 !important;
  }
}


/* =============================================
   RESPONSIVE
============================================= */
@media (max-width: 1024px) {
  #site-nav {
    padding-left: 48px;
    padding-right: 48px;
  }
  .hero-content {
    padding: 80px 48px 64px;
  }
}

@media (max-width: 768px) {
  :root {
    --gutter: 24px;
  }
  #site-nav {
    padding-left: 24px;
    padding-right: 24px;
  }
  .hero-content {
    padding: 72px 24px 56px;
  }
  .hero-stats {
    flex-direction: column;
    gap: 32px;
  }
  .stat-divider {
    display: none;
  }
  .stat-block {
    padding-right: 0;
  }
  .hero-summary {
    max-width: 100%;
    margin-bottom: 48px;
  }
  .hero-scroll-hint {
    display: none;
  }
}


/* =============================================
   SCROLL REVEAL — shared across all sections
   .reveal-item starts invisible, fades up when
   .is-revealed is added by Intersection Observer.
   --reveal-delay (integer) staggers siblings at 100ms each.
============================================= */
.reveal-item {
  opacity: 0;
  transform: translateY(30px);
  transition:
    opacity   0.6s var(--ease-out-expo) calc(var(--reveal-delay, 0) * 100ms),
    transform 0.6s var(--ease-out-expo) calc(var(--reveal-delay, 0) * 100ms);
}
.reveal-item.is-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* Section heading words use the existing .mask-child pattern
   but are triggered by scroll (not page load timer).
   .is-revealed mirrors .name-revealed from the hero. */
.mask-child.is-revealed {
  transform: translateY(0);
  opacity: 1;
}

/* Pause reveals when user prefers reduced motion */
@media (prefers-reduced-motion: reduce) {
  .reveal-item {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .mask-child.section-word {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}


/* =============================================
   SHARED SECTION LAYOUT
============================================= */
.section-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 120px var(--gutter);
}

/* Small-caps label used at the top of each section */
.section-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.60);
  margin-bottom: 20px;
}

/* Section heading — mask-parent/mask-child children,
   same clamp scale as .hero-name but smaller */
.section-heading-wrap {
  margin-bottom: 72px;
}
.section-heading {
  font-size: clamp(36px, 4.5vw, 56px);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.05;
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.25em;
}


/* =============================================
   WORK EXPERIENCE SECTION
============================================= */
#work {
  position: relative;
  overflow: hidden;
  background: var(--color-bg);
  border-top: 1px solid rgba(0, 0, 0, 0.08);
}

/* --- Timeline container ---
   padding-left creates space for the 1px line + dot. */
.work-timeline {
  position: relative;
  padding-left: 48px;
}

/* Vertical 1px rule running the full height */
.timeline-line {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 1px;
  background: rgba(0, 0, 0, 0.12);
}

/* --- Role block --- */
.role-block {
  position: relative;
  padding-bottom: 80px;
}
.role-block:last-child {
  padding-bottom: 0;
}

/* Small filled dot centred on the timeline line.
   left: calc(-48px - 4px) puts the dot centre (4px) at left: 0 of
   .work-timeline, i.e. exactly on the 1px line. */
.role-block::before {
  content: '';
  position: absolute;
  left: -52px;
  top: 12px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--color-fg);
}

/* --- Role header --- */
.role-header {
  margin-bottom: 28px;
}

.role-tenure {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.55);
  margin-bottom: 8px;
}

.role-title {
  font-size: clamp(20px, 2.2vw, 26px);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin-bottom: 6px;
}

.role-org {
  font-size: 14px;
  font-weight: 600;
  color: rgba(0, 0, 0, 0.75);
  margin-bottom: 10px;
}

/* Inline source link(s) */
.role-source {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.55);
  text-decoration: none;
  border-bottom: 1px solid rgba(0, 0, 0, 0.15);
  transition:
    color        var(--duration-fast) var(--ease-out-expo),
    border-color var(--duration-fast) var(--ease-out-expo);
}
.role-source:hover {
  color: var(--color-fg);
  border-color: var(--color-fg);
}

/* Multiple sources on Switch Health */
.role-sources {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin-top: 2px;
}

/* --- Role body --- */
.role-summary {
  font-size: clamp(15px, 1.35vw, 17px);
  line-height: 1.75;
  color: rgba(0, 0, 0, 0.85);
  max-width: 680px;
  margin-bottom: 16px;
}
.role-summary:last-of-type {
  margin-bottom: 0;
}

/* Hint label — mobile only (desktop rows signal via hover) */
.achievements-hint {
  display: none;
}
@media (hover: none) {
  .achievements-hint {
    display: block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(0, 0, 0, 0.45);
    margin-top: 28px;
    margin-bottom: 8px;
  }
}

/* Expandable achievements list — solid black table */
.role-achievements {
  list-style: none;
  border: 1px solid var(--color-fg);
  margin-top: 28px;
}
.role-achievements li {
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.role-achievements li:last-child {
  border-bottom: none;
}

/* Row default: black background, white text */
.achievement-item > summary {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 20px;
  font-size: 14px;
  line-height: 1.65;
  color: var(--color-bg);
  background: var(--color-fg);
  list-style: none;
  user-select: none;
  transition:
    background var(--duration-fast) var(--ease-out-expo),
    color      var(--duration-fast) var(--ease-out-expo);
}
.achievement-item > summary::-webkit-details-marker {
  display: none;
}

/* + sign — white on black */
.achievement-item > summary::before {
  content: '+';
  flex-shrink: 0;
  font-size: 18px;
  font-weight: 800;
  color: var(--color-bg);
  width: 16px;
  text-align: center;
  transition:
    transform var(--duration-fast) var(--ease-out-expo),
    color     var(--duration-fast) var(--ease-out-expo);
}

/* Desktop hover: flip to white bg, black text, + slides right */
@media (hover: hover) {
  .achievement-item:not([open]) > summary:hover {
    background: var(--color-bg);
    color: var(--color-fg);
  }
  .achievement-item:not([open]) > summary:hover::before {
    color: var(--color-fg);
    transform: translateX(5px);
  }
}

/* Open state: white bg, black text, − sign */
.achievement-item[open] > summary {
  background: var(--color-bg);
  color: var(--color-fg);
}
.achievement-item[open] > summary::before {
  content: '−';
  color: var(--color-fg);
  transform: none;
}

/* Smooth expand/collapse — grid-template-rows trick.
   display: grid overrides UA stylesheet's display:none on
   non-summary <details> children, so the element is always
   rendered but visually clipped to 0 height when closed. */
details > .achievement-body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.4s var(--ease-out-expo);
}
details[open] > .achievement-body {
  grid-template-rows: 1fr;
}
.achievement-body-inner {
  overflow: hidden;
}

/* Expanded context paragraph — white bg continues from open summary */
.achievement-detail {
  padding: 12px 20px 16px 50px;
  font-size: 14px;
  line-height: 1.75;
  color: rgba(0, 0, 0, 0.75);
  max-width: 640px;
  background: var(--color-bg);
  border-top: 1px solid rgba(0, 0, 0, 0.08);
}

/* One-time attention pulse on the first + sign to hint expandability.
   Class is added by JS to the first summary element. */
@keyframes hintPulse {
  0%   { transform: scale(1);    opacity: 0.55; }
  40%  { transform: scale(1.6);  opacity: 1;    }
  70%  { transform: scale(0.85); opacity: 0.8;  }
  100% { transform: scale(1);    opacity: 0.55; }
}
summary.achievement-hint-summary::before {
  animation: hintPulse 0.9s var(--ease-spring) 0.6s 3 forwards;
}


/* =============================================
   WORK — RESPONSIVE
============================================= */
@media (max-width: 1024px) {
  .section-inner {
    padding: 96px 48px;
  }
}

@media (max-width: 768px) {
  .section-inner {
    padding: 80px var(--gutter);
  }
  .section-heading-wrap {
    margin-bottom: 48px;
  }
  /* Hide timeline chrome on mobile — too narrow to read */
  .work-timeline {
    padding-left: 0;
  }
  .timeline-line,
  .role-block::before {
    display: none;
  }
  .role-block {
    padding-bottom: 48px;
  }
  .role-summary {
    max-width: 100%;
  }
}


/* =============================================
   WORK — BACKGROUND ILLUSTRATION
   Same pattern as .hero-bg-wrap: absolutely
   positioned, 8% opacity, currentColor for
   black/white system, will-change for GPU layer.
============================================= */
.work-bg-wrap {
  position: absolute;
  inset: 0;
  opacity: 0.08;
  pointer-events: none;
  color: var(--color-fg);
  will-change: opacity; /* stays on GPU composite layer */
}

.work-bg-svg {
  width: 100%;
  height: 100%;
}

/* --- Grid pulse — slow scan effect --- */
.work-grid {
  animation: workGridPulse 9s var(--ease-in-out) infinite;
}

/* --- Cross-hatch patches — staggered so they're never in phase --- */
.work-crosshatch-a {
  animation: workGridPulse 5s var(--ease-in-out) infinite;
}
.work-crosshatch-b {
  animation: workGridPulse 6s var(--ease-in-out) infinite;
  animation-delay: -3s;
}

/* --- Main growth path — subtle pulse, offset from grid --- */
.work-path-edges {
  animation: workGridPulse 7s var(--ease-in-out) infinite;
  animation-delay: -1.5s;
}
.work-path-tertiary {
  animation: workGridPulse 8s var(--ease-in-out) infinite;
  animation-delay: -5s;
}

/* --- Arrows — fast pulse simulates flow direction along path --- */
.work-arrows {
  animation: workArrowPulse 2.5s var(--ease-in-out) infinite;
}

/* --- Primary milestone nodes — slow drift in growth direction --- */
.work-nodes-primary {
  animation: workNodeDrift 22s var(--ease-in-out) infinite alternate;
}

/* --- Concentric rings at peak — slow rotation ---
   transform-origin set to the peak node centre (1200px 180px). */
.work-rings {
  transform-origin: 1200px 180px;
  animation: ringRotate 55s linear infinite;
}

/* --- Secondary nodes — counter-drift for relative motion --- */
.work-nodes-secondary {
  animation: workNodeDriftB 16s var(--ease-in-out) infinite alternate;
  animation-delay: -5s;
}

/* --- Tertiary nodes — slower version of primary drift --- */
.work-nodes-tertiary {
  animation: workNodeDrift 30s var(--ease-in-out) infinite alternate;
  animation-delay: -8s;
}

/* --- Crosshairs — breathe scale, centred on their own bounding box ---
   transform-box: fill-box makes transform-origin relative to the <g> itself. */
.work-crosshair {
  transform-box: fill-box;
  transform-origin: 50% 50%;
  animation: workCrosshairBreathe 4s var(--ease-in-out) infinite alternate;
}
/* Stagger each crosshair so they don't pulse in unison */
.work-crosshair:nth-child(2) { animation-delay: -1.5s; }
.work-crosshair:nth-child(3) { animation-delay: -3s;   }


/* --- Keyframes --- */

/* Grid / path pulse — same shape as linePulse but named separately */
@keyframes workGridPulse {
  0%, 100% { opacity: 1;   }
  50%       { opacity: 0.3; }
}

/* Arrow flow — dips almost to invisible, simulating pulse along path */
@keyframes workArrowPulse {
  0%, 100% { opacity: 1;    }
  50%       { opacity: 0.05; }
}

/* Primary node drift — small translate along the growth direction (up-right) */
@keyframes workNodeDrift {
  0%   { transform: translate(0px,  0px); }
  33%  { transform: translate(5px, -3px); }
  66%  { transform: translate(-2px, 5px); }
  100% { transform: translate(6px, -4px); }
}

/* Counter-drift for secondary nodes — creates relative motion with primaries */
@keyframes workNodeDriftB {
  0%   { transform: translate(0px,   0px); }
  25%  { transform: translate(-4px,  3px); }
  75%  { transform: translate(3px,  -5px); }
  100% { transform: translate(-5px,  2px); }
}

/* Crosshair breathe — subtle scale around element centre */
@keyframes workCrosshairBreathe {
  from { opacity: 0.6; transform: scale(1);    }
  to   { opacity: 1;   transform: scale(1.25); }
}

/* Pause all work background animations when user prefers reduced motion */
@media (prefers-reduced-motion: reduce) {
  .work-grid,
  .work-crosshatch-a,
  .work-crosshatch-b,
  .work-path-edges,
  .work-path-tertiary,
  .work-arrows,
  .work-nodes-primary,
  .work-rings,
  .work-nodes-secondary,
  .work-nodes-tertiary,
  .work-crosshair {
    animation: none;
  }
}


/* =============================================
   EXPERTISE SECTION
============================================= */
#expertise {
  background: var(--color-bg);
  border-top: 1px solid rgba(0, 0, 0, 0.08);
}

/* --- 2×2 card grid ---
   gap: 1px + grid background acts as the shared border between cards.
   The outer border closes the frame. */
.expertise-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(0, 0, 0, 0.1);
}

/* --- Individual card --- */
.expertise-card {
  background: var(--color-bg);
  display: flex;
  flex-direction: column;
  /* Override reveal-item's 30px — spec calls for 24px on cards */
  transform: translateY(24px);
}

/* --- Illustration area ---
   4:3 ratio matches the SVG viewBox (400×300) exactly — no cropping. */
.card-illustration {
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
.card-illustration svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* =============================================
   EXPERTISE CARD SVG ANIMATIONS
   Each card's illustration groups are animated
   only after .is-revealed is added (performance).
   Animations pause on un-revealed cards.
============================================= */

/* Pause all card animations until revealed */
.expertise-card:not(.is-revealed) .c1-filled,
.expertise-card:not(.is-revealed) .c1-outline,
.expertise-card:not(.is-revealed) .c2-source,
.expertise-card:not(.is-revealed) .c2-arrows-l,
.expertise-card:not(.is-revealed) .c2-arrows-r,
.expertise-card:not(.is-revealed) .c2-activate,
.expertise-card:not(.is-revealed) .c3-dots-odd,
.expertise-card:not(.is-revealed) .c3-dots-even,
.expertise-card:not(.is-revealed) .c3-rings,
.expertise-card:not(.is-revealed) .c3-trend,
.expertise-card:not(.is-revealed) .c4-arrow1,
.expertise-card:not(.is-revealed) .c4-step2,
.expertise-card:not(.is-revealed) .c4-arrow2,
.expertise-card:not(.is-revealed) .c4-diamond,
.expertise-card:not(.is-revealed) .c4-branch-a,
.expertise-card:not(.is-revealed) .c4-branch-b {
  animation-play-state: paused;
}

/* --- Card 1: Gantt — filled vs outline counter-pulse --- */
.c1-filled  { animation: c1Active 3s var(--ease-in-out) infinite; }
.c1-outline { animation: c1Active 3s var(--ease-in-out) infinite reverse; animation-delay: -1.5s; }
@keyframes c1Active {
  0%, 100% { opacity: 1;    }
  50%       { opacity: 0.15; }
}

/* --- Card 2: Pipeline — left-to-right relay wave --- */
.c2-source   { animation: c2Wave 3.5s var(--ease-in-out) infinite; }
.c2-arrows-l { animation: c2Wave 3.5s var(--ease-in-out) infinite; animation-delay: 0.55s; }
.c2-arrows-r { animation: c2Wave 3.5s var(--ease-in-out) infinite; animation-delay: 1.1s; }
.c2-activate { animation: c2Wave 3.5s var(--ease-in-out) infinite; animation-delay: 1.65s; }
@keyframes c2Wave {
  0%, 12%   { opacity: 0.15; }
  22%, 55%  { opacity: 1;    }
  65%, 100% { opacity: 0.15; }
}

/* --- Card 3: Dot matrix + trend draw-on --- */
.c3-dots-odd  { animation: c3Breathe 3s var(--ease-in-out) infinite; }
.c3-dots-even { animation: c3Breathe 3s var(--ease-in-out) infinite; animation-delay: -1.5s; }
.c3-rings     { animation: c3Breathe 2.2s var(--ease-in-out) infinite; animation-delay: -0.8s; }
.c3-trend {
  stroke-dasharray: 240;
  stroke-dashoffset: 240;
  animation: c3Draw 5s var(--ease-out-expo) infinite;
}
@keyframes c3Breathe {
  0%, 100% { opacity: 1;    }
  50%       { opacity: 0.12; }
}
@keyframes c3Draw {
  0%   { stroke-dashoffset: 240; opacity: 0; }
  8%   { stroke-dashoffset: 220; opacity: 1; }
  55%  { stroke-dashoffset: 0;   opacity: 1; }
  70%  { stroke-dashoffset: 0;   opacity: 0; }
  72%  { stroke-dashoffset: 240; opacity: 0; }
  100% { stroke-dashoffset: 240; opacity: 0; }
}

/* --- Card 4: Operations flow — sequential relay --- */
.c4-arrow1   { animation: c4Flow 4.5s var(--ease-in-out) infinite; animation-delay: 0s;   }
.c4-step2    { animation: c4Flow 4.5s var(--ease-in-out) infinite; animation-delay: 0.55s; }
.c4-arrow2   { animation: c4Flow 4.5s var(--ease-in-out) infinite; animation-delay: 1.1s;  }
.c4-diamond  { animation: c4Flow 4.5s var(--ease-in-out) infinite; animation-delay: 1.65s; }
.c4-branch-a { animation: c4Flow 4.5s var(--ease-in-out) infinite; animation-delay: 2.2s;  }
.c4-branch-b { animation: c4Flow 4.5s var(--ease-in-out) infinite; animation-delay: 2.6s;  }
@keyframes c4Flow {
  0%, 10%   { opacity: 0.15; }
  20%, 55%  { opacity: 1;    }
  65%, 100% { opacity: 0.15; }
}

/* Reduced motion — disable all card animations */
@media (prefers-reduced-motion: reduce) {
  .c1-filled, .c1-outline,
  .c2-source, .c2-arrows-l, .c2-arrows-r, .c2-activate,
  .c3-dots-odd, .c3-dots-even, .c3-rings, .c3-trend,
  .c4-arrow1, .c4-step2, .c4-arrow2, .c4-diamond, .c4-branch-a, .c4-branch-b {
    animation: none !important;
    opacity: 1 !important;
  }
  .c3-trend { stroke-dashoffset: 0; }
}

/* --- Card body --- */
.card-body {
  padding: 28px 32px 32px;
  display: flex;
  flex-direction: column;
  flex: 1; /* fills remaining card height so tags always sit at bottom */
}

.card-title {
  font-size: clamp(17px, 1.6vw, 20px);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  margin-bottom: 14px;
}

.card-description {
  font-size: clamp(14px, 1.25vw, 15px);
  line-height: 1.75;
  color: rgba(0, 0, 0, 0.80);
  flex: 1;          /* pushes tag row to bottom of card */
  margin-bottom: 24px;
}

/* --- Skill tag chips --- */
.card-tags {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: auto;
}

.tag {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 5px 10px;
  border: 1px solid rgba(0, 0, 0, 0.18);
  line-height: 1;
}

/* Cursor dot expands on card hover — handled in JS */
.expertise-card {
  cursor: none; /* uses the custom cursor dot on desktop */
}
/* Subtle lift after card has been revealed */
.expertise-card.is-revealed {
  transition: transform var(--duration-fast) var(--ease-out-expo);
}
.expertise-card.is-revealed:hover {
  transform: translateY(-4px);
}
@media (hover: none) {
  .expertise-card { cursor: auto; }
  .expertise-card.is-revealed:hover { transform: none; }
}


/* =============================================
   EXPERTISE — RESPONSIVE
============================================= */
@media (max-width: 768px) {
  .expertise-grid {
    grid-template-columns: 1fr; /* single column */
  }
  .card-body {
    padding: 22px 24px 28px;
  }
}


/* =============================================
   EDUCATION SECTION
============================================= */
#education {
  background: var(--color-bg);
  border-top: 1px solid rgba(0, 0, 0, 0.08);
}

.edu-list {
  margin-top: 8px;
}

/* Each entry: body left, year right */
.edu-entry {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 48px;
  align-items: start;
  padding: 40px 0;
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
.edu-entry:first-child {
  border-top: 1px solid rgba(0, 0, 0, 0.08);
}

.edu-year {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.55);
  text-align: right;
  padding-top: 5px; /* optically aligns with degree title cap-height */
  white-space: nowrap;
}

.edu-degree {
  font-size: clamp(18px, 2vw, 22px);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin-bottom: 8px;
}

.edu-institution {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.60);
  margin-bottom: 18px;
}

.edu-description {
  font-size: clamp(15px, 1.35vw, 17px);
  line-height: 1.75;
  color: rgba(0, 0, 0, 0.85);
  max-width: 640px;
}

@media (max-width: 768px) {
  .edu-entry {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 32px 0;
  }
  .edu-year {
    text-align: left;
    order: -1; /* year appears above degree on mobile */
    margin-bottom: 10px;
  }
}


/* =============================================
   BEHIND THIS SITE SECTION
   Narrower max-width signals a different register.
============================================= */
#behind {
  background: var(--color-bg);
  border-top: 1px solid rgba(0, 0, 0, 0.08);
}

/* Behind This Site uses the same max-width as all other sections */

/* Two-column: text left, photo right */
.behind-layout {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 80px;
  align-items: start;
}

/* Body paragraphs */
.behind-body p {
  font-size: clamp(15px, 1.4vw, 17px);
  line-height: 1.8;
  color: rgba(0, 0, 0, 0.85);
  margin-bottom: 20px;
  max-width: 580px;
}
.behind-body p:last-of-type {
  margin-bottom: 32px;
}

/* LinkedIn link — same style as role-source */
.behind-linkedin {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-fg);
  text-decoration: none;
  border-bottom: 1px solid var(--color-fg);
  padding-bottom: 2px;
  transition:
    opacity var(--duration-fast) var(--ease-out-expo);
}
.behind-linkedin:hover {
  opacity: 0.45;
}

/* Photo — circular crop, always in colour */
.behind-photo {
  position: sticky;
  top: 100px; /* sits below the fixed nav */
  margin: 0;
}
.behind-photo img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: center 15%; /* frame face + dog */
  display: block;
  border-radius: 50%;
}

@media (max-width: 900px) {
  .behind-layout {
    grid-template-columns: 1fr;
    gap: 48px;
  }
  .behind-photo {
    position: static;
    max-width: 260px;
    margin: 0 auto; /* center on mobile */
  }
  .behind-body p {
    max-width: 100%;
  }
}


/* =============================================
   CONTACT SECTION
============================================= */
#contact {
  background: var(--color-bg);
  border-top: 1px solid rgba(0, 0, 0, 0.08);
}

/* Side-by-side intro + CTA on desktop */
.contact-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 80px;
  align-items: start;
}

.contact-intro p {
  font-size: clamp(16px, 1.5vw, 19px);
  line-height: 1.75;
  color: rgba(0, 0, 0, 0.85);
}

/* --- Form --- */
.contact-form {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* Two fields side-by-side (name + position) */
.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.form-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.50);
}
.form-label span {
  color: var(--color-fg);
}

.form-field input,
.form-field textarea {
  width: 100%;
  border: 1px solid rgba(0, 0, 0, 0.18);
  padding: 13px 16px;
  font-family: var(--font-primary);
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-fg);
  background: transparent;
  outline: none;
  border-radius: 0;
  transition: border-color var(--duration-fast) var(--ease-out-expo);
  resize: vertical;
}
.form-field input::placeholder,
.form-field textarea::placeholder {
  color: rgba(0, 0, 0, 0.25);
}
.form-field input:focus,
.form-field textarea:focus {
  border-color: var(--color-fg);
}

/* Per-field inline error */
.field-error-msg {
  font-size: 12px;
  color: var(--color-fg);
  opacity: 0.55;
  line-height: 1.5;
  margin-top: -2px;
}
.form-field input.field-invalid,
.form-field textarea.field-invalid {
  border-color: var(--color-fg);
  outline: none;
}

/* Error message */
.form-error {
  font-size: 13px;
  color: rgba(0, 0, 0, 0.65);
  line-height: 1.6;
}
.form-error a {
  color: var(--color-fg);
  text-decoration: underline;
}

/* Submit button */
.contact-submit {
  align-self: flex-start;
  background: var(--color-fg);
  color: var(--color-bg);
  border: none;
  padding: 15px 40px;
  font-family: var(--font-primary);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: none;
  transition: opacity var(--duration-fast) var(--ease-out-expo);
}
.contact-submit:hover {
  opacity: 0.65;
}
.contact-submit:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

/* Success message */
.form-success {
  font-size: clamp(15px, 1.4vw, 17px);
  line-height: 1.7;
  color: rgba(0, 0, 0, 0.65);
  padding: 24px 0;
}

@media (max-width: 900px) {
  .contact-layout {
    grid-template-columns: 1fr;
    gap: 48px;
  }
}
@media (max-width: 600px) {
  .form-row {
    grid-template-columns: 1fr;
  }
}


/* =============================================
   FOOTER
============================================= */
#site-footer {
  border-top: 1px solid var(--color-fg);
  background: var(--color-bg);
}

.footer-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 24px var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.footer-name {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.footer-nav {
  display: flex;
  gap: 28px;
  align-items: center;
  flex-wrap: wrap;
}

.footer-nav-link {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.60);
  text-decoration: none;
  transition: color var(--duration-fast) var(--ease-out-expo);
}
.footer-nav-link:hover {
  color: var(--color-fg);
}

.footer-right {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: rgba(0, 0, 0, 0.60);
  text-align: right;
  white-space: nowrap;
}

@media (max-width: 768px) {
  .footer-inner {
    flex-direction: column;
    align-items: flex-start;
    gap: 20px;
  }
  .footer-right {
    text-align: left;
  }
  .footer-nav {
    gap: 20px;
  }
}