/* EZEKIEL MILES V2 — design system
   Baseline: 8px unit. Grid: 12 col / 24px gutter / max 1440 / margins clamp(24,5vw,96).
   Type scale 1.25 from 16px: 13 / 16 / 20 / 25 / 31 / 39.
   Everything on the site derives from these constants — no ad-hoc spacing. */
:root {
  --u: 8px;
  --gutter: calc(var(--u) * 3);      /* 24px */
  --margin: clamp(24px, 5vw, 96px);
  --maxw: 1440px;
  --bg: #000;
  --fg: #fff;
  --fg2: #9a9a9a;
  --t-xs: 13px; --t-s: 16px; --t-m: 20px; --t-l: 25px; --t-xl: 31px; --t-2xl: 39px;
  /* grotesque monospace, system-resident so it costs no request */
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", "Courier New", monospace;
  --ease: cubic-bezier(.445,.05,.55,.95);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { background: var(--bg); color: var(--fg);
  font: var(--t-s)/1.5 var(--mono);
  -webkit-font-smoothing: antialiased; }
img, video { display: block; width: 100%; height: auto; }
picture { display: contents; }   /* the <img> keeps its own layout rules */
a { color: inherit; text-decoration: none; }
a:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; }

.shell { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--margin); }

/* ---- header: fixed rhythm, all pages identical ---- */
/* Header: one bar, wordmark + email hard left, nav hard right.
   space-between, 2rem padding, 2.5em nav gap, 700 weight, .02em tracking,
   underline on the wordmark. */
.site-head { position: relative; z-index: 20; display: flex;
  align-items: flex-start; justify-content: space-between;
  gap: calc(var(--u) * 4); padding: 2rem 0; }
.site-head .wordmark { font-size: 15px; font-weight: 700; letter-spacing: .02em;
  text-transform: uppercase; }
.site-head .wordmark span { border-bottom: 1px solid currentColor;
  padding-bottom: 1px; }
.byline { margin-top: .25em; font-size: 14px; font-weight: 400;
  color: var(--fg2); }
.byline a { transition: color .2s var(--ease); }
.byline a:hover { color: var(--fg); }
/* Menu: flex:1 right-aligned, 2.5em gap, 700/.02em, underline marks the
   current page, and a CSS-only submenu whose parent link carries an oversized
   padded hit area so the pointer can travel into it without the menu closing. */
/* desktop: no button, nav always shown */
.nav-toggle { display: none; background: none; border: 0; color: var(--fg);
  font: inherit; font-size: 15px; font-weight: 700; letter-spacing: .02em;
  text-transform: uppercase; cursor: pointer; padding: 4px 0; }
.site-nav { display: flex; flex: 1; gap: 2.5em; justify-content: flex-end; }
.site-nav .menu-item { position: relative; }
.site-nav .menu-item > a { display: flex; font-size: 15px; font-weight: 700;
  letter-spacing: .02em; text-transform: uppercase; color: var(--fg); }
.site-nav a span { border-bottom: 1px solid transparent; padding-bottom: 1px; }
.site-nav a:hover span, .site-nav a[aria-current="page"] span {
  border-bottom-color: currentColor; }
@media (min-width: 787px) {
  .site-nav .menu-item > a { margin: -2em -1em; padding: 2em 1em; }
}
/* solid plate: the menu drops over artwork, so transparent text would land
   on the images */
.site-nav .submenu { position: absolute; top: 100%; left: 0; z-index: 20;
  margin: 0 -1rem; padding: calc(var(--u) * 1.5) 1rem calc(var(--u) * 2);
  background: var(--bg); white-space: nowrap;
  opacity: 0; pointer-events: none; }
.site-nav .submenu a { display: block; padding: 0 0 4px;
  font-size: 15px; font-weight: 700; letter-spacing: .02em;
  text-transform: uppercase; color: var(--fg); }
.site-nav .menu-item:hover .submenu,
.site-nav .menu-item:focus-within .submenu { opacity: 1; pointer-events: auto; }
/* hovering any item holds it at full strength and drops every other
   top-level item to a muted grey */
.site-nav .menu-item > a { transition: color .2s var(--ease); }
.site-nav:hover .menu-item > a,
.site-nav:focus-within .menu-item > a { color: var(--fg2); }
.site-nav .menu-item:hover > a,
.site-nav .menu-item:focus-within > a { color: var(--fg); }
.site-nav .menu-item:hover ~ .menu-item .submenu,
.site-nav .menu-item:focus-within ~ .menu-item .submenu {
  opacity: 0; pointer-events: none; }
@media (max-width: 786px) {
  /* Keep the header compact on a phone and move the menu behind a control:
     expanded inline, 10 links push every page's work below the fold. */
  /* 90px header: 8px above, 28px below */
  .site-head { flex-direction: row; flex-wrap: wrap; align-items: flex-start;
    justify-content: space-between; gap: calc(var(--u) * 2);
    padding: 8px 0 28px; }
  .head-left { flex: 1 1 auto; }
  .nav-toggle { flex: 0 0 auto; }
  .nav-toggle { display: block; }
  .site-head.open .nav-toggle::after { content: " \00d7"; }
  .site-nav { display: none; flex: 1 0 100%; width: 100%; gap: 0;
    align-items: flex-start; justify-content: flex-start;
    flex-direction: column; order: 3; padding-top: calc(var(--u) * 2); }
  .site-nav .menu-item { width: 100%; }
  .site-head.open .site-nav { display: flex; }
  .site-head .wordmark { font-size: 14px; }
  /* No hover on touch, so a dropdown is unreachable: the submenu sits open
     inline instead. */
  .site-nav .menu-item > a { font-size: 15px; margin: 0; padding: 11px 0; }
  .site-nav .submenu { position: static; opacity: 1; pointer-events: auto;
    margin: 0; padding: 0 0 6px 1.4em; background: none; white-space: normal; }
  .site-nav .submenu a { padding: 10px 0; font-size: 14px; color: var(--fg2); }
  .site-nav .menu-item:hover ~ .menu-item .submenu { opacity: 1; pointer-events: auto; }
}
/* a stuck :hover on touch must not grey the whole menu out */
@media (hover: none) {
  .site-nav:hover .menu-item > a,
  .site-nav:focus-within .menu-item > a { color: var(--fg); }
}

/* ---- work grid: 12-col; film tiles span 6, gallery tiles span 4 ---- */
/* Home: single centred 695x338 card column. Still image rests; looping MP4
   fades in on hover, or plays on scroll where there is no pointer. */
/* Home: two-up grid of the same cards, caption line under each. */
.home-grid { display: grid; grid-template-columns: repeat(2, 1fr);
  gap: calc(var(--u) * 5) var(--gutter); padding-bottom: calc(var(--u) * 12); }
.home-grid .card { width: 100%; grid-column: auto; }
.gmeta { display: flex; justify-content: space-between; gap: var(--gutter);
  padding-top: calc(var(--u) * 1.5); font-size: 11px; font-weight: 500;
  letter-spacing: .08em; text-transform: uppercase; }
.gmeta .role { color: var(--fg2); }
/* each caption belongs to its own cell, revealed by pointing at that cell */
@media (hover: hover) {
  .home-grid .gmeta { opacity: 0; transition: opacity .25s var(--ease); }
  .home-grid .gcell:hover .gmeta,
  .home-grid .gcell:focus-within .gmeta { opacity: 1; }
}
/* below ~1100px the two halves no longer fit on one line */
@media (max-width: 1100px) {
  .gmeta { flex-direction: column; align-items: flex-start; gap: 2px; }
}
@media (max-width: 786px) { .gmeta, .cap { font-size: 12px; } }
@media (max-width: 860px) { .home-grid { grid-template-columns: 1fr; } }

.stack { display: flex; flex-direction: column; align-items: center;
  gap: calc(var(--u) * 4); padding-bottom: calc(var(--u) * 12); }
.card { position: relative; display: block; width: min(695px, 100%);
  aspect-ratio: 695 / 338; overflow: hidden; background: #111; }
.card img, .card .loop { position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; }
/* still 0.2s ease-out under a loop layer that comes in over 0.4s ease-in-out */
.card img { transition: opacity .2s ease-out; }
.card .loop { opacity: 0; transition: opacity .4s ease-in-out; }
.card:hover .loop, .card:focus-visible .loop, .card.playing .loop { opacity: 1; }
/* On touch a loop is either shown or not, with no crossfade. Any partial
   opacity blends the loop with the still beneath it, and since the two are
   different frames of the same film that reads as a double exposure. */
@media (hover: none) {
  .card .loop, .gallery .cell video { transition: none; }
}
/* Captions: role right-aligned to the left of the card, title left-aligned
   to its right, both 11px bold, 142px down the card. */
.row { display: grid; width: 100%; column-gap: 28px; align-items: start;
  grid-template-columns: 1fr min(695px, 100%) 1fr; }
/* pinned by column, not by source order: a row with no role line must not
   let the card fall into the narrow side column */
.cap { font-size: 11px; font-weight: 500; line-height: 1.35;
  letter-spacing: .08em; text-transform: uppercase; color: var(--fg);
  padding-top: 142px; }
/* scroll columns: captions belong to the piece under the pointer */
.stack .row .cap { transition: opacity .25s var(--ease); }
@media (hover: hover) {
  .stack .row .cap { opacity: 0; }
  .stack .row:hover .cap { opacity: 1; }
}
@media (hover: none) { .stack .row .cap { opacity: 1; } }
.role { grid-column: 1; text-align: right; }
.card { grid-column: 2; }
.label { grid-column: 3; text-align: left; }
.cat-head { grid-column: 1 / -1; font-size: var(--t-xl); font-weight: 700;
  padding-bottom: calc(var(--u) * 2); }
.cat-head.solo { grid-column: auto; }

/* Gallery categories: 2-column masonry, 4px gutters. CSS columns pack it
   without a masonry library. */
/* Uniform tiles rather than a masonry: these galleries mix portrait and
   landscape clips, so equal cells crop to fill and keep the columns even. */
.gallery { display: grid; grid-template-columns: repeat(2, 1fr); gap: 4px;
  padding-bottom: calc(var(--u) * 12); }
.gallery .cell { display: block; position: relative; aspect-ratio: 16 / 9;
  overflow: hidden; background: #111; }
.gallery .cell > *, .gallery .cell img, .gallery .cell picture img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; }
.gallery .cell video { object-fit: cover; }
/* a gallery cell IS its video: it rests on its poster frame and animates
   when played, so it must never be hidden */
/* Break the rhythm: every fifth cell runs the full width as a wide band, so
   the grid reads as a sequence rather than a perfect matrix. */
.gallery:not(.native):not(.masonry) .cell:nth-child(5n + 3) {
  grid-column: span 2; aspect-ratio: 21 / 9; }

/* Motion: every clip at its own frame ratio, nothing cropped. A 6-column
   track packs the mixed 16:9 and 9:16 pieces tight. */
.gallery.native { display: grid; grid-template-columns: repeat(6, 1fr);
  gap: var(--gutter); align-items: start; }
.gallery.native .cell { position: relative; overflow: hidden; background: #111; }
.gallery.native .cell.land { grid-column: span 3; }
.gallery.native .cell.port { grid-column: span 2; }
/* orientation supplies the variety; no width overrides that would break the
   row tiling */
.gallery.native .cell > *, .gallery.native .cell img,
.gallery.native .cell picture img { position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; }

/* Photo keeps the column masonry: stills at their own proportions, uncropped. */
.gallery.masonry { display: block; column-count: 2; column-gap: 4px; }
.gallery.masonry .cell { break-inside: avoid; margin-bottom: 4px;
  position: static; aspect-ratio: auto; overflow: visible; background: none; }
.gallery.masonry .cell > *, .gallery.masonry .cell img,
.gallery.masonry .cell picture img {
  position: static; width: 100%; height: auto; object-fit: fill; }
.gallery.masonry .cell:nth-child(5n + 3) { grid-column: auto; aspect-ratio: auto; }

@media (max-width: 700px) {
  .gallery { grid-template-columns: 1fr; }
  /* one per row: split two ways a 9:16 clip is only 185px wide */
  .gallery.native { grid-template-columns: 1fr; gap: 42px; }
  .gallery.native .cell.land, .gallery.native .cell.port { grid-column: span 1; }
  .gallery .cell:nth-child(5n + 3) { grid-column: span 1; }
  .gallery.masonry { column-count: 1; }
}
@media (max-width: 1100px) {
  .row { display: flex; flex-direction: column; gap: calc(var(--u)); }
  .card { order: 1; }
  .label { order: 2; }
  .role { order: 3; color: var(--fg2); }
  .cap { padding-top: 0; text-align: left; }
}
.card:focus-visible { outline: 2px solid var(--fg); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important;
    transition-duration: .01ms !important; }
}

/* vertical pieces: a third the width of a landscape tile, matched height */
.tile.portrait { grid-column: span 2; }
.tile.portrait .media { aspect-ratio: 9 / 16; }
/* too narrow for title and category on one line */
.tile.portrait .meta { flex-direction: column; align-items: flex-start; gap: 2px; }
@media (max-width: 860px) { .tile.portrait { grid-column: span 3; } }

.grid { display: grid; grid-template-columns: repeat(12, 1fr);
  gap: calc(var(--u) * 6) var(--gutter); padding-bottom: calc(var(--u) * 12); }
.section-label { grid-column: 1 / -1; font-size: var(--t-xs); font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--fg2);
  padding-top: calc(var(--u) * 6); border-top: 1px solid #1c1c1c; }
.tile { grid-column: span 6; position: relative; }
.tile.third { grid-column: span 4; }
.tile .media { aspect-ratio: 16 / 9; overflow: hidden; background: #111; position: relative; }
.tile .media > * { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.tile .meta { display: flex; justify-content: space-between; align-items: baseline;
  padding-top: calc(var(--u) * 1.5); }
.tile .title { font-size: var(--t-s); font-weight: 600; }
.tile .cat { font-size: var(--t-xs); color: var(--fg2); letter-spacing: .08em;
  text-transform: uppercase; }
.tile .media img, .tile .media video { transition: transform .6s var(--ease), opacity .4s var(--ease); }
.tile:hover .media img, .tile:hover .media video { transform: scale(1.03); }
@media (max-width: 900px) {
  .tile, .tile.third { grid-column: 1 / -1; }
  .grid { gap: calc(var(--u) * 5) var(--gutter); }
}

/* ---- project page ---- */
.proj-head { padding-bottom: calc(var(--u) * 6); }
.proj-head h1 { font-size: var(--t-2xl); font-weight: 700; letter-spacing: -.01em; }
.proj-head .cat { font-size: var(--t-xs); color: var(--fg2); letter-spacing: .08em;
  text-transform: uppercase; margin-top: var(--u); }
.proj-media { display: grid; gap: calc(var(--u) * 6); padding-bottom: calc(var(--u) * 10); }
.proj-media figure { background: #111; }
/* vertical pieces play at a third of the measure, not blown up to full width */
.proj-media figure.portrait { max-width: min(33%, 432px); background: none; }
/* several verticals sit side by side on one page */
.proj-media.verticals { grid-auto-flow: column; justify-content: start;
  gap: var(--gutter); }
.proj-media.verticals figure.portrait { max-width: none; width: 100%; }
@media (max-width: 760px) {
  .proj-media.verticals { grid-auto-flow: row; }
  .proj-media.verticals figure.portrait { max-width: 70%; }
}
@media (max-width: 860px) { .proj-media figure.portrait { max-width: 70%; } }
.blurb { max-width: calc(8 / 12 * 100%); font-size: var(--t-m); line-height: 1.6;
  color: var(--fg2); padding-bottom: calc(var(--u) * 8); }
.proj-link { font-size: var(--t-s); font-weight: 600;
  margin-top: calc(var(--u) * -5); padding-bottom: calc(var(--u) * 8); }
.proj-link a { border-bottom: 1px solid currentColor; padding-bottom: 2px; }
.pager { display: flex; justify-content: space-between; gap: var(--gutter);
  padding: calc(var(--u) * 6) 0 calc(var(--u) * 12); border-top: 1px solid #1c1c1c;
  font-size: var(--t-s); font-weight: 600; }
.pager .lbl { display: block; font-size: var(--t-xs); font-weight: 600; color: var(--fg2);
  letter-spacing: .08em; text-transform: uppercase; margin-bottom: var(--u); }
.pager a:hover { color: var(--fg2); }

/* ---- about / contact: 8-col editorial column ---- */
.editorial { max-width: calc((8 / 12) * (var(--maxw) - 2 * 96px)); padding-bottom: calc(var(--u) * 12); }
.editorial h1 { font-size: var(--t-xl); font-weight: 700; padding-bottom: calc(var(--u) * 4); }
.editorial p { font-size: var(--t-m); line-height: 1.6; color: var(--fg2);
  padding-bottom: calc(var(--u) * 3); }
.editorial a { color: var(--fg); border-bottom: 1px solid #333; }
.editorial a:hover { border-color: var(--fg); }

.site-foot { padding: calc(var(--u) * 6) 0 calc(var(--u) * 8); border-top: 1px solid #1c1c1c;
  font-size: var(--t-xs); color: var(--fg2); display: flex; justify-content: space-between;
  gap: var(--gutter); flex-wrap: wrap; }


/* ---------------------------------------------------------------------------
   Mobile layout at 390px: 8px side margins (near full-bleed), the title
   ABOVE the image at 14px regular, 42px between items, and a rules hamburger
   rather than a word.
   --------------------------------------------------------------------------- */
@media (max-width: 786px) {
  :root { --margin: 8px; }

  /* first item sits ~12px below a 90px header; same rhythm as the gaps */
  .home-grid, .stack, .gallery, main.grid { padding-top: 42px; }

  /* home grid: caption above the card */
  .home-grid { gap: 42px; }
  .gcell { display: flex; flex-direction: column; }
  .gcell .card { order: 2; }
  .gmeta { order: 1; padding: 0 0 8px; gap: 1px;
    font-size: 14px; font-weight: 400; letter-spacing: .02em; }
  .gmeta .label { color: var(--fg); }
  .gmeta .role { color: var(--fg2); font-size: 12px; }

  /* scroll columns: same shape */
  .stack { gap: 42px; }
  .row { gap: 0; }
  .row .label { order: 1; padding: 0 0 2px; font-size: 14px; font-weight: 400;
    color: var(--fg); }
  .row .role { order: 2; padding: 0 0 8px; font-size: 12px; color: var(--fg2); }
  .row .card { order: 3; }
  .stack .row .cap { opacity: 1; }   /* no hover, so the names stay put */

  /* gallery: match the same rhythm */
  .gallery { gap: 8px; }

  /* byline is desktop-only: the email lives on the Contact page */
  .byline { display: none; }

  /* hamburger: two rules */
  .nav-toggle { font-size: 0; width: 30px; height: 22px; position: relative; }
  .nav-toggle::before, .nav-toggle::after { content: ""; position: absolute;
    left: 0; right: 0; height: 2px; background: currentColor; }
  .nav-toggle::before { top: 6px; }
  .nav-toggle::after { top: 13px; }
  .site-head.open .nav-toggle::before { top: 10px; transform: rotate(45deg); }
  .site-head.open .nav-toggle::after { top: 10px; transform: rotate(-45deg); }
}
