/* Arlo Radford — site styles.
   One sheet for every page. Tokens first, then the shared pieces (header,
   footer, links, loader, cursor), then each section in page order. */

@font-face {
  font-family: 'General Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/general-sans-400.woff2') format('woff2');
}
@font-face {
  font-family: 'General Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/general-sans-500.woff2') format('woff2');
}

@font-face {
  font-family: 'Gambetta';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/gambetta-500.woff2') format('woff2');
}
@font-face {
  font-family: 'Gambetta';
  font-style: italic;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/gambetta-500-italic.woff2') format('woff2');
}

:root {
  --ink: #111111;
  --paper: #F6F4F0;
  --muted: #4F4F4F;
  --muted-on-dark: #9A9A9A;
  --frame: #1A1A1A;
  --slide: #3A3A3A;
  --placeholder: #E2E0DB;
  --placeholder-2: #D6D3CD;
  --placeholder-3: #CBC8C1;
  --rule: rgba(17, 17, 17, 0.25);

  --font-display: 'Gambetta', Georgia, 'Times New Roman', serif;
  --font: 'General Sans', ui-sans-serif, system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;
  /* 16px, or more where a landscape iPhone's notch eats into the edge */
  --gutter: max(16px, env(safe-area-inset-left), env(safe-area-inset-right));
  --section: clamp(4rem, 3rem + 4vw, 6rem);
  --header-h: 72px;

  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-curtain: cubic-bezier(0.76, 0, 0.24, 1);

  /* client logo base height; each logo scales off it (see .logo-*) */
  --lh: 40px;

  /* the cursor: a plain 16px dot, ink on paper and paper on ink */
  --dot-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='8' fill='%23111111'/%3E%3C/svg%3E") 8 8, auto;
  --dot-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='8' fill='%23F6F4F0'/%3E%3C/svg%3E") 8 8, auto;
}

/* ---------- base ---------- */

*, *::before, *::after { box-sizing: border-box; }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--paper);
  /* scrolling only: no pinch or double-tap zoom (boot.js covers Safari's pinch) */
  touch-action: pan-x pan-y;
}
/* past halfway the page's own background is ink, so the bounce below the
   footer and the strip under a phone's floating toolbar match it (site.js) */
html.at-end { background: var(--ink); }
body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font);
  font-weight: 400;
  letter-spacing: -0.005em;
  color: var(--ink);
  background: var(--paper);
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img, video, svg { display: block; max-width: 100%; }
/* width/height attributes are there for layout stability; CSS decides the size */
img { height: auto; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, p, figure { margin: 0; }
button { font: inherit; color: inherit; letter-spacing: inherit; }
a, button { -webkit-tap-highlight-color: transparent; }
/* iOS draws its own play button over a loop it is not allowed to autoplay
   (Low Power Mode); the poster and the Play label are enough */
video::-webkit-media-controls-start-playback-button { display: none !important; -webkit-appearance: none; }
:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
/* main only takes focus as the skip link's target and after a page switch;
   a ring round the whole page would read as a stray line under the header */
#main:focus { outline: none; }
::selection { background: var(--ink); color: var(--paper); }

/* nothing scrolls behind an open lightbox or menu */
html:has(dialog[open]) { overflow: hidden; }

/* wording that changes on a phone */
.phone-only { display: none; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.skip-link {
  position: absolute;
  top: 12px; left: 12px;
  z-index: 100;
  padding: 10px 14px;
  background: var(--ink);
  color: var(--paper);
  font-size: 14px;
  transform: translateY(-200%);
}
.skip-link:focus { transform: none; }

/* ---------- type ---------- */

/* Gambetta for headings, General Sans for everything else */
.h1, .h2, .h3, .about-hello, .menu-links, .tile-label { font-family: var(--font-display); }
/* italic accent words in headings, e.g. Wedding <em>film</em> */
:is(.h1, .h2, .h3, .about-hello) em { font-style: italic; letter-spacing: -0.01em; }

.h1 {
  font-size: clamp(2.5rem, 1rem + 4vw, 3.75rem);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.02em;
}
.h2 {
  font-size: clamp(1.75rem, 1.1rem + 2.2vw, 2.625rem);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.h3 {
  font-size: clamp(1rem, 0.92rem + 0.35vw, 1.25rem);
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.02em;
}
.lede {
  max-width: 52ch;
  font-size: clamp(1rem, 0.85rem + 0.35vw, 1.125rem);
  line-height: 1.6;
  color: var(--muted);
}
.body {
  font-size: clamp(0.9375rem, 0.82rem + 0.25vw, 1rem);
  line-height: 1.6;
  color: var(--muted);
}
.body-narrow { max-width: 48ch; }
.body-cta { max-width: 46ch; }

/* ---------- layout helpers ---------- */

.section { padding: var(--section) var(--gutter); }
.section-flush-top { padding-top: 0; }
.stack-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 16px;
}
.section-head { margin-bottom: 40px; gap: 24px; }
.section-head > div { display: flex; flex-direction: column; align-items: center; gap: 16px; }

/* page titles on the inner pages */
.page-intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 16px;
  padding: calc(var(--section) * 0.75) var(--gutter) var(--section);
}

/* ---------- text link with the arrow ---------- */

.link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--rule);
  font-size: 14px;
  line-height: 1;
  white-space: nowrap;
}
/* the underline stays slim, but a finger gets a 44px target */
.link::after { content: ''; position: absolute; inset: -14px -6px; }
.link svg { width: 12px; height: 12px; transition: transform 0.3s ease-out; }
.link:hover svg, .link:focus-visible svg { transform: rotate(45deg); }
.cta .link { margin-top: 8px; }

/* ---------- header ---------- */

.site-header {
  position: relative;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  height: var(--header-h);
  padding: 0 var(--gutter);
  flex-shrink: 0;
}
.brand { display: flex; align-items: center; }
.brand img { height: 28px; width: auto; }
.nav { display: flex; gap: 28px; font-size: 14px; }
.nav a { display: block; }
.nav a[aria-current='page'] { border-bottom: 1px solid var(--ink); }

/* hover: the word climbs out the top and a copy climbs in behind it
   (the same label swap as the Tui Media nav) */
.swap { display: inline-grid; overflow: hidden; line-height: 1.3; }
.swap > span { grid-area: 1 / 1; transition: transform 380ms var(--ease-out); }
.swap > span:nth-child(2) { transform: translateY(115%); }
@media (hover: hover) and (pointer: fine) {
  /* the page you're on stays still */
  .nav a:not([aria-current='page']):hover .swap > span:nth-child(1) { transform: translateY(-115%); }
  .nav a:not([aria-current='page']):hover .swap > span:nth-child(2) { transform: translateY(0); }
}

.menu-open {
  display: none;
  align-items: center;
  min-height: 44px;
  padding: 0 0 0 16px;
  border: 0;
  background: transparent;
  font-size: 15px;
}
/* phone menu: a paper panel that slides down out of the header, the page
   dimmed behind it. Its top bar sits exactly over the header, so the
   wordmark stays put and only Menu turns to Close as the panel unrolls
   beneath. A tap outside, Close or Escape rolls it back up. */
.menu {
  position: fixed;
  inset: 0 0 auto;
  width: 100%;
  max-width: none;
  height: auto;
  max-height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  overflow-y: auto;
  background: var(--paper);
  color: var(--ink);
}
.menu:focus, .menu:focus-visible { outline: none; }
.menu::backdrop { background: rgba(17, 17, 17, 0.4); }
.menu[open] { display: block; animation: menu-down 460ms var(--ease-out) both; }
.menu[open] .menu-links { animation: menu-links-down 460ms var(--ease-out) both; }
.menu[open]::backdrop { animation: lb-fade 460ms ease-out both; }
.menu.is-closing { animation: menu-up 240ms ease-in both; }
.menu.is-closing .menu-links { animation: menu-links-up 240ms ease-in both; }
.menu.is-closing::backdrop { animation: lb-fade 240ms ease-in reverse both; }
@keyframes menu-down { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0); } }
@keyframes menu-up { from { clip-path: inset(0); } to { clip-path: inset(0 0 100% 0); } }
@keyframes menu-links-down { from { transform: translateY(-32px); } to { transform: none; } }
@keyframes menu-links-up { to { transform: translateY(-32px); } }
.menu-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--header-h);
  padding: 0 var(--gutter);
}
.menu-bar a { display: flex; align-items: center; min-height: 44px; }
.menu-bar img { height: 22px; width: auto; }
.menu-close {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0 0 0 16px;
  border: 0;
  background: transparent;
  font-size: 15px;
}
.menu-links {
  margin: 0;
  padding: 4px var(--gutter) 20px;
  list-style: none;
  font-size: 24px;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
.menu-links a { display: flex; align-items: center; min-height: 52px; }
.menu-links a[aria-current='page'] { color: var(--muted); }

@media (max-width: 720px) {
  .nav { display: none; }
  .menu-open { display: flex; }
}

/* ---------- footer ---------- */

.site-footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 24px;
  padding: 48px var(--gutter) 24px;
  background: var(--ink);
  color: var(--paper);
  /* ink carries on below the footer without adding any scroll, so the strip
     under a phone's floating toolbar at the very bottom is ink, not paper */
  box-shadow: 0 50vh 0 50vh var(--ink);
}
.site-footer .footer-logo { height: clamp(28px, 4.5vw, 60px); width: auto; }
.footer-nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px 28px;
  font-size: 14px;
}
.footer-nav a { transition: color 0.2s ease; }
.footer-nav a:hover { color: var(--muted-on-dark); }
.footer-meta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--muted-on-dark);
}

/* ---------- loader ----------
   A plain ink curtain with the wordmark rising letter by letter. It covers
   the page while it loads (boot.js puts it up before first paint) and comes
   back up for every page switch (site.js). */

.loader {
  /* in the page at the scroll position (site.js keeps top in step), not
     fixed to the screen: iOS Safari cuts anything fixed off at the top of
     its floating toolbar but draws the page itself underneath, so only a box
     in the page reaches the bottom of the screen. It runs on past the
     bottom, and the padding keeps the wordmark centred in the screen above
     the toolbar. */
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: calc(100vh + 120px);
  height: calc(100lvh + 120px);
  padding-bottom: 120px;
  padding-bottom: calc(100lvh - 100svh + 120px);
  z-index: 80;
  display: none;
  align-items: center;
  justify-content: center;
  background: var(--ink);
  pointer-events: none;
  /* the letters rise this far apart; quicker on a page switch */
  --step: 50ms;
}
.show-loader .loader { display: flex; }
/* while the curtain is up the whole window is ink, including the scrollbar
   strip and any overscroll, so no paper-coloured edge shows beside it */
html { overflow-y: scroll; scrollbar-gutter: stable; }
html.show-loader { background: var(--ink); }
html.show-loader:not(.is-leaving):not(.is-revealing) body { background: var(--ink); }
/* fully covered on a page switch: the page behind goes ink too, so the
   phone's own bars (which take the page's colour) match the curtain */
html.is-covered body { background: var(--ink); }
.loader-inner { display: flex; align-items: center; justify-content: center; }
.loader-word { position: relative; height: clamp(26px, 3.4vw, 40px); aspect-ratio: 982 / 142; }
.loader-word span { position: absolute; top: 0; bottom: 0; overflow: hidden; }
.loader-word img {
  width: 100%;
  height: 100%;
  transform: translateY(125%);
  transition: transform 560ms var(--ease-expo);
}
.loader.is-playing .loader-word img { transform: none; }
/* letter slots across the 982-wide wordmark, a --step apart */
.loader-word span:nth-child(1)  { left: 0%;      width: 9.267%; }
.loader-word span:nth-child(2)  { left: 9.674%;  width: 7.637%; }
.loader-word span:nth-child(3)  { left: 18.228%; width: 6.415%; }
.loader-word span:nth-child(4)  { left: 24.644%; width: 9.572%; }
.loader-word span:nth-child(5)  { left: 38.697%; width: 7.434%; }
.loader-word span:nth-child(6)  { left: 46.130%; width: 9.165%; }
.loader-word span:nth-child(7)  { left: 55.703%; width: 8.452%; }
.loader-word span:nth-child(8)  { left: 65.173%; width: 6.415%; }
.loader-word span:nth-child(9)  { left: 71.894%; width: 9.572%; }
.loader-word span:nth-child(10) { left: 82.485%; width: 7.637%; }
.loader-word span:nth-child(11) { left: 90.937%; width: 8.452%; }
.loader-word span:nth-child(2) img { transition-delay: calc(var(--step) * 1); }
.loader-word span:nth-child(3) img { transition-delay: calc(var(--step) * 2); }
.loader-word span:nth-child(4) img { transition-delay: calc(var(--step) * 3); }
.loader-word span:nth-child(5) img { transition-delay: calc(var(--step) * 4); }
.loader-word span:nth-child(6) img { transition-delay: calc(var(--step) * 5); }
.loader-word span:nth-child(7) img { transition-delay: calc(var(--step) * 6); }
.loader-word span:nth-child(8) img { transition-delay: calc(var(--step) * 7); }
.loader-word span:nth-child(9) img { transition-delay: calc(var(--step) * 8); }
.loader-word span:nth-child(10) img { transition-delay: calc(var(--step) * 9); }
.loader-word span:nth-child(11) img { transition-delay: calc(var(--step) * 10); }
/* switching page: the curtain rises from the bottom to cover this one */
.is-leaving .loader { --step: 30ms; animation: curtain-up 800ms var(--ease-curtain) both; }
@keyframes curtain-up { from { transform: translateY(100%); } to { transform: none; } }
/* the curtain lifts with the wordmark on it. An animation rather than a
   transition, so it still runs when it takes over straight from curtain-up. */
.loader.is-lifted { animation: curtain-lift 1000ms var(--ease-curtain) both; }
@keyframes curtain-lift { from { transform: none; } to { transform: translateY(-100%); } }

/* ---------- home: hero tiles ---------- */

/* the header sits above the tiles; together they fill the first screen */
.hero {
  height: calc(min(100svh, 48vw + 160px) - var(--header-h));
  min-height: min(calc(560px - var(--header-h)), calc(100svh - var(--header-h)));
}
.tiles {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  padding: 0 8px 16px;
  transition: grid-template-columns 0.6s cubic-bezier(0.25, 1, 0.5, 1);
}
.tiles:has(.tile:nth-child(1):focus-visible) { grid-template-columns: 4fr 1fr 1fr; }
.tiles:has(.tile:nth-child(2):focus-visible) { grid-template-columns: 1fr 4fr 1fr; }
.tiles:has(.tile:nth-child(3):focus-visible) { grid-template-columns: 1fr 1fr 4fr; }
/* mouse only: on a tablet a tap would stick the hover open before it navigates */
@media (hover: hover) and (pointer: fine) {
  .tiles:has(.tile:nth-child(1):hover) { grid-template-columns: 4fr 1fr 1fr; }
  .tiles:has(.tile:nth-child(2):hover) { grid-template-columns: 1fr 4fr 1fr; }
  .tiles:has(.tile:nth-child(3):hover) { grid-template-columns: 1fr 1fr 4fr; }
}
.tile { min-width: 0; padding: 0 8px; color: var(--paper); }
.tile:focus-visible { outline: none; }
.tile:focus-visible .tile-frame { outline: 2px solid var(--ink); outline-offset: 2px; }
.tile-frame {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  overflow: hidden;
  background: var(--placeholder);
}
.tile:nth-child(2) .tile-frame { background: var(--placeholder-2); }
.tile:nth-child(3) .tile-frame { background: var(--placeholder-3); }
.tile-frame img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.shade {
  position: absolute;
  inset: 0;
  background: rgba(17, 17, 17, 0.35);
  opacity: 0;
  transition: opacity 0.3s ease;
}
.tile-label {
  position: relative;
  font-size: 15px;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.4s ease 0.15s, transform 0.5s cubic-bezier(0.25, 1, 0.5, 1) 0.15s;
}
.tile-label svg { display: none; }
.tile:not(:hover):not(:focus-visible) .tile-label { transition-delay: 0s; }
.tile:hover .shade, .tile:focus-visible .shade { opacity: 1; }
.tile:hover .tile-label, .tile:focus-visible .tile-label { opacity: 1; transform: none; }

/* ---------- home: about ---------- */

.about-intro { gap: 40px; }
.about-intro .h2 { max-width: 18ch; }
.about-grid {
  width: 100%;
  max-width: 880px;
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  gap: 40px;
  align-items: stretch;
  text-align: left;
}
.about-grid img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; background: var(--frame); }
.about-copy {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
}
.about-copy > div { display: flex; flex-direction: column; gap: 18px; }

/* ---------- client logos ---------- */

.clients { gap: 40px; }
.logos {
  width: 100%;
  max-width: 1040px;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 40px 24px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.logos li {
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(var(--lh) * 1.6);
}
/* each mark sized by eye so they read at about the same weight */
.logos img { width: auto; max-width: 100%; height: calc(var(--lh) * var(--k, 1)); object-fit: contain; }
.logo-nikon { --k: 0.75; }
.logo-sky-automotive { --k: 1.3; }
.logo-team-bainbridge { --k: 1.15; }
.logo-moana { --k: 1.1; }
.logo-nelson-city-council { --k: 1.15; }
.logo-johnson-residential { --k: 0.425; }
.logo-zebratech { --k: 0.8; }
.logo-nelson-english-centre { --k: 1.05; }
.logo-mac-hops { --k: 0.875; }
.logo-nelson-auto-glass { --k: 0.85; }

/* ---------- home: commercial reel ---------- */

.reel-section {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 40px;
  padding: var(--section) 0;
  background: var(--ink);
  color: var(--paper);
}
.reel-section .stack-center { padding: 0 var(--gutter); }
.reel-section .body { color: var(--muted-on-dark); }
.reel {
  --w: min(70cqw, 70svh * 16 / 9);
  --gap: 16px;
  position: relative;
  width: 100%;
  overflow: hidden;
  container-type: inline-size;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
}
.reel-track {
  display: flex;
  gap: var(--gap);
  /* --lead: where the current film's left edge sits (centred, or at the gutter on phones) */
  transform: translateX(calc(var(--lead, 50cqw - var(--w) / 2) - var(--i, 0) * (var(--w) + var(--gap)) + var(--dx, 0px)));
  transition: transform 0.7s var(--ease-expo);
}
.reel-track.is-dragging { transition: none; }
.reel-title { display: none; }
.slide {
  position: relative;
  flex: none;
  width: var(--w);
  aspect-ratio: 16 / 9;
  padding: 0;
  border: 0;
  overflow: hidden;
  background: var(--slide);
}
.slide video { width: 100%; height: 100%; object-fit: cover; pointer-events: none; }
.slide:focus-visible { outline: 2px solid var(--paper); outline-offset: 4px; }
.reel-cursor {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  font-size: 16px;
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
}
.reel.has-label .reel-cursor { opacity: 1; }
.dots { display: flex; justify-content: center; align-items: center; }
.dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 32px;
  padding: 0 3px;
  border: 0;
  background: transparent;
}
.dot span {
  display: block;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--muted);
  transition: width 0.4s ease, background 0.4s ease;
}
.dot[aria-current='true'] span { width: 22px; background: var(--paper); }
.dot:focus-visible { outline: 2px solid var(--paper); outline-offset: 2px; border-radius: 6px; }

/* "Play with sound" on every film, for touch screens where there is no
   hover label to say a tap opens it */
.play-pill { display: none; }
.play-pill svg { width: 9px; height: 10px; }
@media (hover: none), (max-width: 720px) {
  .play-pill {
    position: absolute;
    left: 12px;
    bottom: 12px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 32px;
    padding: 0 14px;
    border-radius: 999px;
    background: rgba(17, 17, 17, 0.72);
    color: var(--paper);
    font-size: 13px;
    line-height: 1;
    pointer-events: none;
    transition: opacity 0.3s ease;
  }
  .slide[aria-current='false'] .play-pill { opacity: 0; }
}

/* ---------- media blocks ---------- */

.still { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; background: var(--frame); }

/* ---------- photo gallery (home + photography) ----------
   Justified rows: every photo keeps its own aspect ratio (--r, set per tile),
   nothing is cropped. A tile's flex-basis is its ratio times the target row
   height, so a row fills up with whole photos and then stretches to the edges,
   the last row included, so the gallery always ends flush. */

.gallery {
  --row: clamp(240px, 26vw, 420px);
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.gallery li { flex: calc(var(--r) * 100) 1 calc(var(--r) * var(--row)); aspect-ratio: var(--r); min-width: 0; }
/* phones: two even columns instead of rows (arGallery in boot.js places each photo) */
.gallery.is-columns { position: relative; display: block; }
.gallery.is-columns li { position: absolute; }
.gallery-more { display: none; }
.feature-title { display: none; }
/* home wedding film: capped so it doesn't fill the whole screen */
.feature-wrap { max-width: 880px; margin-inline: auto; }
.photo {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  overflow: hidden;
  background: var(--frame);
}
.photo img { width: 100%; height: 100%; object-fit: cover; transition: opacity 0.25s ease; }
.photo:hover img { opacity: 0.85; }
.photo:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ---------- photo lightbox ----------
   A page of its own: paper, the wordmark top left, close top right, the photo
   at its full shape in the middle and prev / next underneath. */

.photobox {
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--paper);
  color: var(--ink);
}
.photobox:focus, .photobox:focus-visible, .lightbox:focus, .lightbox:focus-visible { outline: none; }
.photobox[open] { display: flex; flex-direction: column; animation: pb-in 260ms ease-out both; }
.photobox.is-closing { animation: pb-out 200ms ease-in both; }
@keyframes pb-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pb-out { to { opacity: 0; } }
.photobox-bar {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--header-h);
  padding: 0 var(--gutter);
}
.photobox-bar img { height: 28px; width: auto; }
.photobox-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-right: -10px;
  padding: 0;
  border: 0;
  background: transparent;
}
.photobox-close svg { width: 20px; height: 20px; }
.photobox-figure {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px var(--gutter);
}
.photobox-figure img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  transition: opacity 0.25s ease;
}
.photobox-figure img.is-loading { opacity: 0; }
.photobox-nav {
  flex: none;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  min-height: 64px;
  padding: 0 var(--gutter) 8px;
  font-size: 14px;
}
.photobox-nav button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
}
.photobox-nav button:hover { text-decoration: underline; text-underline-offset: 4px; }
.photobox-nav svg { width: 22px; height: 22px; }
.pb-icon, .pb-count { display: none; }
.pb-count { color: var(--muted); }

/* ---------- commercial page: film grid ---------- */

.films {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 40px 16px;
}
.film { display: flex; flex-direction: column; gap: 16px; }
.film-play {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: 0;
  overflow: hidden;
  background: var(--frame);
}
.film-play video { width: 100%; height: 100%; object-fit: cover; pointer-events: none; }
.films-below { margin-top: 16px; }
.films-below .film { max-width: 560px; }
.film-caption { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }

/* ---------- about page ---------- */

.about-page { padding-top: calc(var(--section) * 0.75); }
.about-page .h1 { margin-bottom: calc(var(--section) * 0.6); text-align: center; }
/* photo and copy sit together as one block, centred on the page */
.about-page-grid {
  width: 100%;
  max-width: 1240px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: clamp(32px, 6vw, 112px);
  align-items: center;
}
.about-photo {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--frame);
}
.about-photo > * { position: absolute; inset: 0; width: 100%; height: 100%; transition: transform 800ms var(--ease-expo); }
.about-photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 25%; }
.about-photo:hover > * { transform: scale(1.04); }
.about-page-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  gap: 18px;
  max-width: 540px;
}
.about-page-copy .about-hello {
  margin: 0 0 6px;
  font-size: clamp(2rem, 1.4rem + 2vw, 3.25rem);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.about-page-copy .body { max-width: 50ch; }
.about-links { display: flex; flex-wrap: wrap; gap: 14px 36px; margin-top: 14px; }

/* ---------- lightbox ---------- */

.lightbox {
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 72px var(--gutter);
  border: 0;
  background: transparent;
  color: var(--paper);
}
.lightbox[open] { display: flex; align-items: center; justify-content: center; }
.lightbox::backdrop { background: rgba(17, 17, 17, 0.94); }
/* an open film or photo viewer: iOS Safari draws the page itself, not the
   viewer, under its floating toolbar, so once the viewer has faded in the
   page behind it is hidden and takes the viewer's colour, and comes back
   the moment it starts to close */
html:has(.lightbox[open]:not(.is-closing)),
html:has(.lightbox[open]:not(.is-closing)) body {
  background: var(--ink);
  transition: background-color 0s 300ms;
}
html:has(.photobox[open]:not(.is-closing)),
html:has(.photobox[open]:not(.is-closing)) body {
  background: var(--paper);
  transition: background-color 0s 300ms;
}
html:has(.lightbox[open]:not(.is-closing), .photobox[open]:not(.is-closing)) :is(.site-header, main, .site-footer) {
  visibility: hidden;
  transition: visibility 0s 300ms;
}
/* open: the backdrop fades and the film settles up into place; close reverses it quickly */
.lightbox[open]::backdrop { animation: lb-fade 280ms ease-out both; }
.lightbox[open] .lightbox-media { animation: lb-in 420ms var(--ease-out) both; }
.lightbox[open] .lightbox-close { animation: lb-fade 280ms ease-out 120ms both; }
.lightbox.is-closing::backdrop { animation: lb-fade 220ms ease-in reverse both; }
.lightbox.is-closing .lightbox-media { animation: lb-out 220ms ease-in both; }
.lightbox.is-closing .lightbox-close { animation: lb-fade 160ms ease-in reverse both; }
@keyframes lb-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes lb-in { from { opacity: 0; transform: translateY(12px) scale(0.97); } to { opacity: 1; transform: none; } }
@keyframes lb-out { to { opacity: 0; transform: translateY(8px) scale(0.98); } }
.lightbox-close {
  position: absolute;
  top: 14px;
  right: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
}
.lightbox-close svg { width: 20px; height: 20px; }
.lightbox-media {
  position: relative;
  display: block;
  padding: 0;
  border: 0;
  background: #000;
}
.lightbox-media video {
  width: auto;
  height: auto;
  max-width: min(calc(100vw - 2 * var(--gutter)), 1280px);
  max-height: calc(100dvh - 144px);
  pointer-events: none;
}
.sound {
  position: absolute;
  left: 16px;
  bottom: 16px;
  display: inline-flex;
  align-items: center;
  height: 28px;
  padding: 0 12px;
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.7);
  font-size: 12px;
  line-height: 1;
}
.sound[hidden] { display: none; }

/* ---------- 404 ---------- */

.not-found { min-height: 60vh; justify-content: center; }

/* ---------- cursor ----------
   Only where there is a real pointer. Over ink (footer, reel, lightbox,
   menu) the dot flips to paper so it never disappears. Over the reel the
   moving label (View / Next / Previous / Drag) replaces the dot. */

@media (hover: hover) and (pointer: fine) {
  html, a, button, label, select, summary { cursor: var(--dot-dark); }
  .on-dark, .on-dark a, .on-dark button { cursor: var(--dot-light); }
  input, textarea { cursor: text; }
  .reel.has-label, .reel.has-label * { cursor: none; }
}
@media (hover: none) {
  .reel-cursor { display: none; }
  /* no hover on touch: the labels and their shade are always on */
  .tile-label { opacity: 1; transform: none; }
  .tile .shade { opacity: 1; }
}

/* ---------- breakpoints ---------- */

@media (max-width: 900px) {
  :root { --lh: 32px; }
  .reel { --w: min(86cqw, 70svh * 16 / 9); --gap: 12px; }
  .about-grid, .about-page-grid, .films { grid-template-columns: minmax(0, 1fr); }
  .about-page-grid { max-width: 560px; }
  .about-photo { width: 100%; }
  /* one film per row, so each can keep its own shape (the Milson teaser is 5:4) */
  .film-play { aspect-ratio: var(--ar, 16 / 9); max-height: 52svh; }
  .films-below .film { max-width: none; }
}

/* phones */
@media (max-width: 720px) {
  :root { --lh: 30px; --header-h: 64px; }
  .brand img { height: 22px; }
  .section-head { margin-bottom: 28px; }
  .phone-only { display: inline; }
  .wide-only { display: none; }

  /* home: the three tiles share the first screen */
  .hero { height: auto; min-height: 0; }
  .tiles {
    grid-template-columns: minmax(0, 1fr) !important;
    gap: 8px;
    padding: 0 var(--gutter) var(--gutter);
  }
  .tile { height: clamp(200px, calc((100svh - var(--header-h) - 32px) / 3), 280px); padding: 0; }
  .tile-frame { align-items: flex-end; justify-content: flex-start; }
  .tile-label {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 16px 14px;
    font-size: 24px;
    font-weight: 500;
    letter-spacing: -0.01em;
  }
  .tile-label svg { display: block; width: 14px; height: 14px; }

  /* home: a shorter crop of the portrait and the first two paragraphs; the rest is on About */
  .about-intro { gap: 28px; }
  .about-grid { gap: 24px; }
  .about-grid img { height: 280px; aspect-ratio: auto; object-position: 50% 30%; }
  .about-copy > div > p:nth-child(n + 3) { display: none; }

  .logos { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 16px; }

  /* reel: no full-screen band, the film starts at the gutter with the next one peeking in */
  .reel-section { min-height: 0; gap: 32px; }
  .reel { --lead: var(--gutter); --w: calc(100cqw - 64px); --gap: 12px; }
  .slide { transition: opacity 0.4s ease; }
  .slide[aria-current='false'] { opacity: 0.55; }
  .reel-title { display: block; padding: 12px var(--gutter) 0; font-size: 15px; line-height: 1.4; }
  .dot { min-width: 44px; height: 44px; }

  .feature-title { display: block; margin-top: 12px; font-size: 15px; line-height: 1.4; }

  .gallery { --row: 200px; gap: 12px; }
  .gallery-more { display: flex; justify-content: center; margin-top: 32px; }

  /* the closing "Get in touch" becomes a full-width button */
  .cta .link {
    align-self: stretch;
    justify-content: center;
    gap: 10px;
    height: 52px;
    margin-top: 16px;
    padding: 0;
    border: 0;
    background: var(--ink);
    color: var(--paper);
    font-size: 15px;
  }

  /* photo viewer: the photo runs edge to edge, arrows and a count underneath */
  .photobox-bar img { height: 22px; }
  .photobox-figure { padding: 0; }
  .photobox-nav {
    justify-content: space-between;
    min-height: 88px;
    padding: 0 8px max(16px, env(safe-area-inset-bottom));
  }
  .photobox-nav button { min-width: 56px; min-height: 56px; }
  .pb-word, .pb-sep { display: none; }
  .pb-icon, .pb-count { display: block; }

  /* film player: edge to edge */
  .lightbox { padding: 64px 0; }
  .lightbox-media video { max-width: 100vw; max-height: calc(100dvh - 128px); }

  /* footer: links in two columns, each a full 44px row */
  .site-footer {
    align-items: flex-start;
    text-align: left;
    gap: 28px;
    padding-bottom: calc(40px + env(safe-area-inset-bottom, 0px));
  }
  .site-footer .footer-logo { height: 24px; }
  .footer-nav {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 16px;
    width: 100%;
    font-size: 15px;
  }
  .footer-nav a { display: flex; align-items: center; min-height: 44px; }
  .footer-nav a[href^='mailto:'] { grid-column: 1 / -1; }
  .footer-meta {
    align-self: stretch;
    align-items: flex-start;
    padding-top: 20px;
    border-top: 1px solid rgba(246, 244, 240, 0.15);
  }
}

@media (max-height: 500px) and (orientation: landscape) {
  .lightbox { padding: 12px 64px; }
  .lightbox-media video { max-width: calc(100vw - 128px); max-height: calc(100dvh - 24px); }
  .photobox-bar { height: 52px; }
  .photobox-nav { min-height: 48px; padding-bottom: 4px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }
  .swap > span:nth-child(2) { display: none; }
}

