/* Dan Scott, art director. Look taken from the Sue PDF:
   paper #f3f4f6, ink #101216, grey #5f6672, rule #d9dce2,
   Gabarito 500 + 400 only, 12-col grid, 80px margins (20px on phones).
   Home opens on the PDF cover (full screen) and ends on the PDF end page. */

@font-face {
  font-family: "Gabarito";
  src: url("/assets/fonts/gabarito.woff2") format("woff2");
  font-weight: 400 900;
  font-display: swap;
}

:root {
  --paper: #f3f4f6;
  --ink: #101216;
  --grey: #5f6672;
  --rule: #d9dce2;
  --m: 80px;          /* page margin */
  --g: 20px;          /* gutter */
  --max: 1400px;     /* the reading measure: copy, credits, the hero */
  --frame: 2400px;   /* the outer frame: name, nav, footer. Dan, 12 Nov 2026:
                        the furniture sits out at the page margin, the same
                        edge the work grid runs to, and only the reading
                        column stays narrow in the middle. */
}
@media (max-width: 900px) { :root { --m: 40px; } }
@media (max-width: 600px) { :root { --m: 20px; --g: 16px; } }

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: "Gabarito", system-ui, sans-serif;
  font-weight: 400;
  font-size: 18px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: inherit; text-decoration: none; }
a:hover { color: var(--grey); }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
img, video, iframe { display: block; max-width: 100%; }

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 var(--m); }
.wrap--frame { max-width: var(--frame); margin: 0 auto; padding: 0 var(--m); }

/* A campaign page is as wide as its film can be and still land whole on the
   screen, so the hero and every picture under it share one left and right
   edge. Dan, 12 Nov 2026: capping the film on its own centred it inside the
   measure and it stopped lining up with the artwork below. The column moves,
   not the film. */
.wrap--project {
  max-width: clamp(900px, calc(62vh * 16 / 9 + 2 * var(--m)), var(--max));
}
@media (max-width: 900px) { .wrap--project { max-width: var(--max); } }

/* ---------- Type ---------- */

.label {
  font-size: 14px;
  line-height: 16px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grey);
}
@media (max-width: 600px) { .label { font-size: 12px; line-height: 14px; } }

.lockup {
  display: block;
  margin: 0;
  font-size: clamp(56px, 7.4vw, 132px);
  line-height: 0.98;
  letter-spacing: -0.03em;
  font-weight: 500;
}
.lockup span { display: block; font-weight: 400; color: var(--grey); }
a.lockup:hover { color: var(--ink); }
/* on phones the name fills the width, like the PDF cover */
@media (max-width: 600px) {
  /* big, but with breathing room on the right so it reads as designed, not stretched */
  .lockup { font-size: calc((100vw - 2 * var(--m)) / 6); letter-spacing: -0.03em; line-height: 1.02; }
  .lockup span { white-space: nowrap; }
}

.rule { border: 0; border-top: 1px solid var(--rule); margin: 48px 0; }
@media (max-width: 600px) { .rule { margin: 28px 0; } }

/* A chapter: one campaign inside a page that carries several. Dan, 12 Nov
   2026. The name in the grey label the whole site uses, a line about the
   work, and the people who changed on that one. What never changed, the
   agency and the CD and the AD, is at the foot once. */
/* The title and the Detail switch share a line. The switch is a label like
   every other label on the site, and it sits on the title's baseline so it
   reads as part of the heading rather than as a button stuck beside it. */
.title-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--g); }
.detail-toggle {
  flex: 0 0 auto;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
  transition: color .2s ease;
}
.detail-toggle:hover, .detail-toggle:focus-visible { color: var(--ink); }
.detail-toggle[aria-pressed="true"] { color: var(--ink); }

/* What the switch turns on: under each piece, the campaign it belongs to, a
   line about it, and the people who changed on that one. Hidden until asked. */
.detail { display: none; }
.show-detail .detail { display: block; padding: 12px 0 0; max-width: 34em; }
.detail .label { display: block; margin-bottom: 6px; }
.d-about { margin: 0; font-size: 16px; line-height: 23px; text-wrap: pretty; }
.d-credits { margin: 4px 0 0; font-size: 14px; line-height: 21px; color: var(--grey); }
.show-detail .detail--hero { padding-top: 14px; }
@media (max-width: 600px) {
  .d-about { font-size: 15px; line-height: 22px; }
  .d-credits { font-size: 13px; line-height: 20px; }
  .title-row { flex-direction: row; align-items: baseline; }
}

/* ---------- Info ---------- */

/* Set like the credits on a campaign page: a grey label, then the facts in a
   plain list. Dan, 12 Nov 2026 — the work answers everything except who he has
   done it for and where, and that is a list, not a paragraph. Three columns on
   a laptop so the whole thing lands on one screen; one column on a phone. */
.info { padding-bottom: 72px; }
@media (max-width: 600px) { .info { padding-bottom: 16px; } }
.info .title { margin-bottom: 44px; }
.info-block { margin-bottom: 44px; }
.info-block .label { display: block; margin-bottom: 14px; }
.info-list {
  list-style: none;
  margin: 0;
  padding: 0;
  columns: 3;
  column-gap: var(--g);
  font-size: 19px;
  line-height: 30px;
}
.info-list li { break-inside: avoid; }
/* What I do reads as sentences, so it keeps a single measure. Agencies is a
   short list and looked stranded across three columns, so it takes one. */
.info-block:first-of-type .info-list { columns: 1; max-width: 34em; text-wrap: pretty; }
.info-block:nth-of-type(2) .info-list { columns: 1; }
@media (max-width: 900px) { .info-list, .info-block:first-of-type .info-list { columns: 2; } }
/* On a phone it was one long column of same-sized type and read as a dump.
   Dan, 12 Nov 2026. The two lines about the work stay at reading size and
   carry the page; the agencies and the clients drop a size and the clients
   take two columns, so the whole page is about a screen and a half instead of
   four. */
@media (max-width: 600px) {
  .info .title { margin-bottom: 26px; }
  .info-block { margin-bottom: 28px; }
  .info-block .label { margin-bottom: 10px; }
  .info-list { font-size: 15px; line-height: 24px; }
  .info-block:first-of-type .info-list { columns: 1; font-size: 17px; line-height: 26px; }
  .info-block:first-of-type li + li { margin-top: 2px; }
  .info-block:nth-of-type(2) .info-list { columns: 1; }
  .info-block:nth-of-type(3) .info-list { columns: 2; column-gap: var(--g); }
}

/* ---------- Sheets: PDF cover and end page, full screen ---------- */

.sheet {
  max-width: var(--frame);
  margin: 0 auto;
  padding: 48px var(--m) 44px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 36px;
}
/* The name does not get a screen to itself. Dan, 12 Nov 2026: a CD with four
   minutes should not have to scroll past a held breath to reach the work, so
   the masthead, the line about the work and the top of the grid share the
   opening screen. */
.sheet-top { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--g); }
/* The end of a page is the name and the address, nothing else. Dan, 12 Nov
   2026. They sit close enough to read as one lockup rather than as two
   things that happen to share a footer. */
/* The end of a page: the name on the left, the address on the right, sitting
   on the same last line. Dan, 12 Nov 2026 — stacked in the left-hand corner it
   left the right-hand half of the page empty and read as unfinished. This
   echoes the top of a campaign page, where the name holds one corner and the
   nav holds the other. */
.sheet--end {
  flex-direction: row;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--g);
}
.sheet--end .sheet-top { flex: 0 1 auto; }
/* The closer is a sign-off, not a second masthead. Dan, 12 Nov 2026: at
   masthead size the name shouted over the address it was paired with. Set at
   the same size as the address, with the role in grey after it, the whole end
   of the page reads as one line of type across the frame, and it echoes the
   title treatment on a campaign page: black, grey, full stop. */
.sheet--end .lockup {
  font-size: clamp(22px, 2.6vw, 40px);
  line-height: 1.25;
  letter-spacing: -0.015em;
}
.sheet--end .lockup span { display: inline; margin-left: 0.34em; }
.sheet--end .sheet-bottom { flex: 0 0 auto; padding-bottom: 0.18em; }
.sheet--end .contact-h2 { margin: 0; }
@media (max-width: 760px) {
  .sheet--end { flex-direction: column; align-items: flex-start; gap: 0; padding: 30px var(--m) 30px; }
  .sheet--end .sheet-bottom { padding-bottom: 0; margin-top: 8px; }
}
.sheet-tag { padding-top: 12px; white-space: nowrap; }
/* The way back to the grid. An arrow drawn in the page's own line weight with
   the word under it, rather than a sentence pretending to be a button. */
.up { display: inline-flex; flex-direction: column; align-items: center; gap: 8px; }
.up svg { display: block; overflow: visible; }
/* Dan, 11 Nov 2026: no tail, just a solid triangle pointing up. The triangle
   carries the weight in black and goes grey on the way in; the word under it
   stays grey throughout, like every other label on the site. */
.up svg path { fill: var(--ink); stroke: none; transition: fill .28s ease; }
.up:hover svg path, .up:focus-visible svg path { fill: var(--grey); }
.up span { font-size: 13px; letter-spacing: .08em; text-transform: uppercase; }
.up { transition: transform .28s cubic-bezier(.2,.7,.2,1); }
.up:hover { transform: translateY(-4px); }
.sheet-tag:hover { color: var(--ink); }
.sheet-bottom .rule { margin-top: 0; }

.cols {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--g);
  row-gap: 40px;
}
.cols > div { grid-column: span 6; display: flex; flex-direction: column; gap: 8px; }
/* The sign-off sits above the rule, on the same seven columns and at the same
   size as the intro at the top of the site, so the page opens and closes on
   the same measure. */
.signoff {
  margin: 0 0 40px;
  color: var(--grey);
  max-width: calc((100% - 11 * var(--g)) / 12 * 7 + 6 * var(--g));
  font-size: 22px;
  line-height: 31px;
  text-wrap: balance; }
@media (max-width: 600px) {
  .signoff { max-width: none; margin-bottom: 28px; font-size: 19px; line-height: 27px; }
}
.cols h2 {
  margin: 0;
  font-size: 40px; line-height: 48px; font-weight: 500; letter-spacing: -0.02em;
  overflow-wrap: anywhere;
}
/* The intro sits in grey, like the role under the name and every label on the
   site. "Hello." stays in ink above it, so the two read as a greeting and then
   the detail, not as one block of body copy. Dan, 11 Nov 2026. */
.cols p { margin: 0; font-size: 24px; line-height: 32px; max-width: 30em; color: var(--grey); text-wrap: pretty; }

@media (max-width: 760px) {
  .cols > div { grid-column: 1 / -1; }
  .cols h2 { font-size: 28px; line-height: 34px; }
  .cols p { font-size: 18px; line-height: 26px; }
}
@media (max-width: 600px) {
  .sheet { padding-top: 24px; padding-bottom: 28px; gap: 48px; }
  /* The end sheet is a name and an address, not a cover: it keeps them
     together rather than pushing them to opposite ends of a tall box.
     Dan, 12 Nov 2026 — this was the 48px gap on a phone. */
  .sheet--end { gap: 0; justify-content: flex-start; padding-top: 30px; padding-bottom: 30px; }
  .sheet-top { flex-direction: column-reverse; gap: 20px; }
  .sheet-tag { padding-top: 0; }
  .cols { row-gap: 28px; }
  .cols h2 { font-size: 26px; line-height: 32px; }
  .cols p { font-size: 17px; line-height: 25px; }
}

.sheet--end { border-top: 1px solid var(--rule); }

/* Contact email stays on one line, whatever the width */
h2.contact-h2 { font-size: clamp(20px, 5vw, 40px); line-height: 1.1; font-weight: 500;
  letter-spacing: -0.015em; }
h2.contact-h2 a { white-space: nowrap; }

/* ---------- Work grid: full-bleed, edge to edge ---------- */

/* A repeated tile at the foot of an odd grid. It behaves like any other,
   except it is not a second way into the same campaign. */
.tile-again { display: contents; }
/* Rows are the height of an ordinary tile, so a piece that takes two columns
   also takes two rows and stays at 16:9, and a standing poster takes one
   column by two. Dense flow closes the gaps those leave behind. Dan, 12 Nov
   2026: a grid of identical rectangles reads as generated rather than art
   directed. */
.grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* auto, not a sum from 100vw: 100vw counts the scrollbar but the grid does
     not, so every row came out a few pixels taller than the picture in it and
     the tile's own black showed through as a line between the rows. The
     media's 16/9 sets the height instead. Dan, 12 Nov 2026: "little black
     lines inbetween grids appear randomly on roll over." */
  grid-auto-rows: auto;
  grid-auto-flow: row dense;
  max-width: 2400px;
  margin: 0 auto;
}
.tile--wide { grid-column: span 2; grid-row: span 2; }
.tile--tall { grid-row: span 2; }
.tile--tall .media { aspect-ratio: 16 / 18; }
.tile--wide .media, .tile--tall .media { height: 100%; aspect-ratio: auto; }
@media (max-width: 600px) {
  /* one across on a phone, so spans would only make some pieces enormous */
  .tile--wide, .tile--tall { grid-column: auto; grid-row: auto; }
  .tile--wide .media, .tile--tall .media { height: auto; aspect-ratio: 16 / 9; }
}
@media (max-width: 760px) {
  .grid { grid-template-columns: 1fr; grid-auto-rows: auto; }
  .tile--wide, .tile--tall { grid-column: auto; grid-row: auto; }
  .tile--wide .media, .tile--tall .media { height: auto; aspect-ratio: 16 / 9; }
}

.tile { display: block; }
.tile:hover { color: var(--ink); }

.media { position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: var(--ink); }
.media img, .media video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  /* No opacity transition. Fading the film up over the still blended the two
     into a ghost of the opening frame. The swap is a straight cut. */
  transition: transform .6s cubic-bezier(.2,.7,.2,1), filter .45s ease;
}
.media video { opacity: 0; }
.media.is-playing video { opacity: 1; }
/* once the film is running, drop the still underneath it — otherwise it shows
   through as a ghost frame whenever the video fades */
.media.is-playing img { opacity: 0; }
/* Phones: keep the tile at the pictures' own shape. Forcing 4/3 here cropped
   the sides off every 16/9 still, which is the one thing a folio must not do. */
@media (max-width: 600px) { .media { aspect-ratio: 16 / 9; } }

/* brand reveal: the film/still disperses to the name on grey (desktop hover) */
.reveal {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; text-align: center; padding: 16px;
  background: var(--paper); color: var(--ink);
  opacity: 0;
  transition: opacity .16s ease;
  pointer-events: none;
}
/* the panel covers first, then the type arrives — no ghost of the frame behind it */
.reveal b, .reveal span {
  opacity: 0; transform: translateY(10px);
  transition: opacity .3s ease, transform .44s cubic-bezier(.2,.7,.2,1);
}
.reveal b { font-weight: 500; font-size: clamp(36px, 4.2vw, 64px); line-height: 1; letter-spacing: -0.02em; }
.reveal span { font-size: 16px; line-height: 20px; letter-spacing: 0.04em; color: var(--grey); }

/* caption under each tile (touch screens) */
.caption {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 16px;
  padding: 14px var(--m) 30px;
}
.caption b { display: block; font-weight: 500; font-size: 20px; line-height: 26px; letter-spacing: -0.01em; }
.caption span { display: block; font-size: 15px; line-height: 20px; color: var(--grey); }

@media (hover: hover) and (pointer: fine) {
  .tile .caption { display: none; }
  .tile:not(.veil):hover .media img, .tile:not(.veil):hover .media video,
  .tile:not(.veil):focus-visible .media img, .tile:not(.veil):focus-visible .media video {
    /* The blur mixes the picture's own edge with what is behind it, and what
       is behind it is black, so at scale(1.05) a dark fringe showed along the
       top of the tile on rollover. Dan, 11 Nov 2026. A bigger overscale puts
       the fringe outside the frame; the panel is fading to nothing anyway, so
       it looks the same. */
    opacity: 0; transform: scale(1.14); filter: blur(5px);
    transition: opacity .16s ease, transform .55s cubic-bezier(.2,.7,.2,1), filter .4s ease;
  }
  .tile:hover .reveal, .tile:focus-visible .reveal { opacity: 1; }
  .tile:hover .reveal b, .tile:focus-visible .reveal b {
    opacity: 1; transform: none; transition-delay: .1s;
  }
  .tile:hover .reveal span, .tile:focus-visible .reveal span {
    opacity: 1; transform: none; transition-delay: .16s;
  }
  /* VEIL TEST: film keeps running, a translucent panel lets the type read.
     Roll off and it returns to full colour. */
  .tile.veil .reveal {
    background: rgba(243, 244, 246, .88);
    transition: opacity .22s ease;
  }
  .tile.veil:hover .media img, .tile.veil:focus-visible .media img,
  .tile.veil:hover .media video, .tile.veil:focus-visible .media video {
    transform: scale(1.02);
    transition: transform .6s cubic-bezier(.2,.7,.2,1);
  }
}
@media (hover: none), (pointer: coarse) { .reveal { display: none; } }

.ph {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--grey); font-size: 14px; letter-spacing: .08em; text-transform: uppercase; font-weight: 500;
}

/* ---------- Project page ---------- */

.top { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--g); padding-top: 28px; }
/* Dan, 12 Nov 2026: it felt small and floaty against everything else. It is
   the masthead on 45 pages, so it is allowed to hold the corner. */
.mini { font-size: 24px; line-height: 30px; font-weight: 500; letter-spacing: -0.01em; }
.mini span { display: block; font-weight: 400; color: var(--grey); }
.top nav { display: flex; gap: 32px; padding-top: 9px; }
.top nav .label { font-size: 15px; letter-spacing: 0.1em; }
.top nav a:hover { color: var(--ink); }
/* A phone is 353px of usable width, and the masthead now shares it with three
   nav items. Dan, 12 Nov 2026: at laptop sizes the name wrapped and the nav
   ran into it. Everything comes down a notch so the whole header sits on one
   line with the name on one line under it. */
@media (max-width: 600px) {
  .top { padding-top: 22px; align-items: center; }
  .mini { font-size: 17px; line-height: 22px; }
  .top nav { gap: 14px; padding-top: 0; }
  .top nav .label { font-size: 11px; letter-spacing: 0.07em; }
}

/* Title and brand on one line, the brand in grey, a full stop after each.
   Dan, 12 Nov 2026. The longest pair is Potential unleashed. Royal Edinburgh
   Military Tattoo., which is within a couple of characters of the measure, so
   it wraps on a small laptop. That is fine; it is the only one that does. */
.title {
  margin: 0 0 28px;
  font-size: 44px; line-height: 50px; font-weight: 500; letter-spacing: -0.025em;
  text-wrap: balance;
}
.title span { color: var(--grey); font-weight: 400; margin-left: 0.35em; }

/* The write-up and the credits now sit at the foot of the page, under the
   work rather than above it. Look first, read second. */
.intro {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--g);
  row-gap: 24px;
  margin: 72px 0 0;
  padding-top: 36px;
  border-top: 1px solid var(--rule);
}
@media (max-width: 760px) { .intro { margin-top: 48px; } }
.intro-text { grid-column: 1 / span 7; }
/* Even the lines rather than leaving a stub on the last one. Dan, 12 Nov
   2026: the write-ups were ending on two or three words. The browser works
   out the breaks, so it holds whatever the copy is and at any width. */
.about { margin: 0; font-size: 20px; line-height: 28px; text-wrap: balance; }
/* Condensed, 12 Nov 2026. At the foot of the page the credits are reference,
   so they are set tight and small: a short label column, rows that sit close,
   and the pair reading as one line rather than two columns drifting apart. */
.credits { grid-column: 9 / span 4; margin: 0; display: flex; flex-direction: column; gap: 2px; }
/* Dan, 12 Nov 2026: "creds look a bit floaty, should they not sit condensed
   under the descriptor." On a left-aligned page they do: the write-up and the
   credits share one narrow column at the foot, the credits tucked under the
   copy rather than drifting off at column nine. */
@media (min-width: 901px) {
  .page--left .intro { display: block; }
  .page--left .intro-text { max-width: 34em; }
  .page--left .credits { max-width: 34em; margin-top: 22px; }
  .page--left .credits div { grid-template-columns: 5.2em 1fr; gap: 8px; }
  .page--left .credits dt { font-size: 10px; line-height: 17px; }
  .page--left .credits dd { font-size: 14px; line-height: 17px; }
}
.credits div { display: grid; grid-template-columns: 5.6em 1fr; gap: 10px; align-items: baseline; }
.credits dt { font-size: 11px; line-height: 19px; font-weight: 500; letter-spacing: 0.09em; text-transform: uppercase; color: var(--grey); }
.credits dd { margin: 0; font-size: 15px; line-height: 19px; }

@media (max-width: 760px) {
  .title { font-size: 34px; line-height: 38px; margin-bottom: 20px; }
  /* On a phone the pair will not sit on one line, and half-wrapping strands
     the first word of the brand next to the title. Dan, 12 Nov 2026: give the
     brand its own line instead. */
  .title span { display: block; margin-left: 0; }
  .intro-text, .credits { grid-column: 1 / -1; }
  .about { font-size: 19px; line-height: 27px; }
  .credits { border-top: 1px solid var(--rule); padding-top: 20px; }
  .credits div { grid-template-columns: 9em 1fr; }
  .credits dt { font-size: 12px; }
  .credits dd { font-size: 16px; }
}

.film {
  position: relative;
  /* the hold frame's own shape, 16:9 unless the build says otherwise: a
     square social film letterboxed into 16:9 reads as the wrong crop */
  aspect-ratio: var(--film-ar, 16 / 9);
  overflow: hidden;
  background: var(--ink);
  margin-bottom: var(--g);
}
.film img, .film video { width: 100%; height: 100%; object-fit: cover; }
.film iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.film button {
  position: absolute; inset: 0; width: 100%; height: 100%;
  border: 0; padding: 0; background: transparent; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.film button i {
  width: 92px; height: 92px; border-radius: 50%;
  background: rgba(243,244,246,.92);
  box-shadow: 0 2px 24px rgba(16,18,22,.28);
  display: flex; align-items: center; justify-content: center;
  transition: transform .28s cubic-bezier(.2,.7,.2,1), background .28s ease;
}
.film button i::before {
  content: ""; margin-left: 7px;
  border-left: 23px solid var(--ink); border-top: 14px solid transparent; border-bottom: 14px solid transparent;
  transition: border-left-color .28s ease;
}
.film button:hover i, .film button:focus-visible i {
  transform: scale(1.07); background: var(--paper);
}
.film button:focus-visible { outline: 2px solid var(--paper); outline-offset: -6px; }

/* Still frame sits back a touch so the button reads first */
.film--cta img { transition: transform .5s cubic-bezier(.2,.7,.2,1), filter .4s ease; }
.film--cta:hover img { transform: scale(1.012); filter: brightness(.94); }
@media (prefers-reduced-motion: reduce) {
  .film button i, .film button:hover i, .film--cta img, .film--cta:hover img {
    transition: none; transform: none;
  }
}

.stills { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--g); }
.stills figure { margin: 0; grid-column: 1 / -1; }
.stills figure.portrait { grid-column: auto; }
.stills img { width: 100%; height: auto; }

/* phones: pictures run edge to edge */
@media (max-width: 600px) {
  /* Not .film--panel: that one already sits inside .shots, which has gone
     edge to edge itself. A second negative margin on top of it pushed the
     panel 40px wider than the screen and put a sideways scroll on the page. */
  .film:not(.film--panel), .stills { margin-left: calc(-1 * var(--m)); margin-right: calc(-1 * var(--m)); }
  .film { margin-bottom: 8px; }
  .film button i { width: 64px; height: 64px; }
  .stills { grid-template-columns: 1fr; gap: 8px; }
  .stills figure.portrait { grid-column: 1 / -1; }
}

/* Other work: rule + a punchy heading separates it from the campaign above */
/* Every campaign finishes on the same gap, so the pages end alike.
   No heading and no rule over it. The two pieces nearest this campaign come
   first, then the rest, in one grid. The grid starts where the rule used to
   sit: a full-bleed band of pictures after a column of them is its own
   division, and a line across it was saying the same thing twice. */
/* The column ends and the index begins. Dan, 12 Nov 2026: the page used to
   just run out into white before the grid arrived. A rule closes the piece, a
   label says what follows, and the gap is half what it was so the grid turns
   up while you are still looking. */
.more { margin-top: 72px; }
.more .rule { margin: 0 0 18px; }
.wrap--frame > .rule { margin: 22px 0 34px; }
.more-tag { display: block; margin-bottom: 26px; color: var(--grey); }
@media (max-width: 600px) { .more { margin-top: 48px; } .more-tag { margin-bottom: 18px; } }

/* No motion: swap straight over, no crossfade, no ghosting */
@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal b, .reveal span,
  .media img, .media video { transition: none !important; transform: none !important; }
}

/* ---------- The campaign, under the film ----------
   Justified rows: everything in a row shares a height and the widths come from
   the pictures' own proportions, so a square sits beside a landscape with
   neither cropped. Same measure as the film, so every edge lines up. */

/* Panel rhythm. Dan builds campaign layouts 1600 wide with a 134px gap
   between panels; a percentage of the column keeps that proportion, and because it is a
   percentage it holds the proportion at every screen width. */
/* The film gets more air beneath it than the panels get between them, so the
   page reads in three steps: the idea, the work, then the next section. */
/* No top margin of its own. The film carries the gap under it, and on a page
   whose hero is a still the title's own margin does the same job, so a still
   page and a film page now open at exactly the same height. Dan, 12 Nov 2026
   spotted the difference by eye: it was 32px. */
.shots { margin-top: 0; }
/* One gap, the same between panels side by side and between the rows. Dan,
   11 Nov 2026: find a common spacing and apply it to all. The big breaks are
   kept for the things that are actually a break: the film to the work, and
   the work to the other campaigns. */
.shots .row {
  display: flex;
  gap: var(--g);
  align-items: flex-start;
  margin-bottom: var(--g);
}
.shots .row:last-child { margin-bottom: 0; }
/* A picture on its own that isn't wide would be absurd blown up to the full
   measure, so it stops at seven columns. The left edge still lines up. */
.shots .row--lone {
  max-width: calc((100% - 11 * var(--g)) / 12 * 7 + 6 * var(--g));
}
/* A standing poster or vertical film: seven columns. At the full measure a 9:16
   panel would stand 2844px tall, three screens of scrolling for one poster.
   Seven columns is 910 wide and 1618 tall, which has presence without taking
   over. Left edge still on the line. */
.shots .row--tall {
  max-width: calc((100% - 11 * var(--g)) / 12 * 7 + 6 * var(--g));
}
/* Triumph's house layout: a column of riding shots stacked beside a standing
   press ad. The two columns share the gutter and finish level, which build.py
   solves for, so the block reads as one object. Everything inside a column is
   a gutter apart, not a row apart: a row's 6% break would pull the stack
   taller than the ad beside it. */
/* One gap for the whole of a Triumph page's work: between the columns,
   between the panels stacked in them, and between the rows underneath. The
   number comes from the block and is set on .shots as --bg, a percentage of
   the measure so it holds at any width. */
.shots--block .row { gap: var(--bg); margin-bottom: var(--bg); }
.shots--block .row:last-child { margin-bottom: 0; }

/* Each column is a box of a height build.py works out, with its panels pushed
   to the top and bottom edges. No gap is set here: the gaps are whatever is
   left over inside the box, which is how they come out the same on both sides
   and the same as the gutter between the columns. The box scales with the
   measure, so they stay that way at every width. */
.shots .row--cols { align-items: flex-start; }
.shots .col {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 0;
  min-width: 0;
}
.shots .col figure { flex: 0 0 auto; }

/* A second campaign sharing the page. Same furniture as the intro at the top,
   so it reads as another piece of work rather than a sub-heading. */
.shots-head { margin-bottom: 40px; }
.shots .row + .shots-head, .shots-head:not(:first-child) { margin-top: 9%; }
.shots-title {
  margin: 10px 0 0;
  font-size: 40px; line-height: 48px; font-weight: 500; letter-spacing: -0.02em;
}
.shots-head .about { margin-top: 14px; max-width: 34em; }
@media (max-width: 760px) {
  .shots-title { font-size: 28px; line-height: 34px; }
  .shots-head { margin-bottom: 28px; }
}
@media (max-width: 600px) {
  .shots-head { margin-left: var(--m); margin-right: var(--m); }
}
.shots figure { margin: 0; min-width: 0; }
/* The shape is declared on the element in build.py, so the space is held from
   the first paint and nothing jumps when a file lands. No colour behind it:
   Dan, 11 Nov 2026, the campaign colour flashing up under every panel read as
   try-hard. It waits on paper. */
.shots figure img { background: none; }
.shots figure img,
.shots figure video { width: 100%; height: auto; display: block; }
img { -webkit-user-drag: none; user-select: none; }
/* A panel film sits on the ink while it loads, so there is no white flash
   in the layout before the first frame arrives. */
.shots figure video { background: var(--ink); }
/* A film in the layout that waits to be pressed. Same furniture as the one
   at the top of the page, but its shape comes from the film, not from 16/9. */
.film--panel { aspect-ratio: auto; margin-bottom: 0; }
.film--panel img { width: 100%; height: 100%; object-fit: cover; }
.film--panel button i { width: 68px; height: 68px; }
.film--panel button i::before { border-left-width: 17px; border-top-width: 10px; border-bottom-width: 10px; }
.shots figcaption {
  /* Sentence case. Under a composed campaign panel a shouting label fights
     the work; it should name the piece and get out of the way. */
  margin-top: 10px;
  font-size: 18px; line-height: 24px; font-weight: 500;
  letter-spacing: 0;
  color: var(--grey);
}

@media (max-width: 900px) {
  .shots .row--lone, .shots .row--tall { max-width: none; }
}
@media (max-width: 600px) {
  /* edge to edge, like the film above, so nothing is cropped and both line up */
  .shots {
    margin-top: 40px;
    margin-left: calc(-1 * var(--m));
    margin-right: calc(-1 * var(--m));
  }
  .shots .row { display: block; margin-bottom: 0; }
  .shots .col, .shots .col > .stack { display: block; aspect-ratio: auto !important; }
  .shots figure { margin-bottom: 40px; }
  .shots .row:last-child figure:last-child { margin-bottom: 0; }
  /* the pictures run to the edge, the captions stay on the text margin */
  .shots figcaption { margin-left: var(--m); margin-right: var(--m); }
}

/* ---------------------------------------------------------------------------
   THE LEFT-ALIGNED CAMPAIGN PAGE. Dan, 12 Nov 2026: "move the title text and
   start of the image sequence to the left in line with the end of the rule,
   and align descriptor and creds to the left." So the page hangs off the
   frame's left edge, under the left end of the rule, instead of floating in a
   centred column. The title, the film and the write-up keep the reading
   measure, because a 16:9 film any wider stops landing whole on the screen
   and a line of copy any wider stops being readable. The work itself has no
   such limit, so a strip of posters runs the full frame.
--------------------------------------------------------------------------- */
@media (min-width: 901px) {
  /* The page hangs off the frame's left edge, under the left end of the rule.
     The title, the film and the write-up keep the reading measure, because a
     16:9 film any wider stops landing whole on the screen and a line of copy
     any wider stops being readable. Below 901px the page is one column wide
     anyway and these rules would fight the edge-to-edge bleed, so they stop. */
  .page--left > main > .title-row,
  .page--left > main > .film,
  .page--left > main > .shots,
  .page--left > main > .intro {
    margin-left: 0;
    margin-right: auto;
  }
  /* Dan, 12 Nov 2026: the film runs the width of the rule like the poster
     strips, "as long as the video lands in the first part of the campaign
     frame fully without crop". 223px is the measured height of everything
     above it (name, nav, rule, title); 24px is a breath under it. So the film
     is whichever is smaller: the rule's width, or the width at which a 16:9
     film still ends above the fold. On a short window it backs off by itself
     and never crops. The 900px floor stops it collapsing on a tall window. */
  .page--left > main > .film {
    /* No floor. A floor is the one thing that can push the film past the
       fold, and Dan wants the whole film every time: "id love to be able to
       see it all without any loss on bottom." 223px is the measured height of
       everything above it (name, nav, rule, title) and 40px is real air
       underneath, so the film is whichever is smaller, the rule's width or
       the width at which a 16:9 film still ends above the fold. svh, not vh,
       because on a phone or tablet vh is the tall viewport and would crop. */
    max-width: min(calc(var(--frame) - 2 * var(--m)),
                   calc((100vh - 263px) * 16 / 9));
    max-width: min(calc(var(--frame) - 2 * var(--m)),
                   calc((100svh - 263px) * 16 / 9));
  }
  /* A campaign that is a strip of posters lets the work run the full frame.
     max-width only, never a width: a fixed width would fight the bleed. */
  /* The line above the write-up spans whatever the work above it spans, so on
     a wide strip it runs to the posters' right edge rather than stopping
     short. The copy and the credits stay on their narrow measure. */
}

/* ---------------------------------------------------------------------------
   THE SINGLE-PIECE PAGE. Dan, 12 Nov 2026: the write-up beside the work
   "looks shody" - it sits under the work here exactly as it does on
   Barnardo's. The only thing this page type does is cap the piece's HEIGHT,
   because one tall poster run to the rule's width would be twice the height
   of the screen. "you know i will alaways want these images to land without
   any crop off bottom": the piece is never taller than the screen less the
   furniture above it and a breath under, so the work always lands whole. The
   words sit under it, where words go.
--------------------------------------------------------------------------- */
@media (min-width: 901px) {
  /* The block is exactly as wide as the picture will be, and it is centred.
     Everything in it stays left-aligned to that same edge, so the title, the
     work and the words line up and the page has no empty side. --piece is the
     picture's shape, set by the build. */
  /* The block: as wide as its lead piece can be and still land whole, and
     centred. Everything inside shares its two edges. A page with no --piece
     has no lead to measure, so the fallback 999 leaves it at 100%: the full
     width of the rule, exactly as before. 100%, not the frame's own figure,
     because the frame is 2400 at most but the window is usually narrower. */
  .page--left > main {
    width: min(100%, calc((100vh - 263px) * var(--piece, 999)));
    width: min(100%, calc((100svh - 263px) * var(--piece, 999)));
    margin-inline: auto;
  }
  .page--left > main > .title-row,
  .page--left > main > .film,
  .page--left > main > .shots,
  .page--left > main > .intro { max-width: none; margin-left: 0; margin-right: 0; }
  .page--single .shots .row { max-width: none; justify-content: flex-start; }
  .page--single .shots figure img,
  .page--single .shots figure video {
    max-height: calc(100vh - 263px);
    max-height: calc(100svh - 263px);
    width: auto;
    max-width: 100%;
  }
}

/* A "-fit" piece takes its row to itself but never outgrows the screen. The
   row centres it, so a piece narrower than the column reads as placed rather
   than as a short row. Dan, 12 Nov 2026. */
@media (min-width: 901px) {
  /* Twice the site's gap, which is what the two six-sheets had between them
     in Dan's own export before they were cut apart. Dan, 12 Nov 2026. */
  .shots .row--fit { justify-content: center; align-items: flex-start; gap: calc(var(--g) * 2); }
  .shots .row--fit figure { flex: 0 0 auto !important; max-width: 100%; }
  .shots .row--fit figure > img,
  .shots .row--fit figure > video {
    max-height: calc(100vh - 263px);
    max-height: calc(100svh - 263px);
    width: auto;
    max-width: 100%;
  }
}

/* THE LEAD. Dan, 13 Nov 2026: "treat the first image now as the hero arive on
   it clean beautiful un cropped and space around it the others can be nicely
   stacked below it." The lead row holds the whole fold on its own. The work is
   centred in it and capped to it, so it always lands whole, it always has air
   round it, and whatever follows starts below the fold instead of showing a
   sliver of itself on arrival. */
@media (min-width: 901px) {
  .shots .row--lead {
    min-height: calc(100vh - 263px);
    min-height: calc(100svh - 263px);
    align-items: center;
    justify-content: center;
    margin-bottom: 7vh;
  }
  /* The figure is sized by its picture, so it has to be told not to outgrow
     the row: without this the picture renders at its own pixel width and
     hangs over both margins, and the work under it no longer lines up. */
  /* One picture in the lead is sized by itself and centred. Several share the
     row as usual, so a trio of posters still lines up with the rule. */
  .shots .row--lead figure:only-child { flex: 0 0 auto !important; max-width: 100%; }
  .shots .row--lead figure > img,
  .shots .row--lead figure > video {
    max-height: calc(100vh - 263px);
    max-height: calc(100svh - 263px);
    width: auto;
    max-width: 100%;
  }
  /* Dan, 13 Nov 2026, on the stadium banner: "image as wide as rule and
     centred on page, no more crop or zoom needed, just size up." That was
     the rule's full width, and it overran the fold: Dan, 13 Nov 2026, "the
     football banner country roads is too big." It had been taking the full
     width AND ignoring the height cap, so it filled the screen edge to edge
     and was still cut off at the bottom. Now it is held to 85 per cent of
     the rule and capped to the fold, whichever bites first, so the whole
     piece lands with air above and below it and the stadium still reads big.
     The 85 is a judgement, not a constant: change the one number. */
  .page--single .shots .row--lead figure { max-width: 85%; }
  /* A single piece page left-aligns its rows, and so does the lead. It was
     centred while it ran the rule's full width, where centred and left were
     the same thing. Held to 85 per cent it drifted off the margin, and Dan,
     13 Nov 2026: "the name and brand need to be aligned properly." The left
     edge of the work now sits on the same line as Dan Scott and the campaign
     title, which is the line the eye reads down. */
  .page--single .shots .row--lead { justify-content: flex-start; }
}
