/* 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 after Anton Tammi: one bar, wordmark + email hard left, nav hard
   right. Measured off that clone: 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 transplanted from the Anton Tammi source: 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 here, unlike Anton's near-white
   page, 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; }
/* measured on the source: 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) {
  /* Anton keeps the header compact on a phone and moves the menu behind a
     control. Expanded inline, 10 links pushed every page's work below the fold. */
  /* his header measures 90px with 8px above and 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. Anton swaps in a separate mobile menu for the same reason. */
  .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 card stack, cloned from the original 695x338 column.
   Still image rests; looping MP4 (converted from the original GIF) 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 and overlapped */
@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; }
/* timings measured off the live Wix site: 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. The
   original Wix hover toggled visibility for the same reason. */
@media (hover: none) {
  .card .loop, .gallery .cell video { transition: none; }
}
/* Captions, as on the original: 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, after Anton Tammi's
   photography grid. CSS columns pack it without a masonry library. */
/* Uniform tiles rather than a masonry: these galleries mix portrait and
   landscape clips, and column packing left one column with three items, the
   other with six, and large voids between them. Equal cells crop to fill. */
.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. Fading it out left the page blank. */
/* 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 with row spans measured after layout packs the mixed 16:9 and 9:16
   pieces tight instead of leaving the voids a column masonry produced. */
.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,
   which is the Anton photography grid. */
.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 after Anton Tammi, measured off the clone 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; }

  /* his 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; }

  /* his byline is .deskonly: the email is on the Contact page, not the header */
  .byline { display: none; }

  /* hamburger: two rules, as on his header */
  .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); }
}
