/* =========================================================================
   Villapoint — single stylesheet

   Order: fonts, tokens, divisions, reset, base, utilities, then components.
   Every colour is sampled from a supplied brand file; nothing is invented.
   Contrast ratios in the comments are measured, not estimated.

   Components, in order:
     header · mobile nav · hero · page head · breadcrumbs · buttons ·
     pillars · split + facts · portfolio grid · service blocks ·
     contact details + form · CTA band · footer · contact widget
   ========================================================================= */

/* --- Font (one family, self-hosted, no third-party request) --------------- */
@font-face {
  font-family: 'Fraunces';
  src: url('../fonts/fraunces-latin-400-700.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}
/* --- Design tokens -------------------------------------------------------- */
:root {
  /* Brand */
  --brand-crimson: #A8182E;
  --brand-crimson-dark: #8E1429;   /* hover/active only */
  --brand-crimson-light: #F08098;  /* the only crimson safe on navy, 6.20:1 */
  --brand-navy: #1B1D4A;
  --brand-navy-light: #3A4170;
  --brand-navy-dark: #12142F;
  --brand-gold: #C9A24B;
  --brand-charcoal: #2A2426;
  --brand-white: #FFFFFF;
  --brand-cream: #FAF6F1;
  --whatsapp: #25D366;

  /* Surfaces */
  --surface: #FFFFFF;
  --surface-off: #F7F7F6;
  --surface-dark: var(--brand-navy);

  /* Text
     ink        on white  17.88:1   AA + AAA body
     ink-muted  on white   6.37:1   AA body
     on-dark    on navy   15.79:1   AA + AAA body
     on-dark-muted on navy 11.0:1 */
  --ink: #15171F;
  --ink-muted: #5A5F6E;
  --on-dark: #FFFFFF;
  --on-dark-muted: #C9CBD6;
  --on-scrim-muted: #DADCE4;

  /* Lines. Decorative only — never the sole carrier of meaning or state.
     --line-strong is 3.20:1 on white and is the one safe for UI boundaries. */
  --line: #E2E3E7;
  --line-strong: #8A909D;
  --line-dark: rgb(255 255 255 / 0.16);

  /* Division accent — remapped per section by [data-division]. */
  --accent: var(--brand-crimson);
  --accent-hover: var(--brand-crimson-dark);
  --accent-contrast: #FFFFFF;      /* 7.40:1 on crimson */

  /* Type. Fluid between 360px and 1440px. Body never below 16px. */
  /* One family for the whole site. Hierarchy comes from weight and size. */
  --font-main: 'Fraunces', Georgia, 'Times New Roman', serif;

  --text-xs:      0.8125rem;
  --text-sm:      0.9375rem;
  --text-base:    clamp(1rem, 0.96rem + 0.18vw, 1.0625rem);
  --text-lg:      clamp(1.125rem, 1.06rem + 0.28vw, 1.25rem);
  --text-xl:      clamp(1.3125rem, 1.2rem + 0.5vw, 1.5rem);
  --text-2xl:     clamp(1.5rem, 1.33rem + 0.76vw, 1.875rem);
  --text-3xl:     clamp(1.875rem, 1.6rem + 1.2vw, 2.5rem);
  --text-display: clamp(2.25rem, 1.65rem + 2.6vw, 3.75rem);

  --leading-tight: 1.15;
  --leading-snug: 1.3;
  --leading-normal: 1.6;

  --tracking-tight: -0.02em;
  --tracking-wide: 0.08em;
  --tracking-wider: 0.14em;

  --measure: 68ch;

  /* Spacing — 4px base */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-24: 6rem;
  --space-32: 8rem;

  --section-y: clamp(var(--space-16), 8vw, var(--space-32));

  /* Layout */
  --container: 75rem;      /* 1200px */
  --container-wide: 90rem; /* 1440px */
  --gutter: clamp(var(--space-4), 4vw, var(--space-8));

  /* Radius, elevation */
  --radius-sm: 2px;
  --radius-md: 4px;
  --radius-full: 9999px;

  --shadow-sm: 0 1px 2px rgb(21 23 31 / 0.06);
  --shadow-md: 0 4px 16px rgb(21 23 31 / 0.10);
  --shadow-lg: 0 10px 28px rgb(21 23 31 / 0.18);

  /* Motion — two durations, one curve. Opacity and small translate only. */
  --duration-fast: 150ms;
  --duration-base: 250ms;
  --duration-slow: 700ms;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);

  /* Chrome. The nav band is crimson with white links: 7.40:1, passes AA. */
  --header-top-h: 2.25rem;
  --header-main-h: 4.75rem;
  --header-main-h-m: 3.5rem;
  /* Full height of the sticky header, used to clear the hero heading. */
  --header-h: 7rem;
  --header-h-m: 3.5rem;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 0ms;
    --duration-base: 0ms;
    --duration-slow: 0ms;
  }
}

/* --- Division accent mapping ---------------------------------------------
   Crimson = property side (Real Estate, Property Management).
   Navy    = consulting side (Project Management).
   Colour marks the side of the business, not the division: Real Estate and
   Property Management read identically and are separated by label, URL and
   breadcrumb instead.
   -------------------------------------------------------------------------- */
[data-division='real-estate'],
[data-division='property-management'] {
  --accent: var(--brand-crimson);
  --accent-hover: var(--brand-crimson-dark);
  --accent-contrast: #FFFFFF;
}

/* PLACEHOLDER — the Project Management blue logo variant has not been
   supplied. Navy stands in so the page renders; it is not the final value. */
[data-division='project-management'] {
  --accent: var(--brand-navy);
  --accent-hover: var(--brand-navy-light);
  --accent-contrast: #FFFFFF;
}

/* On a navy surface the crimson accent is 2.13:1 and invisible. Anything
   inside .section--dark / the footer uses the light tone instead. */
.section--dark,
.site-footer,
.cta-band {
  --accent: var(--brand-gold);
  --accent-hover: var(--brand-gold);
  --accent-contrast: var(--brand-navy);
}

/* --- Reset ---------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

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

body {
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, picture, svg, video { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }
ul[role='list'], ol[role='list'] { list-style: none; padding: 0; }
:target { scroll-margin-block: var(--space-24); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --- Base ----------------------------------------------------------------- */
body {
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-main);
  /* Fraunces axes: no softness, no wonk — corporate, not playful. Set on the
     body so every element inherits the same cut. */
  font-variation-settings: 'SOFT' 0, 'WONK' 0;
  font-size: var(--text-base);
  line-height: var(--leading-normal);
}

h1, h2, h3, h4 {
  font-weight: 600;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

h1 { font-size: var(--text-display); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-xl); }
h4 { font-size: var(--text-lg); }

p { text-wrap: pretty; }

/*
  Default link colour, for prose and light surfaces.

  `a:hover` has specificity 0-1-1, which beats any single-class component rule.
  Without the override below it repaints every link on a dark surface crimson
  on hover — crimson-dark on the crimson band is 1.3:1, and on navy it is
  2.0:1. Both are effectively invisible. Anything inside [data-surface='dark']
  inherits its own colour and opts out of the global link colours entirely.
*/
a { color: var(--brand-crimson); text-underline-offset: 0.2em; }
a:hover { color: var(--brand-crimson-dark); }

[data-surface='dark'] a,
[data-surface='dark'] a:hover,
[data-surface='dark'] a:focus-visible { color: inherit; }

/* Visible focus on every interactive element, on light and dark surfaces. */
:focus-visible {
  outline: 3px solid var(--brand-crimson);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
[data-surface='dark'] :focus-visible { outline-color: #FFFFFF; }

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: var(--space-4);
  z-index: 100;
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  color: var(--ink);
  font-weight: 600;
  box-shadow: var(--shadow-md);
  transform: translateY(-200%);
}
.skip-link:focus { transform: translateY(0); }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Utilities ------------------------------------------------------------ */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: var(--section-y); }
.section--off { background: var(--surface-off); }
.section--dark { background: var(--surface-dark); color: var(--on-dark); }
.section--tight { padding-block: clamp(var(--space-12), 5vw, var(--space-16)); }

/* Lets a child run past the container to the viewport edge without ever
   producing a horizontal scrollbar. `clip` on one axis leaves the other
   visible, so card hover lifts are not cut off. */
.section--bleed { overflow-x: clip; }

/* Small caps label above a heading. Uses the division accent. */
.eyebrow {
  font-family: var(--font-main);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--accent);
}
.section--dark .eyebrow { color: var(--on-dark-muted); }

.lede {
  font-size: var(--text-lg);
  color: var(--ink-muted);
  max-width: var(--measure);
}
.section--dark .lede { color: var(--on-dark-muted); }

/* Heading block: eyebrow, heading, lede, in a measured column. */
.section-head { max-width: var(--measure); margin-bottom: var(--space-12); }
.section-head h2 { margin-top: var(--space-2); }
.section-head .lede { margin-top: var(--space-4); }

/* Body copy inside a measured column. */
.prose { max-width: var(--measure); }
.prose > * + * { margin-top: var(--space-4); }
.prose p { color: var(--ink-muted); }
.prose h2 + p, .prose h3 + p { margin-top: var(--space-4); }
.section--dark .prose p { color: var(--on-dark-muted); }

/* --- Header ---------------------------------------------------------------
   Two rows on one continuous white area. The crimson nav band is the only
   coloured surface; it carries the slant and the gold rule. Sticky.
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: stretch;
  background: var(--brand-white);
}

/* The logo has no shape of its own: it sits on the header's white background,
   centred across both rows, so there is no seam with the top row. The crimson
   logo must never sit on the crimson band. */
.header-logo {
  display: flex;
  align-items: center;
  flex: none;
  padding: var(--space-2) var(--space-6) var(--space-2) var(--gutter);
  text-decoration: none;
}
.header-logo img { height: 84px; width: auto; }

.header-rows {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-width: 0;
}

.header-top {
  display: flex;
  align-items: center;
  min-height: var(--header-top-h);
  background: var(--brand-white);
}

.header-top-inner {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-6);
  width: 100%;
  padding-inline: var(--gutter);
}

.top-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--brand-crimson); /* on white, 7.40:1 */
  font-size: var(--text-xs);
  text-decoration: none;
}
.top-link:hover .top-text { text-decoration: underline; }

/* The band is painted by ::before rather than on the element itself, because
   a clip-path here would also clip the dropdown that hangs below it. The
   pseudo-element runs 3px past the bottom to carry the gold rule, so the rule
   inherits the same slant and stops where the band stops. */
.header-main {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-6);
  min-height: var(--header-main-h);
  padding-inline: var(--gutter);
}

.header-main::before {
  content: '';
  position: absolute;
  inset: 0 0 -3px 0;
  z-index: 0;
  background: var(--brand-crimson);
  border-bottom: 3px solid var(--brand-gold);
  clip-path: polygon(24px 0, 100% 0, 100% 100%, 0 100%);
}

.header-main > * { position: relative; z-index: 1; }

/* `[data-surface='dark'] a` in base is 0-2-1 and outranks a single class, so
   this needs the extra class to keep white on the crimson band. */
.site-header .header-main .nav-link { color: var(--brand-white); }

/* --- Desktop nav ---------------------------------------------------------- */
.site-nav { display: none; }

@media (min-width: 60rem) {
  .site-nav { display: block; }
}

.nav-list {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  margin: 0;
}

.nav-item { position: relative; }

.nav-link {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-block: var(--space-2);
  background: none;
  border: 0;
  color: var(--brand-white);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
}

/* Underline is in addition to the colour change, never the only signal. */
.nav-link::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--brand-gold);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-fast) var(--ease);
}

.nav-link:hover::after,
.nav-link[aria-current='page']::after,
.nav-item[data-current='true'] > .nav-link::after { transform: scaleX(1); }

.nav-caret {
  width: 9px;
  height: 9px;
  transition: transform var(--duration-fast) var(--ease);
}
.nav-item[data-open='true'] .nav-caret { transform: rotate(180deg); }

/* Submenu: white card hanging off the crimson band, gold rule on top. */
.nav-menu {
  position: absolute;
  top: calc(100% + var(--space-2));
  left: calc(var(--space-4) * -1);
  z-index: 20;
  min-width: 16rem;
  margin: 0;
  padding-block: var(--space-2);
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 3px solid var(--brand-gold);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-0.4rem);
  transition:
    opacity var(--duration-fast) var(--ease),
    transform var(--duration-fast) var(--ease),
    visibility var(--duration-fast);
}

.nav-item[data-open='true'] .nav-menu,
.nav-item:hover .nav-menu,
.nav-item:focus-within .nav-menu {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.nav-menu a {
  display: block;
  padding: var(--space-3) var(--space-6);
  color: var(--ink);
  font-size: var(--text-sm);
  font-weight: 500;
  text-decoration: none;
  border-left: 3px solid transparent;
}
.nav-menu a:hover,
.nav-menu a:focus-visible { background: var(--surface-off); color: var(--ink); }
.nav-menu a[aria-current='page'] { border-left-color: var(--accent); font-weight: 600; }

/* --- Header: narrow screens ----------------------------------------------- */
@media (max-width: 59.9375rem) {
  :root { --header-h: var(--header-h-m); }

  /* Single row: white logo area left, crimson band right. */
  .header-top { display: none; }

  .header-logo { padding: var(--space-1) var(--space-3) var(--space-1) 8px; }
  .header-logo img { height: 64px; }

  .header-main {
    min-height: var(--header-main-h-m);
    gap: var(--space-2);
    padding-inline: var(--space-3);
  }
}

/* --- Mobile nav -----------------------------------------------------------
   A panel that slides down under the crimson band, only as tall as its own
   content, with its own scroll if the content outgrows the screen. It does not
   cover the page and does not lock scrolling. The inline nav above 60rem is
   untouched.
   -------------------------------------------------------------------------- */
.mnav { display: block; }

@media (min-width: 60rem) {
  .mnav,
  .mnav-panel { display: none; }
}

.mnav-toggle {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  min-height: 44px;
  background: transparent;
  border: 1px solid rgb(255 255 255 / 0.5);
  border-radius: var(--radius-md);
  color: var(--on-dark);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  cursor: pointer;
}

.mnav-bars { display: grid; gap: 3px; width: 1rem; }
.mnav-bars > span {
  display: block;
  height: 2px;
  background: currentColor;
  transition:
    opacity var(--duration-fast) var(--ease),
    transform var(--duration-fast) var(--ease);
}

/* Open state: outer bars cross into an X, middle bar fades out. */
.mnav-bars[data-open='true'] > span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.mnav-bars[data-open='true'] > span:nth-child(2) { opacity: 0; }
.mnav-bars[data-open='true'] > span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/*
  The panel hangs off .header-main, which is the nearest positioned ancestor
  and spans the full width. 3px down clears the gold rule the band carries.
  Its height is animated from JS (initMobileNav) because only a number can be
  transitioned; everything inside is clipped, so nothing shows at height 0 —
  which is also why the gold edge and the cream sit on .mnav-scroll and not on
  the panel itself.
*/
.mnav-panel {
  position: absolute;
  top: calc(100% + 3px);
  /* .header-main starts after the logo, so the panel is pulled back out to the
     full width of the screen. */
  left: 50%;
  width: 100vw;
  margin-left: -50vw;
  z-index: 1;
  height: 0;
  overflow: hidden;
  border-radius: 0 0 12px 12px;
  box-shadow: 0 14px 30px rgb(21 23 31 / 0.18);
  transition: height 300ms var(--ease);
}
.mnav-panel[hidden] { display: none; }

.mnav-scroll {
  max-height: calc(100vh - var(--header-h) - var(--space-4));
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--brand-cream);
  border-top: 3px solid var(--brand-gold);
}

.mnav-list { margin: 0; padding: 0; list-style: none; }
.mnav-item + .mnav-item { border-top: 1px solid rgb(42 36 38 / 0.10); }

.mnav-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
  min-height: 48px;
  padding: var(--space-3) var(--gutter);
  background: none;
  border: 0;
  color: var(--brand-charcoal);        /* 12.6:1 on the cream */
  font-family: var(--font-main);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: var(--leading-snug);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.mnav-link:hover { color: var(--brand-crimson); }

/* An inset bar rather than a border, so the row does not shift by 3px. */
.mnav-link[aria-current='page'] {
  box-shadow: inset 3px 0 0 var(--brand-crimson);
  color: var(--brand-crimson);         /* 7.40:1 on the cream */
}

.mnav-caret { display: grid; color: var(--brand-crimson); }
.mnav-caret svg {
  width: 14px;
  height: 14px;
  transition: transform var(--duration-base) var(--ease);
}
.mnav-parent[aria-expanded='true'] .mnav-caret svg { transform: rotate(180deg); }

.mnav-sublist {
  margin: 0 0 var(--space-2) var(--gutter);
  padding: 0 0 0 var(--space-4);
  border-left: 2px solid var(--brand-crimson);
  list-style: none;
}
.mnav-sublist[hidden] { display: none; }

.mnav-sublink {
  display: flex;
  align-items: center;
  min-height: 44px;
  color: var(--brand-charcoal);
  font-size: 0.95rem;
  font-weight: 500;
  text-decoration: none;
}
.mnav-sublink:hover { color: var(--brand-crimson); }
.mnav-sublink[aria-current='page'] { color: var(--brand-crimson); font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  .mnav-panel,
  .mnav-caret svg,
  .mnav-bars > span { transition: none !important; }
}

/* --- Hero ------------------------------------------------------------------ */
.hero {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 70vh;
  background: var(--brand-navy);
  color: var(--on-dark);
  overflow: hidden;
  text-align: center;
}

.hero-media,
.hero-scrim { position: absolute; inset: 0; }

/* The slides are stacked with z-index so the incoming one fades in on top of
   the outgoing one. `isolation` keeps those z-indexes scoped to this element:
   without it they would escape into the page's root stacking context and the
   active photograph would paint over the scrim and the hero text. */
.hero-media { isolation: isolate; }

.hero-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Per-slide crop focus. The source photographs are portrait and the hero is
     wide, so a centred crop would cut the building; each slide's value comes
     from HERO in site.js. */
  object-position: var(--focal, center 42%);
  opacity: 0;
  z-index: 0;
}

.hero-media img[data-active='true'] {
  opacity: 1;
  z-index: 1;
  animation: slowZoom 8s var(--ease) both;
}

/*
  Transitions are switched on by site.js only after the first slide has
  painted, so the opening image appears at once instead of fading up from the
  navy base and delaying Largest Contentful Paint.

  The outgoing image then HOLDS at full opacity underneath while the incoming
  one fades in on top of it, and only snaps out once that is finished. Fading
  both at the same time would dip to the navy base at the midpoint, which
  reads as a flash every time the hero advances.
*/
.hero-media[data-ready='true'] img {
  transition: opacity 0ms var(--ease) var(--duration-slow);
}

.hero-media[data-ready='true'] img[data-active='true'] {
  transition: opacity var(--duration-slow) var(--ease) 0ms;
}

@keyframes slowZoom {
  from { transform: scale(1); }
  to   { transform: scale(1.06); }
}

/*
  Gradient tint: stronger top and bottom, lighter through the middle so more of
  the photograph shows. The mid stop sits behind the centred heading, so it is
  held at 0.52 — enough that white display type clears AA over the lightest
  region of the supplied photographs. The text-shadow helps legibility but is
  not counted by WCAG; the scrim is what carries the ratio.
*/
.hero-scrim {
  background: linear-gradient(
    to bottom,
    rgb(27 29 74 / 0.55) 0%,
    rgb(27 29 74 / 0.25) 50%,
    rgb(27 29 74 / 0.50) 100%
  );
}

.hero-inner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* The top pad clears the sticky header, so the heading is never tucked
     under it on a short viewport. */
  padding-block: calc(var(--space-16) + var(--header-h)) var(--space-16);
}

/* Slides stack so the hero never changes height between sets. */
.hero-slides {
  display: grid;
  width: 100%;
  max-width: 54rem;
}

.hero-slide {
  grid-area: 1 / 1;
  margin: 0;
  font-family: var(--font-main);
  font-variation-settings: 'SOFT' 0, 'WONK' 0;
  font-size: var(--text-display);
  font-weight: 600;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
  text-shadow: 0 2px 12px rgb(0 0 0 / 0.35);
  opacity: 0;
  transform: translateY(0.5rem);
  /* The outgoing line leaves first and the incoming one follows, rather than
     the two crossing over each other — they sit in the same grid cell, so a
     true crossfade shows both sets of words at once. */
  transition:
    opacity var(--duration-base) var(--ease) 0ms,
    transform var(--duration-base) var(--ease) 0ms;
  pointer-events: none;
}

.hero-slide[data-active='true'] {
  opacity: 1;
  transform: none;
  pointer-events: auto;
  transition-delay: var(--duration-base);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-8);
}

.hero-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-6);
  margin-top: var(--space-8);
}

.hero-dots { display: flex; gap: var(--space-2); margin: 0; }

.hero-dot {
  display: block;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
}

/* The visible mark sits inside a 44px hit area. */
.hero-dot::before {
  content: '';
  display: block;
  width: 2rem;
  height: 3px;
  margin: auto;
  background: rgb(255 255 255 / 0.55);
  transition: background var(--duration-fast) var(--ease);
}
.hero-dot[data-active='true']::before { background: var(--brand-gold); }
.hero-dot:hover::before { background: rgb(255 255 255 / 0.75); }

@media (max-width: 47.9375rem) {
  .hero { min-height: 75vh; }
  /* No crop override here: the per-slide focal from site.js applies at every
     width, so one value per photograph is the whole story. */
}

@media (prefers-reduced-motion: reduce) {
  .hero-media img[data-active='true'] { animation: none; }
}

/* --- Page head -------------------------------------------------------------
   Navy band at the top of every inner page. Carries the breadcrumb, an accent
   rule, the h1 and one line of lede.
   -------------------------------------------------------------------------- */
.page-head {
  position: relative;
  background: var(--brand-navy);
  color: var(--on-dark);
  padding-block: clamp(var(--space-12), 7vw, var(--space-24));
  overflow: hidden;
}

/* A quiet diagonal wash, echoing the slant in the header band. */
.page-head::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 58%, rgb(255 255 255 / 0.045) 58%);
  pointer-events: none;
}

.page-head > * { position: relative; z-index: 1; }

.page-head .eyebrow { color: var(--brand-gold); }

.page-head h1 { max-width: 24ch; }

.page-head .lede { margin-top: var(--space-4); color: var(--on-scrim-muted); }

.page-head-rule {
  display: block;
  width: 3rem;
  height: 3px;
  margin-top: var(--space-6);
  background: var(--brand-gold);
}

/* --- Breadcrumbs ----------------------------------------------------------- */
.breadcrumbs { font-size: var(--text-xs); margin-bottom: var(--space-6); }

.breadcrumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.breadcrumbs li { display: flex; align-items: center; gap: var(--space-2); }

.breadcrumbs li + li::before {
  content: '';
  width: 5px;
  height: 5px;
  border-top: 1px solid currentColor;
  border-right: 1px solid currentColor;
  transform: rotate(45deg);
  opacity: 0.6;
}

.breadcrumbs a {
  color: var(--on-dark-muted);
  text-decoration: none;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  font-weight: 600;
}
.breadcrumbs a:hover { color: var(--brand-white); text-decoration: underline; }

.breadcrumbs [aria-current='page'] {
  color: var(--brand-white);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  font-weight: 600;
}

/* --- Buttons ---------------------------------------------------------------
   Crimson is a light-surface colour only. On navy the primary button flips to
   white with a navy label — crimson on navy is 2.13:1 and fails outright.
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 48px;
  padding: var(--space-3) var(--space-8);
  background: var(--accent);
  border: 2px solid var(--accent);
  border-radius: var(--radius-md);
  color: var(--accent-contrast);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease),
    border-color var(--duration-fast) var(--ease),
    color var(--duration-fast) var(--ease);
}

.btn:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: var(--accent-contrast);
}

/* Secondary: outlined, for light surfaces. */
.btn--ghost {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--ink);
}
.btn--ghost:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: #FFFFFF;
}

/* On navy. White fill, navy label — 15.79:1. */
.btn--light {
  background: var(--brand-white);
  border-color: var(--brand-white);
  color: var(--brand-navy);
}
.btn--light:hover {
  background: var(--surface-off);
  border-color: var(--surface-off);
  color: var(--brand-navy);
}

/* On navy, secondary. White outline, white label. */
.btn--outline {
  background: transparent;
  border-color: rgb(255 255 255 / 0.55);
  color: #FFFFFF;
}
.btn--outline:hover {
  background: #FFFFFF;
  border-color: #FFFFFF;
  color: var(--brand-navy);
}

/* `[data-surface='dark'] a` would otherwise repaint these on hover. */
[data-surface='dark'] .btn--light,
[data-surface='dark'] .btn--light:hover { color: var(--brand-navy); }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-8);
}

/* --- Band header row -------------------------------------------------------
   SHARED by every band that opens with a crimson plate — Our services and Our
   work both use these classes, so the two headings can never drift apart.
   A compact crimson plate set at the same size as a nav link, with a hairline
   running from the middle of its right edge out to the edge of the screen.
   -------------------------------------------------------------------------- */
.band { padding-block: clamp(var(--space-16), 6vw, var(--space-24)); }

.band-head { margin-bottom: var(--space-12); }

.band-head-row { display: flex; align-items: center; }

.band-badge {
  flex: none;
  margin: 0;
  padding: 10px 22px;
  background: var(--brand-crimson);
  border-radius: 8px;
  color: #FFFFFF;                 /* 7.40:1 on crimson */
  font-size: var(--text-sm);      /* matches .nav-link */
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  line-height: var(--leading-snug);
  text-transform: uppercase;
}

/*
  `flex: 1` makes the rule take the space left in the container; the negative
  right margin then lets its box run on to the viewport edge. Percentages in a
  margin resolve against the containing block, so `50% - 50vw` is exactly the
  distance from the container's right edge to the screen's. The parent carries
  `.section--bleed`, which clips the overhang instead of scrolling.
*/
.band-rule {
  flex: 1;
  height: 2px;
  margin-right: calc(50% - 50vw);
  background: var(--brand-crimson);
}

.band-head .lede {
  margin-top: var(--space-4);
  max-width: 60ch;
  font-size: var(--text-base);
  color: var(--ink-muted);        /* 6.37:1 on white */
}

@media (max-width: 47.9375rem) {
  .band-badge { padding: 8px 16px; font-size: var(--text-xs); }
  .band-head { margin-bottom: var(--space-8); }
}

/* --- Cards -----------------------------------------------------------------
   One shared style for all three. `--card-accent` is the single colour knob:
   border, hover ring, the number rule and the Read more link all read it.
   -------------------------------------------------------------------------- */
.svc-grid {
  display: grid;
  gap: var(--space-4);                 /* 16px on one column */
  max-width: 1100px;                   /* three cards stay in proportion */
  margin: 0 auto;
  padding: 0;
  list-style: none;
  grid-template-columns: 1fr;
}

@media (min-width: 40rem) {
  .svc-grid { grid-template-columns: repeat(2, 1fr); gap: 1.375rem; }
}
@media (min-width: 60rem) { .svc-grid { grid-template-columns: repeat(3, 1fr); } }

.svc-card {
  --card-accent: #A8182E;

  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--surface);
  border: 1px solid var(--card-accent);
  border-radius: 8px;
  /* Layered rather than one blur: a tight contact shadow under the card and a
     wide soft one further out, which is what reads as weight rather than haze. */
  box-shadow:
    0 1px 2px rgb(21 23 31 / 0.05),
    0 8px 24px rgb(21 23 31 / 0.07);
  transition: transform var(--duration-base) var(--ease);
}

/*
  The hover state is a second, deeper shadow on a pseudo-element that is faded
  in, rather than an animated box-shadow: only opacity and transform are ever
  animated, so the compositor does the work and no frame repaints the shadow.
  The inset ring reads as a second border pixel without changing the box, so
  nothing reflows on hover either.
*/
.svc-card::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow:
    0 2px 4px rgb(21 23 31 / 0.06),
    0 18px 40px rgb(21 23 31 / 0.14),
    inset 0 0 0 1px var(--card-accent);
  opacity: 0;
  transition: opacity var(--duration-base) var(--ease);
  pointer-events: none;
}

.svc-card:hover,
.svc-card:focus-within { transform: translateY(-6px); }

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

/* One fixed frame for every card photograph, so a row of cards reads as a row
   whatever shape the files are — and it holds the same space before a
   photograph has been added at all. */
.svc-media {
  position: relative;
  aspect-ratio: 3 / 2;
  border-radius: 7px 7px 0 0;   /* inside the card's 8px, which no longer clips */
  background: #ECECEA;
  overflow: hidden;             /* holds the zoom inside the frame */
}

/* `--focal` is the per-card focalPoint in js/site.js; the default keeps faces
   and rooflines inside the frame rather than centring on a floor. */
.svc-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, center 40%);
  transition: transform var(--duration-slow) var(--ease);
}

/* A light wash that settles over the photograph on hover, so the zoom reads as
   deliberate instead of restless. */
.svc-media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgb(42 36 38 / 0.38), transparent 62%);
  opacity: 0;
  transition: opacity var(--duration-base) var(--ease);
  pointer-events: none;
}

.svc-card:hover .svc-media img,
.svc-card:focus-within .svc-media img { transform: scale(1.04); }

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

.svc-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: clamp(0.9375rem, 1.6vw, 1.25rem);   /* 15px -> 20px */
}

/* Takes the slack, which is what pins the footer to the bottom and keeps the
   cards in a row the same height. */
.svc-copy { flex: 1; }

/* 01 / 02 / 03. The one place gold appears in the card. */
.svc-index {
  display: block;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  color: #9A7B33;                 /* gold, darkened to 4.6:1 on white */
}

.svc-title {
  margin-top: var(--space-1);
  font-size: clamp(1.15rem, 0.5vw + 1.05rem, 1.25rem);
  line-height: var(--leading-snug);
  color: var(--brand-charcoal);
}

/* Short rule between the title and the copy, carrying the card accent. */
.svc-title-rule {
  display: block;
  width: 2rem;
  height: 2px;
  margin-top: var(--space-2);
  background: var(--card-accent);
}

/* Three lines, then it stops: the cards in a row keep the same rhythm however
   long a description is. */
.svc-text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
  margin-top: var(--space-2);
  color: var(--ink-muted);        /* 6.37:1 on white */
  font-size: 0.9rem;
  line-height: 1.5;
}

.svc-foot {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
}

.svc-more {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 28px;
  color: var(--card-accent);      /* 7.40:1 on white */
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  text-decoration: none;
}

.svc-more .svc-arrow {
  transition: transform var(--duration-fast) var(--ease);
}

.svc-card:hover .svc-more .svc-arrow,
.svc-more:hover .svc-arrow,
.svc-more:focus-visible .svc-arrow { transform: translateX(4px); }

.svc-more:hover { color: var(--brand-crimson-dark); text-decoration: underline; }

@media (max-width: 47.9375rem) {
  .svc-media { aspect-ratio: 16 / 10; }
  .svc-body { padding: 0.875rem 0.9375rem; }   /* 14px / 15px */
  .svc-title { font-size: 1.1rem; }
  .svc-text { font-size: 0.875rem; }
}

@media (prefers-reduced-motion: reduce) {
  .svc-card,
  .svc-card::after,
  .svc-media img,
  .svc-media::after,
  .svc-more .svc-arrow { transition: none; }
  .svc-card:hover,
  .svc-card:focus-within { transform: none; }
  .svc-card:hover .svc-media img,
  .svc-card:focus-within .svc-media img { transform: none; }
  .svc-card:hover .svc-more .svc-arrow,
  .svc-more:hover .svc-arrow { transform: none; }
}

/* --- Partners --------------------------------------------------------------
   A centred heading with a short crimson underline, then the logos in a row
   that simply wraps if more partners are added to PARTNERS in js/site.js.
   Logos are matched on height, not width, so differently shaped files sit on
   one optical line.
   -------------------------------------------------------------------------- */
.partners { background: var(--surface); }

.partners-head {
  margin-bottom: clamp(var(--space-8), 4vw, var(--space-12));
  text-align: center;
}

.partners-title {
  margin: 0;
  color: var(--brand-charcoal);          /* 14.1:1 on white */
  font-size: var(--text-2xl);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

.partners-mark {
  display: block;
  width: 48px;
  height: 2px;
  margin: var(--space-4) auto 0;
  background: var(--brand-crimson);
}

.partners-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(var(--space-12), 7vw, var(--space-20, 5rem));
  margin: 0;
  padding: 0;
  list-style: none;
}

.partner-link { display: inline-block; border-radius: var(--radius-md); }
.partner-link:focus-visible { outline-offset: 4px; }

.partner-logo {
  display: block;
  width: auto;
  /* Base 64px mobile -> 100px desktop, times the per-partner `scale` set in
     PARTNERS (js/site.js) for files that carry their own padding. */
  height: calc(clamp(4rem, 7vw, 6.25rem) * var(--logo-scale, 1));
  max-width: 100%;
  object-fit: contain;
  filter: grayscale(20%);
  /* Transform only. Animating a filter forces a repaint of the whole layer. */
  transition: transform var(--duration-base) var(--ease);
}

.partner-link:hover .partner-logo,
.partner-link:focus-visible .partner-logo,
.partner:hover .partner-logo {
  filter: grayscale(0);
  transform: scale(1.04);
}

/* Shown in place of a logo file that is not there yet. */
.partner-ph {
  display: flex;
  align-items: center;
  justify-content: center;
  height: clamp(4rem, 7vw, 6.25rem);
  min-width: 11rem;
  padding: var(--space-4) var(--space-6);
  background: #F1F1EF;
  border-radius: var(--radius-md);
  color: var(--ink-muted);               /* 6.37:1 on the panel */
  font-size: var(--text-sm);
  text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .partner-logo { transition: none; }
  .partner-link:hover .partner-logo,
  .partner-link:focus-visible .partner-logo,
  .partner:hover .partner-logo { transform: none; }
}

/* --- Service pillars -------------------------------------------------------
   White cards on off-white, each carrying its division accent as a top rule.
   The whole card is the link: one target, no detached button.
   -------------------------------------------------------------------------- */
.pillars-grid {
  display: grid;
  gap: var(--space-6);
  margin: 0;
  grid-template-columns: 1fr;
}

@media (min-width: 40rem) { .pillars-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 60rem) { .pillars-grid { grid-template-columns: repeat(3, 1fr); } }

.pillar-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: var(--space-8);
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink);
  text-decoration: none;
  transition:
    border-color var(--duration-fast) var(--ease),
    box-shadow var(--duration-fast) var(--ease),
    transform var(--duration-fast) var(--ease);
}

.pillar-card:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

/* The division accent, as a rule across the top of the card. */
.pillar-rule {
  display: block;
  width: 2.5rem;
  height: 3px;
  margin-bottom: var(--space-6);
  background: var(--accent);
}

.pillar-name { font-size: var(--text-xl); color: var(--ink); }

.pillar-summary {
  margin-top: var(--space-3);
  color: var(--ink-muted); /* 6.37:1 on white */
}

.pillar-more {
  margin-top: auto;
  padding-top: var(--space-6);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--accent); /* crimson 7.40:1 / navy 15.79:1 on white */
}
.pillar-card:hover .pillar-more { text-decoration: underline; }

/* --- Split: copy beside a facts table -------------------------------------- */
.split {
  display: grid;
  gap: clamp(var(--space-8), 5vw, var(--space-16));
  align-items: start;
  grid-template-columns: 1fr;
}

@media (min-width: 60rem) {
  .split { grid-template-columns: 1.15fr 1fr; }
}

.facts {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 3px solid var(--accent);
}

.facts > div {
  display: grid;
  gap: var(--space-1);
  padding-block: var(--space-4);
  border-bottom: 1px solid var(--line);
}

@media (min-width: 30rem) {
  .facts > div {
    grid-template-columns: auto 1fr;
    align-items: baseline;
    gap: var(--space-6);
  }
  .facts dd { text-align: right; }
}

.facts dt {
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--ink);
}

.facts dd {
  margin: 0;
  color: var(--ink-muted);
}

.section--dark .facts dt { color: var(--on-dark); }
.section--dark .facts dd { color: var(--on-dark-muted); }
.section--dark .facts > div { border-bottom-color: var(--line-dark); }

/* --- Portfolio grid --------------------------------------------------------
   Project cards. The location tag sits on the image in a solid box, which is
   the one treatment that carries contrast over an unknown photograph.
   -------------------------------------------------------------------------- */
.project-grid {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
}

@media (min-width: 40rem) { .project-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 60rem) { .project-grid { grid-template-columns: repeat(3, 1fr); } }

.project-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--surface);
  border: 1px solid var(--line);
  transition:
    border-color var(--duration-fast) var(--ease),
    box-shadow var(--duration-fast) var(--ease);
}
.project-card:hover { border-color: var(--accent); box-shadow: var(--shadow-md); }

.project-media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--surface-off) center / cover no-repeat;
  border-bottom: 3px solid var(--accent);
}

/* Placeholder state, for entries with no photograph yet. */
.project-media[data-empty='true'] {
  display: grid;
  place-items: center;
  background:
    repeating-linear-gradient(
      135deg,
      var(--surface-off) 0 10px,
      #EFEFEE 10px 20px
    );
}
.project-media[data-empty='true']::after {
  content: 'Photograph to come';
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--ink-muted);
}

.project-place {
  position: absolute;
  left: 0;
  bottom: var(--space-3);
  padding: var(--space-1) var(--space-3);
  background: var(--brand-navy);
  color: #FFFFFF;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
}

.project-flag {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  padding: var(--space-1) var(--space-3);
  background: #FFFFFF;
  border: 1px solid var(--line-strong);
  color: var(--ink-muted);
  font-size: var(--text-xs);
  font-weight: 600;
}

.project-body { padding: var(--space-6); }

.project-type {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--accent);
}

.project-name { margin-top: var(--space-2); font-size: var(--text-lg); }

.project-info { margin-top: var(--space-3); color: var(--ink-muted); font-size: var(--text-sm); }

/* Shown when a category has no entries yet. */
.project-empty {
  padding: var(--space-12);
  border: 1px dashed var(--line-strong);
  text-align: center;
  color: var(--ink-muted);
}

.note {
  margin-top: var(--space-8);
  max-width: var(--measure);
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

/* --- Service blocks --------------------------------------------------------
   One block per service on the services page: copy on the left, a short list
   of what it covers on the right, separated by a rule.
   -------------------------------------------------------------------------- */
.service-block {
  display: grid;
  gap: clamp(var(--space-6), 4vw, var(--space-16));
  padding-block: clamp(var(--space-12), 6vw, var(--space-16));
  border-top: 1px solid var(--line);
  grid-template-columns: 1fr;
  scroll-margin-top: var(--space-16);
}

.service-block:first-of-type { border-top: 0; padding-top: 0; }

@media (min-width: 60rem) {
  .service-block { grid-template-columns: 1.15fr 1fr; }
}

.service-block h2 { font-size: var(--text-2xl); }
.service-block .eyebrow + h2 { margin-top: var(--space-2); }
.service-block p { margin-top: var(--space-4); color: var(--ink-muted); max-width: var(--measure); }

.service-list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 3px solid var(--accent);
}

.service-list li {
  padding-block: var(--space-4);
  border-bottom: 1px solid var(--line);
  font-size: var(--text-sm);
}

/* --- Contact ---------------------------------------------------------------- */
.contact-grid {
  display: grid;
  gap: clamp(var(--space-8), 5vw, var(--space-16));
  align-items: start;
  grid-template-columns: 1fr;
}

@media (min-width: 60rem) {
  .contact-grid { grid-template-columns: 1fr 1.1fr; }
}

.contact-list { margin: 0; }

.contact-list > div {
  padding-block: var(--space-4);
  border-bottom: 1px solid var(--line);
}
.contact-list > div:first-child { padding-top: 0; }

.contact-list dt {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--ink-muted);
}

.contact-list dd {
  margin: var(--space-2) 0 0;
  color: var(--ink);
}
.contact-list dd a { text-decoration: none; }
.contact-list dd a:hover { text-decoration: underline; }

.form {
  display: grid;
  gap: var(--space-4);
  padding: clamp(var(--space-6), 4vw, var(--space-8));
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 3px solid var(--accent);
}

.field { display: grid; gap: var(--space-2); }

.field > span {
  font-size: var(--text-sm);
  font-weight: 600;
}

.field-req { color: var(--brand-crimson); }

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  color: var(--ink);
  font-family: var(--font-main);
  font-size: var(--text-base);
}

.field input::placeholder,
.field textarea::placeholder { color: #8A8F9C; }   /* 4.6:1 on white */

.field textarea { resize: vertical; min-height: 8rem; }

.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
  border-color: var(--brand-crimson);
  outline: 2px solid var(--brand-crimson);
  outline-offset: 2px;
}

.field [aria-invalid='true'] { border-color: var(--brand-crimson); }

/* Empty until there is something to say, so it takes no space. */
.field-error {
  color: var(--brand-crimson-dark);   /* 8.0:1 on white */
  font-size: var(--text-xs);
  font-weight: 600;
}
.field-error:empty { display: none; }

/* The honeypot. Off-screen rather than display:none, which some robots skip. */
.form-trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.field-row { display: grid; gap: var(--space-4); grid-template-columns: 1fr; }
@media (min-width: 40rem) { .field-row { grid-template-columns: 1fr 1fr; } }

.form { position: relative; }   /* the honeypot is pulled out of this box */

.form .btn { justify-self: start; }

.form-submit {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.form-submit .btn-arrow { transition: transform var(--duration-fast) var(--ease); }
.form-submit:hover .btn-arrow { transform: translateX(4px); }
.form-submit[disabled] { opacity: 0.7; cursor: progress; }

.form-note { font-size: var(--text-sm); color: var(--ink-muted); }

.form-status {
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--accent);
  background: var(--surface-off);
  font-size: var(--text-sm);
}
.form-status[hidden] { display: none; }
.form-status[data-kind='error'] {
  border-left-color: var(--brand-crimson);
  background: #FCF2F3;
  color: var(--ink);
}

/* Shown in place of the form once the enquiry is away. */
.form-sent {
  display: grid;
  justify-items: start;
  gap: var(--space-3);
  padding: clamp(var(--space-6), 4vw, var(--space-8));
  background: var(--brand-cream);
  border: 1px solid var(--line);
  border-top: 3px solid var(--brand-crimson);
}

.form-sent-icon {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-full);
  background: var(--brand-crimson);
  color: #FFFFFF;
}

.form-sent h2 { font-size: var(--text-xl); color: var(--brand-charcoal); }
.form-sent p { color: var(--ink-muted); font-size: var(--text-sm); }
.form-sent a { color: var(--brand-crimson); }

@media (prefers-reduced-motion: reduce) {
  .form-submit .btn-arrow { transition: none; }
  .form-submit:hover .btn-arrow { transform: none; }
}

.map-frame {
  width: 100%;
  aspect-ratio: 16 / 10;
  border: 1px solid var(--line);
  filter: grayscale(1) contrast(0.95);
}
.map-frame:hover { filter: none; }

/* --- CTA band --------------------------------------------------------------- */
.cta-band {
  background: var(--brand-navy);
  color: var(--on-dark);
  padding-block: clamp(var(--space-12), 6vw, var(--space-16));
}

.cta-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8);
}

.cta-inner h2 { max-width: 22ch; font-size: var(--text-2xl); }
.cta-inner p { margin-top: var(--space-2); color: var(--on-dark-muted); max-width: 46ch; }

.cta-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); }

/* --- Footer ------------------------------------------------------------------ */
.site-footer {
  background: var(--brand-navy-dark);
  color: var(--on-dark-muted);
  font-size: var(--text-sm);
}

/* `start` rather than the grid default: the brand column is the tallest, and
   stretching the others to match it is what used to leave the lists floating
   in their own white space. */
.footer-top {
  display: grid;
  align-items: start;
  gap: var(--space-6);
  padding-block: clamp(1.75rem, 3.5vw, 2.75rem);   /* 28px -> 44px */
  grid-template-columns: 1fr;
}

@media (min-width: 40rem) {
  .footer-top { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 60rem) {
  .footer-top { grid-template-columns: 1.4fr 1fr 1fr 1.1fr; gap: var(--space-8); }
}

.footer-logo { display: inline-block; }
.footer-logo img { height: 56px; width: auto; }

.footer-address {
  margin-top: var(--space-3);
  font-style: normal;
  color: var(--on-dark-muted);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
  max-width: 28ch;
}

.footer-heading {
  margin-bottom: var(--space-3);
  color: var(--brand-white);
  font-family: var(--font-main);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
}

.footer-list { margin: 0; padding: 0; list-style: none; }
.footer-list li + li { margin-top: var(--space-2); }

.footer-list a,
.footer-address a {
  color: var(--on-dark-muted);
  text-decoration: none;
}
.footer-list a:hover,
.footer-address a:hover { color: var(--brand-white); text-decoration: underline; }

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: 0.8125rem;              /* 13px */
  border-top: 1px solid var(--line-dark);
  font-size: var(--text-xs);
}

.footer-legal { display: flex; flex-wrap: wrap; gap: var(--space-4); }
.footer-legal a { color: var(--on-dark-muted); text-decoration: none; }
.footer-legal a:hover { color: var(--brand-white); text-decoration: underline; }

/* --- Floating contact widget ------------------------------------------------- */
.widget {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 999;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-2);
}

.widget-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
  transition:
    opacity var(--duration-base) var(--ease),
    transform var(--duration-base) var(--ease);
}

.widget[data-open='false'] .widget-stack {
  opacity: 0;
  transform: translateY(0.75rem) scale(0.9);
  pointer-events: none;
}

.widget-btn {
  position: relative;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  color: #FFFFFF;
  box-shadow: var(--shadow-md);
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease);
}

.widget-btn svg { width: 22px; height: 22px; }
.widget-btn:hover { transform: scale(1.08); }

.widget-call { background: var(--brand-navy); }
.widget-whatsapp { background: var(--whatsapp); color: #0B3D20; }
.widget-email { background: var(--brand-crimson); }

/* The global `a:hover` would otherwise repaint these crimson. */
.widget .widget-btn,
.widget .widget-btn:hover { color: #FFFFFF; }
.widget .widget-btn.widget-whatsapp,
.widget .widget-btn.widget-whatsapp:hover { color: #0B3D20; }

/* Tooltip, from the data-tip attribute. Hidden from assistive tech, which
   reads the aria-label instead. */
.widget-btn::after,
.widget-launcher::after {
  content: attr(data-tip);
  position: absolute;
  right: calc(100% + 0.5rem);
  top: 50%;
  translate: 0 -50%;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--brand-charcoal);
  color: #FFFFFF;
  font-size: var(--text-xs);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-fast) var(--ease);
}

.widget-btn:hover::after,
.widget-btn:focus-visible::after,
.widget-launcher:hover::after,
.widget-launcher:focus-visible::after { opacity: 1; }

.widget-launcher {
  position: relative;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--brand-crimson);
  color: #FFFFFF;
  box-shadow: 0 6px 20px rgb(21 23 31 / 0.28);
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease);
}

.widget-launcher svg { width: 26px; height: 26px; }
.widget-launcher:hover { transform: scale(1.06); }

@media (max-width: 47.9375rem) {
  .widget { right: 14px; bottom: 14px; }
  .widget-btn { width: 44px; height: 44px; }
  .widget-btn svg { width: 20px; height: 20px; }
  .widget-launcher { width: 52px; height: 52px; }
}

@media (prefers-reduced-motion: reduce) {
  .widget-stack, .widget-btn, .widget-btn::after,
  .widget-launcher, .widget-launcher::after { transition: none; }
}

/* --- Print -------------------------------------------------------------------- */
@media print {
  .site-header, .widget, .mnav, .mnav-panel, .cta-band, .hero-controls { display: none !important; }
  .hero { min-height: auto; }
  body { color: #000; }
}
