/* Clay Campbell portfolio — homepage revision pass.
   Visual system unchanged: warm paper, deep ink, restrained blue, oversized
   typography, real work doing the talking. What changes is the rhythm — every
   project is composed around its own strongest artifact instead of one shared
   small-label / large-headline / large-rectangle template.

   Everything shown is supplied evidence. Crops, staging, overlap, scroll-snap
   sequences and offsets below are CSS; no artifact is redrawn or reconstructed.

   Deliberate departure carried over from the previous pass: no backdrop-filter
   blur (workspace standard: no glassmorphism). */

:root {
  --paper: #f5f4f0;
  --surface: #e6e5e1;      /* the surface documents are staged on */
  --white: #fff;
  --ink: #0a121b;
  --muted: #a5a7a8;
  --muted-ink: #6d7073;    /* 4.54:1 on --paper */
  --copy: #4c5257;         /* 7.0:1 on --paper: secondary sentences */
  --blue: #1487d4;
  --line: rgba(10, 18, 27, 0.15);
  --max: 1360px;
  --gutter: 24px;
  --radius-media: clamp(14px, 1.8vw, 24px);  /* the page's large-media radius */
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 17px;
  line-height: 1.45;
}
body.info-open { overflow: hidden; }
a { color: inherit; }
img, video { display: block; max-width: 100%; }
button { font: inherit; }
.skip-link { position: fixed; left: 1rem; top: -5rem; z-index: 100; padding: 0.7rem 1rem; background: var(--ink); color: white; }
.skip-link:focus { top: 1rem; }
:focus-visible { outline: 3px solid var(--blue); outline-offset: 4px; }

/* Shared shell. Only these blocks are constrained; project media can run the
   full width of the page when the artifact calls for it. */
.site-header,
.hero,
.project-head,
.packet-layout,
.media-layout,
.media-support,
.connections-layout,
.lifecycle,
.shred-spread,
.trust-film,
.more-work {
  width: min(calc(100% - (var(--gutter) * 2)), var(--max));
  margin-inline: auto;
}

/* Documentary captions: project names, outlets, dates — not interface taxonomy. */
.tiny,
.section-label,
.hero-label,
.project-number,
.case-meta {
  margin: 0;
  color: var(--muted-ink);
  font-size: 0.72rem;
  line-height: 1.35;
  font-weight: 760;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}
.project-context {
  max-width: 68ch;
  margin: 0 0 0.8rem;
  color: var(--muted-ink);
  font-size: clamp(0.74rem, 0.8vw, 0.84rem);
  line-height: 1.5;
  font-weight: 700;
  letter-spacing: 0.055em;
  text-transform: uppercase;
}
.site-header {
  position: relative;
  z-index: 10;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 2rem;
  min-height: 92px;
}
.identity { display: inline-flex; align-items: center; gap: 0.75rem; text-decoration: none; font-weight: 720; }
.identity-mark {
  display: grid;
  place-items: center;
  width: 42px;
  aspect-ratio: 1;
  border-radius: 13px;
  background: var(--ink);
  color: white;
  font-size: 0.68rem;
  letter-spacing: -0.03em;
}
.site-nav { display: flex; align-items: center; gap: clamp(1rem, 3vw, 2.5rem); }
.site-nav a,
.site-nav button {
  border: 0;
  padding: 0;
  background: transparent;
  text-decoration: none;
  color: var(--muted-ink);
  font-weight: 650;
  cursor: pointer;
}
.site-nav a:hover,
.site-nav button:hover,
.site-nav a:focus-visible,
.site-nav button:focus-visible { color: var(--ink); }

/* ---------- Hero: an introduction that gets out of the way ---------- */

.hero { padding: clamp(2.25rem, 5vh, 4rem) 0 clamp(2.5rem, 5vh, 4rem); }
.hero-label { color: var(--muted-ink); }
.hero h1 {
  max-width: 24ch;
  overflow-wrap: break-word;
  margin: clamp(1rem, 2.2vw, 1.8rem) 0 0;
  font-size: clamp(2.4rem, 5.2vw, 5.2rem);
  line-height: 1.0;
  letter-spacing: -0.05em;
  font-weight: 720;
}
.hero-sub {
  max-width: 46ch;
  margin: clamp(1.1rem, 2.2vw, 1.7rem) 0 0;
  color: var(--copy);
  font-size: clamp(1.02rem, 1.25vw, 1.22rem);
  line-height: 1.45;
}
.hero-link {
  display: inline-block;
  margin-top: clamp(1.4rem, 3vw, 2.4rem);
  color: var(--ink);
  font-size: 0.92rem;
  font-weight: 700;
  text-decoration: none;
  border-bottom: 2px solid var(--line);
  padding-bottom: 0.15rem;
}
.hero-link:hover,
.hero-link:focus-visible { border-bottom-color: var(--ink); }
.hero-link span { display: inline-block; transition: transform 180ms ease; }
.hero-link:hover span { transform: translateY(2px); }

/* ---------- Work: shared bones, per-project composition ---------- */

.work { width: 100%; }
.project { margin: 0 0 clamp(5rem, 11vw, 11rem); }
.project-head { display: block; }
/* Uneven pauses between projects: the amount of air is part of the rhythm, so
   the sections do not march down the page at one interval. */
.project-trust { margin-bottom: clamp(6rem, 12vw, 12rem); }
.project-lifecycle { margin-bottom: clamp(5rem, 10vw, 10rem); }
.project-packets { margin-bottom: clamp(4rem, 7.5vw, 7.5rem); }
.project-media { margin-bottom: clamp(3.5rem, 6vw, 6rem); }
.project-connections { margin-bottom: clamp(5rem, 9vw, 9rem); }
.project-shred { margin-bottom: clamp(5.5rem, 10vw, 10rem); }
.project h2,
.more-work h2 {
  overflow-wrap: break-word;
  text-wrap: balance;
  margin: clamp(0.6rem, 1.4vw, 1rem) 0 0;
  font-size: clamp(1.9rem, 3.2vw, 3.4rem);
  line-height: 1.03;
  letter-spacing: -0.045em;
  font-weight: 720;
}
.project-line {
  margin: clamp(0.7rem, 1.6vw, 1.1rem) 0 0;
  max-width: 48ch;
  color: var(--copy);
}
.bleed { width: 100%; }
figure { margin: 0; }
figcaption { margin-top: 0.65rem; }

/* Shred Day: copy at upper left, human image elevated at upper right,
   turnout image lower left and tucked underneath the human image. */

.project-shred .project-head {
  grid-column: 1 / span 5;
  grid-row: 1;
  align-self: start;
  padding: 0;
  position: relative;
  z-index: 4;
}

.project-shred .project-head h2 {
  max-width: 20ch;
}

.project-shred .project-context {
  max-width: 48ch;
}

.shred-spread {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: clamp(1rem, 1.8vw, 1.6rem);
  align-items: start;
}

/* Human image: elevated on the right and visually in front */
.shred-human {
  grid-column: 6 / span 7;
  grid-row: 1;
  position: relative;
  z-index: 3;
  margin-top: 2rem;
}

.shred-human figcaption {
  max-width: 30ch;
}

.shred-human img {
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--radius-media);
}

/* Turnout image: lower left and underneath the human image */
.shred-scale {
  grid-column: 1 / span 8;
  grid-row: 1;
  position: relative;
  z-index: 1;
  margin-top: clamp(17rem, 22vw, 21rem);
}

.shred-scale img {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: center 58%;
  border-radius: var(--radius-media);
}

.shred-note {
  grid-column: 1 / span 4;
  grid-row: 2;
  margin: clamp(1.2rem, 2.4vw, 2rem) 0 0;
  max-width: 30ch;
  color: var(--copy);
  font-size: 0.95rem;
}
/* 02 — Advertising + sponsorship: documents, staged on a surface and browsed.
   Base state (no scripting, and every phone) is a scroll-snap rail of the same
   eight page elements; the fan is added on wide screens by app.js. */
.project-packets { padding-top: clamp(1rem, 3vw, 3rem); }
.packet-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.34fr) minmax(0, 0.66fr);
  grid-template-rows: auto auto;
  gap: clamp(1.2rem, 2.6vw, 2.2rem) clamp(1.5rem, 4vw, 4rem);
  align-items: start;
}
.packet-copy { grid-column: 1; grid-row: 1; }
.packet-copy h2 { max-width: 24ch; }
.packet-stage { grid-column: 2; grid-row: 1 / span 2; }
.packet-tools { grid-column: 1; grid-row: 2; }

.packet-stage {
  display: flex;
  gap: 14px;
  padding: 14px;
  background: var(--surface);
  border-radius: clamp(16px, 2vw, 26px);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.packet-stage::-webkit-scrollbar { display: none; }
.packet-page {
  flex: 0 0 80%;
  margin: 0;
  background: var(--white);
  box-shadow: 0 14px 34px -14px rgba(10, 18, 27, 0.3);
  scroll-snap-align: start;
  transform-origin: 50% 50%;
  transition: transform 420ms cubic-bezier(.2,.75,.2,1), box-shadow 320ms ease, opacity 260ms ease;
}
.packet-open { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: zoom-in; }
.packet-page img { display: block; width: 100%; height: auto; }

/* Page turning is set as quiet type, not as a control panel. */
.packet-controls { display: flex; align-items: baseline; gap: clamp(0.7rem, 1.4vw, 1.1rem); margin-top: clamp(1.1rem, 2vw, 1.8rem); }
.packet-status { margin: 0; color: var(--muted-ink); font-size: 0.72rem; font-weight: 760; letter-spacing: 0.13em; }
.packet-step,
.packet-rail button {
  border: 0;
  padding: 0;
  background: none;
  color: var(--muted-ink);
  font-size: 0.8rem;
  font-weight: 700;
  cursor: pointer;
}
.packet-step { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.3em; }
.packet-rail { display: flex; flex-wrap: wrap; gap: clamp(0.5rem, 1vw, 0.9rem); list-style: none; margin: 0.9rem 0 0; padding: 0; }
.packet-rail button { font-size: 0.72rem; font-weight: 760; letter-spacing: 0.08em; }
.packet-step:hover:not(:disabled),
.packet-rail button:hover { color: var(--ink); }
.packet-step:disabled { opacity: 0.35; cursor: default; }
.packet-rail button[aria-current="true"] { color: var(--ink); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.32em; }

/* 03 — Consumer guidance + media: the interview leads, the stills support it at
   different sizes and offsets rather than in a row of equal tiles. */
.media-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.36fr) minmax(0, 0.64fr);
  gap: clamp(1.5rem, 4vw, 4rem);
  align-items: start;
}
.media-copy h2 { max-width: 22ch; }
.media-primary { position: relative; }
.media-primary .media-video,
.trust-film .trust-video { width: 100%; height: 100%; object-fit: cover; }
.media-primary .media-video {
  aspect-ratio: 16 / 9;
  border-radius: clamp(14px, 1.8vw, 24px);
  background: #111;
}
.media-cap { margin-top: 0.7rem; }

.media-support {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(1rem, 1.8vw, 1.8rem);
  align-items: start;
  margin-top: clamp(2rem, 3vw, 3rem);
}
.media-support img { width: 100%; height: auto; border-radius: clamp(12px, 1.4vw, 18px); }
/* Two supporting frames: the news still on the top left, the street interview
   smaller and dropped well below it on the right. */
.frame-wide {
  grid-column: 1 / span 6;
  grid-row: 1;
  width: 80%;
  margin-top: -8rem;
  margin-left: -0.75rem;
  position: relative;
  z-index: 2;
}
.frame-left { grid-column: 9 / span 4; grid-row: 1; margin-top: -2rem; position: relative;
  z-index: 1; }
  
.frame-left .project-context {
  width: 100%;
  text-align: right;
}
  
.frame-third {
  grid-column: 7 / span 4;
  grid-row: 1;
  margin-top: 0rem;
  position: relative;
  left: -10rem;
  z-index: 3;
}
.motion-toggle {
  position: absolute;
  right: 14px;
  top: 14px;
  min-height: 40px;
  border: 1px solid rgba(255, 255, 255, 0.7);
  border-radius: 999px;
  padding: 0.5rem 0.85rem;
  background: rgba(10, 18, 27, 0.86);
  color: white;
  font-size: 0.76rem;
  font-weight: 700;
  cursor: pointer;
}
.motion-toggle:hover { background: rgba(10, 18, 27, 0.96); }
/* The sound control sits directly under the motion control, in the same chip.
   Desktop (14px + 40px + 8px) and phone (10px + 44px + 8px) both land here, so
   the existing homepage control does not move. */
.motion-toggle + .motion-toggle { top: 62px; }

/* Trust, Built Locally: the film is the section's visual, held inside the page's
   own measure rather than running the width of the browser. The copy follows it
   and stops there; campaign context belongs on a case page. */
.project-trust .trust-film { position: relative; }
.trust-film .trust-video {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-media);
  object-position: center 52%;
  background: #10161c;
}
.trust-head {
  padding-top: clamp(1.2rem, 2.6vw, 2.2rem);
}

.trust-head .project-context {
  max-width: 100ch;
}

.trust-head h2 {
  max-width: 30ch;
}

/* 05 — Contractor Connections: one event photograph, tall and quiet, with the
   copy beside it. No second image, no decoration. */
.connections-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.66fr) minmax(0, 0.34fr);
  gap: clamp(1.5rem, 4vw, 4.5rem);
  align-items: center;
}
.connections-photo img { width: 100%; height: auto; border-radius: var(--radius-media); }
.connections-copy h2 { max-width: 20ch; }
.case-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: clamp(1.2rem, 2.4vw, 2rem);
  font-weight: 720;
  text-decoration: none;
  border-bottom: 2px solid var(--line);
  padding-bottom: 0.15rem;
}
.case-link:hover,
.case-link:focus-visible { border-bottom-color: var(--ink); }
.case-link span { display: inline-block; transition: transform 180ms ease; }
.case-link:hover span { transform: translate(2px, -2px); }

/* Lifecycle: the customer relationship as a six-moment motion sequence. One
   touchpoint holds the stage at a time and the rail underneath is the only
   persistent device, so the section reads as one continuous relationship rather
   than a row of six artifacts. The welcome email is a supplied artifact; the
   mailer, the check-in call and the invitation are simplified representational
   graphics drawn in the page's own system. With scripting off — and with
   reduced motion — the same six moments are a readable stack of states, in
   order, and the rail steps between them by hand. */
.project-lifecycle .project-head { padding-bottom: clamp(1.5rem, 3vw, 2.5rem); }
.project-lifecycle h2 { max-width: 30ch; }

.lifecycle-stage {
  position: relative;
  margin-top: clamp(1.2rem, 2.6vw, 2rem);
  padding: clamp(0.9rem, 2vw, 1.6rem);
  background: var(--surface);
  border-radius: var(--radius-media);
}
.lifecycle-stage.is-staged { padding: 0; aspect-ratio: 16 / 9; overflow: hidden; }

.lifecycle-scenes {
  display: grid;
  gap: clamp(0.9rem, 2vw, 1.6rem);
  margin: 0;
  padding: 0;
  list-style: none;
}
.lifecycle-scenes .scene {
  position: relative;
  display: grid;
  place-items: center;
  min-height: clamp(220px, 30vw, 340px);
  padding: clamp(1rem, 2.4vw, 2.4rem);
  background: var(--white);
  border-radius: clamp(10px, 1.2vw, 18px);
}

/* With script: the stage becomes a frame and the six moments replace one
   another, each rising into place as the last one leaves. */
.lifecycle-stage.is-staged .lifecycle-scenes { display: block; height: 100%; }
.lifecycle-stage.is-staged .scene {
  position: absolute;
  inset: 0;
  min-height: 0;
  padding: clamp(1.4rem, 3.4vw, 3.2rem);
  background: transparent;
  border-radius: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(22px);
  transition: opacity 620ms ease, transform 860ms cubic-bezier(.2,.75,.2,1), visibility 0s linear 620ms;
}
.lifecycle-stage.is-staged .scene.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 820ms ease, transform 1000ms cubic-bezier(.2,.75,.2,1), visibility 0s;
}
/* The hand-back from renewal to acquisition is deliberately slower and softer
   than a step change, so the loop reads as the relationship continuing. */
.lifecycle-stage.is-looping .scene.is-active { transition: opacity 1000ms ease, transform 1240ms cubic-bezier(.2,.75,.2,1), visibility 0s; }
.lifecycle-stage.is-staged .scene.is-past {
  transform: translateY(-20px);
  transition: opacity 540ms ease, transform 700ms cubic-bezier(.2,.75,.2,1), visibility 0s linear 540ms;
}

/* 01 Acquisition — the first moment of the relationship. A new customer's card
   arrives and settles, the welcome is said, and one short accent acknowledges
   the arrival: arrival, acknowledgement, momentum, in about 2.2s. There is no
   line running anywhere, no progress and no waiting state — the card and the
   words are the whole moment, and it stays smaller than the email sequence
   that follows it. */
.art-entry {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: clamp(1.4rem, 3.8vw, 3.6rem);
  width: min(100%, 940px);
}
.entry-card {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: clamp(0.75rem, 1.7vw, 1.15rem);
  width: clamp(176px, 18vw, 244px);
  padding: clamp(0.85rem, 1.6vw, 1.3rem) clamp(0.95rem, 1.9vw, 1.5rem);
  background: var(--white);
  border-radius: clamp(8px, 1vw, 14px);
  box-shadow: 0 24px 48px -30px rgba(10, 18, 27, 0.42);
}
/* The arriving customer's own mark, on the line with the name of what is
   arriving, so the moment reads as a business entering the relationship in a
   still frame and with motion off. */
.entry-id { display: flex; align-items: center; gap: clamp(0.45rem, 1vw, 0.75rem); }
.entry-mark { flex: 0 0 auto; width: clamp(20px, 2vw, 28px); aspect-ratio: 1; border-radius: 50%; background: var(--ink); }
.entry-label { color: var(--muted-ink); font-size: 0.64rem; line-height: 1.25; font-weight: 760; letter-spacing: 0.16em; text-transform: uppercase; }
.entry-accent { display: block; width: clamp(30px, 3.4vw, 46px); height: 3px; border-radius: 2px; background: var(--blue); transform-origin: 0 50%; }
/* The welcome itself: a small supporting label, then the primary message, held
   to one line at desktop width. */
.entry-message { display: flex; flex-direction: column; gap: clamp(0.5rem, 1.1vw, 0.9rem); }
.entry-kicker { margin: 0; color: var(--copy); font-size: 0.64rem; font-weight: 760; letter-spacing: 0.16em; text-transform: uppercase; }
.entry-head { max-width: 18ch; margin: 0; color: var(--ink); font-size: clamp(1.55rem, 3.3vw, 3.1rem); line-height: 1.04; letter-spacing: -0.042em; font-weight: 700; text-wrap: balance; }
/* Arrival, then the welcome, then the acknowledgement. */
.scene-entry.is-active .entry-card { animation: entry-card-in 820ms cubic-bezier(.2,.75,.2,1) 120ms both; }
.scene-entry.is-active .entry-kicker { animation: entry-kicker-in 460ms ease 760ms both; }
.scene-entry.is-active .entry-head { animation: entry-head-in 720ms cubic-bezier(.2,.75,.2,1) 940ms both; }
.scene-entry.is-active .entry-accent { animation: entry-accent-in 640ms cubic-bezier(.25,.7,.2,1) 1620ms both; }
@keyframes entry-card-in { from { opacity: 0; transform: translate(-22px, 14px) rotate(-1.4deg); } }
@keyframes entry-kicker-in { from { opacity: 0; } }
@keyframes entry-head-in { from { opacity: 0; transform: translateY(12px); } }
@keyframes entry-accent-in { from { transform: scaleX(0); } }

/* 02 Welcome email — the four supplied emails of the accreditation onboarding
   sequence, staged as one composition. The welcome email arrives alone and
   holds; the three that follow it become visible as edges tucked behind it;
   then they extend out from behind it into one layered spread, still
   overlapping, with the welcome email still in front and still the primary
   card. Every card is cropped to the same window — all four emails are the same
   width, and each crop starts at the top — so the group reads as one sequence
   rather than four unrelated sheets. */
.welcome-set {
  --doc-w: clamp(160px, 20vw, 288px);
  /* Distance between neighbouring cards in the opened spread, as a share of the
     card's own width: they overlap by design, they are never a four-up row. */
  --fan: calc(var(--doc-w) * 0.62);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
  width: min(100%, 1240px);
  margin-inline: auto;
}
.welcome-set .doc { grid-area: 1 / 1; margin: 0; transform: var(--settled); }
/* With the stage stacked — the scripting-off state — the scene grows to fit the
   cards, so they keep a margin instead of ending flush with the scene edge. The
   cards that sit lower in the deck extend about a tenth of their width below
   the group, so the lower margin carries that as well as the soft shadow. The
   staged stage has its own frame and needs none of this. */
.lifecycle-stage:not(.is-staged) .welcome-set {
  --stack-pad: clamp(1.25rem, 2.6vw, 2.25rem);
  margin-block: var(--stack-pad) calc(var(--stack-pad) + var(--doc-w) * 0.1 + 0.75rem);
}
.welcome-set .doc > img,
.welcome-set .doc-open {
  display: block;
  width: var(--doc-w);
  aspect-ratio: 1207 / 2414;
  border-radius: clamp(6px, 0.8vw, 12px);
  background: var(--white);
  overflow: hidden;
}
.welcome-set .doc > img { height: auto; object-fit: cover; object-position: center top; box-shadow: 0 18px 40px -26px rgba(10, 18, 27, 0.38); }
.welcome-set .doc-open { padding: 0; border: 0; box-shadow: 0 26px 54px -28px rgba(10, 18, 27, 0.5); cursor: zoom-in; }
.welcome-set .doc-open img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center top; }
/* The opened spread. The welcome email holds the front; the three that follow
   it are placed to the right of it, each one a little lower and a little
   further back, each one still overlapping the next. */
.doc-lead { --settled: translateX(calc(var(--fan) * -1.5)); z-index: 5; }
.doc-2 { --settled: translateX(calc(var(--fan) * -0.5)) translateY(calc(var(--doc-w) * 0.03)) rotate(-1.4deg); --peek: calc(var(--doc-w) * 0.05); z-index: 4; }
.doc-3 { --settled: translateX(calc(var(--fan) * 0.5)) translateY(calc(var(--doc-w) * 0.06)) rotate(1.1deg); --peek: calc(var(--doc-w) * 0.10); z-index: 3; }
.doc-4 { --settled: translateX(calc(var(--fan) * 1.5)) translateY(calc(var(--doc-w) * 0.09)) rotate(1.8deg); --peek: calc(var(--doc-w) * 0.15); z-index: 2; }
/* The sequence. The welcome email arrives alone in the middle of the stage —
   where a single email belongs — and holds. Each card behind it then comes out
   to its edge and holds there, so the compact stack is legible as three emails
   behind the welcome email, and only then does the spread open: the welcome
   email moves left out of the way while the three extend out to its right, so
   the group is centred before and after. */
.scene-welcome.is-active .doc-lead { animation: doc-lead 3380ms cubic-bezier(.2,.75,.2,1) 120ms both; }
.scene-welcome.is-active .doc-2 { animation: doc-spread 1700ms linear 1560ms both; }
.scene-welcome.is-active .doc-3 { animation: doc-spread 1700ms linear 1680ms both; }
.scene-welcome.is-active .doc-4 { animation: doc-spread 1700ms linear 1800ms both; }
@keyframes doc-lead {
  0% { opacity: 0; transform: translateX(0) translateY(26px); animation-timing-function: cubic-bezier(.2,.75,.2,1); }
  24%, 62% { opacity: 1; transform: translateX(0) translateY(0); animation-timing-function: cubic-bezier(.2,.75,.2,1); }
  100% { transform: translateX(calc(var(--fan) * -1.5)) translateY(0); }
}
@keyframes doc-spread {
  0% { transform: translateX(0) translateY(0) rotate(0deg); animation-timing-function: cubic-bezier(.2,.75,.2,1); }
  15%, 48% { transform: translateX(var(--peek)) translateY(0) rotate(0deg); animation-timing-function: cubic-bezier(.2,.75,.2,1); }
  100% { transform: var(--settled); }
}

/* 03 Value / benefits mailer — a simplified direct-mail piece. */
.art-mailer {
  display: flex;
  flex-direction: column;
  width: clamp(272px, 46vw, 620px);
  aspect-ratio: 16 / 10;
  padding: clamp(1.1rem, 2.4vw, 2.2rem);
  background: var(--white);
  border-radius: clamp(8px, 1vw, 14px);
  box-shadow: 0 30px 60px -34px rgba(10, 18, 27, 0.46);
}
.art-mailer::before { content: ""; display: block; width: 36px; height: 3px; border-radius: 2px; background: var(--blue); }
.mailer-eyebrow { margin: clamp(0.9rem, 2vw, 1.4rem) 0 0; color: var(--muted-ink); font-size: 0.64rem; font-weight: 760; letter-spacing: 0.16em; text-transform: uppercase; }
.mailer-head { margin: clamp(0.5rem, 1.2vw, 0.9rem) 0 0; max-width: 24ch; color: var(--ink); font-size: clamp(1.05rem, 1.9vw, 1.75rem); line-height: 1.08; letter-spacing: -0.035em; font-weight: 700; }
/* Three stand-in benefit lines: a mark that reads at a glance, with the copy
   itself abstract rather than invented. */
.mailer-lines { display: grid; gap: clamp(0.6rem, 1.2vw, 0.95rem); margin: auto 0 0; padding: 0; list-style: none; }
.mailer-lines li { display: flex; align-items: center; gap: clamp(0.55rem, 1vw, 0.85rem); }
.mailer-lines li::before { content: ""; flex: 0 0 auto; width: 5px; height: 5px; border-radius: 50%; background: var(--ink); opacity: 0.55; }
.mailer-lines li::after { content: ""; flex: 0 0 auto; height: 1px; background: rgba(10, 18, 27, 0.32); }
.mailer-lines li:nth-child(1)::after { width: 68%; }
.mailer-lines li:nth-child(2)::after { width: 50%; }
.mailer-lines li:nth-child(3)::after { width: 60%; }

/* 04 Check-in call — an editorial speech treatment, not a phone thread. */
.art-call { max-width: min(100%, 780px); margin: 0; padding-left: clamp(1rem, 2.2vw, 1.9rem); border-left: 3px solid var(--blue); }
.call-line { margin: 0; max-width: 28ch; color: var(--ink); font-size: clamp(1.3rem, 2.7vw, 2.35rem); line-height: 1.16; letter-spacing: -0.038em; font-weight: 700; text-wrap: balance; }
/* A spoken line, read as a voice: long enough to register as a waveform rather
   than as a stray mark, and still one restrained horizontal gesture. */
.call-wave { display: flex; align-items: flex-end; gap: clamp(6px, 0.75vw, 10px); height: clamp(34px, 3.4vw, 48px); margin-top: clamp(1rem, 2.2vw, 1.7rem); }
.call-wave span { display: block; width: clamp(4px, 0.38vw, 6px); border-radius: 3px; background: var(--ink); transform-origin: 50% 100%; animation: call-wave 1500ms ease-in-out infinite alternate; animation-play-state: paused; }
.call-wave span:nth-child(1) { height: 34%; animation-delay: -200ms; }
.call-wave span:nth-child(2) { height: 62%; animation-delay: -850ms; animation-duration: 1150ms; }
.call-wave span:nth-child(3) { height: 86%; animation-delay: -420ms; animation-duration: 1750ms; }
.call-wave span:nth-child(4) { height: 100%; animation-delay: -1200ms; animation-duration: 1300ms; }
.call-wave span:nth-child(5) { height: 72%; animation-delay: -640ms; animation-duration: 1600ms; }
.call-wave span:nth-child(6) { height: 48%; animation-delay: -1000ms; animation-duration: 1250ms; }
.call-wave span:nth-child(7) { height: 92%; animation-delay: -300ms; animation-duration: 1400ms; }
.call-wave span:nth-child(8) { height: 58%; animation-delay: -1450ms; animation-duration: 1700ms; }
.call-wave span:nth-child(9) { height: 40%; animation-delay: -700ms; animation-duration: 1200ms; }
.scene-call.is-active .call-wave span { animation-play-state: running; }
@keyframes call-wave { from { transform: scaleY(0.26); } to { transform: scaleY(1); } }

/* 05 Event / webinar invitation — a simple invitation moment. */
.art-invite {
  position: relative;
  display: grid;
  place-items: center;
  align-content: center;
  gap: clamp(0.6rem, 1.4vw, 1.1rem);
  width: clamp(258px, 42vw, 560px);
  aspect-ratio: 3 / 2;
  padding: clamp(1.1rem, 2.4vw, 2.2rem);
  background: var(--white);
  border-radius: clamp(8px, 1vw, 14px);
  box-shadow: 0 30px 60px -34px rgba(10, 18, 27, 0.46);
  text-align: center;
}
.art-invite::after { content: ""; position: absolute; inset: clamp(0.6rem, 1.5vw, 1rem); border: 1px solid var(--line); border-radius: clamp(4px, 0.6vw, 8px); }
.invite-mark { width: 28px; height: 3px; border-radius: 2px; background: var(--blue); }
.invite-line { margin: 0; color: var(--ink); font-size: clamp(1.25rem, 2.5vw, 2.1rem); line-height: 1.05; letter-spacing: -0.04em; font-weight: 700; }
.invite-details { display: grid; gap: 7px; width: min(58%, 210px); }
.invite-details span { height: 1px; background: var(--line); }

/* 06 Renewal — the loop closes on itself and the renewal is confirmed: the ring
   draws a full turn, then the check is drawn inside it. */
.art-renewal { display: grid; place-items: center; gap: clamp(0.9rem, 1.9vw, 1.5rem); margin: 0; }
.renewal-arc { display: block; width: clamp(160px, 24vw, 340px); aspect-ratio: 1; }
.renewal-arc svg { display: block; width: 100%; height: 100%; overflow: visible; }
.renewal-track { fill: none; stroke: var(--line); stroke-width: 1.4; }
.renewal-draw { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linecap: round; stroke-dasharray: 452; stroke-dashoffset: 0; transform: rotate(-90deg); transform-origin: 50% 50%; }
.renewal-check {
  fill: none;
  stroke: var(--blue);
  stroke-width: 4.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 89;
  stroke-dashoffset: 0;
  opacity: 0;
}
.scene-renewal.is-active .renewal-draw { animation: renewal-draw 1900ms cubic-bezier(.35,.6,.2,1) 140ms both; }
.scene-renewal.is-active .renewal-check { animation: renewal-check 620ms cubic-bezier(.3,.7,.2,1) 1960ms both; }
@keyframes renewal-draw { from { stroke-dashoffset: 452; } to { stroke-dashoffset: 0; } }
@keyframes renewal-check {
  0% {
    stroke-dashoffset: 89;
    opacity: 0;
  }

  2% {
    opacity: 1;
  }

  100% {
    stroke-dashoffset: 0;
    opacity: 1;
  }
}
.renewal-line {
  position: relative;
  min-height: 1.2em;
  max-width: 24ch;
  color: var(--ink);
  font-size: clamp(1.05rem, 1.7vw, 1.45rem);
  line-height: 1.2;
  letter-spacing: -0.03em;
  font-weight: 700;
  text-align: center;
  text-wrap: balance;
}

.renewal-before,
.renewal-after {
  display: block;
  opacity: 0;
}

.renewal-after {
  position: absolute;
  inset: 0;
}

.scene-renewal.is-active .renewal-before {
  animation: renewal-copy-before 2580ms linear both;
}

.scene-renewal.is-active .renewal-after {
  animation: renewal-copy-in 180ms ease 2580ms both;
}

@keyframes renewal-copy-before {
  0%,
  99.9% {
    opacity: 1;
  }

  100% {
    opacity: 0;
  }
}

@keyframes renewal-copy-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* The rail: six stage markers on one thin route, with a moving indicator. */
.lifecycle-rail { margin-top: clamp(1.3rem, 2.8vw, 2.2rem); }
.rail-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.4rem clamp(1rem, 3vw, 2rem); }
.rail-head .case-link {
  margin-top: 0;
}
.lifecycle-current { display: none; margin: 0; color: var(--ink); font-size: 0.68rem; font-weight: 760; letter-spacing: 0.11em; text-transform: uppercase; }
.lifecycle-toggle {
  margin-left: auto;
  border: 0;
  padding: 0;
  background: none;
  color: var(--muted-ink);
  font-size: 0.8rem;
  font-weight: 700;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
}
.lifecycle-toggle:hover,
.lifecycle-toggle:focus-visible { color: var(--ink); }

.rail-track { position: relative; margin-top: clamp(1.5rem, 3vw, 2.4rem); }
.rail-route { position: absolute; left: 0; right: 0; top: 5px; height: 1px; background: var(--line); }
.rail-progress { position: absolute; left: 0; top: 0; bottom: 0; width: 8.333%; background: var(--ink); transition: width 780ms cubic-bezier(.2,.75,.2,1); }
.lifecycle-steps { position: relative; display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: clamp(0.6rem, 1.4vw, 1.4rem); margin: 0; padding: 0; list-style: none; }
.lifecycle-steps button { display: grid; justify-items: start; gap: 0.5rem; width: 100%; border: 0; padding: 0; background: none; color: var(--muted-ink); text-align: left; cursor: pointer; }
.step-tick { width: 11px; height: 11px; margin-top: 0; border: 1px solid rgba(10, 18, 27, 0.3); border-radius: 50%; background: var(--paper); transition: background-color 420ms ease, border-color 420ms ease, transform 420ms cubic-bezier(.2,.75,.2,1); }
.step-index { color: inherit; font-size: 0.62rem; font-weight: 760; letter-spacing: 0.16em; transition: color 320ms ease; }
.step-name { color: inherit; font-size: 0.7rem; line-height: 1.3; font-weight: 760; letter-spacing: 0.1em; text-transform: uppercase; transition: color 320ms ease; }
.lifecycle-steps button:hover { color: var(--ink); }
.lifecycle-steps button[aria-current="true"] { color: var(--ink); }
.lifecycle-steps button[aria-current="true"] .step-tick { background: var(--ink); border-color: var(--ink); transform: scale(1.18); }

/* ---------- More work: four pieces, one row, one height ---------- */

.more-work { --feed-h: clamp(200px, 27vw, 384px); padding: 0 0 clamp(5rem, 10vw, 9rem); }
/* Each piece is as wide as its own aspect ratio at the shared height, and the
   caption wraps inside that width rather than widening the row. */
.feed-w1 { width: var(--feed-h); }
.feed-w23 { width: calc(var(--feed-h) * 2 / 3); }
.feed-w916 { width: calc(var(--feed-h) * 9 / 16); }
.more-work h2 { max-width: 26ch; font-size: clamp(1.9rem, 3.2vw, 3.4rem); }
.feed {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: clamp(0.8rem, 1.7vw, 1.5rem);
  margin-top: clamp(2.5rem, 5vw, 5rem);
}
/* One shared height; the widths follow each artifact's own aspect ratio. */
.feed-item { flex: 0 0 auto; margin: 0; }
.feed-item > img { width: 100%; height: var(--feed-h); object-fit: cover; border-radius: clamp(10px, 1.2vw, 16px); }
.feed-media { position: relative; width: 100%; height: var(--feed-h); overflow: hidden; border-radius: clamp(10px, 1.2vw, 16px); }
.feed-media video { width: 100%; height: 100%; object-fit: cover; }
.feed-square { aspect-ratio: 1 / 1; }
.feed-vertical { aspect-ratio: 9 / 16; }
.feed-item figcaption { margin-top: 0.7rem; }

/* ---------- Zoom: the same file, shown larger. No second copy is made. ----- */

.zoom { width: min(860px, 94vw); max-height: 92svh; padding: 0; border: 0; border-radius: 18px; background: var(--paper); color: var(--ink); box-shadow: 0 40px 100px rgba(4, 9, 14, 0.5); }
.zoom::backdrop { background: rgba(4, 9, 14, 0.72); }
.zoom-bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.8rem 1.1rem; border-bottom: 1px solid var(--line); }
.zoom-label { margin: 0; color: var(--muted-ink); font-size: 0.72rem; font-weight: 760; letter-spacing: 0.13em; text-transform: uppercase; }
.zoom-close { border: 1px solid var(--line); border-radius: 999px; padding: 0.5rem 0.95rem; background: transparent; color: inherit; font-weight: 700; cursor: pointer; }
.zoom-close:hover { border-color: var(--ink); }
.zoom img { display: block; width: 100%; height: auto; max-height: calc(92svh - 64px); object-fit: contain; background: #fff; }

.site-footer { display: flex; justify-content: space-between; gap: 2rem; padding: 2.2rem max(24px, calc((100vw - var(--max)) / 2)); background: var(--ink); color: white; font-size: 0.82rem; }
.site-footer p { margin: 0; }

.information {
  position: fixed;
  inset: 0 0 0 auto;
  z-index: 50;
  width: min(760px, 100%);
  overflow-y: auto;
  background: var(--ink);
  color: white;
  transform: translateX(102%);
  transition: transform 380ms cubic-bezier(.2,.75,.2,1);
}
.information[aria-hidden="false"] { transform: translateX(0); }
.information-scrim { position: fixed; inset: 0; z-index: 40; background: rgba(4, 9, 14, 0.62); }
.information-bar { display: flex; justify-content: space-between; align-items: center; min-height: 92px; padding: 0 clamp(1.5rem, 5vw, 4rem); border-bottom: 1px solid rgba(255, 255, 255, 0.15); font-weight: 720; }
.info-close { border: 1px solid rgba(255, 255, 255, 0.3); border-radius: 999px; padding: 0.55rem 0.9rem; background: transparent; color: white; cursor: pointer; }
.info-close:hover { border-color: rgba(255, 255, 255, 0.7); }
.information-body { padding: clamp(4rem, 10vw, 8rem) clamp(1.5rem, 6vw, 5rem); }
.information-lead { max-width: 620px; margin: 0 0 clamp(5rem, 10vw, 9rem); font-size: clamp(2.2rem, 4.5vw, 4.2rem); line-height: 1.02; letter-spacing: -0.05em; font-weight: 710; }
.information-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem; }
.information-grid .tiny { color: #6bbef5; }
.information-grid p { color: #bac4cc; }
.information-grid a { color: white; text-underline-offset: 0.25em; }

/* ---------- Wide screens: the packet becomes a staged fan ---------- */

@media (min-width: 901px) {
  .packet-stage.is-staged {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    padding: clamp(20px, 2.6vw, 44px);
    overflow: hidden;
    scroll-snap-type: none;
  }
  .packet-stage.is-staged .packet-page {
    grid-area: 1 / 1;
    width: 56%;
    margin-inline: auto;
    box-shadow: 0 0 0 1px rgba(10, 18, 27, 0.06), 0 20px 38px -20px rgba(10, 18, 27, 0.4);
  }
  /* The sheets beside the front page sit a little lower and a little further
     back, so the stack reads as paper placed by hand rather than a row. */
  .packet-stage.is-staged .packet-page.is-left { transform: translateX(-32%) rotate(-2.4deg) translateY(14px); z-index: 2; }
  .packet-stage.is-staged .packet-page.is-right { transform: translateX(32%) rotate(2.2deg) translateY(14px); z-index: 1; }
  .packet-stage.is-staged .packet-page.is-front { transform: none; z-index: 3; box-shadow: 0 36px 66px -24px rgba(10, 18, 27, 0.5); }
  .packet-stage.is-staged .packet-page.is-off { opacity: 0; visibility: hidden; pointer-events: none; }
  .packet-stage.is-staged .packet-page.is-left .packet-open,
  .packet-stage.is-staged .packet-page.is-right .packet-open { cursor: pointer; }
}

/* ---------- Mobile: its own composition, not a shrunken desktop ---------- */

@media (max-width: 760px) {
  :root { --gutter: 14px; }
  body { font-size: 16px; }
  .site-header { min-height: 72px; }
  .identity > span:last-child { display: none; }
  .site-nav { gap: 1rem; }
  .site-nav a,
  .site-nav button { font-size: 0.88rem; }

  .hero { padding: 2rem 0 2.5rem; }
  .hero h1 { max-width: 20ch; font-size: clamp(2.1rem, 10.5vw, 3.2rem); }
  .hero-sub { max-width: 38ch; }
  .project { margin-bottom: 4.5rem; }
  .project-trust { margin-bottom: 6rem; }
  .project-lifecycle { margin-bottom: 5rem; }
  .project-packets { margin-bottom: 4rem; }
  .project-media { margin-bottom: 4.5rem; }
  .project-connections { margin-bottom: 4.5rem; }
  .project-shred { margin-bottom: 5.5rem; }
  .project h2,
  .packet-copy h2,
  .media-copy h2,
  .trust-head h2,
  .connections-copy h2,
  .more-work h2 { font-size: clamp(1.7rem, 7.4vw, 2.5rem); max-width: none; }

  /* Shred Day: one column — copy, the volunteer, then the turnout. The deskop
     spread's column and row placements are reset here, including the heading's,
     which otherwise sat in the volunteer's grid cell. */
  .shred-spread { grid-template-columns: minmax(0, 1fr); row-gap: 2.4rem; }
  /* The heading sits in a grid cell here, so the shared content measure would
     inset it a second time. On one column it takes the full width instead. */
  .project-shred .project-head { grid-column: 1; grid-row: 1; align-self: auto; position: static; z-index: auto; width: 100%; margin-inline: 0; }
  .shred-human { grid-column: 1; grid-row: 2; margin-top: 0; }
  .shred-scale { grid-column: 1; grid-row: 3; margin-top: 0; }
  .shred-note { grid-column: 1; grid-row: 4; margin-top: 0; max-width: 40ch; }

  /* Packet: one readable page per snap, controls underneath */
  .packet-layout { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto; gap: 1.6rem; }
  .packet-copy,
  .packet-stage,
  .packet-tools { grid-column: 1; grid-row: auto; }
  .packet-page { flex: 0 0 84%; }
  .packet-controls { flex-wrap: wrap; }
  .packet-step,
  .packet-rail button { min-height: 44px; display: inline-flex; align-items: center; }

  /* Media */
  .media-layout { grid-template-columns: minmax(0, 1fr); gap: 1.6rem; }
  .media-support { grid-template-columns: minmax(0, 1fr); gap: 2.4rem; margin-top: 2.2rem; }
  /* Every supporting frame resets, the custom third one included: a single
     column, no desktop row placement, no negative offsets left over. */
  .frame-wide,
  .frame-third,
  .frame-left { grid-column: 1; grid-row: auto; margin-top: 0; position: static; z-index: auto; }
  .motion-toggle { min-height: 44px; right: 10px; top: 10px; }

  /* Trust film, connections */
  .connections-layout { grid-template-columns: minmax(0, 1fr); gap: 1.6rem; align-items: start; }

  /* Lifecycle: the same one-touchpoint-at-a-time stage, taller and narrower.
     The six markers stay one route, with the stage name read out beneath them
     rather than all six names exposed. */
  .lifecycle-stage.is-staged { aspect-ratio: 4 / 5; }
  .lifecycle-stage.is-staged .scene { padding: 1.7rem 1.2rem; }
  .lifecycle-current { display: block; }
  .lifecycle-steps { gap: 0.5rem; }
  .step-tick { width: 9px; height: 9px; }
  .step-name { position: absolute; width: 1px; height: 1px; overflow: hidden; white-space: nowrap; clip-path: inset(50%); }
  .lifecycle-toggle { display: inline-flex; align-items: center; min-height: 44px; }
  /* 01 and 02 at phone width: the arrival stacks its card above its message,
     and the four-email spread stays inside the same gutters at a smaller size,
     with the cards closer together so the overlap still reads. */
  .art-entry { flex-direction: column; align-items: flex-start; gap: 1.5rem; width: 100%; }
  .entry-card { width: min(180px, 52%); }
  .entry-head { font-size: clamp(1.5rem, 7vw, 2.1rem); }
  .welcome-set { --doc-w: min(140px, 31vw); --fan: calc(var(--doc-w) * 0.5); }
  /* The stacked edges are read here at roughly half the desktop card size, so
     they open about twice as far as a share of the card and still stay edges. */
  .doc-2 { --peek: calc(var(--doc-w) * 0.08); }
  .doc-3 { --peek: calc(var(--doc-w) * 0.16); }
  .doc-4 { --peek: calc(var(--doc-w) * 0.24); }

  /* More work: two pieces per row over two rows, aligned to the page gutters.
     The left column is a little wider than the right so that each row's two
     pieces land at almost the same height: a 1.64 : 1 split puts the two 1:1
     pieces level with the 2:3 and 9:16 portraits, so every artifact keeps its
     own ratio and nothing is cropped to fit. The geofenced piece sits beside
     the awards piece on the second row, so the rows read proof, awards /
     geofence, fundraising. */
  .feed {
    display: grid;
    grid-template-columns: minmax(0, 1.64fr) minmax(0, 1fr);
    align-items: start;
    gap: 1.1rem 0.7rem;
  }
  .feed-item { width: 100%; }
  .feed-item > img { height: auto; }
  .feed-media { height: auto; }
  .feed-item:nth-child(1) { order: 1; }
  .feed-item:nth-child(2) { order: 2; }
  .feed-item:nth-child(4) { order: 3; }
  .feed-item:nth-child(3) { order: 4; }
  .feed-item figcaption { margin: 0.5rem 0 0; }

  .zoom { width: min(560px, 94vw); }
  .site-footer { flex-direction: column; gap: 0.6rem; }
  .information-grid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { scroll-behavior: auto !important; transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
  /* The waveform holds a still frame rather than a loop. */
  .call-wave span { animation: none !important; transform: none !important; }
  /* The two rebuilt moments hold their settled state instead of stepping
     through it: the arrival card, its welcome and accent, and the four-email
     spread are each simply there. */
  .scene-entry.is-active .entry-card,
  .scene-entry.is-active .entry-kicker,
  .scene-entry.is-active .entry-head,
  .scene-entry.is-active .entry-accent,
  .scene-welcome.is-active .doc { animation: none !important; }
}

/* =========================================================================
   Desktop case chapters — the homepage's major work sections.

   At desktop widths each major work section is one deliberate chapter: the
   section, not its contents, is the unit the page settles on. Every chapter is
   a viewport tall, its own top edge is the snap position, and the artifact
   region inside it takes the height that is left once the case header, the
   controls and the rail have been laid out — so the artifact fills the room it
   is given rather than sitting in a fixed frame with canvas above and below it.

   `y proximity`, deliberately not `mandatory`: an ordinary scroll still decides
   where the page goes, and a chapter only claims the position once the visitor
   has already come to rest near it. Nothing about the page is trapped.

   The site header is in the flow above the work section (`position: relative`,
   not fixed), so a chapter aligned at the top edge is never covered by it. What
   the first view has to clear is the chapter's own air: `--chapter-air` at the
   head, and an uneven foot that keeps the pause each section used to carry.

   Below this width none of it applies. The phone and the narrow tablet keep the
   sections they already had, and scroll normally. */

@media (min-width: 901px) {
  html:has(.work) { scroll-snap-type: y mandatory; }
  
  .site-header {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

.hero {
  scroll-snap-align: none;
}
  
  .more-work {
  scroll-snap-align: start;
}

.site-footer {
  scroll-snap-align: end;
}
  
  .work > .project {
    --chapter-air: clamp(1.25rem, 3.6vh, 2.25rem);
    display: flex;
    flex-direction: column;
    min-height: 100svh;
    margin: 0;
    padding-block: var(--chapter-air) var(--chapter-air-foot, var(--chapter-air));
    scroll-snap-align: start;
  }

  /* The pause a section used to keep between itself and the next one becomes
     the chapter's own foot, so the cadence stays uneven instead of marching at
     one interval. */
  .work > .project-trust { --chapter-air-foot: calc(var(--chapter-air) * 1.4); }
  .work > .project-lifecycle { --chapter-air-foot: calc(var(--chapter-air) * 1.1); }
  .work > .project-packets { --chapter-air-foot: calc(var(--chapter-air) * 0.9); }
  .work > .project-media { --chapter-air-foot: calc(var(--chapter-air) * 0.7); }
  .work > .project-connections { --chapter-air-foot: calc(var(--chapter-air) * 1.2); }
  .work > .project-shred { --chapter-air-foot: calc(var(--chapter-air) * 1.1); }

  /* Trust, Built Locally: the film is this chapter's own artifact region, so it
     takes the height left under the heading and stops at the page's measure. It
     keeps its ratio — the height decides the film and 16:9 decides its width —
     which is what holds the film, the heading and the route into the case in one
     first view instead of running the heading off the bottom of it. */
  .work > .project > .trust-film {
    flex: 1 1 0;
    min-height: 0;
    width: auto;
    max-width: 100%;
    max-height: calc(min(100vw - var(--gutter) * 2, var(--max)) * 9 / 16);
    aspect-ratio: 16 / 9;
    align-self: center;
  }

  /* Lifecycle: the stage is the artifact region. It takes the height left under
     the introduction, the controls row and the rail, and it is a size container,
     so every artifact inside it is sized from the room the stage actually has
     rather than from a fixed 16:9 frame.

     A definite height, not only a floor — the block-axis container queries those
     artifacts are measured in only resolve against a chapter whose own height is
     settled. It holds only while the sequence is assembled: with scripting off
     the six moments are a stack of states in the flow, which needs its own
     height, so the chapter keeps the floor and grows. */
  .work > .project-lifecycle:has(.lifecycle-stage.is-staged) { height: 100svh; }
  .project-lifecycle > .lifecycle {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  .project-lifecycle .lifecycle-stage.is-staged {
    flex: 1 1 auto;
    min-height: 0;
    max-height: min(74svh, 58vw);
    aspect-ratio: auto;
    --scene-pad: clamp(0.9rem, 2.4vh, 1.9rem);
  }
  /* Declared together with the definite chapter height, so that a browser
     without `:has()` gets the artifacts' viewport fallback rather than a
     container nobody has sized. Written here and resolved inside the stage,
     where `cqh` measures the stage's own box: the height the artifacts have to
     work with. */
  .project-lifecycle:has(.lifecycle-stage.is-staged) .lifecycle-stage.is-staged {
    --stage-room: max(0px, calc(100cqh - var(--scene-pad) * 2));
    container-type: size;
  }
  .project-lifecycle .lifecycle-stage.is-staged .scene { padding: var(--scene-pad); }

  /* Each artifact in the stage is sized from that room — the room settles one
     axis, the artifact's own ratio settles the other — so the composition fills
     the stage instead of floating in it. The viewport-relative caps are the ones
     each artifact already carried. */
  /* The cards read at 1207 : 2414, so a card is twice its own width tall, and
     the spread drops the cards behind it a further tenth of that width. 2.2
     is those two together, with the rotation's share as headroom. */
  .project-lifecycle .lifecycle-stage.is-staged .welcome-set { --doc-w: min(20vw, calc(var(--stage-room, 40svh) / 2.2)); }
  .project-lifecycle .lifecycle-stage.is-staged .art-mailer { width: min(46vw, 620px, calc(var(--stage-room, 40svh) * 1.6)); }
  .project-lifecycle .lifecycle-stage.is-staged .art-invite { width: min(42vw, 560px, calc(var(--stage-room, 40svh) * 1.45)); }
  .project-lifecycle .lifecycle-stage.is-staged .renewal-arc { width: min(24vw, 340px, calc(var(--stage-room, 40svh) * 0.6)); }
  .project-lifecycle .lifecycle-stage.is-staged .renewal-line { font-size: min(1.7vw, calc(var(--stage-room, 40svh) * 0.062)); }
  .project-lifecycle .lifecycle-stage.is-staged .call-line { font-size: min(2.7vw, calc(var(--stage-room, 40svh) * 0.115)); }
  .project-lifecycle .lifecycle-stage.is-staged .call-wave { height: min(3.4vw, calc(var(--stage-room, 40svh) * 0.13)); }
  .project-lifecycle .lifecycle-stage.is-staged .art-entry { gap: min(3.8vw, calc(var(--stage-room, 40svh) * 0.11)); }
  .project-lifecycle .lifecycle-stage.is-staged .entry-card { width: min(18vw, calc(var(--stage-room, 40svh) * 0.62)); }
  .project-lifecycle .lifecycle-stage.is-staged .entry-head { font-size: min(3.3vw, calc(var(--stage-room, 40svh) * 0.13)); }
}
/* ---------- Case page (unchanged) ---------- */

.case { width: min(calc(100% - 48px), var(--max)); margin: 0 auto; }

.case-hero { padding: clamp(1rem, 4vw, 3.5rem) 0 clamp(2rem, 4vw, 3.5rem); }
.case-hero .project-number { color: var(--muted-ink); }
.case-hero h1 {
  max-width: 1100px;
  overflow-wrap: break-word;
  margin: 0.9rem 0 0;
  font-size: clamp(2.6rem, 6.2vw, 6.4rem);
  line-height: 0.97;
  letter-spacing: -0.058em;
  font-weight: 720;
}
.case-standfirst {
  max-width: 720px;
  margin: clamp(1.4rem, 3vw, 2.4rem) 0 0;
  color: #4c5257;
  font-size: clamp(1.1rem, 1.5vw, 1.4rem);
  line-height: 1.4;
}
.case-meta { margin: clamp(1.6rem, 3vw, 2.6rem) 0 0; }

.case-opener { margin: 0; }
.case-opener img {
  width: 100%;
  aspect-ratio: 16 / 9;
  min-height: min(48vw, 620px);
  object-fit: cover;
  object-position: center 42%;
  border-radius: clamp(18px, 2.2vw, 34px);
}
.case figcaption {
  margin-top: 0.8rem;
  color: var(--muted-ink);
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.case-section {
  display: grid;
  grid-template-columns: minmax(0, 0.28fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 5vw, 5rem);
  padding: clamp(4rem, 9vw, 8rem) 0 0;
}
.case-section .section-label { color: var(--muted-ink); padding-top: 0.5rem; }
.case-section > div { max-width: 760px; }
.case-section p { margin: 0 0 1.1rem; }
.case-section p:last-child { margin-bottom: 0; }
.case-lede { font-size: clamp(1.5rem, 2.9vw, 2.5rem); line-height: 1.12; letter-spacing: -0.035em; font-weight: 700; max-width: 22ch; }
.case-note { color: #5b6167; font-size: 0.95rem; }

.case-sequence { padding: clamp(4rem, 9vw, 8rem) 0 0; }
.case-sequence > .section-label { color: var(--muted-ink); }
.sequence-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.75rem);
  margin-top: clamp(1.6rem, 3vw, 2.5rem);
}
.case-sequence figure { margin: 0; }
.sequence-pair img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; object-position: center; border-radius: clamp(14px, 1.6vw, 24px); }
.sequence-pair figure:first-child img { object-position: center 38%; }
.sequence-wide { margin: clamp(1.4rem, 3vw, 2.6rem) 0 0; }
.sequence-wide img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; object-position: center 45%; border-radius: clamp(14px, 1.6vw, 24px); }

.case-nav { padding: clamp(3.5rem, 8vw, 7rem) 0 clamp(6rem, 12vw, 11rem); }
.case-back { display: inline-flex; align-items: center; gap: 0.6rem; font-weight: 720; text-decoration: none; }
.case-back:hover { color: var(--blue); }
.case-back:focus-visible { outline: 3px solid var(--blue); outline-offset: 6px; border-radius: 4px; }

@media (max-width: 760px) {
  .case { width: calc(100% - 28px); }
  .case-opener img { aspect-ratio: 4 / 3; min-height: 0; object-position: center 42%; }
  .case-section { grid-template-columns: 1fr; gap: 0.9rem; padding-top: 3.5rem; }
  .case-section .section-label { padding-top: 0; }
  .case-sequence { padding-top: 3.5rem; }
  .sequence-pair { grid-template-columns: 1fr; gap: 1.4rem; }
  .sequence-pair img { aspect-ratio: 3 / 2; }
  .sequence-wide img { aspect-ratio: 3 / 2; }
  .case-nav { padding: 3.5rem 0 5rem; }
}

/* ---------- Evidence board: Trust, Built Locally ---------- */

/* The child page is an evidence board rather than an article. Everything here is
   scoped to .board and its children, so the homepage and the other case page
   keep the rules they already have. Composition is CSS over supplied artwork
   only: nothing is redrawn, restaged or re-lettered, nothing is cropped away,
   and no live copy sits over a photograph, a document or the film.

   Two states, one markup:
   — the default (and the scripting-off) state is a readable vertical sequence of
     the same artifacts, each at a size it can be understood at;
   — with scripting on, wide screens get the composed tableau, and narrow screens
     get a one-column sequence that scrolls normally. */

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.board {
  --board-max: 1560px;
  --board-gutter: clamp(18px, 3vw, 56px);
  --art-edge: 0 0 0 1px rgba(10, 18, 27, 0.09);
  --art-lift: 0 24px 44px -34px rgba(10, 18, 27, 0.5);
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  background: var(--paper);
  color: var(--ink);
  overscroll-behavior: contain;
}

.board-bar,
.board-head,
.board-field {
  width: min(calc(100% - (var(--board-gutter) * 2)), var(--board-max));
  margin-inline: auto;
}

.board-bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.25rem;
  padding-top: clamp(13px, 1.5vw, 20px);
}

/* The scroll-return cue. It only exists where the gesture does — an overlay over
   a homepage to go back to, a wide screen, and a pointer that can scroll to an
   edge — and it is a note, not a control. */
.board-return-hint {
  display: none;
  margin: 0;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-ink);
}
html.gesture-available:not(.ix-open) .board-return-hint { display: block; }
.board-return-hint kbd {
  font: inherit;
  letter-spacing: inherit;
}

.board-back {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 40px;
  font-size: 0.82rem;
  font-weight: 720;
  letter-spacing: 0.02em;
  text-decoration: none;
  border-bottom: 2px solid var(--line);
  padding-bottom: 0.1rem;
}
.board-back:hover,
.board-back:focus-visible { border-bottom-color: var(--ink); }
.board-back-mark { transition: transform 180ms ease; }
.board-back:hover .board-back-mark { transform: translateX(-3px); }

.board-head { padding-top: clamp(14px, 2vw, 30px); }
.board-eyebrow {
  margin: 0;
  font-size: 0.72rem;
  font-weight: 720;
  letter-spacing: 0.16em;
  color: var(--muted-ink);
}
.board-title {
  margin: 0.5rem 0 0;
  max-width: 26ch;
  font-size: clamp(1.5rem, 2.6vw, 2.5rem);
  line-height: 1.03;
  letter-spacing: -0.045em;
  font-weight: 720;
  text-wrap: balance;
  overflow-wrap: break-word;
}
.board-scope {
  margin: 0.6rem 0 0;
  max-width: 120ch;
  font-size: 0.96rem;
  color: var(--copy);
}
.board-route {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 1.35rem;
  margin: clamp(0.75rem, 1.4vw, 1.2rem) 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--muted-ink);
}
.board-route li { display: inline-flex; align-items: baseline; gap: 0.4rem; }
/* #1487d4 clears 3:1 for the focus outline and rules but only 3.5:1 on paper as
   text at this size, so the small numerals take a darker blue at 5.0:1. */
.route-num { color: #0a6ea8; font-size: 0.64rem; letter-spacing: 0.08em; }

.board-field {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: clamp(1.7rem, 3.6vw, 2.8rem);
  padding: clamp(1.3rem, 2.6vw, 2.2rem) 0 clamp(2.4rem, 5vw, 4.5rem);
}

/* ---------------------------- an artifact -------------------------------- */

.art { position: relative; margin: 0; }
.art-stage { position: relative; }
.art-media {
  position: relative;
  aspect-ratio: var(--ratio, auto);
  box-shadow: var(--art-edge), var(--art-lift);
  border-radius: clamp(4px, 0.5vw, 8px);
  overflow: hidden;
  background: var(--surface);
  transition: transform 200ms ease, box-shadow 200ms ease;
}
.art-media img,
.art-media video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.art-item { position: relative; min-width: 0; }

/* The artifact is the control: one real button stretched over the evidence, and
   the documentary label stays in the markup beside it, never over the picture. */
.art-open {
  position: absolute;
  inset: 0;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  border-radius: clamp(4px, 0.5vw, 8px);
}
.art-inspect {
  position: absolute;
  left: 7px;
  bottom: 7px;
  padding: 0.26rem 0.5rem;
  border-radius: 999px;
  background: rgba(10, 18, 27, 0.88);
  color: #fff;
  font-size: 0.6rem;
  font-weight: 720;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 160ms ease, transform 160ms ease;
  pointer-events: none;
}
.art-open:hover .art-inspect,
.art-open:focus-visible .art-inspect { opacity: 1; transform: translateY(0); }

.art-stage:hover .art-media,
.art-stage:focus-within .art-media {
  transform: translateY(-3px);
  box-shadow: var(--art-edge), 0 30px 52px -34px rgba(10, 18, 27, 0.62);
}

.art-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.85rem;
  margin-top: 0.55rem;
}
.art-label {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  font-size: 0.66rem;
  font-weight: 720;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted-ink);
  transition: color 180ms ease;
}
.art-stage:hover + .art-foot .art-label,
.art-stage:focus-within + .art-foot .art-label { color: var(--ink); }
.art-index { color: #0a6ea8; }
.art-credit { font-size: 0.66rem; color: var(--muted-ink); }
.art-subs { display: none; }
.art-sub {
  position: relative;
  margin: 0.28rem 0 0;
  font-size: 0.62rem;
  letter-spacing: 0.03em;
  color: var(--muted-ink);
}
.art-tools { display: inline-flex; flex-wrap: wrap; gap: 0.45rem; }
.art-btn {
  min-height: 30px;
  border: 0;
  border-bottom: 1px solid var(--line);
  padding: 0 0 0.1rem;
  background: none;
  color: var(--muted-ink);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  cursor: pointer;
}
.art-btn:hover,
.art-btn:focus-visible { color: var(--ink); border-bottom-color: var(--ink); }

/* ------------------- readable sizes (default, no scripting) --------------- */

.art-film .art-media-film { background: #10161c; border-radius: var(--radius-media); width: 100%; }
.art-media-press { background: var(--surface); }
.doc-window {
  height: 100%;
  display: flex;
  justify-content: center;
  padding: clamp(9px, 1.2vw, 18px);
}
.doc-sheet {
  width: min(100%, 600px);
  height: max-content;
  padding: clamp(1rem, 2.2vw, 2rem);
  background: var(--white);
  border-radius: 3px;
  font-size: 0.86rem;
  line-height: 1.5;
}
.doc-sheet > * { margin: 0; }
.doc-sheet > * + * { margin-top: 0.8rem; }
.doc-sheet .rel-headline {
  font-size: clamp(1.05rem, 2vw, 1.6rem);
  line-height: 1.14;
  letter-spacing: -0.035em;
  font-weight: 720;
  text-wrap: balance;
}
.doc-sheet h3 { font-size: 0.95rem; line-height: 1.25; letter-spacing: -0.015em; font-weight: 720; }
.doc-sheet .rel-center { text-align: center; }
.doc-sheet .rel-justify { text-align: justify; }

.art-flyer .art-media-flyer { max-width: min(100%, 520px); }
.art-ads .art-pair,
.art-social .art-cluster { display: flex; flex-wrap: wrap; align-items: flex-start; gap: clamp(0.9rem, 1.8vw, 1.5rem); }
.art-ads .art-item { flex: 0 1 180px; }
.art-ads .art-media-ad { max-width: 180px; }
.art-social .art-item { flex: 0 1 190px; }
.art-mark .art-media-mark { max-width: min(100%, 260px); }

/* ------------------- composed tableau (wide screens, scripting on) -------- */

@media (min-width: 1001px) {
  html.js .board {
    --film-h: clamp(300px, 54dvh, 660px);
    /* The band's artifacts are all sized from this one value, so the pair, the
       cluster and the national mark are provably the same height and share the
       band's baseline rather than each deriving a height of their own. */
    --band-h: clamp(92px, 14.5dvh, 200px);
    height: 100dvh;
    min-height: 760px;
    overflow-y: auto;
  }
  /* The cue is chrome, not content: it keeps its own inset from the canvas edge
     so it never runs to the edge of the board at any width, and the bar sits a
     little tighter to buy the band its breathing room at the foot. */
  html.js .board-bar { padding-top: 7px; padding-right: clamp(12px, 1.4vw, 26px); }
  /* Two stacked columns: the eyebrow belongs to the headline rather than
     floating above it, the scope and the route read as one block of context, and
     the two columns share a top line. */
  html.js .board-head {
    display: grid;
    grid-template-columns: minmax(0, 1.12fr) minmax(0, 1fr);
    column-gap: clamp(1.5rem, 2.6vw, 3rem);
    align-items: start;
    padding-top: 9px;
  }
  html.js .board-title { font-size: clamp(1.4rem, 2.1vw, 2rem); margin-top: 0.3rem; max-width: 34ch; }
  html.js .board-scope { margin: 0; font-size: 0.9rem; }
  html.js .board-life .board-scope {
  max-width: 64ch;
  margin-top: 0.4rem;
  transform: none; /* Kill the translateY drop */
}
  html.js .board-route { margin-top: 0.5rem; gap: 0.3rem 1.05rem; }
  html.js .board-field {
    padding: clamp(16px, 1.8vw, 24px) 0 30px;
    min-height: 0;
    container-type: inline-size;
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    grid-template-rows: repeat(12, minmax(0, 1fr));
    gap: 12px;
    align-items: start;
  }

  html.js .art { display: flex; flex-direction: column; min-height: 0; }
  html.js .art-label,
  html.js .art-credit { font-size: 0.62rem; letter-spacing: 0.055em; }
  html.js .art-stage { flex: 1 1 auto; min-height: 0; }
  html.js .art-foot { flex: 0 0 auto; margin-top: 0.4rem; }
  /* One caption rail across the band and the two documents: a two-line label and
     a one-line label reserve the same height, so the artifacts above them share a
     top and a bottom edge instead of stepping. The film keeps its own foot, which
     carries its controls. */
  html.js .board .art:not(.art-film) .art-foot {
    min-height: 2rem;
    row-gap: 0.1rem;
    align-items: flex-start;
    align-content: flex-start;
  }

  /* The film: the anchor, held inside its own cell, never edge to edge. */
  html.js .art-film { grid-column: 1 / span 8; grid-row: 1 / span 9; align-self: stretch; }
  html.js .art-film .art-media-film {
    width: min(100%, calc(var(--film-h) * 1.7778));
    aspect-ratio: 16 / 9;
    flex: 0 1 auto;
    align-self: flex-start;
  }
  html.js .art-film .art-inspect {
  display: none;
  }
  
  
  /* The documents: press release above, business-facing collateral below. */
html.js .art-press {
  grid-column: 9 / span 4;
  grid-row: 1 / span 6;
  align-self: stretch;
  left: 0;
}

html.js .art-flyer {
  grid-column: 9 / span 4;
  grid-row: 7 / span 6;
  align-self: stretch;
  left: 0;
}

html.js .art-media-press {
  height: 100%;
  aspect-ratio: 7 / 10;
  width: auto;
  justify-self: start;
  margin-left: 0;
}

html.js .art-media-flyer {
  height: 100%;
  width: auto;
  max-width: 100%;
  margin-left: 0;
}



/* 1. Prevent the grid track from expanding to content size */
html.js .art-press {
  min-height: 0;
  overflow: hidden;
}

/* 2. Contain the preview window and clip excess document length */
html.js .art-media-press {
  overflow: hidden;
  position: relative;
}

.doc-window {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.doc-sheet {
  width: 100%;
  height: 100%;
  padding: 0.85rem 0.9rem;
  box-sizing: border-box;
  overflow: hidden;
  background: #ffffff;
}

/* 3. Scale headline & text down to document-sheet preview size */
.doc-sheet .rel-headline {
  font-size: 0.72rem !important;
  line-height: 1.25 !important;
  font-weight: 700 !important;
  margin: 0 0 0.45rem 0 !important;
  letter-spacing: -0.01em;
}

.doc-sheet p {
  font-size: 0.52rem !important;
  line-height: 1.35 !important;
  margin: 0 0 0.4rem 0 !important;
  color: #333333;
}

.doc-sheet h3 {
  font-size: 0.58rem !important;
  margin: 0.4rem 0 0.2rem 0 !important;
}




/* The film holds one composited layer from first paint. */
html.js .art-media-film {
  transform: translateZ(0);
  backface-visibility: hidden;
}


/* --------------------------------------------------------------------------
   SUPPORTING BAND
   One horizontal flex row across columns 1–8:
   paid creative → social → launch email → national brand context.
   Columns 9–12 remain exclusively for the flyer.
   -------------------------------------------------------------------------- */

html.js .art-rollout-band {
  grid-column: 1 / span 8;
  grid-row: 10 / span 3;

  display: flex;
  align-items: flex-start;
  gap: 12px;

  min-width: 0;
  padding: 0;

}

html.js .art-rollout-band > .art {
  grid-column: auto;
  grid-row: auto;
  min-width: 0;
}

/* Base default for 16:9 and ultrawide screens (no overlap) */
html.js .art-rollout-band {
  transform: translateY(-20px);
}

/* On standard 16:10 / squarer laptop screens: video shrinks, safely close the gap */
@media (max-aspect-ratio: 16/9) {
  html.js .art-rollout-band {
    transform: translateY(-20px);
  }
}

/* On even taller/compact viewports (e.g. tablet / 4:3 / tall windows) */
@media (max-aspect-ratio: 14/10) {
  html.js .art-rollout-band {
    transform: translateY(-36px);
  }
}

/* --------------------------------------------------------------------------
   PAID CREATIVE
   -------------------------------------------------------------------------- */

html.js .art-rollout-band .art-ads {
  flex: 0 1 20%;
}

html.js .art-rollout-band .art-ads .art-stage {
  display: flex;
  flex-direction: column;
}

html.js .art-rollout-band .art-ads .art-pair {
  flex: 1 1 auto;
  min-height: 0;

  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;

  gap: 0.7rem;
}

html.js .art-rollout-band .art-ads .art-item {
  flex: 0 0 auto;
  height: auto;
}

html.js .art-rollout-band .art-ads .art-media {
  flex: 0 0 auto;
  height: var(--band-h);
  width: auto;
  max-width: none;
}

html.js .art-rollout-band .art-ads .art-item:last-child {
  margin-top: 0.8rem;
}

html.js .art-rollout-band .art-ads .art-item:last-child .art-media {
  height: calc(var(--band-h) - 0.8rem);
}


/* --------------------------------------------------------------------------
   LOCAL SOCIAL ROLLOUT
   -------------------------------------------------------------------------- */

html.js .art-rollout-band .art-social {
  flex: 0 1 30%;
}

html.js .art-rollout-band .art-social .art-stage {
  display: flex;
  flex-direction: column;
}

html.js .art-rollout-band .art-social .art-cluster {
  flex: 1 1 auto;
  min-height: 0;

  display: flex;
  flex-wrap: nowrap;
  justify-content: flex-start;
  align-items: flex-start;

  gap: 9px;
}

html.js .art-rollout-band .art-social .art-item {
  flex: 0 0 auto;
  height: auto;
}

html.js .art-rollout-band .art-social .art-media {
  flex: 0 0 auto;
  height: calc(var(--band-h) * 0.76);
  width: auto;
  max-width: none;
}


/* --------------------------------------------------------------------------
   BUSINESS LAUNCH EMAIL
   -------------------------------------------------------------------------- */

html.js .art-rollout-band .art-email {
  flex: 1 1 35%;
  min-width: 0;
}

html.js .art-rollout-band .art-email .art-stage {
  width: 100%;
}

html.js .art-rollout-band .art-email .art-media-email {
  width: 100%;
  height: auto;
  aspect-ratio: 12 / 7;
}

html.js .art-rollout-band .art-email .art-media-email img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}


/* --------------------------------------------------------------------------
   NATIONAL BRAND CONTEXT
   -------------------------------------------------------------------------- */

html.js .art-rollout-band .art-mark {
  flex: 0 1 15%;
  min-width: 0;
  margin: 0;
  justify-content: flex-start;
}

html.js .art-rollout-band .art-mark .art-media-mark {
  width: 100%;
  height: auto;
  aspect-ratio: 1280 / 1600;
  margin: 0;
}

html.js .art-rollout-band .art-mark .art-foot {
  justify-content: flex-start;
  text-align: left;
}


/* --------------------------------------------------------------------------
   SUPPORTING CAPTIONS
   -------------------------------------------------------------------------- */

html.js .art-sub {
  display: none;
}

html.js .art-subs {
  display: block;
  font-size: 0.66rem;
  letter-spacing: 0.03em;
  color: var(--muted-ink);
}

/* Shrink the email card (06) */
.art-rollout-band .art-email {
  max-width: 260px; /* adjust down to whatever looks right (e.g. 200px - 240px) */
}

/* If you also want to shrink the water mark next to it (07) */
.art-rollout-band .art-mark {
  max-width: 115px; /* or clamp() */
}



/* ------------------- phone: its own composition --------------------------- */

@media (max-width: 1000px) {
  .board-head { padding-top: 1rem; }
  .board-title { font-size: clamp(1.45rem, 6.2vw, 2.1rem); }
  .board-scope { font-size: 1rem; }
  .board-field { gap: 1.7rem; padding-top: 1.2rem; }
  .board-route { gap: 0.25rem 0.95rem; font-size: 0.64rem; }

  .art-film .art-media-film { border-radius: clamp(10px, 2.6vw, 18px); }
  .art-film .art-foot { flex-direction: column; align-items: flex-start; }
  .art-film .art-tools { margin-top: 0.35rem; }

  .art-press .doc-window { height: auto; padding: 0; }
  .art-press .doc-sheet { width: 100%; border-radius: 6px; }
  .art-press .art-media-press { box-shadow: none; background: none; overflow: visible; }
  .art-press .art-media-press .doc-sheet { box-shadow: var(--art-edge), var(--art-lift); }
  /* One screenful of the release, not the whole document in the middle of the
     phone sequence; the inspector opens it complete. Without scripting the
     sheet is left whole, so the text is never out of reach. */
  html.js .art-press .doc-window {
    max-height: min(52dvh, 460px);
    overflow: hidden;
    border-radius: 6px;
    box-shadow: var(--art-edge), var(--art-lift), inset 0 -16px 14px -14px rgba(10, 18, 27, 0.24);
  }
  html.js .art-press .art-media-press .doc-sheet { box-shadow: none; }

  .art-ads .art-item { flex: 1 1 0; max-width: 46%; }
  /* Never past the size the ad was supplied at. */
  .art-ads .art-media-ad { max-width: 300px; }
  .art-social .art-cluster { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.15rem 0.85rem; }
  .art-social .art-item { flex: none; }
  .art-media { aspect-ratio: var(--ratio, auto); }
  .art-mark .art-media-mark { max-width: min(100%, 230px); }

  .art-btn { min-height: 44px; padding: 0.55rem 0.2rem; font-size: 0.74rem; }
  /* No hover to answer on a touch-first screen, and nine repeated badges would
     be noise: the documentary labels carry the information and the artifact
     itself is the tap target. */
  .art-open { cursor: pointer; }
  .art-inspect { display: none; }
}

.art-rollout-band {
  display: contents;
}

/* ------------------- the inspector: the whole real artifact --------------- */

.board-ix {
  margin: auto;
  padding: 0;
  border: 0;
  inset: 0;
  width: 100%;
  max-width: none;
  max-height: none;
  height: 100dvh;
  overflow: hidden;
  background: rgba(10, 18, 27, 0.76);
  color: var(--ink);
}
.board-ix::backdrop { background: transparent; }
.board-ix[open] { display: grid; place-items: center; padding: clamp(8px, 2vw, 30px); }
.ix-shell {
  display: flex;
  flex-direction: column;
  max-width: 100%;
  max-height: 100%;
  background: var(--paper);
  border-radius: clamp(8px, 1vw, 16px);
  box-shadow: 0 40px 90px -40px rgba(0, 0, 0, 0.7);
  overflow: hidden;
}
.ix-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 0.55rem 0.5rem 1rem;
  border-bottom: 1px solid var(--line);
}
.ix-label {
  margin: 0;
  font-size: 0.68rem;
  font-weight: 720;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-ink);
}
.ix-tools { display: inline-flex; align-items: center; gap: 0.5rem; flex: 0 0 auto; }
.ix-close,
.ix-sound {
  min-height: 40px;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.4rem 0.9rem;
  background: none;
  color: var(--ink);
  font-size: 0.78rem;
  font-weight: 720;
  cursor: pointer;
}
.ix-close:hover,
.ix-sound:hover { border-color: var(--ink); }
.ix-body {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  place-items: center;
  background: var(--surface);
  overflow: hidden;
}
/* Never clipped, whatever the shell's arithmetic works out to: the artifact
   is always contained by the frame it was given. */
.ix-body > img,
.ix-body > video {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  background: #10161c;
}
.ix-body > img { background: none; }


.board-ix[data-kind="document"] .ix-body {
  display: block;
  overflow: auto;
  padding: clamp(9px, 1.8vw, 26px);
}
.ix-sheet {
  width: min(100%, 640px);
  margin-inline: auto;
  padding: clamp(1rem, 3vw, 2.4rem);
  background: var(--white);
  border-radius: 3px;
  box-shadow: var(--art-edge), var(--art-lift);
  font-size: 0.95rem;
  line-height: 1.5;
}
.ix-sheet > * { margin: 0; }
.ix-sheet > * + * { margin-top: 0.85rem; }
.ix-sheet .rel-headline {
  font-size: clamp(1.15rem, 2.4vw, 1.8rem);
  line-height: 1.13;
  letter-spacing: -0.035em;
  font-weight: 720;
  text-wrap: balance;
}
.ix-sheet h3 { font-size: clamp(0.98rem, 1.5vw, 1.1rem); line-height: 1.25; font-weight: 720; }
.ix-sheet .rel-center { text-align: center; }
.ix-sheet .rel-justify { text-align: justify; }
.ix-note {
  margin: 0;
  padding: 0.55rem 1rem;
  border-top: 1px solid var(--line);
  font-size: 0.72rem;
  color: var(--muted-ink);
}

/* ------------------- assembly, contraction, reduced motion ---------------- */

@media (min-width: 1180px) {
  html.js .board .board-head,
  html.js .board .art {
    opacity: 1;
    transform: none;
    transition: opacity 300ms ease, transform 300ms ease;
  }
  /* The stagger lives on the settled state so the delay survives the flip out of
     the arming state. The film stays opaque: it is the element the view
     transition carries, so it has to exist in the incoming frame. */
  html.js .board .board-head { transition-delay: 0ms; }
  html.js .board .art-film { transition-delay: 40ms; }
  html.js .board .art-press { transition-delay: 100ms; }
  html.js .board .art-flyer { transition-delay: 160ms; }
  html.js .board .art-ads { transition-delay: 220ms; }
  html.js .board .art-social { transition-delay: 280ms; }
  html.js .board .art-mark { transition-delay: 340ms; }

  html.js .board[data-assembly="arming"] .board-head,
  html.js .board[data-assembly="arming"] .art:not(.art-film) {
    opacity: 0;
    transition: none;
  }
  html.js .board[data-assembly="arming"] .board-head,
  html.js .board[data-assembly="arming"] .art { transform: translateY(10px) scale(0.994); }

  html.js .board-shell.is-contracting .board {
    transform: scale(0.988);
    opacity: 0;
    transition: transform 260ms ease, opacity 260ms ease;
  }
}

@media (prefers-reduced-motion: reduce) {
  .board-head,
  .art,
  .art-media,
  .art-inspect,
  .board-back-mark { transition: none !important; }
  html.js .board[data-assembly] .board-head,
  html.js .board[data-assembly] .art { opacity: 1; transform: none; }
  html.js .board-shell.is-contracting .board { transform: none; opacity: 1; }
  html:not(.js) .art-film video { display: none; }
  html:not(.js) .art-media-film {
    background-image: var(--film-poster);
    background-position: center;
    background-size: cover;
  }
}

/* ------------------- the board as an overlay on the homepage -------------- */

html.board-open { overflow: hidden; }

/* The overlay is its own scroll container at every width. On a phone that is
   what lets a swipe move the board rather than the homepage locked behind it —
   the board has no height clamp of its own below the composed breakpoint, so the
   shell scrolls and ordinary vertical swiping is completely untouched. On a wide
   screen the board fills the shell exactly, so the shell itself never scrolls and
   the board's own overflow does the work. */
.board-shell {
  position: fixed;
  inset: 0;
  z-index: 60;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.board-shell[hidden] { display: none; }

/* Only the artifact inspector holds scrolling still. */
html.ix-open,
html.ix-open .board-shell,
html.ix-open .board { overflow: hidden; }

/* Progressive enhancement only: one element carries the film across the change,
   so the project the visitor selected is the element that arrives. The name is
   worn exactly once in each state. */
/* Nothing is named for a view transition: naming live media hands the browser a
   still frame of the film to cross-fade, which is the flicker this replaces. The
   board's own contraction moves the whole field, video included, and the film
   keeps playing through it. */

/* =========================================================================
   Evidence board: Lifecycle / Member Activation
   (site/work/member-activation.html)

   One board, one screen: the retention signal, then five stages at the scale
   their evidence earns. The rebrand board's own component (`.board`,
   `.board-field`, `.art*`, `.board-ix`, `board.js`) with its own field — a
   twelve-column wall where the guide is a ten-page deck, the dashboard is the
   widest working surface, the renewal cluster is the largest region on the
   board, and no two artifacts take the same width or break at the same edge.
   Scoped to `.board-life`, which the child page wears on its own body and the
   overlay carries on the wrapper around the imported board.
   ========================================================================= */

/* ---------- shared inside the board -------------------------------------- */

/* Every artifact is a column: the stage takes the room, the caption keeps its
   own, and nothing overflows the cell it was placed in. */
.board-life .art { display: flex; flex-direction: column; }
.board-life .art-stage { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

.board-life .life-strong { margin: 0; font-size: 0.78rem; line-height: 1.25; font-weight: 720; letter-spacing: -0.012em; color: var(--ink); }
.board-life .life-note { margin: 0.12rem 0 0.24rem; font-size: 0.7rem; line-height: 1.35; color: var(--copy); }
.board-life .life-sheet-foot { margin: 0.24rem 0 0; font-size: 0.7rem; letter-spacing: 0.02em; color: var(--muted-ink); }
.board-life .art-foot { margin-top: 0.5rem; row-gap: 0.05rem; }
.board-life .art-inspect { font-size: 0.7rem; padding: 0.24rem 0.6rem; }
/* The board's own labels read at the same size as everything else on it. */
html.js .board-life .art-label { font-size: 0.7rem; }
html.js .board-life .art-btn { font-size: 0.7rem; }
.board-life .art-media { box-shadow: var(--art-edge), var(--art-lift); }

/* ---------- the signal --------------------------------------------------- */

.board-life .signal-value {
  margin: 0;
  font-size: clamp(1.9rem, 2.5vw, 2.5rem);
  line-height: 0.92;
  letter-spacing: -0.05em;
  font-weight: 720;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.board-life .signal-unit { font-size: 0.46em; letter-spacing: -0.01em; }
.board-life .signal-word { margin: 0.1rem 0 0; font-size: 0.82rem; font-weight: 720; color: var(--ink); }
.board-life .signal-span { margin: 0.18rem 0 0; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.11em; text-transform: uppercase; color: var(--muted-ink); }

/* The three-bar comparison lives inside the signal rather than beside it as a
   second, separately captioned chart. */
.board-life .signal-bars { display: grid; gap: 0.32rem; margin: 0.55rem 0 0; padding: 0; list-style: none; }
.board-life .signal-bars li { display: grid; grid-template-columns: 2.7rem 1fr 2.6rem; align-items: center; gap: 0.4rem; }
.board-life .signal-key { font-size: 0.7rem; font-weight: 720; color: var(--ink); }
.board-life .signal-track { height: 7px; border-radius: 4px; background: rgba(10, 18, 27, 0.12); overflow: hidden; }
.board-life .signal-fill { display: block; width: var(--v, 0); height: 100%; border-radius: 4px; background: #0a6ea8; }
.board-life .signal-val { font-size: 0.7rem; font-weight: 720; text-align: right; font-variant-numeric: tabular-nums; color: var(--ink); }
.board-life .signal-delta { margin: 0.42rem 0 0; font-size: 0.7rem; line-height: 1.3; color: var(--copy); }

/* ---------- the guide deck ----------------------------------------------- */

.board-life .guide-stack { position: relative; flex: 1 1 auto; min-height: 0; }
/* The deck is stacked above its neighbours by its own z-order, so the control
   that opens the guide has to sit above the deck: otherwise the ten sheets take
   the click and the viewer never opens. */
.board-life .art-guide .art-open { z-index: 40; }
.board-life .guide-page {
  position: absolute;
  margin: 0;
  height: calc(100% - 22px);
  width: auto;
  aspect-ratio: 1000 / 1294;
  border-radius: 3px;
  overflow: hidden;
  background: var(--white);
  box-shadow: var(--art-edge), 0 16px 28px -22px rgba(10, 18, 27, 0.6);
  transition: transform 240ms ease;
}
.board-life .guide-page img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: left top; }
/* The page number sits on the exposed edge of each sheet: the count is legible
   even where the page itself is not. */
.board-life .guide-page::after {
  content: attr(data-page);
  position: absolute;
  top: 4px;
  right: 3px;
  padding: 0.02rem 0.14rem;
  border-radius: 3px;
  background: rgba(245, 244, 240, 0.94);
  color: var(--ink);
  font-size: 0.68rem;
  font-weight: 760;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
}

/* ---------- the renewal cluster ------------------------------------------ */

.board-life .life-cluster {
  display: grid;
  flex: 1 1 auto;
  min-height: 0;
  padding: 8px 9px 7px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.5);
}
.board-life .life-panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 0.55rem 0.7rem 0.6rem;
  background: var(--white);
  border-radius: 5px;
  box-shadow: var(--art-edge), 0 14px 26px -24px rgba(10, 18, 27, 0.55);
}
.board-life .life-panel-label {
  margin: 0 0 0.42rem;
  padding-bottom: 0.3rem;
  border-bottom: 2px solid var(--ink);
  font-size: 0.7rem;
  font-weight: 760;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
}
.board-life .life-checks, .board-life .life-rows, .board-life .life-notices {
  display: grid;
  gap: 0.34rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.board-life .life-checks { gap: 0.4rem; }
.board-life .life-check { margin: 0; font-size: 0.72rem; font-weight: 720; line-height: 1.2; color: var(--ink); }
.board-life .life-answer { margin: 0.06rem 0 0; padding-left: 0.42rem; border-left: 1px solid var(--line); font-size: 0.7rem; line-height: 1.25; color: var(--copy); }
.board-life .life-rows li { padding-top: 0.3rem; border-top: 1px solid var(--line); }
.board-life .life-rows li:first-child { padding-top: 0; border-top: 0; }
.board-life .life-row-stage { display: block; font-size: 0.72rem; font-weight: 720; color: var(--ink); }
.board-life .life-row-fields { display: block; margin-top: 0.1rem; font-size: 0.7rem; line-height: 1.3; color: var(--copy); }
.board-life .life-notices li { display: grid; grid-template-columns: 1.1rem 1fr; gap: 0.34rem; align-items: start; }
.board-life .life-notice-step { font-size: 0.7rem; font-weight: 760; color: #0a6ea8; padding-top: 0.1rem; font-variant-numeric: tabular-nums; }
.board-life .life-notice-body { font-size: 0.7rem; line-height: 1.3; color: var(--copy); }
.board-life .life-notice-body b { display: block; font-size: 0.7rem; font-weight: 720; color: var(--ink); }
.board-life .life-notice-last .life-notice-body b { color: var(--ink); }
.board-life .life-notice { position: relative; }
.board-life .life-notice:not(.life-notice-last)::after {
  content: "";
  position: absolute;
  left: 0.32rem;
  top: 0.95rem;
  bottom: -0.34rem;
  width: 1px;
  background: var(--line);
}
.board-life .life-spine {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 0.5rem;
  margin: 0.55rem 0 0;
  padding-top: 0.45rem;
  border-top: 1px solid var(--line);
  font-size: 0.7rem;
  font-weight: 760;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink);
}
.board-life .life-spine span + span::before { content: "\2192"; margin-right: 0.5rem; color: #0a6ea8; }

/* ---------- the voices --------------------------------------------------- */

.board-life .voice-cards { display: grid; flex: 1 1 auto; min-height: 0; }
.board-life .voice-card {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0.6rem 0.7rem 0.55rem;
  background: var(--white);
  border-radius: 5px;
  box-shadow: var(--art-edge), 0 14px 26px -24px rgba(10, 18, 27, 0.55);
}
.board-life .voice-lead { border-top: 3px solid #0a6ea8; }
.board-life .voice-quote { margin: 0; }
.board-life .voice-quote p { margin: 0; font-size: 0.7rem; line-height: 1.38; color: var(--ink); }
.board-life .voice-lead .voice-quote p { font-size: 0.76rem; line-height: 1.4; }
.board-life .voice-who { margin: auto 0 0; padding-top: 0.4rem; font-size: 0.7rem; line-height: 1.3; color: var(--copy); }
.board-life .voice-who b { color: var(--ink); font-weight: 720; }
.board-life .voice-who span { color: var(--muted-ink); }

/* ---------- the release sheets: inspector-only with scripting on --------- */

.board-life .life-release { display: grid; gap: 1.5rem; }
html.js .board-life .life-release { display: none; }
.board-life .life-release h3 { margin: 0 0 0.3rem; font-size: 0.95rem; font-weight: 720; color: var(--ink); }
.board-life .life-release p { margin: 0; font-size: 0.8rem; line-height: 1.45; color: var(--copy); }
.board-life .life-release ul, .board-life .life-release ol { margin: 0.4rem 0 0; padding-left: 1.1rem; }
.board-life .life-release li { font-size: 0.8rem; line-height: 1.45; color: var(--copy); }
.board-life .life-release li + li { margin-top: 0.3rem; }
.board-life .life-release b { color: var(--ink); }
.board-life .life-release table { width: 100%; margin: 0.5rem 0 0; border-collapse: collapse; font-size: 0.78rem; }
.board-life .life-release th, .board-life .life-release td { padding: 0.3rem 0.5rem 0.3rem 0; text-align: left; border-bottom: 1px solid var(--line); color: var(--copy); }
.board-life .life-release th { font-size: 0.6rem; font-weight: 760; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted-ink); }
.board-life .life-release-note { font-size: 0.72rem; color: var(--muted-ink); }
.board-life .life-quote { margin: 0; }
.board-life .life-quote p { margin: 0; font-size: 0.9rem; line-height: 1.45; color: var(--ink); }
.board-life .life-quote-lead p { font-size: 1rem; }
.board-life .life-quote cite { display: block; margin-top: 0.4rem; font-size: 0.74rem; font-style: normal; line-height: 1.35; color: var(--muted-ink); }
.board-life .life-statement { margin: 0; }

/* ---------- desktop: the wall, one screen -------------------------------- */

@media (min-width: 1001px) {
  /* Exactly the browser's height: the board is the experience, and the only
     thing below it is one line and the site's own foot. */
  html.js .board-life .board { height: 100dvh; min-height: 700px; overflow-y: auto; }
  html.js .board-life .board-head {
  padding-top: clamp(8px, 1.2vh, 16px);
  margin-bottom: clamp(0.5rem, 1vh, 1rem); /* Positive margin: no overlapping */
}
html.js .art-film .art-stage {
  flex: 0 0 auto;
}
  html.js .board-life .board-statement {
  grid-column: 1 / -1;
}

  html.js .board-life .board-title {
  max-width: none;
}
  html.js .board-life .board-field {
    flex: 1 1 auto;
    min-height: 0;
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    grid-template-rows: repeat(12, minmax(0, 1fr));
    column-gap: 12px;
    row-gap: 10px;
    /* Artifacts take the height of the cell they were given, so every stage is
       built from its row span and nothing overruns the row below. */
    align-items: stretch;
    padding: 2px 0 12px;
  }

  /* Width by evidence, not by stage: two columns for the signal, five for the
     guide, five for the dashboard, then three, six and three underneath, with
     the renewal cluster sitting in the widest region of the board. The signal
     needs four rows rather than six now that the comparison is part of it, and
     the email spends those two rows on being an email you can read. */
  html.js .board-life .art-signal { grid-column: 1 / span 2; grid-row: 1 / span 4; }
  html.js .board-life .art-guide { grid-column: 3 / span 5; grid-row: 1 / span 5; }
  html.js .board-life .art-run { grid-column: 8 / span 5; grid-row: 1 / span 6; }
  html.js .board-life .art-email { grid-column: 1 / span 3; grid-row: 6 / span 7; }
  html.js .board-life .art-support { grid-column: 4 / span 5; grid-row: 7 / span 6; }
  html.js .board-life .art-voices { grid-column: 9 / span 4; grid-row: 7 / span 6; }

  /* the signal: the number, then the comparison inside the same treatment */
  html.js .board-life .art-signal .art-stage { gap: 0; justify-content: flex-start; }
  html.js .board-life .art-signal .signal-bars { margin-top: auto; }

  /* the guide: ten sheets, one deck, stepping right and a touch down */
  html.js .board-life .guide-page {
  left: calc(8% + (var(--i) - 1) * 7.2%);
  top: calc(var(--i) * 1.6px);
  z-index: calc(30 - var(--i));
  transform: rotate(calc(var(--i) * 0.16deg));
  transform-origin: 50% 100%;
}

html.js .board-life .guide-page:first-child {
  left: 0;
}
  /* Hover or focus lifts and spreads the deck a little. It cannot step further
     right than the cell it was given, so the separation is a fan, not a slide. */
  html.js .board-life .art-guide .art-stage:hover .guide-page,
  html.js .board-life .art-guide .art-stage:focus-within .guide-page {
    transform: rotate(calc(0.5deg + var(--i) * 0.3deg)) translateY(calc(var(--i) * -1.1px));
  }

  /* the dashboard: nothing sits on its face. The second crop of the tiles below
     the fold is one control away, in the caption, so the resting state shows the
     dashboard and only the dashboard. */
  html.js .board-life .art-run .art-stage { position: relative; }
  html.js .board-life .art-media-run { width: 100%; }

  /* the email sits on the line of its own caption */
  html.js .board-life .art-email .art-stage { justify-content: flex-end; align-items: flex-start; }
  html.js .board-life .art-media-email { width: min(100%, 320px); }

  /* the renewal cluster: the call's checks, what the call records, and what
     happens when the account runs late — one region, three linked panels */
  html.js .board-life .life-cluster { grid-template-columns: 1.34fr 0.94fr 1.12fr; grid-template-rows: 1fr auto; gap: 10px; }
  html.js .board-life .life-flow .life-checks { gap: 0.3rem; justify-content: space-between; flex: 1 1 auto; }
  html.js .board-life .life-notices { gap: 0.34rem; }

  /* the voices: Beth Sullivan is the reading, the other two are the corroboration.
     Different widths, different edges, set against each other rather than three
     stacked boxes of the same size. */
  html.js .board-life .voice-cards { display: block; }
  /* The quotes are layered over each other; the region's transparent inspect
     overlay still has to be the topmost thing a click can land on. */
  html.js .board-life .art-voices .art-open { z-index: 6; }
  html.js .board-life .voice-card { padding: 0.45rem 0.6rem 0.45rem; }
  html.js .board-life .voice-lead {
    width: 100%;
    position: relative;
    z-index: 3;
    box-shadow: var(--art-edge), 0 18px 30px -22px rgba(10, 18, 27, 0.66);
  }
  html.js .board-life .voice-lead .voice-quote p { font-size: 0.78rem; line-height: 1.4; }
  html.js .board-life .voice-quote p { font-size: 0.7rem; line-height: 1.34; }
  html.js .board-life .voice-who { font-size: 0.7rem; padding-top: 0.28rem; }
html.js .board-life .voice-barber,
html.js .board-life .voice-heel {
  width: 94%;
  position: relative;
  transform: none;
}

html.js .board-life .voice-barber {
  margin: -0.05rem 0 0 auto;
  z-index: 2;
}

html.js .board-life .voice-heel {
  margin: -0.05rem auto 0 0;
  z-index: 1;
}

  /* Assembly: the rebrand board's 660ms beat, in four steps of delay rather
     than one per artifact. */
  html.js .board-life .board-head,
  html.js .board-life .board-field .art {
    opacity: 1;
    transform: none;
    transition: opacity 320ms ease, transform 320ms ease;
    transition-delay: var(--life-d, 0ms);
  }
  html.js .board-life .board[data-assembly="arming"] .board-head,
  html.js .board-life .board[data-assembly="arming"] .board-field .art {
    opacity: 0;
    transform: translateY(10px) scale(0.994);
    transition: none;
  }
}

/* ---------- narrow: the same board, read down the page ------------------- */

@media (max-width: 1179px) {
  .board-life .board { height: auto; }
  html.js .board-life .board-field { display: grid; grid-template-columns: 1fr; gap: 2.1rem; padding: 4px 0 1rem; }
  html.js .board-life .art { min-height: 0; }

  /* the signal keeps its shape: the same three bars, read at phone width */
  .board-life .signal-bars { margin-top: 0.7rem; }

  /* the deck keeps its breadth: the cover leads and the rest follow it in an
     overlapping rail, each sheet showing its own edge and page number */
  .board-life .guide-stack {
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    gap: 0;
    padding-bottom: 6px;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
  }
  .board-life .guide-page {
    position: relative;
    z-index: calc(30 - var(--i));
    flex: 0 0 auto;
    width: min(62%, 245px);
    height: auto;
    scroll-snap-align: start;
  }
  .board-life .guide-page img { height: auto; object-fit: contain; }
  .board-life .guide-page::after { right: auto; left: 4px; }
  .board-life .guide-page + .guide-page { margin-left: calc(min(62%, 245px) * -0.36); }

  /* the dashboard stays the widest thing on the board, the tiles below it */
  .board-life .art-run .art-stage { display: flex; flex-direction: column; gap: 0.7rem; }
  .board-life .art-media-run { width: 100%; }

  /* renewal stays one cluster: the three panels in order, the spine under them */
  .board-life .life-cluster { display: grid; grid-template-columns: 1fr; gap: 0.55rem; }
  .board-life .life-panel { padding: 0.7rem 0.8rem 0.75rem; }
  .board-life .life-check { font-size: 0.78rem; }
  .board-life .life-answer { font-size: 0.7rem; }
  .board-life .life-row-stage { font-size: 0.76rem; }
  .board-life .life-row-fields { font-size: 0.68rem; }
  .board-life .life-notice-body { font-size: 0.68rem; }
  .board-life .life-notice-body b { font-size: 0.74rem; }
  .board-life .life-spine { margin-top: 0.7rem; font-size: 0.72rem; }
  .board-life .life-notice:not(.life-notice-last)::after { bottom: -0.5rem; }

  /* all three statements, one card after another */
  .board-life .voice-cards { display: grid; grid-template-columns: 1fr; gap: 0.7rem; }
  .board-life .voice-card { padding: 0.8rem 0.85rem 0.7rem; transform: none; margin-top: 0; }
  .board-life .voice-quote p, .board-life .voice-lead .voice-quote p { font-size: 0.84rem; line-height: 1.42; }
  html.js .board-life .voice-card { padding: 0.55rem 0.7rem 0.5rem; }
  .board-life .voice-who { font-size: 0.68rem; }

  /* the release sheets stay in the flow with scripting off */
  .board-life .life-release { gap: 1.2rem; }
  .board-life .life-release p, .board-life .life-release li { font-size: 0.86rem; }
  .board-life .life-release table { font-size: 0.82rem; }
  .board-close-line { width: calc(100% - 32px); }
}

/* With scripting off the walkthrough's control does nothing, so it is not
   shown. */
html:not(.js) .board-life .art-tools { display: none; }

/* ---------- a short desktop window: two equal rows instead of 12 squished ones --------- */
@media (min-width: 1180px) and (max-height: 820px) {
  html.js .board-life .board {
    height: auto;
    min-height: 100dvh;
    overflow-y: auto;
  }
  
  html.js .board-life .board-field {
    grid-template-rows: auto;
    row-gap: 16px;
  }

  html.js .board-life .art-signal { grid-column: 1 / span 3; grid-row: 1; }
  html.js .board-life .art-guide  { grid-column: 4 / span 4; grid-row: 1; }
  html.js .board-life .art-run    { grid-column: 8 / span 5; grid-row: 1; }
  html.js .board-life .art-email  { grid-column: 1 / span 3; grid-row: 2; }
  html.js .board-life .art-support{ grid-column: 4 / span 5; grid-row: 2; }
  html.js .board-life .art-voices { grid-column: 9 / span 4; grid-row: 2; }
}

/* ---------- the page viewer (shared inspector, `pages` kind) ------------- */

.board-ix[data-kind="pages"] .ix-body { display: block; overflow: hidden; padding: 0; }
.ix-pages { display: flex; flex-direction: column; width: 100%; height: 100%; min-height: 0; }
/* A flex frame, not a grid one: a grid row sized by its content gives the page
   an indefinite height to measure against, and a taller page then runs past the
   bottom of the viewer instead of being contained by it. */
.ix-page { flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; padding: 0 clamp(6px, 1.4vw, 14px); }
.ix-page img { display: block; width: auto; height: auto; max-width: 100%; max-height: 100%; object-fit: contain; background: none; box-shadow: var(--art-edge), var(--art-lift); border-radius: 3px; }
.ix-pager {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(0.7rem, 2vw, 1.4rem);
  padding: 0.5rem 0.9rem;
  border-top: 1px solid var(--line);
  background: var(--surface);
}
.ix-step {
  min-height: 34px;
  border: 0;
  border-bottom: 1px solid var(--line);
  padding: 0 0 0.1rem;
  background: none;
  color: var(--ink);
  font-size: 0.72rem;
  font-weight: 720;
  letter-spacing: 0.06em;
  cursor: pointer;
}
.ix-step:hover, .ix-step:focus-visible { border-bottom-color: var(--ink); }
.ix-step[disabled] { color: var(--muted); cursor: default; border-bottom-color: transparent; }
.ix-count { margin: 0; font-size: 0.72rem; font-weight: 720; letter-spacing: 0.1em; color: var(--muted-ink); font-variant-numeric: tabular-nums; }


/* =========================================================================
   Evidence board: Partnerships / Revenue Development
   (site/work/partnerships.html)

   The rebrand board's own component (`.board`, `.board-bar`, `.board-head`,
   `.board-field`, `.art*`, `.board-ix`, `board.js`) with its own canvas: the
   packet is the largest artifact and holds the left of the field, the year's
   collected results sit over the title sponsor's photograph in the middle, and
   the two returns the same partnership system produced — public value, then the
   advertiser's own performance — hold the right. One header, one field, one
   reading path, and the whole argument inside the board's first desktop view.

   Scoped to `.board-partner`, which travels on the board element itself. The
   overlay imports that element whole, so the composition arrives with the
   markup and the homepage trigger declares no scope class; the child page's own
   board wears the same class, so both routes show the same canvas.
   ========================================================================= */

/* ---------- shared inside the board -------------------------------------- */

/* These captions are sentences, so each takes its own line under its label
   rather than running on beside it. The board's own wrapping caption rail does
   the work; `flex-basis: 100%` is the only thing added to it. */
.board-partner .art-foot p { flex: 1 0 100%; margin: 0; }
.board-partner .partner-note { font-size: 0.7rem; line-height: 1.35; color: var(--copy); }
/* The one figure in the field that is a result rather than a total: it is given
   the weight a result earns, and left well below the year's totals opposite. */
.board-partner .partner-result {
  font-size: 0.76rem;
  line-height: 1.3;
  font-weight: 720;
  letter-spacing: -0.01em;
  color: var(--ink);
}

/* The field reads as three vertical runs rather than as a row of cards: the
   offer, then the results and the sponsor behind them, then the two returns.
   Grouping them this way is also what keeps the phone sequence in one order —
   offer, results, sponsor, public value, partner value, then the role. */
.board-partner .partner-col { display: flex; flex-direction: column; gap: 2.2rem; min-width: 0; }

/* A plate or a column head carries its label above it, ruled the same way the
   year's plate is; a photograph carries its label in the rail under the picture.
   Two heads, two ruled labels, two labelled photographs: the board's own rhythm
   rather than four arrangements of the same thing. */
.board-partner .art-label-head {
  flex: 0 0 auto;
  margin: 0 0 0.62rem;
  padding-bottom: 0.34rem;
  border-bottom: 2px solid var(--ink);
}

/* ---------- 01 the offer: three of the packet's pages -------------------- */

/* Without scripting, and at every phone width, the pages keep their breadth in
   an overlapping rail — the only thing on this board allowed to scroll
   sideways, so nothing overflows the page and no page is reduced to a
   thumbnail. */
.board-partner .offer-stack {
  position: relative;
  display: flex;
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 6px;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.board-partner .offer-stack::-webkit-scrollbar { display: none; }
/* Five of the packet's eight pages are carried in the markup and never drawn:
   they are what the packet's own control opens in the page viewer, in packet
   order, so the viewer's count is the packet's own pagination. */
.board-partner .offer-rest { display: none; }
/* The stack is layered, so the control that opens the packet has to sit above
   every sheet: otherwise the pages take the click and the viewer never opens. */
.board-partner .art-offer .art-open { z-index: 40; }
.board-partner .offer-page {
  position: relative;
  flex: 0 0 auto;
  width: min(66%, 250px);
  margin: 0 0 0 calc(min(66%, 250px) * -0.26);
  aspect-ratio: 791 / 1024;
  border-radius: 3px;
  overflow: hidden;
  background: var(--white);
  box-shadow: var(--art-edge), 0 18px 32px -24px rgba(10, 18, 27, 0.6);
  scroll-snap-align: start;
}
.board-partner .offer-page img { display: block; width: 100%; height: 100%; object-fit: contain; }
/* The unrendered pages sit between the three drawn ones, so the rail's overlap
   cannot ride on an adjacent-sibling selector: every sheet after the first
   carries it. */
.board-partner .offer-page:first-of-type { margin-left: 0; }
/* No page badge is drawn on the sheets. A numbered tab on each edge turns a
   stack of paper into a carousel indicator, and the stack is not a carousel: the
   sheets are named in the artifact's own label and caption instead, and the
   packet's other pages are one control away in the inspector. */

/* ---------- 02 the year's collected results ------------------------------ */

/* One plate, not three cards: a heading, one rule, and three figures under it,
   so the totals read as an annotation on the program rather than as a row of
   dashboard tiles. The plate is headed this way because a data plate needs its
   own heading; the photographs keep their labels in the caption rail under them
   instead, so no label is ever set over a picture. */
.board-partner .annual-plate { margin: 0; }

.board-partner .annual-label {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  margin: 0 0 0.62rem;
  padding-bottom: 0.34rem;
  border-bottom: 2px solid var(--ink);
  font-size: 0.72rem;
  font-weight: 760;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink);
}

.board-partner .annual-rows { margin: 0; display: grid; gap: 0.72rem; }
.board-partner .annual-row { margin: 0; }
.board-partner .annual-row dt {
  margin: 0;
  font-size: clamp(1.1rem, 1.45vw, 1.4rem);
  line-height: 1.05;
  font-weight: 720;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.board-partner .annual-row:first-child dt { font-size: clamp(1.35rem, 1.95vw, 1.78rem); }
.board-partner .annual-row dd { margin: 0.1rem 0 0; max-width: 34ch; font-size: 0.73rem; line-height: 1.3; color: var(--copy); }
.board-partner .annual-source { margin: 0.62rem 0 0; max-width: 34ch; font-size: 0.7rem; line-height: 1.35; color: var(--muted-ink); }

/* ---------- 04 the public value group ------------------------------------ */

/* Label, figure, the basis the figure is made of, then the sentence the figure
   supports: the group's own hierarchy, in that order and at those four scales. */
.board-partner .value-note { flex: 1 1 auto; min-width: 0; }
.board-partner .value-label { margin: 0 0 0.5rem; }
.board-partner .value-figure {
  margin: 0;
  font-size: clamp(1.3rem, 1.8vw, 1.68rem);
  line-height: 1.06;
  font-weight: 720;
  letter-spacing: -0.038em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.board-partner .value-basis { margin: 0.34rem 0 0; max-width: 30ch; font-size: 0.74rem; line-height: 1.3; color: var(--copy); }
.board-partner .value-why { margin: 0.6rem 0 0; max-width: 34ch; font-size: 0.68rem; line-height: 1.38; color: var(--muted-ink); }

/* ---------- the packet's control ----------------------------------------- */

/* A quiet underlined control in the board's own caption type: the stretched
   overlay opens the packet from the picture itself, and this is the same control
   said out loud, so the affordance never depends on hovering. */
.board-partner .art-btn-strong {
  min-height: 30px;
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 760;
  color: var(--ink);
}
.board-partner .art-btn-strong:hover,
.board-partner .art-btn-strong:focus-visible { border-color: var(--ink); }

/* ---------- 03 the title sponsor's photograph ---------------------------- */

/* The crop is the display crop and nothing else: the frame is shown through a
   window the height of the golfers and their sign, which is what takes the
   empty sky out of the composition. The supplied file is unmodified, and the
   inspector opens the complete frame. This is the smallest picture on the board
   and it keeps to 92% of its run, so the year's figures above it stay the larger
   statement on that side. */
.board-partner .art-media-invest { width: 92%; }
.board-partner .art-media-invest img { object-fit: cover; object-position: 50% 90%; }

/* ---------- the role, as a footer on the field --------------------------- */

.board-partner .partner-role {
  margin: 0;
  padding-top: 0.75rem;
  border-top: 1px solid var(--line);
  font-size: 0.76rem;
  line-height: 1.4;
  letter-spacing: 0.01em;
  color: var(--muted-ink);
}

/* ---------- desktop: one canvas, one view -------------------------------- */

@media (min-width: 1001px) {
  /* The board is exactly the browser's height, so the whole argument is in the
     first view and the only thing under it is the field's own foot. */
  html.js .board-partner { height: 100dvh; min-height: 620px; overflow-y: auto; }
  /* The introduction is one block on the page's left margin — kicker, headline,
     scope — so the board's own rule that parks the scope in a second column is
     released here and nothing sits beside the headline. Every value that would
     add height is held to the smallest one that still reads, because the field
     underneath needs the room. */
  html.js .board-partner .board-head { display: block; padding-top: 2px; margin-bottom: 0; }
  html.js .board-partner .board-title { max-width: 32ch; }
  html.js .board-partner .board-scope {
    max-width: 58ch;
    margin-top: clamp(0.45rem, 0.9vh, 0.85rem);
  }

  html.js .board-partner .board-field {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    /* Two rows, each as tall as its own content: the composition, then the
       role. The rebrand board's twelve equal rows are what the other two
       boards need and are explicitly released here. */
    grid-template-rows: auto auto;
    column-gap: 12px;
    row-gap: clamp(0.75rem, 2.2vh, 2.25rem);
    /* The three runs share a top edge and a bottom edge and the field's free
       height is spent between the composition and the role line, so the footer
       closes the field at its own foot. */
    align-items: stretch;
    align-content: center;
    padding: 2px 0 12px;
  }

  /* Width by evidence: the packet is the largest artifact and takes four of the
     twelve columns; the title sponsor's photograph is the smallest picture on
     the board and takes three; the public value photograph is the largest and
     gets the five that are left. Those three widths are also what lets the runs
     finish on one baseline without any of them being stretched to pad it. */
  html.js .board-partner .partner-col-offer { grid-column: 1 / span 4; }
  html.js .board-partner .partner-col-scale { grid-column: 5 / span 3; }
  html.js .board-partner .partner-col-value { grid-column: 8 / span 5; }
  html.js .board-partner .partner-role { grid-column: 1 / -1; align-self: end; }

  /* Each run keeps its own vertical rhythm rather than being packed at its top:
     a run's two artifacts sit at the head and the foot of the column, so the
     three columns finish on one baseline and the air that separates a result
     from the photograph under it is the same air that separates the composition
     from the role. No rule is drawn between them: a line hung in a gutter reads
     as a table border, and the alignment is doing the work. */
  html.js .board-partner .partner-col { justify-content: space-between; }

  /* Every artifact is a column: the stage takes the room, the caption keeps its
     own, and nothing overruns the run it was placed in. */
  html.js .board-partner .art-stage { display: flex; flex-direction: column; min-height: 0; }
  html.js .board-partner .art { flex: 0 0 auto; }
  /* The offer is the one artifact that may take its run's leftover height, so its
     caption still lands on the baseline the taller runs set. */
  html.js .board-partner .art-offer { flex: 1 1 auto; }

  /* The public value group: the audience photograph is the principal image, and
     the reach figure sits under it in the space to the left of the presentation
     frame. The frame itself is set into the audience photograph's lower-right
     edge, so the two pictures and the figure they stand for read as one end to
     the argument rather than as two more numbered sections. The overlap is a live
     flex item carrying a negative top margin rather than an absolutely positioned
     one — which is also what keeps the text and the picture in one row: flex items
     cannot sit on each other, so the figure can never run under the frame at any
     desktop width. */
  html.js .board-partner .value-row { display: flex; align-items: flex-start; gap: 0 1.15rem; }
  html.js .board-partner .art-item-presenting {
    position: relative;
    z-index: 2;
    flex: 0 0 auto;
    width: 54%;
    margin-top: -12%;
  }

  /* The offer: the sheets are laid on the field the way paper is laid on a desk,
     each stepping across from the cover, their top and bottom edges level. The
     stack's height is what sets a sheet's width — 81% of the column — so the three
     sheets and the two 7.5% steps together take 96% of the column, and the
     remaining 4% is the gutter that keeps the packet clear of the year's figures
     in the next column at every desktop width. The strip each sheet keeps showing
     is its own right-hand margin rather than a slice through the page's footer. */
  html.js .board-partner .offer-stack {
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1.0486;
    overflow: visible;
    padding-bottom: 0;
    scroll-snap-type: none;
  }
  html.js .board-partner .offer-page {
    position: absolute;
    margin-left: 0;
    width: auto;
    height: 100%;
    left: calc(var(--i) * 7.5%);
    top: 0;
    z-index: calc(6 - var(--i));
    transition: transform 240ms ease;
  }
  html.js .board-partner .offer-page + .offer-page { margin-left: 0; }
  /* Hover or focus draws the stack apart by a breath. It cannot step past the
     column, so the separation is that and no more. */
  html.js .board-partner .art-offer .art-stage:hover .offer-page,
  html.js .board-partner .art-offer .art-stage:focus-within .offer-page {
    transform: translateY(calc(var(--i) * -2px));
  }

  /* Entrance: the rebrand board's 660ms beat, in four steps of delay rather than
     one per artifact, so the field gathers instead of marching. */
  html.js .board-partner .board-head,
  html.js .board-partner .board-field .art {
    transition-delay: var(--partner-d, 0ms);
  }
  html.js .board-partner[data-assembly="arming"] .board-head,
  html.js .board-partner[data-assembly="arming"] .board-field .art { transition: none; }
}

/* ---------- narrow: the same board, read down the page ------------------- */

@media (max-width: 1000px) {
  /* The field becomes a deliberate vertical evidence sequence in the order the
     markup already holds: the packet, the year's figures, the title sponsor's
     investment, public value, the advertiser's return, then the role. */
  .board-partner .annual-row dt { font-size: 1.5rem; }
  .board-partner .annual-row:first-child dt { font-size: 1.78rem; }
  .board-partner .annual-row dd { font-size: 0.79rem; max-width: 40ch; }
  .board-partner .partner-role { font-size: 0.76rem; }
  .board-partner .partner-col { gap: 2.4rem; }
  /* On a phone the group's parts simply follow one another: the figure, then the
     second frame. The overlap is a desktop composition, and a touch screen has no
     second chance at a picture something else is sitting on. */
  .board-partner .value-row { display: block; }
  .board-partner .art-item-presenting { width: 100%; margin: 1.2rem 0 0; }
  .board-partner .value-figure { font-size: 1.5rem; }

}

/* ---------- a short desktop window: the same board, one size down --------- */

/* The composition is measured against the column widths, so a wide, short window
   is the one case that runs out of height before it runs out of width — a
   1366 x 768 laptop, where the whole argument would otherwise push its own footer
   under the fold. Everything below is the same composition drawn one size down,
   not a second layout: the rules, the stack, the frame overlap and the two
   photographs' relationship are unchanged. */
@media (min-width: 1001px) and (max-height: 790px) {
  html.js .board-partner .board-title { font-size: clamp(1.28rem, 1.75vw, 1.62rem); }
  html.js .board-partner .board-scope { font-size: 0.86rem; }
  html.js .board-partner .art-media-invest { width: 82%; }
  html.js .board-partner .art-item-presenting { width: 50%; }
  html.js .board-partner .value-figure { font-size: 1.45rem; }
  html.js .board-partner .value-basis { margin-top: 0.28rem; }
  html.js .board-partner .value-why { margin-top: 0.45rem; }
  html.js .board-partner .board-field { row-gap: 1.4vh; padding-bottom: 6px; }
  html.js .board-partner .partner-role { padding-top: 0.5rem; }
}

/* =========================================================================
   Evidence board: Media / Consumer Guidance
   (site/work/media-consumer-guidance.html)

   The rebrand board's own component (`.board`, `.board-bar`, `.board-head`,
   `.board-field`, `.board-ix`, `board.js`) on its own canvas: one statement
   block, one featured interview as the largest card, four pieces of supporting
   coverage as a compact group, and one restrained closing line. Everything fits
   the board's first desktop view; nothing here is a miniature page.

   Scoped to `.board-media`, which travels on the board element itself. The
   overlay imports that element whole, so the composition arrives with the
   markup and the homepage trigger declares no scope class; the child page's own
   board wears the same class, so both routes show the same canvas.
   ========================================================================= */

/* ---------- the board's own values --------------------------------------- */

.board-media {
  --card-gap: clamp(11px, 1.05vw, 17px);
  --card-pad: clamp(15px, 1.3vw, 22px);
  --card-radius: clamp(10px, 0.9vw, 14px);
  --card-edge: var(--art-edge), 0 20px 38px -32px rgba(10, 18, 27, 0.45);
  /* Four tones taken from the board's own paper, white and document surface,
     so the group reads as four covers from one set rather than as four boxes. */
  --card-1: var(--white);
  --card-2: color-mix(in srgb, var(--white) 74%, var(--surface));
  --card-3: color-mix(in srgb, var(--white) 38%, var(--surface));
  --card-4: var(--surface);
}

/* ---------- the shared card vocabulary ----------------------------------- */

/* The small uppercase label that heads every card on the board. It takes the
   board's secondary tone rather than the muted one: the deepest card tone is
   below 4.5:1 for a muted 10px label, and `--copy` clears it on all four. */
/* The outlet marks are one signature, not four brand lockups: a fixed 20px
   height each, native aspect, and a single monochrome treatment. WBAL's supplied
   asset is the reversed (white) cut and would be invisible on these cards, so all
   four take the same ink rather than only the one that needs it; brightness(.42)
   keeps each mark's internal light detail instead of flattening it to a solid
   silhouette the way brightness(0) would. The label beside each mark already names
   the outlet, so the images carry empty alt text and are not read out twice. */
.board-media .outlet-logo {
  height: 20px;
  width: auto;
  max-width: 100%;
  margin-right: 0.6em;
  vertical-align: middle;
  display: inline-block;
  filter: grayscale(1) brightness(.42);
}

.board-media .card-label {
  display: block;
  margin: 0;
  font-size: 0.66rem;
  font-weight: 720;
  letter-spacing: 0.12em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--copy);
}

.board-media .card-title,
.board-media .feature-title {
  display: block;
  margin: 0;
  letter-spacing: -0.032em;
  line-height: 1.08;
  font-weight: 720;
  text-wrap: balance;
  overflow-wrap: break-word;
  color: var(--ink);
}
.board-media .card-title { font-size: clamp(1.05rem, 1.45vw, 1.7rem); }
.board-media .feature-title { font-size: clamp(1.45rem, 2.2vw, 2.2rem); }

.board-media .card-context {
  display: block;
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--copy);
}

/* The one affordance, said the same way on every card: a quiet underlined
   control that never hides what the card is. The arrow is the movement. */
.board-media .coverage-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  align-self: flex-start;
  font-size: 0.7rem;
  font-weight: 760;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 2px solid var(--line);
  padding-bottom: 0.14rem;
}
.board-media .coverage-link span { display: inline-block; transition: transform 180ms ease; }
.board-media .media-card:hover .coverage-link,
.board-media .media-card:focus-visible .coverage-link,
.board-media .media-feature .coverage-link:hover,
.board-media .media-feature .coverage-link:focus-visible { border-bottom-color: var(--ink); }
.board-media .media-card:hover .coverage-link span,
.board-media .media-card:focus-visible .coverage-link span,
.board-media .media-feature .coverage-link:hover span,
.board-media .media-feature .coverage-link:focus-visible span { transform: translate(2px, -2px); }

/* The process that produced the interview, stated rather than illustrated at a
   size nobody could read. The arrows carry the sequence at the board's own
   address-blue, which is the darker of the two the stylesheet keeps for small
   text. */
.board-media .media-process {
  margin: 0;
  font-size: 0.7rem;
  font-weight: 720;
  letter-spacing: 0.12em;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--muted-ink);
}
.board-media .media-process span { color: #0a6ea8; }

/* ---------- the featured interview --------------------------------------- */

.board-media .media-feature {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: clamp(0.85rem, 1.3vw, 1.15rem);
  min-width: 0;
  padding: var(--card-pad);
  background: var(--card-1);
  border-radius: var(--card-radius);
  box-shadow: var(--card-edge);
}
.board-media .feature-head { display: block; }
.board-media .feature-head .feature-title { margin-top: 0.5rem; }
.board-media .feature-stage { min-width: 0; }
.board-media .media-segment {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: contain;
  border-radius: clamp(6px, 0.6vw, 10px);
  background: #10161c;
}
.board-media .feature-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 1.2rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--line);
}

/* ---------- the supporting coverage -------------------------------------- */

.board-media .media-cards {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--card-gap);
  min-width: 0;
}

/* Each card is one link: the whole cover is the target, and nothing on it is
   hidden to make room for an affordance. The cover reads as two blocks — the
   text at the head, a ruled foot under it — so the card's spare height is one
   band between them rather than two gaps with a sentence floating in each. */
.board-media .media-card {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: clamp(0.75rem, 1.1vw, 1.15rem);
  min-width: 0;
  padding: var(--card-pad);
  background: var(--card-1);
  border-radius: var(--card-radius);
  box-shadow: var(--card-edge);
  text-decoration: none;
  color: inherit;
  transition: box-shadow 200ms ease;
}
.board-media .media-card:nth-child(2) { background: var(--card-2); }
.board-media .media-card:nth-child(3) { background: var(--card-3); }
.board-media .media-card:nth-child(4) { background: var(--card-4); }
.board-media .media-card:hover,
.board-media .media-card:focus-visible {
  box-shadow: var(--art-edge), 0 26px 46px -30px rgba(10, 18, 27, 0.58);
}

.board-media .card-body { display: block; }
.board-media .card-body .card-title { margin-top: 0.5rem; }
.board-media .card-body .card-context { margin-top: 0.55rem; }
/* The same footer device the featured card uses, so the four covers and the
   interview read as one set. */
.board-media .card-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  width: 100%;
  padding-top: 0.7rem;
  border-top: 1px solid var(--line);
}

/* ---------- the closing line, as the board's foot ------------------------ */

.board-media .media-foot {
  flex: 0 0 auto;
  width: min(calc(100% - (var(--board-gutter) * 2)), var(--board-max));
  margin-inline: auto;
  padding-bottom: clamp(13px, 1.5vw, 20px);
}
.board-media .media-regions {
  margin: 0;
  padding-top: 0.7rem;
  border-top: 1px solid var(--line);
  font-size: 0.7rem;
  font-weight: 720;
  letter-spacing: 0.13em;
  line-height: 1.5;
  color: var(--muted-ink);
}

/* ---------- the field, stacked (no scripting, and every phone) ------------ */

.board-media .board-statement { max-width: min(66ch, 100%); }

.board-media .board-field {
  display: flex;
  flex-direction: column;
  padding: clamp(1rem, 2vw, 1.6rem) 0 clamp(1.4rem, 3vw, 2.4rem);
}
.board-media .media-grid {
  display: flex;
  flex-direction: column;
  gap: clamp(1.4rem, 3vw, 2rem);
}

/* ---------- tablet: the same two groups, the covers two across ------------ */

@media (min-width: 640px) and (max-width: 1179px) {
  .board-media .media-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---------- desktop: one canvas, one view -------------------------------- */

/* The shared field is released at the shared board breakpoint, because the
   twelve-column grid it becomes there has nothing to place on this board. Its
   content minimum is left alone: from here down to the tablet the board is read
   down the page, so the field has to be free to grow rather than be squeezed
   into the first screen and overlap the board's own closing line. */
@media (min-width: 1001px) {
  html.js .board-media .board-field {
    display: flex;
    flex-direction: column;
    grid-template-columns: none;
    grid-template-rows: none;
    align-items: stretch;
    gap: 0;
    min-height: auto;
  }
  /* Below the composition's own breakpoint this board is not a fixed-height
     canvas, so it does not take the shared board's viewport height and
     internal scroll: it reads down the page exactly as it does on a tablet,
     which is what ordinary page scrolling means here. */
  html.js .board-media { height: auto; min-height: 100dvh; overflow-y: visible; }
}
@media (min-width: 1180px) {
}

/* The composition itself starts at 1180px. Below that the covers would be too
   narrow for their own headlines, and the board reads down the page instead —
   the same thing it does on a tablet and a phone. */
@media (min-width: 1180px) {
  /* The board is exactly the browser's height, so the whole argument is in the
     first view and the only thing under it is the board's own foot. */
  html.js .board-media { height: 100dvh; min-height: 660px; overflow-y: auto; }

  /* The eyebrow, the title and the supporting line are one left-aligned
     statement block. The shared rule that makes `.board-head` a two-column grid
     — which would park the supporting line in a right-hand column — is released
     for this board only, and the block rather than each line carries the
     measure. No line break is forced. */
  html.js .board-media .board-head { display: block; padding-top: 4px; }
  html.js .board-media .board-statement { max-width: min(66ch, 100%); }
  html.js .board-media .board-title {
    max-width: none;
    margin-top: 0.3rem;
    font-size: clamp(1.5rem, 2.1vw, 2rem);
  }
  html.js .board-media .board-scope {
    max-width: none;
    margin-top: clamp(0.35rem, 0.85vh, 0.7rem);
    font-size: 0.9rem;
  }

  /* The rebrand board's field is a twelve-column, twelve-row grid and it aligns
     its items to the start of the cross axis. That grid is what the other three
     boards place their artifacts on; this board's field is one composition
     instead, so both are released here. */
  html.js .board-media .board-field {
    display: flex;
    flex-direction: column;
    grid-template-columns: none;
    grid-template-rows: none;
    align-items: stretch;
    gap: 0;
    flex: 1 1 auto;
    min-height: auto;
    padding: 6px 0 0;
  }

  /* One asymmetrical row: the featured interview takes the larger column, the
     four covers the smaller one, and both are the full height of the field so
     no part of the board floats in a space the composition does not fill. */
  /* The grid takes the height its own content asks for rather than the whole
     field. Nothing here is a fixed-height panel, so stretching it would only
     push the slack into the cards — measured at 60% of a cover empty in the
     stretched version, and 10% in this one. What the field has left over sits
     above the board's own closing line, which is where a page's bottom
     margin belongs. */
  html.js .board-media .media-grid {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1.42fr) minmax(0, 1fr);
    gap: clamp(14px, 1.3vw, 22px);
    align-items: stretch;
  }
  html.js .board-media .media-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: repeat(2, minmax(0, 1fr));
    min-height: 0;
  }
  html.js .board-media .media-card { min-height: 0; }
  /* A label that wraps to two lines and a label that does not are reserved the
     same two lines, so the covers share a title line across each row of the
     grid instead of stepping. The other three boards reserve their caption
     rails the same way. */
  html.js .board-media .card-label { min-height: calc(20px + 1.4em); }
  /* The covers reserve the same headline block, so their description lines and
     their ruled feet land on one line each across the row however many lines a
     headline happens to take. The rest of the board reserves its caption rails
     the same way. */
  html.js .board-media .card-title { min-height: 4.32em; }
  /* The video keeps its own proportion and its own width; the card's spare
     height is spent around it, not by stretching the picture. */
  html.js .board-media .feature-stage { flex: 0 0 auto; }

  /* Entrance: the rebrand board's 660ms beat, in four steps of delay rather than
     one per card, so the field gathers instead of marching. */
  html.js .board-media .board-head,
  html.js .board-media .media-feature,
  html.js .board-media .media-card {
    opacity: 1;
    transform: none;
    transition: opacity 300ms ease, transform 300ms ease, box-shadow 200ms ease;
    transition-delay: var(--media-d, 0ms);
  }
  html.js .board-media[data-assembly="arming"] .board-head,
  html.js .board-media[data-assembly="arming"] .media-feature,
  html.js .board-media[data-assembly="arming"] .media-card {
    opacity: 0;
    transform: translateY(10px);
    transition: none;
  }
}

/* ---------- a short desktop window: the same board, one size down --------- */

/* Every dimension here is the one the taller window uses, drawn smaller, so a
   1366 x 768 screen keeps the whole composition in its first view instead of
   letting the featured card push the closing line under the fold. */
@media (min-width: 1180px) and (max-height: 860px) {
  html.js .board-media { min-height: 560px; }
  html.js .board-media .board-title { font-size: clamp(1.28rem, 1.75vw, 1.62rem); }
  html.js .board-media .board-scope { font-size: 0.86rem; }
  html.js .board-media .feature-title { font-size: clamp(1.24rem, 1.9vw, 1.95rem); }
  html.js .board-media .card-title { font-size: clamp(1rem, 1.3vw, 1.4rem); }
  html.js .board-media .card-context { font-size: 0.74rem; }
  html.js .board-media .card-label { font-size: 0.64rem; }
  html.js .board-media .media-process,
  html.js .board-media .coverage-link { font-size: 0.62rem; }
  html.js .board-media .media-regions { font-size: 0.64rem; }
  html.js .board-media .board-field { padding-top: 2px; }
  /* A wide, short window runs out of height in the featured card before it runs
     out of width, so the video's column gives some width to the covers: the
     same composition, one size down, and the covers get the room their
     headlines need in exchange. */
  html.js .board-media .media-grid { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
}

/* ---------- narrow: the same board, read down the page ------------------- */

@media (max-width: 639px) {
  .board-media .media-feature,
  .board-media .media-card { gap: 0.75rem; }
  .board-media .media-process { line-height: 1.7; }
  .board-media .coverage-link { font-size: 0.72rem; }
}

/* ---------- the arrows are movement, so reduced motion has none ------------ */

@media (prefers-reduced-motion: reduce) {
  .board-media .coverage-link span { transition: none !important; }
  .board-media .media-card:hover .coverage-link span,
  .board-media .media-feature .coverage-link:hover span { transform: none; }
  html.js .board-media .board-head,
  html.js .board-media .media-feature,
  html.js .board-media .media-card { transition: none !important; }
  html.js .board-media[data-assembly] .board-head,
  html.js .board-media[data-assembly] .media-feature,
  html.js .board-media[data-assembly] .media-card { opacity: 1; transform: none; }
}


/* =========================================================================
   Evidence board: Contractor Connections
   (site/work/contractor-connections.html)

   The rebrand board's own component (`.board`, `.board-bar`, `.board-head`,
   `.board-field`, `.art*`, `.board-ix`, `board.js`) on its own canvas: the story,
   the partner model and the delivered result hold the left of the field, and a
   compact two-column collage of the four supplied graphics holds the right.

   The collage is led by the Pride of Baltimore II composition at the largest
   size on the board, with the packed room behind it in the same wide column and
   the two promotions filling the narrow one under the attendee's own words.

   Scoped to `.board-cc`, which travels on the board element itself. The overlay
   imports that element whole, so the composition arrives with the markup and the
   homepage trigger declares no scope class; the child page's own board wears the
   same class, so both routes show the same canvas.

   Nothing here animates: the shared assembly and the picture lift are both
   released for this board, so the spread is simply present when it opens.

   Every graphic is used at its own supplied aspect ratio. Nothing is cropped,
   recoloured, re-lettered or redrawn, and no live text is set over artwork: the
   labels live in the caption rail under each artifact, as on the other boards.
   ========================================================================= */

/* ---------- the board's own values --------------------------------------- */

.board-cc {
  --cc-row: clamp(12px, 1.5vh, 20px);
  /* Everything the collage does not own, measured from the render: the bar, the
     statement block, the field's own top padding and the margin the spread keeps
     under itself. */
  --cc-chrome: 152px;
  /* The collage's height per pixel of its width. Two columns carrying a 16:9, a
     16:9, a 1:1 and a 2:1 graphic and a quote work out at about 0.77, so the
     width a given window can afford is its height over 0.79 — the safety is what
     keeps a short window from pushing the collage past the board. */
  --cc-r: 0.79;
  --cc-w: min(100%, calc((100dvh - var(--cc-chrome)) / var(--cc-r)));
}

/* ---------- the statement: the idea, then the series ---------------------- */

.board-cc .board-ident {
  margin: 0.5rem 0 0;
  max-width: 58ch;
  font-size: 0.9rem;
  line-height: 1.4;
  color: var(--copy);
}

/* ---------- the story ------------------------------------------------------ */

.board-cc .cc-story {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.board-cc .cc-lede {
  margin: 0;
  max-width: 46ch;
  font-size: clamp(0.88rem, 0.95vw, 0.98rem);
  line-height: 1.5;
  color: var(--ink);
}

.board-cc .cc-block { margin-top: clamp(0.85rem, 1.7vh, 1.4rem); }

.board-cc .cc-label {
  margin: 0;
  padding-top: 0.4rem;
  border-top: 1px solid var(--line);
  font-size: 0.66rem;
  font-weight: 720;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--muted-ink);
}

.board-cc .cc-block p {
  margin: 0.45rem 0 0;
  max-width: 46ch;
  font-size: clamp(0.82rem, 0.86vw, 0.9rem);
  line-height: 1.5;
  color: var(--copy);
}

/* The delivered result is its own ruled plate at the foot of the narrative, with
   the space it needs reserved: the rule, the figure and both lines of the note
   are one block, and the block is what the board's height has to hold. It closes
   the story rather than opening it. */
.board-cc .cc-result {
  margin-top: clamp(1.2rem, 3vh, 2.2rem);
  padding-top: clamp(0.8rem, 1.8vh, 1.2rem);
  border-top: 2px solid var(--ink);
}

.board-cc .cc-figure {
  margin: 0;
  font-size: clamp(1.9rem, 2.75vw, 2.6rem);
  line-height: 0.94;
  letter-spacing: -0.05em;
  font-weight: 720;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.board-cc .cc-figure-note {
  margin: 0.28rem 0 0;
  max-width: 32ch;
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--copy);
}

/* ---------- the collage ---------------------------------------------------- */

/* The collage's four places are named, and each artifact is told which one it
   takes. Nothing is positioned by its order in the document, so a later
   rearrangement of the board cannot move an artifact into a cell sized for
   another one — which is what keeps the hierarchy true whatever the reading
   order is. */
.board-cc .cc-collage {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "one" "two" "pride" "side";
  gap: clamp(1.5rem, 3vw, 2.2rem);
  min-width: 0;
}

.board-cc .art-cc1 { grid-area: one; }
.board-cc .art-cc2 { grid-area: two; }
.board-cc .art-cc3 { grid-area: pride; }
.board-cc .cc-side { grid-area: side; }

/* The lower right of the spread is one stack: the attendee's words above the
   Western Maryland promotion, so the quote reads as feedback on the event it
   sits beside. */
.board-cc .cc-side {
  display: flex;
  flex-direction: column;
  gap: inherit;
  min-width: 0;
}

.board-cc .art-media img { object-fit: contain; }

/* The attendee's own words: relayed feedback, set at the top of the small
   column so it reads against the Pride composition. It carries no name and is
   not dressed as a survey result. */
.board-cc .cc-quote {
  margin: 0;
  padding-top: clamp(0.6rem, 1.2vh, 0.9rem);
  border-top: 1px solid var(--line);
}

.board-cc .cc-quote-text {
  margin: 0;
  max-width: 42ch;
  font-size: clamp(0.86rem, 0.9vw, 0.96rem);
  line-height: 1.45;
  letter-spacing: -0.008em;
  color: var(--ink);
}

.board-cc .cc-quote-who {
  margin: 0.45rem 0 0;
  font-size: 0.64rem;
  font-weight: 720;
  letter-spacing: 0.11em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--muted-ink);
}

/* The artifact is the control and the rail carries the same action as a visible
   one: the affordance never depends on hovering, and the small badge that would
   otherwise appear over the picture is not drawn on this board. */
.board-cc .art-inspect { display: none; }
.board-cc .art-foot { row-gap: 0.08rem; }
.board-cc .art-btn { font-size: 0.62rem; letter-spacing: 0.08em; }
.board-cc .art-open { cursor: zoom-in; }

/* ---------- no motion ----------------------------------------------------- */

/* The shared assembly fades the head and the artifacts in as a board settles, a
   picture lifts under the pointer, and the whole board contracts as the pop-out
   closes. All three are released for this board: it is present the moment it
   opens and it leaves the moment it closes. */
.board-cc .art-media { transition: none; }
.board-cc .art-stage:hover .art-media,
.board-cc .art-stage:focus-within .art-media { transform: none; }

@media (min-width: 1180px) {
  html.js .board.board-cc .board-head,
  html.js .board.board-cc .art,
  html.js .board.board-cc[data-assembly="arming"] .board-head,
  html.js .board.board-cc[data-assembly="arming"] .art {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* The pop-out contracts as it closes on the other boards. This one leaves
   without moving. */
html.js .board-shell.is-contracting .board-cc { transform: none; opacity: 1; transition: none; }

/* ---------- narrow desktop: stacked, no composed collage ------------------ */

/* The shared field becomes a twelve-column wall at 1001px, and there is nothing
   for this board to place on it until the spread has the width to hold a story
   column and a collage. Between here and the composition's own breakpoint the
   board reads down the page with ordinary page scrolling, which is also what
   every phone does. */
@media (min-width: 1001px) and (max-width: 1179px) {
  html.js .board-cc { height: auto; min-height: 100dvh; overflow-y: visible; }
  html.js .board-cc .board-field {
    display: flex;
    flex-direction: column;
    grid-template-columns: none;
    grid-template-rows: none;
    align-items: stretch;
    gap: clamp(1.8rem, 3.4vw, 2.6rem);
    min-height: auto;
  }
  html.js .board-cc .cc-story { max-width: 74ch; }
  html.js .board-cc .cc-lede,
  html.js .board-cc .cc-block p { max-width: 68ch; }
}

/* ---------- the composed spread ------------------------------------------- */

@media (min-width: 1180px) {
  /* The board is the browser's height, and the spread inside it is content-tall:
     the row is not stretched, so the result plate sits where the narrative ends
     and the leftover falls under the spread as the board's own bottom margin. */
  html.js .board-cc { height: 100dvh; min-height: 620px; overflow-y: auto; }

  /* The eyebrow block is released so the identifier sits under the headline
     rather than being parked in a second column, and the statement — not each
     line — carries the measure. */
  html.js .board-cc .board-head { display: block; padding-top: 4px; }
  html.js .board-cc .board-statement { max-width: min(72ch, 100%); }
  html.js .board-cc .board-title { max-width: none; margin-top: 0; font-size: clamp(1.5rem, 2.1vw, 2rem); }
  html.js .board-cc .board-ident { margin-top: clamp(0.28rem, 0.7vh, 0.5rem); font-size: 0.86rem; }

  html.js .board-cc .board-field {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    grid-template-rows: auto;
    align-content: start;
    align-items: start;
    padding: 6px 0 0;
  }

  html.js .board-cc .cc-story {
    grid-column: 1 / span 4;
    align-self: start;
    padding-right: calc(clamp(18px, 2.6vw, 44px) + 6px);
  }
  /* The controlled overlap: the collage crosses the gutter it was given and laps
     into the story's column, so the two halves of the spread interlock instead
     of meeting at a grid line. The story's own measure is what keeps the live
     text clear of the pictures — asserted in the checks, not assumed. */
  html.js .board-cc .cc-evidence {
    grid-column: 5 / span 8;
    margin-left: clamp(-44px, -2.6vw, -18px);
    min-width: 0;
  }

  /* Two rows on the main column and the narrow one: 01 beside 02, then 03 with
     the quote and 04 beside it, so the board reads left to right and top to
     bottom in its own numbering. The whole collage is capped by the height the
     window can afford, and the pictures flush to the right edge of the field, so
     whatever the cap takes off them falls on the left, toward the story, where
     the overlap already lives. */
  html.js .board-cc .cc-collage {
    grid-template-columns: minmax(0, 1.94fr) minmax(0, 1fr);
    grid-template-areas:
      "one   two"
      "pride side";
    column-gap: clamp(12px, 1.4vw, 22px);
    row-gap: var(--cc-row);
    align-items: start;
    width: var(--cc-w);
    margin-left: auto;
  }

  /* One scale, four sizes: Pride is the widest and tallest thing on the board,
     the packed room takes the second-largest place behind it in the same column,
     and the two promotions fill the small column as supporting evidence. */
  html.js .board-cc .art-media { margin-left: auto; }
  html.js .board-cc .art-media-cc3 { width: 100%; }
  html.js .board-cc .art-media-cc1 { width: 86%; }
  html.js .board-cc .art-media-cc2 { width: 100%; }
  html.js .board-cc .art-media-cc4 { width: 100%; }
  html.js .board-cc .art-foot { justify-content: flex-end; }
  html.js .board-cc .cc-quote { width: 100%; }
}

/* ---------- narrow composed window: one size down ------------------------- */

/* At the narrow end of the composed range the story column is about 360px wide
   and forty-odd characters a line, which is what makes it the tallest thing on
   the board rather than the pictures. It steps down so the spread still fits the
   window it was opened in. */
@media (min-width: 1180px) and (max-width: 1319px) {
  html.js .board-cc .cc-lede { font-size: 0.84rem; }
  html.js .board-cc .cc-block p { font-size: 0.76rem; }
  html.js .board-cc .cc-block { margin-top: 0.7rem; }
  html.js .board-cc .cc-label { font-size: 0.6rem; }
  html.js .board-cc .cc-figure { font-size: 1.7rem; }
  html.js .board-cc .cc-figure-note { font-size: 0.72rem; }
  html.js .board-cc .cc-quote-text { font-size: 0.78rem; }
  html.js .board-cc .cc-quote-who { font-size: 0.58rem; }
  html.js .board-cc .cc-result { margin-top: 1rem; padding-top: 0.7rem; }
}

/* ---------- a short desktop window: one size down ------------------------- */

/* A 16:9 laptop gives the collage less height than its width would like, and the
   narrative has to keep its place above the result plate. The story steps down
   rather than letting either column run past the board. */
@media (min-width: 1180px) and (max-height: 800px) {
  html.js .board-cc .cc-lede { font-size: 0.86rem; }
  html.js .board-cc .cc-block p { font-size: 0.78rem; }
  html.js .board-cc .cc-block { margin-top: 0.72rem; }
  html.js .board-cc .cc-label { font-size: 0.62rem; }
  html.js .board-cc .cc-figure { font-size: 1.75rem; }
  html.js .board-cc .cc-figure-note { font-size: 0.74rem; }
  html.js .board-cc .cc-quote-text { font-size: 0.8rem; }
  html.js .board-cc .cc-quote-who { font-size: 0.6rem; }
  html.js .board-cc .cc-result { margin-top: 1.05rem; padding-top: 0.72rem; }
}

/* ---------- both: the smallest composed window ---------------------------- */

@media (min-width: 1180px) and (max-width: 1319px) and (max-height: 800px) {
  html.js .board-cc .cc-lede { font-size: 0.82rem; }
  html.js .board-cc .cc-block p { font-size: 0.74rem; }
  html.js .board-cc .cc-block { margin-top: 0.64rem; }
  html.js .board-cc .cc-label { font-size: 0.58rem; }
  html.js .board-cc .cc-figure { font-size: 1.6rem; }
  html.js .board-cc .cc-figure-note { font-size: 0.7rem; }
  html.js .board-cc .cc-result { margin-top: 0.9rem; padding-top: 0.62rem; }
}

/* ---------- a very short window: the last step down ----------------------- */

@media (min-width: 1180px) and (max-height: 740px) {
  html.js .board-cc .cc-lede { font-size: 0.8rem; }
  html.js .board-cc .cc-block p { font-size: 0.72rem; }
  html.js .board-cc .cc-block { margin-top: 0.58rem; }
  html.js .board-cc .cc-label { font-size: 0.56rem; padding-top: 0.32rem; }
  html.js .board-cc .cc-figure { font-size: 1.5rem; }
  html.js .board-cc .cc-figure-note { font-size: 0.68rem; }
  html.js .board-cc .cc-result { margin-top: 0.8rem; padding-top: 0.55rem; }
}

/* ---------- phone: the same board, read down the page --------------------- */

@media (max-width: 1179px) {
  .board-cc .cc-quote-text { max-width: none; }
  .board-cc .cc-result { margin-top: clamp(1.5rem, 4vh, 2.4rem); }
}

/* =========================================================================
   Evidence board: Shred Day
   (site/work/shred-day.html)

   The rebrand board's own component (`.board`, `.board-bar`, `.board-head`,
   `.board-field`, `.art*`, `.board-ix`, `board.js`) on its own canvas: the
   turnout holds the tall left column — the largest object on the board — and the
   four remaining pieces of supplied evidence arrange themselves around it. The
   service photograph sits beside the line it served, at the second largest size;
   the earned-media frame and the broadcast advertisement carry the top of the
   right-hand field; the sponsor bags close it. The verified result is the
   board's own closing band, across the full field at the foot.

   Scoped to `.board-shd`, which travels on the board element itself. The overlay
   imports that element whole, so the composition arrives with the markup and the
   homepage trigger declares no scope class; the child page's own board wears the
   same class, so both routes show the same canvas.

   Nothing here animates: the shared assembly and the picture lift are both
   released for this board, and the advertisement never plays itself. The
   advertisement is the board's only moving evidence and the board stays static
   around it.

   Every supplied file is used at its own aspect ratio, uncropped and
   unretouched. No live text is set over artwork: every label lives in the
   caption rail under its own evidence, as on the other boards.
   ========================================================================= */

/* ---------- the board's own values --------------------------------------- */

.board-shd {
  /* One gutter, used between columns, between the spread's two rows and between
     the evidence and the closing band, so the rhythm is one number. */
  --shd-gap: clamp(14px, 1.5vw, 26px);
}

/* ---------- the statement: the idea, then the work ------------------------ */

.board-shd .board-ident {
  margin: 0.5rem 0 0;
  max-width: 58ch;
  font-size: 0.9rem;
  line-height: 1.4;
  color: var(--copy);
}

/* The crop point, on both scopes that draw the earned-media frame: the frame on
   the board, and the frame when it is opened in the inspector. */
.board-shd,
.board-ix.ix-shd { --shd-earned-crop: center 27%; }

/* ---------- the spread, read down the page -------------------------------- */

/* The default state, and every phone: one column, the evidence in the order the
   document gives it — turnout, service, earned media, broadcast, partner — at
   sizes that can be understood on their own. This is also the narrow-desktop
   state between the tablet breakpoint and the composed spread's own width. */

.board-shd .shd-spread {
  display: flex;
  flex-direction: column;
  gap: clamp(1.7rem, 3.6vw, 2.8rem);
  min-width: 0;
}

.board-shd .art-media { box-shadow: var(--art-edge), var(--art-lift); }
.board-shd .art-media img,
.board-shd .art-media video { object-fit: contain; }

/* The turnout and the service keep the greater weight at every stacked width,
   and the three supporting pieces keep the composed spread's own order — the
   television frame, then the sponsor bags, then the advertisement — so the
   hierarchy a phone reads is the hierarchy the composed board carries. */
.board-shd .art-media-shdline { width: min(100%, 760px); }
.board-shd .art-media-shddump { width: min(92%, 700px); }
.board-shd .art-media-shdtv { width: min(88%, 640px); }
.board-shd .art-media-shdbags { width: min(80%, 580px); }
.board-shd .art-media-shdvideo { width: min(76%, 560px); }

/* Fill the earned-media frame instead of letterboxing the photo. The supplied
   file is a portrait photograph; the board shows a landscape window into it, and
   the point that window sits on is one value, declared once here for the frame
   on the board and for the frame when it is opened. */
.board-shd .art-media-shdtv {
  overflow: hidden;
}

.board-shd .art-media-shdtv img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--shd-earned-crop, center 27%);
}

/* Opening the earned-media photograph shows the same window into it that the
   board shows — the same ratio, at the same point — rather than the whole
   portrait beside the frame that was clicked. `.ix-shd` travels on this board's
   own inspector dialog, which the pop-out mounts beside the board rather than
   inside it, so the rule cannot be scoped through `.board-shd`.

   The photograph is taken out of the flow and pinned to the frame's own box: an
   image left in the flow sizes itself from the file, so a portrait supplied
   inside a landscape frame would stand at its intrinsic height and be clipped
   by the frame's edge — the crop Clay was seeing. Pinned, the frame's ratio
   decides the window, and the crop point is the one the board declares.

   The dialog's own `data-ratio` on the inspect control carries the same
   landscape ratio as the frame on the board: the two have to agree for the
   window to match. */
.board-ix.ix-shd .ix-body { position: relative; }

.board-ix.ix-shd .ix-body > img[src$="tv%20appearance.jpg"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  object-fit: cover;
  object-position: var(--shd-earned-crop, center 27%);
}


/* The artifact is the control and the rail carries the same action as a visible
   one: no affordance on this board depends on hovering, and the small badge that
   would otherwise appear over the picture is not drawn. */
.board-shd .art-inspect { display: none; }
.board-shd .art-open { cursor: zoom-in; }
.board-shd .art-foot { min-height: 2rem; row-gap: 0.1rem; align-items: flex-start; }
.board-shd .art-label { font-size: 0.68rem; }
.board-shd .art-btn { font-size: 0.68rem; }

/* ---------- the closing band: three verified figures, one statement ------- */

.board-shd .shd-results {
  margin-top: clamp(0.2rem, 0.2vh, 0.2rem);
  padding-top: clamp(0.2rem, 0.2vh, 0.2rem);
  border-top: 2px solid var(--ink);
}

/* What the closing band's totals cover. It heads the band and sits above the
   figures, and its height is part of the board's reserved clearance (see
   `--shd-clear`), so it cannot push a figure past the foot of the board. */
.board-shd .shd-band-label {
  margin: 0 0 0.42rem;
  font-size: 0.68rem;
  font-weight: 720;
  letter-spacing: 0.1em;
  line-height: 1.3;
  color: var(--muted-ink);
}

.board-shd .shd-figures {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.9rem 1.6rem;
}

.board-shd .shd-figure-block { display: flex; flex-direction: column; min-width: 0; }

.board-shd .shd-figure {
  margin: 0;
  font-size: clamp(1.9rem, 2.75vw, 2.6rem);
  line-height: 0.94;
  letter-spacing: -0.05em;
  font-weight: 720;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.board-shd .shd-figure-note {
  margin: 0.28rem 0 0;
  font-size: 0.68rem;
  font-weight: 720;
  letter-spacing: 0.14em;
  line-height: 1.3;
  text-transform: uppercase;
  color: var(--muted-ink);
}

/* ---------- no motion ----------------------------------------------------- */

/* The shared assembly fades the head and the artifacts in as a board settles, a
   picture lifts under the pointer, and the whole board contracts as the pop-out
   closes. The first two are released for this board: it is present the moment it
   opens, and the advertisement is the only thing on it that moves. */
.board-shd .art-media { transition: none; }
.board-shd .art-stage:hover .art-media,
.board-shd .art-stage:focus-within .art-media { transform: none; }

@media (min-width: 1180px) {
  html.js .board.board-shd .board-head,
  html.js .board.board-shd .art,
  html.js .board.board-shd[data-assembly="arming"] .board-head,
  html.js .board.board-shd[data-assembly="arming"] .art {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

html.js .board-shell.is-contracting .board-shd { transform: none; opacity: 1; transition: none; }

/* ---------- narrow desktop: stacked, no composed spread ------------------- */

/* Between the tablet breakpoint and the composed spread's own width the shared
   field would otherwise become the twelve-column wall, and there is nothing on
   this board to place on it until a turnout column and two supporting columns
   both have room. The board reads down the page instead. */
@media (min-width: 1001px) and (max-width: 1179px) {
  html.js .board-shd { height: auto; min-height: 0; overflow-y: visible; }
  html.js .board-shd .board-field {
    display: flex;
    flex-direction: column;
    grid-template-columns: none;
    grid-template-rows: none;
    align-items: stretch;
    gap: clamp(1.8rem, 3.4vw, 2.6rem);
    min-height: auto;
  }
  html.js .board-shd .art-media-shdline { width: min(100%, 820px); }
  html.js .board-shd .art-media-shddump { width: min(92%, 760px); }
}

/* ---------- the composed spread ------------------------------------------- */

@media (min-width: 1180px) {
  /* The board is the browser's height, and the spread inside it is content-tall:
     the field's own grid reserves the closing band as its last row, and the
     leftover above that band is the pacing between the evidence and the result. */
  /* The shared board keeps a 760px floor. This one does not need one: the
     composition is a fraction of the window's own height (see `--shd-hero`), so
     the board is exactly the window it was opened in at every size tested, and
     the turnout itself carries the floor against a window too short to draw. */
  html.js .board-shd { height: 100dvh; min-height: 0; overflow-y: auto; }

  /* Everything in the composed spread is derived from one length: the turnout's
     own side, in pixels. The composition is 2.531 turnout sides plus two
     gutters wide, so the width the field has settles it; `--shd-clear` is the
     rest of the board — the bar, the statement, the field's own padding and the
     closing band — measured from the render, and it is what keeps a short window
     inside its board. */
  html.js .board-shd {
    --shd-clear: 426px;
    --shd-hero: min(
      600px,
      calc((100cqw - var(--shd-gap) * 2) / 2.531),
      max(260px, calc((100dvh - var(--shd-clear)) * 1.1283))
    );
  }

  html.js .board-shd .board-field {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    /* The evidence row takes every pixel the closing band does not need, so the
       spread centres in the room it has and the figures keep the board's foot. */
    grid-template-rows: minmax(auto, 1fr) auto;
    align-items: start;
    align-content: stretch;
    column-gap: 0;
    row-gap: var(--shd-gap);
    padding: clamp(16px, 1.8vw, 24px) 0 30px;
    min-height: 0;
  }

  html.js .board-shd .shd-spread {
    grid-column: 1;
    grid-row: 1;
    align-self: center;
    display: grid;
    grid-template-columns:
      var(--shd-hero)
      calc(var(--shd-hero) * 0.756)
      calc(var(--shd-hero) * 0.775);
    column-gap: var(--shd-gap);
    row-gap: var(--shd-gap);
    align-items: end;
    align-content: start;
    min-width: 0;
  }

  html.js .board-shd .shd-results {
    grid-column: 1;
    grid-row: 2;
    align-self: end;
    margin-top: 0;
  }

  /* Five named places. The turnout holds the tall column across both rows; the
     service sits beside the line it served; the earned-media frame and the
     sponsor bags share one right edge in the third column, and the broadcast
     advertisement closes the second.  */
  html.js .board-shd .art-shdline { grid-column: 1; grid-row: 1 / span 2; align-self: start; }
  html.js .board-shd .art-shddump { grid-column: 2; grid-row: 1; }
  html.js .board-shd .art-shdtv { grid-column: 3; grid-row: 1; }
  html.js .board-shd .art-shdvideo { grid-column: 2; grid-row: 2; }
  html.js .board-shd .art-shdbags { grid-column: 3; grid-row: 2; }

  /* One scale, four sizes: the turnout is the widest and tallest thing on the
     board and fills its column; the service takes the second column whole and
     stays larger than everything supporting it; the earned-media frame steps in
     from its column and the sponsor bags step in behind them, right-justified so
     what the step leaves falls toward the story, where the air already lives. */
  html.js .board-shd .art-media-shdline { width: 100%; }
  html.js .board-shd .art-media-shddump { width: 100%; }
  html.js .board-shd .art-media-shdtv { width: 79%; margin-left: auto; }
  html.js .board-shd .art-media-shdbags { width: 72%; margin-left: auto; }
  html.js .board-shd .art-media-shdvideo { width: 88%; margin-left: auto; }

  /* Every caption rail sits under its own picture, and the supporting rails are
     justified with the pictures above them. */
  html.js .board-shd .art-shdvideo .art-foot,
  html.js .board-shd .art-shdtv .art-foot,
  html.js .board-shd .art-shdbags .art-foot { justify-content: flex-end; }

  /* Shred Day uses one full-width opening statement instead of
   the shared two-column board header. */
html.js .board-shd .board-head {
  grid-template-columns: minmax(0, 1fr);
  column-gap: 0;
  row-gap: 0.65rem;
}

html.js .board-shd .board-head > * {
  grid-column: 1 / -1;
}

html.js .board-shd .board-title {
  width: 100%;
  max-width: 38ch;
  white-space: normal;
  line-height: 0.98;
  font-size: clamp(1.4rem, 2.1vw, 2rem);
}

html.js .board-shd .board-ident {
  max-width: 92ch;
  margin-top: 0.45rem;
}

/* ---------- a short desktop window: the chrome steps down ----------------- */

/* A 16:9 laptop leaves the composed spread less room than its width would like,
   so the parts of the board that are not the evidence step one size down rather
   than letting the closing band run past the board. */
@media (min-width: 1180px) and (max-height: 860px) {
  html.js .board-shd { --shd-clear: 394px; }
  .board-shd .board-title { font-size: clamp(1.3rem, 1.8vw, 1.72rem); }
  .board-shd .board-scope { font-size: 0.86rem; }
  .board-shd .board-ident { margin-top: 0.36rem; font-size: 0.84rem; }
  .board-shd .shd-figure { font-size: clamp(1.6rem, 2.2vw, 2rem); }
  .board-shd .shd-results { margin-top: 0; padding-top: clamp(0.6rem, 1.4vh, 0.9rem); }
  html.js .board-shd .board-field { padding: 12px 0 20px; }
}

@media (min-width: 1180px) and (max-height: 740px) {
  html.js .board-shd { --shd-clear: 386px; }
  .board-shd .board-title { font-size: clamp(1.24rem, 1.7vw, 1.6rem); }
  .board-shd .board-scope { font-size: 0.82rem; }
  .board-shd .shd-figure { font-size: clamp(1.5rem, 2rem, 1.85rem); }
  html.js .board-shd .board-field { padding: 10px 0 16px; }
}

/* ---------- phone: the same board, read down the page --------------------- */

@media (max-width: 1000px) {
  .board-shd .board-ident { font-size: 0.88rem; }
  .board-shd .shd-results { margin-top: clamp(1.5rem, 4vh, 2.4rem); }
  .board-shd .art-media-shdline { width: 100%; }
  .board-shd .art-media-shddump { width: 92%; }
  .board-shd .art-media-shdtv { width: 88%; }
  .board-shd .art-media-shdbags { width: 80%; }
  .board-shd .art-media-shdvideo { width: 76%; }
}


/* 2. Stop the images container from forcing empty clearance */
.board-shd .shd-spread {
  height: auto !important;
  min-height: 0 !important;
  padding-bottom: 0 !important;
}
