/* ==========================================================================
   GHG Builders — site stylesheet
   Hand-authored static rebuild of the WordPress/Elementor site.
   Sections: 1 Fonts · 2 Tokens · 3 Reset · 4 Layout · 5 Type · 6 Buttons
             7 Header · 8 Hero · 9 Sections · 10 About · 11 Projects
             12 Gallery · 13 Lightbox · 14 Contact · 15 Legal · 16 CTA
             17 Footer · 18 Animations · 19 Responsive
   ========================================================================== */

/* 1 · Fonts ---------------------------------------------------------------
   Lato ships only 100/300/400/700/900. The original site declared 500/600,
   which browsers resolved to 400/700 — those real weights are used here.    */

@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/lato-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/lato-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/lato-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/lato-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Lato';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/lato-400-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Lato';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/lato-400-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Lato';
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/lato-700-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Lato';
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/lato-700-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* 2 · Tokens ------------------------------------------------------------- */

:root {
  /* palette — carried over from the Elementor global kit */
  --c-black: #000000;
  --c-blue: #21a9e1;
  --c-blue-hover: #4db5e4;
  --c-dark: #22252d;        /* footer / header / page-head */
  --c-dark-alt: #313540;    /* contact band / footer bottom bar */
  --c-text: #292b2c;
  --c-heading: #050706;
  --c-white: #ffffff;
  --c-muted: #a8a8a8;
  --c-rule: #7878782b;
  --c-rule-light: #ffffff14;
  --c-cta-overlay: rgba(30, 30, 30, 0.365); /* matches original Elementor overlay: rgba(30,30,30,0.73) on a 0.5-opacity layer */

  /* form feedback — solid fills, white text, both clear WCAG AA on the
     white form panel (5.0:1 and 5.4:1). Brand blue is only 2.7:1 against
     white, so it cannot carry white text here. */
  --c-ok: #15803d;
  --c-error: #c0392b;

  /* type scale */
  --f-body: 'Lato', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --t-hero: 56px;
  --t-hero-sub: 20px;
  --t-section: 29px;
  --t-body: 16px;
  --t-kicker: 14px;
  --t-nav: 14px;
  --t-topbar: 11px;

  /* metrics */
  --header-h: 84px;
  --wrap: 1140px;
  --measure: 500px;

  /* one hover fade for the whole site */
  --fade: 0.45s ease;
}

/* 3 · Reset -------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: var(--f-body);
  font-size: var(--t-body);
  font-weight: 400;
  line-height: 1.6;
  color: var(--c-text);
  background: var(--c-white);
  -webkit-font-smoothing: antialiased;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

a {
  color: var(--c-blue);
  text-decoration: none;
}

a:hover {
  color: var(--c-blue-hover);
}

h1,
h2,
h3,
p {
  margin: 0;
}

button {
  font: inherit;
  cursor: pointer;
}

:focus-visible {
  outline: 2px solid var(--c-blue);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 12px 20px;
  background: var(--c-white);
  color: var(--c-dark);
}

.skip-link:focus {
  left: 0;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* 4 · Layout ------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: 20px;
}

/* 5 · Type --------------------------------------------------------------- */

.kicker {
  font-size: var(--t-kicker);
  font-weight: 400;
  color: var(--c-blue);
  margin-bottom: 10px;
}

.h-section {
  font-size: var(--t-section);
  font-weight: 400;
  line-height: 1.2;
  color: var(--c-heading);
  margin-bottom: 10px;
}

.prose p {
  margin-bottom: 1em;
  text-align: justify;
}

.prose p:last-child {
  margin-bottom: 0;
}

/* 6 · Buttons ------------------------------------------------------------
   The original has four distinct button styles. They differ in weight,
   letter-spacing, border and padding, so they are kept separate here.      */

/* 1. Solid blue — "Get started", "You can learn more here", "View our work" */
.btn {
  display: inline-block;
  padding: 18px 24px;
  background: var(--c-blue);
  color: var(--c-white);
  font-size: 14px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 2px;
  text-transform: uppercase;
  border: 0;
  border-radius: 0;
  transition: background-color var(--fade), color var(--fade);
}

.btn:hover {
  background: var(--c-blue-hover);
  color: var(--c-white);
}

/* 2. Solid blue, bold, no tracking — the CTA band's "Contact Us Today!" */
.btn--bold {
  font-weight: 700;
  letter-spacing: 0;
}

/* 3. Solid blue with a hairline white keyline — gallery "View other projects".
      Hover fills with the dark grey rather than lightening. */
.btn--keyline {
  padding: 11px 20px;
  border: 1px solid var(--c-white);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0;
  transition: background-color var(--fade), border-color var(--fade),
    color var(--fade);
}

.btn--keyline:hover {
  background: var(--c-dark-alt);
  border-color: var(--c-dark-alt);
  color: var(--c-white);
}

/* text-only link button (homepage "Expertise / Market Ready / Our Work") */
.btn-text {
  display: inline-block;
  padding: 10px;
  background: transparent;
  color: var(--c-blue);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
  text-transform: uppercase;
  transition: color var(--fade);
}

.btn-text:hover {
  color: var(--c-text);
}

/* 4. Transparent with a heavy 3px keyline — project cards' "View more" */
.btn-outline {
  display: inline-block;
  padding: 11px 30px;
  background: transparent;
  border: 3px solid currentColor;
  border-radius: 1px;
  color: var(--c-white);
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase;
  transition: background-color var(--fade), border-color var(--fade),
    color var(--fade);
}

.btn-outline:hover {
  background: var(--c-blue-hover);
  border-color: var(--c-blue);
  color: var(--c-white);
}

/* 7 · Header -------------------------------------------------------------
   Fixed to the viewport on every page. Transparent while the hero is in
   view; `.is-stuck` (added by site.js once the hero scrolls past) switches
   it to a frosted dark bar.                                                */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  background: transparent;
  transition: background-color 0.3s ease, backdrop-filter 0.3s ease,
    box-shadow 0.3s ease;
}

.site-header.is-stuck {
  background: rgba(34, 37, 45, 0.72);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08), 0 8px 30px rgba(0, 0, 0, 0.28);
}

/* No backdrop-filter support: fall back to a near-opaque bar. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header.is-stuck {
    background: rgba(34, 37, 45, 0.96);
  }
}

.topbar {
  border-bottom: 1px solid var(--c-rule-light);
}

.topbar__inner {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 4px;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: 20px;
}

.topbar__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px;
  color: var(--c-white);
  font-size: var(--t-topbar);
  font-weight: 700;
  line-height: 1.5;
  text-transform: uppercase;
  /* slow cross-fade rather than a snap to blue */
  transition: color var(--fade), opacity var(--fade);
}

.topbar__link:hover {
  color: var(--c-blue);
  opacity: 0.8;
}

.topbar__link svg {
  width: 11px;
  height: 11px;
  fill: currentColor;
  flex: none;
  transition: fill var(--fade);
}

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  max-width: var(--wrap);
  margin-inline: auto;
  padding: 10px 20px;
}

.masthead__logo img {
  width: 190px;
  height: auto;
}

.nav {
  display: flex;
  align-items: center;
}

.nav__list {
  display: flex;
  align-items: center;
  gap: 5px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav__link {
  display: block;
  padding: 10px;
  color: var(--c-white);
  font-size: var(--t-nav);
  font-weight: 700;
  line-height: 1.5;
  text-transform: uppercase;
  transition: background-color var(--fade), color var(--fade);
}

.nav__link:hover {
  color: var(--c-white);
  background: rgba(255, 255, 255, 0.08);
}

.nav__link[aria-current='page'] {
  background: var(--c-blue);
  color: var(--c-white);
}

.nav__toggle {
  display: none;
  padding: 8px;
  background: transparent;
  border: 0;
  color: var(--c-white);
  line-height: 0;
}

.nav__toggle svg {
  width: 26px;
  height: 26px;
  fill: currentColor;
}

/* 8 · Hero --------------------------------------------------------------- */

/* Default hero: 60vh (expertise, about, contact-us). */
.hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 60vh;
  padding: var(--header-h) 0 40px;
  /* dark backdrop: the first image fades in from dark, never from white */
  background-color: var(--c-dark);
  overflow: hidden;
  isolation: isolate;
}

/* Full-height hero (home, market-ready). */
.hero--tall {
  min-height: 100vh;
  padding-bottom: 180px;
}

/* Ken Burns background slideshow (replaces Elementor's Swiper slideshow) */
.hero__slideshow {
  position: absolute;
  inset: 0;
  z-index: -2;
}

/* Load gate ----------------------------------------------------------------
   The hero slideshow starts hidden and un-animated. site.js waits for the
   first image to DECODE, then adds `.is-ready`: the container fades in and the
   cross-fade starts from a clean first frame, so the decode race can never
   flash through. A <noscript> block reveals it when JS is off; reduced motion
   reveals it instantly (in the reduced-motion block). Default-hidden means
   there is no flash of the un-gated state before JS runs.
   Scoped to .hero only — the below-the-fold .cta slideshow is unaffected. */
.hero .hero__slideshow {
  opacity: 0;
  transition: opacity 0.6s ease;
}

.hero .hero__slideshow.is-ready {
  opacity: 1;
}

/* Before JS runs the whole slideshow is hidden (container opacity 0) and every
   slide is opacity 0; site.js sets `.is-current` on the first slide and reveals
   the container. No base first-child opacity here — a slide is only ever shown
   by `.is-current`, which JS controls. */

/* Cross-fading slideshow.
   Slides are stacked with the FIRST on top (z-index set inline, N..1) and all
   sit at opacity 1 by default. A slide fades *out* to reveal the fully-opaque
   slide beneath it, and slide 1 fades back *in* on top at the loop seam.
   Fading one layer out over an opaque one keeps coverage at exactly 1 for the
   whole cycle — cross-fading two half-opaque layers would instead let 25% of
   the backdrop show through at the midpoint of every transition. */

/* JS-driven crossfade. Each slide fades via a class-toggled opacity
   transition, not an infinite @keyframes animation: this plays reliably on
   mobile Safari (which mishandles restarting a keyframe animation when its
   name is swapped in) and, unlike a long-running CSS animation, is not paused
   by iOS Low Power Mode. site.js toggles `.is-current` and layers the incoming
   slide above the outgoing one, so coverage stays complete through the fade. */
.hero__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1s ease;
  will-change: opacity;
  overflow: hidden; /* clip the zoomed image layer's overscan */
  /* Underlying copy of the image: a graceful fallback if ::before inherit is
     unsupported. It sits behind ::before, which draws the same image zoomed. */
  background-size: cover;
  background-position: center;
}

/* The Ken Burns zoom lives on a separate inner layer so it never shares a
   compositor layer with the opacity crossfade (fading and transforming the
   same element is what made the old hero feel heavy). The image is inherited
   from the slide's own background-image — set inline on slide 1 and by site.js
   on the rest — so no per-slide markup change is needed. 20s linear reads as a
   barely-perceptible drift, matching the original Elementor slideshow, instead
   of the previous fast 6s zoom. */
.hero__slide::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: inherit;
  background-size: cover;
  background-position: center;
  transform: scale(1);
  transition: transform 20s linear;
  will-change: transform;
}

.hero__slide.is-current {
  opacity: 1;
}

.hero__slide.is-current::before {
  transform: scale(1.3); /* matches Elementor Ken Burns "in"; only ~1.08 is seen per 5s slide */
}

/* First slide only. It is activated before its very first paint, so a
   class-triggered transition can start already at its end value and sit still
   (the "first image doesn't zoom while the rest do" bug). A one-shot keyframe
   animation always plays from 0%, independent of when the class lands, so the
   opening slide zooms identically to the others. site.js removes `is-kenburns`
   once it finishes, letting the normal is-current transition drive later loops. */
@keyframes hero-kenburns-in {
  from { transform: scale(1); }
  to   { transform: scale(1.3); }
}

.hero__slide.is-kenburns::before {
  animation: hero-kenburns-in 20s linear forwards;
}

/* single static background image */
.hero__slide--static {
  opacity: 1;
  transition: none;
}

.hero__slide--static::before {
  transform: none;
  transition: none;
}

.hero__overlay {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--c-black);
  opacity: 0.3;
}

/* The title runs full width; only the subtitle is held to a 500px measure. */
.hero__content {
  width: 100%;
  padding: 1em;
  text-align: center;
}

.hero__title {
  font-size: var(--t-hero);
  font-weight: 700;
  letter-spacing: 1.5px;
  line-height: 1.2;
  color: var(--c-white);
  padding-bottom: 20px;
}

.hero__sub {
  max-width: var(--measure);
  margin-inline: auto;
  font-size: var(--t-hero-sub);
  font-weight: 700;
  line-height: 1.4;
  color: var(--c-white);
  padding-bottom: 20px;
}

/* compact dark page header (our-work index, project pages, legal pages).
   Top padding clears the fixed header, matching the original's
   margin-top:-85px + padding-top:175px. */
.page-head {
  background: var(--c-dark);
  padding: 175px 0 80px;
  text-align: center;
}

/* kicker pads 10px below, title pads 10px above — 20px total, no flex gap */
.page-head__kicker {
  padding-bottom: 10px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--c-white);
}

.page-head__title {
  padding-top: 10px;
  font-size: 2em;
  font-weight: 700;
  line-height: 1.2;
  color: var(--c-white);
}

/* 9 · Sections ----------------------------------------------------------- */

/* two-column intro: copy left, masked photo right */
.split {
  display: flex;
  align-items: stretch;
  max-width: var(--wrap);
  margin: 190px auto 0;
  padding: 60px 0 100px;
}

/* gap: 20px is Elementor's inherited default container spacing, on top of the
   per-widget margins below (kicker 10, heading 10, copy 20). */
.split__copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 20px;
  width: 50.262%;
  padding: 60px 100px 0 40px;
}

.split__media {
  width: 49.694%;
}

.split__copy .btn {
  align-self: flex-start;
}

.split__copy .prose {
  margin-bottom: 20px;
}

/* Masked photo panel (homepage / expertise / market-ready).
   A single photo sits as the background; an opaque white PNG with two
   offset transparent windows is layered over it, so the photo shows
   through as two panels. Set the photo via --photo. */
.image-mask {
  background-image: var(--photo);
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  border: 1px solid var(--c-white);
}

.image-mask img {
  width: 100%;
  height: auto;
  display: block;
}

/* centred narrative block */
.centered {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-top: 190px;
  padding: 5rem 0 4rem;
  text-align: center;
}

.centered .kicker,
.centered .h-section {
  text-align: center;
}

.centered__body {
  max-width: 564px;
  margin-inline: auto;
}

/* link row — horizontal on desktop, stacked on mobile */
.centered__links {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  gap: 20px;
  margin-top: 20px;
}

/* 10 · About splits ------------------------------------------------------
   Full-bleed alternating rows: the image column runs to the page edge.     */

.about-split {
  display: flex;
  align-items: center;
  padding: 6rem 0 3rem;
}

.about-split--reverse {
  flex-direction: row-reverse;
}

.about-split__media {
  width: 66%;
  margin-right: 30px;
}

.about-split--reverse .about-split__media {
  margin-right: 0;
  margin-left: 30px;
}

.about-split__media img {
  width: 100%;
}

.about-split__copy {
  display: flex;
  flex-direction: column;
  gap: 20px;
  width: 33.956%;
  margin-left: 30px;
  margin-right: 50px;
}

.about-split--reverse .about-split__copy {
  margin-left: 50px;
  margin-right: 30px;
}

.about-split__copy .h-section {
  text-align: start;
}

/* 11 · Project cards (Our Work) ------------------------------------------ */

.projects {
  background: var(--c-dark);
}

.project-card {
  position: relative;
  display: flex;
  align-items: stretch;
  min-height: 461px;
  margin-bottom: 80px;
  background-color: var(--c-dark-alt);
  background-size: cover;
  background-position: center center;
  /* parallax — the original uses background-attachment:fixed on all 11 cards */
  background-attachment: fixed;
  isolation: isolate;
}

/* background-attachment:fixed is unreliable on touch platforms (iOS Safari
   renders it as a badly-scaled static image), so fall back to scroll there. */
@media (hover: none), (pointer: coarse) {
  .project-card {
    background-attachment: scroll;
  }
}

/* flat overlay, not a gradient */
.project-card::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--c-dark-alt);
  opacity: 0.41;
}

/* content is bottom-aligned and runs full width — not boxed.
   The 20px gap is Elementor's default container spacing (--widgets-spacing),
   which the original inherits rather than declares. */
.project-card__body {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-start;
  gap: 20px;
  width: 100%;
  padding: 14em 2em 2em;
  color: var(--c-white);
}

.project-card__title {
  font-size: 3.5em;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--c-white);
}

.project-card__sub {
  margin: 0 0 10px;
  font-size: 1em;
  font-weight: 400;
  line-height: 1.2;
  text-transform: uppercase;
  color: var(--c-white);
}

/* 12 · Gallery ----------------------------------------------------------- */

/* Full-bleed stacked photography — images run edge to edge at 100% width. */
.gallery {
  display: block;
  background: var(--c-white);
}

.gallery__item {
  display: block;
  width: 100%;
  border: 0;
  padding: 0;
  background: none;
  cursor: zoom-in;
}

.gallery__item img {
  width: 100%;
  height: auto;
}

.gallery__actions {
  padding: 60px 20px;
  text-align: center;
}

/* 13 · Lightbox ---------------------------------------------------------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.92);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0.25s ease;
}

.lightbox.is-open {
  opacity: 1;
  visibility: visible;
}

.lightbox__img {
  max-width: 92vw;
  max-height: 88vh;
  object-fit: contain;
}

.lightbox__btn {
  position: absolute;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  background: transparent;
  border: 0;
  color: var(--c-white);
  font-size: 30px;
  line-height: 1;
  opacity: 0.75;
  transition: opacity 0.2s ease;
}

.lightbox__btn:hover {
  opacity: 1;
}

.lightbox__btn--close {
  top: 12px;
  right: 16px;
}

.lightbox__btn--prev {
  left: 12px;
}

.lightbox__btn--next {
  right: 12px;
}

.lightbox__count {
  position: absolute;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  color: var(--c-white);
  font-size: 13px;
  letter-spacing: 1px;
  opacity: 0.75;
}

/* 14 · Contact ----------------------------------------------------------- */

/* Dark band; content boxed to 1140 but the background is full-bleed. */
.contact {
  background: var(--c-dark-alt);
}

.contact__inner {
  display: flex;
  align-items: stretch;
  gap: 10px;
  max-width: var(--wrap);
  margin-inline: auto;
  padding: 4rem 1rem 3rem;
}

.contact__col {
  width: 100%;
}

/* "Get In Touch" — an Elementor divider widget with inline text */
.divider-text {
  display: flex;
  align-items: center;
  gap: 20px;
  padding-block: 2px;
}

.divider-text__label {
  flex: none;
  color: var(--c-white);
  font-size: 1.6em;
  font-weight: 700;
  line-height: 1.2;
}

.divider-text__rule {
  width: 313px;
  height: 1px;
  border: 0;
  margin: 0;
  background: var(--c-white);
}

.contact__logo {
  width: 230px;
  padding: 1em 0 2em;
}

.contact__details {
  display: flex;
  align-items: stretch;
  padding-top: 20px;
}

/* 16px between the phone and email rows (client preference — the original
   worked out at 6px, which read as too tight once these became plain links
   rather than Elementor icon-boxes). */
.contact__col-details {
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 100%;
  padding-bottom: 30px;
}

.contact__detail {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--c-white);
  font-size: 18px;
  font-weight: 700;
  line-height: 1;
  transition: color var(--fade), opacity var(--fade);
}

.contact__detail:hover {
  color: var(--c-blue);
  opacity: 0.85;
}

.contact__detail svg {
  width: 20px;
  height: 20px;
  fill: var(--c-blue-hover);
  flex: none;
  transition: fill var(--fade);
}

.contact__hours {
  width: 65%;
  color: var(--c-white);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
}

/* white panel — holds the contact form, and the 404 signpost */
.contact__form-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  background: var(--c-white);
}

/* Contact form ------------------------------------------------------------
   Matched to the original Elementor form: white fields flush to the panel,
   a 1px #7878782B hairline, no radius, 2px between fields, and a full-width
   #4DB5E4 submit. (The Elementor kit declares #D08E02 for buttons; the form
   overrode it — #4DB5E4 is the colour the original actually rendered.) */

.form {
  width: 100%;
}

.form__fields {
  display: flex;
  flex-wrap: wrap;
}

/* Fields sit flush. The -1px pulls each row up so neighbouring 1px borders
   overlap into a single hairline rather than stacking into a 2px rule. */
.form__group {
  width: 100%;
  margin-bottom: -1px;
}

.form__group--half {
  width: 50%;
}

/* the left field of each pair overlaps its neighbour's border */
.form__group--half:nth-child(odd) {
  margin-right: -1px;
}

/* lift the focused field so its blue border is not painted over by the
   overlapping border of the field after it */
.form__group:focus-within {
  position: relative;
  z-index: 1;
}

.form__input,
.form__textarea {
  width: 100%;
  min-height: 40px;
  padding: 5px 14px;
  font-family: var(--f-body);
  font-size: 15px;
  line-height: 1.4;
  color: var(--c-text);
  background: var(--c-white);
  border: 1px solid var(--c-rule);
  border-radius: 0;
  transition: border-color var(--fade);
}

.form__textarea {
  display: block;
  min-height: 100px;
  resize: vertical;
}

/* 70% black. `opacity: 1` is required — Firefox dims placeholders by default,
   and the original's inherited 0.6 opacity computed to ~#AEAEAE on white,
   about 2.3:1 contrast (fails WCAG AA). This is ~8.6:1. */
.form__input::placeholder,
.form__textarea::placeholder {
  color: rgba(0, 0, 0, 0.7);
  opacity: 1;
}

.form__input:focus,
.form__textarea:focus {
  outline: none;
  border-color: var(--c-blue);
}

.form__input[aria-invalid='true'],
.form__textarea[aria-invalid='true'] {
  border-color: var(--c-error);
}

/* per-field error text: 5.4:1 on white — readable as-is, kept on the same
   token as the status fill so the two reds cannot drift apart. */
.form__error {
  margin: 4px 0 0;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--c-error);
}

.form__error[hidden] {
  display: none;
}

/* Honeypot: off-screen rather than display:none, so bots still fill it. */
.form__honey {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form__turnstile {
  margin: 12px 0 2px;
}

/* Same colour and hover as every other .btn on the site: blue, fading to the
   lighter accent. (The original form ran these the other way round.) */
.form__submit {
  width: 100%;
  min-height: 40px;
  padding: 12px 24px;
  background: var(--c-blue);
  color: var(--c-white);
  font-family: var(--f-body);
  font-size: 14px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: 2px;
  text-transform: uppercase;
  border: 0;
  border-radius: 0;
  transition: background-color var(--fade), color var(--fade), opacity var(--fade);
}

.form__submit:hover:not(:disabled) {
  background: var(--c-blue-hover);
  color: var(--c-white);
}

.form__submit:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Status message — success, or a top-level error from the endpoint.
   These sit on the WHITE form panel, so they are solid fills with white
   text. (They were previously tinted backgrounds with pale text, which was
   written for the dark band and computed to ~1.1:1 against the panel —
   effectively invisible.) */
.form__status {
  margin: 10px 0 0;
  padding: 12px 14px;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.4;
}

.form__status:empty {
  display: none;
}

.form__status--ok {
  background: var(--c-ok);
  color: var(--c-white);
}

.form__status--error {
  background: var(--c-error);
  color: var(--c-white);
}

.map {
  width: 100%;
  height: 50vh;
  border: 0;
  display: block;
}

/* 404 — "where to go next" list, occupies the form column */
.signpost {
  padding: 40px;
}

.signpost h2 {
  margin-bottom: 6px;
  font-size: var(--t-section);
  font-weight: 400;
  line-height: 1.2;
  color: var(--c-heading);
}

.signpost > p {
  margin-bottom: 24px;
}

.signpost__list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--c-rule);
}

.signpost__list li {
  border-bottom: 1px solid var(--c-rule);
}

.signpost__list a {
  display: block;
  padding: 16px 4px;
  color: var(--c-text);
  transition: color var(--fade), padding-left 0.3s ease;
}

.signpost__list a:hover {
  color: var(--c-blue);
  padding-left: 12px;
}

.signpost__list span {
  display: block;
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--c-blue);
}

/* 15 · Legal ------------------------------------------------------------- */

.legal {
  max-width: 860px;
  margin-inline: auto;
  padding: 70px 20px 90px;
}

.legal h2 {
  margin: 40px 0 12px;
  font-size: 22px;
  font-weight: 700;
  color: var(--c-heading);
}

.legal h2:first-of-type {
  margin-top: 0;
}

.legal h3 {
  margin: 28px 0 8px;
  font-size: 16px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--c-heading);
}

.legal p {
  margin-bottom: 1em;
}

.legal__updated {
  color: var(--c-blue);
  font-weight: 700;
}

.legal__sibling {
  margin-bottom: 28px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--c-rule);
  font-size: 15px;
}

/* 16 · CTA band ---------------------------------------------------------- */

.cta {
  position: relative;
  display: flex;
  align-items: stretch;
  min-height: 600px;
  padding: 0 1rem;
  overflow: hidden;
  isolation: isolate;
}

.cta__overlay {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--c-cta-overlay);
}

.cta__inner {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-end;
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  text-align: end;
}

.cta__title {
  margin-bottom: 10px;
  font-size: var(--t-section);
  font-weight: 400;
  line-height: 1.2;
  color: var(--c-white);
}

/* 17 · Footer ------------------------------------------------------------ */

.site-footer {
  background: var(--c-dark);
  padding: 2rem 0 1rem;
}

.site-footer__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
}

/* A real 1px line with equal space above and below, so the logo + tagline sit
   centred between the two rules. (Previously this was a zero-height box with a
   border-top and 15px of padding — which drew the line at the *top* of the box,
   leaving 10px above it and 40px below.)
   The 20px here is the only thing setting the gap around the logo/tagline
   block: 20px under the top rule, 20px over the bottom one. */
.site-footer__rule {
  width: 100%;
  height: 1px;
  margin: 20px 0;
  border: 0;
  background: var(--c-rule);
}

/* logo and tagline sit flush — no gap between them */
.site-footer__logo {
  width: 290px;
  max-width: 100%;
}

.site-footer__tagline {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--c-white);
  text-align: center;
}

.site-footer__nav {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0 40px;
  margin: 0 0 40px;
  padding: 0 1rem;
  list-style: none;
}

.site-footer__nav a {
  display: block;
  padding: 7px 8px;
  color: var(--c-white);
  font-size: 12px;
  font-weight: 400;
  text-transform: uppercase;
  transition: color var(--fade);
}

.site-footer__nav a:hover,
.site-footer__nav a[aria-current='page'] {
  color: var(--c-blue);
}

/* bottom bar: copyright left, secondary links right */
.site-footer__bar {
  background: var(--c-dark-alt);
}

.site-footer__bar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 0.5rem 1rem;
}

.site-footer__copy {
  font-size: 12px;
  font-weight: 700;
  color: var(--c-white);
}

.site-footer__meta {
  display: flex;
  align-items: center;
  gap: 0 40px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer__meta a {
  display: block;
  padding: 0 5px;
  color: var(--c-white);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  transition: color var(--fade);
}

.site-footer__meta a:hover {
  color: var(--c-blue);
}

/* 18 · Animations -------------------------------------------------------- */





/* Scroll reveals ---------------------------------------------------------
   FOUC-safe by construction: `.reveal` never appears in the static HTML or
   in a stylesheet rule that can match before JS runs — site.js adds it. If
   JS never runs, fails, or is blocked, every element simply stays visible.
   For elements already on screen at load, JS adds `.reveal` and `.in` in the
   same tick: the before-change style equals the after-change style, so no
   transition fires and there is no flash.                                   */

.reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.reveal.in {
  opacity: 1;
  transform: none;
}

/* Hero entrance — staggered by position, driven by .hero-in on the hero. */
.hero__content > .reveal:nth-child(1) {
  transition-delay: 0.08s;
}

.hero__content > .reveal:nth-child(2) {
  transition-delay: 0.22s;
}

.hero__content > .reveal:nth-child(3) {
  transition-delay: 0.36s;
}

/* Hover micro-interactions ----------------------------------------------- */

/* photos zoom inside a clipped wrapper */
.gallery__item,
.about-split__media {
  overflow: hidden;
}

.gallery__item img,
.about-split__media img {
  transition: transform 0.9s cubic-bezier(0.2, 0.6, 0.2, 1);
}

.gallery__item:hover img,
.about-split__media:hover img {
  transform: scale(1.04);
}

/* project bands: lighten the overlay so the photograph comes forward */
.project-card::before {
  transition: opacity 0.5s ease;
}

.project-card:hover::before {
  opacity: 0.24;
}

/* card-like rows lift with a soft shadow */
.signpost__list li {
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.signpost__list li:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.1);
}

/* logos: header/footer dim, contact logo scales a touch */
.masthead__logo img,
.site-footer__logo {
  transition: opacity var(--fade);
}

.masthead__logo:hover img,
.site-footer__logo:hover {
  opacity: 0.75;
}

.contact__logo {
  transition: transform var(--fade), opacity var(--fade);
}

.contact__logo:hover {
  transform: scale(1.03);
}

/* Reduced motion ---------------------------------------------------------
   Everything above is switched off: no reveals, no hero entrance, no hover
   transforms, no Ken Burns, no parallax.                                    */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .reveal,
  .reveal.in {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0s;
  }

  .gallery__item:hover img,
  .about-split__media:hover img,
  .contact__logo:hover,
  .signpost__list li:hover {
    transform: none;
  }

  .signpost__list li:hover {
    box-shadow: none;
  }

  /* reveal the hero immediately and show the first slide statically — the
     crossfade and its load gate are motion effects. site.js also skips the
     autoplay timer under reduced motion. */
  .hero .hero__slideshow {
    opacity: 1;
    transition: none;
  }

  .hero__slide {
    transition: none;
  }

  .hero__slide:first-child,
  .hero__slide.is-current {
    opacity: 1;
  }

  .project-card {
    background-attachment: scroll;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* 19 · Responsive -------------------------------------------------------- */

@media (max-width: 1024px) {
  .split {
    padding: 100px 10px;
  }

  .split__copy {
    padding: 0 40px 0 0;
  }

  .centered__body {
    padding-inline: 20px;
  }

  .project-card__title {
    font-size: 2.5em;
  }

  .about-split__media {
    width: 100%;
  }

  .about-split__copy {
    width: 70%;
  }

  .divider-text__label {
    font-size: 30px;
  }

  .contact__logo {
    width: 236px;
  }
}

@media (max-width: 768px) {
  :root {
    --t-hero: 40px;
    --t-hero-sub: 16px;
  }

  /* On phones only the slim contact strip stays pinned — a full 84px header
     eats too much of a small viewport. The masthead scrolls away with the
     page. NB: the header must drop its own backdrop-filter here, or it would
     become the containing block for the fixed .topbar inside it. */
  .site-header {
    position: absolute;
  }

  .site-header.is-stuck {
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    box-shadow: none;
  }

  .topbar {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 51;
    transition: background-color 0.3s ease, backdrop-filter 0.3s ease;
  }

  .site-header.is-stuck .topbar {
    background: rgba(34, 37, 45, 0.72);
    backdrop-filter: blur(14px) saturate(160%);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08);
  }

  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .site-header.is-stuck .topbar {
      background: rgba(34, 37, 45, 0.96);
    }
  }

  /* clear the now-fixed topbar */
  .masthead {
    padding-top: 47px;
  }

  .nav__toggle {
    display: block;
  }

  .nav__list {
    display: none;
    position: absolute;
    inset: 100% 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--c-white);
  }

  .nav__list.is-open {
    display: flex;
  }

  .nav__list li:not(:last-child) {
    border-bottom: 1px solid var(--c-dark-alt);
  }

  .nav__link {
    padding: 17px 25px;
    color: var(--c-text);
    text-align: center;
  }

  .nav__link:hover,
  .nav__link[aria-current='page'] {
    background: var(--c-white);
    color: var(--c-blue);
  }

  .masthead {
    position: relative;
  }

  /* the original keeps the logo at 190px on every breakpoint */

  .hero,
  .hero--tall {
    min-height: 50vh;
    padding: 10em 0 2em;
  }

  .split {
    flex-direction: column;
    margin-top: 0;
    padding: 4rem 0 2rem;
  }

  .split__copy,
  .split__media {
    width: 100%;
  }

  .split__copy {
    padding: 0 1rem;
  }

  .split__media {
    margin-top: 40px;
  }

  .centered {
    margin-top: 0;
    padding: 4rem 1rem 2rem;
  }

  .centered__links {
    flex-direction: column;
  }

  /* stack the about rows, image first in both */
  .about-split,
  .about-split--reverse {
    flex-direction: column;
    padding: 1em 0;
  }

  .about-split__media,
  .about-split--reverse .about-split__media {
    width: 100%;
    margin: 0 0 1em;
    order: -1;
  }

  .about-split__copy,
  .about-split--reverse .about-split__copy {
    width: 100%;
    margin: 0;
    padding: 1em;
  }

  .page-head {
    padding: 150px 0 50px;
  }

  .page-head__kicker {
    font-size: 14px;
  }

  .page-head__title {
    font-size: 1.5em;
  }

  .project-card {
    min-height: 40vh;
    margin-bottom: 3em;
  }

  .project-card__body {
    padding: 3em 1em;
  }

  .project-card__title {
    font-size: 2em;
  }

  .contact__inner {
    flex-direction: column;
    padding: 3rem 1rem 2rem;
  }

  .contact__details {
    flex-direction: column;
  }

  .contact__hours {
    width: 100%;
  }

  .page-head__title {
    padding-top: 0;
  }

  .divider-text__label {
    font-size: 25px;
  }

  .divider-text__rule {
    width: auto;
    flex: 1;
  }

  .cta {
    min-height: 420px;
    padding: 3rem 1rem;
  }

  .cta__inner {
    align-items: center;
    text-align: center;
  }

  .site-footer {
    padding: 3rem 0 1rem;
  }

  .site-footer__logo {
    width: 250px;
  }

  .site-footer__tagline {
    font-size: 13px;
  }

  .site-footer__nav {
    gap: 0 23px;
    margin-bottom: 23px;
  }

  .site-footer__bar-inner {
    /* column-reverse keeps the links row above the copyright (which is first in
       the DOM), so the four items sit horizontally and the copyright drops to
       its own line below. */
    flex-direction: column-reverse;
    gap: 12px;
    padding: 1rem;
  }

  /* Balanced two-by-two: two links per row (Instagram / Terms, then Privacy /
     Love this site), so the block reads horizontally and stays even on the
     narrowest phones instead of orphaning the fourth link on its own line. */
  .site-footer__meta {
    display: grid;
    grid-template-columns: 1fr 1fr;
    justify-items: center;
    gap: 4px 16px;
  }

  .site-footer__meta a {
    padding: 8px 6px;
    font-size: 11px;
  }

  .site-footer__copy {
    font-size: 11px;
    text-align: center;
  }

  .signpost {
    padding: 30px 20px;
  }

  .lightbox__btn--prev {
    left: 2px;
  }

  .lightbox__btn--next {
    right: 2px;
  }
}
