/* ============================================================
   Brand tokens: change a color here and it updates everywhere.
   The palette is logo blue, white, black and grey only.
   ============================================================ */
:root {
  --blue: #4b68f0; /* measured from the blob logo */
  --black: #000000;
  --ink: #222222;
  --grey: #666666;
  --grey-soft: #b5b5b5;
  --paper: #ffffff;
  --tint: #f2f2f2;
  --line: rgba(0, 0, 0, 0.12);
  --present: #e5002b; /* only used for the current role dot */
  /* Proxima Nova was the old site's Typekit font; Figtree is the free stand in */
  --font: "proxima-nova", "Figtree", "Helvetica Neue", Helvetica, Arial, sans-serif;
  /* Subtle "tech" shadow used on every big heading */
  --heading-shadow: 0 0 30px rgba(75, 104, 240, 0.4);
  --heading-shadow-dark: 1px 1px 0 rgba(75, 104, 240, 0.9), 3px 3px 0 rgba(75, 104, 240, 0.45), 0 0 30px rgba(75, 104, 240, 0.6);
  --radius: 22px;
  --gutter: clamp(16px, 5vw, 72px);
  --ease: cubic-bezier(.2, .8, .2, 1);
  color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 84px; }
body {
  margin: 0;
  font-family: var(--font);
  font-size: 18px;
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: var(--blue); }
h1, h2, h3 { line-height: 1.1; margin: 0; color: var(--black); text-wrap: balance; }
::selection { background: var(--blue); color: #fff; }
:focus-visible { outline: 3px solid var(--blue); outline-offset: 3px; }

/* Big headings */
.display {
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  color: var(--blue);
  text-shadow: var(--heading-shadow);
}
.display--light { color: #fff; text-shadow: var(--heading-shadow-dark); }
h2.display { font-size: clamp(40px, 7vw, 88px); }

/* Scroll progress */
.progress { position: fixed; inset: 0 0 auto 0; height: 4px; z-index: 60; }
.progress span { display: block; height: 100%; width: 100%; background: var(--blue); transform-origin: left; transform: scaleX(0); }

/* Nav */
.nav {
  position: sticky; top: env(safe-area-inset-top, 0px); z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px var(--gutter);
  background: rgba(255, 255, 255, 0.86);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border-bottom: 1px solid transparent;
  transition: border-color .3s, padding .3s;
}
.nav.is-scrolled { border-color: var(--line); padding-block: 4px; }
/* The logo box is the same size on every page so switching pages only changes colors */
.nav__logo { display: block; height: 41.6px; padding: 0 1px; border-radius: 999px; }
.nav__logo img { height: 100%; width: auto; transition: transform .4s var(--ease); }
.nav__logo:hover img { transform: scale(1.04); }
.nav__links { display: flex; gap: 6px; align-items: center; }
.nav__links a {
  padding: 8px 14px; border-radius: 999px;
  color: var(--black); text-decoration: none; font-weight: 600; font-size: 16px;
  transition: color .2s, background .2s;
}
.nav__links a:hover, .nav__links a.is-active, .nav__links a[aria-current="page"] { color: var(--blue); background: var(--tint); }
.nav__links .nav__cta { background: var(--blue); color: #fff; margin-left: 8px; }
.nav__links .nav__cta:hover { background: var(--black); color: #fff; }
.nav__toggle { display: none; width: 44px; height: 44px; border: 0; background: var(--tint); border-radius: 50%; cursor: pointer; position: relative; }
.nav__toggle span { position: absolute; left: 12px; right: 12px; height: 2px; background: var(--black); transition: transform .3s var(--ease); }
.nav__toggle span:first-child { top: 18px; } .nav__toggle span:last-child { top: 25px; }
.nav__toggle[aria-expanded="true"] span:first-child { transform: translateY(3.5px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] span:last-child { transform: translateY(-3.5px) rotate(-45deg); }
.mobile-menu {
  position: fixed; inset: 64px 0 auto 0; z-index: 49; background: #fff;
  display: grid; padding: 12px var(--gutter) 24px; border-bottom: 1px solid var(--line);
}
.mobile-menu[hidden] { display: none; }
.mobile-menu a { padding: 14px 0; font-size: 24px; font-weight: 700; color: var(--black); text-decoration: none; border-bottom: 1px solid var(--line); }

/* Buttons */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 14px 26px; border-radius: 999px; font: 700 17px/1 var(--font);
  text-decoration: none; cursor: pointer; border: 2px solid var(--blue);
  transition: transform .25s var(--ease), box-shadow .25s, background .25s, color .25s;
}
.btn:hover { transform: translateY(-3px); box-shadow: 0 10px 24px rgba(75, 104, 240, .3); }
.btn--primary { background: var(--blue); color: #fff; }
.btn--ghost { background: transparent; color: var(--blue); }
.btn--light { background: #fff; color: var(--black); border-color: #fff; }

/* Hero */
.hero {
  position: relative;
  display: grid; grid-template-columns: 1.25fr 1fr; align-items: center; gap: 24px;
  padding: 56px var(--gutter) 88px; overflow: hidden;
}
.hero::before {
  content: ""; position: absolute; inset: auto -20% -40% 30%; height: 80%;
  background: radial-gradient(closest-side, rgba(75, 104, 240, .14), transparent);
  pointer-events: none;
}
.eyebrow { font-weight: 700; color: var(--grey); text-transform: uppercase; letter-spacing: .14em; font-size: 14px; margin: 0 0 18px; }
.hero__title { font-size: clamp(40px, 6.4vw, 104px); line-height: .95; }
.hero__title .line { display: block; }
.hero__title .small { font-size: .5em; margin-top: .35em; color: var(--black); }
/* Stops a line re-wrapping while it scrambles, where the screen is wide enough to hold it */
@media (min-width: 480px) { .hero__title .line { white-space: nowrap; } }
.hero__lede { max-width: 38ch; font-size: clamp(18px, 1.6vw, 22px); color: var(--grey); margin: 28px 0 32px; }
.hero__lede strong { color: var(--black); }
.hero__actions { display: flex; gap: 12px; flex-wrap: wrap; }

/* Mascot: the logo artwork, unchanged. It floats, squishes when poked and can be dragged. */
.hero__mascot { position: relative; display: grid; place-items: center; }
.mascot {
  width: min(100%, 480px); aspect-ratio: 1;
  cursor: grab; touch-action: pan-y; user-select: none; /* pan-y lets a finger on the logo still scroll the page */
  animation: bob 6s ease-in-out infinite;
  filter: drop-shadow(0 30px 40px rgba(75, 104, 240, .28));
}
.mascot img { width: 100%; height: 100%; object-fit: contain; pointer-events: none; }
.mascot.is-squish { animation: squish .55s var(--ease); }
.mascot__hint { position: absolute; bottom: 4%; right: 6%; margin: 0; font-weight: 700; font-style: italic; color: var(--grey); font-size: 15px; }
@keyframes bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-16px); } }
@keyframes squish { 0% { transform: scale(1); } 30% { transform: scale(1.12, .9); } 60% { transform: scale(.94, 1.06); } 100% { transform: scale(1); } }

/* Moving banner */
.marquee { background: var(--blue); color: #fff; overflow: hidden; padding: 18px 0; }
.marquee__track { display: flex; gap: 28px; width: max-content; animation: marquee 38s linear infinite; font-weight: 800; font-size: clamp(20px, 2.6vw, 30px); text-transform: uppercase; white-space: nowrap; letter-spacing: .02em; }
.marquee b { color: #fff; opacity: .6; }
.marquee:hover .marquee__track { animation-play-state: paused; }
@keyframes marquee { to { transform: translateX(-50%); } }

/* Stats */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; padding: 88px var(--gutter) 40px; }
.stat { border-top: 3px solid var(--blue); padding-top: 16px; }
.stat strong { display: block; font-size: clamp(36px, 4.4vw, 60px); font-weight: 900; color: var(--blue); line-height: 1; font-variant-numeric: tabular-nums; text-shadow: var(--heading-shadow); }
.stat span { display: block; margin-top: 8px; color: var(--grey); font-size: 15px; line-height: 1.4; }

/* Sections */
.section { padding: 96px var(--gutter); }
.section--dark { background: var(--black); color: #d9d9d9; }
.section__head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 16px 48px; margin-bottom: 48px; }
.section__intro { max-width: 46ch; margin: 0; color: var(--grey); font-size: 19px; }
.section--dark .section__intro { color: var(--grey-soft); }
.section__intro + .btn { margin-top: 18px; }

/* Page header (Recreation) */
.page-head { padding: 72px var(--gutter) 40px; }
.page-head h1 { font-size: clamp(48px, 9vw, 120px); }
.page-head p { max-width: 52ch; color: var(--grey); font-size: 20px; margin: 20px 0 0; }

/* Project cards */
.projects { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.card {
  --rx: 0deg; --ry: 0deg;
  display: flex; flex-direction: column; background: #fff;
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
  transform: perspective(900px) rotateX(var(--rx)) rotateY(var(--ry));
  transition: transform .3s var(--ease), box-shadow .3s, border-color .3s;
}
.card:hover { box-shadow: 0 24px 48px rgba(0, 0, 0, .14); border-color: rgba(75, 104, 240, .45); }
.card__media { aspect-ratio: 16 / 9; overflow: hidden; background: var(--tint); }
.card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease); }
.card:hover .card__media img { transform: scale(1.06); }
.card__body { padding: 24px 26px 28px; }
.card h3 { font-size: 24px; margin: 0 0 12px; }
.card ul { margin: 0; padding-left: 18px; color: #444; font-size: 16px; }
.card li { margin-bottom: 6px; }
.card li::marker { color: var(--blue); }

/* Featured campaigns */
.subhead { font-size: 28px; margin: 72px 0 24px; }
.campaigns { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
.campaign {
  position: relative; display: block; padding: 36px; border-radius: var(--radius);
  background: var(--blue); color: #fff; text-decoration: none; overflow: hidden;
  transition: transform .35s var(--ease);
}
.campaign:nth-child(2) { background: var(--black); }
.campaign::after { content: ""; position: absolute; right: -60px; bottom: -60px; width: 220px; height: 220px; background: url("assets/blob.png") center / contain no-repeat; opacity: .22; transition: transform .6s var(--ease); }
.campaign:hover { transform: translateY(-6px); }
.campaign:hover::after { transform: rotate(40deg) scale(1.15); }
.campaign__label { font-weight: 800; font-size: 13px; letter-spacing: .1em; text-transform: uppercase; opacity: .8; }
.campaign h3 { color: #fff; font-size: clamp(30px, 3.4vw, 44px); font-weight: 900; margin: 10px 0 12px; }
.campaign p { margin: 0 0 24px; max-width: 44ch; color: rgba(255,255,255,.9); }
.campaign__link { font-weight: 700; border-bottom: 2px solid currentColor; }

/* Timeline */
.timeline { list-style: none; margin: 0; padding: 0 0 0 28px; position: relative; max-width: 880px; }
.timeline::before { content: ""; position: absolute; left: 6px; top: 24px; bottom: 24px; width: 2px; background: linear-gradient(var(--blue), rgba(75, 104, 240, .2)); }
.timeline li { position: relative; padding: 0 0 16px 12px; }
.timeline li::before { content: ""; position: absolute; left: -28px; top: 22px; width: 16px; height: 16px; border-radius: 50%; background: var(--blue); box-shadow: 0 0 0 6px rgba(75, 104, 240, .3); }
.timeline li.is-current::before { background: var(--present); box-shadow: 0 0 0 6px rgba(229, 0, 43, .3); animation: present 2.4s ease-in-out infinite; }
@keyframes present { 50% { box-shadow: 0 0 0 11px rgba(229, 0, 43, 0); } }
/* Same glow and scan line as the Recreation cards. The scan also runs once as a role scrolls in, for touch screens. */
.timeline__card { position: relative; overflow: hidden; padding: 16px 20px; border: 1px solid transparent; border-radius: 16px; transition: border-color .3s, box-shadow .3s; }
.timeline__card:hover { border-color: var(--blue); box-shadow: 0 0 26px rgba(75, 104, 240, .45); }
.timeline__card::before { content: ""; position: absolute; inset: 0; pointer-events: none; opacity: 0; transition: opacity .3s; background: radial-gradient(260px circle at var(--mx, 50%) var(--my, 50%), rgba(75, 104, 240, .28), transparent 70%); }
.timeline__card:hover::before { opacity: 1; }
.timeline__card::after { content: ""; position: absolute; left: 0; right: 0; top: -40%; height: 40%; pointer-events: none; opacity: 0; background: linear-gradient(transparent, rgba(255, 255, 255, .14)); }
.timeline li.is-in .timeline__card::after { animation: scan-once 1.2s calc(var(--d, 0s) + .3s) linear; }
.timeline .timeline__card:hover::after { opacity: 1; animation: scan .9s linear; }
.timeline__card > * { position: relative; }
@keyframes scan { to { top: 100%; } }
@keyframes scan-once { from { opacity: 1; top: -40%; } to { opacity: 1; top: 100%; } }
.timeline__when { font-size: 14px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--grey-soft); }
.timeline h3 { color: #fff; font-size: clamp(22px, 2.4vw, 30px); margin: 6px 0 8px; }
.timeline p { margin: 0; max-width: 62ch; }

/* Channel previews (Recreation) */
.channel-group + .channel-group { margin-top: 56px; }
.group-title { font-size: 15px; letter-spacing: .14em; text-transform: uppercase; color: var(--grey); margin-bottom: 18px; }
.channels { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }
.channel-card {
  display: flex; flex-direction: column; min-width: 0; border-radius: var(--radius); border: 1px solid var(--line); background: #fff; overflow: hidden;
  transition: transform .3s var(--ease), box-shadow .3s, border-color .3s;
}
.channel-card:hover { transform: translateY(-5px); box-shadow: 0 20px 40px rgba(0, 0, 0, .12); border-color: rgba(75, 104, 240, .45); }
.channel-card__head { display: flex; align-items: center; gap: 14px; padding: 18px; text-decoration: none; color: var(--ink); }
.channel-card__head img { width: 60px; height: 60px; border-radius: 50%; object-fit: cover; flex: none; }
.channel-card h3 { font-size: 20px; }
.channel-card__handle { display: block; font-weight: 700; font-size: 14px; color: var(--blue); }
.channel-card__bio { margin: 0; padding: 0 18px 16px; color: var(--grey); font-size: 15px; line-height: 1.4; }
.thumbs { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; margin-top: auto; }
.thumbs a { display: block; aspect-ratio: 16 / 9; overflow: hidden; background: var(--tint); }
.thumbs img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s var(--ease); }
.thumbs a:hover img { transform: scale(1.08); }
/* Instagram has no dark embed. At 980px wide its photo grid runs from 158px to 811px, so the
   frame stays that size, main.js scales it to fit the card, and the white header is cropped off. */
.ig-window { position: relative; overflow: hidden; aspect-ratio: 980 / 653; margin-top: auto; background: #1c1c1c; }
.ig-embed { position: absolute; left: 0; top: 0; width: 980px; height: 811px; border: 0; transform-origin: 0 0; transform: translateY(calc(var(--ig-scale, .4) * -158px)) scale(var(--ig-scale, .4)); transition: opacity .5s; }
/* Stays hidden over the dark box until loaded, so it never flashes white */
.js .ig-embed:not(.is-loaded) { opacity: 0; }

/* Self hosting (Recreation) */
.code-intro { display: grid; grid-template-columns: 1.6fr auto; gap: 24px 48px; align-items: center; margin-bottom: 40px; }
.code-intro p { margin: 0; max-width: 62ch; color: #d9d9d9; font-size: 19px; }
.stack { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.stack__item { display: grid; grid-template-columns: auto 1fr; gap: 2px 16px; align-items: center; padding: 20px; border-radius: 18px; background: #161616; border: 1px solid #2c2c2c; transition: transform .3s var(--ease), border-color .3s; }
.stack__item:hover { transform: translateY(-4px); border-color: var(--blue); }
.stack__item img { grid-row: span 2; width: 60px; height: 60px; padding: 8px; object-fit: contain; border-radius: 14px; background: #fff; }
.stack__item h3 { color: #fff; font-size: 20px; }
.stack__item p { margin: 0; color: var(--grey-soft); font-size: 15px; line-height: 1.4; }

/* About */
.about { display: grid; grid-template-columns: minmax(220px, 300px) 1.6fr minmax(160px, 240px); gap: 48px; align-items: center; }
.about__big { font-size: clamp(26px, 3vw, 38px); font-weight: 700; color: var(--black); line-height: 1.25; margin-top: 0; }
.about__text p:not(.about__big) { color: #444; max-width: 60ch; }
.about__logo { width: 100%; height: auto; justify-self: center; }
.headshot { margin: 0; aspect-ratio: 4 / 5; border-radius: var(--radius); overflow: hidden; background: var(--tint); }
.headshot img { width: 100%; height: 100%; object-fit: cover; }

.gallery {
  display: flex; gap: 20px; overflow-x: auto; scroll-snap-type: x mandatory;
  margin: 56px calc(var(--gutter) * -1) 0; padding: 8px var(--gutter) 24px;
  scrollbar-width: thin; scrollbar-color: var(--blue) transparent;
}
.gallery.is-dragging { cursor: grabbing; scroll-snap-type: none; }
.gallery figure { flex: 0 0 auto; margin: 0; scroll-snap-align: start; }
.gallery img { height: clamp(260px, 38vw, 420px); width: auto; border-radius: var(--radius); pointer-events: none; transition: transform .5s var(--ease); }
.gallery figure:hover img { transform: translateY(-6px); }
.gallery figcaption { margin-top: 10px; font-size: 15px; color: var(--grey); font-weight: 600; }
.is-zoomable { cursor: zoom-in; }

/* Full screen photo viewer */
.photo-view { position: fixed; inset: 0; width: 100vw; height: 100dvh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: #000; color: #fff; overflow: hidden; }
.photo-view[open] { display: flex; flex-direction: column; animation: view-in .25s ease-out; }
@keyframes view-in { from { opacity: 0; } }
.photo-view__stage { flex: 1; min-height: 0; overflow: hidden; display: grid; place-items: center; padding: 16px; }
.photo-view__stage img { max-width: 100%; max-height: 100%; object-fit: contain; cursor: zoom-in; transition: transform .25s var(--ease); }
.photo-view__stage img.is-zoomed { transform: scale(2.4); cursor: zoom-out; touch-action: none; }
html:has(.photo-view[open]) { overflow: hidden; }
.photo-view__caption { margin: 0; padding: 14px 72px 20px; text-align: center; font-size: 17px; font-weight: 600; }
.photo-view button { position: absolute; width: 48px; height: 48px; border-radius: 50%; border: 1px solid rgba(255,255,255,.4); background: rgba(0,0,0,.6); color: #fff; font-size: 26px; line-height: 1; cursor: pointer; transition: background .2s; }
.photo-view button:hover { background: var(--blue); }
.photo-view__close { top: 16px; right: 16px; }
.photo-view__prev { left: 16px; top: 50%; translate: 0 -50%; }
.photo-view__next { right: 16px; top: 50%; translate: 0 -50%; }

/* Footer, including Connect with me */
.footer { position: relative; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 14px 32px; padding: 38px var(--gutter); background: var(--black); color: var(--grey-soft); font-size: 16px; }
.footer__connect { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 26px; }
.footer__connect img { width: 58px; height: 58px; object-fit: contain; }
.footer h2 { color: #fff; font-size: 25px; font-weight: 800; text-shadow: var(--heading-shadow-dark); }
.footer a { color: #fff; font-weight: 600; text-decoration: none; border-bottom: 1px solid rgba(255,255,255,.35); }
.footer a:hover { border-color: #fff; }
.footer p { margin: 0; }
.email { display: inline-flex; align-items: center; gap: 8px; }
.copy { font: 700 12px var(--font); text-transform: uppercase; letter-spacing: .08em; padding: 4px 10px; border-radius: 999px; border: 1px solid rgba(255,255,255,.5); background: transparent; color: #fff; cursor: pointer; }
.copy:hover { background: #fff; color: var(--black); }
.footer :focus-visible { outline-color: #fff; }

/* ============================================================
   Recreation: the portfolio's colors inverted, plus techier motion
   ============================================================ */
.page-dark { --line: rgba(255, 255, 255, 0.18); --tint: #1c1c1c; color: #d9d9d9; background: var(--black); color-scheme: dark; }
.page-dark h1, .page-dark h2, .page-dark h3 { color: #fff; }
.page-dark .display { color: #fff; text-shadow: var(--heading-shadow-dark); }
.page-dark a { color: #fff; }
.page-dark a.btn--light { color: var(--black); }
.page-dark :focus-visible { outline-color: #fff; }
#net { position: fixed; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }
.page-dark .nav { background: rgba(0, 0, 0, 0.78); }
/* Both logo versions have black lettering, so the logo sits on white here */
.page-dark .nav__logo { background: #fff; }
.page-dark .nav__links a { color: #fff; }
.page-dark .nav__links a:hover, .page-dark .nav__links a[aria-current="page"] { color: #fff; background: rgba(75, 104, 240, .4); }
.page-dark .nav__links .nav__cta:hover { background: #fff; color: var(--black); }
.page-dark .nav__toggle { background: #1c1c1c; }
.page-dark .nav__toggle span { background: #fff; }
.page-dark .mobile-menu { background: #000; }
.page-dark .mobile-menu a { color: #fff; }
.page-dark .eyebrow { color: var(--grey-soft); font-family: "JetBrains Mono", Consolas, monospace; text-transform: none; letter-spacing: 0; font-size: 16px; }
.page-dark .eyebrow::before { content: "> "; color: var(--blue); }
.page-dark .eyebrow::after { content: ""; display: inline-block; width: .55em; height: 1em; margin-left: .15em; vertical-align: -.12em; background: var(--blue); animation: caret 1s steps(2) infinite; }
@keyframes caret { 50% { opacity: 0; } }
.page-dark .page-head p:not(.eyebrow) { color: var(--grey-soft); }
.page-dark .section--dark { background: transparent; }
.page-dark .group-title { color: var(--grey-soft); font-family: "JetBrains Mono", Consolas, monospace; letter-spacing: .06em; text-transform: none; }
.page-dark .group-title::before { content: "// "; color: var(--blue); }
.page-dark .footer { border-top: 1px solid var(--line); }
.channels-blurb { max-width: 62ch; margin: 0 0 40px; font-size: 20px; color: #d9d9d9; }

.page-head--lab { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 24px 48px; }

/* Same logo treatment as Lily's Lab: floating, poke to squish, ring spinning around it */
.lab-mascot { position: relative; width: clamp(150px, 20vw, 250px); aspect-ratio: 1; display: grid; place-items: center; }
.lab-mascot::before, .lab-mascot::after { content: ""; position: absolute; inset: -4%; border-radius: 50%; pointer-events: none; }
.lab-mascot::before { border: 2px dashed rgba(75, 104, 240, .85); animation: spin 18s linear infinite; }
.lab-mascot::after { inset: 4%; border: 1px solid rgba(255, 255, 255, .55); animation: ring 3s ease-out infinite; }
.lab-mascot .mascot { width: 84%; filter: drop-shadow(0 0 26px rgba(75, 104, 240, .55)); animation: lab-bob 5s ease-in-out infinite; }
.lab-mascot .mascot.is-squish { animation: squish .55s var(--ease); }
.lab-mascot .mascot__hint { left: 0; right: 0; bottom: -10px; text-align: center; font: 500 12px "JetBrains Mono", Consolas, monospace; color: var(--grey-soft); }
@keyframes lab-bob { 50% { transform: translateY(-10px) rotate(4deg); } }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes ring { from { transform: scale(.9); opacity: 1; } to { transform: scale(1.2); opacity: 0; } }

/* Cards: a glow follows the pointer and a scan line sweeps over on hover */
.page-dark .channel-card, .page-dark .stack__item { position: relative; overflow: hidden; background: #0d0d0d; border-color: rgba(255, 255, 255, .16); }
.page-dark .channel-card:hover, .page-dark .stack__item:hover { border-color: var(--blue); box-shadow: 0 0 26px rgba(75, 104, 240, .45); }
.page-dark .channel-card__head { color: #fff; }
.page-dark .channel-card__handle { color: #9db0ff; }
.page-dark .channel-card__bio { color: var(--grey-soft); }
.page-dark .channel-card::before, .page-dark .stack__item::before { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; opacity: 0; transition: opacity .3s; background: radial-gradient(260px circle at var(--mx, 50%) var(--my, 50%), rgba(75, 104, 240, .28), transparent 70%); }
.page-dark .channel-card:hover::before, .page-dark .stack__item:hover::before { opacity: 1; }
.page-dark .channel-card::after, .page-dark .stack__item::after { content: ""; position: absolute; left: 0; right: 0; top: -40%; height: 40%; z-index: 1; pointer-events: none; opacity: 0; background: linear-gradient(transparent, rgba(255, 255, 255, .14)); }
.page-dark .channel-card:hover::after, .page-dark .stack__item:hover::after { opacity: 1; animation: scan .9s linear; }
.page-dark .stack__item img { transition: transform .4s cubic-bezier(.3, 1.6, .5, 1); }
.page-dark .stack__item:hover img { transform: scale(1.1) rotate(-4deg); }

/* Reveal on scroll: only elements below the fold start hidden */
.js .reveal.is-below:not(.is-in) { opacity: 0; transform: translateY(28px); }
.reveal { transition: opacity .8s var(--ease), transform .8s var(--ease); transition-delay: var(--d, 0s); }
.reveal.is-in { opacity: 1; transform: none; }

/* Responsive */
@media (max-width: 1100px) {
  .projects, .stack { grid-template-columns: 1fr 1fr; }
  .stats { grid-template-columns: 1fr 1fr; }
  .about { grid-template-columns: minmax(200px, 280px) 1fr; }
  .about__logo { display: none; }
}
@media (max-width: 860px) {
  body { font-size: 17px; }
  .nav__links { display: none; }
  .nav__toggle { display: block; }
  .hero { grid-template-columns: 1fr; padding-top: 24px; }
  .hero__mascot { order: -1; }
  .mascot { width: min(64vw, 300px); }
  .mascot__hint { display: none; }
  .stats { grid-template-columns: 1fr 1fr; }
  .projects, .campaigns, .about, .stack, .code-intro { grid-template-columns: 1fr; }
  .page-head--lab { grid-template-columns: 1fr; }
  .page-head--lab .lab-mascot { order: -1; justify-self: center; }
  .section { padding-block: 72px; }
  .headshot { max-width: 280px; }
  .footer { flex-direction: column; align-items: flex-start; }
  .photo-view__prev, .photo-view__next { top: auto; bottom: 10px; translate: none; }
}
@media (max-width: 520px) {
  .stats { grid-template-columns: 1fr; }
  .channels { grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  html { scroll-behavior: auto; }
  .js .reveal.is-below:not(.is-in) { opacity: 1; transform: none; }
}
