/* ============================================
   TOKENS
   ============================================ */
:root{
  --cream: #121214;
  --ink: #FFFFFF;
  --coral: #FF4433;
  --coral-text: #FF7566;
  --lime: #CFFF5C;
  --violet: #9D8FFF;
  --muted: #9AA4BD;

  /* deep counterpart of coral — used for the mobile nav
     drawer's panel so it reads as a dark surface rather
     than a bright poster color, matching the rest of the
     site's near-black canvas. */
  --coral-deep: #5C2318;

  --font-display: "Fraunces", serif;
  --font-shout: "Archivo Black", sans-serif;
  --font-body: "Space Grotesk", sans-serif;
  --font-mono: "Space Mono", monospace;

  /* smooth, no-overshoot easing for hover/entrance motion —
     replaces an earlier springy overshoot curve that read as
     more playful than intended. */
  --ease: cubic-bezier(.16,1,.3,1);

  --edge: 6px;
  --max: 1240px;
  --nav-h: 84px; /* fallback; script.js measures the real height on load/resize */
}

*{ box-sizing:border-box; }
html{ scroll-behavior:smooth; }

/* ============================================
   VIEW TRANSITIONS — clicking a Work row "zooms"
   into its project page. Progressive enhancement:
   browsers without cross-document view-transition
   support (Safari/Firefox as of writing) just do a
   normal navigation, no fallback code needed.
   ============================================ */
@view-transition{
  navigation:auto;
}
::view-transition-group(*){
  animation-duration:.5s;
  animation-timing-function:var(--ease);
}
@media (prefers-reduced-motion:reduce){
  ::view-transition-group(*){ animation-duration:.001s; }
}

body{
  margin:0;
  background:var(--cream);
  color:var(--ink);
  font-family:var(--font-body);
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
}

img{ max-width:100%; display:block; }
a{ color:inherit; text-decoration:none; }
ul,ol{ list-style:none; margin:0; padding:0; }
h1,h2,h3,p{ margin:0; }

::selection{ background:var(--ink); color:var(--cream); }

/* grain texture overlay */
.grain{
  position:fixed; inset:0; z-index:999; pointer-events:none;
  opacity:0.05; mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ============================================
   NAV
   ============================================ */
.nav{
  position:sticky; top:0; z-index:100;
  display:flex; align-items:center; justify-content:space-between;
  padding:20px clamp(20px,4vw,56px);
  background:var(--cream);
  border-bottom:3px solid var(--ink);
}
.nav__left{ display:flex; align-items:center; gap:clamp(20px,4vw,48px); }
.nav__mark{
  font-family:var(--font-shout); font-size:1.2rem;
  display:flex; align-items:center; gap:10px;
}
.nav__mark .dot{ color:var(--coral-text); }
.nav__links{ display:flex; gap:clamp(6px,1vw,10px); }
.nav__links a{
  font-family:var(--font-mono); font-size:0.75rem; text-transform:uppercase;
  letter-spacing:0.03em; display:flex; align-items:center; gap:6px;
  padding:7px 14px; border-radius:100px;
  transition:color .15s, background .15s;
}
.nav__links a:hover{ background:var(--ink); color:var(--cream); }
.nav__cta{
  font-family:var(--font-mono); font-size:0.8rem; font-weight:700;
  padding:9px 16px; border:2px solid var(--ink); border-radius:100px;
  transition:transform .15s, background .15s, color .15s;
}
.nav__cta:hover{ background:var(--ink); color:var(--cream); }

@media (max-width:760px){
  .nav__left{ gap:16px; }
  .nav__links{ display:none; }
}
@media (max-width:480px){
  .nav__cta{ padding:8px 12px; font-size:0.7rem; }
  .nav__left{ gap:12px; }
}

/* ============================================
   MOBILE DRAWER
   ============================================ */
.mobile-drawer__overlay{
  position:fixed; inset:0; z-index:290;
  background:rgba(0,0,0,0.5);
  opacity:0; pointer-events:none;
  transition:opacity .25s ease;
}
.mobile-drawer__overlay.is-open{ opacity:1; pointer-events:auto; }

.mobile-drawer{
  position:fixed; top:0; left:0; bottom:0; z-index:300;
  width:min(78vw, 340px);
  background:var(--coral-deep);
  border-right:5px solid var(--ink);
  padding:28px 28px;
  display:flex; flex-direction:column; gap:40px;
  transform:translateX(-100%);
  transition:transform .3s cubic-bezier(.65,0,.35,1);
}
.mobile-drawer.is-open{ transform:translateX(0); }

.mobile-drawer__close{
  align-self:flex-end;
  font-family:var(--font-mono); font-size:1rem; font-weight:700;
  background:none; border:2px solid var(--ink); color:var(--ink);
  width:36px; height:36px; border-radius:50%; cursor:pointer;
}

.mobile-drawer__links{ display:flex; flex-direction:column; gap:26px; margin-top:20px; }
.mobile-drawer__links a{
  font-family:var(--font-shout);
  text-transform:uppercase;
  font-size:1.5rem; color:var(--ink);
  display:flex; align-items:baseline; gap:12px;
}
.mobile-drawer__cta{
  margin-top:auto;
  font-family:var(--font-mono); font-weight:700; font-size:0.85rem;
  padding:12px 22px; background:var(--ink); color:var(--cream);
  border-radius:100px; text-align:center;
}

@media (min-width:761px){
  .mobile-drawer, .mobile-drawer__overlay{ display:none; }
}

/* ============================================
   HERO
   full-bleed (max-width:none overrides the generic
   section rule) so the big type below actually spans
   the window instead of sitting in a centered 1240px
   column. Wrapped by .hero-flip below for the scroll
   transition into Background.
   ============================================ */
.hero{
  position:relative;
  max-width:none;
  padding:clamp(20px,4vw,56px);
  overflow:hidden;
  min-height:100vh;
  min-height:100svh;
  display:flex;
  flex-direction:column;
  justify-content:center;
  align-items:center;
  background:var(--cream);
}

.hero__intro{
  position:relative; z-index:2;
  text-align:center;
}

/* faint oversized wordmark sitting behind the hero
   content — the layered-scale depth cue from the Wix
   template's parallax cards / Love & Money's giant
   logo, done as a static outline instead of a second
   scroll rig. */
.hero__watermark{
  position:absolute; top:50%; left:50%; z-index:1;
  transform:translate(-50%,-52%);
  font-family:var(--font-shout);
  font-size:clamp(7rem,40vw,34rem);
  line-height:1; white-space:nowrap;
  color:transparent;
  -webkit-text-stroke:1.5px rgba(255,255,255,0.07);
  pointer-events:none; user-select:none;
}

/* magnetic cursor glow — a soft coral spotlight that
   trails the pointer across the hero, lighting up the
   watermark as it passes. Injected by script.js
   (initHeroGlow), desktop/fine-pointer/motion-OK only —
   see its JS gate and the media query below, same as
   the custom cursor. */
.hero__glow{
  position:absolute; top:0; left:0; z-index:1;
  width:640px; height:640px; margin:-320px 0 0 -320px;
  border-radius:50%;
  background:radial-gradient(circle, rgba(255,68,51,0.55) 0%, rgba(255,68,51,0) 70%);
  pointer-events:none;
  opacity:0;
  transition:opacity .4s ease;
  will-change:transform;
}
.hero__glow.is-visible{ opacity:1; }

@media (hover:none), (pointer:coarse){
  .hero__glow{ display:none; }
}

.hero__scroll-cue{
  font-family:var(--font-mono); font-size:0.8rem; text-transform:uppercase;
  letter-spacing:0.08em; color:var(--muted);
  margin-top:56px;
  animation:scrollCueBob 1.8s ease-in-out infinite;
}
@keyframes scrollCueBob{
  0%,100%{ transform:translateY(0); opacity:0.6; }
  50%{ transform:translateY(8px); opacity:1; }
}

.sticker{
  font-family:var(--font-mono); font-weight:700; font-size:0.75rem;
  text-transform:uppercase; text-align:center;
  display:flex; align-items:center; justify-content:center;
}
.sticker--tape{
  background:var(--lime); color:var(--cream);
  padding:8px 18px; border:3px solid var(--ink);
}
.sticker--circle{
  width:110px; height:110px; border-radius:50%;
  background:var(--coral); color:var(--cream);
  border:4px solid var(--ink); line-height:1.3;
}

.hero__eyebrow{
  position:relative; z-index:1;
  font-family:var(--font-mono); text-transform:uppercase;
  letter-spacing:0.08em; font-size:0.85rem; color:var(--violet);
  margin-top:clamp(24px, 5vw, 64px);
  margin-bottom:6px;
}
.hero__name{
  position:relative; z-index:1;
  font-family:var(--font-shout);
  text-transform:uppercase;
  font-size:clamp(3rem, 11.5vw, 9.5rem);
  line-height:0.92; letter-spacing:-0.01em;
  margin-bottom:clamp(16px, 2.4vw, 28px);
}
.hero__tagline{
  position:relative; z-index:1;
  font-size:clamp(1rem,1.6vw,1.3rem);
  line-height:1.65; max-width:840px;
  margin:0 auto clamp(48px, 8vw, 96px);
}
.hero__tagline em{
  font-style:normal; background:var(--lime); color:var(--cream);
  padding:3px 6px; box-decoration-break:clone;
}

/* ============================================
   MARQUEE LINE — a bare strip of moving dashes,
   no text. Used for the footer bar (in normal flow)
   and the site footer bar. The hero has its own
   text ticker instead (.hero__ticker below) — a bare
   dash strip alone at the bottom of the hero's tall
   scroll-parallax wrapper read as an unstyled leftover
   floating in empty space.
   ============================================ */
.marquee-line{
  position:relative;
  height:18px;
  overflow:hidden;
  border-top:3px solid var(--ink); border-bottom:3px solid var(--ink);
  background:var(--ink);
}
.marquee-line::before{
  content:"";
  position:absolute; inset:0;
  background-image:repeating-linear-gradient(to right, var(--cream) 0 26px, transparent 26px 42px);
  animation:marqueeLine 3.5s linear infinite;
}
.marquee-line--reverse::before{ animation-direction:reverse; }
.marquee-line--violet{ background:var(--violet); }
.marquee-line--violet::before{
  background-image:repeating-linear-gradient(to right, var(--cream) 0 26px, transparent 26px 42px);
}
@keyframes marqueeLine{ from{ transform:translateX(0); } to{ transform:translateX(-42px); } }

@media (prefers-reduced-motion:reduce){
  .marquee-line::before{ animation:none; }
}

/* ============================================
   HERO TICKER — a scrolling coral banner pinned to
   the hero's bottom edge, replacing the old bare dash
   marquee with something that actually reads as part
   of the design during the scroll-parallax dead zone.
   Content is written twice in the HTML back-to-back;
   the keyframe scrolls exactly half the track's width,
   so the loop seam is invisible.
   ============================================ */
.hero__ticker{
  position:absolute; bottom:0; z-index:2;
  left:50%; width:100vw; margin-left:-50vw;
  height:40px;
  overflow:hidden;
  border-top:3px solid var(--ink); border-bottom:3px solid var(--ink);
  background:var(--coral);
}
.hero__ticker-track{
  display:flex; align-items:center; gap:14px;
  height:100%; width:max-content; white-space:nowrap;
  font-family:var(--font-mono); font-weight:700; font-size:0.8rem;
  text-transform:uppercase; letter-spacing:0.06em; color:var(--ink);
  animation:heroTicker 16s linear infinite;
}
@keyframes heroTicker{ from{ transform:translateX(0); } to{ transform:translateX(-50%); } }

@media (prefers-reduced-motion:reduce){
  .hero__ticker-track{ animation:none; }
}

@media (max-width:760px){
  .hero{ padding-top:40px; overflow:visible; }
  .hero__ticker{
    position:relative; left:auto;
    width:100vw; margin-left:calc(50% - 50vw);
    margin-top:40px;
  }
}

/* ============================================
   HERO PARALLAX — a taller wrapper that keeps .hero
   pinned (position:sticky) while its own extra height
   scrolls past, so script.js (initHeroParallax) can
   drift/scale/fade .hero's content out at a different
   rate than the actual scroll — the classic parallax
   depth cue (marsrejects.com, thetinypod.com: content
   pinned in place while the scene transforms around
   it) — instead of a plain scroll cut into Background.
   Desktop only (see the max-width:760px override
   below) — a pinned scroll effect is more likely to
   feel janky than smooth on small screens, and costs
   precious scroll distance there.
   ============================================ */
.hero-flip{
  position:relative;
  height:125vh;
  /* slide up under the sticky nav so .hero's own
     min-height:100svh box actually starts at the true
     top of the viewport — otherwise the nav's reserved
     flow height pushes .hero (and its centered content)
     down, off true screen-center by half the nav's
     height. */
  margin-top:calc(-1 * var(--nav-h));
}
.hero{
  will-change:transform, opacity;
}
@media (min-width:761px){
  .hero{ position:sticky; top:0; }
}
@media (max-width:760px), (prefers-reduced-motion:reduce){
  .hero-flip{ height:auto; }
}

/* ============================================
   STATEMENT — a full-bleed manifesto line between
   Hero and Background, the "big single sentence"
   beat both references use (Love & Money's "LOVE AND
   MONEY BUILDS...", the Wix template's headline).
   ============================================ */
.statement{
  text-align:center;
  padding-top:clamp(60px,10vw,120px);
  padding-bottom:clamp(60px,10vw,120px);
}
.statement__text{
  font-family:var(--font-shout);
  text-transform:uppercase; letter-spacing:-0.01em;
  font-size:clamp(1.8rem,5.4vw,3.6rem);
  line-height:1.12;
  max-width:1000px; margin:0 auto;
}
.statement__text em{
  font-style:normal; color:var(--coral-text);
}

/* ============================================
   BACKGROUND
   ============================================ */
.background__content{
  display:grid;
  grid-template-columns: auto minmax(0, 560px);
  justify-content:space-between;
  align-items:center;
  gap:40px;
}
.background__bio{
  font-size:1.05rem; line-height:1.7;
  padding-top:clamp(28px, 5vw, 56px);
  padding-bottom:clamp(28px, 5vw, 56px);
}

.background__minji{
  position:relative; flex:none; z-index:1; pointer-events:none;
  width:clamp(280px, 30vw, 460px);
  margin:0 auto;
  transform-origin:center;
  will-change:transform, opacity;
  opacity:0;
  transform:translateY(30px) rotate(-3deg) scale(0.88);
  transition:transform .6s var(--ease), opacity .3s ease;
}
.background__minji.is-visible{
  opacity:1;
  transform:translateY(0) rotate(-1.5deg) scale(1);
}
.background__minji-img{
  width:100%; display:block;
  filter:drop-shadow(8px 10px 0 var(--ink));
}
.background__minji-tape{
  position:absolute;
  width:64px; height:26px;
  border:3px solid var(--ink);
  box-shadow:4px 4px 0 var(--ink);
}
.background__minji-tape--l{
  top:-16px; left:6%; transform:rotate(-6deg);
  background:var(--lime);
}
.background__minji-tape--r{
  top:-18px; right:10%; transform:rotate(5deg);
  background:var(--coral);
}

@media (max-width:900px){
  .background__content{
    grid-template-columns:1fr;
    justify-items:center;
    text-align:left;
  }
}

@media (prefers-reduced-motion:reduce){
  .background__minji{ transition:opacity .3s ease; }
}

/* ============================================
   SECTION SURFACES — alternating full-bleed color
   bands (statement/background/work/experience/skills/
   contact), the loud high-contrast block rhythm from
   the Love & Money / Wix Studio references. Each
   section paints edge-to-edge via a ::before sized to
   100vw (the same break-out trick already used by
   .marquee-line/.hobby-collage) regardless of the
   section element's own centered max-width box;
   isolation:isolate gives the section its own stacking
   context so the pseudo's z-index:-1 stays trapped
   behind that section's content instead of leaking out
   to sit behind the nav or an earlier section.
   .surface-light/.surface-bold locally reassign
   --cream/--ink/--muted, so every existing rule that
   already reads those tokens (borders, hover inverts,
   card fills) flips automatically — no per-component
   overrides needed except where a section's own accent
   color collides with its new background (see Contact).
   ============================================ */
.statement, .background, .work, .experience, .skills, .contact{
  position:relative;
  isolation:isolate;
  border-top:3px solid var(--ink);
}
.statement::before, .background::before, .work::before,
.experience::before, .skills::before, .contact::before{
  content:"";
  position:absolute; top:0; bottom:0;
  left:50%; width:100vw; margin-left:-50vw;
  background:var(--cream);
  z-index:-1;
}

.surface-light{
  --cream: #F2ECDD;
  --ink: #15130F;
  --muted: #6B6558;
}

.contact.surface-bold{
  --cream: var(--coral);
  --ink: #15130F;
  --muted: #7A3324;
}

/* ============================================
   SHARED SECTION HEAD
   ============================================ */
section{ padding:clamp(70px,9vw,130px) clamp(20px,4vw,56px); max-width:var(--max); margin:0 auto; background:var(--cream); color:var(--ink); }

/* stacked numeral-over-headline, both huge — the
   idealworks "playbook" arrangement (04 / BUILD A
   WORLD tucked tight on top of each other) rather than
   a small badge sitting beside the title on one line. */
.section-head{
  display:flex; flex-direction:column; align-items:flex-start;
  margin-bottom:clamp(40px,6vw,70px);
}
.section-head__num{
  font-family:var(--font-shout);
  font-size:clamp(2.4rem,7vw,5rem);
  line-height:0.9;
  color:var(--accent, var(--coral-text));
  margin-bottom:-0.08em;
}
.section-head__title{
  font-family:var(--font-shout);
  text-transform:uppercase; letter-spacing:-0.01em;
  font-size:clamp(2.6rem,8vw,5.2rem);
  line-height:0.94;
}
.section-head__note{
  font-family:var(--font-mono); font-size:0.8rem; color:var(--muted);
  margin-top:16px;
}

.reveal{ opacity:0; transform:translateY(28px); transition:opacity .6s ease, transform .6s ease; }
.reveal.is-visible{ opacity:1; transform:translateY(0); }

/* word-by-word title reveal — piggybacks on the
   .reveal/.is-visible trigger above for section
   titles; .hero__name gets its own is-visible
   class added once on load (see script.js). */
.word-reveal{
  display:inline-block;
  opacity:0; transform:translateY(36px) scale(0.6);
  transition:opacity .5s ease, transform .7s var(--ease);
  transition-delay:calc(var(--i,0) * 90ms);
}
.reveal.is-visible .word-reveal,
.hero__name.is-visible .word-reveal{
  opacity:1; transform:translateY(0) scale(1);
}
@media (prefers-reduced-motion:reduce){
  .word-reveal{ transition:none; opacity:1; transform:none; }
}

/* ============================================
   POP-IN — a reusable scroll-triggered entrance for
   repeated items (work rows, experience entries,
   skill cards, contact lines): scales up from small
   with the same bounce as .word-reveal above, staggered
   per item via --i (script.js initPopIn). One-shot,
   like the section .reveal it rides alongside.
   ============================================ */
.pop-in{
  opacity:0;
  transform:translateY(28px) scale(0.85);
  transition:opacity .5s ease, transform .6s var(--ease);
  transition-delay:calc(var(--i,0) * 90ms);
}
.pop-in.is-visible{
  opacity:1;
  transform:translateY(0) scale(1);
}
@media (prefers-reduced-motion:reduce){
  .pop-in{ transition:none; opacity:1; transform:none; }
}

/* ============================================
   WORK
   .work__layout breaks out to the true viewport edge
   (the same 100vw/-50vw trick as .marquee-line) so
   .work__pin can sit flush against the actual left
   edge of the screen — no gutter, no card margin —
   and stay there via position:sticky, released once
   .work__layout itself (taller than the panel, thanks
   to the 4 stacked rows) scrolls past. .work__list
   keeps its own reading-width padding so the project
   text doesn't run edge-to-edge too.
   ============================================ */
.work__layout{
  position:relative;
  display:flex; align-items:flex-start;
  width:100vw; margin-left:calc(50% - 50vw);
}
.work__pin{
  position:sticky;
  top:var(--nav-h);
  flex:none;
  isolation:isolate;
  width:clamp(120px,14vw,220px);
  height:calc(100vh - var(--nav-h));
  background:var(--ink);
  overflow:hidden;
  display:flex; flex-direction:column; align-items:center; justify-content:space-between;
  padding:28px 0;
}
.work__pin-dots{
  position:absolute; inset:0;
  background-image:radial-gradient(circle, rgba(255,255,255,0.4) 1.5px, transparent 1.5px);
  background-size:24px 24px;
  -webkit-mask-image:radial-gradient(ellipse at 50% 40%, black, transparent 75%);
  mask-image:radial-gradient(ellipse at 50% 40%, black, transparent 75%);
}
/* rotated running label — the strip's own identity
   (a spine label) instead of just a logo mark sitting
   in an otherwise-empty box. */
.work__pin-spine{
  position:relative; z-index:1;
  writing-mode:vertical-rl; transform:rotate(180deg);
  font-family:var(--font-shout); text-transform:uppercase;
  letter-spacing:0.04em;
  font-size:clamp(0.95rem,1.6vw,1.3rem);
  color:var(--cream);
  opacity:0.92;
}
.work__pin-mark{
  position:relative; z-index:1;
  font-family:var(--font-shout); font-size:1.2rem;
  color:var(--cream);
}
.work__pin-mark .dot{ color:var(--coral-text); }

.work__list{
  flex:1; min-width:0;
  border-top:3px solid var(--ink);
  padding:0 clamp(20px,4vw,56px);
}

@media (max-width:760px){
  .work__layout{ flex-direction:column; }
  .work__pin{
    position:static; width:100%; height:110px;
    flex-direction:row; justify-content:center; gap:16px;
    padding:0;
  }
  .work__pin-spine{ writing-mode:horizontal-tb; transform:none; font-size:1rem; }
  .work__list{ padding:0 clamp(20px,5vw,40px); }
}
.work__row{
  position:relative;
  display:flex; justify-content:space-between; align-items:flex-start; gap:24px;
  flex-wrap:wrap;
  padding:30px 4px;
  border-bottom:3px solid var(--ink);
  cursor:pointer;
  transition:background .2s, padding-left .2s;
}
.work__row:hover{ background:var(--ink); color:var(--cream); padding-left:18px; }
.work__row:hover .work__desc{ color:#5c5763; }
.work__row:hover .work__links a{ border-color:var(--coral); color:var(--coral); }

.work__row-main{ max-width:600px; }
.work__row-main:focus-visible{ outline:2px solid var(--coral); outline-offset:6px; border-radius:2px; }
.work__row-head{ display:flex; align-items:center; gap:14px; margin-bottom:8px; }
.work__index{
  font-family:var(--font-mono); font-weight:700; font-size:0.8rem;
  color:var(--coral-text); flex:none;
}
.work__thumb{
  width:48px; height:48px; flex:none; overflow:hidden;
  border:2.5px solid var(--ink); border-radius:10px; background:var(--cream);
  transition:border-color .2s, transform .2s;
}
.work__row:hover .work__thumb{ border-color:var(--coral); transform:rotate(-4deg) scale(1.05); }
.work__thumb img{ width:100%; height:100%; object-fit:cover; display:block; }
.work__title{
  font-family:var(--font-display); font-weight:700; font-style:italic;
  font-size:clamp(1.3rem,2.6vw,1.9rem);
}
.work__desc{ font-size:0.95rem; line-height:1.5; color:var(--muted); transition:color .2s; }

.work__row-meta{ display:flex; flex-direction:column; align-items:flex-end; gap:14px; }
.work__tags{ display:flex; gap:8px; flex-wrap:wrap; justify-content:flex-end; }
.work__tags span{
  font-family:var(--font-mono); font-size:0.7rem; text-transform:uppercase;
  border:1.5px solid currentColor; border-radius:100px; padding:3px 10px;
}
.work__links{ display:flex; gap:14px; }
.work__links a{
  font-family:var(--font-mono); font-size:0.78rem; font-weight:700;
  border-bottom:2px solid transparent; transition:border-color .2s, color .2s;
}
.work__links a:hover{ border-color:currentColor; }

/* ============================================
   WORK HOVER PREVIEW — a floating polaroid-style
   thumbnail that trails the cursor while hovering a
   .work__row (script.js initWorkPreview), making good
   on the section note's "Hover a row to preview →".
   Sits below the custom cursor's z-index so the ring
   still reads on top of it. Desktop, fine-pointer,
   motion-OK only — see the JS gate and the media
   queries below.
   ============================================ */
.work-preview{
  position:fixed; top:0; left:0; z-index:450;
  width:200px; aspect-ratio:4/3;
  border:4px solid var(--ink);
  box-shadow:10px 10px 0 rgba(0,0,0,0.4);
  overflow:hidden;
  background:var(--cream);
  opacity:0;
  pointer-events:none;
  transition:opacity .18s ease;
  will-change:transform, opacity;
}
.work-preview.is-visible{ opacity:1; }
.work-preview img{ width:100%; height:100%; object-fit:cover; display:block; }

@media (hover:none), (pointer:coarse), (max-width:760px){
  .work-preview{ display:none; }
}

/* ============================================
   CUSTOM CURSOR — a small brand-colored ring that
   trails the pointer across the whole site (script.js
   initCustomCursor, appended once to <body> so every
   page gets it without its own markup), swelling over
   links/buttons. html.has-custom-cursor is only added
   once the JS actually runs, and only on fine-pointer/
   hover-capable, non-reduced-motion devices — so a
   script failure or a touch device just keeps the
   normal system cursor instead of going invisible.
   ============================================ */
.custom-cursor{
  position:fixed; top:0; left:0; z-index:500;
  width:20px; height:20px; margin:-10px 0 0 -10px;
  border-radius:50%;
  border:3px solid var(--ink);
  background:var(--coral);
  pointer-events:none;
  opacity:0;
  transition:width .2s var(--ease), height .2s var(--ease),
             margin .2s var(--ease), background .2s ease, opacity .15s ease;
}
html.has-custom-cursor, html.has-custom-cursor *{ cursor:none !important; }
html.has-custom-cursor .custom-cursor{ opacity:1; }
html.has-custom-cursor .custom-cursor.is-hover{
  width:42px; height:42px; margin:-21px 0 0 -21px;
  background:var(--lime);
}
html.has-custom-cursor .custom-cursor.is-down{
  width:14px; height:14px; margin:-7px 0 0 -7px;
}

@media (hover:none), (pointer:coarse){
  .custom-cursor{ display:none; }
  html.has-custom-cursor, html.has-custom-cursor *{ cursor:auto !important; }
}

/* ============================================
   EXPERIENCE
   ============================================ */
.experience__list{ display:flex; flex-direction:column; }
.experience__item{
  position:relative;
  display:grid; grid-template-columns:180px 1fr; gap:24px;
  padding:34px 0 34px 28px; border-top:3px solid var(--ink);
  transition:transform .25s var(--ease);
}
.experience__item:last-child{ border-bottom:3px solid var(--ink); }
.experience__item--coral{ --accent:var(--coral); }
.experience__item--lime{ --accent:var(--lime); }
.experience__item--violet{ --accent:var(--violet); }

/* accent rail — a colored bar that grows in from the
   top on hover, same "flag" gesture as the skills
   cards' hard-shadow lift, scaled down for a full-width
   row instead of a standalone card. */
.experience__item::before{
  content:"";
  position:absolute; left:0; top:0; bottom:0;
  width:5px; background:var(--accent, var(--coral));
  transform:scaleY(0); transform-origin:top;
  transition:transform .3s var(--ease);
}
.experience__item:hover{ transform:translateX(4px); }
.experience__item:hover::before{ transform:scaleY(1); }

.experience__dates{
  font-family:var(--font-mono); font-weight:700; font-size:0.8rem;
  text-transform:uppercase; letter-spacing:0.02em;
  color:var(--accent, var(--violet));
  border:1.5px solid var(--accent, var(--violet));
  border-radius:100px;
  padding:6px 14px;
  display:inline-flex; width:fit-content;
  white-space:nowrap;
  /* a grid item's "inline-flex" is blockified to "flex", so
     the default grid align-items/justify-items:stretch was
     ballooning this into a full-height, full-width capsule
     instead of hugging its text. */
  align-self:start; justify-self:start;
}

.experience__body h3{
  font-family:var(--font-display); font-weight:700; font-size:1.5rem;
  margin-bottom:14px;
}
.experience__body h3 span{
  font-family:var(--font-body); font-weight:400; font-style:normal;
  font-size:1rem; color:var(--muted); display:block; margin-top:2px;
}
.experience__body ul{ display:flex; flex-direction:column; gap:8px; margin-bottom:16px; }
.experience__body li{
  font-size:0.95rem; line-height:1.55; padding-left:20px; position:relative;
}
.experience__body li::before{
  content:"→"; position:absolute; left:0; color:var(--accent, var(--coral-text)); font-weight:700;
}
.experience__tags{ display:flex; gap:8px; flex-wrap:wrap; }
.experience__tags span{
  font-family:var(--font-mono); font-size:0.7rem; text-transform:uppercase;
  border:1.5px solid currentColor; border-radius:100px;
  padding:3px 10px;
}

@media (max-width:640px){
  .experience__item{ grid-template-columns:1fr; gap:10px; }
}

/* ============================================
   SKILLS
   ============================================ */
/* base/fallback layout — overridden into a looping
   book-page marquee by both the max-width:760px (horizontal,
   touch-panned) and min-width:761px (vertical, mouse-panned)
   blocks below; initSkillsStack in script.js drives both. */
.skills__grid{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(230px, 1fr));
  gap:24px;
  padding-top:10px;
}
.skills__cat{
  position:relative; z-index:1;
  /* dark card face for every category (was a full
     color fill per card) — the category color now
     lives only in the icon + hard shadow below, via
     --accent, so it reads as an accent rather than
     the whole card, and no longer disappears against
     a same-colored section background. */
  background:var(--cream); color:var(--ink);
  border:4px solid var(--ink); border-radius:2px;
  padding:26px;
  box-shadow:8px 8px 0 var(--accent, var(--coral));
  transition:transform .25s var(--ease), box-shadow .25s var(--ease);
}
.skills__cat:hover{
  z-index:5;
  transform:translate(-6px,-6px);
  box-shadow:16px 16px 0 var(--accent, var(--coral));
}
.skills__cat h3{
  font-family:var(--font-display); font-weight:700; font-style:italic;
  font-size:1.3rem; margin-bottom:16px;
}
.skills__cat--coral{ --accent:var(--coral); }
.skills__cat--lime{ --accent:var(--lime); }
.skills__cat--violet{ --accent:var(--violet); }
.skills__cat--ink{ --accent:var(--muted); }

.skills__tags{ display:flex; flex-wrap:wrap; gap:8px; }
.skills__tags span{
  font-family:var(--font-mono); font-size:0.75rem;
  border:1.5px solid currentColor; border-radius:100px; padding:5px 12px;
}

/* cutout-sticker icons — same paper-cutout language as
   the hero collage (solid shape, thick ink border, hard
   shadow) rather than icon-font glyphs, so the category
   badges read as part of the same scrapbook rather than
   a different kit. Solid-filled in --accent now (was a
   plain cream cutout) so each icon carries its card's
   color instead of the card's whole background doing it. */
.skills__icon{
  display:block; margin-bottom:18px;
}
.skills__icon--circle,
.skills__icon--diamond,
.skills__icon--rounded{
  width:42px; height:42px;
  background:var(--accent, var(--coral));
  border:3px solid var(--ink);
  box-shadow:5px 5px 0 var(--ink);
}
.skills__icon--circle{ border-radius:50%; }
.skills__icon--diamond{ transform:rotate(45deg); }
.skills__icon--rounded{ border-radius:30%; }
.skills__icon--tri{
  width:0; height:0;
  border-left:20px solid transparent;
  border-right:20px solid transparent;
  border-bottom:36px solid var(--accent, var(--coral));
  filter:drop-shadow(5px 5px 0 var(--ink));
}

.skills__nav{ display:none; }

@media (max-width:760px){
  /* Horizontal "book page" marquee. Every card is pinned
     into the same grid cell and positioned by --dist — its
     signed circular distance from the current (continuous,
     ever-drifting) position — 0 = active/centered, ±1 = the
     previous/next page peeking at the edges, ±2 = further
     pages parked just off-screen. initSkillsStack in
     script.js recomputes --dist every animation frame and
     writes the transform directly, so transform/opacity
     have no CSS transition here — one would just lag a
     beat behind the constantly-moving target. Dragging a
     card grabs the position outright (script.js), and
     Prev/Next eases it by one card. */
  .skills__grid{
    display:grid;
    grid-template-columns:1fr;
    overflow:hidden;
    cursor:grab;
    touch-action:pan-y;
  }
  .skills__grid.is-dragging{ cursor:grabbing; }
  .skills__cat{
    grid-row:1; grid-column:1;
    width:82%;
    margin:0 auto;
    min-height:270px;
    padding:20px 22px;
    z-index:calc(10 - var(--absdist,0));
    opacity:calc(1 - var(--absdist,0) * 0.4);
    transition:box-shadow .3s var(--ease);
  }
  /* .skills__grid-prefixed so this beats .pop-in.is-visible's
     transform (script.js's scroll-reveal stagger, same
     0,0,2,0 specificity but declared earlier in the file) —
     without it every card snaps flat once its pop-in
     reveal fires, killing the deck. */
  .skills__grid .skills__cat{
    transform:translateX(calc(var(--dist,0) * 105%));
  }
  .skills__cat.is-active{
    box-shadow:12px 12px 0 var(--accent, var(--coral));
    z-index:50;
  }
  .skills__cat:focus-visible{
    outline:3px solid var(--ink); outline-offset:2px;
  }

  .skills__cat__head{
    display:flex; align-items:center; gap:12px;
  }
  .skills__cat .skills__icon{ margin-bottom:0; flex-shrink:0; }
  .skills__cat .skills__icon--circle,
  .skills__cat .skills__icon--diamond,
  .skills__cat .skills__icon--rounded{ width:30px; height:30px; }
  .skills__cat .skills__icon--tri{
    border-left-width:14px; border-right-width:14px; border-bottom-width:24px;
  }
  .skills__cat h3{ margin-bottom:0; font-size:1.05rem; }
  .skills__tags{ margin-top:16px; }

  /* Prev | Next page controls below the carousel. */
  .skills__nav{
    display:flex; align-items:center; justify-content:center; gap:14px;
    margin-top:18px;
    font-family:var(--font-mono); font-size:0.8rem; letter-spacing:.02em;
  }
  .skills__nav button{
    background:none; border:none; padding:6px; cursor:pointer;
    color:var(--ink); font:inherit;
  }
  .skills__nav__prev::before{ content:"‹ "; }
  .skills__nav__next::after{ content:" ›"; }
  .skills__nav__sep{ opacity:.4; }
}

@media (min-width:761px){
  /* Same book-page marquee as the mobile block above, just
     bigger — cards share one grid cell and are positioned by
     --dist along the X axis, same as mobile, so the deck
     loops left-to-right on every breakpoint (panned by mouse
     drag or wheel here instead of touch). touch-action:pan-y
     leaves normal vertical page scroll alone; only the
     horizontal drag gesture is captured by the grid, so
     swiping here never fights page scroll or bleeds outside
     the carousel. */
  .skills__grid{
    display:grid;
    grid-template-columns:1fr;
    max-width:min(980px, 92%);
    margin:0 auto;
    overflow:hidden;
    cursor:grab;
    touch-action:pan-y;
  }
  .skills__grid.is-dragging{ cursor:grabbing; }
  .skills__cat{
    grid-row:1; grid-column:1;
    min-height:clamp(360px, 44vw, 520px);
    padding:clamp(32px, 4vw, 52px);
    z-index:calc(10 - var(--absdist,0));
    opacity:calc(1 - var(--absdist,0) * 0.4);
    transition:box-shadow .3s var(--ease);
  }
  /* .skills__grid-prefixed for the same specificity-over-pop-in
     reason as the mobile rule above. */
  .skills__grid .skills__cat{
    transform:translateX(calc(var(--dist,0) * 105%));
  }
  .skills__cat.is-active{
    box-shadow:18px 18px 0 var(--accent, var(--coral));
    z-index:50;
  }
  .skills__cat:focus-visible{
    outline:3px solid var(--ink); outline-offset:2px;
  }
  /* scale the card's internals up with it — the base sizes
     (42px icon, 1.3rem h3) read small once the card itself
     is filling most of the viewport. */
  .skills__cat h3{ font-size:clamp(1.3rem, 2.2vw, 1.8rem); margin-bottom:22px; }
  .skills__cat .skills__icon--circle,
  .skills__cat .skills__icon--diamond,
  .skills__cat .skills__icon--rounded{ width:clamp(42px, 4vw, 56px); height:clamp(42px, 4vw, 56px); }
  .skills__cat .skills__icon--tri{
    border-left-width:clamp(20px, 2vw, 26px); border-right-width:clamp(20px, 2vw, 26px);
    border-bottom-width:clamp(36px, 3.5vw, 46px);
  }
  .skills__cat .skills__tags span{ font-size:0.85rem; padding:7px 14px; }

  /* Prev | Next page controls below the carousel. */
  .skills__nav{
    display:flex; align-items:center; justify-content:center; gap:14px;
    margin-top:22px;
    font-family:var(--font-mono); font-size:0.85rem; letter-spacing:.02em;
  }
  .skills__nav button{
    background:none; border:none; padding:6px; cursor:pointer;
    color:var(--ink); font:inherit;
  }
  .skills__nav__prev::before{ content:"‹ "; }
  .skills__nav__next::after{ content:" ›"; }
  .skills__nav__sep{ opacity:.4; }
}

/* ============================================
   CONTACT
   back to black to close the palette loop —
   normal white-on-dark, same as Background/Work.
   ============================================ */
.contact{ text-align:left; }
.contact__cta{
  font-family:var(--font-shout);
  text-transform:uppercase;
  font-size:clamp(2.6rem,8vw,5.6rem); line-height:0.96; margin-bottom:20px;
}
.contact__sub{ font-size:1.1rem; max-width:480px; margin-bottom:36px; color:var(--muted); }
.contact__email{
  display:inline-block; font-family:var(--font-mono); font-weight:700;
  font-size:clamp(1.3rem,4vw,2rem);
  border-bottom:4px solid var(--ink); padding-bottom:4px; margin-bottom:48px;
  transition:color .2s, border-color .2s;
}
.contact__email:hover{ color:var(--violet); border-color:var(--violet); }

.contact__row{
  display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap;
  gap:24px; border-top:3px solid var(--ink); padding-top:28px;
}
.contact__links{ display:flex; gap:24px; flex-wrap:wrap; }
.contact__links a{
  font-family:var(--font-mono); font-size:0.9rem; font-weight:700;
  text-transform:uppercase; letter-spacing:0.02em;
  transition:color .2s;
}
.contact__links a:hover{ color:var(--violet); }
.contact__resume{
  font-family:var(--font-mono); font-weight:700; font-size:0.85rem;
  padding:12px 22px; background:var(--ink); color:var(--coral);
  border-radius:100px; transition:transform .15s;
}
.contact__resume:hover{ transform:scale(1.03); }
.contact:not(.surface-bold) .contact__resume{ color:var(--cream); }
.contact:not(.surface-bold) .contact__resume:hover{ background:var(--coral); }

/* ============================================
   FOOTER
   ============================================ */
.footer{
  padding:0 clamp(20px,4vw,56px) 40px;
}
.footer .marquee-line{
  width:100vw; margin-left:calc(50% - 50vw);
}
.footer__top, .footer__copy{
  max-width:var(--max); margin:0 auto;
  font-family:var(--font-mono); font-size:0.8rem;
}
.footer__top{ display:block; padding:24px 0 8px; font-weight:700; }
.footer__top:hover{ color:var(--coral-text); }
.footer__copy{ color:var(--muted); padding-bottom:10px; }

/* ============================================
   PROJECT DETAIL PAGES
   ============================================ */
.project-detail__back{
  display:inline-flex; align-items:center; gap:8px;
  font-family:var(--font-mono); font-weight:700; font-size:0.85rem;
  color:var(--muted); margin-bottom:32px; transition:color .2s;
}
.project-detail__back:hover{ color:var(--coral-text); }
.project-detail__back:focus-visible{ outline:2px solid var(--coral); outline-offset:4px; border-radius:2px; }

.project-detail__hero{
  border:3px solid var(--ink); border-radius:2px; overflow:hidden;
  margin-bottom:28px;
}
.project-detail__hero img{ width:100%; height:auto; display:block; }

.project-detail__meta{
  display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap;
  gap:16px; border-bottom:3px solid var(--ink); padding-bottom:28px; margin-bottom:36px;
}
.project-detail__tags{ display:flex; gap:8px; flex-wrap:wrap; }
.project-detail__tags span{
  font-family:var(--font-mono); font-size:0.75rem; text-transform:uppercase;
  border:1.5px solid currentColor; border-radius:100px; padding:4px 12px;
}

.project-detail__body{ max-width:760px; }
.project-detail__lede{
  font-family:var(--font-display); font-weight:600; font-style:italic;
  font-size:clamp(1.3rem,3vw,1.7rem); line-height:1.4; margin-bottom:40px;
}
.project-detail__body h3{
  font-family:var(--font-mono); font-weight:700; text-transform:uppercase;
  font-size:0.85rem; letter-spacing:0.04em; color:var(--coral-text);
  margin:36px 0 14px;
}
.project-detail__body p{ font-size:1rem; line-height:1.7; color:var(--muted); }
.project-detail__body ul{ display:flex; flex-direction:column; gap:10px; }
.project-detail__body ul li{
  font-size:1rem; line-height:1.6; color:var(--muted);
  padding-left:22px; position:relative;
}
.project-detail__body ul li::before{
  content:"—"; position:absolute; left:0; color:var(--coral-text);
}

.project-detail__nav{
  display:flex; justify-content:space-between; gap:16px; flex-wrap:wrap;
  border-top:3px solid var(--ink); margin-top:56px; padding-top:28px;
}
.project-detail__nav a{
  font-family:var(--font-mono); font-weight:700; font-size:0.85rem;
  border-bottom:2px solid transparent; transition:border-color .2s, color .2s;
}
.project-detail__nav a:hover{ border-color:var(--coral); color:var(--coral-text); }

@media (max-width:640px){
  .project-detail__meta{ flex-direction:column; align-items:flex-start; }
}

/* ============================================
   HOBBIES — scattered photo moodboard (hobbies.html)
   full-bleed (breaks out to 100vw via the same
   left:50%/margin-left:-50vw trick as the section
   color blocks above), with tiles freely positioned
   via per-tile --x/--y/--w custom properties instead
   of a grid, so sizes and gaps stay irregular rather
   than packed to a repeating track. Clicking a photo
   opens the floating lightbox anchored right next to
   that tile (see below).
   ============================================ */
.hobby-collage{
  position:relative;
  width:100vw; margin-left:calc(50% - 50vw);
  min-height:1020px;
  margin-top:12px; margin-bottom:40px;
}
.hobby-tile{
  position:absolute;
  left:var(--x); top:var(--y);
  width:var(--w);
}
.hobby-tile:hover, .hobby-tile:focus-within{ z-index:5; }

.hobby-tile--tall{ aspect-ratio:3/4; }
.hobby-tile--square{ aspect-ratio:4/5; }
.hobby-tile--wide{ aspect-ratio:4/3; }
.hobby-tile--lg{ aspect-ratio:4/5; }

.hobby-card__btn{
  display:block; position:relative;
  width:100%; height:100%;
  background:none; border:none; padding:0; margin:0;
  font:inherit; color:inherit; text-align:left; cursor:pointer;
  border:4px solid var(--ink);
  box-shadow:10px 10px 0 rgba(0,0,0,0.35);
  transition:transform .25s var(--ease), box-shadow .25s var(--ease);
}
.hobby-card__btn__frame{
  display:block; width:100%; height:100%; overflow:hidden;
}
.hobby-card__btn img{
  display:block; width:100%; height:100%; object-fit:cover;
  transition:transform .35s var(--ease), filter .35s ease;
}
.hobby-card__label{
  position:absolute; left:10px; bottom:10px; z-index:1;
  font-family:var(--font-mono); font-weight:700; font-size:0.7rem;
  text-transform:uppercase; letter-spacing:0.02em;
  background:var(--ink); color:var(--cream);
  padding:6px 10px;
  opacity:0; transform:translateY(6px);
  transition:opacity .25s ease, transform .25s ease;
}

.hobby-card__btn:hover,
.hobby-card__btn:focus-visible{
  transform:translate(-6px,-6px);
  box-shadow:16px 16px 0 var(--coral);
}
.hobby-card__btn:hover img,
.hobby-card__btn:focus-visible img{
  transform:scale(1.06);
}
.hobby-card__btn:hover .hobby-card__label,
.hobby-card__btn:focus-visible .hobby-card__label{
  opacity:1; transform:translateY(0);
}
.hobby-card__btn:focus-visible{ outline:2px solid var(--coral); outline-offset:4px; }

.hobby-tile--text .sticker{ width:100%; height:100%; }
.hobby-tile--text .sticker--tape{ border-width:3px; }
.hobby-tile--text .sticker--circle{
  width:100%; aspect-ratio:1/1; margin:0 auto;
}

@media (prefers-reduced-motion:reduce){
  .hobby-card__btn img{ transition:none; }
}

@media (max-width:760px){
  .hobby-collage{
    position:static; width:auto; margin-left:0;
    min-height:0;
    display:flex; flex-direction:column; align-items:center; gap:28px;
    padding:0 clamp(20px,5vw,40px);
  }
  .hobby-tile{
    position:static !important;
    width:min(340px, 82vw) !important;
  }
  .hobby-tile--text{ width:min(220px, 60vw) !important; }
  .hobby-card__label{ opacity:1; transform:none; }
}

/* ============================================
   LIGHTBOX — really just a floating text caption now
   (title + blurb, no repeated image — the photo's
   already right there in the tile). On hover-capable
   pointers it opens/closes purely on hover (script.js
   initHobbyLightbox), so the backdrop stays
   click-through (pointer-events:none) and the close
   button is hidden — nothing to dismiss, it just
   follows the mouse. JS measures the hovered tile and
   the panel, then floats it to whichever side has
   room, staying anchored to that tile instead of the
   viewport edge. On touch/coarse pointers, where hover
   doesn't exist, it falls back to tap-to-toggle with a
   centered card, a dimmed clickable backdrop, and a
   visible close button.
   ============================================ */
.lightbox{
  position:fixed; inset:0; z-index:400;
  visibility:hidden;
  opacity:0;
  pointer-events:none;
  transition:opacity .2s ease, visibility 0s linear .2s;
}
.lightbox.is-open{
  visibility:visible; opacity:1;
  transition:opacity .2s ease;
}
.lightbox__backdrop{
  position:absolute; inset:0;
  background:transparent;
  pointer-events:none;
}
.lightbox.is-centered.is-open .lightbox__backdrop{
  background:rgba(0,0,0,0.55);
  backdrop-filter:blur(2px);
  pointer-events:auto;
}
.lightbox__panel{
  position:fixed; z-index:1;
  top:0; left:0;
  width:min(240px, 82vw);
  background:var(--cream);
  color:var(--ink);
  border:5px solid var(--ink);
  box-shadow:10px 10px 0 var(--coral);
  padding:16px 18px;
  max-height:min(70vh, 400px);
  overflow-y:auto;
  display:flex; flex-direction:column;
  opacity:0;
  pointer-events:auto;
  transform:scale(0.92);
  transition:transform .3s var(--ease), opacity .2s ease, top .18s ease, left .18s ease;
}
.lightbox.is-open .lightbox__panel{
  opacity:1;
  transform:scale(1);
}
.lightbox.is-centered .lightbox__panel{
  transition:opacity .2s ease, transform .2s ease;
}
.lightbox__close{
  position:absolute; top:14px; right:14px; z-index:1;
  width:32px; height:32px; border-radius:50%;
  background:var(--ink); color:var(--cream);
  border:3px solid var(--cream);
  font-family:var(--font-mono); font-size:0.9rem; font-weight:700;
  cursor:pointer;
  transition:transform .2s, background .2s, color .2s;
}
.lightbox__close:hover{ background:var(--coral); transform:rotate(90deg); }
.lightbox__title{
  font-family:var(--font-display); font-weight:700; font-style:italic;
  font-size:1.15rem; margin:0 0 8px;
}
.lightbox__caption{ font-size:0.85rem; line-height:1.5; color:var(--muted); }

@media (hover:hover) and (pointer:fine){
  .lightbox__close{ display:none; }
}

@media (max-width:640px){
  .lightbox__panel{
    width:min(280px, 84vw);
    padding:20px 22px 22px;
  }
}

@media (prefers-reduced-motion:reduce){
  .lightbox, .lightbox__panel{ transition:opacity .15s ease; }
  .lightbox__panel{ transform:none !important; }
}
