/* ==========================================================================
   Third Bay Media — site layer.
   Sits on top of design-system.css (Modernist). Every value here comes from
   a token in that file; nothing hard-codes a color or a font. The rules
   below are the inline styles from the Claude Design canvas, extracted.
   ========================================================================== */

/* --- page shell ---------------------------------------------------------- */

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
}

.page {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* Sits at the top of the document, behind the nav, and is watched rather than
   listening to scroll. Once it leaves the viewport the nav compresses. Its
   height is the trigger distance, and being absolutely positioned it never
   moves when the nav's own height changes — so the two can't feed back into
   each other. */
.nav-sentinel {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 48px;
  pointer-events: none;
}

.page-main { flex: 1; }

/* The site's single horizontal gutter. Sections opt in; full-bleed bands
   (hero image, dark banner) deliberately don't. */
.gutter { padding-inline: calc(var(--space-8) * 1); }

a { color: var(--color-accent); }
a:hover { color: var(--color-accent-700); }

/* --- navigation ---------------------------------------------------------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--color-bg);
  padding: 14px var(--space-8);
  gap: 26px;
  transition: padding 0.25s ease, gap 0.25s ease;
}

.nav-brand {
  letter-spacing: -0.02em;
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  text-decoration: none;
  color: inherit;
  transition: font-size 0.25s ease;
}

/* --- compressed nav -------------------------------------------------------
   Past the sentinel the bar loses height and the wordmark steps down. The 2px
   rule and the booking button both stay — the system's structure doesn't move,
   only the space around it. */

.is-compact .nav { padding-block: 7px; gap: 20px; }
.is-compact .nav .nav-brand { font-size: 15px; }
.is-compact .brand-dot { width: 7px; height: 7px; }
.is-compact .nav a.btn { padding-block: 5px; }
.brand-dot { transition: width 0.25s ease, height 0.25s ease; }

/* The square that follows the wordmark, in nav and footer. */
.brand-dot {
  width: 9px;
  height: 9px;
  background: var(--color-accent);
  display: block;
}

/* The brand and the booking button are anchors here (they were a span and a
   button in the design source), so they need to out-specify the design
   system's blanket `.nav a` rule. */
.nav .nav-brand { font-size: 18px; }
.nav a.btn { margin-left: 6px; }
.nav a.btn-primary { color: var(--color-bg); }
.nav a.btn-primary:hover { color: var(--color-bg); background: var(--color-accent-600); }
.nav a.btn-primary:active { background: var(--color-accent-700); }

/* --- grid primitives ------------------------------------------------------
   The modular grid the system is built on: equal-width cells separated by
   2px rules. Column counts collapse at the two breakpoints at the bottom
   of this file. */

.grid { display: grid; }
.g-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.g-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.g-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Ruled grids share a vertical gutter only — the cell's own top rule
   supplies the horizontal separation. */
.g-ruled { gap: 0 var(--space-8); }
.g-ruled-wide { gap: 0 48px; }
.g-gap { gap: var(--space-8); }
.g-gap-lg { gap: 40px; }

/* An asymmetric two-column split: content weighted left, note right. */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 48px;
}
.split-even { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.split-lead { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); }
.split-case { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); }
.split-form { grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr); }
.split-end { align-items: end; }
.split-start { align-items: start; }

/* --- the ruled cell -------------------------------------------------------
   The system's core unit: a 2px rule above, content flush left below. */

.cell {
  position: relative;
  /* The rule is drawn by ::before so it can animate in; the border stays for
     its 2px of layout only. See "drawn rules" below. */
  border-top: 2px solid transparent;
  padding: 20px 0 28px;
}
.cell-inset { padding-right: var(--space-6); }
.cell-tall { padding: var(--space-6) 0 var(--space-8); }
.cell-taller { padding: 28px 0 36px; }

/* The small accent label that opens a cell or a page. */
.kicker {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 11px;
  letter-spacing: 0.12em;
  color: var(--color-accent);
  text-transform: uppercase;
}

/* --- drawn rules ----------------------------------------------------------
   The 2px dividers wipe in from the left as they enter the viewport, which
   animates the system's own structure rather than adding an effect on top of
   it. Without JavaScript the `.js-draw` class is never set and every rule is
   simply present, so this is additive only. */

.cell::before,
.g-ruled-top::before {
  content: '';
  position: absolute;
  top: -2px;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--color-divider);
  transform-origin: left;
}

.js-draw .cell::before,
.js-draw .g-ruled-top::before {
  transform: scaleX(0);
  transition: transform 0.55s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: var(--draw-delay, 0ms);
}
.js-draw .cell.lit::before,
.js-draw .g-ruled-top.lit::before { transform: scaleX(1); }

/* --- the index numeral ----------------------------------------------------
   The services carry a fixed 01–09 catalogue number. Set large and faint it
   reads as an index rather than a label, and turns nine cards into a body of
   work. Faint ink, not accent — nine red numerals would spend the accent. */

.index-num {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 46px;
  line-height: 0.82;
  letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--color-text) 16%, transparent);
}
.index-num-sm { font-size: 30px; margin-bottom: 10px; }

/* A service row: numeral in its own column, everything else beside it. */
.service-row {
  display: grid;
  grid-template-columns: 68px minmax(0, 1fr);
  gap: 0 20px;
  align-items: start;
}

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

/* Fluid display type. `.display` is the homepage scale; `.display-sm` is
   every interior page head. */
.display {
  font-size: clamp(46px, 7.2vw, 104px);
  line-height: 0.92;
  letter-spacing: -0.035em;
  text-transform: uppercase;
  margin: 0 0 var(--space-6);
  text-wrap: balance;
}
.display-sm {
  font-size: clamp(40px, 6vw, 76px);
  line-height: 0.95;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  margin: var(--space-3) 0 0;
}
.display-banner {
  font-size: clamp(38px, 6vw, 84px);
  line-height: 0.95;
  letter-spacing: -0.035em;
  text-transform: uppercase;
  margin: 0 0 var(--space-6);
  max-width: 22ch;
}

.h-section {
  font-size: 32px;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  margin: 0;
}
.h-sub {
  font-size: 25px;
  text-transform: uppercase;
  margin: 0 0 var(--space-3);
}

.lede { font-size: 17px; line-height: 1.5; max-width: 38ch; }
.note { font-size: 15px; margin: 0; }
.fine { font-size: 13px; margin: 0; }

/* The about page's opening paragraph, set a step above body copy. */
.about-lede { font-size: 19px; line-height: 1.45; margin: 0 0 var(--space-4); }
.team-name { font-size: 20px; margin: 0 0 2px; text-transform: uppercase; }

.measure { max-width: 46ch; }
.measure-wide { max-width: 58ch; }

/* The eyebrow above the homepage headline: discipline list, slash-separated. */
.eyebrow {
  display: flex;
  gap: 14px;
  align-items: center;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
  margin-bottom: var(--space-6);
}
.eyebrow-accent { color: var(--color-accent); }
.eyebrow-sep { opacity: 0.35; }

/* --- section furniture --------------------------------------------------- */

.section { padding-top: 48px; }
.section-lg { padding-top: 56px; }

/* The homepage header: headline left, standfirst right, both sitting on
   the baseline above the hero band. */
.hero-head { padding-block: 56px 40px; }
.hero-note { padding-bottom: var(--space-2); }

/* A grid that opens with its own rule rather than per-cell rules. */
.g-ruled-top {
  position: relative;
  border-top: 2px solid transparent;
  padding-top: var(--space-6);
}

/* The standard body block under a page head. */
.section-body { padding-block: var(--space-8); }
/* A trailing action row closing a page. */
.section-close { padding-top: 40px; }
.mb-3 { margin-bottom: 10px; }
.mb-1 { margin-bottom: var(--space-1); }
.mb-2 { margin-bottom: var(--space-2); }
.mb-5 { margin-bottom: 20px; }
.mb-4 { margin-bottom: 14px; }
.mt-3 { margin-top: var(--space-3); }
.ta-right { text-align: right; }
.strong { font-weight: 600; }
/* Money in a table cell reads in the heading face. */
.price-cell {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
}

.hr-flush { margin: 0 0 var(--space-4); }
.hr-lead { margin: 0 0 20px; }

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-6);
  margin-bottom: 20px;
}
.section-link { font-size: 13px; font-weight: 600; text-decoration: none; }

/* --- one rule per boundary ------------------------------------------------
   Two 2px dividers meeting at a section edge read as one 4px line, and where
   one of them is a drawn rule they fight. The rule at a boundary therefore
   belongs to the element *below* it whenever that element draws one — which
   `.cell` and `.g-ruled-top` always do. An element only closes itself when
   nothing below will: hence the `-flush` / `-closed` modifiers here.
   -------------------------------------------------------------------------- */

.page-head {
  padding: 48px var(--space-8) 28px;
  border-bottom: 2px solid var(--color-divider);
}
.page-head-plain { border-bottom: 0; }
/* For pages whose body opens straight onto ruled cells. */
.page-head-flush { border-bottom: 0; }

/* --- stats --------------------------------------------------------------- */

.stat-v {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 42px;
  letter-spacing: -0.03em;
  /* The values count up on scroll — tabular figures stop the width jittering
     while the digits change. */
  font-variant-numeric: tabular-nums;
}
.stat-v-sm { font-size: 38px; }
.stat-k {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

/* --- cards --------------------------------------------------------------- */

.work-card {
  display: block;
  color: inherit;
  text-decoration: none;
}
.work-card h3 { transition: color 0.15s ease; }
.work-card:hover h3 { color: var(--color-accent); }
.work-card:focus-visible { outline-offset: 4px; }

/* --- colour on reveal -----------------------------------------------------
   A deliberate exception to the system's "do not tint or colorize imagery".
   Work cards sit in black and white as the system requires — which is stricter
   than they were — and give up their real colour only on reveal. The framing:
   the work is in colour, the site is not.

   Where there is no hover (touch), a bare stylesheet shows colour outright,
   since an interaction nobody can perform is just a permanently grey photo.
   With JavaScript the `.js-reveal` gate swaps that for a scroll reveal: the
   card nearest the middle of the screen is the one in colour. */

.work-card .media {
  filter: grayscale(1) contrast(1.08);
  transition: filter 0.45s ease;
}

@media (hover: hover) {
  .work-card:hover .media,
  .work-card:focus-visible .media { filter: none; }
}

@media (hover: none) {
  .work-card .media { filter: none; }
  .js-reveal .work-card .media { filter: grayscale(1) contrast(1.08); }
  .js-reveal .work-card.in-view .media { filter: none; }
}

.card-tags {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.card-title-lg {
  font-size: 20px;
  margin: 10px 0 var(--space-1);
  text-transform: uppercase;
}
.card-title-xl {
  font-size: 25px;
  margin: var(--space-3) 0 6px;
  text-transform: uppercase;
}
/* The tighter heading used inside ruled cells (services, team, journal). */
.cell-title {
  font-size: 20px;
  margin: var(--space-2) 0 6px;
  text-transform: uppercase;
  letter-spacing: -0.01em;
}
.cell-title-lg {
  font-size: 25px;
  margin: 10px 0 var(--space-2);
  text-transform: uppercase;
  letter-spacing: -0.015em;
}
.card-line { font-size: 14px; margin: 0; }

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

/* Every photograph mounts in a ratio-locked frame. `.media-empty` is the
   unfilled state carried over from the canvas's image slots — a labelled
   placeholder rather than a broken image. */
.media {
  position: relative;
  overflow: hidden;
  background: var(--color-neutral-200);
}
.media > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.media-4x3 { aspect-ratio: 4 / 3; }
.media-3x2 { aspect-ratio: 3 / 2; }
.media-3x4 { aspect-ratio: 3 / 4; }
.media-1x1 { aspect-ratio: 1 / 1; }

.media-empty {
  display: grid;
  place-items: center;
  padding: var(--space-4);
  border: 2px dashed var(--color-divider);
  background: var(--color-surface);
}
.media-empty span {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  color: var(--color-neutral-600);
}

/* Inside a `.media-band` the frame fills the band instead of holding its
   own ratio. */
.media-fill {
  position: absolute;
  inset: 0;
  aspect-ratio: auto;
}

/* Full-bleed banded image, ruled top and bottom. */
.media-band {
  position: relative;
  height: 62vh;
  min-height: 380px;
  border-top: 2px solid var(--color-divider);
}
.media-band-sm { height: 56vh; min-height: 340px; }
/* Closes the band itself, for the one case where nothing below draws a rule
   (a case study with no stats row). */
.media-band-closed { border-bottom: 2px solid var(--color-divider); }

/* The reel badge pinned to the corner of the hero band. */
.reel-badge {
  position: absolute;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  background: var(--color-neutral-900);
  color: var(--color-bg);
  padding: 14px 20px;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
}
.reel-badge::before {
  content: '';
  width: 12px;
  height: 14px;
  background: var(--color-accent);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  display: block;
}

/* --- hero video -----------------------------------------------------------
   The band takes a real loop when one exists, and a very slowly drifting still
   until then. The drift is the photograph moving, not a simulated video —
   about a 6% push over half a minute, slow enough to read as life rather than
   as an effect. */

.hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.08);
}

.hero-still img { animation: drift 34s ease-in-out infinite alternate; }
@keyframes drift {
  from { transform: scale(1.0) translate3d(0, 0, 0); }
  to { transform: scale(1.06) translate3d(-1.5%, -1%, 0); }
}

/* Auto-playing motion needs a control. Square, accent, bottom-left — the reel
   badge holds the opposite corner. */
.hero-pause {
  position: absolute;
  left: 0;
  bottom: 0;
  z-index: 3;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--color-neutral-900);
  cursor: pointer;
}
.hero-pause::before,
.hero-pause::after {
  content: '';
  position: absolute;
  top: 50%;
  width: 3px;
  height: 13px;
  margin-top: -6.5px;
  background: var(--color-bg);
}
.hero-pause::before { left: 15px; }
.hero-pause::after { right: 15px; }
/* Paused — the two bars become a single play triangle. */
.hero-pause[aria-pressed='true']::before {
  left: 15px;
  width: 11px;
  height: 13px;
  background: var(--color-accent);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}
.hero-pause[aria-pressed='true']::after { display: none; }
.hero-pause:hover { background: var(--color-accent); }
.hero-pause:focus-visible { outline: 2px solid var(--color-bg); outline-offset: -6px; }

/* Flags a hero still standing in for the reel. Development only. */
.hero-pending {
  position: absolute;
  left: 0;
  bottom: 0;
  z-index: 3;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 6px 12px;
  background: var(--color-accent-100);
  color: var(--color-accent-800);
}

/* The reel badge is a plain label until there's a reel to link to. */
.reel-badge-static { cursor: default; }

/* --- where we'll be next --------------------------------------------------
   A single ruled line under the hero band. Reads as an operated site rather
   than a published one. */

.next-event {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-4);
  padding: 12px var(--space-8);
  /* Top rule only — see "one rule per boundary" above. The stats grid below
     draws its own. */
  border-top: 2px solid var(--color-divider);
  font-size: 14px;
}
.next-event-label { flex: none; }
.next-event-name { font-family: var(--font-heading); font-weight: var(--font-heading-weight); }
.next-event-venue { color: var(--color-neutral-700); }
.next-event-date {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  color: var(--color-accent-700);
  font-variant-numeric: tabular-nums;
}
.next-event-more { font-size: 12px; margin-left: auto; }
.next-event-empty .hero-pending { position: static; margin-left: auto; }

/* --- the client marquee ---------------------------------------------------
   A type specimen, not decoration: fifteen years of names set in the heading
   face, moving slowly enough to read. The track is duplicated for a seamless
   loop, which is why it is hidden from assistive tech — a plain list beside it
   carries the same names. */

.marquee-band { margin-top: 56px; }

.marquee {
  display: flex;
  overflow: hidden;
  border-block: 2px solid var(--color-divider);
  padding-block: 16px;
  user-select: none;
}
.marquee-track {
  display: flex;
  flex: none;
  gap: var(--space-8);
  padding-right: var(--space-8);
  animation: marquee 52s linear infinite;
}
.marquee:hover .marquee-track,
.marquee:focus-within .marquee-track { animation-play-state: paused; }

.marquee-item {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 24px;
  letter-spacing: -0.015em;
  text-transform: uppercase;
  white-space: nowrap;
}
.marquee-item::after {
  content: '';
  display: inline-block;
  width: 8px;
  height: 8px;
  background: var(--color-accent);
  margin-left: var(--space-8);
  vertical-align: 0.28em;
}
@keyframes marquee { to { transform: translateX(-50%); } }

/* --- the red poster band --------------------------------------------------
   The one full field of accent the system allows. One line, no button — the
   ink banner at the foot of the page carries the call to action. */

.poster-band {
  margin-top: 56px;
  background: var(--color-accent);
  color: var(--color-bg);
  padding: clamp(52px, 8vw, 88px) var(--space-8);
}
.poster-line {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: clamp(34px, 5.6vw, 76px);
  line-height: 0.95;
  letter-spacing: -0.035em;
  text-transform: uppercase;
  margin: 0;
  max-width: 20ch;
  text-wrap: balance;
}

/* --- before / after comparison --------------------------------------------
   Two photographs stacked in one frame; the top one is clipped by --pos, and
   the divider and handle both read from the same variable so they can never
   disagree. clip-path rather than a width, so the clipped image is never
   squashed as the divider moves. */

.compare { --pos: 50%; }

.compare-frame {
  position: relative;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  border-top: 2px solid var(--color-divider);
  border-bottom: 2px solid var(--color-divider);
  touch-action: pan-y;
}

.compare-layer { position: absolute; inset: 0; }
.compare-layer img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The system prints photographs in black and white. Here it also isolates
     craft — framing, light, focus — from livery colour. */
  filter: grayscale(1) contrast(1.08);
  user-select: none;
  -webkit-user-drag: none;
}
.compare-before { clip-path: inset(0 calc(100% - var(--pos)) 0 0); }

.compare-placeholder {
  width: 100%;
  height: 100%;
  border: 0;
}
/* The two placeholder halves must read as different surfaces, or the divider
   is invisible before the photographs land. */
.compare-before .compare-placeholder { background: var(--color-neutral-300); }

.compare-divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--pos);
  width: 2px;
  margin-left: -1px;
  background: var(--color-accent);
  pointer-events: none;
}

.compare-tag {
  position: absolute;
  bottom: 0;
  z-index: 2;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 7px 12px;
  background: var(--color-neutral-900);
  color: var(--color-bg);
  pointer-events: none;
}
.compare-tag-before { left: 0; }
.compare-tag-after { right: 0; }

.compare-handle {
  position: absolute;
  top: 50%;
  left: var(--pos);
  z-index: 3;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--color-accent);
  cursor: grab;
}
/* Two triangles pointing out from the centre — the same clip-path idiom the
   reel badge uses. */
.compare-handle::before,
.compare-handle::after {
  content: '';
  position: absolute;
  top: 50%;
  width: 7px;
  height: 11px;
  margin-top: -5.5px;
  background: var(--color-bg);
}
.compare-handle::before { left: 12px; clip-path: polygon(100% 0, 100% 100%, 0 50%); }
.compare-handle::after { right: 12px; clip-path: polygon(0 0, 0 100%, 100% 50%); }
.compare-handle:active { cursor: grabbing; }
.compare-handle:focus-visible { outline: 2px solid var(--color-text); outline-offset: 3px; }

/* The handle only works with JavaScript; without it the frame is a static
   50/50 split, which still makes the point. */
.compare-handle { display: none; }
.js-compare .compare-handle { display: block; }
.js-compare .compare-frame { cursor: ew-resize; }

.compare-caption { margin-top: var(--space-3); max-width: 62ch; }

/* Flags a comparison that is still missing its photographs. Development only
   — the section does not render in production until both are set. */
.compare-pending {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 4px 10px;
  background: var(--color-accent-100);
  color: var(--color-accent-800);
  white-space: nowrap;
}

/* --- the poster banner ----------------------------------------------------
   The one place the system runs a full dark field: display type, one action,
   nothing else. */
.banner {
  margin-top: 64px;
  background: var(--color-neutral-900);
  color: var(--color-bg);
  padding: 64px var(--space-8);
}
.banner-sm { margin-top: 56px; padding: 56px var(--space-8); }
.banner-sm h2 {
  font-size: clamp(34px, 5vw, 68px);
  line-height: 0.95;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  margin: 0 0 20px;
  max-width: 24ch;
}
.banner p { font-size: 17px; max-width: 52ch; margin: 0 0 28px; }

/* --- pricing ------------------------------------------------------------- */

.price {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 28px;
  letter-spacing: -0.02em;
  margin-bottom: var(--space-2);
}
.price-lg {
  font-size: 44px;
  letter-spacing: -0.03em;
  color: var(--color-accent-700);
  margin-bottom: var(--space-3);
}

.includes { display: flex; flex-direction: column; gap: 6px; }
.includes-row {
  display: flex;
  gap: 10px;
  font-size: 13px;
  border-top: 1px solid var(--color-divider);
  padding-top: 6px;
}
.includes-row::before {
  content: '—';
  color: var(--color-accent);
  font-weight: 600;
}

/* Service name and its "from" price share a baseline. */
.service-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-4);
  margin-bottom: var(--space-2);
}
.service-from {
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* --- case study ---------------------------------------------------------- */

.case-gallery {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}
.case-gallery > .span-2 { grid-column: span 2; }

.pull-quote {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: clamp(26px, 3.4vw, 44px);
  line-height: 1.08;
  letter-spacing: -0.025em;
  max-width: 34ch;
}

.back-link { font-size: 13px; font-weight: 600; text-decoration: none; }
.case-title { margin: 0; max-width: 20ch; }
.case-tags { margin: 20px 0 var(--space-3); }
.mt-4 { margin-top: 14px; }
/* Gap between a case study's body sections. */
.mt-7 { margin-top: 28px; }

/* --- journal ------------------------------------------------------------- */

.journal-row {
  display: grid;
  grid-template-columns: 120px minmax(0, 1fr) 180px;
  gap: var(--space-8);
  align-items: start;
  padding: var(--space-6) 0;
}
.journal-title {
  font-size: 25px;
  margin: 0 0 var(--space-2);
  text-transform: uppercase;
  letter-spacing: -0.015em;
}

/* --- contact ------------------------------------------------------------- */

.booking-form { display: grid; gap: var(--space-4); }
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}
.need-options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-1);
}
.form-actions {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}
.form-sent {
  font-size: 13px;
  color: var(--color-accent-700);
  font-weight: 600;
}
.steps {
  font-size: 14px;
  padding-left: 18px;
  margin: 0;
  display: grid;
  gap: 6px;
}

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

.site-footer {
  margin-top: 64px;
  border-top: 2px solid var(--color-divider);
  padding: var(--space-8);
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) repeat(3, minmax(0, 0.6fr));
  gap: var(--space-8);
  align-items: start;
}
.footer-brand {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 18px;
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}
.footer-col {
  display: grid;
  gap: 6px;
  font-size: 13px;
}
.footer-col a { color: inherit; text-decoration: none; }
.footer-col a:hover { color: var(--color-accent); }
.footer-fine { font-size: 11px; }
.footer-blurb { font-size: 12px; margin: var(--space-2) 0 0; max-width: 34ch; }
.footer-legal { margin-top: 10px; }

/* --- utilities ----------------------------------------------------------- */

/* The price anchor under the homepage headline. Accent-700 rather than the
   accent itself — the system reserves the base accent for chrome and large
   type, and only the deep step clears contrast at paragraph size. */
.price-anchor {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 14px;
  line-height: 1.35;
  color: var(--color-accent-700);
  margin: 0;
}

.actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: var(--space-8);
}
.price-anchor + .actions { margin-top: var(--space-4); }
.btn-lg { padding: var(--space-3) 20px; }
.btn-xl { padding: 14px 22px; }
.stack-0 { margin: 0; }

/* Content for assistive tech only — the marquee's real list, and the label on
   the hero's pause control. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- responsive ---------------------------------------------------------- */

@media (max-width: 1040px) {
  .g-4, .g-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 760px) {
  .g-4, .g-3, .g-2,
  .split, .split-even, .split-lead, .split-case, .split-form,
  .journal-row, .field-row {
    grid-template-columns: minmax(0, 1fr);
  }
  .site-footer { grid-template-columns: 1fr 1fr; }
  /* The journal thumbnail is the first thing to go on a phone — the row
     reads as date + headline. */
  .journal-row .media { display: none; }
  .nav { flex-wrap: wrap; gap: var(--space-3); }
  .banner, .banner-sm { padding-inline: var(--space-6); }
  .gutter, .page-head { padding-inline: var(--space-6); }
  /* The index numeral stacks above its content rather than beside it. */
  .service-row { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .service-row .index-num { font-size: 32px; margin-bottom: var(--space-3); }
}

@media (prefers-reduced-motion: reduce) {
  /* Rules are present immediately; the count-up is skipped in site.js. */
  .js-draw .cell::before,
  .js-draw .g-ruled-top::before {
    transform: scaleX(1);
    transition: none;
  }
  /* The colour reveal and the nav compression both still happen — they carry
     state, not decoration — but they snap rather than ease. */
  .work-card .media,
  .nav,
  .nav-brand,
  .brand-dot {
    transition: none;
  }
  /* Ambient motion stops outright. The marquee keeps its names and can be
     scrolled by hand; the hero still holds its frame; site.js pauses the
     hero video. */
  .marquee-track { animation: none; }
  .marquee { overflow-x: auto; }
  .hero-still img { animation: none; }
}