/* =========================================================================
   FORREST ARCHITECTS — Design System
   Calm, confident, bespoke. Warm neutral palette, generous whitespace,
   editorial type, and quiet interaction: text lights up on hover, imagery
   sits slightly veiled until you engage with it.
   ========================================================================= */

:root {
  /* ---- Palette (warm neutral, taupe accent carried over from brand) ---- */
  --color-bg: #1c1a17;
  --color-bg-alt: #242019;
  --color-ink: #f7f4ef;
  --color-ink-soft: #cac2b4;
  --color-ink-faint: #9a9184;
  --color-line: rgba(247, 244, 239, 0.12);
  --color-line-strong: rgba(247, 244, 239, 0.24);
  --color-accent: #af9f91;
  --color-accent-deep: #8a7a68;
  --color-paper: #fbf9f6;

  /* ---- Type ---- */
  /* Calibri (Windows/Office) with Arial as the fallback everywhere else —
     both are system fonts, so there's no webfont to download. Headings and
     body share one family; hierarchy comes from weight, size and spacing. */
  --font-serif: Calibri, Carlito, Arial, "Helvetica Neue", Helvetica, sans-serif;
  --font-sans: Calibri, Carlito, Arial, "Helvetica Neue", Helvetica, sans-serif;
  /* Canva Sans itself can't be licensed for use outside Canva's own editor,
     so the wordmark and menu (the two places that used the "FORREST
     ARCHITECTS" logotype look) use Work Sans instead — a free, similarly
     plain, geometric grotesque — loaded from Google Fonts. Everything else
     stays on the system Calibri/Arial stack above. */
  --font-brand: "Work Sans", Calibri, Arial, "Helvetica Neue", Helvetica, sans-serif;

  /* ---- Motion ---- */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-soft: cubic-bezier(0.22, 0.61, 0.36, 1);
  --dur-quick: 0.35s;
  --dur-med: 0.6s;
  --dur-slow: 1.1s;
  --dur-kenburns: 7s;
  --dur-crossfade: 1.8s;

  /* ---- Layout ---- */
  /* Reduced per client request — matches the header/Work-toolbar's own
     (already-tightened) side inset, so body copy, the footer and section
     CTAs sit at the same distance from the edge instead of further in. */
  --gutter: clamp(1rem, 2.5vw, 2rem);
  /* Widened per client request — on large/wide monitors the old 1440px cap
     left a big empty margin either side of the CTA ("Have a site in mind?")
     and footer even after the --gutter reduction above, since that inset
     only applies inside this cap. 1800px keeps a sensible line-length limit
     on very wide screens while noticeably closing that gap. */
  --max-width: 1800px;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-quick: 0.001s;
    --dur-med: 0.001s;
    --dur-slow: 0.001s;
    --dur-kenburns: 0.001s;
    --dur-crossfade: 0.001s;
  }
}

/* ---------------------------------------------------------------------- */
/* Reset & base                                                           */
/* ---------------------------------------------------------------------- */
* {
  box-sizing: border-box;
}

html {
  /* Lenis (js/main.js -> initSmoothScroll) now owns scroll easing site-
     wide, so the native CSS smooth-scroll is turned off here — running
     both at once tends to fight each other on any jump-to-anchor. */
  scroll-behavior: auto;
}

/* ---------------------------------------------------------------------- */
/* Lenis smooth-scroll — minimal required styles from the library itself  */
/* ---------------------------------------------------------------------- */
html.lenis,
html.lenis body {
  height: auto;
}

.lenis:not(.lenis-autoToggle).lenis-stopped {
  overflow: clip;
}

.lenis.lenis-smooth iframe {
  pointer-events: none;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-ink);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* Sitewide vignette, per client request, for a moodier feel — a fixed
   overlay so it reads the same on every page without editing each HTML
   file individually. Centre stays fully clear; only the outer edges/
   corners darken. pointer-events: none so it never blocks clicks, and it
   sits above ordinary content but below the page-load veil and custom
   cursor dot so those still work as before. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 900;
  pointer-events: none;
  background: radial-gradient(ellipse at center, transparent 55%, rgba(0, 0, 0, 0.45) 100%);
}

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

a {
  color: inherit;
}

h1, h2, h3, h4 {
  font-family: var(--font-serif);
  font-weight: 700;
  line-height: 1.15;
  margin: 0;
  letter-spacing: 0;
}

p {
  margin: 0;
}

ul, ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

button {
  font-family: inherit;
  background: none;
  border: none;
  cursor: pointer;
  color: inherit;
}

::selection {
  background: var(--color-accent);
  color: var(--color-paper);
}

:focus-visible {
  outline: 1px solid var(--color-accent-deep);
  outline-offset: 4px;
}

.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--color-ink-faint);
}

.eyebrow::before {
  content: "";
  width: 22px;
  height: 1px;
  background: var(--color-accent-deep);
}

/* ---------------------------------------------------------------------- */
/* Quiet, seamless page-load / transition veil                           */
/* ---------------------------------------------------------------------- */
.page-veil {
  position: fixed;
  inset: 0;
  background: var(--color-bg);
  z-index: 999;
  transform: translateY(0);
  transition: transform var(--dur-med) var(--ease), opacity var(--dur-med) var(--ease);
  pointer-events: none;
}

.page-veil.is-hidden {
  opacity: 0;
  transform: translateY(-2%);
}

.page-veil.is-leaving {
  opacity: 1;
  pointer-events: all;
}

/* ---------------------------------------------------------------------- */
/* Custom cursor (desktop, fine-pointer only)                            */
/* ---------------------------------------------------------------------- */
.cursor-dot {
  position: fixed;
  top: 0;
  left: 0;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: var(--color-accent-deep);
  pointer-events: none;
  z-index: 1000;
  transition: transform var(--dur-quick) var(--ease-soft), opacity var(--dur-quick) ease;
  opacity: 0;
  will-change: transform;
}

.has-fine-pointer .cursor-dot {
  opacity: 0.85;
}

.cursor-dot.is-active {
  transform: scale(4.5);
  background: rgba(138, 122, 104, 0.18);
  box-shadow: 0 0 0 1px rgba(138, 122, 104, 0.35);
}

/* ---------------------------------------------------------------------- */
/* Header + hidden nav toggle                                            */
/* ---------------------------------------------------------------------- */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Previously matched .container's max-width + auto-margin centring, so
     on wide screens the wordmark lined up with page content below (e.g.
     "Selected Projects"). Per client request the header itself now runs
     full viewport width instead, with its own smaller padding, so
     "Forrest Architects" and "Menu" sit closer to the browser's actual
     left/right edges — no longer tied to --max-width/--gutter. */
  width: 100%;
  padding: clamp(1.1rem, 2vw, 1.75rem) clamp(1rem, 2.5vw, 2rem);
  color: #f7f4ef;
}

/* Work page only, per client request: the "Forrest Architects" wordmark is
   removed from the header entirely (see work.html) so the page can start
   much closer to the top without an oversized gap under it — just the
   Menu toggle remains, so it needs to be pushed to the right explicitly
   now that it's the header's only child (space-between has nothing left
   to space between). */
.page-work .site-header {
  justify-content: flex-end;
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-family: var(--font-brand);
  /* Matched to the "Menu" label's size and weight (.nav-toggle-label below)
     per client request — same size, same normal (non-bold) weight. Enlarged
     from the original 0.72rem across a few rounds per client request, then
     dialled back slightly from 0.92rem. */
  font-weight: 400;
  font-size: 0.86rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  text-decoration: none;
  /* Plain white, always — opt out of the header's mix-blend-mode: difference
     (used on the menu toggle for guaranteed contrast) since that trick makes
     the wordmark shift colour depending on what's behind it. A soft shadow
     keeps it legible over lighter parts of the video/photos. */
  color: #ffffff;
  mix-blend-mode: normal;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.4);
  /* --wordmark-scroll-opacity is written by initWordmarkFade() in js/main.js
     as the page scrolls, so the wordmark eases out rather than staying
     pinned over body content underneath it. The transition below is what
     makes that a soft fade instead of a jump; prefers-reduced-motion
     collapses --dur-quick to near-zero (see the top of this file), so it
     still simply disappears for those visitors, just without the animation. */
  opacity: var(--wordmark-scroll-opacity, 1);
  transition: opacity var(--dur-quick) ease;
}

.wordmark span {
  font-weight: 400;
  opacity: 1;
  margin-left: 0.55em;
}

/* The small mark next to the wordmark text — recoloured to a flat white
   with the original white area made transparent (see images/forrest-mark.png),
   so it reads cleanly over photos/video the same way the text does. */
.wordmark-mark {
  /* Fixed px, not em: kept at its own (already slightly reduced) size
     regardless of the wordmark text's font-size, per client request that
     the two scale independently. Enlarged from the original 9.73px across
     a few rounds per client request, then dialled back slightly from
     14px. */
  height: 12.5px;
  width: auto;
  display: block;
  flex-shrink: 0;
}

.wordmark:hover {
  opacity: 0.6;
}

/* Once scrolled far enough to be fully (or almost fully) faded, it's also
   taken out of the tab order / click target — an invisible link should
   never be focusable. */
.wordmark.is-scroll-hidden {
  pointer-events: none;
}

/* Hide the wordmark while the full-screen menu is open — it was sitting
   right on top of "HOME", the first link in the nav list. */
body.nav-open .wordmark {
  opacity: 0;
  pointer-events: none;
}

.nav-toggle {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.4rem 0;
  color: inherit;
  /* Guarantees contrast against whatever's behind it (photo, video, dark
     nav panel) without needing an explicit colour per background. This used
     to live on .site-header itself, but that also caught the wordmark,
     which now needs a fixed, literal white instead — see .wordmark above. */
  mix-blend-mode: difference;
  /* Fades out on scroll in lockstep with the wordmark — same
     --wordmark-scroll-opacity variable, written by initWordmarkFade() in
     js/main.js, and the same transition so neither leads or lags. */
  opacity: var(--wordmark-scroll-opacity, 1);
  transition: opacity var(--dur-quick) ease;
}

/* Once faded out, take it out of the tab order / click target too — same
   reasoning as .wordmark.is-scroll-hidden above. */
.nav-toggle.is-scroll-hidden {
  pointer-events: none;
}

/* Keep the Menu button visible while the full-screen nav itself is open,
   even if the page had scrolled before it was opened — it's the only way
   to close the menu again. */
body.nav-open .nav-toggle {
  opacity: 1;
  pointer-events: auto;
}

.nav-toggle-label {
  /* "Menu"/"Close" removed from view per client request — just the icon
     lines now. Kept in the DOM (visually hidden, not display:none) so
     screen reader users still get a text label for the button. */
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.nav-toggle-label .close-word {
  display: none;
}

body.nav-open .nav-toggle-label .open-word {
  display: none;
}

body.nav-open .nav-toggle-label .close-word {
  display: inline;
}

.nav-toggle-icon {
  display: inline-flex;
  flex-direction: column;
  /* Enlarged from the original 5px/22px in two rounds per client request. */
  gap: 7px;
  width: 30px;
}

.nav-toggle-icon span {
  height: 1px;
  background: currentColor;
  transition: transform var(--dur-med) var(--ease), opacity var(--dur-med) var(--ease);
}

body.nav-open .nav-toggle-icon span:first-child {
  transform: translateY(3px) rotate(45deg);
}

body.nav-open .nav-toggle-icon span:last-child {
  transform: translateY(-3px) rotate(-45deg);
}

/* On mobile the header is just the wordmark and the menu icon — nothing
   else competing for space — so both can afford to sit slightly larger
   than on desktop, per client request. */
@media (max-width: 700px) {
  .wordmark {
    font-size: 0.82rem;
  }

  .wordmark-mark {
    height: 11.5px;
  }

  /* Per client request: mobile shows just the logo mark, not the "Forrest
     Architects" letters. Visually hidden rather than removed from the DOM
     (same technique as .nav-toggle-label above) so the link still has an
     accessible name for screen reader users on mobile. */
  .wordmark-text {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  .nav-toggle-icon {
    width: 26px;
    gap: 6px;
  }
}

/* ---------------------------------------------------------------------- */
/* Full-panel navigation — hidden until summoned                         */
/* ---------------------------------------------------------------------- */
.site-nav {
  position: fixed;
  inset: 0;
  z-index: 400;
  background: var(--color-bg);
  color: var(--color-paper);
  display: flex;
  align-items: flex-start;
  overflow-y: auto;
  visibility: hidden;
  clip-path: inset(0 0 100% 0);
  transition: clip-path var(--dur-slow) var(--ease), visibility 0s;
}

body.nav-open .site-nav {
  visibility: visible;
  clip-path: inset(0 0 0 0);
}

.site-nav-inner {
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  /* Top padding is set to clear the fixed header by the same amount on
     every page, rather than relying on vertical centering — which made
     "Home" sit right under the header on some window sizes and further
     away on others. */
  padding: clamp(6.5rem, 16vh, 9rem) var(--gutter) clamp(2rem, 6vh, 3rem);
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.5rem, 4vw, 3rem);
}

.site-nav-list li {
  border-top: 1px solid rgba(247, 244, 239, 0.14);
}

.site-nav-list li:last-child {
  border-bottom: 1px solid rgba(247, 244, 239, 0.14);
}

.site-nav-list a {
  display: flex;
  align-items: baseline;
  gap: 1.25rem;
  padding: 1.1rem 0;
  text-decoration: none;
  font-family: var(--font-brand);
  /* Not bold, per client request. */
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  /* Same size as the wordmark (see .wordmark above) rather than its own
     large display size. */
  font-size: 12px;
  color: var(--color-paper);
  transition: color var(--dur-med) var(--ease), padding-left var(--dur-med) var(--ease), letter-spacing var(--dur-med) var(--ease);
  opacity: 0.9;
}

.site-nav-list a .idx {
  font-family: var(--font-sans);
  font-size: 0.8rem;
  letter-spacing: 0.15em;
  color: var(--color-accent);
  opacity: 0.8;
}

.site-nav-list a:hover,
.site-nav-list a:focus-visible {
  color: var(--color-accent);
  padding-left: 0.6rem;
  opacity: 1;
  text-shadow: 0 0 26px rgba(175, 159, 145, 0.55);
}

/* Pinned to the bottom-right corner of the menu panel, mirroring "Close"
   top-right — rather than sitting in the document flow directly under the
   link list. On short/narrow viewports (see the media query near the other
   760px breakpoints below) it drops back into normal flow instead, so it
   can never overlap the link list above it when space is tight. */
.site-nav-footer {
  position: absolute;
  right: var(--gutter);
  bottom: clamp(1.5rem, 4vh, 3rem);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
  gap: 0.5rem;
  font-size: 0.85rem;
  color: rgba(247, 244, 239, 0.65);
}

.site-nav-footer a {
  text-decoration: none;
  transition: color var(--dur-quick) ease;
  border-bottom: 1px solid transparent;
}

.site-nav-footer a:hover {
  color: var(--color-accent);
  border-color: rgba(175, 159, 145, 0.5);
}

/* Narrow/short viewports (phones, especially landscape): the corner
   position risks overlapping "Contact" if the list runs long, so the
   footer drops back into normal flow below the list, left-aligned like
   the rest of the menu. */
@media (max-width: 700px), (max-height: 640px) {
  .site-nav-footer {
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
    text-align: left;
    gap: clamp(1.25rem, 4vw, 2rem);
    padding-bottom: clamp(1.5rem, 4vh, 3rem);
  }
}

/* ---------------------------------------------------------------------- */
/* Text links that "light up"                                            */
/* ---------------------------------------------------------------------- */
.link {
  position: relative;
  display: inline-block;
  text-decoration: none;
  color: var(--color-ink);
  transition: color var(--dur-med) var(--ease), letter-spacing var(--dur-med) var(--ease);
}

.link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 100%;
  bottom: -0.18em;
  height: 1px;
  background: var(--color-accent-deep);
  transition: right var(--dur-med) var(--ease), opacity var(--dur-med) ease;
  opacity: 0.7;
}

.link:hover,
.link:focus-visible {
  color: var(--color-accent-deep);
  letter-spacing: 0.01em;
  text-shadow: 0 0 20px rgba(175, 159, 145, 0.45);
}

.link:hover::after,
.link:focus-visible::after {
  right: 0;
}

/* ---------------------------------------------------------------------- */
/* Media / imagery — veiled until engaged                                */
/* ---------------------------------------------------------------------- */
.media {
  position: relative;
  overflow: hidden;
  background: var(--color-bg-alt);
}

.media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.82;
  filter: saturate(0.85) contrast(0.97) brightness(0.99);
  transform: scale(1.001);
  transition: opacity var(--dur-slow) var(--ease), filter var(--dur-slow) var(--ease), transform 1.4s var(--ease);
}

.media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 45%, rgba(255, 250, 240, 0.22), transparent 70%);
  opacity: 0;
  transition: opacity var(--dur-med) var(--ease);
  pointer-events: none;
}

.media:hover img,
.media:focus-within img {
  opacity: 1;
  filter: saturate(1) contrast(1) brightness(1);
  transform: scale(1.035);
}

.media:hover::after,
.media:focus-within::after {
  opacity: 1;
}

.media-caption {
  /* Full-bleed overlay so the project name can sit centred over the photo
     itself, rather than pinned to the bottom-left corner. */
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 1.25rem;
  color: var(--color-paper);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity var(--dur-med) var(--ease), transform var(--dur-med) var(--ease);
}

.media:hover .media-caption,
.media:focus-within .media-caption {
  opacity: 1;
  transform: translateY(0);
}

.media-caption h3 {
  /* Project names sized down per client request (was 15px). */
  font-size: 13px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.media-caption span {
  /* Category tag stays tucked in the corner, out of the way of the centred name. */
  position: absolute;
  right: 1.25rem;
  bottom: 1.25rem;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-accent);
}

/* ---------------------------------------------------------------------- */
/* Scroll reveal                                                          */
/* ---------------------------------------------------------------------- */
[data-reveal] {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 1s var(--ease), transform 1s var(--ease);
}

[data-reveal].in-view {
  opacity: 1;
  transform: translateY(0);
}

[data-reveal-delay="1"] { transition-delay: 0.08s; }
[data-reveal-delay="2"] { transition-delay: 0.16s; }
[data-reveal-delay="3"] { transition-delay: 0.24s; }
[data-reveal-delay="4"] { transition-delay: 0.32s; }

/* ---------------------------------------------------------------------- */
/* Buttons                                                                */
/* ---------------------------------------------------------------------- */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.9rem 0;
  font-size: 0.8rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--color-ink);
  border-top: 1px solid var(--color-line-strong);
  border-bottom: 1px solid var(--color-line-strong);
  transition: color var(--dur-med) var(--ease), border-color var(--dur-med) var(--ease), padding-left var(--dur-med) var(--ease);
}

.btn::before {
  content: "";
  width: 0;
  height: 1px;
  background: var(--color-accent-deep);
  transition: width var(--dur-med) var(--ease);
}

.btn:hover,
.btn:focus-visible {
  color: var(--color-accent-deep);
  border-color: var(--color-accent-deep);
  padding-left: 0.5rem;
}

.btn:hover::before,
.btn:focus-visible::before {
  width: 1.5rem;
}

.btn-solid {
  border: none;
  background: var(--color-bg);
  color: var(--color-paper);
  padding: 1rem 1.75rem;
  border-radius: 2px;
  transition: background var(--dur-med) var(--ease), color var(--dur-med) var(--ease), transform var(--dur-quick) var(--ease);
}

.btn-solid:hover,
.btn-solid:focus-visible {
  background: var(--color-accent-deep);
  color: var(--color-paper);
  transform: translateY(-1px);
}

/* ---------------------------------------------------------------------- */
/* Hero                                                                   */
/* ---------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}

.hero .media {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.hero .media img {
  opacity: 0.72;
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(28, 26, 23, 0.28) 0%, rgba(28, 26, 23, 0.12) 45%, rgba(28, 26, 23, 0.55) 100%);
  z-index: 0;
}

.hero-content {
  position: relative;
  z-index: 1;
  width: 100%;
  padding: clamp(6rem, 16vh, 9rem) var(--gutter) clamp(3rem, 8vh, 5rem);
  color: var(--color-paper);
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.hero-content .eyebrow {
  color: rgba(247, 244, 239, 0.75);
  font-size: 13px;
}

.hero-content .eyebrow::before {
  background: var(--color-accent);
}

.hero-title {
  font-size: clamp(2.6rem, 8vw, 6.4rem);
  max-width: 16ch;
}

.hero-sub {
  max-width: 42ch;
  font-size: clamp(1rem, 1.4vw, 1.15rem);
  color: rgba(247, 244, 239, 0.85);
}

/* Practice page hero heading — small and set on one line, overriding the
   large display size/wrap-width above. Below ~700px wide there isn't room
   for the whole sentence on one line without clipping it, so it wraps
   normally there instead. */
.practice-hero-title {
  font-size: 13px;
  max-width: none;
  white-space: nowrap;
}

@media (max-width: 700px) {
  .practice-hero-title {
    white-space: normal;
    max-width: 28ch;
  }
}

/* ---------------------------------------------------------------------- */
/* Home — full-bleed hero video                                          */
/* ---------------------------------------------------------------------- */
.hero-landing {
  min-height: 100vh;
}

/* Background video — the only hero visual now (no fallback still image
   behind it). Two purpose-cropped source files (see index.html) mean this
   never has to crop hard to fill the screen, so a plain centred position
   is enough on both phone and desktop. Fades in once it's actually able to
   play; if autoplay is blocked or the file fails to load, the dark page
   background shows through instead. */
.hero-bg-video {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.4s ease;
  pointer-events: none;
}

.hero-bg-video.is-active {
  opacity: 0.72;
}

.scroll-cue {
  position: absolute;
  right: var(--gutter);
  bottom: clamp(1.5rem, 4vh, 3rem);
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: rgba(247, 244, 239, 0.7);
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.scroll-cue-line {
  width: 1px;
  height: 34px;
  background: rgba(247, 244, 239, 0.4);
  overflow: hidden;
  position: relative;
}

.scroll-cue-line::after {
  content: "";
  position: absolute;
  top: -100%;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--color-accent);
  animation: cue-drop 2.6s var(--ease) infinite;
}

@keyframes cue-drop {
  0% { top: -100%; }
  60% { top: 100%; }
  100% { top: 100%; }
}

/* ---------------------------------------------------------------------- */
/* Section rhythm                                                        */
/* ---------------------------------------------------------------------- */
.section {
  padding: clamp(4.5rem, 12vh, 8rem) 0;
}

.section-alt {
  background: var(--color-bg-alt);
}

.section-head {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  margin-bottom: clamp(2.5rem, 6vh, 4.5rem);
  max-width: 46ch;
}

.section-head h2 {
  font-size: clamp(1.9rem, 4vw, 3rem);
}

.section-head p {
  color: var(--color-ink-soft);
  font-size: 1.05rem;
  max-width: 42ch;
}

/* Work page intro line — set on one line at (almost) all desktop/laptop
   widths, including narrower windows and scaled-up-DPI displays where the
   viewport's CSS width can be well under the physical screen size.
   .work-section-head drops the shared 46ch cap so the line isn't boxed in,
   and the font-size scales down fluidly with the viewport so the sentence
   keeps fitting on one line without wrapping or overflowing. Only on
   genuine mobile widths does it revert to a normal, wrapped paragraph. */
/* Row that holds the category filters and the "Selected Projects" heading
   side by side — filters on the left, heading on the right — per client
   request, instead of the heading stacked directly above the filters. */
.work-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem 3rem;
  margin-bottom: clamp(2.5rem, 6vh, 4.5rem);
  /* Break out of .container's centred max-width + --gutter (same full-bleed
     trick as .work-grid below) and use the same smaller horizontal padding
     as .site-header, per client request — so "Selected Projects" and the
     filters line up with the Menu/wordmark inset above, instead of sitting
     further in like the rest of the page's body copy. */
  width: 100vw;
  position: relative;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
  padding-left: clamp(1rem, 2.5vw, 2rem);
  padding-right: clamp(1rem, 2.5vw, 2rem);
}

.work-toolbar .work-filters,
.work-toolbar .work-section-head {
  margin-bottom: 0;
}

@media (max-width: 700px) {
  .work-toolbar {
    flex-direction: column;
    align-items: flex-start;
    gap: 1.5rem;
  }
}

.work-section-head {
  max-width: none;
}

/* "Selected Projects" heading specifically, per client request — scoped to
   this page's eyebrow rather than the shared .eyebrow rule, so Contact/
   Practice/Services section headings are unaffected. */
.work-section-head .eyebrow {
  font-size: 13px;
}

/* Practice page eyebrows — "Since 2017" (founder split-copy), "Philosophy"
   and "The team" — each scoped so Contact/Work/Services eyebrows and the
   Practice hero's own "Practice" eyebrow are unaffected. */
.page-practice .split-copy .eyebrow,
.section-head.philosophy-head .eyebrow,
.section-head.team-head .eyebrow {
  font-size: 13px;
}

/* Philosophy section intro line ("We see architecture as a bridge...") —
   per client request, kept on one line rather than wrapping. Drops the
   shared 46ch/42ch caps and scales the font size down fluidly with the
   viewport so the whole sentence keeps fitting on one line. Only on
   genuine mobile widths does it revert to a normal, wrapped paragraph. */
.section-head.philosophy-head {
  max-width: none;
}

/* Specificity here is deliberately higher than the shared .section-head p
   rule (which caps paragraphs at 42ch) so this wins regardless of
   stylesheet order. */
.section-head.philosophy-head .philosophy-intro {
  max-width: none;
  white-space: nowrap;
  font-size: clamp(0.6rem, 1.35vw, 1.05rem);
}

@media (max-width: 700px) {
  .section-head.philosophy-head .philosophy-intro {
    white-space: normal;
    max-width: 42ch;
    font-size: 1.05rem;
  }
}

.work-section-head .work-intro-line {
  max-width: none;
  white-space: nowrap;
  font-size: clamp(0.68rem, 1.6vw, 1.05rem);
}

@media (max-width: 700px) {
  .work-section-head .work-intro-line {
    white-space: normal;
    max-width: 30ch;
    font-size: 1.05rem;
  }
}

.section-head.split {
  flex-direction: row;
  justify-content: space-between;
  align-items: flex-end;
  max-width: none;
  flex-wrap: wrap;
  gap: 1.5rem;
}

/* "Have a site in mind?" CTA — eyebrow and follow-up line sit side by side
   on one row, rather than the shared .section-head's default stacked
   (column) layout. */
.cta-head {
  flex-direction: row;
  align-items: baseline;
  flex-wrap: wrap;
  max-width: none;
  gap: 0.85rem;
}

.section-head.cta-head .cta-sub {
  font-size: 12.48px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-ink-soft);
}

/* ---------------------------------------------------------------------- */
/* Featured work grid (home)                                             */
/* ---------------------------------------------------------------------- */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2.5vw, 2rem);
}

.feature-grid .media {
  aspect-ratio: 4 / 5;
}

@media (max-width: 900px) {
  .feature-grid {
    grid-template-columns: 1fr;
  }
}

/* ---------------------------------------------------------------------- */
/* Two-column intro / philosophy blocks                                  */
/* ---------------------------------------------------------------------- */
.split-block {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
}

.split-block.reverse {
  grid-template-columns: 1.1fr 0.9fr;
}

.split-block.reverse .split-media {
  order: 2;
}

.split-media {
  aspect-ratio: 4 / 3;
}

.split-copy {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.split-copy p {
  color: var(--color-ink-soft);
  font-size: 1.05rem;
  max-width: 48ch;
}

.split-copy h2 {
  font-size: clamp(1.8rem, 3.6vw, 2.6rem);
}

@media (max-width: 860px) {
  .split-block,
  .split-block.reverse {
    grid-template-columns: 1fr;
  }
  .split-block.reverse .split-media {
    order: 0;
  }
}

/* ---------------------------------------------------------------------- */
/* Stats strip                                                           */
/* ---------------------------------------------------------------------- */
.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--color-line);
}

.stats div {
  padding: clamp(1.5rem, 3vw, 2.5rem) clamp(1rem, 2vw, 2rem);
  border-right: 1px solid var(--color-line);
}

.stats div:last-child {
  border-right: none;
}

.stats strong {
  display: block;
  font-family: var(--font-serif);
  font-size: clamp(1.8rem, 3.5vw, 2.6rem);
  margin-bottom: 0.4rem;
}

.stats span {
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  color: var(--color-ink-faint);
}

@media (max-width: 760px) {
  .stats {
    grid-template-columns: repeat(2, 1fr);
  }
  .stats div:nth-child(2n) {
    border-right: none;
  }
}

/* ---------------------------------------------------------------------- */
/* Work — filter + grid + lightbox                                       */
/* ---------------------------------------------------------------------- */
.work-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
}

/* Bold/underline "active tab" treatment removed per client request — every
   filter (All / New Build / Alterations / Multi-Unit) now stays the same
   plain style regardless of which is selected. Clicking still filters the
   grid exactly as before, there's just no visual indicator on the button
   itself any more. */
.work-filters button {
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-ink-faint);
  padding: 0.35rem 0;
  position: relative;
}

/* Work grid v2 — a mosaic of collage "groups", each bundling several
   different projects (1 big photo + 2 smaller ones, in a few different
   arrangements) rather than one photo per project in a uniform grid, per
   client request. Photos sit flush against each other with no gap/divider
   of any colour ("connect the projects together") — full-bleed edge to
   edge, same trick as the old .work-grid used. */
.work-collage {
  display: flex;
  flex-direction: column;
  margin-top: clamp(2rem, 5vh, 3rem);
  width: 100vw;
  position: relative;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
}

.work-collage-group {
  display: flex;
  /* Wide, shallow proportions so a full row of 3 photos reads as a single
     panoramic strip rather than a tall block. */
  aspect-ratio: 21 / 9;
  transition: opacity var(--dur-med) var(--ease);
  /* Without this, flexbox's default automatic minimum size lets the
     photos' own natural aspect ratio push this row taller than the
     21:9 aspect-ratio above calls for (a group is itself a flex item of
     .work-collage's column layout) — same min-size:auto issue as the
     nested .work-collage-side/-row fix below, just one level up. */
  min-height: 0;
}

.work-collage-group[hidden] {
  display: none;
}

/* "Big photo on top, 2 below" pattern needs a column-direction group;
   every other pattern (main-left, mirrored main-right, 3 equal thirds,
   leftover half/half) is a plain row, so no extra class is needed there. */
.work-collage-group.pattern-top {
  flex-direction: column;
}

.work-collage-group.pattern-half {
  aspect-ratio: 21 / 6;
}

.work-collage-main {
  flex: 2;
}

.work-collage-third {
  flex: 1;
}

/* A 2-up stack (vertical) or row (horizontal) of smaller photos sitting
   alongside/below the main photo. min-height/min-width:0 override
   flexbox's default min-size:auto, which would otherwise let an image's
   own intrinsic aspect ratio force this box to keep more room than its
   flex-grow share and squeeze its sibling. */
.work-collage-side {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
}

.work-collage-row {
  flex: 1;
  display: flex;
  min-height: 0;
  min-width: 0;
}

.work-collage-side .work-collage-cell,
.work-collage-row .work-collage-cell {
  flex: 1;
}

.work-collage-cell {
  position: relative;
  overflow: hidden;
  min-height: 0;
  min-width: 0;
  display: block;
  width: 100%;
  height: 100%;
  border: none;
  padding: 0;
  margin: 0;
  background: none;
  cursor: pointer;
}

.work-collage-cell[hidden] {
  display: none;
}

/* Muted (near-monochrome) by default, full colour on hover/focus — same
   treatment as the previous single-photo grid. */
.work-collage-cell img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: grayscale(0.85) saturate(0.2) contrast(1.02) brightness(0.85);
  transform: scale(1.001);
  transition: filter var(--dur-slow) var(--ease), transform 1.4s var(--ease);
}

.work-collage-cell:hover img,
.work-collage-cell:focus-within img {
  filter: grayscale(0) saturate(1) contrast(1) brightness(1);
  transform: scale(1.035);
}

/* Vignette as each photo "lights up" into full colour on hover/focus —
   edges darken while the centre stays clear. */
.work-collage-cell::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at center, transparent 45%, rgba(0, 0, 0, 0.55) 100%);
  opacity: 0;
  transition: opacity var(--dur-med) var(--ease);
  pointer-events: none;
}

.work-collage-cell:hover::before,
.work-collage-cell:focus-within::before {
  opacity: 1;
}

/* Project name — hidden until hover/focus, per client request, then fades
   in together with the colour reveal. */
.work-collage-label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0.75rem;
  color: var(--color-paper);
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.6);
  pointer-events: none;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity var(--dur-med) var(--ease), transform var(--dur-med) var(--ease);
}

.work-collage-cell:hover .work-collage-label,
.work-collage-cell:focus-within .work-collage-label {
  opacity: 1;
  transform: translateY(0);
}

@media (max-width: 760px) {
  /* Every pattern collapses to one full-width photo per row, in the same
     top-to-bottom project order as the markup, still edge to edge. Each
     pattern class is named explicitly here so it outweighs that same
     class's own (more specific) aspect-ratio rule set above. */
  .work-collage-group,
  .work-collage-group.pattern-top,
  .work-collage-group.pattern-thirds,
  .work-collage-group.pattern-half {
    flex-direction: column;
    aspect-ratio: auto;
  }

  .work-collage-main,
  .work-collage-third {
    flex: none;
    width: 100%;
  }

  .work-collage-side,
  .work-collage-row {
    flex: none;
    flex-direction: column;
    width: 100%;
  }

  .work-collage-cell {
    aspect-ratio: 4 / 3;
  }
}

/* Filtered view (New Build / Alterations / Multi-Unit) — the hand-arranged
   main+side/thirds patterns only make sense with every photo present; once
   a filter hides most of a group, the 1-2 survivors would otherwise stretch
   to fill the whole group (e.g. a single photo stuffed into a 21:9 box).
   Instead, flatten every group/side/row wrapper with display:contents so
   their still-visible cells become direct children of one plain grid, and
   give every cell the same 4:3 tile size — a simple, even "side by side"
   layout for however many photos match, still edge to edge (0 gap). Order
   follows the markup, same as the unfiltered collage. */
.work-collage.is-filtered {
  display: grid;
  /* auto-fit (not auto-fill) so a small number of results — e.g. just 2
     photos under a narrow filter — expand to fill the row edge to edge
     instead of sitting as small tiles with empty track space beside them. */
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 0;
}

.work-collage.is-filtered .work-collage-group,
.work-collage.is-filtered .work-collage-side,
.work-collage.is-filtered .work-collage-row {
  display: contents;
}

.work-collage.is-filtered .work-collage-cell {
  aspect-ratio: 4 / 3;
  width: 100%;
  height: 100%;
}

/* Lightbox — full-bleed, edge-to-edge single photo per screen (no white
   card, no side panel), matching the reference the client shared. Caption
   sits directly over the image on a dark scrim instead of beside it. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 800;
  display: flex;
  background: #000;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-med) var(--ease), visibility 0s var(--dur-med);
}

.lightbox.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur-med) var(--ease), visibility 0s;
}

.lightbox-inner {
  width: 100%;
  height: 100%;
}

.lightbox-media {
  position: relative;
  width: 100%;
  height: 100%;
  background: #000;
}

/* Specificity here is deliberately higher than .media:hover img so the
   photo is always shown at full quality, regardless of where the pointer
   happens to be resting over this full-screen overlay. */
.lightbox.is-open .lightbox-media img {
  opacity: 1;
  filter: none;
  transform: none;
  /* Show the whole photo, letterboxed on the black background if the
     viewer's window shape doesn't match the image — object-fit: cover
     (the default for .media img elsewhere) would otherwise crop the top
     and bottom off portrait-leaning shots and diptychs to fill whatever
     width/height ratio the browser window happens to be. */
  object-fit: contain;
}

.lightbox-media::after {
  /* Switch off the inherited .media hover-veil radial gradient — it has no
     purpose on a static full-screen photo. */
  content: none;
}

.lightbox-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(10, 9, 8, 0.75), transparent 45%);
  pointer-events: none;
}

.lightbox-copy {
  position: absolute;
  left: clamp(1.25rem, 4vw, 3rem);
  bottom: clamp(1.25rem, 4vw, 3rem);
  right: clamp(4rem, 10vw, 7rem);
  max-width: 44ch;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  color: var(--color-paper);
  z-index: 2;
}

.lightbox-tag {
  display: none;
}

.lightbox-title {
  font-family: var(--font-brand);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--color-paper);
}

.lightbox-notes {
  margin-top: 0.35rem;
}

.lightbox-notes summary {
  cursor: pointer;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-paper);
  list-style: none;
}

.lightbox-notes summary::-webkit-details-marker {
  display: none;
}

.lightbox-notes summary:hover {
  color: var(--color-paper);
}

.lightbox-notes p {
  margin-top: 0.6rem;
  color: var(--color-paper);
  font-size: 0.92rem;
}

/* Prev/next arrows + counter — only shown when a project has more than one
   photo (data-images on the trigger); hidden via the [hidden] attribute
   otherwise, so single-image projects look exactly as before. */
.lightbox-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 2.75rem;
  height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: rgba(20, 18, 16, 0.4);
  color: var(--color-paper);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  transition: background var(--dur-quick) ease;
  z-index: 2;
}

.lightbox-nav:hover,
.lightbox-nav:focus-visible {
  background: rgba(20, 18, 16, 0.7);
}

.lightbox-prev {
  left: clamp(0.75rem, 2vw, 1.5rem);
}

.lightbox-next {
  right: clamp(0.75rem, 2vw, 1.5rem);
}

.lightbox-count {
  position: absolute;
  bottom: clamp(1.25rem, 4vw, 3rem);
  right: clamp(1.25rem, 4vw, 3rem);
  padding: 0.25rem 0.65rem;
  border-radius: 999px;
  background: rgba(20, 18, 16, 0.5);
  color: var(--color-paper);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  z-index: 2;
}

.lightbox-close {
  position: absolute;
  top: clamp(1rem, 3vw, 2rem);
  left: clamp(1rem, 3vw, 2rem);
  z-index: 2;
  width: 2.25rem;
  height: 2.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(20, 18, 16, 0.4);
  font-size: 1.1rem;
  color: var(--color-paper);
  transition: background var(--dur-quick) ease;
}

.lightbox-close:hover,
.lightbox-close:focus-visible {
  background: rgba(20, 18, 16, 0.7);
}

@media (max-width: 640px) {
  .lightbox-copy {
    right: clamp(1.25rem, 4vw, 3rem);
    max-width: none;
  }
  .lightbox-nav {
    width: 2.25rem;
    height: 2.25rem;
    font-size: 1.2rem;
  }
}

/* ---------------------------------------------------------------------- */
/* Practice — team                                                       */
/* ---------------------------------------------------------------------- */
.team-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(1rem, 2.5vw, 2rem);
}

.team-card .media {
  aspect-ratio: 4 / 5;
  margin-bottom: 1rem;
}

.team-card h3 {
  font-size: 13px;
}

.team-card span {
  display: block;
  font-size: 0.82rem;
  color: var(--color-ink-faint);
  margin-top: 0.25rem;
}

@media (max-width: 900px) {
  .team-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 540px) {
  .team-grid {
    grid-template-columns: 1fr;
  }
}

/* ---------------------------------------------------------------------- */
/* Services                                                              */
/* ---------------------------------------------------------------------- */
.service-list {
  border-top: 1px solid var(--color-line);
}

/* "How we work" section-head only: match the gap between the paragraph and
   the rule to the gap above the eyebrow at the top of the section (same
   clamp() as .section's own padding), so the two feel even rather than the
   paragraph-to-rule gap reading noticeably tighter than the top of the
   section. */
.section-head.process-head {
  margin-bottom: clamp(4.5rem, 12vh, 8rem);
}

/* "Services", "How we work" and "Project types" eyebrows, per client
   request — each scoped to its own section on this page only, so other
   pages' eyebrows are unaffected. */
.page-services .split-copy .eyebrow,
.section-head.process-head .eyebrow,
.section-head.project-types-head .eyebrow,
.section-head.services-cta-head .eyebrow,
.section-head.cta-head .eyebrow,
.page-contact .section-head .eyebrow {
  font-size: 13px;
}

.service-row {
  display: grid;
  grid-template-columns: 5rem 1fr 1.3fr;
  gap: clamp(1rem, 3vw, 2.5rem);
  padding: clamp(1.75rem, 4vh, 2.75rem) 0;
  border-bottom: 1px solid var(--color-line);
  align-items: baseline;
}

.service-row .num {
  font-family: var(--font-serif);
  color: var(--color-accent-deep);
  font-size: 1.1rem;
}

.service-row h3 {
  font-size: 15px;
}

.service-row p {
  color: var(--color-ink-soft);
}

@media (max-width: 760px) {
  .service-row {
    grid-template-columns: 1fr;
    gap: 0.75rem;
  }
}

/* ---------------------------------------------------------------------- */
/* Contact                                                               */
/* ---------------------------------------------------------------------- */
.contact-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 6vw, 5rem);
}

/* Left column now holds the intro text (eyebrow/heading/paragraph) stacked
   above the studio details, so both grid columns start at the same top
   edge as the form on the right — per client request, the form was
   previously sitting lower than the "Let's start with a conversation."
   heading because the intro used to live outside the grid entirely. */
.contact-left {
  display: flex;
  flex-direction: column;
  gap: clamp(2.5rem, 6vh, 4.5rem);
}

.contact-left .section-head {
  margin-bottom: 0;
}

.contact-details dl {
  display: grid;
  gap: 1.75rem;
}

.contact-details dt {
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-ink-faint);
  margin-bottom: 0.4rem;
}

.contact-details dd {
  margin: 0;
  font-size: 13px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 1.6rem;
  position: relative;
}

.field label {
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-ink-faint);
}

.field input,
.field textarea {
  font-family: var(--font-sans);
  font-size: 1rem;
  color: var(--color-ink);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--color-line-strong);
  padding: 0.6rem 0;
  transition: border-color var(--dur-quick) ease;
}

.field input:focus,
.field textarea:focus {
  border-color: var(--color-accent-deep);
  outline: none;
}

.field textarea {
  resize: vertical;
  min-height: 110px;
}

.field .error {
  font-size: 0.78rem;
  color: #9a5b4c;
  min-height: 1.1em;
}

.form-status {
  margin-top: 1rem;
  font-size: 0.92rem;
  color: var(--color-ink-soft);
}

.form-status.is-success {
  color: #5c7a5f;
}

.form-status.is-error {
  color: #9a5b4c;
}

@media (max-width: 860px) {
  .contact-grid {
    grid-template-columns: 1fr;
    gap: 3rem;
  }
}

/* ---------------------------------------------------------------------- */
/* Footer                                                                 */
/* ---------------------------------------------------------------------- */
.site-footer {
  border-top: 1px solid var(--color-line);
  padding: clamp(2.5rem, 6vh, 4rem) 0 clamp(1.5rem, 4vh, 2.5rem);
}

.footer-top {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 2rem;
  margin-bottom: clamp(2rem, 5vh, 3rem);
}

.footer-top h2 {
  font-size: 20px;
  max-width: none;
  white-space: nowrap;
}

/* Footer is shared markup across every page, so this is scoped to the
   Services page's body class only, per client request — other pages'
   footers keep the normal 20px heading size. */
.page-services .footer-top h2 {
  font-size: 13px;
}

/* On mobile, .footer-top wraps to a stacked column and "Start a project" /
   "Email us directly" ends up on its own line under the heading. The
   solid button's own left padding (1.75rem) then made its visible text
   sit noticeably right of the heading's flush-left edge — pull the box
   back by that same amount so the text lines up instead. Left as-is on
   wider screens, where the button sits on the right per space-between and
   this offset isn't relevant. */
@media (max-width: 700px) {
  .footer-top .btn-solid {
    margin-left: -1.75rem;
  }
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 2.5rem;
}

.footer-col {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  font-size: 0.92rem;
}

.footer-col .label {
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-ink-faint);
  margin-bottom: 0.4rem;
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--color-line);
  font-size: 0.78rem;
  color: var(--color-ink-faint);
}

/* ---------------------------------------------------------------------- */
/* Utility                                                                */
/* ---------------------------------------------------------------------- */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}
