/* ==========================================================================
   Jasper Briks — site.css
   One stylesheet, no build step. Tokens first, then base, then components in
   the order they appear on the page. See VISUAL.md for the design rules this
   implements; change the rule that's there rather than appending overrides.
   ========================================================================== */

/* ------------------------------------------------------------ 0. TYPEFACE */
/*
 * Inter, self-hosted from this server — no font CDN (CLAUDE.md rule 3).
 *
 * Two variable files cover every weight the site uses and the italics the
 * two-tone headings need, so the whole typeface is two requests. Subset to
 * Latin plus the characters actually used (— ’ € → ² ×): 740KB of full Inter
 * down to 210KB. Re-subset rather than dropping in the stock files if a new
 * language or symbol is ever needed.
 *
 * font-display: swap — the text is readable in the fallback immediately and
 * is never invisible while the font loads.
 */
@font-face {
  font-family: "Inter";
  src: url("../fonts/InterVariable.subset.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/InterVariable-Italic.subset.woff2") format("woff2");
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}

/* --------------------------------------------------------------- 1. TOKENS */
:root {
  --navy:      #324A6D;
  --blue:      #467FF7;
  --midnight:  #0F172A;
  --white:     #FFFFFF;
  --off:       #F8F9FA;

  /* Inter is self-hosted above; the system stack is only the swap fallback
     for the moment before it loads. */
  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --wrap: 1536px;
  --gutter: 1.5rem;

  --ease-in-soft: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-hover:   cubic-bezier(0.19, 1, 0.22, 1);

  --focus: 0 0 0 3px rgba(70, 127, 247, 0.55);
}

@media (min-width: 640px) {
  :root { --gutter: 2.5rem; }
}

/* ----------------------------------------------------------------- 2. BASE */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* The oversized ghost numerals and display type are wider than a phone on
     purpose; clip rather than let them create a horizontal scrollbar. */
  overflow-x: clip;
}

/*
 * Anchor targets clear the fixed header, which is 4.5rem tall (1rem padding +
 * a 2.5rem logo + 1rem). Without this, following #<slug> or #muurschilderingen
 * scrolls the heading right up under the bar and it reads as a broken link.
 */
:target { scroll-margin-top: 5.5rem; }

body {
  margin: 0;
  background: var(--navy);
  color: var(--white);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, picture, svg { display: block; max-width: 100%; }
img { height: auto; border: 0; }

a { color: inherit; text-decoration: none; }

h1, h2, h3, h4, p, ul, ol, figure, blockquote { margin: 0; }
ul, ol { padding: 0; list-style: none; }

::selection { background: var(--blue); color: var(--white); }

:focus-visible {
  outline: none;
  box-shadow: var(--focus);
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--blue);
  color: var(--white);
  padding: 0.75rem 1.25rem;
  font-size: 0.8rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.2em;
}
.skip-link:focus { left: 0; }

.wrap {
  width: 100%;
  max-width: min(var(--wrap), 100%);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* ----------------------------------------------------- 3. TYPE PRIMITIVES */

/* The signature heading: black, uppercase, very tight, two-tone, part italic. */
.display {
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.04em;
  line-height: 0.85;
  font-size: clamp(2.75rem, 9vw, 6rem);
  color: var(--white);
}
.display > span { display: block; }
.display .it { font-style: italic; }
.display .accent { color: var(--blue); font-style: normal; }
.display.dark { color: var(--navy); }
.display.xl { font-size: clamp(3rem, 13vw, 8.5rem); line-height: 0.8; }
.display.md { font-size: clamp(2rem, 5vw, 3.25rem); line-height: 0.95; }
.display.md .accent { display: inline; }
/*
 * Keeps a two-tone heading on a single line instead of stacking the halves —
 * "SAMENWERKEN?" split across two colours, "GESELECTEERD WERK" as two words.
 * The whitespace between the spans in the markup supplies the gap.
 */
.display.one-line > span { display: inline; }
/*
 * A smaller floor for a heading that is too wide for a phone at the normal
 * size — either a long single line ("GESELECTEERD WERK") or a single
 * unbreakable word ("MUURSCHILDERINGEN", ~10em on its own).
 *
 * A 390px screen less the 1.5rem gutters leaves 342px, so the floor has to
 * stay under ~35px. This matters more than it looks: `html` has
 * `overflow-x: clip`, so a heading that is too wide is silently CUT OFF at
 * the right edge rather than scrolling — it just looks like missing letters.
 *
 * Deliberately no `nowrap`: a multi-word heading should wrap rather than run
 * off the side. Use this on any .display whose longest word is over ~12
 * characters.
 */
.display.long { font-size: clamp(1.95rem, 8vw, 6rem); }

/* Tiny, heavily tracked labels — the counterweight to the giant headings. */
.eyebrow {
  display: block;
  font-size: 0.625rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.4em;
  line-height: 1.6;
  color: var(--white);
}
.eyebrow.accent     { color: var(--blue); }
.eyebrow.muted      { color: rgba(255, 255, 255, 0.6); }
.eyebrow.dark-muted { color: rgba(50, 74, 109, 0.6); }

.accent { color: var(--blue); }

.lede {
  font-size: clamp(1.0625rem, 2vw, 1.25rem);
  color: rgba(255, 255, 255, 0.72);
  line-height: 1.7;
  max-width: 38rem;
}

.prose p {
  font-size: clamp(1rem, 1.4vw, 1.1875rem);
  color: rgba(255, 255, 255, 0.72);
  line-height: 1.75;
  margin-bottom: 1.75rem;
}
.prose p:last-child { margin-bottom: 0; }
.prose.dark p { color: rgba(50, 74, 109, 0.82); }

/*
 * Long-form prose also needs subheads, lists and inline links — the privacy
 * statement is the first page with all three. Smaller and far less tracked
 * than a .display heading on purpose: these are signposts inside body copy,
 * not section titles.
 */
.prose h2 {
  font-size: clamp(1rem, 1.5vw, 1.1875rem);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  line-height: 1.3;
  color: var(--white);
  margin: 3rem 0 1rem;
}
.prose h2:first-child { margin-top: 0; }
.prose.dark h2 { color: var(--navy); }

.prose ul {
  margin: 0 0 1.75rem;
  padding-left: 1.25rem;
  font-size: clamp(1rem, 1.4vw, 1.1875rem);
  line-height: 1.75;
  color: rgba(255, 255, 255, 0.72);
}
.prose.dark ul { color: rgba(50, 74, 109, 0.82); }
.prose li { margin-bottom: 0.5rem; }
.prose li::marker { color: var(--blue); }

.prose a {
  color: var(--blue);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}
.prose a:hover { text-decoration-thickness: 2px; }

.prose blockquote {
  border-left: 2px solid var(--blue);
  padding-left: 1.5rem;
  font-style: italic;
  font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
  color: rgba(255, 255, 255, 0.85);
  line-height: 1.7;
  margin-bottom: 1.75rem;
}

.underline-accent {
  color: var(--white);
  text-decoration: underline;
  text-decoration-color: var(--blue);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.5em;
}

/* --------------------------------------------------------------- 4. BANDS */
.band {
  position: relative;
  padding: 5rem 0;
  overflow: hidden;
}
@media (min-width: 640px)  { .band { padding: 7rem 0; } }
@media (min-width: 1024px) { .band { padding: 9rem 0; } }

.band-dark  { background: var(--navy);  color: var(--white); }
.band-light { background: var(--white); color: var(--navy); }

/* The giant ghost section numerals. */
.band-numeral {
  position: absolute;
  top: 2rem;
  left: 1.5rem;
  font-size: 22vw;
  font-weight: 900;
  line-height: 1;
  color: rgba(255, 255, 255, 0.03);
  user-select: none;
  pointer-events: none;
  z-index: 0;
}
.band-numeral.right { left: auto; right: 1.5rem; }

.band > .wrap { position: relative; z-index: 1; }

.section-head { margin-bottom: 4rem; border-left: 4px solid var(--blue); padding-left: 2rem; }
.section-head .display { margin-bottom: 1rem; }
.section-head.dark { border-left: 0; padding-left: 0; }

/* -------------------------------------------------------------- 5. BUTTONS */
.btn {
  --fill: var(--blue);
  --fill-text: var(--white);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 1rem 2.25rem;
  /*
   * Explicitly transparent. Every .btn used to be an <a>, which has no
   * background, so this was never needed — until .btn went on a <button>,
   * which the browser gives a light grey `buttonface` background. That made
   * white-on-transparent .btn-outline render as white on light grey and all
   * but disappear. .btn-solid overrides this, as it should.
   */
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  border: 1px solid transparent;
  border-radius: 999px;
  overflow: hidden;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.6875rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  transition: transform 400ms var(--ease-hover), box-shadow 400ms var(--ease-hover);
  isolation: isolate;
}
/* The liquid fill: a panel parked below the button that slides up on hover. */
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--fill);
  transform: translateY(100%);
  transition: transform 500ms var(--ease-hover);
  z-index: -1;
}
.btn > span {
  position: relative;
  transition: color 350ms var(--ease-hover);
}
.btn:hover::before,
.btn:focus-visible::before { transform: translateY(0); }
.btn:hover > span,
.btn:focus-visible > span { color: var(--fill-text); }

.btn-outline {
  border-color: rgba(255, 255, 255, 0.3);
  color: var(--white);
  --fill: var(--blue);
  --fill-text: var(--white);
}
/*
 * The light-band counterpart to .btn-outline: navy label and hairline on
 * white, filling blue the same way. Use it for the secondary action on a
 * white band, so it reads as a button without outranking the blue CTA.
 */
.btn-outline-navy {
  border-color: rgba(50, 74, 109, 0.35);
  color: var(--navy);
  --fill: var(--blue);
  --fill-text: var(--white);
}
.btn-outline-navy:hover { border-color: var(--blue); }

.btn-solid {
  background: var(--blue);
  color: var(--white);
  --fill: var(--white);
  --fill-text: var(--blue);
}
.btn-solid:hover { box-shadow: 0 0 45px rgba(70, 127, 247, 0.4); }

.btn-lg { padding: 1.25rem 3rem; font-size: 0.8125rem; }
.btn-xl {
  padding: 1.75rem 3rem;
  font-size: clamp(0.9375rem, 2vw, 1.25rem);
  letter-spacing: 0.18em;
}
@media (min-width: 640px) { .btn-xl { padding: 2.25rem 5rem; } }

/* --------------------------------------------------------------- 6. HEADER */
/*
 * Sits ABOVE the mobile overlay (105), not below it. When it was behind, the
 * open menu covered its own close button and there was no way out.
 */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 120;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem var(--gutter);
  background: rgba(50, 74, 109, 0.85);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.logo {
  position: relative;
  z-index: 110;
  display: flex;
  align-items: center;
  height: 2.5rem;
  flex: none;
}
.logo-text {
  font-size: 1.1875rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.04em;
  color: var(--white);
  transition: opacity 450ms var(--ease-in-soft), transform 450ms var(--ease-in-soft);
}
.logo-mark {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 450ms var(--ease-in-soft), transform 450ms var(--ease-in-soft);
}
.logo-mark img {
  height: 2.25rem;
  width: auto;
  object-fit: contain;
  /* The wordmark art is dark; invert it to sit on the navy header. */
  filter: brightness(0) invert(1);
}
/* Swap only where there is a real pointer — on touch the logo just links home. */
@media (hover: hover) and (min-width: 1024px) {
  .logo:hover .logo-text { opacity: 0; transform: translateY(-14px); }
  .logo:hover .logo-mark { opacity: 1; transform: translateY(0); }
}
@media (min-width: 640px) { .logo-text { font-size: 1.375rem; } }

.nav-desktop { display: none; }
@media (min-width: 1024px) {
  .nav-desktop {
    display: flex;
    align-items: center;
    gap: 2.5rem;
  }
}

.nav-link {
  position: relative;
  font-size: 0.6875rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.3em;
  color: rgba(255, 255, 255, 0.85);
  padding-bottom: 0.4rem;
  transition: color 300ms ease;
}
.nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 0;
  background: var(--blue);
  box-shadow: 0 0 10px var(--blue);
  transition: width 350ms var(--ease-hover);
}
.nav-link:hover,
.nav-link.is-current { color: var(--blue); }
.nav-link:hover::after,
.nav-link.is-current::after { width: 100%; }

/* Burger */
.burger {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 0.375rem;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  z-index: 110;
}
.burger span {
  display: block;
  height: 2px;
  background: var(--white);
  transition: transform 300ms ease, opacity 300ms ease, width 300ms ease;
}
.burger span:nth-child(1) { width: 1.5rem; }
.burger span:nth-child(2) { width: 1rem; }
.burger span:nth-child(3) { width: 1.25rem; }
.burger[aria-expanded="true"] span:nth-child(1) { width: 1.5rem; transform: translateY(8px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { width: 1.5rem; transform: translateY(-8px) rotate(-45deg); }
@media (min-width: 1024px) { .burger { display: none; } }

/*
 * Mobile overlay. Lives OUTSIDE .site-header in the markup: the header has a
 * backdrop-filter, which makes it the containing block for fixed-position
 * descendants — nested inside, this was clipped to the header bar and looked
 * broken. `visibility` keeps it out of the tab order while closed.
 */
.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 105;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2rem;
  background: var(--midnight);
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform 450ms var(--ease-hover), visibility 0s linear 450ms;
}
.mobile-menu.is-open {
  transform: translateY(0);
  visibility: visible;
  transition: transform 450ms var(--ease-hover), visibility 0s;
}

/*
 * Lock the page behind any overlay (menu or lightbox). It has to be on <html>
 * as well as <body>: body-only locking still scrolls on iOS Safari.
 */
.scroll-locked, .scroll-locked body { overflow: hidden; }

/* While open, the bar blends into the overlay so only the X reads. */
.menu-open .site-header {
  background: transparent;
  border-bottom-color: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.mobile-menu > a:not(.btn) {
  font-size: 1.5rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.3em;
  color: var(--white);
  /* The 0.3em tracking adds a trailing space; pull it back so the column
     reads as centred rather than shunted left. */
  text-indent: 0.3em;
}
.mobile-menu .btn { margin-top: 1rem; }
@media (min-width: 1024px) { .mobile-menu { display: none; } }

/* ----------------------------------------------------------------- 7. HERO */
.hero {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100svh;
  padding: 7rem var(--gutter) 5rem;
  background: var(--navy);
  overflow: hidden;
}
.hero-media { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.hero-media picture, .hero-img { width: 100%; height: 100%; }
.hero-img {
  object-fit: cover;
  animation: reveal-img 1.8s var(--ease-in-soft) both;
}
/*
 * The hero's blue overlay: a flat panel of --navy at 0.75, carried over from
 * the original build (`bg-[#324A6D] opacity-75` in Hero.tsx). It is the one
 * place on this site an image is tinted — see VISUAL.md, "Image tone" — and
 * it is what makes the white headline legible over the mural's bright whites.
 * Keep it flat and keep it navy; this exact value is the agreed look.
 */
.hero-veil { position: absolute; inset: 0; background: var(--navy); opacity: 0.75; }

.hero-body { position: relative; z-index: 2; text-align: center; }

.hero-title {
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.045em;
  line-height: 0.82;
  font-size: clamp(3rem, 14vw, 11rem);
  color: var(--white);
  text-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
}
.hero-title > span { display: block; }

.hero-sub {
  margin: 2.25rem auto 0;
  max-width: 34rem;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.42em;
  color: rgba(255, 255, 255, 0.85);
}
@media (min-width: 640px) { .hero-sub { font-size: 0.9375rem; letter-spacing: 0.5em; } }

.reveal-text { animation: reveal-text 1.2s var(--ease-in-soft) both; animation-delay: var(--d, 0s); }

.scroll-cue {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}
.scroll-cue span {
  font-size: 0.5rem;
  text-transform: uppercase;
  letter-spacing: 0.6em;
  color: rgba(255, 255, 255, 0.5);
}
.scroll-rail {
  position: relative;
  width: 1px;
  height: 4.5rem;
  background: rgba(255, 255, 255, 0.15);
  overflow: hidden;
}
.scroll-rail i {
  position: absolute;
  inset: 0;
  background: var(--blue);
  animation: scroll-line 2s linear infinite;
}

/* ------------------------------------------------------ 8. WORK (HOMEPAGE) */
.work-grid {
  display: grid;
  grid-template-columns: 1fr;
  background: var(--navy);
  margin-top: 3rem;
}
@media (min-width: 640px) { .work-grid { grid-template-columns: repeat(2, 1fr); } }

/*
 * The tile's height is set here and nowhere else — the picture inside is
 * absolutely positioned, so this min-height is what every tile ends up being.
 * Deep on purpose: these are the only photographs on the home page and they
 * are the product.
 */
.work-tile {
  position: relative;
  display: block;
  min-height: 21rem;
  border: 0.5px solid rgba(255, 255, 255, 0.12);
  overflow: hidden;
}
@media (min-width: 640px)  { .work-tile { min-height: 28rem; } }
@media (min-width: 1024px) { .work-tile { min-height: 32rem; } }
@media (min-width: 1440px) { .work-tile { min-height: 36rem; } }

/*
 * The picture fills the tile absolutely so every tile is the same height
 * whatever shape the photo is. Left in normal flow it sets its own height from
 * the image's aspect ratio, and one portrait photo makes its tile tower over
 * the landscape ones. `height: 100%` doesn't save it either: the tile only has
 * a min-height, which is not a definite height for a percentage to resolve
 * against. Take the picture out of flow and the tile keeps its own height.
 */
.work-tile picture { position: absolute; inset: 0; display: block; }
.work-img { width: 100%; height: 100%; object-fit: cover; }

/*
 * The home tiles' entrance, carried over from the original build's
 * Portfolio.tsx: the photograph arrives desaturated, darkened, faded and
 * slightly overscaled, and settles to full colour at rest as it scrolls in.
 *
 * It sits on the <img> and owns filter, opacity AND transform together. That
 * is only safe because .work-tile no longer carries .reveal — one owner per
 * property, one entrance per tile. Don't put .reveal back on the tile: two
 * entrances on the same thing read as a stutter (WORKING-METHOD.md §9).
 */
.tile-in {
  filter: grayscale(1) brightness(0.6);
  opacity: 0.4;
  transform: scale(1.1);
  transition:
    filter 1200ms var(--ease-in-soft),
    opacity 1200ms var(--ease-in-soft),
    transform 1800ms var(--ease-in-soft);
}
.tile-in.is-visible {
  filter: grayscale(0) brightness(1);
  opacity: 1;
  transform: scale(1);
}
/* No JS, or reduced motion: resting state immediately, never stuck grey. */
.no-js .tile-in { filter: none; opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .tile-in { transition: none; }
}

.work-meta {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 0.25rem;
  padding: 1.5rem;
  background: linear-gradient(to top, rgba(50, 74, 109, 0.92), rgba(50, 74, 109, 0) 55%);
  pointer-events: none;
}
.work-meta h3 {
  font-size: clamp(1.25rem, 2.5vw, 1.625rem);
  font-weight: 900;
  font-style: italic;
  text-transform: uppercase;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--white);
}

/* Centres the "more work" button under the grid. */
.center-cue { display: flex; justify-content: center; margin-top: 4rem; }

/* ---------------------------------------------------------------- 9. LOGOS */
.logo-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
}
@media (min-width: 640px)  { .logo-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1024px) { .logo-grid { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 1440px) { .logo-grid { grid-template-columns: repeat(5, 1fr); } }

.logo-card {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 8rem;
  padding: 1.5rem;
  background: var(--white);
  border-radius: 1rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
  transition: transform 600ms var(--ease-hover), box-shadow 600ms var(--ease-hover);
}
@media (min-width: 640px) { .logo-card { height: 10rem; } }

/*
 * The logos come in wildly different aspect ratios, so "max-height: 100%"
 * made a wide wordmark huge next to a square mark. Capping BOTH axes to the
 * same optical box gives every logo the same presence on the wall.
 */
.logo-card picture {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}
.logo-img {
  width: auto;
  height: auto;
  max-width: 78%;
  max-height: 2.75rem;
  object-fit: contain;
}
@media (min-width: 640px)  { .logo-img { max-height: 3.25rem; } }
@media (min-width: 1440px) { .logo-img { max-height: 3.75rem; } }
/* Logos rest at full colour everywhere. The hover is the card lifting, only. */
@media (hover: hover) and (min-width: 1024px) {
  .logo-card:hover { transform: scale(1.05) rotate(1deg); z-index: 2; }
}

.logo-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: 8rem;
  padding: 1.5rem;
  text-align: center;
  background: var(--blue);
  border-radius: 1rem;
  box-shadow: 0 12px 30px rgba(70, 127, 247, 0.25);
  transition: background 450ms ease;
}
@media (min-width: 640px) { .logo-cta { height: 10rem; } }
.logo-cta-title {
  font-size: 0.75rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  line-height: 1.3;
  color: var(--white);
  transition: color 450ms ease;
}
.logo-cta-sub {
  font-size: 0.5625rem;
  font-weight: 700;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.8);
  transition: color 450ms ease;
}
.logo-cta:hover { background: var(--white); }
.logo-cta:hover .logo-cta-title { color: var(--blue); }
.logo-cta:hover .logo-cta-sub { color: rgba(50, 74, 109, 0.7); }

/* -------------------------------------------------------------- 10. VERHAAL */
.verhaal-grid { display: grid; gap: 3.5rem; align-items: center; }
@media (min-width: 640px) {
  .verhaal-grid { grid-template-columns: 1fr 1fr; gap: 4rem; }
  .verhaal-copy  { order: 1; }
  .verhaal-media { order: 2; }
}
@media (min-width: 1024px) { .verhaal-grid { gap: 7rem; } }

.verhaal-copy .eyebrow { margin-bottom: 1.5rem; }
.verhaal-copy .display { margin-bottom: 2.5rem; }

.arrow-link {
  display: inline-flex;
  align-items: center;
  gap: 1.5rem;
  margin-top: 3rem;
}
.arrow-link .eyebrow { transition: color 300ms ease; }
.arrow-link:hover .eyebrow { color: var(--blue); }
.arrow-rail {
  position: relative;
  display: block;
  width: 4rem;
  height: 2px;
  background: rgba(255, 255, 255, 0.25);
  overflow: hidden;
}
.arrow-rail::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--blue);
  transform: translateX(-100%);
  transition: transform 500ms var(--ease-hover);
}
.arrow-link:hover .arrow-rail::after { transform: translateX(0); }

.verhaal-media { position: relative; }
.portrait {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: 1.5rem;
  overflow: hidden;
  box-shadow: 0 30px 60px -20px rgba(0, 0, 0, 0.45);
}
.portrait picture, .portrait-img { width: 100%; height: 100%; }
/* Full colour at rest — Jasper asked for more colour across the site. */
.portrait-img {
  object-fit: cover;
  transition: transform 1s var(--ease-in-soft);
}
.portrait:hover .portrait-img { transform: scale(1.08); }

/*
 * The inset frame is a vignette, not a border: it works by matching the band
 * behind it. On navy that is navy; on a light band it has to be white, or it
 * reads as a heavy navy box instead of the soft edge it does on the homepage.
 */
.portrait-frame {
  position: absolute;
  inset: 0;
  border: 1.25rem solid rgba(50, 74, 109, 0.4);
  pointer-events: none;
  transition: border-color 600ms ease;
}
.portrait:hover .portrait-frame { border-color: rgba(50, 74, 109, 0.2); }

.band-light .portrait-frame { border-color: rgba(255, 255, 255, 0.85); }
.band-light .portrait:hover .portrait-frame { border-color: rgba(255, 255, 255, 0.6); }
.band-light .decor-square { border-color: rgba(50, 74, 109, 0.14); }

.portrait-tag {
  position: absolute;
  left: 0;
  bottom: 2.5rem;
  transform: rotate(-90deg);
  transform-origin: bottom left;
  background: var(--blue);
  padding: 0.75rem 1.5rem;
  font-size: 0.5rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.4em;
  color: var(--white);
  white-space: nowrap;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.25);
}

.decor-square {
  position: absolute;
  top: -1.5rem;
  right: -1.5rem;
  width: 8rem;
  height: 8rem;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 1rem;
  z-index: -1;
}
.decor-glow {
  position: absolute;
  bottom: -2.5rem;
  left: -2.5rem;
  width: 16rem;
  height: 16rem;
  background: rgba(70, 127, 247, 0.14);
  border-radius: 50%;
  filter: blur(60px);
  z-index: -1;
}

/* ---------------------------------------------------------- 11. TESTIMONIALS */
.quote-grid { display: grid; gap: 4rem; }
@media (min-width: 1024px) { .quote-grid { grid-template-columns: repeat(12, 1fr); } }

.quote { position: relative; padding-left: 3rem; }
@media (min-width: 1024px) {
  .quote { grid-column: 1 / span 7; padding-left: 5rem; }
  .quote.offset { grid-column: 6 / span 7; border-left: 1px solid rgba(50, 74, 109, 0.08); }
}
.quote::before {
  content: "\201C";
  position: absolute;
  top: -2.5rem;
  left: -0.5rem;
  font-size: 7rem;
  font-weight: 900;
  line-height: 1;
  color: rgba(70, 127, 247, 0.14);
  user-select: none;
}
.quote blockquote {
  font-size: clamp(1.375rem, 3.5vw, 2.25rem);
  font-weight: 900;
  font-style: italic;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--navy);
  margin-bottom: 2rem;
}
.quote figcaption { display: flex; align-items: center; gap: 1rem; }
.quote-rule { display: block; width: 3rem; height: 1px; background: var(--blue); flex: none; }
.quote figcaption strong {
  display: block;
  font-size: 0.8125rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--navy);
}
.quote figcaption em {
  display: block;
  font-style: normal;
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: rgba(50, 74, 109, 0.55);
}

/* ----------------------------------------------------------------- 12. HIRE */
.hire-band { text-align: center; }
.hire-ghost {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 38vw;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.05em;
  line-height: 1;
  color: rgba(255, 255, 255, 0.03);
  white-space: nowrap;
  user-select: none;
  pointer-events: none;
}
.hire-inner { position: relative; z-index: 1; }
.hire-head { margin-bottom: 4.5rem; }
.hire-head .eyebrow { margin-bottom: 1.5rem; letter-spacing: 0.5em; }

.steps {
  display: grid;
  gap: 2.5rem;
  max-width: 58rem;
  margin: 0 auto 4.5rem;
  text-align: left;
}
@media (min-width: 640px) { .steps { grid-template-columns: repeat(3, 1fr); gap: 3rem; } }

.steps li { border-top: 1px solid rgba(255, 255, 255, 0.14); padding-top: 1.5rem; }
.step-num {
  display: block;
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--blue);
  margin-bottom: 0.5rem;
}
.steps h3 {
  font-size: 0.8125rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--white);
  margin-bottom: 0.5rem;
  transition: color 300ms ease;
}
.steps li:hover h3 { color: var(--blue); }
.steps p {
  font-size: 0.8125rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.6);
}

.hire-cta { display: flex; flex-direction: column; align-items: center; gap: 2rem; }
.hire-cta .lede { text-align: center; }

.availability {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-top: 2rem;
  font-size: 0.625rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: rgba(255, 255, 255, 0.5);
}
.availability .rule { display: block; width: 2rem; height: 1px; background: rgba(255, 255, 255, 0.2); }

/* --------------------------------------------------------------- 13. FOOTER */
.site-footer {
  background: var(--navy);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  padding: 4rem 0 2.5rem;
}
.footer-top {
  display: flex;
  flex-direction: column;
  gap: 3rem;
  margin-bottom: 4rem;
}
@media (min-width: 640px) { .footer-top { flex-direction: row; justify-content: space-between; } }

.footer-name {
  font-size: 1.1875rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.03em;
  color: var(--white);
  margin-bottom: 0.75rem;
}
.footer-tagline {
  max-width: 18rem;
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.6);
}

.footer-cols { display: grid; grid-template-columns: repeat(2, auto); gap: 2.5rem 3rem; }
@media (min-width: 640px) { .footer-cols { grid-template-columns: repeat(3, auto); gap: 4rem; } }

.footer-col { display: flex; flex-direction: column; gap: 0.75rem; }
.footer-col .eyebrow { margin-bottom: 0.5rem; }
.footer-col a, .footer-plain {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: rgba(255, 255, 255, 0.65);
  line-height: 1.8;
  transition: color 300ms ease;
}
.footer-col a:hover { color: var(--white); }

.footer-social { display: flex; align-items: center; gap: 0.625rem; }
.footer-icon { width: 1rem; height: 1rem; flex: none; color: var(--blue); transition: color 300ms ease; }
.footer-social:hover .footer-icon { color: var(--white); }

.footer-bottom {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  padding-top: 2rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 0.5625rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.35em;
  color: rgba(255, 255, 255, 0.5);
  text-align: center;
}
@media (min-width: 640px) { .footer-bottom { flex-direction: row; justify-content: space-between; text-align: left; } }
/* The credit matches the copyright line exactly — same size, same uppercase,
   same tracking. It used to override both and read as a different thing. */
.footer-credit a { color: rgba(255, 255, 255, 0.7); transition: color 300ms ease; }
.footer-credit a:hover { color: var(--blue); }

/* ------------------------------------------------------------ 14. PAGE HEADS */
.page-head { position: relative; overflow: hidden; padding: 8rem 0 4rem; }
.page-head.light { background: var(--white); color: var(--navy); }
.page-head.dark  { background: var(--navy);  color: var(--white); }
.page-head.tall  { padding: 10rem 0 5rem; }
@media (min-width: 1024px) { .page-head.tall { padding: 13rem 0 6rem; } }
.page-head > .wrap { position: relative; z-index: 1; }

.head-wordmark {
  height: 2rem;
  width: auto;
  margin-bottom: 1.5rem;
  filter: brightness(0) invert(1);
}
@media (min-width: 640px) { .head-wordmark { height: 3rem; } }

.crumbs {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 2rem;
  font-size: 0.5625rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.4em;
  color: var(--blue);
}
.crumbs a { transition: color 300ms ease; }
.crumbs.light a:hover { color: var(--white); }
.crumbs:not(.light) a:hover { color: var(--navy); }
.crumbs span[aria-hidden] { opacity: 0.35; }
.crumbs span[aria-current] { color: rgba(255, 255, 255, 0.85); }
.page-head.light .crumbs span[aria-current] { color: var(--navy); }

.page-head-body { border-left: 1px solid rgba(50, 74, 109, 0.14); padding-left: 1.5rem; }
.page-head.dark .page-head-body { border-left: 0; padding-left: 0; }
.page-head-body.wide { max-width: 56rem; }
.page-head-body .display { margin-bottom: 0.75rem; }

.page-lede {
  margin-top: 2rem;
  max-width: 34rem;
  font-size: clamp(1.25rem, 3vw, 2rem);
  font-weight: 300;
  line-height: 1.25;
  color: rgba(255, 255, 255, 0.82);
}
.page-lede.tight {
  font-size: clamp(1.0625rem, 2vw, 1.375rem);
  font-weight: 500;
  line-height: 1.5;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  color: rgba(255, 255, 255, 0.7);
}

.page-tail { padding: 4rem 0; }
.page-tail.light { background: var(--white); border-top: 1px solid rgba(50, 74, 109, 0.08); }
.page-tail .wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  text-align: center;
}
@media (min-width: 640px) { .page-tail .wrap { flex-direction: row; justify-content: space-between; } }
.tail-link { transition: color 300ms ease; }
.tail-link:hover { color: var(--navy); }

/* -------------------------------------------------------- 15. CASE STUDIES */
.cases { background: var(--white); padding-bottom: 4rem; }
.case { padding-bottom: 5rem; }
@media (min-width: 1024px) { .case { padding-bottom: 8rem; } }

.case-grid { display: grid; grid-template-columns: 1fr; gap: 0.75rem; }
@media (min-width: 640px)  { .case-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .case-grid { grid-template-columns: repeat(4, 1fr); } }

.case-main {
  position: relative;
  overflow: hidden;
  background: #eceff3;
  min-height: 24rem;
}
@media (min-width: 640px)  { .case-main { grid-column: span 2; min-height: 30rem; } }
@media (min-width: 1024px) { .case-main { min-height: 40rem; } }
.case-main .zoom, .case-main picture, .case-main .case-img { width: 100%; height: 100%; }
/*
 * A video sits in the same slot as the main image but needs less height — it
 * is 16:9, not a wall. The 16:9 belongs to the video itself, not to the slot:
 * when the slot carried it, it collapsed to the video's height and left the
 * rest of the grid cell empty beside the copy panel.
 *
 * So the slot keeps full height and takes the same navy as .case-copy, and
 * the facade is centred on it. The two columns then read as a matched pair of
 * panels rather than a video floating above dead space.
 */
.case-video .case-main {
  min-height: 0;
  background: var(--navy);
  display: flex;
  align-items: center;
}
.case-video .video {
  height: auto;
  aspect-ratio: 16 / 9;
}

.case-serie {
  position: absolute;
  top: 1.5rem;
  left: 1.5rem;
  background: var(--navy);
  color: var(--white);
  padding: 0.4rem 1rem;
  font-size: 0.5625rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  z-index: 2;
}

.case-copy {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 2.5rem;
  background: var(--navy);
  color: var(--white);
  padding: 2.5rem;
}
@media (min-width: 640px)  { .case-copy { grid-column: span 2; padding: 3rem; } }
.case-copy h2 {
  font-size: clamp(1.75rem, 4vw, 3rem);
  font-weight: 900;
  font-style: italic;
  text-transform: uppercase;
  letter-spacing: -0.035em;
  line-height: 1;
  margin: 1.5rem 0 2rem;
}
/* Real paragraphs, authored as blank lines in the content. */
.case-text p {
  font-size: 0.9375rem;
  line-height: 1.75;
  color: rgba(255, 255, 255, 0.78);
  margin-bottom: 1.1rem;
}
.case-text p:last-child { margin-bottom: 0; }
.case-url {
  display: inline-block;
  margin-top: 1.5rem;
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--blue);
}
.case-url:hover { text-decoration: underline; }
.case-date {
  text-align: right;
  padding-top: 2rem;
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  font-size: 0.625rem !important;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.3em;
  color: var(--blue) !important;
}

.case-detail { overflow: hidden; background: #eceff3; height: 15rem; }
@media (min-width: 1024px) { .case-detail { height: 20rem; } }
.case-detail .zoom, .case-detail picture, .case-detail .case-img { width: 100%; height: 100%; }

.case-img { object-fit: cover; }

/* ------------------------------------------------------------- 16. GALLERY */
/*
 * Section titles were white-on-white before — legible navy now, since these
 * are the signposts for the two gallery groups.
 */
.section-title { background: var(--white); padding: 6rem var(--gutter) 3rem; text-align: center; }
.section-title h2 {
  font-size: clamp(1.125rem, 2.5vw, 1.5rem);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.45em;
  color: var(--navy);
}
.section-rule { display: block; width: 5rem; height: 2px; background: var(--blue); margin: 1.75rem auto 0; }
.section-note {
  max-width: 34rem;
  margin: 1.75rem auto 0;
  font-size: 0.9375rem;
  line-height: 1.7;
  color: rgba(50, 74, 109, 0.7);
}

.gallery { background: var(--white); padding-bottom: 6rem; }
.gallery-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.5rem; }
@media (min-width: 640px)  { .gallery-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1024px) { .gallery-grid { grid-template-columns: repeat(5, 1fr); } }

.gallery-cell { aspect-ratio: 1 / 1; overflow: hidden; background: #eceff3; }
.gallery-cell .zoom, .gallery-cell picture, .gallery-img { width: 100%; height: 100%; }
.gallery-img { object-fit: cover; transition: transform 700ms var(--ease-in-soft); }
@media (hover: hover) and (min-width: 1024px) {
  .gallery-cell:hover .gallery-img { transform: scale(1.08); }
}

/* ------------------------------------------------------------------ 17. BIO */
.bio-grid { display: grid; gap: 3rem; align-items: start; }
@media (min-width: 640px) { .bio-grid { grid-template-columns: 1fr 1fr; gap: 4rem; } }
@media (min-width: 1024px) { .bio-grid { gap: 5rem; } }

/*
 * Verhaal reuses the home page's .portrait component verbatim (Fred, 6 Nov
 * 2026) — rounded frame, inset border, rotated tag and decor. Only the
 * sticky behaviour is added here.
 */
.bio-media { position: relative; }
@media (min-width: 1024px) { .bio-media { position: sticky; top: 8rem; } }

.bio-copy { display: flex; flex-direction: column; gap: 3rem; }
.bio-title {
  font-size: clamp(1.625rem, 4vw, 2.25rem);
  font-weight: 900;
  font-style: italic;
  text-transform: uppercase;
  letter-spacing: -0.035em;
  color: var(--navy);
  margin-bottom: 1.5rem;
}
.bio-copy .prose strong.accent { color: var(--blue); font-weight: 700; }

.values { display: grid; gap: 2rem; }
.value {
  border-left: 4px solid var(--blue);
  padding: 1.5rem 0 1.5rem 2rem;
  background: var(--off);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
  transition: background 450ms ease, box-shadow 450ms ease;
}
.value:hover { background: var(--white); box-shadow: 0 16px 36px rgba(0, 0, 0, 0.08); }
.value h3 {
  font-size: clamp(1.125rem, 2.5vw, 1.5rem);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.03em;
  color: var(--navy);
  margin-bottom: 0.5rem;
}
.value p { font-size: 0.875rem; line-height: 1.7; color: rgba(50, 74, 109, 0.75); }

.bio-closer {
  padding-top: 2.5rem;
  border-top: 1px solid rgba(50, 74, 109, 0.12);
  font-size: 1.0625rem;
  font-style: italic;
  line-height: 1.7;
  color: rgba(50, 74, 109, 0.8);
}

.cta-band { text-align: center; }
.cta-band .display { margin-bottom: 3rem; }
.cta-meta { margin-top: 3rem; }

/* ------------------------------------------------------- 17b. BACKDROP TEXTURE */
/*
 * The contact and quote pages were flat navy. This lays one of Jasper's own
 * murals behind them, blurred to the point of being pure colour and texture,
 * plus a faint brick grid. Both are decorative: the navy underneath is what
 * guarantees the text contrast, so nothing breaks if either fails to load.
 */
.textured { position: relative; isolation: isolate; }
.textured::before,
.textured::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}
.textured::before {
  background-image: image-set(
    url("../img/brand/texture.webp") type("image/webp"),
    url("../img/brand/texture.jpg") type("image/jpeg")
  );
  background-image: url("../img/brand/texture.jpg");   /* older Safari/Firefox */
  background-size: cover;
  background-position: center;
  opacity: 0.22;
}
/* A brick course, drawn rather than downloaded. */
.textured::after {
  background-image:
    repeating-linear-gradient(0deg,
      rgba(255,255,255,0.045) 0 1px, transparent 1px 44px),
    repeating-linear-gradient(90deg,
      rgba(255,255,255,0.045) 0 1px, transparent 1px 96px);
  background-position: 0 0;
  opacity: 0.6;
  mask-image: radial-gradient(ellipse at 50% 0%, #000 0%, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse at 50% 0%, #000 0%, transparent 78%);
}
@supports (background-image: image-set(url("x.webp") type("image/webp"))) {
  .textured::before {
    background-image: image-set(
      url("../img/brand/texture.webp") type("image/webp"),
      url("../img/brand/texture.jpg") type("image/jpeg")
    );
  }
}

/* -------------------------------------------------------------- 18. CONTACT */
.tile-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.14);
}
@media (min-width: 640px)  { .tile-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .tile-grid { grid-template-columns: repeat(3, 1fr); } }

.tile {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 0.5rem;
  min-height: 8rem;
  padding: 1.75rem;
  background: var(--navy);
  transition: background 450ms ease, color 450ms ease;
}
@media (min-width: 640px) { .tile { min-height: 10rem; padding: 2.5rem; } }

.tile-label { letter-spacing: 0.35em; }
.tile-value {
  font-size: 1rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--white);
}
@media (min-width: 640px) { .tile-value { font-size: 1.125rem; } }

.tile-icon { width: 1.25rem; height: 1.25rem; margin-bottom: auto; color: rgba(255, 255, 255, 0.55); }

.tile-blue:hover { background: var(--blue); }
.tile-blue:hover .tile-label { color: var(--white); }

.tile-white:hover { background: var(--white); }
.tile-white:hover .tile-icon,
.tile-white:hover .tile-value { color: var(--navy); }
.tile-white:hover .tile-label { color: rgba(50, 74, 109, 0.6); }

.biz {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  margin-top: 3rem;
}
@media (min-width: 1024px) { .biz { flex-direction: row; align-items: center; gap: 2.5rem; } }
.biz-nums { display: flex; flex-wrap: wrap; gap: 0.5rem 2rem; margin-top: 0.5rem; font-family: var(--mono); font-size: 0.75rem; color: rgba(255, 255, 255, 0.7); }
.biz-rule { display: none; }
@media (min-width: 1024px) { .biz-rule { display: block; flex: 1; height: 1px; background: rgba(255, 255, 255, 0.1); } }
.biz-right { text-align: left; }
@media (min-width: 1024px) { .biz-right { text-align: right; } }
.biz-avail {
  margin-top: 0.5rem;
  font-size: 0.8125rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--white);
}

.contact-nudge { margin-top: 3.5rem; font-size: 0.9375rem; color: rgba(255, 255, 255, 0.65); }
.contact-nudge a { color: var(--blue); text-decoration: underline; text-underline-offset: 0.3em; }

/* ------------------------------------------------------------- 19. THE FORM */
.hire-page {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
  background: var(--navy);
  padding-top: 5rem;
  overflow: hidden;
}
.hire-page-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 2rem var(--gutter);
}
.back-link { transition: color 300ms ease; }
.back-link:hover { color: var(--white); }

.form-wrap {
  flex: 1;
  width: 100%;
  max-width: 48rem;
  margin: 0 auto;
  padding: 2rem var(--gutter) 5rem;
}

.form-head { margin-bottom: 3rem; }
.form-head .display { margin-bottom: 1.5rem; }
.form-intro { font-size: 1rem; line-height: 1.7; color: rgba(255, 255, 255, 0.65); max-width: 34rem; }

.enquiry { display: flex; flex-direction: column; gap: 2.5rem; }

/* Honeypot — off-screen, not display:none, so bots still see it. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.field { display: flex; flex-direction: column; gap: 0.75rem; }
.field label {
  font-size: 0.5625rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.4em;
  color: var(--blue);
}
.field label .n { opacity: 0.6; }

.field input,
.field textarea {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 0;
  padding: 0.5rem 0 0.75rem;
  font-family: inherit;
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--white);
  transition: border-color 300ms ease, box-shadow 200ms ease;
  resize: vertical;
}
@media (min-width: 640px) {
  .field input, .field textarea { font-size: 1.5rem; }
  .field input.big { font-size: 2rem; }
}
.field input::placeholder,
.field textarea::placeholder { color: rgba(255, 255, 255, 0.4); }
.field input:focus,
.field textarea:focus {
  outline: none;
  border-bottom-color: var(--blue);
  box-shadow: 0 2px 0 0 var(--blue);
}
.field.has-error input,
.field.has-error textarea { border-bottom-color: #FF8A8A; }

.field-error { font-size: 0.8125rem; font-weight: 500; color: #FFB3B3; }
.form-error-top {
  margin-bottom: 2rem;
  padding: 1rem 1.25rem;
  border-left: 3px solid #FF8A8A;
  background: rgba(255, 138, 138, 0.1);
  font-size: 0.9375rem;
  color: #FFD5D5;
}

.field-row { display: grid; gap: 2.5rem; }
@media (min-width: 640px) { .field-row { grid-template-columns: 1fr 1fr; gap: 3rem; } }

.form-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.5rem;
  padding-top: 1rem;
}
.form-actions .go { display: inline-block; transition: transform 300ms var(--ease-hover); }
.form-actions .btn:hover .go { transform: translateX(6px); }
.form-note { font-size: 0.8125rem; color: rgba(255, 255, 255, 0.55); }
.form-note a { color: var(--blue); }

.sent { display: flex; flex-direction: column; align-items: flex-start; gap: 1.75rem; padding: 3rem 0; }
.sent .display { margin-bottom: 0.5rem; }
.sent-alt { font-size: 0.9375rem; color: rgba(255, 255, 255, 0.6); }
.sent-alt a { color: var(--blue); }

.hire-page-foot { padding: 2rem var(--gutter); border-top: 1px solid rgba(255, 255, 255, 0.08); }

/* --------------------------------------------------------------- 20. ERROR */
.error-band { text-align: center; padding: 10rem 0 8rem; }
.error-band .display { margin: 1.5rem 0 2rem; }
.error-band .lede { margin: 0 auto; }
.error-actions { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: center; margin-top: 3rem; }

/* ------------------------------------------------- 21. SCROLL-REVEAL + MOTION */
/*
 * .reveal is the single scroll-reveal hook; site.js adds .is-visible with one
 * IntersectionObserver.
 *
 * It does ONE thing: a short fade and rise on the element itself. Never give it
 * filter, brightness or scale as well: when two rules animated filter on the
 * same images they fought over one property and the result read as glitchy.
 *
 * Nothing on this site filters a photo any more — every image rests at full
 * colour (see VISUAL.md, "Image tone"), so there is no greyscale rule for a
 * reveal to collide with. Don't reintroduce one here.
 */
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 600ms var(--ease-in-soft), transform 600ms var(--ease-in-soft);
  transition-delay: var(--d, 0s);
}
.reveal.is-visible { opacity: 1; transform: translateY(0); }

/* No JS? Show everything, immediately. */
.no-js .reveal { opacity: 1; transform: none; }

/*
 * Case-study photographs rest in greyscale and come to full colour as they
 * scroll into view. Driven by the same observer as .reveal, via .is-visible.
 *
 * This class owns `filter` and NOTHING else — .reveal owns opacity and
 * transform. Two rules animating filter on one image is exactly what made the
 * original build read as glitchy (WORKING-METHOD.md §9), so never add filter
 * to .reveal or a second desaturation rule to these images.
 *
 * It is scroll-driven, not hover-driven, which is why it is safe on a phone:
 * the colour arrives on its own. The mural gallery is deliberately excluded —
 * those squares are always full colour (VISUAL.md, "Image tone").
 */
.tone-in {
  filter: grayscale(1);
  /*
   * Long on purpose. The observer fires at 15% visible, so a short fade is
   * finished before the photo is properly in view and the grey is never
   * really seen. This wants to resolve while you are still scrolling toward
   * it, not the instant its top edge appears.
   */
  transition: filter 2600ms var(--ease-in-soft);
}
.tone-in.is-visible { filter: grayscale(0); }

/* No JS, or reduced motion: full colour immediately, never stuck grey. */
.no-js .tone-in { filter: none; }
@media (prefers-reduced-motion: reduce) {
  .tone-in { transition: none; }
}

@keyframes reveal-img {
  from { transform: scale(1.1); opacity: 0; }
  to   { transform: scale(1);   opacity: 1; }
}
@keyframes reveal-text {
  from { transform: translateY(40px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}
@keyframes scroll-line {
  from { transform: translateY(-100%); }
  to   { transform: translateY(100%); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .reveal {
    opacity: 1 !important;
    transform: none !important;
  }
  .scroll-cue { display: none; }
}

/* ------------------------------------------ 22. ZOOM, LIGHTBOX AND VIDEO */

/* The zoom button wraps a picture; it must not look like a button. */
.zoom {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  position: relative;
  overflow: hidden;
}
.zoom picture, .zoom img { width: 100%; height: 100%; object-fit: cover; }

.zoom-hint {
  position: absolute;
  right: 0.75rem;
  bottom: 0.75rem;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: rgba(50, 74, 109, 0.75);
  opacity: 0;
  transition: opacity 300ms ease;
  pointer-events: none;
}
.zoom-hint::before,
.zoom-hint::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  background: var(--white);
  transform: translate(-50%, -50%);
}
.zoom-hint::before { width: 0.75rem; height: 2px; }
.zoom-hint::after  { width: 2px; height: 0.75rem; }
@media (hover: hover) {
  .zoom:hover .zoom-hint { opacity: 1; }
}

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: rgba(15, 23, 42, 0.96);
  opacity: 0;
  transition: opacity 250ms ease;
}
.lightbox.is-open { opacity: 1; }
.lightbox[hidden] { display: none; }

.lightbox-figure {
  margin: 0;
  max-width: 100%;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}
/* contain, not cover: the whole frame is the point of opening it. */
.lightbox-figure img {
  max-width: 100%;
  max-height: 82vh;
  width: auto;
  object-fit: contain;
  border-radius: 4px;
}
.lightbox-figure figcaption {
  font-size: 0.625rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.3em;
  color: rgba(255, 255, 255, 0.6);
  text-align: center;
}

.lightbox-close,
.lightbox-nav {
  position: absolute;
  background: rgba(255, 255, 255, 0.1);
  border: 0;
  color: var(--white);
  cursor: pointer;
  border-radius: 50%;
  transition: background 250ms ease;
  line-height: 1;
}
.lightbox-close:hover,
.lightbox-nav:hover { background: var(--blue); }

.lightbox-close {
  top: 1rem;
  right: 1rem;
  width: 2.75rem;
  height: 2.75rem;
  font-size: 1.75rem;
}
.lightbox-nav {
  top: 50%;
  transform: translateY(-50%);
  width: 3rem;
  height: 3rem;
  font-size: 2rem;
}
.lightbox-nav.prev { left: 0.75rem; }
.lightbox-nav.next { right: 0.75rem; }
@media (min-width: 1024px) {
  .lightbox-nav.prev { left: 2rem; }
  .lightbox-nav.next { right: 2rem; }
}

/* Click-to-play video facade: nothing loads from YouTube until pressed. */
.video { position: relative; width: 100%; height: 100%; overflow: hidden; background: var(--midnight); }
.video picture, .video-poster { width: 100%; height: 100%; object-fit: cover; }
.video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

.video-play {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  width: 100%;
  background: rgba(50, 74, 109, 0.45);
  border: 0;
  cursor: pointer;
  transition: background 350ms ease;
}
.video-play:hover { background: rgba(50, 74, 109, 0.25); }

.video-icon {
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  background: var(--blue);
  position: relative;
  box-shadow: 0 10px 40px rgba(70, 127, 247, 0.45);
  transition: transform 350ms var(--ease-hover);
}
.video-icon::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 54%;
  transform: translate(-50%, -50%);
  border-left: 1.125rem solid var(--white);
  border-top: 0.6875rem solid transparent;
  border-bottom: 0.6875rem solid transparent;
}
.video-play:hover .video-icon { transform: scale(1.08); }

.video-label {
  font-size: 0.625rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.35em;
  color: var(--white);
}

/* The panorama block: full grid width, wide frame, shown end-to-end. */
/*
 * The panorama band shows the wall whole — the same framing you get when you
 * click into it. So it takes its height from the photograph rather than
 * forcing an aspect ratio and cropping to fill it: the StaPoTech wall is
 * roughly 4.6:1, and cropping that to 21:9 cut about half its width off,
 * which is the one thing this band exists to show.
 *
 * This deliberately overrides the generic `.zoom img { height: 100%;
 * object-fit: cover }` used by the square gallery cells.
 */
.case-panorama {
  grid-column: 1 / -1;
  overflow: hidden;
  background: #eceff3;
}
.case-panorama .zoom,
.case-panorama picture,
.case-panorama .pano-img {
  display: block;
  width: 100%;
  height: auto;
}
.case-panorama .pano-img { object-fit: contain; }

/* ------------------------------------------------------- 23. COOKIE BAR */
/*
 * Sits below the header (120) and below the mobile menu overlay (105), so it
 * can never cover the thing that closes them. Hidden via the `hidden`
 * attribute until site.js finds no stored choice, so it does not flash for a
 * returning visitor and is absent entirely without JS.
 */
.cookiebar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 90;
  background: rgba(15, 23, 42, 0.96);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  padding: 1.25rem var(--gutter);
}
.cookiebar[hidden] { display: none; }

.cookiebar-inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.25rem;
  max-width: var(--wrap);
  margin: 0 auto;
}
@media (min-width: 1024px) {
  .cookiebar-inner { flex-direction: row; align-items: center; gap: 2.5rem; }
}

.cookiebar-text {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.78);
}
.cookiebar-text strong { color: var(--white); font-weight: 700; }
.cookiebar-text a { color: var(--blue); text-decoration: underline; text-underline-offset: 0.2em; }

/* The actions never shrink below their content, and never wrap mid-button. */
.cookiebar-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; flex: none; }
.cookiebar-actions .btn { padding: 0.75rem 1.75rem; }

/* A video the visitor has declined: say so, and offer a way back. */
.video-blocked {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  height: 100%;
  margin: 0;
  padding: 2rem;
  text-align: center;
  font-size: 0.875rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.75);
  background: var(--midnight);
}
.video-allow {
  font: inherit;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: 0.625rem;
  color: var(--white);
  background: var(--blue);
  border: 0;
  border-radius: 999px;
  padding: 0.75rem 1.75rem;
  cursor: pointer;
}
.video-allow:hover { box-shadow: 0 0 30px rgba(70, 127, 247, 0.45); }
