/* ============ WOOK — Media Artist Portfolio ============ */

:root {
  --bg: #ffffff;
  --bg-alt: #f2f2f2;
  --card: rgba(0, 0, 0, 0.03);
  --card-border: rgba(0, 0, 0, 0.12);
  --text: #0a0a0a;
  --muted: #6b6b6b;
  --accent: #000000;
  --accent-2: #3a3a3a;
  --gradient: linear-gradient(120deg, #000000, #3a3a3a 60%, #000000);
  --on-accent: #ffffff;
  --font: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Malgun Gothic', sans-serif;
  /* actual rendered height of header.nav — measured by JS (varies:
     one row on desktop, two rows on mobile once the nav pills wrap
     below the logo) so every sticky offset that depends on the header
     can just reference this instead of a hardcoded guess */
  --header-h: 58px;
}

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

html { scroll-behavior: smooth; }

html.page-ready body { opacity: 1; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  line-height: 1.6;
  min-height: 100vh;
  overflow-x: hidden;
  opacity: 0;
  transition: opacity 0.6s ease;
}

/* film-grain texture, sits above the particle canvas, below content */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.05;
  mix-blend-mode: overlay;
  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");
}

/* custom cursor (desktop / hover-capable pointers only) */
html.has-custom-cursor, html.has-custom-cursor a, html.has-custom-cursor button {
  cursor: none;
}

.cursor-dot, .cursor-ring {
  position: fixed;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 999;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.cursor-dot {
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: var(--accent);
}

.cursor-ring {
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.4);
  transition: opacity 0.2s ease, width 0.25s ease, height 0.25s ease, margin 0.25s ease, border-color 0.25s ease, background 0.25s ease;
}

.cursor-ring--active {
  width: 56px;
  height: 56px;
  margin: -28px 0 0 -28px;
  border-color: var(--accent);
  background: rgba(0, 0, 0, 0.06);
}

/* scroll reveal — items spin/settle into place one at a time as they
   enter the viewport, Apple-style product-page storytelling */
.reveal {
  opacity: 0;
  transform: perspective(900px) translateY(56px) rotate(-6deg) rotateX(14deg) scale(0.88);
  transition: opacity 0.85s cubic-bezier(0.16, 1, 0.3, 1), transform 0.85s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: var(--reveal-delay, 0s);
}

.reveal.in-view {
  opacity: 1;
  transform: perspective(900px) translateY(0) rotate(0deg) rotateX(0deg) scale(1);
}

/* cards get a touch more spin than plain sections, for a livelier feel */
.card.reveal {
  transform: perspective(900px) translateY(60px) rotate(-9deg) rotateX(18deg) scale(0.85);
}

.card.reveal.in-view {
  transform: perspective(900px) translateY(0) rotate(0deg) rotateX(0deg) scale(1);
}

/* marquee ticker */
.marquee {
  overflow: hidden;
  border-top: 1px solid var(--card-border);
  border-bottom: 1px solid var(--card-border);
  padding: 16px 0;
  white-space: nowrap;
}

.marquee-track {
  display: inline-flex;
  gap: 40px;
  animation: marquee-scroll 22s linear infinite;
  will-change: transform;
}

.marquee-track span {
  font-family: var(--font);
  font-size: 0.95rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 40px;
}

.marquee-track span em {
  font-style: normal;
  color: var(--accent);
  margin-right: 40px;
}

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

h1, h2, h3 {
  font-family: var(--font);
  font-weight: 700;
  letter-spacing: -0.01em;
}

.logo {
  font-family: var(--font);
  font-weight: 700;
  letter-spacing: 0.04em;
}

a { color: inherit; text-decoration: none; }

/* ---------- Intro splash — a brief particle-assembly moment before
   the home page reveals itself, once per browser session ---------- */
html.intro-lock, html.intro-lock body { overflow: hidden; height: 100%; }

.intro-splash {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  transition: opacity 0.5s ease;
}

.intro-splash canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
}

/* faint rotating rings behind the forming wordmark, tying the intro
   visually back to the hero/interlude sections that follow it — fade
   in immediately during the prelude, well before the mark itself */
.intro-orbit {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1s ease;
}

.intro-splash.intro-rings-visible .intro-orbit {
  opacity: 1;
}

.intro-splash .intro-mark {
  position: relative;
  z-index: 1;
  font-family: var(--font);
  font-weight: 800;
  font-size: clamp(2.2rem, 8vw, 5rem);
  letter-spacing: -0.03em;
  color: var(--text);
  opacity: 0;
  transform: scale(0.82);
  transition: opacity 0.45s ease, transform 0.55s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.intro-splash.intro-mark-visible .intro-mark {
  opacity: 1;
  transform: scale(1);
}

/* the tagline settles in just after the wordmark snaps into place —
   same trigger class, just staggered later via transition-delay */
.intro-splash .intro-tagline {
  position: relative;
  z-index: 1;
  margin-top: 14px;
  font-family: var(--font);
  font-weight: 500;
  font-size: clamp(0.85rem, 1.8vw, 1.05rem);
  letter-spacing: -0.005em;
  color: var(--muted);
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.6s ease 0.35s, transform 0.6s ease 0.35s;
}

.intro-splash.intro-mark-visible .intro-tagline {
  opacity: 1;
  transform: translateY(0);
}

.intro-splash.intro-done {
  opacity: 0;
  pointer-events: none;
}

/* thin scroll-progress line pinned to the very top of the viewport,
   present on every page (injected by JS). Sits just behind the intro
   splash so it never flashes on top of it before the reveal. */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  z-index: 9998;
  pointer-events: none;
  background: transparent;
}

.scroll-progress-fill {
  height: 100%;
  width: 100%;
  background: var(--gradient);
  transform: scaleX(0);
  transform-origin: left center;
}

/* faint VEX/wrangle-style code texture, tiled behind everything —
   an engineering-adjacent texture nodding to the tooling behind the
   work, injected by JS on every page so it never has to be hand-kept
   in sync across pages */
.code-texture {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  padding: 24px;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-size: 12.5px;
  letter-spacing: 0.1px;
  line-height: 1.65;
  color: rgba(0, 0, 0, 0.16);
  white-space: pre;
}

/* scrolled via JS transform (translateY), not native scroll — this
   just needs to be a plain block the parent can clip and move */
.code-texture-inner {
  will-change: transform;
}

/* each line wipes into view left-to-right in discrete chunks (rather
   than fading in whole), reading as though it's being typed out —
   staggered by --i (row index, set inline per row) so a whole block
   types itself out top-to-bottom in a cascade */
.code-row {
  overflow: hidden;
  white-space: pre;
  clip-path: inset(0 100% 0 0);
  animation: code-type-in 0.4s steps(24, end) forwards;
  animation-delay: calc(var(--i, 0) * 35ms);
}

@keyframes code-type-in {
  to { clip-path: inset(0 0 0 0); }
}

.code-texture .tok-num {
  color: rgba(0, 0, 0, 0.12);
}

.code-texture .tok-kw {
  color: rgba(0, 0, 0, 0.34);
  font-weight: 600;
}

.code-texture .tok-attr {
  color: rgba(0, 0, 0, 0.3);
  font-weight: 600;
}

.code-texture .tok-str {
  color: rgba(0, 0, 0, 0.22);
  font-style: italic;
}

.code-texture .tok-comment {
  color: rgba(0, 0, 0, 0.13);
  font-style: italic;
}

/* generative flow-field lines — thin sweeping strands drifting very
   slowly, sitting furthest back of all the background layers */
canvas#flow-bg {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

canvas#particle-bg {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  opacity: 0.55;
  pointer-events: none;
}

/* ---------- Layout ---------- */

.page {
  position: relative;
  z-index: 1;
}

.container {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 28px;
}

/* ---------- Nav ---------- */

header.nav {
  position: sticky;
  top: 0;
  z-index: 10;
  backdrop-filter: blur(14px);
  background: rgba(255, 255, 255, 0.72);
  border-bottom: 1px solid var(--card-border);
}

.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 13px 28px;
  max-width: 1100px;
  margin: 0 auto;
}

.logo {
  font-size: 0.98rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.logo span { color: var(--accent); }

nav.links {
  display: flex;
  gap: 28px;
  align-items: center;
}

nav.links a {
  font-size: 0.8rem;
  letter-spacing: 0.03em;
  color: var(--muted);
  transition: color 0.2s ease;
  position: relative;
}

nav.links a:hover,
nav.links a.active {
  color: var(--text);
}

nav.links a.active::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -6px;
  width: 100%;
  height: 2px;
  background: var(--gradient);
  border-radius: 2px;
}

.nav-ig {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--card-border);
  font-size: 0.85rem;
  transition: border-color 0.2s ease, transform 0.2s ease;
}

.nav-ig:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
}


/* ---------- Playful home intro — a short phrase greets you first,
   grows large as you scroll, then bursts apart into particles (JS)
   while the kiukukim wordmark fades in behind it. The hero is a tall
   runway with its content pinned to the viewport while it scrolls
   underneath, so the whole sequence is tied directly to scroll. ---------- */

.kiukukim-hero {
  position: relative;
  height: 240vh;
}

.hero-pin {
  position: sticky;
  top: var(--header-h);
  height: calc(100vh - var(--header-h));
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

/* slow-spinning decorative rings behind the text — two thin circles,
   each drawn as a partial arc (via stroke-dasharray) so gaps drift
   past as they rotate at different speeds/directions, an ambient
   orbiting feel around whatever text is centered in the stage */
.hero-orbit {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.orbit-ring {
  position: absolute;
  width: min(62vw, 600px);
  height: min(62vw, 600px);
  overflow: visible;
}

.orbit-ring circle {
  fill: none;
  stroke: rgba(0, 0, 0, 0.16);
  stroke-width: 1;
}

.orbit-ring--a {
  animation: orbit-spin 42s linear infinite;
}

.orbit-ring--a circle {
  stroke-dasharray: 1600 159;
}

.orbit-ring--b {
  width: min(50vw, 480px);
  height: min(50vw, 480px);
  animation: orbit-spin 30s linear infinite reverse;
}

.orbit-ring--b circle {
  stroke: rgba(0, 0, 0, 0.3);
  stroke-dasharray: 300 422;
}

@keyframes orbit-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.hero-stage {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 260px;
}

.hero-stage > * {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  will-change: opacity, transform;
}

.intro-phrase {
  font-family: var(--font);
  font-weight: 700;
  font-size: clamp(1.15rem, 2.6vw, 1.8rem);
  line-height: 1.5;
  letter-spacing: -0.01em;
  opacity: 1;
  transform: scale(1);
}

/* fill and outline copies of the same line, stacked in one grid cell —
   JS crossfades between them on scroll, then dissolves the outline
   copy (blur + widening letter-spacing) for a scattering exit */
.phrase-stack {
  display: grid;
}

.phrase-stack > * {
  grid-area: 1 / 1;
  will-change: opacity, filter, letter-spacing;
}

.phrase-fill {
  color: var(--text);
  opacity: 1;
}

.phrase-outline {
  color: transparent;
  -webkit-text-stroke: 1px var(--text);
  text-stroke: 1px var(--text);
  opacity: 0;
}

.kiukukim-mark {
  font-family: var(--font);
  font-size: clamp(3rem, 11vw, 8.5rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  background: var(--gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 30px rgba(0, 0, 0, 0.18));
  user-select: none;
  opacity: 0;
  transform: scale(0.85);
}

/* ---------- Interludes — short beats from the artist statement,
   each with slow rings behind it. A bright gradient wipe flashes
   through as each one scrolls into view, like passing through a ring
   into the next scene, then its text/CTA settles in. ---------- */

.interlude {
  position: relative;
  min-height: 90vh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  overflow: hidden;
  padding: 60px 24px;
}

/* a huge, barely-there scene number sitting behind each interlude's
   content — an index marker at a scale that reads as pure texture */
.interlude[data-scene]::before {
  content: attr(data-scene);
  position: absolute;
  z-index: 0;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--font);
  font-weight: 800;
  font-size: clamp(9rem, 32vw, 24rem);
  line-height: 1;
  color: rgba(0, 0, 0, 0.045);
  pointer-events: none;
  user-select: none;
}

.stat-scene[data-scene]::before {
  color: rgba(255, 255, 255, 0.05);
}

/* fixed side index — desktop only, mirrors the giant scene numbers */
.scene-index {
  position: fixed;
  right: 24px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: center;
}

.scene-index-dot {
  font-family: var(--font);
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--muted);
  background: none;
  border: none;
  cursor: pointer;
  padding: 4px;
  opacity: 0.45;
  transition: opacity 0.25s ease, color 0.25s ease, transform 0.25s ease;
}

.scene-index-dot:hover {
  opacity: 0.8;
}

.scene-index-dot.active {
  color: var(--text);
  opacity: 1;
  transform: scale(1.3);
}

.interlude-text {
  position: relative;
  z-index: 1;
  font-family: var(--font);
  font-weight: 700;
  font-size: clamp(1.4rem, 3.4vw, 2.4rem);
  line-height: 1.5;
  max-width: 26ch;
  color: var(--text);
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1), transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

.interlude.in-view .interlude-text {
  opacity: 1;
  transform: translateY(0);
}

.interlude-cta {
  position: relative;
  z-index: 1;
  display: inline-flex;
  opacity: 0;
  transform: translateY(40px) scale(0.94);
  transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1), transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

.interlude.in-view .interlude-cta {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/* the actual gradient text lives on this inner wrapper (not the <a>
   itself) so the magnetic cursor-follow effect (which drives this
   element's own transform) never fights the outer reveal animation */
.interlude-cta-inner {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font);
  font-weight: 700;
  font-size: clamp(1.3rem, 3.2vw, 1.9rem);
  letter-spacing: -0.01em;
  background: var(--gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.interlude-cta-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.5em;
  font-weight: 700;
  letter-spacing: normal;
  color: var(--on-accent);
  background: var(--accent);
  background-clip: initial;
  -webkit-background-clip: initial;
  border-radius: 999px;
  padding: 3px 11px;
}

/* the wipe-through flash itself — a small gradient disc that rapidly
   scales up past the edges of the screen and fades, timed to the
   moment the section becomes active */
.scene-wipe {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 36px;
  height: 36px;
  margin: -18px 0 0 -18px;
  border-radius: 50%;
  background: var(--gradient);
  opacity: 0;
  pointer-events: none;
  z-index: 0;
}

.interlude.in-view .scene-wipe {
  animation: wipe-through 1s cubic-bezier(0.65, 0, 0.35, 1) forwards;
}

@keyframes wipe-through {
  0% { opacity: 0.85; transform: scale(1); }
  55% { opacity: 0.45; transform: scale(40); }
  100% { opacity: 0; transform: scale(55); }
}

/* ---------- Stat scene — a color-inverted beat in the middle of the
   scroll, breaking the rhythm of the quote interludes with a couple
   of honest numbers about the work instead of another line of text */
.stat-scene {
  background: #050505;
}

.stat-scene .orbit-ring circle {
  stroke: rgba(255, 255, 255, 0.18);
}

.stat-scene .orbit-ring--b circle {
  stroke: rgba(255, 255, 255, 0.32);
}

.metric-row {
  position: relative;
  z-index: 1;
  display: flex;
  gap: clamp(48px, 10vw, 120px);
  flex-wrap: wrap;
  justify-content: center;
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1), transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

.stat-scene.in-view .metric-row {
  opacity: 1;
  transform: translateY(0);
}

.metric {
  text-align: center;
}

.metric-num {
  font-family: var(--font);
  font-weight: 800;
  font-size: clamp(3rem, 9vw, 6rem);
  letter-spacing: -0.03em;
  line-height: 1;
  color: #ffffff;
}

.metric-label {
  margin-top: 10px;
  font-size: 0.9rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}

/* ---------- Hero ---------- */

.hero {
  padding: 110px 0 80px;
  text-align: center;
}

.eyebrow {
  display: block;
  font-family: var(--font);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  color: var(--muted);
  margin-bottom: 14px;
}

.eyebrow::before { content: "[ "; color: var(--accent); }
.eyebrow::after { content: " ]"; color: var(--accent); }

.hero {
  position: relative;
}

/* glowing gradient orbs behind the hero — soft, blurred light sources
   for a glossy, high-production feel */
.hero::before,
.hero::after {
  content: "";
  position: absolute;
  z-index: -1;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.35;
  pointer-events: none;
  animation: orb-float 12s ease-in-out infinite alternate;
}

.hero::before {
  width: 380px;
  height: 380px;
  top: -120px;
  left: 8%;
  background: radial-gradient(circle, rgba(0, 0, 0, 0.55), transparent 70%);
}

.hero::after {
  width: 420px;
  height: 420px;
  top: 40px;
  right: 6%;
  background: radial-gradient(circle, rgba(0, 0, 0, 0.3), transparent 70%);
  animation-delay: -6s;
}

@keyframes orb-float {
  from { transform: translate(0, 0) scale(1); }
  to { transform: translate(-16px, 24px) scale(1.08); }
}

.hero h1 {
  font-size: clamp(2.8rem, 7vw, 5.4rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.03em;
  background: var(--gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 24px rgba(0, 0, 0, 0.15));
}

.hero p.sub {
  margin: 22px auto 0;
  max-width: 560px;
  color: var(--muted);
  font-size: 1.05rem;
}

.hero-actions {
  margin-top: 36px;
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
}

.btn {
  padding: 13px 26px;
  border-radius: 10px;
  font-size: 0.95rem;
  font-weight: 500;
  transition: transform 0.2s ease, opacity 0.2s ease;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.btn.primary {
  background: var(--gradient);
  color: var(--on-accent);
  font-weight: 600;
}

.btn.ghost {
  border: 1px solid var(--card-border);
  color: var(--text);
}

.btn:hover { transform: translateY(-2px); opacity: 0.92; }

/* ---------- Stats ---------- */

.stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  margin-top: 70px;
}

.stat-card {
  background: var(--card);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--card-border);
  border-radius: 16px;
  padding: 28px 20px;
  text-align: center;
  transition: border-color 0.25s ease, transform 0.25s ease;
}

.stat-card:hover {
  border-color: rgba(0, 0, 0, 0.3);
  transform: translateY(-3px);
}

.stat-card .num {
  font-family: var(--font);
  font-size: 2rem;
  color: var(--accent);
}

.stat-card .label {
  margin-top: 6px;
  font-size: 0.85rem;
  color: var(--muted);
}

/* ---------- Section ---------- */

section { padding: 110px 0; }

.section-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  margin-bottom: 36px;
  flex-wrap: wrap;
  gap: 12px;
}

.section-head h2 { font-size: 2.3rem; letter-spacing: -0.02em; }
.section-head p { color: var(--muted); font-size: 0.95rem; }

/* Apple-esque minimal "Learn more >" link */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--accent);
  font-size: 0.95rem;
  transition: gap 0.2s ease;
}

.link-arrow:hover { gap: 8px; }

/* ---------- Feature blocks (full-width, stacked storytelling) ---------- */

.feature-block {
  padding: 90px 0;
  border-bottom: 1px solid var(--card-border);
}

.feature-block:last-child { border-bottom: none; }

.feature-inner {
  max-width: 720px;
  margin: 0 auto;
  text-align: center;
}

.feature-eyebrow {
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-2);
  margin-bottom: 18px;
}

.feature-block h3 {
  font-size: clamp(2.2rem, 5vw, 3.6rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin-bottom: 20px;
}

.feature-block p {
  color: var(--muted);
  font-size: 1.05rem;
  max-width: 520px;
  margin: 0 auto 28px;
}

.feature-media {
  margin-top: 56px;
  border-radius: 24px;
  overflow: hidden;
  border: 1px solid var(--card-border);
  background: #000;
  max-width: 860px;
  margin-left: auto;
  margin-right: auto;
  box-shadow: 0 40px 100px -40px rgba(0, 0, 0, 0.6);
}

.feature-media img,
.feature-media video {
  width: 100%;
  display: block;
  max-height: 520px;
  object-fit: cover;
}

.feature-media.square img,
.feature-media.square video {
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

/* ---------- Tabs ---------- */

.tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 24px;
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding: 4px 0;
}

.tabs::-webkit-scrollbar { display: none; }

.tab-btn {
  font-family: var(--font);
  padding: 8px 18px;
  border-radius: 999px;
  border: 1px solid var(--card-border);
  background: transparent;
  color: var(--muted);
  font-size: 0.85rem;
  cursor: pointer;
  transition: all 0.2s ease;
  flex: 0 0 auto;
  white-space: nowrap;
}

.tab-btn:hover { color: var(--text); border-color: rgba(0, 0, 0, 0.3); }

.tab-btn.active {
  color: var(--on-accent);
  border-color: var(--accent);
  background: var(--accent);
}

.panel { display: none !important; }
.panel.active { display: grid !important; }
#panel-exhibition.active { display: flex !important; flex-direction: column; gap: 60px; }

/* Exhibition tab: grouped by location, with bigger landscape tiles
   than the default work grid so on-site footage reads clearly. */
.exhibition-group-head {
  margin-bottom: 22px;
}

.exhibition-group-head h3 {
  font-size: 1.5rem;
  letter-spacing: -0.01em;
}

#panel-exhibition .card.wide .thumb {
  max-width: 860px;
}

@media (max-width: 900px) {
  #panel-exhibition .card.wide .thumb { max-width: 100%; }
}

/* ---------- Work grid (gallery) ----------
   Portrait cards sit three to a row; landscape cards take the full
   row on their own so they never get cropped or feel oversized. */

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

.card.wide {
  grid-column: 1 / -1;
}

.card.wide .thumb {
  max-width: 520px;
  margin: 0 auto;
}

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

@media (max-width: 440px) {
  .grid { grid-template-columns: 1fr; }
  .card.wide .thumb { max-width: none; }
}

/* the card currently "spotlighted" by scroll-driven autoplay */
.card.is-playing {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3), 0 20px 60px -20px rgba(0, 0, 0, 0.3);
}

.card.is-playing .thumb::after {
  content: "NOW PLAYING";
  position: absolute;
  top: 10px;
  right: 10px;
  font-family: var(--font);
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  color: var(--on-accent);
  background: var(--accent);
  padding: 4px 9px;
  border-radius: 999px;
  z-index: 2;
}

.thumb video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  background: #000;
}

.video-card .thumb .play { display: none; }

/* landscape (16:9) videos get their own aspect ratio instead of the
   default 4:5 portrait box, so they sit compact and true-to-source
   inside their masonry column */
.thumb.landscape {
  aspect-ratio: 16 / 9;
}

.thumb.landscape video {
  object-fit: contain;
  background: #000;
}

/* true 9:16 (1080x1920 / 2160x3840) videos get a matching tall box —
   at this exact ratio object-fit: cover fills it with zero cropping,
   since the box shape now equals the source footage's own shape */
.thumb.ratio-9x16 {
  aspect-ratio: 9 / 16;
}

/* ---------- Coming soon ---------- */

.coming-soon {
  width: 100%;
  border: 1px dashed var(--card-border);
  border-radius: 20px;
  padding: 70px 30px;
  text-align: center;
  color: var(--muted);
}

.coming-soon svg { color: var(--accent-2); margin-bottom: 18px; }
.coming-soon h3 { color: var(--text); font-size: 1.2rem; margin-bottom: 8px; }
.coming-soon p { font-size: 0.9rem; }

.card {
  background: transparent;
  border: none;
  border-radius: 0;
  overflow: visible;
  transition: transform 0.25s ease, opacity 0.25s ease;
  display: flex;
  flex-direction: column;
}

.card:hover {
  transform: translateY(-4px);
}

.card .thumb {
  border-radius: 3px;
  overflow: hidden;
  transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}

.thumb {
  position: relative;
  aspect-ratio: 4 / 5;
  background: #111 center / cover no-repeat;
}

.thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.thumb .play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(180deg, rgba(0,0,0,0) 55%, rgba(0,0,0,0.55));
  opacity: 0;
  transition: opacity 0.2s ease;
}

.card:hover .thumb .play { opacity: 1; }

.thumb .play svg { width: 46px; height: 46px; filter: drop-shadow(0 2px 8px rgba(0,0,0,0.5)); }

.thumb .pinned-tag {
  position: absolute;
  top: 10px;
  left: 10px;
  background: rgba(0,0,0,0.55);
  border: 1px solid rgba(255, 255, 255, 0.25);
  font-size: 0.7rem;
  padding: 4px 8px;
  border-radius: 999px;
  color: #ffffff;
}

.card-body {
  padding: 14px 2px 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1;
}

.card-body .cap {
  font-family: var(--font);
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--text);
  min-height: 2.4em;
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.tags span {
  font-size: 0.7rem;
  color: var(--text);
  background: rgba(0, 0, 0, 0.06);
  border-radius: 999px;
  padding: 3px 9px;
}

.meta {
  margin-top: auto;
  display: flex;
  justify-content: space-between;
  font-size: 0.78rem;
  color: var(--muted);
  border-top: 1px solid var(--card-border);
  padding-top: 12px;
}

.meta .metrics { display: flex; gap: 14px; }

.ig-link { font-size: 0.78rem; }
.ig-link a { color: var(--accent); }
.ig-link a:hover { text-decoration: underline; }

/* ---------- About ---------- */

.about-grid {
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: 50px;
  align-items: start;
}

.avatar-wrap {
  border-radius: 20px;
  overflow: hidden;
  border: 1px solid var(--card-border);
  aspect-ratio: 1 / 1;
  background: #111;
}

.avatar-wrap img { width: 100%; height: 100%; object-fit: cover; }

.about-text h3 {
  margin-top: 28px;
  font-size: 1.15rem;
  color: var(--accent-2);
}

.about-text p { color: var(--muted); margin-top: 10px; }

.about-text p.lead::first-letter {
  font-family: var(--font);
  font-weight: 800;
  font-size: 3.4em;
  float: left;
  line-height: 0.78;
  padding-right: 10px;
  padding-top: 6px;
  color: var(--accent-2);
}

.about-text ul {
  margin-top: 12px;
  padding-left: 18px;
  color: var(--muted);
}

.about-text li { margin-bottom: 6px; }

.pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
}

.pill {
  border: 1px solid var(--card-border);
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 0.82rem;
  color: var(--text);
}

/* ---------- Contact ---------- */

.contact-box {
  max-width: 640px;
  margin: 0 auto;
  text-align: center;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 20px;
  padding: 60px 40px;
}

.contact-box h2 { font-size: 2rem; margin-bottom: 14px; }
.contact-box p { color: var(--muted); margin-bottom: 30px; }

.contact-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-width: 360px;
  margin: 0 auto;
}

.contact-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 16px 20px;
  transition: border-color 0.2s ease, transform 0.2s ease;
}

.contact-row:hover { border-color: var(--accent); transform: translateY(-2px); }
.contact-row .k { color: var(--muted); font-size: 0.85rem; }
.contact-row .v { font-weight: 500; }

/* ---------- Footer ---------- */

footer {
  border-top: 1px solid var(--card-border);
  padding: 34px 0;
  text-align: center;
  color: var(--muted);
  font-size: 0.82rem;
}

/* ---------- Responsive ---------- */

@media (max-width: 720px) {
  .about-grid { grid-template-columns: 1fr; }
  .avatar-wrap { max-width: 220px; margin: 0 auto; }
  .stats { grid-template-columns: 1fr; }

  /* the nav row wraps onto a second line: logo + IG link stay on top,
     the link list drops below as its own full-width row of pill
     buttons — always visible, no tap-to-reveal menu, styled the same
     way as the category tabs on the works page for a consistent feel */
  .nav-inner {
    flex-wrap: wrap;
    row-gap: 12px;
  }

  nav.links {
    order: 3;
    flex-basis: 100%;
    display: flex;
    flex-wrap: nowrap;
    gap: 8px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }

  nav.links::-webkit-scrollbar { display: none; }

  nav.links a {
    flex: 0 0 auto;
    padding: 9px 18px;
    border-radius: 999px;
    border: 1px solid var(--card-border);
    font-size: 0.85rem;
    white-space: nowrap;
  }

  nav.links a.active {
    color: var(--on-accent);
    background: var(--accent);
    border-color: var(--accent);
  }

  nav.links a.active::after { display: none; }

  /* the fixed VEX code texture sits directly behind any text that
     isn't on its own opaque card/section background (headings,
     eyebrows, body copy, tab labels) — a white halo keeps those
     letterforms readable without changing anything on solid
     backgrounds, since white-on-white is invisible there */
  h1, h2, h3, p, .eyebrow, .tab-btn, #panel-count, .pill {
    text-shadow:
      0 0 1px #fff, 0 0 2px #fff, 0 0 7px rgba(255, 255, 255, 0.9),
      1px 1px 0 #fff, -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff;
  }

  /* code texture is dropped entirely on mobile — too little room to
     breathe there, it just fights with the content instead of
     reading as background texture */
  .code-texture { display: none; }
}
