:root{
  --bg: #0b0b0a;
  --bg-raised: #121211;
  --text: #f0ede6;
  --muted: #8f8c85;
  --line: #262523;
  --accent: #c7c7a4;
  --sage-bg: #d9d9c5;
  --sage-text: #1a1a16;
  --sage-muted: #6b6a5f;
  --serif: Arial, Helvetica, sans-serif;
  --sans: Arial, Helvetica, sans-serif;
  --mono: Arial, Helvetica, sans-serif;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-fast: cubic-bezier(0.4, 0, 0.2, 1);
}
*{box-sizing:border-box; margin:0; padding:0;}
html{scroll-behavior:smooth;}
html, body{height:100%;}
body{
  background:var(--bg);
  color:var(--text);
  font-family:var(--sans);
  font-size:14px;
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
  display:flex;
  flex-direction:column;
  min-height:100vh;
}
a{color:var(--text); text-decoration:none; transition:color 0.2s var(--ease-fast);}
a:hover{color:var(--muted);}

.wrap{max-width:680px; margin:0 auto; padding:0 24px;}
.wrap-wide{max-width:1040px;}

header{
  background:var(--sage-bg);
  padding:32px 0 26px;
}
.header-inner{
  display:flex;
  justify-content:space-between;
  align-items:center;
  flex-wrap:wrap;
  gap:12px;
}
.logo{
  font-family:var(--serif);
  font-size:16px;
  font-weight:500;
  letter-spacing:0.2px;
  color:var(--sage-text);
}
nav{display:flex; gap:18px;}
nav a{
  font-size:12.5px;
  color:var(--sage-muted);
  font-family:var(--sans);
}
nav a.active{color:var(--sage-text);}
nav a:hover{color:var(--sage-text);}

main{flex:1 0 auto; position:relative;}
.page{display:none;}
.page.active{display:block; animation:page-enter 0.4s var(--ease);}
.page.leaving{
  display:block;
  position:absolute;
  top:0; left:0; right:0;
  animation:page-leave 0.32s var(--ease) forwards;
  pointer-events:none;
}
@keyframes page-enter{
  from{opacity:0; transform:translateY(10px);}
  to{opacity:1; transform:translateY(0);}
}
@keyframes page-leave{
  from{opacity:1; transform:translateY(0);}
  to{opacity:0; transform:translateY(-10px);}
}

.page-inner{
  min-height:60vh;
  display:flex;
  align-items:center;
  padding:60px 0;
}

.panel{width:100%; padding:80px 0; box-sizing:border-box;}
.hero-panel{
  position:relative;
  margin-top:-1px;
  background:var(--sage-bg);
  color:var(--sage-text);
  min-height:100vh;
  display:flex;
  align-items:center;
  justify-content:center;
  overflow:hidden;
}
.hero-panel .wrap{position:relative; z-index:2;}
/* blends the beige panel into the next panel's near-black background at
   the bottom edge only, instead of a hard color cut between the two */
.hero-panel::after{
  content:'';
  position:absolute;
  inset:0;
  z-index:0;
  pointer-events:none;
  background:linear-gradient(180deg, transparent 78%, var(--bg) 100%);
}
.timeline-panel{
  background:var(--bg);
  color:var(--text);
  min-height:100vh;
  display:flex;
  align-items:center;
  padding:100px 0;
}

.eyebrow{
  font-family:var(--mono);
  font-size:12px;
  letter-spacing:0.06em;
  text-transform:lowercase;
  color:var(--accent);
  display:block;
  margin-bottom:20px;
}

h1{
  font-family:var(--serif);
  font-weight:400;
  font-size:24px;
  line-height:1.3;
  letter-spacing:-0.01em;
  margin-bottom:16px;
}
h1 em{font-style:italic; color:var(--muted);}

.lede{
  font-size:13.5px;
  color:var(--text);
  max-width:48ch;
  margin-bottom:8px;
}
.lede a{border-bottom:1px solid var(--muted);}
.lede a:hover{border-color:var(--text);}

.lede-lg{
  font-size:16px;
  max-width:44ch;
  margin:12px 0 0;
}

/* poster-style hero */
.poster-wrap{
  position:relative;
  width:100%;
  max-width:960px;
  min-height:620px;
  padding:0 24px 80px;
}
.poster-corner{
  position:absolute;
  top:0;
  display:flex;
  align-items:center;
  gap:6px;
  font-family:Arial, Helvetica, sans-serif;
  font-size:11.5px;
  font-weight:700;
  letter-spacing:0.04em;
  color:#3a3830;
}
.poster-corner-left{
  left:24px;
  writing-mode:vertical-rl;
  transform:rotate(180deg);
  top:132px;
}
.poster-arrow{font-size:9px;}

.hero-palette{
  position:absolute;
  top:16px;
  right:16px;
  z-index:3;
  display:flex;
  gap:0;
  height:14px;
  width:110px;
  border:1px solid rgba(22,21,16,0.25);
}
.hero-palette span{flex:1; height:100%;}

.poster-emblem{
  position:absolute;
  top:16px;
  left:24px;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:3px;
  border:1.5px solid #22201a;
  padding:10px 7px;
}
.poster-emblem span{
  font-family:var(--mono);
  font-size:10.5px;
  font-weight:700;
  letter-spacing:0.02em;
  line-height:1;
  color:#22201a;
}

.poster-main{
  position:relative;
  z-index:2;
  max-width:640px;
  margin:0 auto;
  padding-top:24%;
  text-align:center;
}
.poster-name{
  position:relative;
  z-index:2;
  font-family:Arial, Helvetica, sans-serif;
  font-weight:900;
  font-size:60px;
  line-height:0.95;
  letter-spacing:-0.01em;
  text-transform:uppercase;
  color:#161510;
  margin:0;
  text-shadow:
    0 0 14px var(--sage-bg),
    0 0 14px var(--sage-bg),
    0 0 6px var(--sage-bg);
}
.poster-tag{
  font-family:var(--mono);
  font-size:13px;
  color:#3a3830;
  margin-top:18px;
  position:relative;
  z-index:2;
}
.poster-def{
  font-family:Arial, Helvetica, sans-serif;
  font-style:italic;
  font-size:14px;
  color:#3a3830;
  max-width:34ch;
  line-height:1.6;
  margin:10px auto 0;
  position:relative;
  z-index:2;
}

.poster-est{
  position:absolute;
  left:0;
  right:0;
  width:auto;
  bottom:100px;
  text-align:center;
  font-family:var(--mono);
  font-size:10.5px;
  letter-spacing:0.1em;
  text-transform:uppercase;
  color:#5a5850;
}
.poster-quote{
  position:absolute;
  left:0;
  right:0;
  width:auto;
  bottom:40px;
  text-align:center;
}
.poster-quote p{
  font-family:Arial, Helvetica, sans-serif;
  font-style:italic;
  font-size:13.5px;
  color:#3a3830;
  margin:0;
}

@media(max-width:720px){
  .poster-wrap{min-height:auto; padding:100px 24px 120px;}
  .poster-main{max-width:100%; padding-top:0;}
  .poster-name{font-size:38px;}
  .poster-emblem{top:16px; left:12px; padding:7px 5px;}
  .poster-emblem span{font-size:9px;}
  .poster-corner-left{top:100px; left:12px;}
  .hero-palette{top:16px; right:12px; width:90px; height:11px;}
  .poster-quote{position:relative; left:auto; width:auto; bottom:auto; margin-top:40px; text-align:center;}
  .poster-est{position:relative; left:auto; width:auto; bottom:auto; margin-top:12px; display:block; text-align:center;}
}

.timeline{
  position:relative;
  display:flex;
  flex-direction:column;
  gap:64px;
  padding:24px 0;
}
.tl-item{
  display:flex;
  gap:28px;
  align-items:flex-start;
  opacity:0;
  transform:translateY(18px);
  transition:opacity 0.7s var(--ease), transform 0.7s var(--ease);
}
.tl-item.in-view{opacity:1; transform:translateY(0);}
.tl-marker{
  position:relative;
  z-index:1;
  padding-top:6px;
}
.tl-dot{
  display:block;
  width:18px;
  height:18px;
  border-radius:50%;
  background:var(--bg);
  border:2px solid var(--muted);
  transition:border-color 0.4s var(--ease);
}
.tl-item.in-view .tl-dot{border-color:var(--accent);}
.tl-content{flex:1;}
.tl-age{
  font-family:var(--mono);
  font-size:15px;
  color:var(--accent);
  margin-bottom:8px;
}
.tl-age:empty{
  display:inline-block;
  width:64px;
  height:15px;
  border-bottom:1px dashed var(--muted);
}
.tl-body{font-size:14px; line-height:1.5; color:var(--text); max-width:46ch; min-height:1.4em;}
.tl-body:empty{
  display:block;
  width:100%;
  max-width:64px;
  height:15px;
  border-bottom:1px dashed var(--muted);
}

section{margin-top:80px;}
.section-title{
  font-family:var(--mono);
  font-size:12px;
  letter-spacing:0.06em;
  color:var(--accent);
  text-transform:lowercase;
  margin-bottom:28px;
}
.section-title.timeline-title{margin-top:96px;}

.home-bio{
  font-size:15px;
  line-height:1.85;
  color:var(--text);
  max-width:58ch;
}

/* list rows used for projects / writing / work */
.row-list{display:flex; flex-direction:column; gap:22px;}
.row{
  display:flex;
  justify-content:space-between;
  align-items:baseline;
  gap:16px;
}
.row:first-child{padding-top:0;}
.row-num{
  font-family:var(--mono);
  font-size:11px;
  color:var(--accent);
  width:20px;
  flex-shrink:0;
}
.row-main{flex:1; min-width:0;}
.row-title{
  font-size:13.5px;
  font-weight:500;
  color:var(--text);
  transition:color 0.2s var(--ease-fast);
}
.row-title .arrow{color:var(--muted); font-weight:400; margin-left:4px; transition:color 0.2s var(--ease-fast);}
.row-desc{
  font-size:12px;
  color:var(--muted);
  margin-top:3px;
}
.row-meta{
  font-family:var(--mono);
  font-size:11px;
  color:var(--accent);
  white-space:nowrap;
  padding-top:2px;
}
.row:hover .row-title{color:var(--muted);}
.row:hover .row-title .arrow{color:var(--accent);}

/* blog accordion */
.blog-row{
  width:100%;
  background:none;
  border:none;
  font:inherit;
  cursor:pointer;
  text-align:left;
}
.blog-toggle{
  font-family:var(--mono);
  font-size:14px;
  color:var(--accent);
  margin-left:12px;
  transition:transform 0.3s var(--ease);
}
.blog-item.open .blog-toggle{transform:rotate(45deg);}
.blog-drop{
  max-height:0;
  overflow:hidden;
  transition:max-height 0.4s var(--ease);
}
.blog-item.open .blog-drop{max-height:300px;}
.blog-drop-placeholder{
  font-size:13px;
  font-style:italic;
  color:var(--muted);
  border:1px dashed var(--line);
  padding:16px;
  margin:14px 0 8px;
}

/* brain dump — read-only stream, edited by hand in index.html only */
.dump-list{
  display:flex;
  flex-direction:column;
  gap:36px;
  margin-top:44px;
}
.dump-entry{
  border-left:2px solid var(--line);
  padding-left:20px;
}
.dump-date{
  font-family:var(--mono);
  font-size:11px;
  letter-spacing:0.06em;
  text-transform:lowercase;
  color:var(--accent);
  margin-bottom:8px;
}
.dump-text{
  font-size:14px;
  line-height:1.7;
  color:var(--text);
  max-width:56ch;
}

/* projects gallery — alternating left/right rows, expanding hover */
.gallery{
  display:flex;
  flex-direction:column;
  gap:88px;
  margin-top:48px;
}
.piece{
  display:grid;
  grid-template-columns:1.3fr 1fr;
  gap:40px;
  align-items:center;
  cursor:pointer;
}
.piece:nth-child(even){grid-template-columns:1fr 1.3fr;}
.piece:nth-child(even) .piece-media{order:2;}
.piece:nth-child(even) .piece-caption{order:1; text-align:right;}
.piece:nth-child(even) .piece-desc,
.piece:nth-child(even) .piece-links{margin-left:auto;}
.piece:nth-child(even) .piece-links{align-items:flex-end;}
.piece-media{
  position:relative;
  aspect-ratio:4/3;
  background:var(--bg-raised);
  border:1px solid var(--line);
  overflow:hidden;
  transition:border-color 0.4s var(--ease), transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.piece-media img, .piece-media video{
  width:100%;
  height:100%;
  object-fit:cover;
  display:block;
  transition:transform 0.6s var(--ease), filter 0.6s var(--ease);
}
/* for a cover photo whose own aspect ratio doesn't match the shared 4:3
   box — object-fit:cover was cropping the top/bottom off; contain plus a
   little breathing room shows the whole image instead, slightly smaller
   within the frame rather than filling and cutting it off. Two variants:
   --contain (black background) for a cover that's already black/dark
   itself (Elsewhere); --contain-light (white background, less padding
   so the image reads bigger) for a cover with a white background of its
   own (Focal, sf-atlas) — a black frame around a white image looked odd. */
.piece-media--contain{padding:20px; box-sizing:border-box; background:#000;}
.piece-media--contain img{object-fit:contain;}
.piece-media--contain-light{padding:6px; box-sizing:border-box; background:#fff;}
.piece-media--contain-light img{object-fit:contain;}
.piece-placeholder-label{
  position:absolute;
  inset:0;
  display:flex;
  align-items:center;
  justify-content:center;
  font-family:var(--mono);
  font-size:11px;
  letter-spacing:0.06em;
  text-transform:lowercase;
  color:var(--muted);
  pointer-events:none;
}
.piece:hover .piece-media{
  border-color:var(--accent);
  transform:scale(1.03);
  box-shadow:0 20px 50px rgba(0,0,0,0.35);
}
.piece:hover .piece-media img, .piece:hover .piece-media video{
  transform:scale(1.06);
  filter:brightness(1.08);
}
.piece-title{font-size:19px; font-weight:500; color:var(--text);}
.piece-medium{
  font-family:var(--mono);
  font-size:12px;
  color:var(--accent);
  margin-top:8px;
  text-transform:lowercase;
}
.piece-desc{font-size:13px; color:var(--muted); margin-top:14px; max-width:34ch; line-height:1.6;}
/* sits directly underneath the description, in its own block — a clear
   step down (not squeezed right under it, not off to the side) */
.piece-links{margin-top:20px; display:flex; flex-direction:column; gap:6px; max-width:34ch;}
/* not a link — just tells the user the cover art itself is clickable */
.piece-hint{font-size:13px; font-weight:600; color:var(--text);}
.piece-link{
  font-size:13px;
  color:var(--text);
  text-decoration:underline;
  text-underline-offset:3px;
  text-decoration-color:var(--line);
  width:fit-content;
}
.piece-link:hover{color:var(--accent); text-decoration-color:var(--accent);}
.in-progress-note{margin-top:80px;}

@media(max-width:720px){
  .piece, .piece:nth-child(even){grid-template-columns:1fr;}
  .piece:nth-child(even) .piece-media{order:0;}
  .piece:nth-child(even) .piece-caption{order:0; text-align:left;}
  .piece:nth-child(even) .piece-desc,
  .piece:nth-child(even) .piece-links{margin-left:0;}
  .piece:nth-child(even) .piece-links{align-items:flex-start;}
}

/* lightbox */
.lightbox{
  position:fixed;
  inset:0;
  z-index:1100;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:40px 24px;
  opacity:0;
  transition:opacity 0.35s var(--ease);
}
.lightbox[hidden]{display:none;}
.lightbox.showing{opacity:1;}
.lightbox-backdrop{
  position:absolute;
  inset:0;
  background:rgba(11,11,10,0.88);
}
.lightbox-content{
  position:relative;
  z-index:1;
  width:100%;
  max-width:760px;
  transform:scale(0.96) translateY(10px);
  transition:transform 0.35s var(--ease);
}
.lightbox.showing .lightbox-content{transform:scale(1) translateY(0);}
.lightbox-media{
  width:100%;
  aspect-ratio:4/3;
  background:var(--bg-raised);
  border:1px solid var(--line);
  overflow:hidden;
  position:relative;
}
/* video gets no forced aspect-ratio at all here (unlike the 4:3 default
   meant for photos) — it renders at its own natural size, full frame,
   never cropped. An earlier version forced a 16:9 box, which was still
   an assumption about the source's shape rather than actually reading
   it, and any mismatch (or the cloned .about-mix-cover's own competing
   aspect-ratio) still cropped it */
.lightbox-media.lightbox-media--video{aspect-ratio:auto; background:#050505;}
.lightbox-media img{width:100%; height:100%; object-fit:cover; display:block;}
.lightbox-media video{width:100%; height:auto; object-fit:contain; display:block;}

/* glass "start/stop" scrub bar — shown whenever a video is playing,
   sits over the bottom edge of the video. .lightbox-video-controls is
   the original (Cinematography reels, inside the project lightbox);
   .video-scrub-controls is the same thing generalized for anywhere else
   a video needs it (project-piece demos, the DJing mix player's FL
   Studio clip) — same look, same auto-hide-on-inactivity behavior. */
.lightbox-video-controls,
.video-scrub-controls{
  position:absolute;
  left:16px;
  right:16px;
  bottom:16px;
  z-index:2;
  display:flex;
  align-items:center;
  gap:12px;
  padding:8px 14px 8px 8px;
  border-radius:999px;
  background:rgba(20,20,20,0.5);
  backdrop-filter:blur(14px);
  -webkit-backdrop-filter:blur(14px);
  opacity:1;
  transition:opacity 0.35s var(--ease-fast);
  border:1px solid rgba(255,255,255,0.18);
  box-shadow:0 8px 24px rgba(0,0,0,0.3);
}
.lightbox-video-controls[hidden],
.video-scrub-controls[hidden]{display:none;}
/* auto-hide after 2s of no mouse movement — toggled by js/script.js,
   fades out instead of disappearing abruptly, and never blocks clicks
   (or the seek drag) while faded since pointer-events goes with it */
.lightbox-video-controls.idle,
.video-scrub-controls.idle{opacity:0; pointer-events:none;}
.lightbox-video-toggle,
.video-scrub-toggle{
  flex-shrink:0;
  width:34px;
  height:34px;
  border-radius:50%;
  background:rgba(255,255,255,0.12);
  border:1px solid rgba(255,255,255,0.25);
  color:#fff;
  font-size:12px;
  cursor:pointer;
  display:flex;
  align-items:center;
  justify-content:center;
  transition:background 0.2s var(--ease-fast);
}
.lightbox-video-toggle:hover,
.video-scrub-toggle:hover{background:rgba(255,255,255,0.22);}

/* the "small scroll bar at the bottom of the video" — a native range
   input restyled into a slim glass-pill scrubber, shared look with
   .mini-seek below */
.lightbox-video-seek,
.video-scrub-seek{
  flex:1;
  -webkit-appearance:none;
  appearance:none;
  height:4px;
  border-radius:999px;
  background:rgba(255,255,255,0.25);
  cursor:pointer;
  outline:none;
}
.lightbox-video-seek::-webkit-slider-thumb,
.video-scrub-seek::-webkit-slider-thumb{
  -webkit-appearance:none;
  width:13px; height:13px;
  border-radius:50%;
  background:#fff;
  cursor:pointer;
  box-shadow:0 0 0 3px rgba(255,255,255,0.15);
}
.lightbox-video-seek::-moz-range-thumb,
.video-scrub-seek::-moz-range-thumb{
  width:13px; height:13px;
  border-radius:50%;
  background:#fff;
  border:none;
  cursor:pointer;
  box-shadow:0 0 0 3px rgba(255,255,255,0.15);
}
.lightbox-video-seek::-moz-range-track,
.video-scrub-seek::-moz-range-track{
  height:4px;
  border-radius:999px;
  background:rgba(255,255,255,0.25);
}
.lightbox-caption{margin-top:18px;}
.lightbox-title{font-size:18px; color:var(--text);}
.lightbox-medium{
  font-family:var(--mono);
  font-size:12px;
  color:var(--accent);
  margin-top:6px;
  text-transform:lowercase;
}
.lightbox-desc{font-size:13.5px; color:var(--muted); margin-top:10px; max-width:52ch;}
.lightbox-close{
  position:absolute;
  top:-40px;
  right:0;
  background:none;
  border:none;
  color:var(--muted);
  font-size:16px;
  cursor:pointer;
  transition:color 0.2s var(--ease-fast);
}
.lightbox-close:hover{color:var(--text);}

/* about page passion blocks */
.passion{
  padding:0;
  margin-bottom:32px;
}
.passion:last-child{margin-bottom:0;}
.passion-label{
  font-family:var(--mono);
  font-size:11px;
  color:var(--accent);
  margin-bottom:5px;
  text-transform:lowercase;
}
.passion-body{font-size:13px; color:var(--text); max-width:48ch;}

/* contact page */
.contact-list{display:flex; flex-direction:column; gap:26px; margin-top:8px;}
.contact-row{
  display:flex;
  justify-content:space-between;
  align-items:center;
}
.contact-label{font-size:12px; color:var(--accent); font-family:var(--mono);}
.contact-value{font-size:13px; color:var(--text); transition:color 0.2s var(--ease-fast);}
.contact-row:hover .contact-value{color:var(--muted);}

footer{
  border-top:1px solid var(--line);
  padding:24px 24px;
  font-size:13px;
  color:var(--muted);
  display:flex;
  justify-content:center;
  flex-shrink:0;
  width:100%;
}

/* about page — intentionally blank, rebuilding from scratch */

/* music gate — frosted glass carousel pre-page */
#music-gate{
  position:fixed;
  inset:0;
  z-index:1000;
  overflow:hidden;
  background:#f4f4f2;
  display:flex;
  align-items:center;
  justify-content:center;
  opacity:1;
  filter:blur(0px);
  transform:scale(1);
  transition:opacity 0.7s var(--ease), filter 0.7s var(--ease), transform 0.7s var(--ease);
}
#music-gate.fading{
  opacity:0;
  filter:blur(22px);
  transform:scale(1.08);
  pointer-events:none;
}
#music-gate[hidden]{display:none;}

.gate-bg{
  position:absolute;
  inset:0;
  overflow:hidden;
}
.gate-bg-layer{
  position:absolute;
  inset:-10%;
  background:linear-gradient(160deg, #ffffff, #eceae4);
  filter:blur(60px);
  transition:opacity 0.9s var(--ease);
}
.gate-bg-layer-a{opacity:1;}
.gate-bg-layer-b{opacity:0;}
.gate-bg-scrim{
  position:absolute;
  inset:0;
  background:linear-gradient(180deg, rgba(255,255,255,0.6) 0%, rgba(255,255,255,0.15) 35%, rgba(15,13,11,0.55) 65%, rgba(10,9,8,0.7) 100%);
}

.gate-content{
  position:relative;
  z-index:1;
  width:100%;
  max-width:720px;
  display:flex;
  flex-direction:column;
  align-items:center;
  padding:0 20px;
  transition:opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
#music-gate.fading .gate-content{opacity:0; transform:translateY(-14px);}

.gate-mark{
  font-family:var(--mono);
  font-size:13px;
  letter-spacing:0.08em;
  color:#3a3830;
  margin-bottom:48px;
}

.gate-carousel{
  display:flex;
  align-items:center;
  gap:16px;
  width:100%;
  overflow-x:auto;
  overflow-y:visible;
  scroll-snap-type:x mandatory;
  padding:40px calc(50% - 95px) 20px;
  scrollbar-width:none;
  perspective:1500px;
}
.gate-carousel::-webkit-scrollbar{display:none;}

/* .gate-card is the scroll-snap target and never gets a transform itself —
   mutating transform on a snap-aligned element causes erratic/uncontrolled
   re-snapping in some browsers. All visual motion lives on the child
   .gate-card-visual instead, which the snap machinery never looks at. */
.gate-card{
  flex:0 0 190px;
  scroll-snap-align:center;
  cursor:pointer;
  transform-style:preserve-3d;
}
.gate-card-visual{
  transition:opacity 0.15s linear;
  will-change:transform;
}
.gate-carousel.snapping .gate-card-visual{
  transition:transform 0.42s var(--ease), opacity 0.3s var(--ease);
}

.gate-art{
  position:relative;
  width:190px;
  height:190px;
  border-radius:14px;
  overflow:hidden;
  box-shadow:0 20px 40px rgba(0,0,0,0.22);
  border:1px solid rgba(0,0,0,0.08);
  background:var(--bg-raised);
}
.gate-art img{width:100%; height:100%; object-fit:cover; display:block;}
.gate-play{
  position:absolute;
  bottom:10px;
  right:10px;
  width:34px;
  height:34px;
  border-radius:50%;
  background:rgba(255,255,255,0.22);
  backdrop-filter:blur(8px);
  -webkit-backdrop-filter:blur(8px);
  border:1px solid rgba(255,255,255,0.4);
  color:#fff;
  font-size:12px;
  cursor:pointer;
  display:flex;
  align-items:center;
  justify-content:center;
  transition:background 0.2s var(--ease-fast);
}
.gate-play:hover{background:rgba(255,255,255,0.35);}
.gate-card-title{
  margin-top:12px;
  font-size:13.5px;
  font-weight:600;
  color:#22201a;
  text-align:center;
  opacity:0;
  transition:opacity 0.3s var(--ease);
}
.gate-card.active .gate-card-title{opacity:1;}
.gate-card-artist{
  font-size:11px;
  color:#6b6a5f;
  text-align:center;
  margin-top:2px;
  opacity:0;
  transition:opacity 0.3s var(--ease);
}
.gate-card.active .gate-card-artist{opacity:1;}

.gate-player{
  display:flex;
  align-items:center;
  gap:14px;
  width:100%;
  max-width:460px;
  margin-top:44px;
  padding:12px 16px;
  border-radius:999px;
  background:rgba(255,255,255,0.14);
  backdrop-filter:blur(16px);
  -webkit-backdrop-filter:blur(16px);
  border:1px solid rgba(255,255,255,0.28);
}
.gate-player-btn{
  background:none;
  border:none;
  color:rgba(255,255,255,0.85);
  font-size:14px;
  cursor:pointer;
  flex-shrink:0;
}
.gate-player-play{font-size:13px;}
.gate-player-info{flex:1; min-width:0;}
.gate-player-title{
  font-size:12.5px;
  font-weight:600;
  color:#fff;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.gate-player-artist{
  font-size:10.5px;
  color:rgba(255,255,255,0.6);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.gate-enter{
  flex-shrink:0;
  background:rgba(255,255,255,0.9);
  color:#1a1208;
  border:none;
  border-radius:999px;
  padding:8px 16px;
  font-size:12px;
  font-weight:700;
  cursor:pointer;
  transition:background 0.2s var(--ease-fast);
}
.gate-enter:hover{background:#fff;}

.gate-hint{
  font-size:11px;
  color:rgba(255,255,255,0.5);
  margin-top:22px;
  text-align:center;
}
.gate-skip{
  background:none;
  border:none;
  color:rgba(255,255,255,0.55);
  font-family:var(--mono);
  font-size:11.5px;
  margin-top:10px;
  cursor:pointer;
  text-decoration:underline;
  text-underline-offset:3px;
}
.gate-skip:hover{color:#fff;}

@media(max-width:520px){
  .gate-card{flex-basis:150px;}
  .gate-art{width:150px; height:150px;}
  .gate-carousel{padding:20px calc(50% - 75px);}
  .gate-player{flex-wrap:wrap; border-radius:24px;}
  .gate-enter{width:100%; order:5;}
}

/* mini player — a pill that expands into a square now-playing panel */
.mini-player{
  position:fixed;
  right:20px;
  bottom:20px;
  z-index:900;
  display:flex;
  align-items:center;
  border-radius:999px;
  background:rgba(240, 237, 230, 0.12);
  backdrop-filter:blur(12px);
  -webkit-backdrop-filter:blur(12px);
  border:1px solid rgba(240, 237, 230, 0.18);
  box-shadow:0 8px 24px rgba(0,0,0,0.25);
  opacity:0;
  transform:translateY(10px);
  overflow:hidden;
  transition:opacity 0.4s var(--ease), transform 0.4s var(--ease),
    width 0.35s var(--ease), height 0.35s var(--ease), border-radius 0.35s var(--ease);
}
.mini-player.showing{opacity:1; transform:translateY(0);}
.mini-player[hidden]{display:none;}

.mini-player-pill{
  display:flex;
  align-items:center;
  gap:12px;
  padding:10px 16px 10px 10px;
  cursor:pointer;
}
.mini-player.expanded .mini-player-pill{display:none;}

/* shown after skipping the gate — no track to toggle, so the play/pause
   icon is hidden and the whole pill exists only to reopen the gate */
.mini-player.no-track .mini-player-toggle{display:none;}
.mini-player.no-track .mini-player-pill{padding:10px 18px;}

.mini-player-toggle{
  width:30px;
  height:30px;
  border-radius:50%;
  background:rgba(240, 237, 230, 0.14);
  border:1px solid rgba(240, 237, 230, 0.2);
  color:var(--text);
  font-size:11px;
  cursor:pointer;
  display:flex;
  align-items:center;
  justify-content:center;
  transition:background 0.2s var(--ease-fast);
  flex-shrink:0;
}
.mini-player-toggle:hover{background:rgba(240, 237, 230, 0.26);}
.mini-player-title{
  font-family:var(--mono);
  font-size:11.5px;
  letter-spacing:0.02em;
  color:var(--text);
  max-width:160px;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}

.mini-player-expanded{
  display:none;
  flex-direction:column;
  align-items:center;
  width:240px;
  padding:20px;
  position:relative;
}
.mini-player.expanded .mini-player-expanded{display:flex;}
.mini-player.expanded{
  width:240px;
  height:340px;
  border-radius:20px;
  align-items:stretch;
}

.mini-collapse{
  position:absolute;
  top:10px;
  right:10px;
  background:none;
  border:none;
  color:var(--muted);
  font-size:13px;
  cursor:pointer;
  width:24px;
  height:24px;
  display:flex;
  align-items:center;
  justify-content:center;
  transition:color 0.2s var(--ease-fast);
}
.mini-collapse:hover{color:var(--text);}

.mini-art{
  width:100%;
  aspect-ratio:1/1;
  border-radius:12px;
  overflow:hidden;
  box-shadow:0 12px 30px rgba(0,0,0,0.3);
  margin-top:14px;
}
.mini-art img{width:100%; height:100%; object-fit:cover; display:block;}

.mini-expanded-title{
  font-size:13.5px;
  font-weight:600;
  color:var(--text);
  text-align:center;
  margin-top:16px;
}
.mini-expanded-artist{
  font-size:11px;
  color:var(--muted);
  text-align:center;
  margin-top:3px;
}

/* lets the user scrub through the background track, same restyled
   range-input treatment as .lightbox-video-seek */
.mini-seek{
  display:block;
  width:100%;
  margin-top:16px;
  -webkit-appearance:none;
  appearance:none;
  height:4px;
  border-radius:999px;
  background:rgba(240, 237, 230, 0.2);
  cursor:pointer;
  outline:none;
}
.mini-seek::-webkit-slider-thumb{
  -webkit-appearance:none;
  width:12px; height:12px;
  border-radius:50%;
  background:var(--text);
  cursor:pointer;
  box-shadow:0 0 0 3px rgba(240, 237, 230, 0.15);
}
.mini-seek::-moz-range-thumb{
  width:12px; height:12px;
  border-radius:50%;
  background:var(--text);
  border:none;
  cursor:pointer;
  box-shadow:0 0 0 3px rgba(240, 237, 230, 0.15);
}
.mini-seek::-moz-range-track{
  height:4px;
  border-radius:999px;
  background:rgba(240, 237, 230, 0.2);
}

.mini-controls{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:20px;
  margin-top:18px;
}
.mini-control-btn{
  background:none;
  border:none;
  color:var(--text);
  font-size:15px;
  cursor:pointer;
  transition:color 0.2s var(--ease-fast);
}
.mini-control-btn:hover{color:var(--accent);}
.mini-control-play{font-size:14px;}

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

/* about page — strict black & white palette, scoped to this page only */
#page-about{
  --bg: #000;
  --bg-raised: #0d0d0d;
  --text: #fff;
  --muted: #999;
  --line: #2a2a2a;
  --accent: #fff;
  background:var(--bg);
  color:var(--text);
}

.about-banner{
  position:relative;
  min-height:100vh;
  display:flex;
  align-items:center;
  justify-content:center;
  background-color:#0a0a0a;
  background-size:cover;
  background-position:center;
  overflow:hidden;
}
.about-banner-overlay{
  position:absolute;
  inset:0;
  /* fades the photo into the page's black background at the top and
     bottom edges only (a vertical gradient never varies left-to-right, so
     the sides stay a hard, untouched edge) — short enough that the
     transition still reads as a distinct edge, not a slow bleed */
  background:linear-gradient(180deg,
    #000 0%,
    rgba(0,0,0,0.55) 9%,
    rgba(0,0,0,0.55) 55%,
    rgba(0,0,0,0.75) 88%,
    #000 100%);
}
.about-banner-copy{
  position:relative;
  z-index:1;
  text-align:center;
}
.about-eyebrow{
  font-family:var(--mono);
  font-size:12px;
  letter-spacing:0.12em;
  text-transform:lowercase;
  color:#ccc;
  margin-bottom:18px;
}
.about-banner-title{
  font-family:Arial, Helvetica, sans-serif;
  font-weight:900;
  font-size:80px;
  letter-spacing:0.02em;
  color:#fff;
  margin:0;
  line-height:1;
}
.about-banner-sub{
  font-family:var(--mono);
  font-size:13px;
  letter-spacing:0.2em;
  text-transform:uppercase;
  color:#bbb;
  margin-top:16px;
}
.about-scroll-cue{
  font-family:var(--mono);
  font-size:11px;
  letter-spacing:0.08em;
  color:#888;
  margin-top:56px;
  animation:about-cue-bob 1.8s var(--ease) infinite;
}
@keyframes about-cue-bob{
  0%, 100%{transform:translateY(0); opacity:0.6;}
  50%{transform:translateY(6px); opacity:1;}
}

/* top-of-page intro, before the first category banner — gives the page
   breathing room and pushes DJing (and everything after it) down instead
   of opening straight into a full-bleed photo section */
.about-page-intro{
  padding:160px 0 72px;
  text-align:center;
  background:#000;
}
.about-page-intro-eyebrow{
  font-family:Arial, Helvetica, sans-serif;
  font-weight:900;
  font-size:13px;
  letter-spacing:0.3em;
  text-transform:uppercase;
  color:#fff;
  margin-bottom:20px;
}
.about-page-intro-title{
  font-family:Arial, Helvetica, sans-serif;
  font-weight:700;
  font-size:clamp(20px, 3vw, 32px);
  line-height:1.55;
  color:#e6e6e6;
  max-width:620px;
  margin:0 auto;
}

.about-category{position:relative; padding:100px 0 120px; overflow:hidden;}
/* Travel's grid left a lot of empty space before the Future banner —
   pull the next section up a bit without losing all the breathing room */
.about-category[data-category="travel"]{padding-bottom:56px;}
/* Future is just a heading + one paragraph — the shared category padding
   left a lot of empty space above and below it for no reason */
.about-category[data-category="future"]{padding:56px 0 80px;}

.about-intro-copy .section-title{color:#fff;}
.about-lede{font-size:14px; line-height:1.8; color:var(--muted); max-width:52ch;}
/* Travel/Future are just a heading + a paragraph of body copy right
   under it — the shared .section-title margin-bottom (28px, tuned for
   headings that sit above a full grid/gallery) left too much air between
   the heading and its own text here, so these two pull it in tighter */
.about-category[data-category="travel"] .about-intro-copy .section-title,
.about-category[data-category="future"] .about-intro-copy .section-title{
  margin-bottom:14px;
}

/* DJing's (and Travel's/Future's) bio copy — centered, no side art */
.about-intro-copy--center{
  text-align:center;
  max-width:640px;
  margin:0 auto;
}
.about-intro-copy--center .about-lede{margin:0 auto;}

/* Cinematography: bio on the left, the film-strip photo filling the other
   half of the section on the right — a static, real two-column layout
   (no bounce, no absolute positioning) so the two never overlap regardless
   of copy length. mix-blend-mode:screen keeps the same black-background
   isolation trick used elsewhere on this page. */
.about-cinema-hero{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:64px;
  align-items:center;
}
.about-cinema-roll{
  width:100%;
}
.about-cinema-roll img{
  width:100%;
  display:block;
  mix-blend-mode:screen;
}

/* about page — djing mix gallery */
.about-mixes-wrap{margin-top:96px;}
.about-mix-grid{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(240px, 1fr));
  gap:32px;
  margin-top:32px;
}
.about-mix-card{
  cursor:pointer;
  opacity:0;
  transform:translateY(16px);
  transition:opacity 0.6s var(--ease), transform 0.6s var(--ease);
}
.about-mix-card.in-view{opacity:1; transform:translateY(0);}
.about-mix-cover{
  position:relative;
  aspect-ratio:1/1;
  border-radius:14px;
  overflow:hidden;
  background:rgba(255,255,255,0.05);
  backdrop-filter:blur(16px);
  -webkit-backdrop-filter:blur(16px);
  border:1px dashed rgba(255,255,255,0.18);
  display:flex;
  align-items:center;
  justify-content:center;
  transition:border-color 0.3s var(--ease-fast), background 0.3s var(--ease-fast);
}
.about-mix-card:hover .about-mix-cover{border-color:rgba(255,255,255,0.4); background:rgba(255,255,255,0.08);}
.about-mix-cover img,
.about-mix-cover video{width:100%; height:100%; object-fit:cover; display:block; position:absolute; inset:0;}
/* real video, not a placeholder — solid border instead of the dashed
   "nothing here yet" style used by empty cards. No forced aspect-ratio
   box at all here (unlike the square/16:9 versions tried earlier) — the
   video is taken out of the absolute-fill/object-fit:cover treatment
   entirely and just rendered at its own natural size, so it is never
   cropped regardless of what its real aspect ratio turns out to be. */
.about-mix-cover--video{
  aspect-ratio:auto;
  border-style:solid;
  cursor:pointer;
}
.about-mix-cover--video video{
  position:static;
  width:100%;
  height:auto;
  object-fit:contain;
}
.about-mix-placeholder-label{
  font-family:var(--mono);
  font-size:11px;
  letter-spacing:0.06em;
  text-transform:lowercase;
  color:var(--muted);
}
.about-mix-play{
  position:absolute;
  bottom:12px;
  right:12px;
  width:38px;
  height:38px;
  border-radius:50%;
  background:rgba(255,255,255,0.1);
  border:1px solid rgba(255,255,255,0.2);
  color:#fff;
  font-size:13px;
  display:flex;
  align-items:center;
  justify-content:center;
  cursor:not-allowed;
  opacity:0.5;
}
.about-mix-play:not([disabled]){
  cursor:pointer;
  opacity:0.85;
  transition:opacity 0.2s var(--ease-fast), background 0.2s var(--ease-fast);
}
.about-mix-play:not([disabled]):hover{opacity:1; background:rgba(255,255,255,0.2);}

/* default vinyl graphic standing in for a mix cover — grooves via a
   repeating radial gradient, a colored label dot in the center. Pure
   CSS, no image/canvas — same graphic is reused (scaled up) inside the
   mix player overlay below. */
.about-mix-cover--vinyl{background:radial-gradient(circle at 30% 25%, #1c1c1c, #050505 70%); cursor:pointer;}
.mix-vinyl-icon{
  position:relative;
  width:72%;
  aspect-ratio:1/1;
  border-radius:50%;
  background:
    radial-gradient(circle at center, #c23a24 0%, #c23a24 8%, transparent 8.6%, transparent 100%),
    repeating-radial-gradient(circle at center, #232323 0px, #232323 2px, #101010 2px, #101010 5px);
  box-shadow:0 14px 32px rgba(0,0,0,0.55), inset 0 0 0 1px rgba(255,255,255,0.06);
}
.mix-vinyl-icon-label{
  position:absolute;
  top:50%; left:50%;
  width:6%;
  aspect-ratio:1/1;
  transform:translate(-50%,-50%);
  border-radius:50%;
  background:#050505;
}
.about-mix-title{margin-top:14px; font-size:13.5px; font-weight:600; color:#fff;}
.about-mix-meta{
  font-family:var(--mono);
  font-size:11px;
  color:var(--muted);
  margin-top:4px;
  text-transform:lowercase;
}

.about-mixes-wrap--center{text-align:center;}
.about-mixes-wrap--center .about-lede{margin:0 auto;}

/* travel — click/tap or Enter/Space opens #travel-viewer (see below) with
   the real photo, no clone, so it can FLIP smoothly back into place. */
.about-travel-grid{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(260px, 1fr));
  gap:32px;
  margin-top:32px;
  text-align:left;
}
.about-travel-card{
  cursor:pointer;
  opacity:0;
  transform:translateY(16px);
  transition:opacity 0.6s var(--ease), transform 0.6s var(--ease);
}
.about-travel-card.in-view{opacity:1; transform:translateY(0);}
/* flush — no border, no background box, no letterboxing. The frame just
   matches a fixed 4:3 grid shape (object-fit:cover) so the grid itself
   reads as a clean, consistent layout; the full uncropped photo is what
   shows in the expanded viewer instead */
.about-travel-cover{
  position:relative;
  aspect-ratio:4/3;
  border-radius:14px;
  overflow:hidden;
}
.about-travel-cover img{
  width:100%; height:100%;
  object-fit:cover;
  display:block;
  position:absolute; inset:0;
  transition:transform 0.5s var(--ease-fast);
}
.about-travel-card:hover .about-travel-cover img{transform:scale(1.05);}
.about-travel-summary{margin-top:14px; display:flex; align-items:baseline; justify-content:space-between; gap:12px;}
/* .about-travel-detail is never shown in place any more — it's just
   where each card's description text lives, read by openTravelViewer()
   in js/script.js and shown in #travel-viewer's side panel instead */
.about-travel-detail{display:none;}

/* travel photo viewer — full-viewport overlay. js/script.js FLIP-moves
   the clicked card's real <img> into #travel-viewer-photo (a fixed,
   larger, left-of-center slot) and back again on close; only a single
   .opened class drives fade/slide-in here since there's no intermediate
   state like the DJing mix player's .side-by-side. */
.travel-viewer{position:fixed; inset:0; z-index:960;}
.travel-viewer[hidden]{display:none;}
.travel-viewer-backdrop{
  position:absolute;
  inset:0;
  background:rgba(0,0,0,0.8);
  opacity:0;
  pointer-events:none;
  transition:opacity 0.5s var(--ease);
}
.travel-viewer.opened .travel-viewer-backdrop{opacity:1; pointer-events:auto;}

/* the blurred wash of the currently-viewed photo, behind everything */
.travel-viewer-bg-blur{
  position:absolute;
  inset:-5%;
  background-size:cover;
  background-position:center;
  filter:blur(70px) brightness(0.45) saturate(1.3);
  opacity:0;
  transition:opacity 0.7s var(--ease);
  pointer-events:none;
}
.travel-viewer.opened .travel-viewer-bg-blur{opacity:0.65;}

.travel-viewer-stage{position:relative; width:100%; height:100%; pointer-events:none;}

.travel-viewer-close{
  position:absolute;
  top:24px; right:24px;
  width:40px; height:40px;
  border-radius:50%;
  background:rgba(255,255,255,0.08);
  border:1px solid rgba(255,255,255,0.2);
  color:#fff;
  font-size:15px;
  cursor:pointer;
  opacity:0;
  pointer-events:none;
  transition:opacity 0.3s var(--ease-fast);
  z-index:2;
}
.travel-viewer.opened .travel-viewer-close{opacity:1; pointer-events:auto;}

.travel-viewer-photo{
  position:fixed;
  top:50%;
  left:calc(50% - 170px);
  width:520px;
  height:390px;
  max-width:52vw;
  max-height:66vh;
  transform:translate(-50%, -50%);
  border-radius:14px;
  overflow:hidden;
  box-shadow:0 30px 80px rgba(0,0,0,0.65);
  background:#050505;
  opacity:0;
  transition:opacity 0.4s var(--ease);
}
/* fades out with everything else on close instead of sitting there as a
   solid dark box once the real <img> has already FLIPed back to its
   card — it used to have no opacity transition at all, so it stayed
   fully visible (a "stuck black box") until the whole overlay force-hid
   itself half a second later */
.travel-viewer.opened .travel-viewer-photo{opacity:1;}
.travel-viewer-photo img{width:100%; height:100%; object-fit:contain; display:block;}

.travel-viewer-panel{
  position:absolute;
  top:50%;
  left:calc(50% + 220px);
  width:320px;
  max-width:30vw;
  transform:translateY(-50%) translateX(24px);
  opacity:0;
  transition:opacity 0.5s var(--ease) 0.15s, transform 0.5s var(--ease) 0.15s;
  pointer-events:none;
}
.travel-viewer.opened .travel-viewer-panel{opacity:1; transform:translateY(-50%) translateX(0);}
.travel-viewer-title{font-family:Arial, Helvetica, sans-serif; font-weight:700; font-size:22px; color:#fff;}
.travel-viewer-meta{font-family:var(--mono); font-size:12px; color:#999; margin-top:6px; text-transform:lowercase;}
.travel-viewer-desc{font-size:14px; line-height:1.85; color:#ccc; margin:16px 0 0;}

@media(max-width:860px){
  .travel-viewer-photo{
    left:50%;
    top:42%;
    width:80vw;
    height:auto;
    max-width:80vw;
    max-height:45vh;
    aspect-ratio:4/3;
  }
  .travel-viewer-panel{
    left:50%;
    top:auto;
    bottom:8%;
    width:80vw;
    max-width:80vw;
    transform:translateX(-50%) translateY(16px);
    text-align:center;
  }
  .travel-viewer.opened .travel-viewer-panel{transform:translateX(-50%) translateY(0);}
}

/* audio-reactive border — frames the whole DJing section, not just a
   corner widget. js/script.js writes --djing-border-w/--djing-border-a
   every frame from live Web Audio frequency data (or a gentle idle pulse
   when nothing is playing) directly onto .about-category.djing, so this
   is a single pseudo-element repaint per frame, no per-orb DOM elements. */
.about-category.djing{
  --djing-border-w: 2px;
  --djing-border-a: 0.25;
  --djing-glow: 8px;
}
.about-djing-border{
  position:absolute;
  inset:0;
  pointer-events:none;
  z-index:6;
  box-shadow:
    inset 0 0 0 var(--djing-border-w) rgba(255,255,255,var(--djing-border-a)),
    inset 0 0 var(--djing-glow) rgba(255,255,255,calc(var(--djing-border-a) * 0.6));
}

/* DJing mix player — a full-viewport overlay opened by clicking a mix's
   vinyl. js/script.js FLIP-moves the card's own .mix-vinyl-icon into
   #mix-player-vinyl (and back again on close) and drives states via
   classes on .mix-player:
     .opened          — vinyl has arrived, large and centered; a
                        "click to play" hint shows, centered near the top
     .playing         — added when the user clicks the vinyl: the mix
                        itself starts (ducking the background track via
                        the same generic play/pause/ended delegation the
                        Cinematography reels use — #mix-audio is just
                        another non-background element)
     .side-by-side    — added 2s into .playing: the vinyl shrinks and
                        moves to the left, the FL Studio clip slides in
                        from the right to take the spot the vinyl used
                        to occupy. Both stay fully visible together as
                        the overlay's two main components — this never
                        fades to a mini corner icon or lets the page
                        become interactive again; it's a still-modal
                        two-up "now playing" view for as long as the mix
                        keeps going. (An earlier version also spun the
                        vinyl continuously here — removed after it kept
                        stuttering at the start of the animation before
                        settling into a clean spin, and turned out not
                        to be needed for the interaction to read well.)
   Only the ✕ (or the backdrop, before playback starts) closes the
   player — audio/video stop, and the vinyl FLIPs smoothly back into the
   exact card slot it came from. */
.mix-player{
  position:fixed;
  inset:0;
  z-index:950;
  --mix-border-w: 0px;
  --mix-border-a: 0;
  --mix-glow: 0px;
}
.mix-player[hidden]{display:none;}
/* the same audio-reactive border technique as the page's DJing section
   (.about-djing-border), reacting to the mix's own audio instead of the
   background track — only visible once a mix is actually playing */
.mix-player-border{
  position:fixed;
  inset:0;
  pointer-events:none;
  z-index:1;
  box-shadow:
    inset 0 0 0 var(--mix-border-w) rgba(255,255,255,var(--mix-border-a)),
    inset 0 0 var(--mix-glow) rgba(255,255,255,calc(var(--mix-border-a) * 0.6));
}
.mix-player-backdrop{
  position:absolute;
  inset:0;
  background:rgba(0,0,0,0.82);
  opacity:0;
  pointer-events:none;
  transition:opacity 0.5s var(--ease);
}
.mix-player.opened .mix-player-backdrop{opacity:1; pointer-events:auto;}

.mix-player-stage{position:relative; width:100%; height:100%; pointer-events:none;}

.mix-player-close{
  position:absolute;
  top:24px; right:24px;
  width:40px; height:40px;
  border-radius:50%;
  background:rgba(255,255,255,0.08);
  border:1px solid rgba(255,255,255,0.2);
  color:#fff;
  font-size:15px;
  cursor:pointer;
  opacity:0;
  pointer-events:none;
  transition:opacity 0.3s var(--ease-fast);
  z-index:2;
}
.mix-player.opened .mix-player-close{opacity:1; pointer-events:auto;}

/* the landing slot the real vinyl icon is FLIP-moved into. top/left here
   are always the box's own top-left corner (never a self-centering -50%
   transform mixed with viewport-relative offsets — that combination
   silently pushed an earlier "dock to the corner" version off-screen) */
.mix-player-vinyl{
  position:fixed;
  top:calc(50% - 210px);
  left:calc(50% - 210px);
  width:420px;
  height:420px;
  max-width:60vw;
  max-height:60vw;
  opacity:0;
  transition:top 1.1s cubic-bezier(0.16,1,0.3,1), left 1.1s cubic-bezier(0.16,1,0.3,1),
    width 1.1s cubic-bezier(0.16,1,0.3,1), height 1.1s cubic-bezier(0.16,1,0.3,1),
    opacity 0.5s var(--ease);
  pointer-events:none;
}
.mix-player-vinyl .mix-vinyl-icon{width:100%; height:100%;}
/* pointer-events:auto here is what makes the vinyl clickable to actually
   start playback — without it, clicks on the "opened, not yet playing"
   vinyl fell through to the backdrop behind it and closed the player
   instead, which looked like clicking the vinyl just sent it back */
.mix-player.opened .mix-player-vinyl{opacity:1; pointer-events:auto; cursor:pointer;}
.mix-player.side-by-side .mix-player-vinyl{
  top:calc(50% - 130px);
  left:calc(50% - 380px);
  width:260px;
  height:260px;
  max-width:34vw;
  max-height:34vw;
}

/* subtle invitation to start playback, shown only in the brief window
   after the vinyl arrives and before the user clicks it */
.mix-player-hint{
  position:absolute;
  top:56px;
  left:50%;
  transform:translateX(-50%);
  font-family:var(--mono);
  font-size:12px;
  letter-spacing:0.1em;
  text-transform:lowercase;
  color:#aaa;
  opacity:0;
  transition:opacity 0.4s var(--ease-fast);
  pointer-events:none;
  animation:about-cue-bob 1.8s var(--ease) infinite;
}
.mix-player.opened:not(.playing) .mix-player-hint{opacity:1;}

/* the card the vinyl was borrowed from — a quiet empty state, not a
   jarring hole, while its vinyl is off playing in the overlay */
.about-mix-cover--vinyl.mix-vinyl-borrowed{background:rgba(255,255,255,0.03);}

/* takes over the vinyl's old spot once .side-by-side kicks in — no
   forced aspect-ratio, same "never crop the source" approach as the
   Cinematography reels, since a screen recording's real shape isn't
   known ahead of time */
.mix-player-flvideo{
  position:absolute;
  top:50%;
  left:calc(50% - 40px);
  width:600px;
  max-width:56vw;
  max-height:64vh;
  border-radius:12px;
  overflow:hidden;
  background:#050505;
  box-shadow:0 30px 70px rgba(0,0,0,0.6);
  opacity:0;
  transform:translateY(-50%) translateX(60px);
  transition:opacity 0.6s var(--ease), transform 0.6s var(--ease);
  pointer-events:none;
}
.mix-player-flvideo video{width:100%; height:auto; max-height:64vh; object-fit:contain; display:block;}
.mix-player.flvideo-visible .mix-player-flvideo{opacity:1; transform:translateY(-50%) translateX(0);}

.mix-player-info{
  position:absolute;
  left:50%;
  bottom:6%;
  transform:translateX(-50%);
  text-align:center;
  opacity:0;
  transition:opacity 0.5s var(--ease);
  pointer-events:none;
}
.mix-player.opened .mix-player-info{opacity:1;}
.mix-player-title{font-family:Arial, Helvetica, sans-serif; font-weight:700; font-size:20px; color:#fff;}
.mix-player-meta{font-family:var(--mono); font-size:12px; color:#999; margin-top:6px; text-transform:lowercase;}

@media(max-width:900px){
  .mix-player.side-by-side .mix-player-vinyl{
    top:calc(50% - 240px);
    left:calc(50% - 90px);
    width:180px;
    height:180px;
    max-width:50vw;
    max-height:50vw;
  }
  .mix-player-flvideo{left:50%; top:calc(50% + 60px); width:80vw; max-width:80vw; transform:translate(-50%, 0) translateY(30px);}
  .mix-player.flvideo-visible .mix-player-flvideo{transform:translate(-50%, 0) translateY(0);}
}

@media(max-width:720px){
  .mix-player-vinyl{top:calc(50% - 140px); left:calc(50% - 140px); width:280px; height:280px;}
}

@media(max-width:720px){
  .about-banner-title{font-size:48px;}
  .about-lede{margin:0 auto;}
  .about-cinema-hero{grid-template-columns:1fr; text-align:center; gap:32px;}
  .about-cinema-hero .about-cinema-roll{order:-1;}
}

@media(max-width:520px){
  h1{font-size:30px;}
  .header-inner{align-items:flex-start;}
  nav{gap:16px;}
  .row{flex-direction:column; gap:2px;}
  .contact-row{flex-direction:column; align-items:flex-start; gap:4px;}
  .poster-name{font-size:30px;}
}

/* Objectify case-study viewer — a full-viewport overlay opened by
   clicking that project's own thumbnail (not the generic project
   lightbox). js/script.js FLIP-moves the real <img> (not a clone) into
   #objectify-viewer-hero and back again on close. Two classes drive it:
     .opened   — the image has grown in
     .revealed — added ~700ms later: the image shrinks (a max-height
                 transition, not a transform, so the flex column simply
                 re-centers around the now-shorter image — reading as
                 "the image moves up" as a natural side effect rather
                 than a hand-choreographed second animation) while the
                 two sphere viewers fade in below it and get their
                 Three.js scenes created for the first time (lazily, and
                 only once actually visible/sized — creating a WebGL
                 context inside a still-hidden container has corrupted
                 the canvas permanently on some GPUs in earlier features
                 on this site). */
.objectify-viewer{position:fixed; inset:0; z-index:970;}
.objectify-viewer[hidden]{display:none;}
.objectify-viewer-backdrop{
  position:absolute;
  inset:0;
  background:rgba(0,0,0,0.85);
  opacity:0;
  pointer-events:none;
  transition:opacity 0.5s var(--ease);
}
.objectify-viewer.opened .objectify-viewer-backdrop{opacity:1; pointer-events:auto;}

.objectify-viewer-stage{
  position:relative;
  width:100%;
  height:100%;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:28px;
  padding:90px 24px 48px;
  overflow-y:auto;
}

.objectify-viewer-close{
  position:fixed;
  top:24px; right:24px;
  width:40px; height:40px;
  border-radius:50%;
  background:rgba(255,255,255,0.08);
  border:1px solid rgba(255,255,255,0.2);
  color:#fff;
  font-size:15px;
  cursor:pointer;
  opacity:0;
  pointer-events:none;
  transition:opacity 0.3s var(--ease-fast);
  z-index:2;
}
.objectify-viewer.opened .objectify-viewer-close{opacity:1; pointer-events:auto;}

.objectify-viewer-hero{
  width:min(640px, 80vw);
  max-height:60vh;
  opacity:0;
  transform:scale(0.85);
  border-radius:14px;
  overflow:hidden;
  background:#f4f2ec;
  box-shadow:0 30px 80px rgba(0,0,0,0.55);
  flex-shrink:0;
  transition:opacity 0.5s var(--ease), transform 0.6s var(--ease), max-height 0.7s var(--ease);
}
.objectify-viewer-hero img{width:100%; height:100%; object-fit:contain; display:block;}
.objectify-viewer.opened .objectify-viewer-hero{opacity:1; transform:scale(1);}
.objectify-viewer.revealed .objectify-viewer-hero{max-height:220px;}

.objectify-viewer-spheres{
  display:flex;
  gap:28px;
  flex-wrap:wrap;
  justify-content:center;
  opacity:0;
  transform:translateY(16px);
  transition:opacity 0.5s var(--ease) 0.1s, transform 0.5s var(--ease) 0.1s;
  pointer-events:none;
}
.objectify-viewer.revealed .objectify-viewer-spheres{opacity:1; transform:translateY(0); pointer-events:auto;}

.objectify-sphere-card{
  width:min(320px, 42vw);
  display:flex;
  flex-direction:column;
  align-items:center;
}
.objectify-sphere-title{
  font-family:var(--mono);
  font-size:12px;
  letter-spacing:0.08em;
  text-transform:lowercase;
  color:#999;
  margin-bottom:10px;
}
.objectify-sphere-canvas{
  position:relative;
  width:100%;
  aspect-ratio:1/1;
  border-radius:14px;
  overflow:hidden;
  background:radial-gradient(circle at 35% 30%, #1c1c1c, #050505 75%);
  cursor:grab;
}
.objectify-sphere-canvas:active{cursor:grabbing;}
.objectify-sphere-canvas canvas{display:block; width:100% !important; height:100% !important;}
.objectify-sphere-hint{
  margin-top:10px;
  font-family:var(--mono);
  font-size:11px;
  color:#777;
  letter-spacing:0.06em;
}

@media(max-width:640px){
  .objectify-viewer-stage{padding:80px 16px 32px; gap:20px;}
  .objectify-sphere-card{width:min(280px, 80vw);}
}

/* Reusable project cover → demo video viewer — same choreography as the
   Objectify viewer above, generalized for any project that has a cover
   image + demo clip (marked data-video-piece / data-demo-src). One
   shared overlay, so a new project with a demo needs zero new CSS/JS. */
.piece-viewer{position:fixed; inset:0; z-index:970;}
.piece-viewer[hidden]{display:none;}
.piece-viewer-backdrop{
  position:absolute;
  inset:0;
  background:rgba(0,0,0,0.85);
  opacity:0;
  pointer-events:none;
  transition:opacity 0.5s var(--ease);
}
.piece-viewer.opened .piece-viewer-backdrop{opacity:1; pointer-events:auto;}

.piece-viewer-stage{
  position:relative;
  width:100%;
  height:100%;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:28px;
  padding:90px 24px 48px;
  overflow-y:auto;
}

.piece-viewer-close{
  position:fixed;
  top:24px; right:24px;
  width:40px; height:40px;
  border-radius:50%;
  background:rgba(255,255,255,0.08);
  border:1px solid rgba(255,255,255,0.2);
  color:#fff;
  font-size:15px;
  cursor:pointer;
  opacity:0;
  pointer-events:none;
  transition:opacity 0.3s var(--ease-fast);
  z-index:2;
}
.piece-viewer.opened .piece-viewer-close{opacity:1; pointer-events:auto;}

.piece-viewer-hero{
  width:min(640px, 80vw);
  max-height:60vh;
  opacity:0;
  transform:scale(0.85);
  border-radius:14px;
  overflow:hidden;
  background:#f4f2ec;
  box-shadow:0 30px 80px rgba(0,0,0,0.55);
  flex-shrink:0;
  transition:opacity 0.5s var(--ease), transform 0.6s var(--ease), max-height 0.7s var(--ease);
}
.piece-viewer-hero img{width:100%; height:100%; object-fit:contain; display:block;}
.piece-viewer.opened .piece-viewer-hero{opacity:1; transform:scale(1);}
.piece-viewer.revealed .piece-viewer-hero{max-height:180px;}

.piece-viewer-demo{
  position:relative;
  width:min(880px, 90vw);
  max-height:66vh;
  border-radius:14px;
  overflow:hidden;
  background:#050505;
  box-shadow:0 30px 80px rgba(0,0,0,0.6);
  opacity:0;
  transform:translateY(16px);
  transition:opacity 0.5s var(--ease) 0.1s, transform 0.5s var(--ease) 0.1s;
  pointer-events:none;
}
.piece-viewer-demo video{width:100%; height:100%; max-height:66vh; object-fit:contain; display:block;}
.piece-viewer.revealed .piece-viewer-demo{opacity:1; transform:translateY(0); pointer-events:auto;}

@media(max-width:640px){
  .piece-viewer-stage{padding:80px 16px 32px; gap:20px;}
}
