/* ==========================================================================
   Yuqian Sun — portfolio framework
   Black, minimal, cinematic. Reusable classes for header/nav, homepage
   showreel + project cards, and project-detail media layouts.
   ========================================================================== */

/* ---- Reset ---- */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
img, video { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; margin: 0; padding: 0; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
h1, h2, h3, h4, p { margin: 0; }

/* ---- Design tokens ---- */
:root {
  --bg: #000000;
  --fg: #ffffff;
  --fg-dim: rgba(255, 255, 255, 0.62);
  --fg-faint: rgba(255, 255, 255, 0.34);
  --border: rgba(255, 255, 255, 0.14);
  --border-soft: rgba(255, 255, 255, 0.08);
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --gutter: clamp(20px, 5vw, 64px);
  --nav-h: 84px;
  --font: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
}

html { background: var(--bg); }

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

.eyebrow {
  display: block;
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg-faint);
}

/* ==========================================================================
   Header / Navigation
   ========================================================================== */

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  background: linear-gradient(to bottom, rgba(0,0,0,0.55), rgba(0,0,0,0));
  transition: background 0.4s var(--ease), backdrop-filter 0.4s var(--ease);
}

.site-header.is-scrolled {
  background: rgba(0, 0, 0, 0.82);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border-soft);
}

.header-inner {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--gutter);
}

.logo { display: inline-flex; align-items: center; gap: clamp(4px, 0.7vw, 9px); }
.logo-img { height: clamp(19px, 2.1vw, 24px); width: auto; }
.logo-mark { height: clamp(34px, 4vw, 46px); width: auto; object-fit: contain; }

.main-nav ul { display: flex; gap: clamp(20px, 3vw, 40px); }

.nav-link {
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-dim);
  position: relative;
  padding: 6px 0;
  transition: color 0.3s var(--ease);
}
.nav-link:hover, .nav-link.is-active { color: var(--fg); }
.nav-link::after {
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: 0;
  height: 1px;
  background: var(--fg);
  transition: right 0.35s var(--ease);
}
.nav-link:hover::after, .nav-link.is-active::after { right: 0; }

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 32px;
  height: 32px;
  z-index: 110;
}
.nav-toggle span {
  display: block;
  width: 100%;
  height: 1px;
  background: var(--fg);
  transition: transform 0.3s var(--ease), opacity 0.3s var(--ease);
}
.nav-open .nav-toggle span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-open .nav-toggle span:nth-child(2) { opacity: 0; }
.nav-open .nav-toggle span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

@media (max-width: 720px) {
  .nav-toggle { display: flex; }
  .main-nav {
    position: fixed;
    inset: 0;
    background: #000;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.4s var(--ease);
  }
  .nav-open .main-nav { opacity: 1; visibility: visible; }
  .main-nav ul { flex-direction: column; align-items: center; gap: 28px; }
  .main-nav .nav-link { font-size: 20px; letter-spacing: 0.1em; }
}

/* ==========================================================================
   Showreel (homepage hero)
   Centered, letterboxed at its native cinematic ratio — never cropped or
   stretched. The frame's width is capped by viewport width, viewport
   height, and an absolute max, so it always lands with black space
   around it instead of forcing a fixed aspect box that could crop.
   ========================================================================== */

.showreel {
  position: relative;
  width: 100%;
  min-height: 100vh;
  background: #000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(16px, 3vh, 28px);
  padding: calc(var(--nav-h) + clamp(24px, 5vh, 56px)) var(--gutter) clamp(40px, 8vh, 96px);
}

.showreel-frame {
  position: relative;
  width: min(90vw, 76vh * 2.35, 1700px);
  aspect-ratio: 2.35 / 1;
  background: #000;
}

.showreel-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}

.showreel-label {
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
  text-align: center;
}

/* ==========================================================================
   Section shell
   ========================================================================== */

.section {
  padding: clamp(64px, 10vw, 140px) var(--gutter);
}

.section-heading {
  margin-bottom: clamp(32px, 6vw, 64px);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
}

.section-heading h2 {
  font-size: clamp(22px, 2.4vw, 30px);
  font-weight: 500;
  letter-spacing: 0.02em;
}

/* ==========================================================================
   Work / Project cards
   ========================================================================== */

.project-list {
  display: flex;
  flex-direction: column;
  gap: clamp(56px, 9vw, 120px);
}

.project-card-link { display: block; width: 80%; margin: 0 auto; }

.project-media {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #0a0a0a;
}

/* Modifier: use when a project's real cover/hover media has a 1.85:1
   composition (e.g. Cosmic Blue) — keeps the container matched to the
   source ratio so object-fit: cover never has to crop. */
.project-media.ratio-185 {
  aspect-ratio: 1.85 / 1;
}

.project-cover,
.project-hover-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity 0.6s var(--ease), transform 0.8s var(--ease);
}

.project-hover-video {
  opacity: 0;
}

.project-media:hover .project-cover {
  transform: scale(1.03);
}

.project-media.is-hovering .project-hover-video {
  opacity: 1;
}
.project-media.is-hovering .project-cover {
  opacity: 0;
}

/* if no hover video source is available, keep the still image showing */
.project-media.no-video .project-hover-video { display: none; }

.project-info {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-top: 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--border-soft);
}

.project-title {
  font-size: clamp(20px, 2.6vw, 30px);
  font-weight: 500;
  letter-spacing: 0.01em;
  transition: opacity 0.3s var(--ease);
}

.project-card-link:hover .project-title { opacity: 0.7; }

.project-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-faint);
  white-space: nowrap;
}

/* ==========================================================================
   Reveal-on-scroll (subtle, restrained)
   ========================================================================== */

.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}
.reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* ==========================================================================
   Project detail — reusable media layout classes
   ========================================================================== */

.project-hero {
  position: relative;
  padding-top: 0;
}

.project-hero-media {
  width: 100%;
  aspect-ratio: 16 / 8;
  max-height: 92vh;
  overflow: hidden;
  background: #050505;
}
.project-hero-media img,
.project-hero-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Full user-controlled film player — centered and letterboxed at its
   native ratio (object-fit: contain), unlike .project-hero-media above
   which is an edge-to-edge cropped ambient loop. Use this variant when
   a project links to a real, playable cut rather than a background clip. */
.film-player {
  background: #000;
  padding: calc(var(--nav-h) + clamp(24px, 5vh, 56px) + 50px) var(--gutter) clamp(40px, 8vh, 80px);
  display: flex;
  justify-content: center;
}

.film-player-frame {
  position: relative;
  width: min(100%, 127.512vh * 2.35, 2911px);
  aspect-ratio: 2.35 / 1;
  background: #000;
}

.film-player-frame video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}

.media {
  margin: clamp(56px, 9vw, 120px) 0;
}

.media img, .media video { width: 100%; height: 100%; object-fit: cover; }
.media figcaption {
  margin-top: 14px;
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--fg-faint);
}

/* Full-width cinematic media */
.media-full {
  padding: 0;
}
.media-full .media-frame { width: 100%; aspect-ratio: 16 / 8; }
.media-full figcaption { padding: 0 var(--gutter); }

/* Very wide horizontal media */
.media-wide {
  padding: 0 var(--gutter);
}
.media-wide .media-frame { width: 100%; aspect-ratio: 21 / 8; }

/* Full-width single image/video at its own natural aspect ratio — no
   forced container ratio, so it's never cropped or letterboxed
   regardless of the source's proportions (e.g. "Style Reference"). */
.media-natural {
  padding: 0 var(--gutter);
}
.media-natural img,
.media-natural video {
  max-width: 100%;
  height: auto;
  display: block;
  margin: 0 auto;
}

/* Vertical stack of full-width media, one per row, each at its own
   natural aspect ratio — no grid, no carousel, just scroll. E.g. a
   closing sequence of video shots. */
.media-stack {
  padding: 0 var(--gutter);
  display: flex;
  flex-direction: column;
  gap: clamp(28px, 5vw, 64px);
}
.media-stack video,
.media-stack img {
  width: 90%;
  height: auto;
  display: block;
  margin: 0 auto;
}

/* Two images at their own natural aspect ratios, matched by height
   rather than forced into identical boxes — e.g. an "Inspiration" pair
   with different source dimensions. Centered as a group so there's
   generous black space around them; add .scale-lg to one image to make
   it read as modestly larger (12.5% taller) than the other. Stacks on
   mobile. */
.media-duo {
  padding: 0 var(--gutter);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: clamp(24px, 4vw, 56px);
}
.media-duo img,
.media-duo video {
  width: auto;
  height: clamp(180px, 22vw, 360px);
  display: block;
}
.media-duo .scale-lg {
  height: clamp(202.5px, 24.75vw, 405px);
}
@media (max-width: 720px) {
  .media-duo { flex-direction: column; }
  .media-duo img,
  .media-duo video,
  .media-duo .scale-lg {
    height: auto;
    width: 100%;
    max-width: 420px;
  }
}

/* Two-column grid of large horizontal media — e.g. a "Concept Images"
   set, 2-up per row. Each frame is locked to its stated ratio and uses
   object-fit: contain so a source that isn't pixel-exact still shows
   uncropped, unstretched, letterboxed if needed. Collapses to one
   column on mobile. */
.media-grid {
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(20px, 3vw, 40px);
}
.media-grid .media-frame { aspect-ratio: 2 / 1; }
.media-grid .media-frame img,
.media-grid .media-frame video {
  object-fit: contain;
}
@media (max-width: 720px) {
  .media-grid { grid-template-columns: 1fr; }
}

/* Modifier: use when a grid's real media doesn't match the default
   .media-grid ratio (2:1, matched to the uploaded Concept Images
   files). Scene Design's uploaded files are natively 2912x1382
   (~2.11:1) — matching that exactly means object-fit: contain never
   has to letterbox, so there are no gray side bars. Everything else
   (columns, gap, padding, contain-fit) is inherited from .media-grid
   unchanged. */
.media-grid.ratio-scene .media-frame { aspect-ratio: 2912 / 1382; }

/* Modifier: removes .media-frame's fixed-box behavior entirely so each
   item renders at its own natural size instead — no forced aspect
   ratio, no object-fit, no background showing through. Use when a
   grid's sources have slightly different ratios and the goal is for
   each image to just fill its column width naturally (e.g.
   "Live / Jamming") rather than share one box. */
.media-grid.natural-fit {
  align-items: start;
}
.media-grid.natural-fit .media-frame {
  position: static;
  aspect-ratio: auto;
  overflow: visible;
  background: none;
}
.media-grid.natural-fit .media-frame img,
.media-grid.natural-fit .media-frame video {
  position: static;
  width: 100%;
  height: auto;
  object-fit: initial;
}

/* Two-column grid of wide, cropped media — e.g. a "Character Design" set
   mixing stills and a looping clip. Unlike .media-grid (contain, never
   crops), this relies on .media-frame's own default object-fit: cover
   so every item — image or video — shares one wide ratio and a
   sensible centered crop when a source doesn't match it exactly. */
.character-grid {
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(20px, 3vw, 40px);
}
.character-grid .media-frame { aspect-ratio: 16 / 9; }
@media (max-width: 720px) {
  .character-grid { grid-template-columns: 1fr; }
}

/* Trims a small, uniform margin off every edge of an item (mostly read
   as top/bottom at this ratio) to clip OS chrome — title bar, taskbar —
   visible in a full-screen capture. A uniform scale keeps the content
   itself undistorted; overflow: hidden on .media-frame does the actual
   clipping. Applied per-item (not to the whole grid) so a source with
   no such chrome to remove isn't cropped unnecessarily. */
.character-grid .media-frame.crop-ui img,
.character-grid .media-frame.crop-ui video {
  transform: scale(1.12);
}

/* Scales the whole Character Design block (label + grid) down ~20% and
   centers it within the page's normal content width, instead of
   spanning the full content width like the other media sections. Both
   children share the same width/centering, so the label's left edge
   lines up with the grid's left edge. */
.character-design-scale {
  padding: 0 var(--gutter);
}
.character-design-scale .media-label-row,
.character-design-scale .character-grid {
  width: 80%;
  margin-left: auto;
  margin-right: auto;
  padding: 0;
}

/* Scales a label + .media-natural pair down to 70% width, centered
   within the page's normal content width — e.g. Music Notes and
   Interactive Device on the Bebop Brain page. Both children share the
   same width/centering, so the label's left edge lines up with the
   resized image's left edge, and any two sections using this class
   share the same content width as each other. */
.media-scale-70 {
  padding: 0 var(--gutter);
}
.media-scale-70 .media-label-row,
.media-scale-70 .media-natural {
  width: 70%;
  margin-left: auto;
  margin-right: auto;
  padding: 0;
}

/* Two side-by-side */
.media-pair {
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(12px, 2vw, 24px);
}
.media-pair .media-frame { aspect-ratio: 4 / 3; }
@media (max-width: 720px) {
  .media-pair { grid-template-columns: 1fr; }
}

/* Small uppercase label placed above a media block (e.g. "Inspiration"),
   aligned with the row beneath it — reuses the .eyebrow type style. */
.media-label-row {
  padding: 0 var(--gutter);
  margin-bottom: clamp(18px, 3vw, 28px);
}

/* Four equal-width images in a single row — smaller, editorial scale,
   distinct from the two-up .media-pair layout. Wraps to two columns
   on mobile. */
.media-quad {
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  align-items: start;
  gap: clamp(8px, 1.4vw, 18px);
}
/* Uniform card size for all four — matches the 3:4 ratio that three of
   the four source images already have natively, so those three render
   with no crop at all; only an off-ratio image needs any cropping. */
.media-quad .media-frame { aspect-ratio: 3 / 4; }
@media (max-width: 720px) {
  .media-quad { grid-template-columns: repeat(2, 1fr); }
}

/* Smaller centered media */
.media-small {
  padding: 0 var(--gutter);
  max-width: 640px;
  margin-left: auto;
  margin-right: auto;
}
.media-small .media-frame { aspect-ratio: 1 / 1; }

/* Portrait-oriented media */
.media-portrait {
  padding: 0 var(--gutter);
  max-width: 460px;
}
.media-portrait .media-frame { aspect-ratio: 4 / 5; }
.media-portrait.align-right { margin-left: auto; }

/* Text / description block */
.text-block {
  padding: 0 var(--gutter);
  max-width: 720px;
}
.text-block .project-title-lg {
  font-size: clamp(28px, 5vw, 48px);
  font-weight: 500;
  letter-spacing: 0.01em;
  margin: 10px 0 22px;
}
.text-block .project-meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin-bottom: 26px;
  padding-bottom: 26px;
  border-bottom: 1px solid var(--border-soft);
}
.text-block p {
  color: var(--fg-dim);
  font-size: clamp(15px, 1.6vw, 18px);
  line-height: 1.7;
  max-width: 60ch;
}

/* Process documentation — alternating rhythm */
.process-block {
  padding: 0 var(--gutter);
}
.process-block .process-heading {
  margin-bottom: clamp(28px, 5vw, 48px);
}
.process-row {
  display: flex;
  align-items: flex-end;
  gap: clamp(20px, 4vw, 56px);
  margin-bottom: clamp(20px, 4vw, 56px);
}
.process-row.reverse { flex-direction: row-reverse; }
.process-row .media-small,
.process-row .media-portrait {
  padding: 0;
  margin: 0;
  max-width: none;
}
.process-row .process-col-lg { flex: 1.4; }
.process-row .process-col-sm { flex: 1; }
@media (max-width: 720px) {
  .process-row, .process-row.reverse { flex-direction: column; }
}

/* Credits / software / role */
.credits-block {
  padding: 0 var(--gutter);
  max-width: 720px;
  border-top: 1px solid var(--border-soft);
  padding-top: clamp(32px, 6vw, 56px);
}
.credits-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px 40px;
}
.credits-grid dt {
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin-bottom: 6px;
}
.credits-grid dd {
  margin: 0;
  color: var(--fg-dim);
  font-size: 15px;
  line-height: 1.6;
}
@media (max-width: 560px) {
  .credits-grid { grid-template-columns: 1fr; }
}

/* Shared media frame (used inside every .media-* variant) */
.media-frame {
  position: relative;
  width: 100%;
  overflow: hidden;
  background: #0a0a0a;
}
.media-frame img, .media-frame video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Project footer nav (prev/next + back to work) */
.project-footer-nav {
  padding: clamp(48px, 8vw, 90px) var(--gutter);
  border-top: 1px solid var(--border-soft);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}
.project-footer-nav a {
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-dim);
  transition: color 0.3s var(--ease);
}
.project-footer-nav a:hover { color: var(--fg); }

/* ==========================================================================
   About page
   ========================================================================== */

.about-layout {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: clamp(32px, 6vw, 80px);
  align-items: start;
}
@media (max-width: 860px) {
  .about-layout { grid-template-columns: 1fr; }
}

.about-portrait { width: 100%; aspect-ratio: 4 / 5; overflow: hidden; background: #0a0a0a; }
.about-portrait img { width: 100%; height: 100%; object-fit: cover; }

.about-name {
  font-size: clamp(28px, 4vw, 42px);
  font-weight: 500;
  margin-bottom: 22px;
}
.about-bio {
  color: var(--fg-dim);
  font-size: clamp(15px, 1.6vw, 18px);
  line-height: 1.75;
  max-width: 60ch;
  margin-bottom: 40px;
}
.about-disciplines {
  margin-bottom: 40px;
}
.about-disciplines ul {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 14px;
}
.about-disciplines li {
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-dim);
  border: 1px solid var(--border);
  padding: 8px 14px;
}
.about-cv {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}
.about-cv a {
  display: inline-block;
  font-size: 13px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg);
  border-bottom: 1px solid var(--fg);
  padding-bottom: 4px;
  transition: opacity 0.3s var(--ease);
}
.about-cv a:hover { opacity: 0.6; }

/* ==========================================================================
   Contact page
   ========================================================================== */

.contact-layout { max-width: 720px; }
.contact-intro {
  color: var(--fg-dim);
  font-size: clamp(15px, 1.6vw, 18px);
  line-height: 1.75;
  margin-bottom: 48px;
  max-width: 55ch;
}
.contact-list { display: flex; flex-direction: column; }
.contact-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 22px 0;
  border-top: 1px solid var(--border-soft);
  font-size: clamp(18px, 2.4vw, 26px);
  transition: opacity 0.3s var(--ease);
}
.contact-list .contact-item:last-child { border-bottom: 1px solid var(--border-soft); }
.contact-item:hover { opacity: 0.6; }
.contact-item .contact-arrow {
  font-size: 14px;
  color: var(--fg-faint);
}

/* ==========================================================================
   Footer
   ========================================================================== */

.site-footer {
  padding: clamp(40px, 6vw, 64px) var(--gutter);
  border-top: 1px solid var(--border-soft);
}
.footer-inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
}
.footer-links { display: flex; flex-wrap: wrap; gap: 20px; }
.footer-link {
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-dim);
  transition: color 0.3s var(--ease);
}
.footer-link:hover { color: var(--fg); }
.footer-meta {
  font-size: 12px;
  letter-spacing: 0.05em;
  color: var(--fg-faint);
}

/* ==========================================================================
   Utility
   ========================================================================== */

.page-top-space { height: var(--nav-h); }
