/* ================================
   Phat Nguyen — Portfolio
   Recreated from the original Framer site
   ================================ */

@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../assets/fonts/montserrat-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../assets/fonts/montserrat-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../assets/fonts/montserrat-vietnamese.woff2') format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}

:root {
  /* Fixed palettes — the raw light/dark color values that everything else
     (including the theme-following and footer-contrast tokens below) is
     built from. */
  --bg-dark: #000000;
  --bg-light: #ffffff;
  --text-light: #ffffff;
  --text-dark: #111111;
  --text-dark-dim: #6b6b68;
  --pill-bg-onlight: #111111;
  --divider-dark: rgba(255,255,255,0.14);
  --divider-light: rgba(0,0,0,0.14);

  /* Theme-following tokens — everything else on the page reads these, and
     the light-theme block further down redefines them. Dark values here
     double as the fallback for browsers with no matching @media block and
     no explicit override, i.e. the current brand default. */
  --surface: var(--bg-dark);
  --on-surface: var(--text-light);
  --on-surface-dim: #5c5c5c;
  --on-surface-muted: #eaeaea;
  --divider: var(--divider-dark);
  /* --pill-bg/--pill-text are NOT theme-swapped — nothing renders them
     unmodified (nav-links pills override background to transparent and set
     their own color below; footer pills override background to
     --pill-bg-onlight). --pill-text still matters as the inherited text
     color for those footer pills though, which need to stay readable on
     their fixed-dark button background regardless of site theme, so it's
     pinned white rather than following the theme. */
  --pill-bg: #000000;
  --pill-text: #ffffff;
  --pill-bg-hover: #1a1a1a;
  --pill-outline-border: rgba(255,255,255,0.35);
  --pill-outline-border-hover: rgba(255,255,255,0.9);
  --overlay-rgb: 0 0 0;
  --hamburger-bg: #ffffff;
  --logo-invert: 0;
  /* Accent button (homepage "Get in touch") — deliberately inverted from
     the page so it pops regardless of theme: light button in dark theme,
     dark button in light theme. */
  --accent-bg: #ffffff;
  --accent-text: #000000;
  --accent-bg-hover: #ececec;
  /* Footer CTA is a deliberate contrast band, always the opposite of
     whatever the main theme currently is: light footer on a dark page,
     dark footer on a light page. */
  --footer-bg: var(--bg-light);
  --footer-text: var(--text-dark);
  --footer-text-dim: var(--text-dark-dim);
  --footer-pill-bg: var(--pill-bg-onlight);
  --footer-pill-text: #ffffff;

  --container: 1600px;
  --gutter: clamp(24px, 5vw, 64px);
  --ff: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

/* Light theme: applied when the OS prefers light and the user hasn't
   explicitly forced dark, OR when the toggle has explicitly set light —
   the second rule's higher specificity/later-wins order lets it override
   the system either way. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --surface: var(--bg-light);
    --on-surface: var(--text-dark);
    --on-surface-dim: var(--text-dark-dim);
    --on-surface-muted: #333333;
    --divider: var(--divider-light);
    --pill-outline-border: rgba(0,0,0,0.35);
    --pill-outline-border-hover: rgba(0,0,0,0.9);
    --overlay-rgb: 255 255 255;
    --hamburger-bg: #111111;
    --logo-invert: 1;
    --accent-bg: #000000;
    --accent-text: #ffffff;
    --accent-bg-hover: #1a1a1a;
    --footer-bg: var(--bg-dark);
    --footer-text: var(--text-light);
    --footer-text-dim: rgba(255,255,255,0.6);
    --footer-pill-bg: #ffffff;
    --footer-pill-text: #000000;
  }
}
:root[data-theme="light"] {
  --surface: var(--bg-light);
  --on-surface: var(--text-dark);
  --on-surface-dim: var(--text-dark-dim);
  --on-surface-muted: #333333;
  --divider: var(--divider-light);
  --pill-outline-border: rgba(0,0,0,0.35);
  --pill-outline-border-hover: rgba(0,0,0,0.9);
  --overlay-rgb: 255 255 255;
  --hamburger-bg: #111111;
  --logo-invert: 1;
  --accent-bg: #000000;
  --accent-text: #ffffff;
  --accent-bg-hover: #1a1a1a;
  --footer-bg: var(--bg-dark);
  --footer-text: var(--text-light);
  --footer-text-dim: rgba(255,255,255,0.6);
  --footer-pill-bg: #ffffff;
  --footer-pill-text: #000000;
}

/* ---------- ASCII decor (hero / footer brand mark) ---------- */
.ascii-decor {
  position: relative;
  width: 100%;
  height: 100%;
  --mx: 50%;
  --my: 50%;
}
.ascii-decor-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.ascii-decor-svg > g {
  opacity: 0.45;
}
.ascii-decor-crisp-shape {
  opacity: 0.55;
}
.ascii-decor-highlight-shape {
  opacity: 0;
  transition: opacity 0.5s ease;
  -webkit-mask-image: radial-gradient(160px circle at var(--mx) var(--my), #000 0%, transparent 72%);
  mask-image: radial-gradient(160px circle at var(--mx) var(--my), #000 0%, transparent 72%);
}
.ascii-decor.is-active .ascii-decor-highlight-shape {
  opacity: 1;
}
/* Cursor-reactive highlight is a hover affordance — skip rendering it below
   desktop widths so touch devices don't pay for the mask/opacity repaint. */
@media (max-width: 899px) {
  .ascii-decor-highlight-shape { display: none; }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--ff);
  background: var(--surface);
  color: var(--on-surface);
  transition: background 0.25s ease, color 0.25s ease;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }

.wrap {
  max-width: var(--container);
  margin: 0 auto;
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}
/* A `.wrap` that's a direct flex child (e.g. inside `.hero`) would otherwise
   shrink to fit its content instead of filling/centering — auto margins on a
   flex item take priority over stretch alignment, per spec. */
.hero > .wrap {
  width: 100%;
}

/* ---------- Nav ---------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  height: 80px;
  padding: 10px 0;
  box-sizing: border-box;
  background: linear-gradient(to bottom, rgb(var(--overlay-rgb) / 0.9), rgb(var(--overlay-rgb) / 0));
  /* height/padding both animate (rather than one snapping and the other
     easing) so the bar shrinks as one smooth motion instead of visibly
     stuttering. backdrop-filter is deliberately NOT in this list — Chrome
     and Safari can't animate blur() cheaply, so transitioning it caused
     that stutter; it now flips on/off instantly alongside the (still
     animated, and cheap) background-color fade. */
  transition: background 0.3s ease, height 0.3s ease, padding 0.3s ease;
}
.nav.is-scrolled {
  height: 48px;
  padding: 6px 0;
  background: rgb(var(--overlay-rgb) / 0.9);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.nav-inner {
  height: 100%;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.nav-right {
  display: flex;
  align-items: center;
  gap: 6px;
}
.nav--light {
  background: none;
}
.logo {
  position: relative;
  display: inline-block;
  width: 110px;
  height: 47px;
  transition: width 0.3s ease, height 0.3s ease;
}
.logo-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: left center;
  /* Both logo SVGs are solid white fills — inverting flips them to black
     for light theme instead of needing a second pair of dark-colored
     assets to keep in sync with the white ones. */
  filter: invert(var(--logo-invert));
  transition: opacity 0.3s ease, filter 0.25s ease;
}
.logo-img-compact {
  opacity: 0;
}
.nav.is-scrolled .logo {
  width: 32px;
  height: 34px;
}
.nav.is-scrolled .logo-img-full {
  opacity: 0;
}
.nav.is-scrolled .logo-img-compact {
  opacity: 1;
}
@media (max-width: 899px) {
  .logo { width: 55px; height: 23.5px; }
  .nav.is-scrolled .logo { width: 25px; height: 26px; }
  /* nav-links collapses out of flow behind the hamburger here, so
     nav-right's only visible flex children are the theme icon and the
     hamburger. The icon's own scale(1.105) grows it ~3px past its box on
     each side without taking any extra layout space, and the desktop gap
     (6px, deliberately tight so the icon sits close to the LinkedIn pill)
     leaves barely 3px of real clearance once that overflow eats into it —
     enough to visually crowd the hamburger. Widen the gap here only. */
  .nav-right { gap: 16px; }
}
.nav-links {
  display: flex;
  gap: 10px;
}
.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 30px;
  padding: 10px 20px;
  border-radius: 60px;
  background: var(--pill-bg);
  color: var(--pill-text);
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: normal;
  text-transform: uppercase;
  border: none;
  transition: transform .25s ease, background .25s ease;
}
.pill:hover { transform: translateY(-2px); background: var(--pill-bg-hover); }
.nav--onlight .pill { border-color: rgba(0,0,0,0.1); }

.nav-links .pill {
  background: transparent;
  color: var(--on-surface);
  border: 1px solid var(--pill-outline-border);
}
.nav-links .pill:hover {
  background: transparent;
  border-color: var(--pill-outline-border-hover);
}

.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  padding: 0;
  background: none;
  border: none;
  color: var(--on-surface);
  cursor: pointer;
}
/* Animated sun/moon SVG (assets/theme-icon.svg), inlined so JS can drive
   its native SMIL timeline directly and CSS can recolor it. The source
   only uses one color throughout (a warm yellow) — overridden here to
   follow the theme instead, via attribute selectors on that literal
   color, since the inline paths don't use currentColor themselves. */
/* Scaled up visually (not sized up) so the nav's own height stays fixed
   at its usual budget instead of growing to fit a taller layout box. */
.theme-icon { display: block; width: 60px; height: 60px; transform: scale(1.105); }
.theme-icon svg { display: block; width: 100%; height: 100%; }
.theme-icon svg [fill="#ffd15f"] { fill: var(--on-surface); transition: fill 0.25s ease; }
.theme-icon svg [stroke="#ffd15f"] { stroke: var(--on-surface); transition: stroke 0.25s ease; }

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 32px;
  height: 32px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  width: 100%;
  height: 1.5px;
  background: var(--hamburger-bg);
  transition: transform 0.3s ease, opacity 0.3s ease, background 0.25s ease;
}

/* On mobile the pill row collapses into a hamburger that reveals the
   links as a dropdown, instead of three pills crowding the shrunk logo. */
@media (max-width: 899px) {
  .nav-toggle { display: flex; }
  .nav-links {
    position: absolute;
    top: calc(100% + 12px);
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    padding: 14px;
    border-radius: 16px;
    background: rgb(var(--overlay-rgb) / 0.85);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s;
  }
  .nav-links .pill {
    justify-content: flex-start;
    height: 40px;
  }
  .nav.is-open .nav-links {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
  }
  .nav.is-open .nav-toggle span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
  .nav.is-open .nav-toggle span:nth-child(2) { opacity: 0; }
  .nav.is-open .nav-toggle span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }
}
@media (prefers-reduced-motion: reduce) {
  .nav-links, .nav-toggle span { transition: none; }
}

/* ---------- Home page: fit everything in one viewport ---------- */
html.page-home {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
body.page-home {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
body.page-home .nav { flex: 0 0 auto; }
body.page-home .hero { flex: 1 1 auto; min-height: 0; }
body.page-home .marquee { flex: 0 0 auto; }

@media (max-width: 899px) {
  body.page-home .marquee { padding-bottom: 24px; }
  body.page-home .hero-decor {
    width: min(105vw, 490px);
    right: -30%;
    top: 28%;
  }
}

/* ---------- Hero (home) ---------- */
.hero {
  position: relative;
  min-height: 92vh;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding-top: 40px;
  padding-bottom: 60px;
  overflow: visible;
}
.hero-inner {
  position: relative;
  z-index: 2;
  max-width: 720px;
}
@keyframes fade-up {
  from { opacity: 0; transform: translateY(24px); }
  to { opacity: 1; transform: translateY(0); }
}
.hero h1 {
  max-width: 550px;
  width: 100%;
  font-size: clamp(30px, 7vw, 42px);
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 1.15;
  margin: 0 0 28px;
  animation: fade-up 0.8s cubic-bezier(.16,1,.3,1) both;
}
.contact-link {
  animation: fade-up 0.8s cubic-bezier(.16,1,.3,1) both;
  animation-delay: 0.15s;
}
.marquee {
  animation: fade-up 0.8s cubic-bezier(.16,1,.3,1) both;
  animation-delay: 0.3s;
}
@media (prefers-reduced-motion: reduce) {
  .hero h1, .contact-link, .marquee, .case-hero .case-name { animation: none; }
}
.hero h1 .dim { color: var(--on-surface-dim); }
.hero h1 .bright { color: var(--on-surface); }
.hero h1 .accent-line {
  text-decoration: none;
}

.hero-decor {
  position: absolute;
  right: -8%;
  top: -5%;
  width: min(42vw, 630px);
  aspect-ratio: 1 / 1;
  z-index: 0;
  pointer-events: none;
  overflow: visible;
}

.contact-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 30px;
  padding: 10px 20px;
  border-radius: 70px;
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: normal;
  text-transform: uppercase;
  background: var(--accent-bg);
  color: var(--accent-text);
  width: fit-content;
  transition: transform 0.25s ease, background 0.25s ease;
}
.contact-link:hover { transform: translateY(-2px); background: var(--accent-bg-hover); }

/* ---------- Marquee (home work strip) ---------- */
.marquee {
  position: relative;
  width: 100%;
  overflow: hidden;
  padding: 46px 0 10px;
  -webkit-mask-image: linear-gradient(to right, transparent, black 4%, black 96%, transparent);
  mask-image: linear-gradient(to right, transparent, black 4%, black 96%, transparent);
}
.marquee-track {
  display: flex;
  gap: 8px;
  width: max-content;
  will-change: transform;
}
.marquee-item {
  position: relative;
  width: 320px;
  flex: 0 0 auto;
}
.marquee-item img {
  width: 320px;
  height: 230px;
  object-fit: cover;
  border-radius: 4px;
  filter: saturate(0.9) contrast(1.02);
  transition: filter .3s ease;
}
.marquee-item:hover img { filter: saturate(1.05) contrast(1.05); }
.marquee-view {
  position: absolute;
  left: 50%;
  top: calc(50% + 5px);
  transform: translate(-50%, -50%);
  height: 30px;
  padding: 10px 20px;
  border-radius: 999px;
  background: rgba(40,34,30,0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: #fff;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: normal;
  opacity: 0;
  transition: opacity .25s ease;
  pointer-events: none;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.marquee-item:hover .marquee-view { opacity: 1; }
.marquee-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--on-surface-dim);
  margin-bottom: 8px;
  display: block;
}

/* ---------- Works grid ---------- */
.works-section {
  padding: 120px 0 100px;
}
.works-heading {
  font-size: clamp(28px, 4vw, 44px);
  font-weight: 500;
  letter-spacing: -0.02em;
  margin: 0 0 56px;
}

/* ---------- About page ---------- */
.about-hero {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 48px;
}
.about-hero-text { flex: 1 1 auto; min-width: 0; }
.about-photo {
  flex: 0 0 auto;
  width: 220px;
  aspect-ratio: 3/4;
  object-fit: cover;
  border-radius: 16px;
}
@media (max-width: 899px) {
  .about-hero { flex-direction: column-reverse; gap: 28px; }
  .about-photo { width: 100%; max-width: 260px; }
}
.about-intro { max-width: 720px; margin-top: -24px; }
.about-intro p {
  font-size: 18px;
  line-height: 1.6;
  color: var(--on-surface-muted);
  margin: 0;
}
@media (max-width: 899px) {
  .about-intro p { font-size: 16px; }
}
.about-exp-list div {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.about-exp-role {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--on-surface);
}
.about-exp-meta {
  font-size: 13px;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--on-surface-dim);
}
.works-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}
.work-card { display: block; }
.work-card figure {
  margin: 0 0 14px;
  overflow: hidden;
  border-radius: 4px;
  aspect-ratio: 4/5;
}
.work-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s cubic-bezier(.2,.7,.2,1);
}
.work-card:hover img { transform: scale(1.045); }
.work-card .label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--on-surface-dim);
}

@media (max-width: 900px) {
  .works-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .works-grid { grid-template-columns: 1fr; }
}

/* ---------- Case study hero ---------- */
.case-hero {
  position: relative;
  height: 88vh;
  min-height: 520px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
@media (max-width: 899px) {
  .case-hero {
    height: 50vh;
    height: 50dvh;
    min-height: 360px;
  }
}
.case-hero img.bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: brightness(0.62);
}
.case-hero-inner {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 40px;
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 40px;
}
.case-hero .case-name {
  grid-column: 2;
  max-width: 680px;
  justify-self: end;
  width: 100%;
  font-size: 36px;
  font-weight: 600;
  text-align: left;
  color: #fff;
  animation: fade-up 0.8s cubic-bezier(.16,1,.3,1) both;
}
@media (max-width: 760px) {
  .case-hero-inner { grid-template-columns: 1fr; }
  .case-hero .case-name { grid-column: 1; justify-self: start; }
}

/* ---------- Case study content ---------- */
.case-section {
  padding: 90px 0;
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 40px;
  border-bottom: 1px solid var(--divider);
}
.case-section .label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--on-surface-dim);
}
.case-section .content {
  max-width: 680px;
  justify-self: end;
  text-align: left;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.6s cubic-bezier(.16,1,.3,1), transform 0.6s cubic-bezier(.16,1,.3,1);
}
.case-section .content.in-view { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .case-section .content { opacity: 1; transform: none; transition: none; }
}
.case-section .content p {
  font-size: 18px;
  line-height: 1.55;
  font-weight: 400;
  color: var(--on-surface-muted);
  margin: 0 0 20px;
}
@media (max-width: 899px) {
  .case-section .content p { font-size: 16px; }
}
.case-section .content p:last-child { margin-bottom: 0; }
.case-section .content.challenge-list {
  margin: 0;
  padding-left: 0;
  list-style: none;
}
.case-section .content.challenge-list li {
  font-size: 18px;
  line-height: 1.55;
  font-weight: 400;
  color: var(--on-surface-muted);
  margin: 0 0 12px;
}
@media (max-width: 899px) {
  .case-section .content.challenge-list li { font-size: 16px; }
}
.case-section .content.challenge-list li:last-child { margin-bottom: 0; }

.deliverables-list { max-width: 680px; justify-self: end; width: 100%; }
.deliverables-list div {
  padding: 18px 0;
  border-bottom: 1px solid var(--divider);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}
.deliverables-list div:last-child { border-bottom: none; }
.deliverables-list div {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.5s cubic-bezier(.16,1,.3,1), transform 0.5s cubic-bezier(.16,1,.3,1);
}
.deliverables-list.in-view div { opacity: 1; transform: translateY(0); }
.deliverables-list.in-view div:nth-child(1) { transition-delay: 0s; }
.deliverables-list.in-view div:nth-child(2) { transition-delay: .08s; }
.deliverables-list.in-view div:nth-child(3) { transition-delay: .16s; }
.deliverables-list.in-view div:nth-child(4) { transition-delay: .24s; }
.deliverables-list.in-view div:nth-child(5) { transition-delay: .32s; }
@media (prefers-reduced-motion: reduce) {
  .deliverables-list div { opacity: 1; transform: none; transition: none; }
}

@media (max-width: 760px) {
  .case-section { grid-template-columns: 1fr; }
  .case-section .content, .deliverables-list { justify-self: start; }
}

/* ---------- Case study gallery: static masonry grid ---------- */
.case-gallery { padding: 20px 0 80px; }
.case-gallery-grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.case-gallery-squares {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
.case-gallery-squares img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 4px;
  display: block;
}
.case-gallery-long img {
  width: 100%;
  aspect-ratio: 1440 / 800;
  object-fit: cover;
  border-radius: 4px;
  display: block;
}
@media (max-width: 700px) {
  .case-gallery-squares { grid-template-columns: 1fr; }
}

/* ---------- Case study gallery: auto-scrolling carousel near the
   footer, same continuous-offset approach as the homepage marquee ---------- */
.gallery-carousel {
  position: relative;
  width: 100%;
  overflow: hidden;
  padding: 20px 0 80px;
  -webkit-mask-image: linear-gradient(to right, transparent, black 4%, black 96%, transparent);
  mask-image: linear-gradient(to right, transparent, black 4%, black 96%, transparent);
}
.gallery-track {
  display: flex;
  gap: 16px;
  width: max-content;
  will-change: transform;
}
.gallery-item {
  position: relative;
  width: 500px;
  flex: 0 0 auto;
}
.gallery-tilt {
  border-radius: 4px;
  overflow: hidden;
  transition: transform 0.4s ease;
  will-change: transform;
}
.gallery-img {
  width: 500px;
  height: 270px;
  object-fit: cover;
  display: block;
  pointer-events: none;
}

/* ---------- Footer CTA ---------- */
.footer-cta {
  position: relative;
  background: var(--footer-bg);
  color: var(--footer-text);
  padding: 140px 0 90px;
  overflow: hidden;
  transition: background 0.25s ease, color 0.25s ease;
}
.footer-decor {
  position: absolute;
  right: -8%;
  top: 0;
  width: min(50vw, 680px);
  aspect-ratio: 1 / 1;
  pointer-events: none;
  overflow: hidden;
}
@media (max-width: 899px) {
  .footer-cta { padding: 80px 0; }
  .footer-decor {
    top: auto;
    bottom: 0;
    right: -8%;
    /* Capped in absolute px, not just vw — footer-cta's own height barely
       grows across this range (content reflows to fewer/wider rows as it
       goes), so a purely viewport-relative size overshoots the section's
       actual height around tablet widths and gets clipped by its
       overflow:hidden, reading as a wall of texture instead of a corner
       accent. */
    width: min(65vw, 280px);
  }
}
.footer-inner {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 48px;
}
.footer-cta h2 {
  font-size: clamp(28px, 4.4vw, 46px);
  font-weight: 500;
  letter-spacing: -0.02em;
  text-align: center;
  margin: 0;
  width: 100%;
}
.footer-links {
  display: flex;
  gap: 64px;
  flex-wrap: wrap;
  justify-content: center;
}
.footer-link-group {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.footer-link-group .label {
  display: block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--footer-text-dim);
  margin-bottom: 14px;
}
.footer-link-group .pill {
  width: 120px;
  height: 30px;
  padding: 10px 20px;
  border-radius: 70px;
  background: var(--footer-pill-bg);
  color: var(--footer-pill-text);
  border-color: transparent;
}

.next-work {
  background: var(--surface);
  color: var(--on-surface);
  padding: 110px var(--gutter) 130px;
  text-align: center;
  border-top: 1px solid var(--divider);
  opacity: 0;
  transform: translateY(40px) scale(0.9);
  transition: opacity 0.7s cubic-bezier(.16,1,.3,1), transform 0.7s cubic-bezier(.16,1,.3,1);
}
.next-work.in-view {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.next-work-label {
  font-size: 20px;
  font-weight: 500;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  margin: 0 0 40px;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.6s cubic-bezier(.16,1,.3,1), transform 0.6s cubic-bezier(.16,1,.3,1);
}
.next-work-label.in-view { opacity: 1; transform: translateY(0); }
.next-work-block {
  max-width: 560px;
  margin: 0 auto;
  text-align: left;
  perspective: 1200px;
}
.next-work-name {
  display: block;
  text-align: center;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--on-surface-dim);
  margin-bottom: 16px;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.6s cubic-bezier(.16,1,.3,1) 0.1s, transform 0.6s cubic-bezier(.16,1,.3,1) 0.1s;
}
.next-work-name.in-view { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .next-work, .next-work-label, .next-work-name { opacity: 1; transform: none; transition: none; }
}
/* .next-work-link stays flat and untransformed on purpose — it's the
   hover hit box. Tilting it directly (previous attempt) meant its own
   hit-test region rotated in 3D too, so at steep angles the rendered
   card foreshortened away from the cursor, firing mouseleave, snapping
   back flat, firing mouseenter again, and so on — a jitter loop worst at
   the edges where the tilt is steepest. The actual rotation now lives on
   the .next-work-tilt child instead, which has no bearing on hit-testing
   for its stable parent. */
.next-work-link {
  display: block;
}
.next-work-tilt {
  border-radius: 4px;
  overflow: hidden;
  transition: transform 0.4s ease;
  will-change: transform;
}
.next-work-img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  opacity: 0;
  transform-origin: bottom;
  transform: rotateX(-80deg);
  pointer-events: none;
}
.next-work-img.in-view {
  animation: next-work-flip 1s cubic-bezier(.16,1,.3,1) both;
}
@keyframes next-work-flip {
  from { opacity: 0; transform: rotateX(-80deg); }
  to { opacity: 1; transform: rotateX(0deg); }
}
@media (prefers-reduced-motion: reduce) {
  .next-work-img { opacity: 1; transform: none; }
  .next-work-img.in-view { animation: none; }
}

@media (max-width: 560px) {
  .footer-links { gap: 32px; }
}

/* ---------- Cross-document page transitions ----------
   Makes navigating between pages (e.g. the Next Work link) feel like
   scrolling further down one continuous page instead of a hard page swap.
   Native browser feature (Chrome/Edge 126+); unsupported browsers just do a
   normal instant navigation, no JS fallback needed. */
@view-transition {
  navigation: auto;
}
::view-transition-group(root) {
  animation-duration: 0.6s;
  animation-timing-function: cubic-bezier(.4, 0, .2, 1);
}
::view-transition-old(root) {
  animation-name: page-scroll-out;
}
::view-transition-new(root) {
  animation-name: page-scroll-in;
}
@keyframes page-scroll-out {
  to { transform: translateY(-100%); }
}
@keyframes page-scroll-in {
  from { transform: translateY(100%); }
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(root) { animation: none; }
}
