/* David Barker -- prototype.
   Every colour here is a fill operator read out of reference/design.pdf, not a
   sampled pixel. Do not eyeball-correct them. */
:root{
  --crimson:#90122f;   /* the body copy. Set 398 times in the deck -- the voice */
  --orange:#e58e31;    /* his name, film titles, company names. Spend it rarely */
  --white:#ffffff;
  --quote-bg:#e8e6e1;  /* the quote boxes. Off-white, not the deck's pure #fff */
  --near:#eeeeee;      /* the quieter text tone */
  --grey:#808080;      /* captions and attributions */
  --lift:#c2455f;      /* crimson, lifted — hover only */
  --dim:#595959;
  --ground:#000000;

  /* Roughly 55 / 25 / 20, straight off the deck's three pages. */
  --w-works:55vw;
  --w-about:25vw;
  --w-photos:20vw;
}

*{box-sizing:border-box}
html,body{margin:0;padding:0;height:100%}
body{
  background:var(--ground);
  color:var(--near);
  font-family:'Roboto Mono',ui-monospace,Menlo,Consolas,monospace;
  overflow:hidden;                 /* each column scrolls itself */
  -webkit-font-smoothing:antialiased;
}

/* dvh, not vh. On a phone 100vh is the height with the browser chrome HIDDEN,
   so a 100vh column hangs below what you can actually see and the bottom of
   the last work is unreachable. dvh tracks the real visible height; the vh
   line above it is the fallback for browsers without dvh. */
#stage{display:flex;height:100vh;height:100dvh;width:100vw}
.col{position:relative;height:100vh;height:100dvh;overflow:hidden}
/* The drifting columns take the pan gesture themselves so a swipe scrubs them
   instead of the browser trying to scroll something. Pinch-zoom is left alone. */
.col.drift{touch-action:pinch-zoom}

#works{width:var(--w-works);overflow-y:auto;scrollbar-width:none}
#works::-webkit-scrollbar{display:none}
#about{width:var(--w-about)}
#photos{width:var(--w-photos)}

.track{will-change:transform}

/* ---------------------------------------------------------------- works */
.item{position:relative;display:block}
.item img{display:block;width:100%;height:auto}

/* The opening frame is a still and nothing else: the life on load comes from
   the right column already drifting, not from a film peeking in at the fold. */
#works-track > .item:first-child{height:100vh;height:100dvh;overflow:hidden}
#works-track > .item:first-child img{height:100%;object-fit:cover}

/* The whole tile is clickable: a still enlarges, a film plays. */
.item.clickable{cursor:pointer}
.item.clickable:focus-visible{outline:1px solid var(--orange);outline-offset:-1px}

/* Captions carry a direction marker pointing at their own column, exactly as
   the deck sets them: `> Josephine` bottom-left, `Pimped Feature Film <`. */
.caption{
  position:absolute;left:1.4rem;bottom:1.1rem;
  font-size:.72rem;letter-spacing:.06em;color:var(--near);
  text-shadow:0 1px 6px rgba(0,0,0,.75);
  pointer-events:none;
}
.caption .mark{color:var(--grey)}
.caption .title{font-weight:500}
.caption .sub{color:var(--near);font-weight:300}
.caption.top{top:1.1rem;bottom:auto}

/* The play triangle over a film. */
.play{
  position:absolute;inset:0;display:grid;place-items:center;pointer-events:none;
}
.play svg{width:clamp(28px,2.9vw,56px);height:auto;opacity:.92;
  filter:drop-shadow(0 2px 12px rgba(0,0,0,.6))}
.item.clickable:hover .play svg{opacity:1}

/* Quote blocks: solid white boxes behind black italic text, tight leading, the
   box hugging each line's own width. That per-line ragged edge is the whole
   look -- box-decoration-break is what makes it, do not replace with a
   background on the block. */
/* The deck leaves 1.3% of page height above a quote and 2.2% below; David
   wants them equal, so both are the smaller figure. Keep them equal. */
.quote{padding:1.3vh 1.4rem;max-width:58%}
.quote p{margin:0;font-family:Arial,Helvetica,sans-serif;font-style:italic;
  font-size:.92rem;line-height:1.42}
.quote .q,.quote .by{
  background:var(--quote-bg);color:#000;
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
  padding:.09em .28em;
}
.quote .by{font-style:normal;font-size:.82rem;display:inline-block;margin-top:1.6vh}

/* A quote sitting on top of an image, as on the deck's first page. Measured
   off that page rather than guessed: its line boxes are 2.76% of page height
   against 2.11% here, so the type is ~30% larger than a standalone quote, and
   the attribution sits at plain line spacing (0.49%) rather than being pushed
   away from the quote. The narrow measure is what wraps it after "little". */
.item .quote{position:absolute;top:0;left:0;max-width:14vw;padding:1.4rem}
/* Leading, not size, is what separates the boxes: the deck leaves a 0.49%
   black sliver between each line. At 1.34 the boxes touch and read as one
   block. */
.item .quote p{font-size:clamp(12px,2.11vh,24px);line-height:1.58}
.item .quote .by{font-size:clamp(11px,1.9vh,21px);margin-top:.2vh}

/* The scroll cue: a thin rule ending in a small solid triangle. */
.scroll-cue{position:absolute;right:5.5%;bottom:8%;width:10px;
  display:flex;flex-direction:column;align-items:center;pointer-events:none;
  opacity:.85;transition:opacity .65s ease}
.scroll-cue i{display:block;width:1px;height:22vh;background:var(--crimson)}
.scroll-cue b{display:block;width:0;height:0;
  border-left:5px solid transparent;border-right:5px solid transparent;
  border-top:8px solid var(--crimson)}
#works.scrolled .scroll-cue{opacity:0}

/* ---------------------------------------------------------------- about */
/* Right-aligned, ragged left, against black. The ragged-left setting only
   works because every glyph is the same width -- keep it monospace. */
/* Type size is taken off the deck rather than guessed: its body copy sets to
   ~17-18 characters per line, and at 405pt slide height the face is ~10pt --
   i.e. about 2.4% of viewport height. Hence vh-based sizing, and a `ch`
   measure, which is exact because the face is monospace. Set this too small
   and the crimson-on-black goes muddy and unreadable, which is what a
   rem-based guess produced. */
#about .track{padding:0 1vw}
.about-block{padding:9vh 0}
.about-name{color:var(--orange);font-weight:400;letter-spacing:.02em;
  text-align:left;margin:0 0 3.4vh;
  font-size:clamp(13px,2.2vh,23px)}
/* The roles right-align to the column's own edge (79.3% of page width in the
   deck). Only the body copy below is pushed left. Line spacing is 3.05% of
   page height top-to-top -- the deck sets these two lines tight. */
.about-roles{text-align:right;margin:0 0 6vh;line-height:1.39}
.about-roles span{display:block;font-size:clamp(13px,2.2vh,23px)}
.about-roles .r1{color:var(--orange)}
.about-roles .r2{color:var(--crimson)}
/* The copy block's LEFT edge aligns with the left edge of his name, and the
   text is right-aligned inside it -- so the ragged left lands on the same
   margin as "David Barker". The roles line above still right-aligns to the
   column's own edge; the two are deliberately on different margins.

   The measure is set in vw, not ch, because the target is geometric: the
   right edge lands on the middle of the black column. The column runs
   55->80vw, so its midpoint is 67.5vw; the copy starts at 56vw, hence
   67.5 - 56 = 11.5vw. Switch this back to a ch measure and the right edge
   drifts with type size and misses the midpoint. */
.about p.para{
  color:var(--crimson);text-align:right;
  font-size:clamp(10px,1.9vh,20px);
  font-weight:200;line-height:1.52;letter-spacing:.005em;
  margin:0 auto 3.2vh 0;max-width:11.5vw;
}
.about p.para em{font-style:normal;color:var(--orange)}
.about .rule{height:1px;background:var(--crimson);opacity:.35;
  margin:5vh auto 5vh 0;max-width:11.5vw}

/* --------------------------------------------------------------- contact */
/* Pinned to the bottom of the middle column, centred in the black band
   between the copy's right edge (67.5vw) and the photography column (80vw).
   75% of the 25vw column lands on 73.75vw, which is that midpoint, and it
   stays there if the column widths change. */
#about .contact{
  position:absolute;bottom:3.2vh;left:75%;transform:translateX(-50%);
  display:flex;align-items:center;gap:.9vw;z-index:3;
}
/* The icons take their colour from the body copy, so changing the crimson in
   the panel moves them with it. The PNGs are used as alpha masks rather than
   drawn: they are a flat colour on full transparency, so masking gives David's
   exact artwork with the palette's colour behind it. Tracing them to SVG got
   only ~88% shape agreement, which is not good enough to substitute. */
#about .contact .ic{
  display:block;
  width:clamp(26px,5.6vh,60px);height:clamp(26px,5.6vh,60px);
  background-color:var(--crimson);
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-size:contain;mask-size:contain;
  /* No colour transition: the stylesheet's default crimson would visibly fade
     to the palette's value on every load. Hover changes colour instantly. */
  transition:transform .2s;
}
#about .contact .mail{
  -webkit-mask-image:url(../icons/email_1.png);mask-image:url(../icons/email_1.png);
}
#about .contact .insta{
  -webkit-mask-image:url(../icons/instagram.png);mask-image:url(../icons/instagram.png);
}
#about .contact a:hover .ic{background-color:var(--lift,#c2455f);transform:translateY(-1px)}

/* Without mask support the icons would be solid crimson squares, so fall back
   to the artwork in its own red. */
@supports not ((-webkit-mask-image:url(a)) or (mask-image:url(a))){
  #about .contact .ic{
    background-color:transparent;background-repeat:no-repeat;
    background-position:center;background-size:contain;
  }
  #about .contact .mail{background-image:url(../icons/email_1.png)}
  #about .contact .insta{background-image:url(../icons/instagram.png)}
}
#about .contact a:focus-visible{outline:2px solid var(--orange);outline-offset:3px}

/* --------------------------------------------------------------- photos */
#photos .shot{display:block;width:100%;cursor:pointer}
#photos .shot img{display:block;width:100%;height:auto}

/* --------------------------------------------------------------- viewer */
#viewer{position:fixed;inset:0;z-index:50;background:rgba(0,0,0,.97);
  display:grid;place-items:center;padding:3vmin}
#viewer[hidden]{display:none}
#viewer-body{max-width:94vw;max-height:88vh;display:grid;place-items:center}
#viewer-body img{max-width:94vw;max-height:88vh;width:auto;height:auto;display:block}
/* A film keeps its own aspect -- never scale up, never re-crop. Letterboxing
   is correct here, not a bug. */
#viewer-body .frame{position:relative;width:min(94vw,calc(88vh*16/9));
  aspect-ratio:16/9;background:#000}
#viewer-body iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
#viewer-caption{position:fixed;left:2rem;bottom:1.4rem;font-size:.74rem;
  color:var(--grey);letter-spacing:.06em}
#viewer-close{position:fixed;top:1rem;right:1.4rem;z-index:6;
  background:none;border:0;color:var(--near);font-size:1.9rem;line-height:1;
  cursor:pointer;padding:.2rem .5rem;font-family:inherit}
#viewer-close:hover{color:var(--orange)}

/* ---------------------------------------------------------------- strips */
/* On a phone the photography stops being a column and becomes a horizontal
   strip drifting right-to-left, dropped into the works column at two points.
   Hidden on desktop, where the right column does the job. */
.strip{display:none}

/* ---------------------------------------------------------------- mobile */
/* Left and middle stay as columns and keep their behaviour. The right
   column's 20% is freed, so the other two expand proportionally to fill the
   width: 55/80 and 25/80 of what they had. */
@media (max-width:820px){
  :root{
    --w-works:68.75vw;
    --w-about:31.25vw;
  }
  #photos{display:none}
  .strip{display:block}

  /* Room after the last work, so it clears the bottom edge while the browser
     chrome slides in and out rather than sitting flush against it. */
  #works-track{padding-bottom:9vh}

  /* The opening frame is cropped to the viewport on desktop. On a phone the
     column is narrow, so cover-cropping a square photograph cuts most of it
     away -- pictures run full width at their own aspect instead. */
  #works-track > .item:first-child{height:auto;overflow:visible}
  #works-track > .item:first-child img{height:auto;object-fit:fill}

  #about .track{padding:0 2vw}
  /* The desktop rule -- right edge on the middle of the black column -- cannot
     survive here: it would leave the copy about 6 characters wide. On a phone
     the copy takes the column instead, which keeps the deck's measure of
     roughly 15 characters a line. */
  .about p.para{max-width:none;margin:0 0 3.2vh 0;
    font-size:clamp(9px,3.05vw,15px);line-height:1.5}
  .about .rule{max-width:none;margin:5vh 0}
  .about-name{font-size:clamp(10px,3.3vw,16px);margin:0 0 3vh}
  .about-roles span{font-size:clamp(10px,3.3vw,16px)}
  .about-block{padding:7vh 0}

  /* The landing quote is deck-matched on desktop (2.11vh), and that rule wins
     here too because `.item .quote p` outranks `.quote p`. On a 268px column
     it swamped the photograph, so it is reduced by 35% on a phone only --
     leave the desktop figures alone, they are measured off the deck. */
  #works-track .item .quote p{font-size:clamp(9px,1.37vh,16px);line-height:1.5}
  #works-track .item .quote .by{font-size:clamp(8px,1.24vh,14px)}
  #works-track .item .quote{max-width:62%;padding:.9rem}

  .quote{max-width:82%;padding:1.3vh 1rem}
  .quote p{font-size:clamp(10px,3vw,14px);line-height:1.4}
  .quote .by{font-size:clamp(9px,2.6vw,12px)}
  .item .quote{max-width:70%;padding:1rem}
  .caption{left:.9rem;bottom:.8rem;font-size:.62rem}
  .scroll-cue{right:7%;bottom:7%}
  .scroll-cue i{height:16vh}

  #about .contact{left:50%;bottom:2.4vh;gap:3vw}
  #about .contact img{height:clamp(24px,5vh,46px)}

  .v-nav{width:22vw}
  #viewer-caption{left:1rem;font-size:.66rem}
}

/* The strip itself. 5-6 pictures on a rail, drifting right to left, looping
   the same way the columns do -- two copies, offset wrapped at the halfway
   mark. */
/* Tighter than the quotes' 1.3vh: the tiles want to sit almost flush against
   the works above and below them. Symmetric, and the only lever is this one
   number. */
.strip{position:relative;overflow:hidden;height:24vh;margin:.45vh 0;
  background:var(--ground);
  /* Hand horizontal gestures to the strip and leave vertical panning to the
     column. Without this the browser claims the whole gesture and the swipe
     never reaches the drag handler -- the strip then has only its one speed. */
  touch-action:pan-y;
  -webkit-user-select:none;user-select:none;}
.strip .rail .shot img{-webkit-user-drag:none;pointer-events:none}
.strip .rail{display:flex;height:100%;will-change:transform}
.strip .rail .shot{flex:0 0 auto;height:100%;width:auto;cursor:pointer}
.strip .rail .shot img{height:100%;width:auto;display:block}

/* ------------------------------------------------- viewer carousel (6) */
/* A still opens into its own category and you flick left-right through it.
   Films are not part of a set: clicking one plays it and nothing else. */
#viewer-body .stage{position:relative;display:grid;place-items:center;
  max-width:94vw;max-height:88vh}
.v-nav{position:fixed;top:0;bottom:0;width:14vw;min-width:64px;border:0;
  background:none;cursor:pointer;color:var(--near);font-family:inherit;
  font-size:1.5rem;opacity:.32;transition:opacity .18s;z-index:2}
.v-nav:hover{opacity:1}
.v-nav.prev{left:0}
.v-nav.next{right:0}
.v-nav:disabled{opacity:.08;cursor:default}
#viewer.is-film .v-nav{display:none}
#viewer-caption .count{color:var(--dim);margin-left:.9rem}
#viewer-caption .cat{color:var(--grey);letter-spacing:.1em;text-transform:lowercase}
/* Keep the frame still while a neighbouring image decodes. */
#viewer-body img{transition:opacity .14s}
#viewer-body img.swapping{opacity:.35}
