/* James Bartolozzi — portfolio */
@font-face{font-family:'Gangster';src:url('../fonts/GangsterGrotesk-Light.otf') format('opentype');font-weight:300;font-display:swap}
@font-face{font-family:'Gangster';src:url('../fonts/GangsterGrotesk-Regular.otf') format('opentype');font-weight:400;font-display:swap}
@font-face{font-family:'Gangster';src:url('../fonts/GangsterGrotesk-Bold.otf') format('opentype');font-weight:700;font-display:swap}

:root{
  --bg:#000; --fg:#fff; --dim:#8a8a8a; --line:#1e1e1e; --hl:#fff;
  --pad:clamp(1.25rem,4vw,3.5rem);
  --gap:clamp(.75rem,1.6vw,1.5rem);
  /* container matches NYT's 1200px; prose ~600px is their reading measure */
  --maxw:1200px; --prose:48ch;
  --ease:cubic-bezier(.22,.61,.36,1);
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--bg); color:var(--fg);
  font-family:'Gangster',system-ui,-apple-system,'Helvetica Neue',sans-serif;
  font-weight:400; line-height:1.6;
  font-size:clamp(1rem,.55vw + .87rem,1.125rem);
  -webkit-font-smoothing:antialiased;
}
img,video{max-width:100%;height:auto;display:block}
a{color:inherit;text-decoration:none}
.skip{position:absolute;left:-9999px}
.skip:focus{left:var(--pad);top:.5rem;z-index:100;background:#fff;color:#000;padding:.5rem .9rem}
:focus-visible{outline:2px solid #fff;outline-offset:3px}

/* ---------- nav ---------- */
.nav{
  position:sticky;top:0;z-index:50;
  display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding:1rem var(--pad);
  background:rgba(0,0,0,.72);backdrop-filter:blur(14px);
  border-bottom:1px solid var(--line);
}
.brand{font-weight:700;letter-spacing:-.01em;font-size:1.05rem}
.menu{display:flex;gap:clamp(1rem,2vw,2rem);flex-wrap:wrap}
.menu a{font-size:.92rem;color:var(--dim);transition:color .25s var(--ease);position:relative}
.menu a:hover,.menu a.on{color:var(--fg)}
.menu a.on::after{content:"";position:absolute;left:0;right:0;bottom:-4px;height:1px;background:currentColor}
.menu-btn{display:none;background:none;border:0;padding:.5rem;cursor:pointer;width:40px}
.menu-btn span{display:block;height:1.5px;background:#fff;margin:5px 0;transition:transform .3s var(--ease),opacity .3s var(--ease)}
.menu-btn[aria-expanded="true"] span:first-child{transform:translateY(3.25px) rotate(45deg)}
.menu-btn[aria-expanded="true"] span:last-child{transform:translateY(-3.25px) rotate(-45deg)}

/* ---------- layout ---------- */
main{max-width:var(--maxw);margin:0 auto;padding:0 var(--pad)}
.intro{padding:clamp(3rem,9vw,7rem) 0 clamp(2rem,5vw,3.5rem)}
.intro h1{
  font-weight:700;letter-spacing:-.025em;line-height:1.08;margin:0 0 1rem;
  font-size:clamp(1.9rem,4.6vw,3.6rem);max-width:17ch;
}
.intro p{color:var(--dim);margin:0;max-width:52ch;font-size:clamp(.95rem,.4vw + .85rem,1.06rem)}

/* ---------- project grid ---------- */
.grid{
  display:grid;gap:var(--gap);
  grid-template-columns:repeat(3,1fr);
  padding:clamp(1.5rem,4vw,2.75rem) 0 clamp(3rem,8vw,6rem);
}
.card{position:relative;display:block;overflow:hidden;background:#0b0b0b;aspect-ratio:16/10}
.card img{width:100%;height:100%;object-fit:cover;
  transition:transform .7s var(--ease),opacity .45s var(--ease);opacity:.92}
.card:hover img,.card:focus-visible img{transform:scale(1.04);opacity:.42}
.card-title{
  position:absolute;inset:0;margin:0;display:grid;place-items:center;
  padding:1rem;text-align:center;
  font-size:clamp(1.05rem,1.5vw,1.45rem);font-weight:700;letter-spacing:-.015em;
  color:#fff;opacity:0;transition:opacity .35s var(--ease);
  background:linear-gradient(to top,rgba(0,0,0,.55),rgba(0,0,0,.15));
}
.card-title span{transform:translateY(6px);transition:transform .35s var(--ease)}
.card:hover .card-title,.card:focus-visible .card-title{opacity:1}
.card:hover .card-title span,.card:focus-visible .card-title span{transform:none}

/* No hover (touch): titles are always visible, since hover can't reveal them. */
@media (hover:none){
  .card img{opacity:.6}
  .card-title{opacity:1}
  .card-title span{transform:none}
}

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---------- app header ---------- */
.appbar{
  display:grid;grid-template-columns:auto 1fr;
  gap:clamp(1.25rem,3.5vw,2.5rem);align-items:start;
  padding-bottom:clamp(1.75rem,4vw,2.75rem);
  border-bottom:1px solid var(--line);
}
/* icons already carry their own squircle and alpha -- no radius, no background */
.appicon{width:clamp(76px,9vw,116px);height:auto}
.apptag{max-width:var(--prose)}
.apptag p{margin:0;color:#c9c9c9;font-size:clamp(1.02rem,.5vw + .92rem,1.2rem);line-height:1.5}
.applinks{display:flex;flex-wrap:wrap;align-items:center;gap:.75rem 1.5rem;margin-top:1.4rem}
.applink{display:inline-flex;align-items:center;gap:.55rem;
  font-size:1.02rem;font-weight:700;letter-spacing:-.01em;
  color:#d6d6d6;transition:color .25s var(--ease)}
.applink:hover,.applink:focus-visible{color:var(--fg)}
.applink span{border-bottom:1px solid #4a4a4a;padding-bottom:1px;
  transition:border-color .25s var(--ease)}
.applink:hover span,.applink:focus-visible span{border-color:currentColor}
.applink svg{width:19px;height:19px;flex:none}
/* Apple ships the badge black-on-transparent; inverting gives their white variant */
.badge{display:inline-flex;line-height:0}
.badge img{height:42px;width:auto;filter:invert(1)}

/* ---------- project page ---------- */
.project{display:flex;flex-direction:column;gap:clamp(2.5rem,6.5vw,5.5rem);
  padding-bottom:clamp(3rem,8vw,6rem)}
.phead{padding:clamp(3rem,8vw,6rem) 0 clamp(1.25rem,3vw,2rem);
  border-bottom:1px solid var(--line)}
.phead h1{margin:0;font-weight:700;letter-spacing:-.025em;line-height:1.05;
  font-size:clamp(2rem,5.5vw,4.2rem)}

.prose{display:flex;flex-direction:column;gap:1.15rem;max-width:var(--prose)}
/* a text block with no paired image spans the full content width */
.prose.full{max-width:none}
.prose h3{margin:.5rem 0 0;font-weight:700;letter-spacing:-.015em;
  font-size:clamp(1.2rem,2vw,1.6rem)}
.prose p{margin:0;color:#c9c9c9}
.prose ul{margin:0;padding-left:1.15rem;color:#c9c9c9;
  display:flex;flex-direction:column;gap:.45rem}
.prose a{color:#fff;text-decoration:underline;text-decoration-color:#555;
  text-underline-offset:3px;transition:text-decoration-color .25s var(--ease)}
.prose a:hover{text-decoration-color:#fff}

/* text block layouts: full (default) | left | right — which side the image sits on */
.split{
  display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(1.25rem,3vw,2.75rem);align-items:center;
}
.split .prose{max-width:none}
.split-media{margin:0;background:#0b0b0b;overflow:hidden}
.split-media img,.split-media video{width:100%;display:block}
/* a portrait clip at half-column width runs taller than the paragraph beside it,
   so cap it by height instead and centre it in its half */
.split-media.tall{background:none;display:flex;justify-content:center}
.split-media.tall img,.split-media.tall video{
  width:auto;max-height:clamp(300px,38vw,460px);background:#0b0b0b}
/* DOM order is always image-then-text; `right` flips it visually only */
.split-right .split-media{order:2}

/* worked-at strip: centred at the top of the bio column, above the paragraphs */
.logos{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:clamp(1.5rem,3vw,2.5rem);
  margin:0 0 .35rem;padding:.35rem 0;
}
.logos img{
  height:clamp(15px,1.65vw,21px);width:auto;max-width:none;flex:none;
  opacity:.55;transition:opacity .4s var(--ease);
}
/* each viewBox is cropped to its ink, so height == cap height for a wordmark.
   Magic Leap stacks two lines beside a mark, so it needs the taller box to
   read at the same size as the others. */
.logos img[src$="logo-magic-leap.svg"]{height:clamp(26px,2.8vw,36px)}
.logos:hover img{opacity:.9}

/* link lists under the bio — as many columns as fit, one on a phone */
.cols{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(255px,1fr));
  gap:clamp(1.75rem,4vw,3rem);margin-top:clamp(2.5rem,6vw,4.5rem);
}
.cols .prose{max-width:none;gap:.85rem}
.cols .prose h3{margin:0}

/* full-width statement media */
.fullmedia{margin:0;background:#0b0b0b}
.fullmedia img,.fullmedia video{width:100%;display:block}

/* 3 video */
.embed{position:relative;aspect-ratio:16/9;background:#0b0b0b}
.embed iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.filmstrip{background:#0b0b0b;position:relative}
.filmstrip video{width:100%;display:block}
/* translucent play button over the first frame; hidden once the clip is running */
.playbtn{
  position:absolute;inset:0;margin:auto;width:88px;height:88px;
  display:grid;place-items:center;padding:0;border:0;background:none;cursor:pointer;
  color:#fff;opacity:.85;transition:opacity .25s var(--ease),transform .25s var(--ease);
}
.playbtn svg{width:100%;height:100%;overflow:visible}
.playbtn circle{fill:rgba(0,0,0,.34);stroke:rgba(255,255,255,.85);stroke-width:2;
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}
.playbtn path{fill:#fff}
.playbtn:hover,.playbtn:focus-visible{opacity:1;transform:scale(1.06)}
.filmstrip.playing .playbtn{opacity:0;pointer-events:none;transform:scale(.9)}
@media (prefers-reduced-motion:reduce){.playbtn{transition:none}}

/* the curated row — three across by default, four when a quad block asks for it */
.shots{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--gap)}
.shots.n4{grid-template-columns:repeat(4,1fr)}
.shots.n2{grid-template-columns:repeat(2,1fr)}

/* gallery — justified rows. flex-basis and flex-grow both track the aspect ratio,
   so every row fills the width exactly and heights match within a row. Nothing crops. */
.gallery{display:flex;flex-wrap:wrap;gap:var(--gap)}
.gallery .cell{
  flex:var(--ar,1.5) 1 calc(var(--ar,1.5) * 200px);
  margin:0;background:#0b0b0b;overflow:hidden;
}
.gallery .cell img,.gallery .cell video{
  width:100%;height:auto;display:block;aspect-ratio:var(--ar,1.5);object-fit:cover}
/* A phantom final item soaks up the slack on an underfull last row, so a lone
   leftover sits at its natural size instead of inflating to the full width. */
.gallery.rows::after{content:"";flex-grow:99999}
/* the photography page is the gallery, so its cells run larger -- two across
   at desktop instead of three, and a panorama takes a row to itself. */
.gallery.wide{padding-bottom:clamp(3rem,8vw,6rem)}
.gallery.wide .cell{flex-basis:calc(var(--ar,1.5) * 260px)}

/* the curated three stay a fixed grid, uniform and deliberate */
.shots .cell{margin:0;background:#0b0b0b;overflow:hidden}
.shots .cell img,.shots .cell video{width:100%;height:100%;object-fit:cover;aspect-ratio:3/2}

/* empty-section placeholders (hidden with: python3 tools/build.py --production) */
.ph{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;
  min-height:clamp(7rem,14vw,11rem);padding:1.5rem;text-align:center;
  border:1px dashed #333;border-radius:2px;background:repeating-linear-gradient(
    45deg,transparent,transparent 9px,rgba(255,255,255,.018) 9px,rgba(255,255,255,.018) 18px);
}
.ph-label{font-weight:700;color:#6f6f6f;letter-spacing:.02em}
.ph-hint{font-size:.82rem;color:#555;max-width:46ch;line-height:1.5}
.ph-hint a{color:#777}
.ph-hint code,.prose code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.92em;background:rgba(255,255,255,.06);padding:.12em .38em;border-radius:2px;color:#9a9a9a}

/* ---------- pager ---------- */
.pager{display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  margin-top:clamp(3rem,7vw,5rem);padding-top:1.75rem;border-top:1px solid var(--line)}
.pager a{display:flex;flex-direction:column;gap:.2rem;color:var(--dim);
  transition:color .25s var(--ease);max-width:45%}
.pager a.next{text-align:right;align-items:flex-end}
.pager a span{font-size:.72rem;letter-spacing:.12em;text-transform:uppercase}
.pager a:hover{color:#fff}

/* ---------- contact ---------- */
.contact{padding:clamp(4rem,12vw,9rem) 0}
.contact h1{margin:0 0 1rem;font-weight:700;letter-spacing:-.025em;font-size:clamp(2rem,5.5vw,3.6rem)}
.contact p{color:var(--dim);margin:0 0 1rem}
.contact .big{font-size:clamp(1.2rem,2.6vw,1.8rem)}
.contact .big a{color:#fff;text-decoration:underline;text-decoration-color:#555;
  text-underline-offset:4px;transition:text-decoration-color .25s var(--ease)}
.contact .big a:hover{text-decoration-color:#fff}
.elsewhere{list-style:none;padding:0;margin:2.5rem 0 0;display:flex;flex-direction:column;gap:.6rem}
.elsewhere a{color:var(--dim);transition:color .25s var(--ease)}
.elsewhere a:hover{color:#fff}

/* ---------- footer ---------- */
.foot{display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  max-width:var(--maxw);margin:0 auto;padding:2rem var(--pad) 3rem;
  border-top:1px solid var(--line);color:var(--dim);font-size:.85rem}
.foot a{transition:color .25s var(--ease)}
.social{display:flex;align-items:center;gap:1.1rem}
.social a{display:inline-flex;color:var(--dim)}
.social svg{width:17px;height:17px}
.social a:hover,.social a:focus-visible{color:#fff}
.foot a:hover{color:#fff}

/* ---------- lightbox ---------- */
.zoomable{cursor:zoom-in}
.lb{
  position:fixed;inset:0;z-index:200;display:none;
  align-items:center;justify-content:center;
  background:rgba(0,0,0,.94);
  padding:clamp(1rem,4vw,3rem);
}
.lb.open{display:flex}
.lb:focus{outline:none}
.lb img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;
  opacity:0;transition:opacity .28s var(--ease)}
.lb img.ready{opacity:1}
.lb-btn{
  position:absolute;background:none;border:0;color:#fff;cursor:pointer;
  font:400 2rem/1 'Gangster',system-ui,sans-serif;
  padding:.6rem .9rem;opacity:.65;transition:opacity .2s var(--ease);
}
.lb-btn:hover{opacity:1}
.lb-close{top:.4rem;right:.6rem;font-size:2.4rem}
.lb-prev{left:.2rem;top:50%;transform:translateY(-50%)}
.lb-next{right:.2rem;top:50%;transform:translateY(-50%)}
.lb-count{position:absolute;bottom:1rem;left:0;right:0;text-align:center;
  color:var(--dim);font-size:.8rem;letter-spacing:.08em}
body.lb-lock{overflow:hidden}
@media (max-width:720px){
  .lb-btn{font-size:1.6rem}
  .lb-close{font-size:2rem}
}

/* ---------- reveal ---------- */
.rv{opacity:0;transform:translateY(14px)}
.rv.in{opacity:1;transform:none;transition:opacity .7s var(--ease),transform .7s var(--ease)}

/* ---------- mobile ---------- */
@media (max-width:1100px){
  .grid{grid-template-columns:repeat(2,1fr)}
  .gallery .cell{flex-basis:calc(var(--ar,1.5) * 170px)}
  .gallery.wide .cell{flex-basis:calc(var(--ar,1.5) * 220px)}
  .shots.n4{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:820px){
  .shots{grid-template-columns:1fr}
  .gallery .cell{flex-basis:calc(var(--ar,1.5) * 200px)}
  .gallery.wide .cell{flex-basis:calc(var(--ar,1.5) * 200px)}
  .split{grid-template-columns:1fr}
  .appbar{grid-template-columns:1fr}
  .split-right .split-media{order:0}
}
@media (max-width:720px){
  .grid{grid-template-columns:1fr}
  .gallery .cell{flex:1 1 100%}
  .menu-btn{display:block}
  .menu{
    position:fixed;inset:61px 0 auto 0;flex-direction:column;gap:0;
    background:rgba(0,0,0,.97);backdrop-filter:blur(18px);
    border-bottom:1px solid var(--line);
    padding:.5rem var(--pad) 1.5rem;
    display:none;
  }
  .menu.open{display:flex}
  .menu a{padding:.85rem 0;font-size:1.05rem;border-bottom:1px solid var(--line)}
  .menu a:last-child{border-bottom:0}
  .pager a{max-width:100%}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
  .rv{opacity:1;transform:none}
}
