/* =========================================================
   Kyle Ferreira — Portfolio
   --------------------------------------------------------- */

:root {
  --bg: #f4f3f0;
  --bg-2: #ecebe6;
  --ink: #0d0d0d;
  --ink-2: #1a1a1a;
  --muted: #8a8a8a;
  --muted-2: #b8b6af;
  --hairline: #dfdcd5;
  --dark: #0a0a0a;
  --dark-text: #f4f3f0;
  --dark-muted: rgba(244, 243, 240, 0.72);
  --accent: #9ec5fe;
  --accent-2: #cfe1fc;
  --accent-ink: #0d0d0d;

  --radius: 14px;
  --radius-lg: 28px;

  --container: clamp(20px, 5vw, 80px);

  --ease: cubic-bezier(0.7, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);

  --display: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
  --body: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--body);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

html { scroll-behavior: auto; }

body {
  overflow-x: hidden;
  font-size: 16px;
  line-height: 1.5;
}
body.has-cursor { cursor: none; }
body.has-cursor a,
body.has-cursor button { cursor: none; }

a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
img, svg { display: block; max-width: 100%; }

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

/* =========================================================
   Cursor (mix-blend-mode: difference inverts on dark bg)
========================================================= */
.cursor, .cursor-dot {
  position: fixed;
  top: 0; left: 0;
  pointer-events: none;
  z-index: 9999;
  transform: translate3d(-50%, -50%, 0);
  transition: opacity .25s ease, width .25s var(--ease-out), height .25s var(--ease-out), background .25s ease;
  mix-blend-mode: difference;
}
.cursor {
  width: 32px; height: 32px;
  border: 1.5px solid #ffffff;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: #ffffff;
  font-size: 11px;
  font-family: var(--body);
  font-weight: 500;
  background: transparent;
}
.cursor-dot {
  width: 5px; height: 5px;
  background: #ffffff;
  border-radius: 50%;
}
.cursor.is-hover {
  width: 72px; height: 72px;
  background: #ffffff;
  color: #000;
  border-color: #ffffff;
}
.cursor.is-hidden, .cursor-dot.is-hidden { opacity: 0; }

@media (hover: none), (pointer: coarse) {
  .cursor, .cursor-dot { display: none; }
}

/* =========================================================
   Loader
========================================================= */
.loader {
  position: fixed; inset: 0;
  background: var(--bg);
  z-index: 10000;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 18px;
  transition: opacity .6s var(--ease-out), visibility .6s;
}
.loader.is-done { opacity: 0; visibility: hidden; }
.loader-bar {
  width: 220px; height: 1px;
  background: var(--hairline);
  overflow: hidden;
}
.loader-bar span {
  display: block; width: 0; height: 100%;
  background: var(--ink);
  transition: width .8s var(--ease-out);
}
.loader-text {
  font-family: var(--display);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: 0.04em;
}

/* =========================================================
   Navigation
========================================================= */
.nav {
  position: fixed; top: 0; left: 0; right: 0;
  z-index: 100;
  display: flex; align-items: center; justify-content: space-between;
  padding: 22px var(--container);
  pointer-events: none;
}
.nav > * { pointer-events: auto; }

.nav-mark {
  font-family: var(--display);
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.02em;
  color: var(--ink);
  transition: opacity .3s ease;
}
.nav-mark:hover { opacity: 0.6; }

.nav-toggle {
  position: relative;
  width: 36px; height: 36px;
  display: grid;
  grid-template-columns: repeat(2, 4px);
  grid-template-rows: repeat(3, 4px);
  gap: 5px;
  align-content: center; justify-content: center;
  padding: 0;
  border-radius: 50%;
  transition: background .3s ease;
}
.nav-toggle span {
  width: 4px; height: 4px;
  background: var(--ink);
  border-radius: 50%;
  transition: transform .4s var(--ease-out), opacity .3s ease, background .3s ease;
}
.nav-toggle:hover span { transform: scale(1.4); }
/* When the menu pane is open, dots fade out and a clean X icon takes over */
.nav-toggle.is-open span { opacity: 0; }
.nav-toggle.is-open::before,
.nav-toggle.is-open::after {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  width: 20px; height: 1.5px;
  background: #ffffff;
  border-radius: 1px;
  transform-origin: center;
}
.nav-toggle.is-open::before { transform: translate(-50%, -50%) rotate(45deg); }
.nav-toggle.is-open::after  { transform: translate(-50%, -50%) rotate(-45deg); }

/* Slide-out menu */
.menu {
  position: fixed; top: 0; right: 0;
  width: min(420px, 90vw);
  height: 100vh;
  background: var(--ink);
  color: var(--dark-text);
  z-index: 99;
  padding: 120px var(--container) 40px;
  transform: translateX(100%);
  transition: transform .7s var(--ease);
  display: flex; flex-direction: column;
  justify-content: space-between;
}
.menu.is-open { transform: translateX(0); }
.menu ul { list-style: none; display: flex; flex-direction: column; gap: 6px; }
.menu li { overflow: visible; }
.menu a {
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(36px, 5vw, 56px);
  letter-spacing: -0.03em;
  display: inline-block;
  position: relative;
  padding: 4px 0;
  transition: transform .4s var(--ease-out), color .3s ease;
}
.menu a::after {
  content: '';
  position: absolute; left: 0; bottom: 6px;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0); transform-origin: left;
  transition: transform .4s var(--ease-out);
}
.menu a:hover { transform: translateX(12px); }
.menu a:hover::after { transform: scaleX(1); }
.menu-meta {
  display: flex; flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: rgba(255,255,255,0.5);
  letter-spacing: 0.02em;
}

/* =========================================================
   Hero — Framer layout (cream bg, name left, portrait top-right)
========================================================= */
.hero {
  min-height: 100vh;
  /* TWEAK: hero padding = top  right  bottom  left.
     Increase the top number to push everything lower.
     Decrease the left number (or use 0) to push name+email closer to the edge. */
  padding: 140px var(--container) 80px;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  background: var(--bg);
  /* Clip any overflow inside the hero so very-large name / wide intro
     can't bleed past the section's edges when you tweak the values. */
  overflow: hidden;
}

.hero-grid {
  display: grid;
  /* minmax(0, 1fr) lets the left column shrink below the name's natural
     width — without this, a too-big "FERREIRA" would force the column to
     grow and shove everything else off-screen. */
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto 1fr auto;
  /* TWEAK: column-gap = space between the name column and the portrait/intro column.
     row-gap is whitespace between the top row (name + portrait) and the bottom row (email + intro). */
  column-gap: 20px;
  row-gap: 40px;
  align-items: start;
  min-height: 0; /* prevent grid from forcing min-content height */
}
.hero-name { grid-column: 1 / 2; grid-row: 1 / 3; align-self: start; }

/* PORTRAIT placement.
   TWEAK align-self:
     'start'  → top-right (sits next to KYLE)
     'center' → middle (between KYLE & FERREIRA)
     'end'    → bottom (sits next to FERREIRA — matches the reference)
   TWEAK margin-bottom — lifts the portrait UP from the row below it.
   TWEAK margin-right — negative value pulls it past the right edge. */
.hero-portrait {
  grid-column: 2 / 4;
  grid-row: 1 / 3;
  align-self: start;
  /* Push the portrait to the RIGHT edge of its column instead of the default
     (which is the left edge, right next to "FERREIRA"). This is the lever
     that fixes the overlap. */
  justify-self: end;
  margin-bottom: 36px;
  margin-right: -10px;
}

/* TWEAK padding-bottom — bigger value pushes the email UP from the bottom edge */
.hero-email {
  grid-column: 1 / 2;
  grid-row: 3 / 4;
  align-self: end;
  padding-bottom: 12px;
}

/* INTRO paragraph column.
   TWEAK width: clamp(min, fluid, max) controls how wide the intro column is.
   TWEAK justify-self: 'end' pins right, 'start' pins left, 'center' centers.
   TWEAK margin-bottom: lifts the intro UP from the bottom edge. */
.hero-intro {
  grid-column: 2 / 3;
  grid-row: 3 / 4;
  align-self: end;
  width: clamp(400px, 42vw, 620px);
  justify-self: end;
  margin-right: -10px;
  margin-bottom: 8px;
}

/* Display type — KYLE / FERREIRA in the hero
   TWEAK font-size: the third number caps the maximum size (try 168 / 184 / 200).
   TWEAK line-height: lower (0.85) tightens the stack, higher (0.95) opens it. */
.display {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(80px, 14.5vw, 200px);
  line-height: 0.88;
  letter-spacing: -0.05em;
  color: var(--ink);
}
.display em {
  font-style: italic;
  font-weight: 500;
  color: var(--muted);
}

/* Circular portrait, top-right */
.portrait-frame {
  width: clamp(150px, 16vw, 230px);
  height: clamp(150px, 16vw, 230px);
  border-radius: 50%;
  overflow: hidden;
  position: relative;
  background: var(--ink-2);
  transition: transform .6s var(--ease-out);
}
.portrait-frame:hover { transform: scale(1.04); }
.portrait-frame img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

/* INTRO paragraph text (right-bottom of hero).
   TWEAK font-size: third number caps the maximum.
   TWEAK line-height: 1.3 = tight, 1.5 = airy. */
.hero-intro p {
  font-family: var(--display);
  font-size: clamp(22px, 2.4vw, 30px);
  line-height: 1.35;
  text-align: justify;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink);
}

/* (legacy centered-tagline classes intentionally removed in this layout) */

/* (legacy bottom-bleed bigname removed — see .hero--dark .hero-bigname above) */
/* (hero email + status pill removed in dark hero layout) */

/* (.display rule lives earlier in this file — duplicate removed) */
.display-line {
  display: block;
  overflow: hidden;
  /* Bottom padding adds a buffer below the line so letter descenders /
     diagonals (the apex of "A", legs of "R") don't get clipped by
     overflow:hidden. Negative margin-bottom pulls the next line back up
     so the visual stacking between KYLE and FERREIRA stays tight. */
  padding: 0 0 0.12em 0;
  margin-bottom: -0.12em;
  width: max-content;
}
.display-line > span,
.display-line > [data-reveal] {
  display: inline-block;
  transform: translateY(110%);
  transition: transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: var(--reveal-delay, 0s);
  will-change: transform;
}
.display-line > [data-reveal].is-in,
.display-line > span.is-in {
  transform: translateY(0);
}
/* (.display em + .portrait-frame rules live earlier in this file — duplicates removed) */

/* EMAIL copy link (left-bottom of hero).
   TWEAK font-size: third number caps the maximum. */
.email-copy {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: clamp(15px, 1.2vw, 18px);
  position: relative;
  padding: 6px 0;
  font-weight: 500;
}
.email-copy .email-text {
  border-bottom: 1px solid transparent;
  transition: border-color .3s ease;
}
.email-copy:hover .email-text { border-color: var(--ink); }
.email-copy .copy-icon,
.email-copy .check-icon {
  width: 16px; height: 16px;
  transition: opacity .25s ease, transform .25s ease;
}
.email-copy .check-icon {
  position: absolute; right: 0;
  opacity: 0; transform: scale(0.6);
}
.email-copy.is-copied .copy-icon { opacity: 0; transform: scale(0.6); }
.email-copy.is-copied .check-icon { opacity: 1; transform: scale(1); }

/* (.hero-intro p rule lives earlier in this file — duplicate removed) */

/* Reveal helpers */
[data-reveal-text] {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .9s var(--ease-out), transform .9s var(--ease-out);
}
[data-reveal-text].is-in {
  opacity: 1;
  transform: translateY(0);
}

/* Scroll cue — pinned to the bottom center */
.hero-scroll {
  position: absolute;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 4;
  display: flex; flex-direction: column;
  align-items: center; gap: 6px;
  font-size: 11px;
  color: var(--muted);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  animation: float 2.4s var(--ease-out) infinite;
}
.hero-scroll svg { width: 14px; height: 14px; }
@keyframes float {
  0%, 100% { transform: translate(-50%, 0); opacity: .7; }
  50%      { transform: translate(-50%, 6px); opacity: 1; }
}
@keyframes pulse {
  0% { box-shadow: 0 0 0 0 rgba(108, 209, 123, 0.5); }
  70% { box-shadow: 0 0 0 8px rgba(108, 209, 123, 0); }
  100% { box-shadow: 0 0 0 0 rgba(108, 209, 123, 0); }
}

/* =========================================================
   Section heads
========================================================= */
.section-head {
  padding: 24px var(--container);
  border-top: 1px solid var(--hairline);
}
.section-head--row {
  display: flex; align-items: center; justify-content: space-between;
}
.section-label {
  font-family: var(--body);
  font-weight: 500;
  font-size: 16px;
  letter-spacing: -0.01em;
}
.work-count {
  font-size: 13px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.show-more {
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 10px 22px;
  font-size: 14px;
  font-weight: 500;
  background: var(--bg);
  transition: background .3s ease, color .3s ease, border-color .3s ease, transform .35s var(--ease-out);
}
.show-more:hover {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
  transform: translateY(-2px);
}

/* =========================================================
   Work grid — Lune-style cards (grey → black on hover)
========================================================= */
.work {
  padding: 0 0 60px;
  position: relative;
  background: var(--bg);
}
.work-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 1.5vw, 24px);
  padding: 0 var(--container);
}

.project--more {
  display: none;
}
.work-grid.is-expanded .project--more {
  display: block;
  animation: fadeUp .7s var(--ease-out) both;
}
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(28px); }
  to { opacity: 1; transform: translateY(0); }
}

.work-more {
  display: flex;
  justify-content: center;
  padding: 40px var(--container) 0;
}

.project {
  display: block;
  position: relative;
  /* JS pushes a small tilt + offset via CSS variables when the cursor moves
     over the card; the transition keeps it smooth. */
  transform: perspective(900px)
             rotateX(var(--rx, 0deg))
             rotateY(var(--ry, 0deg))
             translate3d(var(--tx, 0px), var(--ty, 0px), 0);
  transition: transform .35s var(--ease-out);
  will-change: transform;
}

/* Image area — clipped square with the blur overlay layer */
.project-media {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--bg-2);
  isolation: isolate;
  transition: transform .8s var(--ease-out);
}
.project-media::after {
  content: '';
  position: absolute; inset: 0;
  z-index: 2;
  background: rgba(13, 13, 13, 0);
  backdrop-filter: blur(0px);
  -webkit-backdrop-filter: blur(0px);
  pointer-events: none;
  transition: backdrop-filter .55s var(--ease), -webkit-backdrop-filter .55s var(--ease), background .55s ease;
}
.project:hover .project-media::after {
  background: rgba(13, 13, 13, 0.35);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.project:hover .project-media { transform: scale(1.005); }

/* Floating category pill, top-right of the image */
.project-label {
  position: absolute;
  top: 14px; right: 14px;
  z-index: 4;
  padding: 5px 12px;
  background: rgba(244, 243, 240, 0.92);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--ink);
}

/* Hover overlay — description text + view CTA, fades up */
.project-overlay {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 24px;
  color: #fff;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .45s var(--ease-out) .05s, transform .55s var(--ease-out);
  pointer-events: none;
}
.project:hover .project-overlay {
  opacity: 1;
  transform: translateY(0);
}
.project-desc {
  font-family: var(--display);
  font-size: clamp(15px, 1.4vw, 18px);
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: -0.01em;
  margin-bottom: 18px;
  max-width: 92%;
}
.project-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 8px 16px;
  border: 1px solid rgba(255,255,255,0.4);
  border-radius: 999px;
  width: fit-content;
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.project-cta span { font-size: 14px; }
.project-overlay--dark { color: #fff; }
.project:hover .proj-art { transform: scale(1.06); }

.proj-art {
  position: absolute; inset: 0; z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 8%;
  text-align: center;
  font-family: var(--display);
  letter-spacing: -0.02em;
  overflow: hidden;
  transition: transform 1s var(--ease-out);
}
.project:hover .proj-art { transform: scale(1.06); }

/* ---------- Project artwork: IDE/code-window placeholder ----------
   Each card is styled like a code editor window. A small chrome bar with
   traffic-light dots + filename sits at the top, and lines of code type
   themselves out left-to-right (via clip-path + steps()) when the card
   enters the viewport (JS toggles .is-active). */

.proj-art--ide {
  background: #0e1117;
  color: #d9d9e3;
  padding: 0;
  align-items: stretch;
  justify-content: flex-start;
  font-family: ui-monospace, 'SF Mono', Menlo, Monaco, Consolas, monospace;
}

/* Window chrome */
.ide-chrome {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 16px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  background: rgba(255, 255, 255, 0.02);
  flex-shrink: 0;
}
.ide-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.ide-dot--r { background: #ff5f57; }
.ide-dot--y { background: #febc2e; }
.ide-dot--g { background: #28c840; }
.ide-tab {
  margin-left: 8px;
  font-size: 11px;
  color: rgba(255, 255, 255, 0.5);
  letter-spacing: 0.02em;
  text-transform: none;
  font-family: ui-monospace, monospace;
}

/* Code body */
.ide-code {
  margin: 0;
  padding: 18px 18px 22px;
  font-family: inherit;
  font-size: clamp(11px, 0.9vw, 13.5px);
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.78);
  white-space: pre;
  overflow: hidden;
  flex: 1;
  text-align: left;
}

/* Each line is clipped from the right by default; reveals on .is-active */
.code-line {
  display: block;
  clip-path: inset(0 100% 0 0);
  will-change: clip-path;
}
.proj-art--ide.is-active .code-line {
  animation: code-type 0.9s steps(28, end) forwards;
  /* Stagger lines using --i; base delay so the chrome reads first */
  animation-delay: calc(0.25s + var(--i, 0) * 0.55s);
}
@keyframes code-type {
  to { clip-path: inset(0 0 0 0); }
}

/* Syntax highlighting */
.c-kw  { color: #c084fc; }   /* keywords (import, const, return) */
.c-mod { color: #a8d4ff; }   /* modules / objects */
.c-str { color: #b8e986; }   /* strings */
.c-num { color: #f0a05a; }   /* numbers */
.c-fn  { color: #ffd866; }   /* functions */
.c-tag { color: #ff7b72; }   /* HTML tags */
.c-attr{ color: #f0a05a; }   /* HTML attributes */
.c-cm  { color: rgba(255,255,255,0.4); font-style: italic; } /* comments */

/* Blinking cursor at the end of typed text */
.c-cursor {
  display: inline-block;
  width: 7px;
  height: 1em;
  margin-left: 2px;
  vertical-align: text-bottom;
  background: var(--accent);
  animation: code-blink 0.9s steps(2) infinite;
}
@keyframes code-blink {
  50% { opacity: 0; }
}

/* Slight tonal shifts per project so the trio still feels distinct */
.proj-art--finance.proj-art--ide { background: #0e1117; }   /* default GitHub-dark */
.proj-art--property.proj-art--ide { background: #11141c; } /* slightly cooler */
.proj-art--wood.proj-art--ide    { background: #15110d; }   /* warm dark */

/* ---------- Card flip — physical-card style Y-axis flip on hover.
   Applied per-card via .project--flip so we can test on one project
   while the others keep the blur+description overlay treatment. */

.project--flip .project-media {
  perspective: 1400px;
}
/* Suppress the default blur+overlay for flip cards (we want the back face
   reveal to be the hover effect instead). */
.project--flip:hover .project-media::after { background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; }
.project--flip .project-overlay { display: none; }

.card-flip {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  /* TWEAK: change duration to make the flip faster (0.6s) or slower (1.2s) */
  transition: transform 0.85s cubic-bezier(0.65, 0, 0.35, 1);
  border-radius: inherit;
}
.project--flip:hover .card-flip {
  transform: rotateY(180deg);
}

.card-face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  border-radius: inherit;
  overflow: hidden;
}
.card-face--back {
  transform: rotateY(180deg);
  background: var(--bg-2);
}
.card-face--back img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Small label pill sitting on the back face so it doesn't read as a stock photo */
.card-back-pill {
  position: absolute;
  bottom: 14px; left: 14px;
  z-index: 2;
  padding: 6px 14px;
  background: rgba(13, 13, 13, 0.78);
  color: var(--dark-text);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ---------- Property card: animated line chart (buy vs rent) ----------
   Uses the same IDE chrome + dark background as the code cards so the
   trio reads as a series, but the body is an SVG chart with two paths
   that draw in left-to-right when the card enters the viewport. */

.proj-art--chart {
  background: #11141c;
  color: #d9d9e3;
  padding: 0;
  align-items: stretch;
  justify-content: flex-start;
  font-family: ui-monospace, 'SF Mono', Menlo, Monaco, Consolas, monospace;
}
.chart-body {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 28px 32px;
  min-height: 0;
}
.chart-svg {
  width: 100%;
  height: 100%;
  max-height: 280px;
  overflow: visible; /* let end labels & dots breathe */
}

/* Gridlines */
.chart-grid line {
  stroke: rgba(255, 255, 255, 0.06);
  stroke-width: 0.6;
  stroke-dasharray: 3 3;
}

/* Two animated lines: draw left-to-right by animating dash-offset */
.chart-line {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 420;
  stroke-dashoffset: 420;
}
.chart-line--buy  { stroke: var(--accent); filter: drop-shadow(0 0 6px rgba(158, 197, 254, 0.35)); }
.chart-line--rent { stroke: rgba(255, 255, 255, 0.5); stroke-dasharray: 6 4, 420; }

/* Soft glow area under the buy line — also reveals with the line */
.chart-area {
  fill: var(--accent);
  opacity: 0;
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform 2.4s var(--ease-out), opacity 0.6s ease;
}
.proj-art--chart.is-active .chart-area {
  transform: scaleX(1);
  opacity: 0.07;
  transition-delay: 0.5s;
}

/* Markers + labels appear after lines finish drawing */
.chart-cross,
.chart-dot,
.chart-label {
  opacity: 0;
  transition: opacity 0.6s ease 2.6s;
}
.chart-cross { fill: var(--accent); }
.chart-cross::after { content: ''; }
.chart-dot--buy   { fill: var(--accent); }
.chart-dot--rent  { fill: rgba(255, 255, 255, 0.7); }
.chart-label {
  font-family: var(--display);
  font-size: 11px;
  font-weight: 600;
  text-anchor: end;
  letter-spacing: 0.02em;
}
.chart-label--buy  { fill: var(--accent); }
.chart-label--rent { fill: rgba(255, 255, 255, 0.55); }

/* Trigger: when the card enters the viewport, draw both lines */
.proj-art--chart.is-active .chart-line {
  animation: chart-draw 2.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.proj-art--chart.is-active .chart-line--rent { animation-delay: 0.25s; }
.proj-art--chart.is-active .chart-line--buy  { animation-delay: 0.55s; }
.proj-art--chart.is-active .chart-cross,
.proj-art--chart.is-active .chart-dot,
.proj-art--chart.is-active .chart-label { opacity: 1; }

@keyframes chart-draw {
  to { stroke-dashoffset: 0; }
}

/* Soft pulse on the crossover marker after it appears */
.proj-art--chart.is-active .chart-cross {
  animation: cross-pulse 1.8s ease-in-out infinite;
  animation-delay: 3s;
}
@keyframes cross-pulse {
  0%, 100% { opacity: 0.6; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.18); }
}

/* Ghost / coming soon cards */
.proj-art--ghost {
  background: linear-gradient(160deg, #ecebe6 0%, #d8d6cf 100%);
  position: relative;
}
.proj-art--ghost::after {
  content: '';
  position: absolute; inset: 0;
  background: repeating-linear-gradient(135deg, transparent 0 16px, rgba(13, 13, 13, 0.04) 16px 17px);
}
.proj-art--ghost-2 {
  background: linear-gradient(160deg, #e6e9ec 0%, #c5cad0 100%);
}
.proj-art--ghost-3 {
  background: linear-gradient(160deg, #e8e4dd 0%, #d2cab9 100%);
}
.ghost-num {
  position: relative;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(80px, 12vw, 160px);
  letter-spacing: -0.05em;
  color: rgba(13, 13, 13, 0.12);
  z-index: 2;
}
.project--more .project-overlay {
  background: linear-gradient(180deg, rgba(13, 13, 13, 0.0) 0%, rgba(13, 13, 13, 0.55) 100%);
}

/* Title + arrow below the image */
.project-meta {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 4px 4px;
  font-size: 14px;
}
.project-title {
  font-weight: 500;
  letter-spacing: -0.01em;
}
.project-arrow {
  font-size: 14px;
  color: var(--muted);
  transition: transform .35s var(--ease-out), color .3s ease;
}
.project:hover .project-arrow {
  color: var(--ink);
  transform: translate(2px, -2px);
}

/* =========================================================
   Services hover section (alternating angle, grey-out style)
========================================================= */
.services {
  padding: 0 0 100px;
  position: relative;
}
.services-stage {
  position: relative;
  padding: 60px var(--container);
  min-height: 520px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.services-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  z-index: 2;
  position: relative;
  width: 100%;
}
.service-item {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(40px, 9vw, 130px);
  letter-spacing: -0.04em;
  line-height: 1.05;
  color: var(--ink);
  text-align: center;
  text-transform: uppercase;
  position: relative;
  cursor: none;
  transition: color .4s ease;
  font-style: italic;
}
.service-item span {
  display: inline-block;
}
.services-stage.is-hovering .service-item {
  color: var(--muted-2);
}
.services-stage.is-hovering .service-item.is-active {
  color: var(--ink);
}

/* The floating image card — sits ON TOP of the words (z-index 3).
   Angle is set per item by JS via --rot. */
.services-image {
  position: absolute;
  width: clamp(220px, 24vw, 340px);
  aspect-ratio: 5 / 6;
  pointer-events: none;
  z-index: 3;
  opacity: 0;
  --rot: -4deg;
  transform: translate(-50%, -50%) scale(0.92) rotate(var(--rot));
  transition: opacity .35s ease, transform .55s var(--ease-out);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(0,0,0,0.18);
  background: var(--bg-2);
}
.services-image.is-visible {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1) rotate(var(--rot));
}
.svc-art {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity .25s ease;
}
.svc-art.is-shown { opacity: 1; }
.svc-art svg { width: 100%; height: 100%; display: block; }

/* =========================================================
   About — sticky polaroid + scroll-reveal stack
========================================================= */
.about {
  padding: 0 0 120px;
  position: relative;
}
.about-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 80px;
  padding: 60px var(--container) 0;
  align-items: start;
}

.about-stack {
  display: flex;
  flex-direction: column;
  gap: clamp(60px, 12vh, 140px);
  max-width: 720px;
}
.about-block {
  position: relative;
  padding-left: 60px;
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 1s var(--ease-out), transform 1s var(--ease-out);
}
.about-block.is-in {
  opacity: 1;
  transform: translateY(0);
}
.about-num {
  position: absolute;
  left: 0; top: 6px;
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}
.about-block p {
  font-family: var(--display);
  font-size: clamp(22px, 2.6vw, 36px);
  line-height: 1.3;
  letter-spacing: -0.02em;
  font-weight: 500;
}
.about-block .about-lead {
  font-weight: 500;
}

.about-tags {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.about-tags li {
  display: inline-flex;
  align-items: center;
  padding: 8px 18px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  font-size: 14px;
  font-weight: 500;
  background: var(--bg);
  transition: background .3s ease, color .3s ease, transform .35s var(--ease-out);
}
.about-tags li:hover {
  background: var(--ink);
  color: var(--bg);
  transform: translateY(-2px);
}

/* Sticky polaroid that follows the scroll-reveal */
.about-photo {
  position: sticky;
  top: 22vh;
  align-self: start;
  display: flex;
  justify-content: center;
}
.polaroid {
  width: 100%;
  max-width: 340px;
  aspect-ratio: 4 / 5;
  background: var(--bg);
  border-radius: 10px;
  overflow: hidden;
  transform: rotate(3deg);
  box-shadow: 0 18px 40px rgba(0,0,0,0.08);
  transition: transform .7s var(--ease-out);
}
.polaroid:hover {
  transform: rotate(-6deg) scale(1.04);
}
.polaroid img {
  width: 100%; height: 100%;
  object-fit: cover;
}

/* =========================================================
   Contact — lavender pills + eye peek + minimal footer
========================================================= */
.contact {
  background: var(--dark);
  color: var(--dark-text);
  /* TWEAK: top / horizontal / bottom padding for the whole black section */
  padding: 36px var(--container) 28px;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  margin-top: 0;
  position: relative;
}

/* Eye-peek detail — top-right of contact, offset from the right edge so it
   doesn't sit under the fixed nav menu button. Pupils track the cursor via JS. */
.contact-eyes {
  position: absolute;
  top: 36px;
  right: clamp(80px, 8vw, 120px);
  display: flex;
  gap: 6px;
  z-index: 5;
}
.eye {
  width: clamp(28px, 3vw, 38px);
  height: clamp(28px, 3vw, 38px);
  background: #ffffff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
  box-shadow: 0 4px 12px rgba(0,0,0,0.25);
}
.eye-pupil {
  width: 38%;
  height: 38%;
  background: var(--dark);
  border-radius: 50%;
  transition: transform .12s linear;
}

.contact-main {
  /* TWEAK: padding-top is space below the eyes / above the headline.
     padding-bottom is space between the last button and the footer credits. */
  padding: 36px 0 76px;
  max-width: 1100px;
}
.contact-headline {
  font-family: var(--display);
  font-weight: 700;
  /* TWEAK: change the max value (the third number) to resize the "Sooooo, what's next?" text */
  font-size: clamp(40px, 7.6vw, 108px);
  line-height: 0.95;
  letter-spacing: -0.045em;
}
.contact-headline em {
  font-style: italic;
  font-weight: 500;
  color: rgba(244, 243, 240, 0.45);
}
.contact-headline .display-line { padding: 4px 0; }

.contact-cta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  /* TWEAK: gap between the buttons */
  gap: 8px;
  /* TWEAK: spacing between headline and the first button */
  margin-top: 22px;
}

.cta-pill {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  background: var(--accent);
  color: var(--accent-ink);
  /* TWEAK: button vertical / horizontal padding (button "thickness") */
  padding: 12px 22px;
  border-radius: 999px;
  font-family: var(--display);
  /* TWEAK: button label size */
  font-size: clamp(15px, 1.4vw, 19px);
  font-weight: 500;
  letter-spacing: -0.01em;
  transition: background .35s ease, color .3s ease;
  will-change: transform;
}
.cta-pill:hover {
  background: #ffffff;
  color: var(--dark);
}
.cta-pill .cta-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  background: rgba(255, 255, 255, 0.7);
  border-radius: 50%;
  font-size: 12px;
  font-weight: 600;
  font-style: italic;
  color: var(--dark);
}
.cta-pill--ghost {
  background: transparent;
  color: rgba(244, 243, 240, 0.55);
  border: 1px solid rgba(255,255,255,0.18);
}
.cta-pill--ghost .cta-icon {
  background: rgba(255,255,255,0.12);
  color: var(--dark-text);
}
.cta-pill--ghost:hover {
  background: rgba(255,255,255,0.1);
  color: var(--dark-text);
}

/* Footer (Ngan-style: name | credit | LinkedIn icon) */
.footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 18px;
  border-top: 1px solid rgba(255,255,255,0.08);
  margin-top: 0;
  font-size: 13px;
  color: var(--dark-muted);
}
.footer-left {
  font-family: var(--display);
  font-size: 18px;
  font-weight: 500;
  color: var(--dark-text);
}
.footer-mid {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  font-size: 12px;
}
.footer-right {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.footer-right a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: rgba(255,255,255,0.08);
  border-radius: 50%;
  font-size: 13px;
  font-weight: 600;
  font-style: italic;
  color: var(--dark-text);
  transition: background .3s ease;
}
.footer-right a:hover { background: rgba(255,255,255,0.18); }
/* GitHub icon variant: SVG instead of an italic letter, so reset the font-style. */
.footer-right .footer-icon { font-style: normal; }
.footer-right .footer-icon svg { width: 16px; height: 16px; }

/* Tilt hover — applied to elements with [data-tilt] (JS sets a small random base tilt) */
[data-tilt] {
  transition: transform .35s var(--ease-out), color .3s ease, background .3s ease;
}

/* =========================================================
   Toast
========================================================= */
.toast {
  position: fixed; bottom: 24px; left: 50%;
  transform: translate(-50%, 80px);
  background: var(--ink);
  color: var(--bg);
  padding: 12px 20px;
  border-radius: 999px;
  font-size: 13px;
  letter-spacing: 0.01em;
  z-index: 200;
  pointer-events: none;
  opacity: 0;
  transition: opacity .35s ease, transform .45s var(--ease-out);
}
.toast.is-show { opacity: 1; transform: translate(-50%, 0); }

/* =========================================================
   Responsive
========================================================= */
@media (max-width: 960px) {
  .hero { padding: 110px var(--container) 60px; }
  .hero-grid {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto auto;
    row-gap: 30px;
  }
  .hero-name { grid-column: 1; grid-row: 1; }
  .hero-portrait { grid-column: 1; grid-row: 2; justify-self: start; padding-top: 0; }
  .hero-intro { grid-column: 1; grid-row: 3; width: 100%; max-width: none; }
  .hero-email { grid-column: 1; grid-row: 4; padding-bottom: 0; }
  .display { font-size: clamp(56px, 18vw, 120px); }

  .work-grid { grid-template-columns: 1fr 1fr; }

  .about-grid { grid-template-columns: 1fr; gap: 30px; }
  .about-photo { position: static; padding-top: 12px; justify-content: flex-start; }
  .polaroid { max-width: 240px; }

  .services-stage { min-height: 380px; }
  .contact { padding: 24px 24px 24px; }
  .contact-eyes { top: 16px; }
  .contact-main { margin-top: -20px; }
  .footer { flex-direction: column; align-items: flex-start; gap: 16px; text-align: left; }
  .footer-mid { align-items: flex-start; }
}

@media (max-width: 600px) {
  :root { --container: 22px; }
  .nav { padding: 18px var(--container); }
  .hero { padding: 100px var(--container) 60px; }
  .display { font-size: clamp(50px, 17vw, 96px); letter-spacing: -0.04em; }
  .hero-intro p { font-size: 17px; text-align: left; }
  .hero-scroll { display: none; }
  .display { font-size: clamp(52px, 19vw, 110px); letter-spacing: -0.04em; }
  .work-grid { grid-template-columns: 1fr; }
  .about-block p { font-size: 22px; }
  .contact-headline { font-size: clamp(34px, 9.5vw, 56px); }
  .menu a { font-size: 38px; }
  .hero-scroll { display: none; }
  .services-stage { padding: 40px 0; min-height: auto; }
  .service-item { font-size: clamp(36px, 11vw, 56px); }
  .services-image { display: none; }
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
