/* ==================================================================
   Director portfolio — no build step. Fonts are self-hosted (no calls
   out to Google), 60KB total across three woff2 files.

   Type follows arthurvalverde.com's name/nav face throughout — Archivo
   Narrow, SIL OFL — including the grid's project titles, which started
   as a Didone stand-in (Cinzel) but were moved onto the header's own
   face instead: one typeface for the whole site.
   ================================================================== */

@font-face{
  font-family:'Archivo Narrow';
  src:url('fonts/archivo-narrow-latin.woff2') format('woff2');
  font-weight:400 700; font-style:normal; font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
    U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Archivo Narrow';
  src:url('fonts/archivo-narrow-latin-ext.woff2') format('woff2');
  font-weight:400 700; font-style:normal; font-display:swap;
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,
    U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,
    U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:'Cinzel';
  src:url('fonts/cinzel-latin.woff2') format('woff2');
  font-weight:400 900; font-style:normal; font-display:swap;
}
:root{
  --black:#000;
  --white:#fff;
  --ink:#111;
  --muted:#6d6d6d;
  --rule:#e6e6e6;

  --sans: "Archivo Narrow", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --display: "Cinzel", Georgia, "Times New Roman", serif;

  --grey: #9c9c9c;              /* Arthur's secondary type colour */
  --masthead-h: 52px;
  --ease: cubic-bezier(.22,.61,.36,1);
  --page-ms: 380ms;
}

*,*::before,*::after{ box-sizing:border-box; }

html,body{
  margin:0; padding:0;
  height:100%;
  background:var(--black);
  color:var(--ink);
  font-family:var(--sans);
  -webkit-font-smoothing:antialiased;
  -webkit-text-size-adjust:100%;
}

/* Lock the document: the panels do their own scrolling. */
body{ overflow:hidden; overscroll-behavior:none; }

img{ display:block; max-width:100%; }
button{ font:inherit; color:inherit; background:none; border:0; padding:0; cursor:pointer; }
a{ color:inherit; text-decoration:none; }

/* ------------------------------------------------------------------
   Deck — three stacked full-viewport panels, moved with transforms.
   Slot -1 / 0 / +1 is assigned in JS so the loop wraps in both directions.
   ------------------------------------------------------------------ */
.deck{ position:fixed; inset:0; overflow:hidden; }

.view{
  position:absolute; inset:0;
  width:100%; height:100%;
  transform:translate3d(100%,0,0);   /* JS overwrites immediately */
  will-change:transform;
  backface-visibility:hidden;
}
.view--animate{ transition:transform var(--page-ms) var(--ease); }

/* Only the panel in slot 0 takes input. */
.view[aria-hidden="true"]{ pointer-events:none; }
.view[aria-hidden="true"] :where(a,button){ pointer-events:none; }

/* ==================================================================
   GRID
   ================================================================== */
.view--grid{
  background:var(--white);
  overflow-y:auto;
  overflow-x:hidden;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior-y:contain;
}

.masthead{
  position:sticky; top:0; z-index:5;
  display:flex; align-items:flex-start; justify-content:space-between; gap:16px;
  padding:calc(env(safe-area-inset-top) + clamp(13px,1.9vw,24px))
          clamp(15px,1.56vw,20px)
          clamp(11px,1vw,12px);
  background:var(--black);
  color:var(--white);
}
/* Name and role read as one continuous line, split by a rule:
   ANDREW PIGGOTT DOMANSKI | FILM DIRECTOR */
.masthead__name{
  display:flex; flex-direction:row; align-items:baseline;
  min-width:0;
}
.masthead__who,
.masthead__role{
  /* Scales with the viewport rather than sitting on a floor: the whole line
     is ~20.5x the font-size, so on a 320px phone it has to come down to keep
     off the edges. The 13px floor is the narrowest it ever needs to go. */
  font-size:clamp(13px,4.3vw,24px);
  line-height:1.2;
  letter-spacing:.02em;
  text-transform:uppercase;
  font-weight:600;
  color:var(--white);
  white-space:nowrap;
}
/* The divider is furniture, not type — it sits back from both halves. */
.masthead__role::before{
  content:"|";
  margin:0 .45em;
  font-weight:400;
  opacity:.45;
}
.masthead__link{
  font-size:clamp(12px,1.25vw,16px);
  letter-spacing:.02em;
  text-transform:uppercase;
  font-weight:400;
  color:var(--grey);
  transition:color .2s ease;
}
.masthead__link:hover{ color:var(--white); }

/* Full-bleed banner rows, 33vh tall — matching the reference site. */
.grid{ display:block; }

.tile{
  position:relative; display:block;
  width:100%;
  aspect-ratio:16/7;
  overflow:hidden;
  background:#0d0d0d;
}
.tile__img{
  --poster-zoom:1;           /* raise per project to crop baked-in letterbox bars */
  width:100%; height:100%;
  object-fit:cover;          /* centre-crop, like the reference */
  object-position:center;
  transform:scale(var(--poster-zoom));
  transition:transform 900ms var(--ease), opacity .5s ease;
  opacity:0;
}
.tile__img.is-loaded{ opacity:1; }
@media (hover:hover){
  .tile:hover .tile__img{ transform:scale(calc(var(--poster-zoom) * 1.06)); }
}

/* Title: Arthur's treatment — a Didone, tracked wide, vertically centred
   and inset from the left, hidden until you hover the row. */
.tile__scrim{
  position:absolute; inset:0;
  background:rgba(0,0,0,.30);
  opacity:0;
  transition:opacity .3s cubic-bezier(.33,0,.2,1);
  pointer-events:none;
}
.tile__title{
  position:absolute;
  left:50%; top:50%; transform:translate(-50%,-50%);
  margin:0;
  width:calc(100% - 2 * clamp(18px,2.73vw,35px));
  text-align:center;
  overflow-wrap:break-word;
  color:var(--white);
  font-family:var(--display);
  font-size:clamp(16px,2.6vw,30px);
  line-height:1.25;
  letter-spacing:.02em;
  text-transform:none;
  font-weight:400;
  font-style:normal;
  text-shadow:0 1px 26px rgba(0,0,0,.34);
  pointer-events:none;
  opacity:0;
  transition:opacity .3s cubic-bezier(.33,0,.2,1);
}
@media (hover:hover){
  .tile:hover .tile__title,
  .tile:focus-visible .tile__title{ opacity:1; }
  .tile:hover .tile__scrim,
  .tile:focus-visible .tile__scrim{ opacity:1; }
}
/* Touch has no hover, so app.js walks the rows on a timer instead and marks
   one at a time. Same three moves as the hover state, so a phone sees the
   film exactly the way a cursor would reveal it. */
@media (hover:none){
  /* This walk is ambient rather than a reply to a tap, so it runs slower
     than the hover state, and the fade shares the zoom's curve so the two
     halves of the reveal land as one move instead of a blink over a drift.
     At 4s a row, an 0.8s fade also leaves the outgoing and incoming rows
     genuinely crossfading rather than cutting. */
  .tile__title,
  .tile__scrim{ transition:opacity .8s var(--ease); }
  .tile__img{ transition:transform 1600ms var(--ease), opacity .5s ease; }

  .tile.is-active .tile__title,
  .tile.is-active .tile__scrim{ opacity:1; }
  .tile.is-active .tile__img{ transform:scale(calc(var(--poster-zoom) * 1.06)); }
}

/* Cinzel (serif) for grid project titles, centred both axes. */

/* ==================================================================
   REEL
   ================================================================== */
.view--reel{ background:var(--black); overflow:hidden; }

.reel-stage{
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  background:var(--black);
}

/* The track carries both slides and is what actually animates. */
.reel-track{ position:absolute; inset:0; will-change:transform; }
.reel-track.is-animating{ transition:transform 420ms var(--ease); }

.reel-slide{
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  backface-visibility:hidden;
}

/* Letterbox: fit the video's real shape inside the viewport, never crop. */
.reel-box{
  --ar: 1.7778;
  position:relative;
  width:  min(100vw, calc(100vh * var(--ar)));
  height: min(100vh, calc(100vw / var(--ar)));
  background:var(--black);
}
@supports (width:100dvw){
  .reel-box{
    width:  min(100dvw, calc(100dvh * var(--ar)));
    height: min(100dvh, calc(100dvw / var(--ar)));
  }
}
.reel-box iframe,
.reel-poster{
  position:absolute; inset:0;
  width:100%; height:100%;
  border:0; display:block;
}
/* The poster sits ON TOP of the iframe and only fades once the player has
   actually put frames on screen. Underneath it would be useless: Vimeo
   paints its own black background the moment the iframe exists, so the
   poster would be covered during exactly the load it exists to cover.
   This is what makes a flick land on the film's own frame, not a black gap.
   The box already carries the video's shape, so cover and contain agree. */
.reel-poster{
  object-fit:cover;
  z-index:2;
  pointer-events:none;
  transition:opacity .3s ease;
}
.reel-slide.is-playing .reel-poster{ opacity:0; }

.reel-hit{
  position:absolute; inset:0;
  width:100%; height:100%;
  cursor:default;
  -webkit-tap-highlight-color:transparent;
}

/* ---- chrome: deliberately almost invisible ---- */
.reel-chrome{ position:absolute; inset:0; pointer-events:none; }
.reel-chrome > *{ pointer-events:auto; }

.chev, .reel-close{
  position:absolute;
  display:grid; place-items:center;
  width:44px; height:44px;
  color:var(--white);
  opacity:.22;
  transition:opacity .25s ease;
}
.chev svg, .reel-close svg{
  width:24px; height:24px;
  fill:none; stroke:currentColor; stroke-width:1.5;
  stroke-linecap:round; stroke-linejoin:round;
}
.chev:hover, .reel-close:hover{ opacity:.85; }

.chev--up{   left:50%; transform:translateX(-50%); top:max(10px, env(safe-area-inset-top)); }
.chev--down{ left:50%; transform:translateX(-50%); bottom:max(10px, env(safe-area-inset-bottom)); }
.reel-close{ top:max(10px, env(safe-area-inset-top)); right:10px; }

/* Entry hint — chevrons pulse once, then settle back to near-invisible. */
.reel-chrome.is-hinting .chev{ animation:hint 2.4s var(--ease) 1 both; }
.chev--down{ animation-delay:.12s; }
@keyframes hint{
  0%   { opacity:0; }
  18%  { opacity:.9; }
  55%  { opacity:.9; }
  100% { opacity:.22; }
}
.chev--up.is-nudge{   animation:nudgeUp .5s ease; }
.chev--down.is-nudge{ animation:nudgeDown .5s ease; }
@keyframes nudgeUp{   50%{ transform:translate(-50%,-5px); opacity:.8; } }
@keyframes nudgeDown{ 50%{ transform:translate(-50%, 5px); opacity:.8; } }

/* Edge click zones — pointer devices only, so they never eat a tap. */
.edge{ position:absolute; top:0; bottom:0; width:70px; cursor:pointer; }
.edge--left{ left:0; }
.edge--right{ right:0; }
@media (hover:none), (max-width:767px){
  .edge, .chev, .reel-close{ display:none; }
  .reel-chrome.is-hinting .chev{ display:grid; }  /* hint still shows on touch */
}

.sound-chip{ display:none; }

/* ==================================================================
   CONTACT
   ================================================================== */
.view--contact{
  background:var(--white);
  overflow-y:auto; overflow-x:hidden;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior-y:contain;
}
.contact{
  min-height:100%;
  display:flex; flex-direction:column;
  padding:0 clamp(22px,6vw,40px);
}
.contact__back{
  position:absolute; top:max(14px, env(safe-area-inset-top)); right:clamp(16px,5vw,28px);
  width:34px; height:34px; display:grid; place-items:center;
  color:var(--ink); opacity:.30; transition:opacity .2s ease;
}
.contact__back svg{ width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:1.4; stroke-linecap:round; }
.contact__back:hover{ opacity:.8; }

.contact__inner{
  flex:1;
  /* Wide enough that every bio line lands as a single statement — the
     longest is 583px. Drop this and lines start orphaning their last words. */
  max-width:600px;
  width:100%;
  margin:0 auto;
  /* Sits close under the X rather than leaving it stranded above a big
     empty gap — the whole page reads as one aligned block, not two. */
  padding-top:calc(env(safe-area-inset-top) + 52px);
  padding-bottom:24px;
}
.contact__name{
  margin:0 0 clamp(26px,5vh,40px);
  font-size:clamp(19px,1.97vw,25.2px);
  line-height:1.3;
  letter-spacing:.02em;
  text-transform:uppercase;
  font-weight:400;
  color:#111;
}
/* Same colour and weight as the name above it — only the size differs. */
.contact__role{
  display:block;
  margin-top:2px;
  font-size:clamp(12px,1.17vw,15px);
  letter-spacing:.10em;
  font-weight:400;
  color:#111;
}
/* Shared text scale across the contact page — Arthur's 15px / 2.2 rhythm. */
.contact__inner :where(p, a, span, li){
  font-size:15px;
  letter-spacing:.03em;
  line-height:2.2;
}

.bio{ margin:0 0 clamp(18px,3vh,26px); }
.bio p{ margin:0; color:#999; }
.bio p:first-child{ margin-bottom:.5em; }

/* CONTACT and REPRESENTATION are the same component — one rule set, so the
   two blocks can never drift apart. */
.block{
  border-top:1px solid var(--rule);
  padding-top:clamp(14px,2.4vh,20px);
}
#details{ margin-bottom:clamp(18px,3vh,26px); }
.block h2{
  margin:0;
  font-size:15px; letter-spacing:.03em; line-height:2.2;
  text-transform:uppercase; font-weight:400; color:#111;
}
/* Two columns so the values line up however long the label is. */
.block ul{
  list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:max-content 1fr; column-gap:1.6em;
}
.block li{ display:contents; }
.block .label{
  color:#111;
  font-size:11px;
  font-weight:400;
  letter-spacing:.08em;
  line-height:2.2;
  text-transform:uppercase;
}

/* The opening bio line reads as the page's own heading — same treatment
   as a label (weight, colour, caps, tracking-in-em so it scales with it)
   but sized above the copy underneath it rather than matching EMAIL/USA. */
.bio p:first-child{
  color:#111;
  font-size:16px;
  font-weight:400;
  letter-spacing:.08em;
  line-height:1.3;
  text-transform:uppercase;
}
.block a{
  color:#999;
  border-bottom:1px solid transparent;
  transition:color .2s ease, border-color .2s ease;
}
.block a:hover{ color:#111; border-bottom-color:#111; }
.block span:not(.label){ color:#999; }

/* On a narrow phone the two columns stop fitting, so the region sits
   above its agency instead of beside it. */
@media (max-width:520px){
  .block ul{ display:block; }
  .block li{ display:block; margin-bottom:1em; }
  .block li:last-child{ margin-bottom:0; }
  .block .label{ display:block; line-height:1.6; }
}

.social{
  display:flex; align-items:center; justify-content:center;
  gap:clamp(26px,7vw,38px);
  padding:18px 0;
  padding-bottom:max(18px, calc(env(safe-area-inset-bottom) + 18px));
  border-top:1px solid var(--rule);
}
.social a{ display:grid; place-items:center; width:40px; height:40px; opacity:.55; transition:opacity .2s ease; }
.social a:hover{ opacity:1; }
.social svg{ width:21px; height:21px; fill:currentColor; }

/* ==================================================================
   Accessibility
   ================================================================== */
/* Present to assistive tech and the document outline, invisible on screen. */
.sr-only{
  position:absolute !important;
  width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  clip-path:inset(50%);
  overflow:hidden; white-space:nowrap;
}
:where(a,button):focus-visible{ outline:2px solid #4c8dff; outline-offset:3px; border-radius:2px; }
/* The reel panel is a focus holder, not a control — it carries no ring.
   The chevrons, the close button and the sound chip keep theirs. */
.view--reel:focus,
.view--reel:focus-visible{ outline:none; }
.reel-hit:focus-visible{ outline:2px solid #4c8dff; outline-offset:-6px; }

@media (prefers-reduced-motion:reduce){
  .view--animate{ transition-duration:1ms; }
  .tile__img{ transition:opacity .2s ease; }
  @media (hover:hover){ .tile:hover .tile__img{ transform:none; } }
  @media (hover:none){ .tile.is-active .tile__img{ transform:none; } }
  .reel-frame{ transition-duration:1ms; }
  .reel-chrome.is-hinting .chev{ animation:none; opacity:.5; }
}
