/* =============================================================================
   DAVID ROBINSON DESIGN — style.css
   Modelled on blond.cc/spaces: white ground, one grotesk (Akkurat) at one
   weight, uppercase meta, a 16px gutter grid that runs edge to edge, a
   column-masonry of 3:2 and 4:5 images, no rules, no pills, no colour.
   ============================================================================= */

@font-face {
  font-family: 'Akkurat';
  src: url('fonts/akkurat-light.woff2') format('woff2'), url('fonts/akkurat-light.otf') format('opentype');
  font-weight: 300; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Akkurat';
  src: url('fonts/akkurat-regular.woff2') format('woff2'), url('fonts/akkurat-regular.otf') format('opentype');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Akkurat';
  src: url('fonts/akkurat-bold.woff2') format('woff2'), url('fonts/akkurat-bold.otf') format('opentype');
  font-weight: 700; font-style: normal; font-display: swap;
}

/* ── Tokens — the blond.cc scale: head/body 24 → 20 → 18, lead 40 → 32 → 28,
      title 100 → 80 → 44; gutter 16 → 12 → 8; space 48 → 36 → 32 ─────────── */
:root {
  --bg: #ffffff;
  --fg: #000000;
  --fg-dim: rgba(0, 0, 0, 0.55);        /* blond uses 37.5%; 55% keeps ≥4.5:1 on white */
  --fg-line: rgba(0, 0, 0, 0.12);

  --font: 'Akkurat', 'Helvetica Neue', Helvetica, Arial, sans-serif;

  --gutter: 16px;
  --margin: 16px;
  --space: 48px;
  --header-h: max(var(--space), 48px);   /* never shorter than a 44px hit target */
  --logo-h: 90px;
  --header-real: calc(var(--logo-h) + var(--gutter) * 4);  /* mark + doubled padding */                        /* mark height — the header box matches it */
  --rule-w: 6px;                          /* fallback where round() is unsupported */
  --rule-w: round(calc(var(--logo-h) * 0.0685), 1px); /* 38/555 — the underscore in the mark */
  --mark-inset: calc(var(--logo-h) * 0.34144); /* dead space beside the glyph in its square frame: (1 - 176/555) / 2 */

  --fs-head: 24px;
  --fs-body: 24px;
  --fs-lead: 40px;
  --fs-title: 100px;
  --fs-small: 16px;

  /* highlight reveal — the pause before the first word lights, then the gap
     from one word to the next. Both are here so the pace is tuned in one place. */
  --hl-delay: 500ms;
  --hl-step: 170ms;

  --ls-head: -0.01em;
  --ls-body: -0.025em;
}
@media (max-width: 1440px) { :root { --fs-head: 20px; --fs-body: 20px; --fs-lead: 32px; --fs-title: 80px; } }
@media (max-width: 1080px) { :root { --gutter: 12px; --margin: 12px; --space: 36px; --fs-head: 18px; --fs-body: 18px; --fs-lead: 28px; --fs-title: 44px; } }
@media (max-width: 768px)  { :root { --gutter: 8px; --margin: 8px; --space: 32px; --fs-small: 15px; } }

/* ── Base ────────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { background: var(--bg); height: 100%; -webkit-text-size-adjust: 100%; }
body {
  margin: 0; min-height: 100%;
  font-family: var(--font); font-weight: 400;
  font-size: var(--fs-body); line-height: 1.2; letter-spacing: var(--ls-body);
  color: var(--fg); background: var(--bg);
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}
img, video { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
p { margin: 0; }
p + p { margin-top: 1em; }
ul { margin: 0; padding: 0; list-style: none; }
h1, h2, h3, h4 { margin: 0; font-weight: 400; line-height: 1.2; font-size: inherit; }
strong, b { font-weight: 400; }
::selection { background: var(--fg); color: var(--bg); }
:focus-visible { outline: 1px solid var(--fg); outline-offset: 3px; }

.site { position: relative; display: flex; flex-direction: column; min-height: 100vh; }
main { flex: 1 0 auto; position: relative; z-index: 1; background: var(--bg); padding-bottom: calc(var(--space) * 2); }

/* uppercase meta — nav, subjects, captions, titles */
.meta { font-size: var(--fs-head); letter-spacing: var(--ls-head); line-height: 1.2; text-transform: uppercase; }
.small { font-size: var(--fs-small); letter-spacing: -0.01em; }
.dim { color: var(--fg-dim); }
.dot { margin: 0 0.08em; }
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ── Header — logo · (subject) · exit + burger. The menu is a panel inside the
      sticky header: opening it grows the header, so the whole page shifts down ── */
.site-header {
  position: sticky; top: 0; z-index: 30;
  background: var(--bg);
  transition: transform 0.42s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: transform;
  font-size: var(--fs-head); letter-spacing: var(--ls-head); line-height: 1.2; text-transform: uppercase;
}
.header-bar {
  min-height: var(--header-h); padding: calc(var(--gutter) * 2) var(--margin);
  display: flex; align-items: center; justify-content: space-between; gap: var(--gutter);
}
/* scrolled down: the bar slides out of the way; scrolling up brings it back */
html.header-hidden .site-header { transform: translateY(-100%); }
/* On the work grid the bar sits in flow directly above the first row of
   images: below the fold on arrival, it rides up with the grid as the user
   scrolls, then pins when it reaches the top of the screen. */
.arrival ~ .site-header { position: sticky; top: 0; }
@media (prefers-reduced-motion: reduce) { .site-header { transition: none; } }
.site-header a { white-space: nowrap; }
.logo { flex: none; display: block; }
/* square frame — the stacked mark sits centred in a 1:1 box at half the old height */
.logo .mark { display: block; height: var(--logo-h); width: var(--logo-h); object-fit: contain; object-position: center; }
@media (max-width: 768px) { :root { --logo-h: 60px; } }
.logo:hover, .header-right a:hover { color: var(--fg-dim); }
.subject-line { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; flex: 1 1 auto; }
.header-right { flex: none; display: flex; align-items: center; gap: var(--gutter); margin-right: calc(var(--mark-inset) - 8px); min-height: 44px; }
.subject-line { line-height: 44px; }

/* burger → cross */
.menu-toggle {
  width: 44px; height: 44px; padding: 0; border: 0; background: none; cursor: pointer; color: inherit;
  position: relative; display: block;
}
.menu-toggle span {
  position: absolute; left: 8px; right: 8px; top: 50%;
  height: var(--rule-w); margin-top: calc(var(--rule-w) / -2); background: currentColor;
  transition: transform 0.35s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.2s;
}
.menu-toggle span:nth-child(1) { transform: translateY(calc(var(--rule-w) * -2)); }
.menu-toggle span:nth-child(3) { transform: translateY(calc(var(--rule-w) * 2)); }
html.menu-open .menu-toggle span:nth-child(1) { transform: rotate(45deg); }
html.menu-open .menu-toggle span:nth-child(2) { opacity: 0; transform: scaleX(0); }
html.menu-open .menu-toggle span:nth-child(3) { transform: rotate(-45deg); }

/* the panel: collapsed to 0 rows, opened to its natural height */
.menu { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.45s cubic-bezier(0.22, 0.61, 0.36, 1); }
.menu-inner { min-height: 0; overflow: hidden; }
.menu-list { padding: var(--gutter) var(--margin) calc(var(--space) * 1.25); display: flex; flex-direction: column; align-items: flex-end; text-align: right; }
.menu-list a { display: block; font-size: var(--fs-title); line-height: 1; letter-spacing: var(--ls-head); min-height: 44px; }
.menu-list a:hover, .menu-list a.is-active { color: var(--fg-dim); }
html.menu-open .menu { grid-template-rows: 1fr; }
/* without JS the panel cannot be opened, so it stays open */
html:not(.js) .menu { grid-template-rows: 1fr; }
html:not(.js) .menu-toggle { display: none; }
.menu-inner { visibility: hidden; transition: visibility 0s 0.45s; }
html.menu-open .menu-inner, html:not(.js) .menu-inner { visibility: visible; transition-delay: 0s; }

@media (max-width: 1080px) {
  .site-header .subject-line { display: none; }
}

/* ── Work grid — columns of stacked items (JS distributes; CSS grid without JS) ── */
/* no top padding — the header already supplies a gutter below the mark, so the
   space above and below the logo reads equal */
.work { padding: 0 var(--margin) 0; }
.work .column { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 var(--gutter); align-items: start; }
@media (min-width: 1441px) { .work .column { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 768px) { .work .column { grid-template-columns: 1fr; } }
.work .group { display: flex; flex-direction: column; min-width: 0; }

.item { position: relative; min-width: 0; }
.item > a { display: block; }
.item .media { position: relative; overflow: hidden; background: var(--bg); }
.item .media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: var(--crop, 50% 50%); transition: opacity 0.25s; }
.item .media img.hover { opacity: 0; z-index: 2; }
.media--landscape { aspect-ratio: 3 / 2; }
.media--portrait { aspect-ratio: 4 / 5; }
/* the meta block is a fixed 2 × space tall — that is the vertical rhythm of the grid */
.item .content { height: calc(var(--space) * 2); padding: var(--gutter) 0; display: grid; }
.item .subject, .item .caption { grid-area: 1 / 1; font-size: var(--fs-head); letter-spacing: var(--ls-head); line-height: 1.2; text-transform: uppercase; }
.item .caption { opacity: 0; }
.item .subject .dot, .subject-line .dot { margin: 0 0.22em; }
/* ── Hover: the label lights word by word in the project accent ──────────────
      Each word reveals its accent-coloured duplicate in sequence, the same
      device as the opening statement run fast. Insets follow the Akkurat cap
      metrics (line box 1.2em, caps 0.229em..0.971em) with 0.08em of air. */
/* ═══════════════════════════════════════════════════════════════════════════
   HIGHLIGHT — one component behind every highlighted word on the site: the
   opening statement, the page titles, the section headings, the closing
   statement and the grid's hover labels. Each word carries a reversed copy of
   itself in a filled box; revealing the copy lights the word. Contexts differ
   only in colour and vertical metrics, set through --hl-bg / --hl-ink and
   --hl-t / --hl-b, so the treatment reads the same at every size.
   ═══════════════════════════════════════════════════════════════════════════ */
.hl .w, .item .subject .hw { position: relative; display: inline-block; }
.hl .w .over, .item .subject .hw .hov {
  /* equal air on all four sides: the caps sit clear vertically, so the block
     also extends past the word left and right, the padding keeping the
     duplicate text aligned with the base */
  --hl-t: 0.073em; --hl-b: 0.073em; --hl-x: 0.08em;
  position: absolute;
  left: calc(var(--hl-x) * -1); right: calc(var(--hl-x) * -1);
  top: var(--hl-t); bottom: var(--hl-b);
  padding: 0 var(--hl-x); box-sizing: border-box;
  overflow: hidden;
  background: var(--hl-bg, var(--fg)); color: var(--hl-ink, var(--bg));
  pointer-events: none;
  visibility: hidden;
  transition: visibility 0s linear;
}
.hl .w .over > span, .item .subject .hw .hov > span {
  display: block; white-space: pre; margin-top: calc(var(--hl-t) * -1);
}
/* script.js adds .is-lit once the block is in view; the words then light half a
   second later, one after another. A block already on screen at load lights on
   the same half-second, which is what makes a page announce itself without a
   scroll. Nothing animates without JS, so there every highlight is already lit. */
.hl.is-lit .w .over {
  visibility: visible;
  transition-delay: calc(var(--hl-delay, 500ms) + var(--i, 0) * var(--hl-step, 170ms));
}
html:not(.js) .hl .w .over { visibility: visible; }
/* the boxes overhang each word by --hl-x, so a heading whose every word is lit
   needs a little more air between them or the fields close up on each other.
   The arrival statement sets its own, wider, 0.22em. */
.page-title h1.hl, .intro h1.hl, .c-section .text h2.hl, .content .title.hl { word-spacing: 0.18em; }

/* ── Equal padding on every highlight ─────────────────────────────────────
   The box is inset from the word's line box, but the glyphs do not sit in the
   middle of a line box: uppercase has no descender ink, so an equal inset
   leaves roughly three times more space below the caps than above, and mixed
   case pushes descenders straight out through the bottom edge. Each context
   has its own line-height and case, so each needs its own pair. These values
   were measured against the painted glyph extents (canvas actualBoundingBox
   against the baseline), tuned until the ink sits 0.08em from all four edges —
   the same 0.08em used left and right. The box geometry is CSS-driven, so every
   word in a heading still gets an identical box whatever letters it contains. */
.hl.arrival-line .w .over        { --hl-t: 0.056em; --hl-b: 0.096em; }
.page-title h1.hl .w .over       { --hl-t: 0.020em; --hl-b: 0.033em; }
.intro h1.hl .w .over            { --hl-t: 0.014em; --hl-b: 0.083em; }
.content .title.hl .w .over      { --hl-t: 0.070em; --hl-b: 0.220em; }
.c-section .text h2.hl .w .over  { --hl-t: 0.045em; --hl-b: -0.092em; }
/* same size and line-height as the section headings, so the same pair: the box
   spans the font's full ascender-to-descender, not one sample word's */
.c-statement p.hl .w .over       { --hl-t: 0.045em; --hl-b: -0.092em; }

/* the grid label keeps the project's accent; its metrics match the section
   headings, being the same size and case */
.item .subject .hw .hov { --hl-t: 0.071em; --hl-b: 0.220em; --hl-bg: var(--accent); --hl-ink: var(--ink, #000); }
@media (hover: hover) {
  .item:hover .subject .hw .hov { visibility: visible; transition-delay: calc(var(--i) * 70ms); }
}
.item:focus-within .subject .hw .hov { visibility: visible; transition-delay: calc(var(--i) * 70ms); }
@media (prefers-reduced-motion: reduce) {
  .hl .w .over, .item .subject .hw .hov { transition: none; }
  .hl.is-lit .w .over { transition-delay: 0s; }
}

.item .subject .client, .item .subject .name { white-space: nowrap; }
@media (hover: hover) {
  .item:hover .media img.hover { opacity: 1; }
}
/* keyboard users get the same swap */
.item:focus-within .media img.hover { opacity: 1; }
@media (max-width: 768px) {
  .item .content { height: auto; min-height: calc(var(--space) * 2); }
  .item .caption { display: none; }
}

/* ── Page title (case studies) ───────────────────────────────────────────── */
.page-title { padding: var(--gutter) var(--margin) var(--space); text-align: center; }
.page-title h1 { font-size: var(--fs-title); line-height: 1; letter-spacing: var(--ls-head); text-transform: uppercase; text-wrap: balance; }

/* ── Page opener (Expertise / Process / About / Contact) ─────────────────── */
.intro { padding: var(--gutter) var(--margin) var(--space); }
.intro h1 { font-size: var(--fs-title); line-height: 1; letter-spacing: var(--ls-head); text-transform: uppercase; }
.intro .lede { margin-top: var(--space); font-size: var(--fs-lead); line-height: 1.1; letter-spacing: var(--ls-body); max-width: 30ch; }

/* ── Content blocks — the blond.cc two-column media system ───────────────── */
.content { padding: 0 var(--margin); display: flex; flex-direction: column; gap: var(--gutter); }
.content > * { min-width: 0; }

.frame { position: relative; overflow: hidden; background: var(--bg); }
.frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.frame.contain { background: var(--bg); }
.frame.contain img { object-fit: contain; }
.frame.auto { aspect-ratio: auto; }
.frame.auto img { height: auto; }

.c-banner .frame { aspect-ratio: 16 / 9; }

.c-text { padding: var(--space) 0 0; }
/* One body size across the site: the opening paragraph of a case study used to
   be set at lead size and full width, which read as a different kind of text
   from the copy below it. It now takes the same size and the same measure, so
   every block of body copy on a page matches. */
.c-text.size-large .text,
.c-text.size-small .text { font-size: var(--fs-body); line-height: 1.2; letter-spacing: var(--ls-body); }
.c-text.size-large p + p,
.c-text.size-small p + p { margin-top: 1em; }
.c-text.size-large,
.c-text.size-small { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gutter); }
.c-text.size-large .text,
.c-text.size-small .text { grid-column: 1; }
.c-text.size-large.pos-right .text,
.c-text.size-small.pos-right .text { grid-column: 2; }
.c-text .title, .c-row .text .title { display: block; margin-bottom: 0.6em; color: var(--fg-dim); font-size: var(--fs-head); letter-spacing: var(--ls-head); line-height: 1.2; }
.c-text .text a { border-bottom: 1px solid var(--fg-line); }
.c-text .text a:hover { border-color: var(--fg); }

.c-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gutter); padding: var(--space) 0 0; }
.c-list .list { grid-column: 1; }
.c-list .title { display: block; }
.c-list .title::after { content: ":"; }

.c-gallery { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 var(--gutter); align-items: start; padding-top: var(--space); }
/* three across, for rows of sketches or development renders */
.c-gallery.cols-3 { grid-template-columns: repeat(3, 1fr); }
.c-gallery figure { margin: 0; min-width: 0; }
.c-image { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 var(--gutter); }
.c-image figure { margin: 0; min-width: 0; }
.c-image.pos-span figure { grid-column: 1 / -1; }
.c-image.pos-left figure { grid-column: 1; }
.c-image.pos-right figure { grid-column: 2; }
figcaption, .figcap { padding: var(--gutter) 0 0; font-size: var(--fs-small); letter-spacing: -0.01em; line-height: 1.3; color: var(--fg-dim); }
.figcap .meta { display: block; font-size: var(--fs-small); text-transform: none; color: var(--fg); }
.caption-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gutter); }

.c-row { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gutter); align-items: start; }
.c-row .frame { grid-row: 1; }
.c-row.side-left .frame { grid-column: 1; }
.c-row.side-left .text { grid-column: 2; }
.c-row.side-right .frame { grid-column: 2; }
.c-row.side-right .text { grid-column: 1; grid-row: 1; }
.c-row .text {
  padding-top: 0;
  position: sticky;
  top: calc(var(--header-real) + var(--gutter));
  align-self: start;
}
@media (max-width: 768px) { .c-row .text { position: static; } }

.c-quote { padding: var(--space) 0 0; }
.c-quote blockquote { margin: 0; max-width: 40ch; font-size: var(--fs-lead); line-height: 1.05; letter-spacing: var(--ls-body); }
.c-quote blockquote p::before { content: "\201C"; }
.c-quote blockquote p::after { content: "\201D"; }
.c-quote cite { display: block; margin-top: var(--gutter); font-style: normal; font-size: var(--fs-body); }

.c-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: var(--gutter); padding: var(--space) 0 0; justify-items: center; }
.stat { text-align: left; }
.stat .value { display: block; font-size: var(--fs-title); line-height: 1; letter-spacing: var(--ls-head); }
.stat .value small { font-size: 0.4em; letter-spacing: 0; }
.stat .label { display: block; margin: var(--gutter) 0 0; max-width: 28ch; }

.c-note { padding: var(--space) 0 0; }
.c-note p { color: var(--fg-dim); }

/* section: lead text + card deck (Expertise / Process / About) */
.c-section {
  display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--gutter);
  padding: var(--space) 0; align-items: start; scroll-margin-top: var(--header-h);
}
.c-section .text { grid-column: 1 / span 5; }
.c-section .text {
  position: sticky;
  top: calc(var(--header-real) + var(--gutter));
  align-self: start;
}
@media (max-width: 768px) { .c-section .text { position: static; } }
/* The section number used to sit in a filled black box. Set plain, it reads as a
   label on its own -- `.meta` already supplies the uppercase, the size and the
   tracking. The old asymmetric padding (0.5em top / 0.3em bottom) went with the
   box: uppercase carries no descender ink, so symmetric padding sat the caps
   high inside it. With no box to sit in, the padding goes too, which also lets
   the number align flush with the heading beneath it. */
.c-section .text .kicker {
  display: inline-block;
  margin-bottom: var(--gutter);
}
.c-section .text h2 { font-size: var(--fs-lead); line-height: 1.05; letter-spacing: var(--ls-body); margin-bottom: var(--gutter); }
.c-section .text p { max-width: 36ch; }
.c-section .text .tags { margin-top: var(--gutter); color: var(--fg-dim); }
.c-section .deck-wrap { grid-column: 7 / span 6; }
.c-section.flip .text { grid-column: 7 / span 6; }
.c-section.flip .deck-wrap { grid-column: 1 / span 6; grid-row: 1; }

.c-deck { padding: var(--space) 0 0; }
.c-deck .deck { aspect-ratio: 3 / 2; }
/* Half-width carousel: one column of the same two-column grid the row and image
   blocks use, so it lines up with everything else on the page. With title/html
   the second column holds the copy; without, the carousel simply occupies the
   left half. */
.c-deck.size-half {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: var(--gutter); align-items: start;
}
.c-deck.size-half .deck { aspect-ratio: 4 / 3; }
.c-deck.size-half .text > *:first-child { margin-top: 0; }
/* pad: true insets the slides on the sides and bottom but not the top, so the
   image still starts level with the copy beside it while getting some room
   against the frame. The card is absolutely positioned with inset: 0, so
   border-box keeps the padding inside that box rather than growing it. */
.c-deck.is-padded .deck .card {
  padding: 0 calc(var(--gutter) * 2) calc(var(--gutter) * 2);
  box-sizing: border-box;
}
/* Padding alone achieved nothing visible here. These renders sit on white, so
   white padding against them reads as no padding at all, and `cover` went on
   filling the inset box by cropping - the case was still cut off at the top and
   zoomed, with no room around the subject. `contain` fits the whole render
   inside the padded box, which is what the padding was for. The three sources
   are 1.33-1.46 against a 4/3 frame, so letterboxing is negligible. */
.c-deck.is-padded .deck .card img { object-fit: contain; object-position: top center; }
.deck { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: var(--bg); cursor: pointer; -webkit-user-select: none; user-select: none; touch-action: pan-y; }
.deck .card { position: absolute; inset: 0; opacity: 0; transition: opacity 0.35s; }
.deck .card.is-active { opacity: 1; z-index: 1; }
.deck .card img { width: 100%; height: 100%; object-fit: cover; }
.deck-ui { display: flex; align-items: baseline; justify-content: space-between; gap: var(--gutter); padding: var(--gutter) 0 0; }
.deck-caption { text-transform: uppercase; font-size: var(--fs-head); letter-spacing: var(--ls-head); min-height: 1.2em; }
.deck-controls { display: flex; align-items: baseline; gap: var(--gutter); flex: none; text-transform: uppercase; }
.deck-controls .count { font-variant-numeric: tabular-nums; color: var(--fg-dim); }
.deck-btn { font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; min-height: 44px; }
.deck-btn:hover { color: var(--fg-dim); }
.deck-btn:disabled { color: var(--fg-dim); cursor: default; }
.deck-btn svg { display: none; }

/* big uppercase list (clients) */
.c-biglist { padding: var(--space) 0 0; }
.c-biglist .title { display: block; margin-bottom: var(--gutter); color: var(--fg-dim); }
.c-biglist li { font-size: var(--fs-lead); line-height: 1.05; letter-spacing: var(--ls-head); text-transform: uppercase; }

/* key / value list (awards, contact) */
.c-kv { padding: var(--space) 0 0; }
.c-kv .title { display: block; margin-bottom: var(--gutter); color: var(--fg-dim); }
.c-kv .row { display: grid; grid-template-columns: 6em 1fr; gap: var(--gutter); padding: 0.35em 0; }
.c-kv .key { color: var(--fg-dim); font-variant-numeric: tabular-nums; }
.c-kv .val a { border-bottom: 1px solid var(--fg-line); }
.c-kv .val a:hover { border-color: var(--fg); }
.c-kv .val .sub { display: block; color: var(--fg-dim); }
.c-kv.narrow { max-width: 40ch; }

/* FAQ */
.c-faq { padding: var(--space) 0 0; display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--gutter); }
.c-faq .title { grid-column: 1 / span 4; color: var(--fg-dim); }
.c-faq .group { grid-column: 5 / span 8; }
.c-faq .group-title { display: block; margin: var(--space) 0 var(--gutter); color: var(--fg-dim); }
.c-faq .group-title:first-child { margin-top: 0; }
.c-faq details { border-top: 1px solid var(--fg-line); }
.c-faq details:last-child { border-bottom: 1px solid var(--fg-line); }
.c-faq summary { list-style: none; cursor: pointer; display: flex; justify-content: space-between; gap: var(--gutter); padding: 0.6em 0; min-height: 44px; align-items: center; position: relative; }
.c-faq summary::-webkit-details-marker { display: none; }
/* the marker is two bars, not a glyph — the upright rotates onto the crossbar,
   turning + into − and back */
.c-faq summary { --mark-size: 15px; --mark-w: 2px; }
.c-faq summary::after,
.c-faq summary::before { content: ""; flex: none; background: currentColor; }
.c-faq summary::after { width: var(--mark-size); height: var(--mark-w); }
.c-faq summary::before {
  position: absolute; right: calc((var(--mark-size) - var(--mark-w)) / 2); top: 50%;
  width: var(--mark-w); height: var(--mark-size); margin-top: calc(var(--mark-size) / -2);
  transform: rotate(0deg);
  transition: transform 0.35s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.c-faq details[open] summary::before { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .c-faq summary::before { transition: none; } }
.c-faq .answer { padding: 0 0 1em; max-width: 44ch; color: var(--fg-dim); }
.c-faq .answer ul { list-style: disc; padding-left: 1.2em; margin: 0.4em 0 0.8em; }

/* three plain text columns (why / how / who, focus) */
/* Why / How / Who — the three columns sit as a group in the middle of the page
   rather than spreading to the full width, while the copy inside each stays
   left aligned and ragged right. */
.c-cols {
  display: grid; grid-template-columns: repeat(3, minmax(0, 30ch));
  /* --space rather than --gutter: at a 16px gutter the three columns of running
     text read as one block, because the gap between columns was no wider than
     the word spacing inside them. It scales down with the token on smaller
     screens, where the columns stack anyway. */
  justify-content: center; gap: var(--space); padding: var(--space) 0 0;
}
.c-cols .col .meta { display: block; margin-bottom: var(--gutter); font-weight: 700; }
.c-cols .col p { max-width: 30ch; }

.c-statement { padding: calc(var(--space) * 2) 0 0; }
.c-statement p { font-size: var(--fs-lead); line-height: 1.05; letter-spacing: var(--ls-body); max-width: 30ch; }
/* the marked phrase is built as a highlight, so it needs no colour of its own */

.c-embed { padding: var(--space) 0 0; }
.c-embed .title { display: block; margin-bottom: var(--gutter); }
.c-embed .embed { background: var(--bg); min-height: 700px; }

@media (max-width: 1080px) {
  .c-section .text { grid-column: 1 / span 6; }
  .c-section .deck-wrap { grid-column: 7 / span 6; }
  .c-section.flip .text { grid-column: 7 / span 6; }
  .c-section.flip .deck-wrap { grid-column: 1 / span 6; }
  .c-faq .title { grid-column: 1 / -1; }
  .c-faq .group { grid-column: 1 / -1; }
}
@media (max-width: 768px) {
  /* .c-gallery.cols-3 is listed explicitly: it is a two-class selector, so the
     bare .c-gallery below would not outrank it and the row would stay three
     across on a phone. */
  .c-text.size-small, .c-text.size-large, .c-list, .c-row, .c-image, .c-gallery, .c-gallery.cols-3, .c-deck.size-half, .c-cols { grid-template-columns: 1fr; }
  .c-text.size-small .text, .c-text.size-small.pos-right .text,
  .c-text.size-large .text, .c-text.size-large.pos-right .text, .c-list .list { grid-column: 1; }
  .c-image.pos-left figure, .c-image.pos-right figure { grid-column: 1; }
  .c-row.side-left .frame, .c-row.side-right .frame,
  .c-row.side-left .text, .c-row.side-right .text { grid-column: 1; grid-row: auto; }
  .c-row .text { padding: var(--gutter) 0 var(--space); }
  .c-gallery figure + figure { margin-top: var(--gutter); }
  .c-section { grid-template-columns: 1fr; }
  .c-section .text, .c-section.flip .text { grid-column: 1; }
  .c-section .deck-wrap, .c-section.flip .deck-wrap { grid-column: 1; grid-row: auto; margin-top: var(--gutter); }
  .caption-grid { grid-template-columns: 1fr; }
  .c-kv .row { grid-template-columns: 1fr; gap: 0; }
}

/* ── Pagination (next / previous project) ───────────────────────────────── */
.pagination { padding: calc(var(--space) * 2) var(--margin) 0; }
.pagination .title { display: block; margin-bottom: var(--gutter); color: var(--fg-dim); }
.pagination .column { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 var(--gutter); align-items: start; }
.pagination .item .media { aspect-ratio: 3 / 2; }
.pagination .item .content { display: block; height: auto; }
.pagination .item .content .label { display: block; color: var(--fg-dim); }
.pagination .item .caption { display: none; }
.pagination .item:hover .subject { opacity: 1; }
@media (max-width: 768px) { .pagination .column { grid-template-columns: 1fr; } }

/* ── Footer — sits beneath the page; content scrolls up to reveal it ───────── */
.site-footer {
  min-height: 100vh; min-height: 100svh;
  padding: var(--space) var(--margin) calc(var(--gutter) + env(safe-area-inset-bottom, 0px));
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--space);
  background: var(--bg);
}
/* the reveal is switched on by script.js only after it has measured the footer
   and confirmed it fits the viewport; otherwise the footer stays in flow */
html.footer-ready .site-footer { position: fixed; left: 0; bottom: 0; width: 100%; z-index: 0; }
html.footer-ready body { padding-bottom: var(--footer-h, 0px); }
/* The fixed footer is viewport-tall, so the slogan at its top sits directly
   behind the header band. `main` is what hides it, but on every page except the
   home page main starts *below* the header, leaving that strip with nothing
   opaque behind it — so the slogan showed through each time the header slid
   away on scroll. This band backs the strip. It is absolute, not fixed, so it
   scrolls off with the document and the reveal at the foot of the page is
   untouched; main paints over it everywhere else. */
html.footer-ready .site::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0;
  height: var(--header-real); background: var(--bg); z-index: 1; pointer-events: none;
}
.footer-about { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 var(--gutter); align-content: start; }
.footer-slogan { grid-column: 1 / -1; font-size: var(--fs-title); line-height: 1; letter-spacing: var(--ls-head); text-transform: uppercase; text-wrap: balance; }
.footer-about .text { margin-top: calc(var(--space) * 2); max-width: 44ch; }
.footer-about .text p + p { margin-top: 1em; }
.footer-info { display: grid; grid-template-columns: repeat(8, 1fr); gap: 0 var(--gutter); align-items: end; }
.footer-info .address { grid-column: 1 / span 2; font-style: normal; }
.footer-info .address span { display: block; }
.footer-info .contact { grid-column: 3 / span 3; }
.footer-info .contact .row { display: flex; gap: 0.3em; }
.footer-info .contact .key::after { content: ":"; }
.footer-info .contact a:hover, .footer-info .footer-menu a:hover { color: var(--fg-dim); }
.footer-info .footer-menu { grid-column: 6 / span 2; display: flex; flex-direction: column; }
.footer-info .legal { grid-column: 8; justify-self: end; text-transform: uppercase; white-space: nowrap; }
@media (max-width: 1080px) {
  .footer-about { grid-template-columns: repeat(2, 1fr); }
  .footer-info { grid-template-columns: repeat(2, 1fr); row-gap: var(--space); }
  .footer-info .address { grid-column: 1; }
  .footer-info .contact { grid-column: 2; }
  .footer-info .footer-menu { grid-column: 1; }
  .footer-info .legal { grid-column: 2; justify-self: end; }
}
@media (max-width: 768px) {
  .footer-about { grid-template-columns: 1fr; }
  .footer-info { grid-template-columns: 1fr; }
  .footer-info .address, .footer-info .contact, .footer-info .footer-menu, .footer-info .legal { grid-column: 1; justify-self: start; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PROJECT ACCENTS — one swatch per project, set as --accent on the element.
   Palette: red · red-deep · green · orange · yellow · purple · pink · sky
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --c-red: #E5342A; --c-red-deep: #B0231A; --c-green: #0FA958; --c-orange: #F04E23;
  --c-yellow: #D9F227; --c-purple: #8B45C6; --c-pink: #F03B9B; --c-sky: #9FC1E0;
  --accent: var(--c-red);
}

/* ── Home grid — the label strip fills with the project accent on hover ───────
      The box bleeds half a gutter either side so the text itself does not move. */
.item .content {
  margin: 0;
  padding: var(--gutter) 0;
  align-items: center;
}
/* breathing room between the box and the next project in the column */
.item { margin-bottom: var(--gutter); }

/* ═══════════════════════════════════════════════════════════════════════════
   PACKBOX — the project summary, square, to the right of the title.
   Pharmaceutical-pack idiom in Akkurat. The design rests on contrast, not
   ornament: one item set very large and bold against everything else small,
   light and wide-tracked, with a single hairline dividing the two zones.
   Uses the 300 weight, which the site ships but had never called on.
   ═══════════════════════════════════════════════════════════════════════════ */
.page-title--project {
  display: flex; align-items: center; gap: var(--gutter);
  /* gap below matches the grid gutter, so the box sits on the images the same
     way the grid tiles sit on each other */
  padding-bottom: var(--gutter);
}
.page-title--project h1 { flex: 1 1 auto; min-width: 0; text-align: center; text-wrap: balance; }
/* the title lights in the project's own colour, matching the summary box beside
   it and the section headings below — the accent comes off the section */
.page-title--project { --hl-bg: var(--accent); --hl-ink: var(--ink, #000); }
/* bottom-aligned so the box always sits one gutter above the banner, whatever
   height the title runs to */
.page-title--project .packbox { flex: none; align-self: flex-end; }

.packbox {
  container-type: inline-size;
  width: clamp(240px, 25vw, 330px); aspect-ratio: 1 / 1;
  background: var(--accent, transparent); color: var(--ink, #000);
  padding: clamp(18px, 1.7vw, 26px);
  display: flex; flex-direction: column; justify-content: space-between;
  text-align: left;
}
.packbox .pb-l, .packbox .pb-r { display: flex; flex-direction: column; min-width: 0; }

/* zone 1 — the client, then the product name at full volume */
.packbox .pb-client { display: flex; flex-direction: column; gap: 0.35em; }
/* capitalised label style: the field name and the category */
.packbox .pb-lab,
.packbox .pb-cat {
  font-size: calc(var(--fs-small) * 0.8); font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; line-height: 1.2;
}
.packbox .pb-name {
  flex: 1 1 auto;
  display: grid; place-items: center start;
  text-align: left;
  font-size: min(clamp(30px, 3.4vw, 50px), var(--pb-fit, 50px)); font-weight: 700;
  letter-spacing: -0.03em; line-height: 0.9;
  text-transform: uppercase;
  white-space: nowrap; overflow-wrap: normal;
}

/* zone 2 — hairline, the descriptor, then the summary in the light weight */
.packbox .pb-r { padding-top: 0.9em; border-top: 1px solid currentColor; gap: 0.6em; }
/* body text: the client name and the summary read the same */
.packbox .pb-val,
.packbox .pb-sum {
  font-size: var(--fs-small); font-weight: 400;
  letter-spacing: var(--ls-body); line-height: 1.35;
  text-transform: none;
  overflow-wrap: anywhere;
}
.packbox .pb-sum { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }

@media (max-width: 768px) {
  .page-title--project { flex-direction: column; }
  .page-title--project .packbox { width: 100%; max-width: 330px; aspect-ratio: auto; min-height: 240px; }
}

/* ── Section headings — every one is a highlight, and they all share one size
      and style so the treatment reads the same across the site. The filled box
      is black by default; inside a case study it takes the project's accent,
      the same colour field as the summary box beside the title. The selectors
      are spelled out to outrank the per-block rules further up. ──────────── */
.content .title,
.content .c-text .title,
.content .c-row .text .title,
.content .c-list .title,
.content .c-biglist .title,
.content .c-kv .title,
.content .c-faq .title,
.content .c-embed .title {
  display: block;
  margin-bottom: 0.8em;
  font-size: var(--fs-head);
  line-height: 1.2;
  letter-spacing: var(--ls-head);
  text-transform: uppercase;
  color: var(--fg);
}
.content.is-project { --hl-bg: var(--accent); --hl-ink: var(--ink, #000); }
/* the Services heading's trailing colon reads as a typo inside a filled box */
.c-list .title::after { content: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   ARRIVAL — the statement set edge to edge on white. Scrolling sweeps a black
   highlight across it word by word, the type reversing to white as it passes.
   Once the line is fully read the statement lifts away and the work grid
   rises from the foot of the screen.

   The section is three screens tall; its inner stage is pinned, so all of
   that height is scroll budget for the sequence rather than empty page.
   ═══════════════════════════════════════════════════════════════════════════ */
.arrival { position: relative; height: 165svh; z-index: 0; }
/* already seen this session: the page opens straight on the grid, no flash */
html.arrival-seen .arrival { display: none; }
.arrival-stage {
  position: sticky; top: 0;
  height: 100svh;
  container-type: inline-size;
  display: grid; align-content: center;
  padding: 0 var(--margin);
  overflow: hidden;
}
.work { position: relative; z-index: 1; background: var(--bg); }

.arrival-inner { }

/* ── the statement ──────────────────────────────────────────────────────── */
.arrival-line { margin: 0; font-weight: 700; text-transform: uppercase; letter-spacing: -0.04em; word-spacing: 0.22em; }
.arrival-line .row {
  display: block;
  /* one --fit for the whole sentence, set on the h1 at build time */
  font-size: calc(var(--fit) * 1cqw);
  line-height: 1.05;
  white-space: nowrap;
}

/* each word carries a reversed copy of itself, revealed left to right — the
   shared highlight component, driven here by scroll rather than by .is-lit */

/* ── a quiet cue that there is more below ───────────────────────────────── */
.arrival-cue {
  position: absolute; left: var(--margin); bottom: var(--space);
  font-size: var(--fs-small); letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--fg-dim);
}

@media (prefers-reduced-motion: reduce) {
  .arrival { height: 100svh; }
  .arrival-inner { transform: none; opacity: 1; }
  .arrival-line .w .over { visibility: visible !important; }
}
