/* ============================================================
   Marvin Homes — site theme
   Tokens are copied verbatim from Design System Extracted/tokens/*.
   Component classes are ports of the design-system JSX components.
   Do not edit dist/*.html — edit here and re-run `node src/build.mjs`.
   ============================================================ */

/* ---------- @font-face — self-hosted woff2 ----------
   Gelasio replaces Georgia Pro (it is metric-compatible with Georgia, so the
   display sizing from the original design carries over unchanged).
   Archivo replaces Helvetica Now Text — a neutral grotesque of the same
   lineage. Both are SIL Open Font License, so they are safe to self-host. */
@font-face{
  font-family:"Gelasio";
  src:url("../fonts/gelasio-400.woff2") format("woff2");
  font-weight:400; font-style:normal; font-display:swap;
}
/* 500 was added 2026-08-26 so headings could come down a step from 600
   without falling back to a browser-synthesised weight. Pulled from Google's
   own latin subset and self-hosted like the rest. */
@font-face{
  font-family:"Gelasio";
  src:url("../fonts/gelasio-500.woff2") format("woff2");
  font-weight:500; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"Gelasio";
  src:url("../fonts/gelasio-600.woff2") format("woff2");
  font-weight:600; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"Gelasio";
  src:url("../fonts/gelasio-700.woff2") format("woff2");
  font-weight:700; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"Archivo";
  src:url("../fonts/archivo-400.woff2") format("woff2");
  font-weight:400; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"Archivo";
  src:url("../fonts/archivo-500.woff2") format("woff2");
  font-weight:500; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"Archivo";
  src:url("../fonts/archivo-600.woff2") format("woff2");
  font-weight:600; font-style:normal; font-display:swap;
}

/* ---------- Tokens ---------- */
:root{
  /* Brand primitives */
  --gold-900:#6d5514; --gold-800:#8c6d1e; --gold-700:#a98a28; --gold-600:#c5a132;
  --gold-500:#cfae4a; --gold-400:#dcc275; --gold-300:#e8d6a1; --gold-200:#f1e6c7; --gold-100:#f8f2e2;

  /* ---------- Brand blue ----------
     --blue-900 (#132131) is THE brand colour. Everything darker or lighter is
     a variation of it. The lighter mid-blues exist for accents; the pale blue
     of the logo mark is intentionally left alone in the artwork itself. */
  --blue-900:#132131; --blue-800:#1b2c3f; --blue-700:#24394f; --blue-600:#324b66;
  --blue-500:#456382; --blue-400:#6382a0; --blue-300:#93a9be; --blue-200:#c2cedb; --blue-100:#e4eaf0;

  /* Legacy aliases — any stray reference lands on the new brand blue. */
  --navy-900:var(--blue-900); --navy-800:var(--blue-800); --navy-700:var(--blue-700);
  --navy-600:var(--blue-600); --navy-500:var(--blue-500); --navy-400:var(--blue-400);
  --navy-300:var(--blue-300); --navy-200:var(--blue-200); --navy-100:var(--blue-100);

  /* ---------- Neutrals ----------
     The dark end IS the brand blue (no warm brown-black anywhere). Greys carry
     a slight blue cast so they sit with it; the page stays a soft warm paper,
     which is what makes the blue read as ink rather than as a corporate field. */
  --ink-900:var(--blue-900); --ink-800:var(--blue-800); --ink-700:var(--blue-700);
  --stone-900:#1f2b36; --stone-800:#33414e; --stone-700:#4d5b68; --stone-600:#6b7885;
  --stone-500:#8e99a4; --stone-400:#b0b9c2; --stone-300:#ced5dc; --stone-200:#e1e6ea; --stone-100:#eef1f4;
  --bone:#f0ece4; --bone-deep:#e7e2d8;
  --ivory:var(--bone-deep); --cream:#f4f1ea; --white:#ffffff; --black:#000000;

  /* Semantic: surfaces */
  --surface-page:var(--bone);
  --surface-raised:var(--white);
  --surface-sunken:var(--bone-deep);
  --surface-inverse:var(--ink-900);
  --surface-inverse-deep:var(--ink-900);
  --surface-accent:var(--gold-100);

  /* Semantic: text */
  --text-primary:var(--ink-900);
  --text-secondary:var(--stone-700);
  --text-muted:var(--stone-500);
  --text-inverse:var(--cream);
  --text-inverse-muted:#a7b6c6;
  --text-brand:var(--ink-900);
  --text-accent:var(--gold-700);
  --text-on-gold:var(--ink-900);

  /* Semantic: lines */
  --border-subtle:var(--stone-200);
  --border-default:var(--stone-300);
  --border-strong:var(--stone-400);
  --border-inverse:rgba(255,255,255,0.14);
  --hairline-gold:var(--gold-600);

  /* Semantic: interactive */
  --accent:var(--gold-600); --accent-hover:var(--gold-700); --accent-active:var(--gold-800);
  --accent-contrast:var(--ink-900);
  --brand:var(--ink-900); --brand-hover:var(--ink-800); --brand-active:var(--black);
  --brand-contrast:var(--cream);
  --focus-ring:var(--gold-600);

  /* Type */
  --font-display:"Gelasio",Georgia,"Times New Roman",serif;
  --font-body:"Archivo","Helvetica Neue",Helvetica,Arial,sans-serif;
  --text-2xs:0.6875rem; --text-xs:0.75rem; --text-sm:0.875rem; --text-base:1rem; --text-md:1.125rem;
  --text-lg:1.375rem; --text-xl:1.75rem; --text-2xl:2.25rem; --text-3xl:3rem; --text-4xl:4rem; --text-5xl:5.25rem;
  --leading-tight:1.05; --leading-snug:1.2; --leading-normal:1.5; --leading-relaxed:1.7;
  --tracking-tight:-0.01em; --tracking-normal:0; --tracking-wide:0.04em;
  --tracking-wider:0.12em; --tracking-widest:0.28em;
  /* 2026-08-26: display weight came down a step, 600 -> 500. Gelasio 600 at
     the display sizes this design uses (48px h1, 36px h2) sets a heavy, slabby
     line; 500 keeps the same letterforms with noticeably finer stems, which is
     what reads as expensive. 500 is self-hosted alongside 400/600/700 so this
     is a real face, not a synthesised one. */
  --weight-body:400; --weight-display:500;

  /* Spacing */
  --space-0:0; --space-1:.25rem; --space-2:.5rem; --space-3:.75rem; --space-4:1rem; --space-5:1.5rem;
  --space-6:2rem; --space-7:3rem; --space-8:4rem; --space-9:6rem; --space-10:8rem;
  /* Content runs close to full width with tight side margins; only running
     text is capped (see --width-prose and the max-widths on .lede etc.) so
     line length stays readable on very wide screens. */
  --width-prose:68ch; --width-content:1560px; --width-wide:1840px;
  /* Between the original 4rem and the full-width 1.75rem — ~50px at 1440. */
  --gutter-page:clamp(1.25rem,3.5vw,3.5rem);
  /* The tallest any single photograph may render. Sized so a project card or a
     lightbox image clears the sticky header AND still leaves margin top and
     bottom, whatever browser chrome the visitor has. 64vh on a 900px viewport
     is 576px: + 87px of card body + 85px of header = 748px, 152px to spare. */
  --media-max-h:64vh;

  /* Effects */
  --radius-none:0; --radius-xs:2px; --radius-sm:3px; --radius-md:5px; --radius-lg:8px; --radius-pill:999px;
  --shadow-xs:0 1px 2px rgba(19,33,49,.06);
  --shadow-sm:0 1px 3px rgba(19,33,49,.08),0 1px 2px rgba(19,33,49,.06);
  --shadow-md:0 4px 12px rgba(19,33,49,.09),0 2px 4px rgba(19,33,49,.06);
  --shadow-lg:0 12px 32px rgba(19,33,49,.12),0 4px 8px rgba(19,33,49,.06);
  --shadow-xl:0 24px 60px rgba(19,33,49,.16),0 8px 16px rgba(19,33,49,.08);
  --ring:0 0 0 3px rgba(197,161,50,.4);
  --ease-standard:cubic-bezier(.4,0,.2,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
  --ease-in:cubic-bezier(.4,0,1,1);
  --dur-fast:120ms; --dur-base:220ms; --dur-slow:400ms;
  --rule-thin:1px; --rule-accent:2px;

  --header-h:84px;
  /* The on-page section nav, which sticks directly beneath the header. Anything
     else that sticks has to clear both. */
  --subnav-h:62px;
}

/* On mobile browsers `vh` measures the viewport with the URL bar retracted, so a
   vh budget can still overflow the screen you are actually looking at. `dvh`
   tracks the visible viewport instead. Progressive: unsupported browsers keep vh. */
@supports (height:100dvh){
  :root{ --media-max-h:64dvh; }
}

/* ---------- Base ---------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
/* Astra's dynamic CSS ships html{font-size:91.2%} below 921px and below 544px.
   The whole spacing scale is expressed in rem, so that quietly rescaled every
   token by 0.912 on tablet and phone (--space-4 rendered 14.592px, --space-9
   87.552px) while px values set per widget in Elementor did not move at all.
   Two scales drifting apart at the tightest breakpoint is the single largest
   reason spacing read as random on mobile. The design system carries its own
   responsive steps - media queries on .section, clamp() on display sizes - so
   the root stays at 100% and 1rem means 16px at every width. */
html{font-size:100%}
body{
  margin:0;
  font-family:var(--font-body);
  font-size:var(--text-base);
  line-height:var(--leading-normal);
  color:var(--text-primary);
  background:var(--surface-page);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
h1,h2,h3,h4,h5{
  font-family:var(--font-display); font-weight:var(--weight-display);
  line-height:var(--leading-snug); color:var(--text-primary);
  margin:0 0 .5em; text-wrap:balance;
}
h1{font-size:var(--text-3xl);line-height:var(--leading-tight)}
h2{font-size:var(--text-2xl)}
h3{font-size:var(--text-xl)}
h4{font-size:var(--text-lg)}
p{margin:0 0 1em;text-wrap:pretty}
img{max-width:100%}
a{color:var(--text-brand);text-decoration:none;transition:color var(--dur-fast) var(--ease-standard)}
a:hover{color:var(--accent-hover)}
:focus-visible{outline:none;box-shadow:var(--ring);border-radius:var(--radius-sm)}
::selection{background:var(--gold-200);color:var(--ink-900)}

/* ---------- Layout ---------- */
.container{width:100%;max-width:var(--width-content);margin:0 auto;padding-left:var(--gutter-page);padding-right:var(--gutter-page)}
.container--wide{max-width:var(--width-wide)}
.section{padding-top:var(--space-9);padding-bottom:var(--space-9)}
.section--tight{padding-top:var(--space-7);padding-bottom:var(--space-7)}
.section--cream{background:var(--surface-page)}
.section--ivory{background:var(--surface-sunken)}
/* Dark bands are the brand blue #132131. */
.section--dark{background:var(--ink-900);color:var(--text-inverse)}
.section--dark h1,.section--dark h2,.section--dark h3{color:var(--cream)}
/* The closing CTA band: a quiet bone field with a gold rule, not a gold field. */
.section--accent{background:var(--surface-sunken);border-top:1px solid var(--border-subtle);border-bottom:1px solid var(--border-subtle)}

/* ---------- Eyebrow + gold rule ----------
   Eyebrows are muted blue-grey; the short gold rule beneath is the one brand
   accent. Gold text + gold rule together is what read as collegiate. */
.eyebrow{
  display:block; font-family:var(--font-body); font-size:var(--text-xs);
  letter-spacing:var(--tracking-wider); text-transform:uppercase;
  color:var(--stone-600); font-weight:400; margin:0;
}
.eyebrow--inverse{color:var(--text-inverse-muted)}
.eyebrow--accent{color:var(--text-accent)}
.rule-gold{height:var(--rule-accent);width:56px;background:var(--gold-600);border:0;margin:var(--space-4) 0}

/* ---------- SectionHeading ---------- */
.section-heading{max-width:640px}
.section-heading__title{margin:var(--space-4) 0 0;font-size:var(--text-2xl)}
.section-heading__lead{margin:var(--space-4) 0 0;font-size:var(--text-md);line-height:var(--leading-relaxed);color:var(--text-secondary)}
.section--dark .section-heading__lead{color:var(--text-inverse-muted)}
.section-head-row{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-5);flex-wrap:wrap;margin-bottom:var(--space-7)}

/* ---------- Buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:12px 24px;
  font-family:var(--font-body);font-size:var(--text-xs);font-weight:400;
  letter-spacing:var(--tracking-wider);text-transform:uppercase;line-height:1;
  border-radius:var(--radius-sm);border:1px solid transparent;cursor:pointer;
  white-space:nowrap;
  transition:background var(--dur-base) var(--ease-standard),
             color var(--dur-base) var(--ease-standard),
             border-color var(--dur-base) var(--ease-standard);
}
.btn--sm{padding:8px 16px;font-size:var(--text-2xs);gap:6px}
.btn--lg{padding:16px 34px;font-size:var(--text-sm);gap:10px}
.btn--full{display:flex;width:100%}
/* Primary is warm ink — neutral and expensive-looking, per the reference sites.
   Gold fill is reserved for .btn--accent, used at most once per page. */
.btn--primary{background:var(--ink-900);color:var(--cream);border-color:var(--ink-900)}
.btn--primary:hover{background:var(--ink-800);border-color:var(--ink-800);color:var(--cream)}
.btn--accent{background:var(--gold-600);color:var(--ink-900);border-color:var(--gold-600)}
.btn--accent:hover{background:var(--gold-700);border-color:var(--gold-700);color:var(--ink-900)}
.btn--secondary{background:var(--stone-800);color:var(--cream);border-color:var(--stone-800)}
.btn--secondary:hover{background:var(--ink-900);border-color:var(--ink-900);color:var(--cream)}
.btn--outline{background:transparent;color:var(--ink-900);border-color:var(--ink-900)}
.btn--outline:hover{background:var(--ink-900);color:var(--cream)}
.btn--outline-gold{background:transparent;color:var(--gold-700);border-color:var(--gold-600)}
.btn--outline-gold:hover{background:var(--gold-600);color:var(--ink-900)}
.btn--ghost{background:transparent;color:var(--ink-900)}
.btn--ghost:hover{background:var(--stone-100);color:var(--ink-800)}
.section--dark .btn--outline-gold{color:var(--cream);border-color:rgba(255,255,255,.4)}
.section--dark .btn--outline-gold:hover{background:var(--cream);border-color:var(--cream);color:var(--ink-900)}
/* Over photography the gold outline loses contrast — go to cream on glass. */
.hero .btn--outline-gold,.page-head .btn--outline-gold{
  color:var(--cream);border-color:rgba(255,255,255,.55);
  background:rgba(12,20,30,.28);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
}
.hero .btn--outline-gold:hover,.page-head .btn--outline-gold:hover{
  background:var(--gold-600);border-color:var(--gold-600);color:var(--ink-900);
}
.btn .i{width:1em;height:1em;flex:none;stroke-width:1.75}
.btn--lg .i{width:18px;height:18px}
.btn--sm .i{width:14px;height:14px}

/* ---------- Icons ---------- */
.i{display:inline-block;vertical-align:middle;width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
.i--gold{color:var(--gold-700)}

/* ---------- Stat ---------- */
.stat__value{font-family:var(--font-display);font-weight:600;font-size:var(--text-3xl);line-height:1;color:var(--ink-900);font-variant-numeric:tabular-nums}
.stat__label{display:block;margin-top:var(--space-2);font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--text-muted)}
/* Stat numerals on dark are the one place gold earns a full-size role. */
.section--dark .stat__value{color:var(--gold-500)}
.section--dark .stat__label{color:var(--text-inverse-muted)}
.stat-row{display:flex;justify-content:space-between;flex-wrap:wrap;gap:var(--space-6)}

/* ---------- Badge / Tag ---------- */
/* Location badges sit on photography — smoked glass reads as neutral and
   premium, where a gold pill on every card read as excessive. */
.badge{
  display:inline-flex;align-items:center;gap:6px;padding:6px 11px;
  font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;
  border-radius:var(--radius-xs);
  background:rgba(12,20,30,.62);color:var(--cream);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
}
.badge--accent{background:var(--gold-600);color:var(--ink-900);-webkit-backdrop-filter:none;backdrop-filter:none}
.badge--quiet{background:var(--gold-100);color:var(--gold-800);-webkit-backdrop-filter:none;backdrop-filter:none}
.tag{
  display:inline-flex;align-items:center;gap:6px;padding:7px 14px;
  font-size:var(--text-xs);color:var(--text-secondary);
  background:var(--white);border:1px solid var(--border-subtle);border-radius:var(--radius-pill);
}

/* ---------- Card ---------- */
.card{
  background:var(--surface-raised);border:1px solid var(--border-subtle);
  border-radius:var(--radius-md);box-shadow:var(--shadow-sm);
  transition:box-shadow var(--dur-base) var(--ease-standard),transform var(--dur-base) var(--ease-standard);
}
.card--hover:hover{box-shadow:var(--shadow-xl);transform:translateY(-3px)}
.card__body{padding:var(--space-5)}

/* Padded card. This used to carry a 56px gold stub at the top-left; it read as a
   stray mark rather than an accent, so the card is now plain and the gold rule
   stays where it means something — under an eyebrow, as .rule-gold. */
.card--pad{position:relative;padding:var(--space-6);overflow:hidden}

/* ---------- PropertyCard ---------- */
.property{display:flex;flex-direction:column;overflow:hidden}
.property__media{position:relative;aspect-ratio:4/3;background:var(--stone-200);overflow:hidden}
.property__media img{width:100%;height:100%;object-fit:cover;display:block;transition:transform var(--dur-slow) var(--ease-standard)}
.property:hover .property__media img{transform:scale(1.04)}
.property__badge{position:absolute;top:14px;left:14px}
.property__body{padding:var(--space-5);display:flex;flex-direction:column;gap:var(--space-3)}
.property__name{margin:0;font-size:var(--text-lg);color:var(--ink-900)}
.property__loc{display:inline-flex;align-items:center;gap:6px;font-size:var(--text-sm);color:var(--text-muted)}
.property__specs{display:flex;flex-wrap:wrap;gap:var(--space-4);padding-top:var(--space-2);border-top:1px solid var(--border-subtle)}
.property__spec{display:inline-flex;align-items:center;gap:6px;font-size:var(--text-sm);color:var(--text-secondary)}
.property__price{margin-top:var(--space-2);font-family:var(--font-display);font-weight:600;font-size:var(--text-xl);color:var(--ink-900);font-variant-numeric:tabular-nums}

/* ---------- Quote ---------- */
.quote{margin:0}
.quote__text{font-family:var(--font-display);font-weight:600;font-size:var(--text-xl);line-height:1.4;color:var(--ink-900);margin:0}
.quote__attr{display:block;margin-top:var(--space-5);font-size:var(--text-xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--text-muted)}
.quote--inverse .quote__text{color:var(--cream)}
.quote--inverse .quote__attr{color:var(--text-inverse-muted)}
.quote--inverse .quote__attr b{color:var(--gold-500);font-weight:400}
.quote__mark{width:40px;height:2px;background:var(--gold-600);border:0;margin:0 0 var(--space-5)}
.quote--center{text-align:center}
.quote--center .quote__mark{margin-left:auto;margin-right:auto}

/* ---------- Grids ---------- */
.grid{display:grid;gap:var(--space-5)}
.grid--2{grid-template-columns:repeat(2,1fr)}
.grid--3{grid-template-columns:repeat(3,1fr)}
.grid--4{grid-template-columns:repeat(4,1fr)}
.split{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-8);align-items:center}
.split--wide-left{grid-template-columns:1.15fr 1fr}
.split--wide-right{grid-template-columns:1fr 1.15fr}

/* ---------- Media ---------- */
.media{position:relative;overflow:hidden;border-radius:var(--radius-md);background:var(--stone-200)}
.media img{width:100%;height:100%;object-fit:cover;display:block}
.media--4x3{aspect-ratio:4/3}
.media--5x4{aspect-ratio:5/4}
.media--3x2{aspect-ratio:3/2}
.media--1x1{aspect-ratio:1/1}
.media--tall{aspect-ratio:3/4}
.media__caption{
  position:absolute;left:0;right:0;bottom:0;padding:var(--space-5);
  background:linear-gradient(to top,rgba(12,20,30,.72),transparent);
  color:var(--cream);font-size:var(--text-sm);
}

/* ---------- Header ---------- */
.mh-header{
  position:sticky;top:0;z-index:40;
  background:rgba(240,236,228,.88);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  border-bottom:1px solid var(--border-subtle);
}
/* Three columns so the wordmark sits dead centre — the pattern shared by the
   reference sites. Nav left, logo centre, actions right. */
.mh-header__inner{
  /* Equal outer columns so the centre column is page-centred regardless of
     how wide the logo and the actions happen to be. */
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  gap:var(--space-6);height:var(--header-h);
}
.mh-header__logo img{height:44px;width:auto;display:block}
/* Explicit column AND row on every child — column alone lets grid advance to
   a second row. Logo left, nav centred, phone + CTA right. */
.mh-header__logo{grid-area:1/1;display:flex;align-items:center;justify-self:start}
.mh-header .mh-nav{grid-area:1/2;justify-self:center}
.mh-header__cta{grid-area:1/3;justify-self:end}
.mh-header .nav-toggle{grid-area:1/3;justify-self:end}

/* Phone is plain clickable text, not a button. */
.mh-header__phone{
  display:inline-flex;align-items:center;gap:8px;
  font-size:var(--text-xs);letter-spacing:var(--tracking-wide);
  color:var(--text-secondary);white-space:nowrap;
}
.mh-header__phone:hover{color:var(--text-primary)}
.mh-header__phone .i{width:15px;height:15px;color:var(--gold-700)}
.mh-nav{display:flex;align-items:center;gap:var(--space-6)}
.mh-nav a{
  padding:6px 0;font-size:var(--text-xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;
  color:var(--text-secondary);border-bottom:2px solid transparent;
  transition:color var(--dur-fast) var(--ease-standard),border-color var(--dur-fast) var(--ease-standard);
}
.mh-nav a:hover{color:var(--ink-900)}
.mh-nav a[aria-current="page"]{color:var(--ink-900);border-bottom-color:var(--gold-600)}
.mh-header__cta{display:flex;align-items:center;gap:var(--space-3)}

/* Mobile drawer */
.nav-toggle{display:none;background:none;border:0;padding:8px;cursor:pointer;color:var(--ink-900)}
.nav-toggle .i{width:24px;height:24px}
.drawer{
  position:fixed;inset:0;z-index:50;visibility:hidden;pointer-events:none;
  /* The closed panel sits translated past the right edge; clip it here so it
     cannot widen the document and create a horizontal scrollbar. */
  overflow:hidden;
}
.drawer__scrim{
  position:absolute;inset:0;background:rgba(12,20,30,.5);opacity:0;
  transition:opacity var(--dur-base) var(--ease-standard);
}
.drawer__panel{
  position:absolute;top:0;right:0;bottom:0;width:min(88vw,360px);
  background:var(--cream);box-shadow:var(--shadow-xl);
  transform:translateX(100%);transition:transform var(--dur-slow) var(--ease-out);
  display:flex;flex-direction:column;padding:var(--space-6);overflow-y:auto;
}
.drawer.is-open{visibility:visible;pointer-events:auto}
.drawer.is-open .drawer__scrim{opacity:1}
.drawer.is-open .drawer__panel{transform:translateX(0)}
.drawer__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-6)}
.drawer__head img{height:34px;width:auto}
.drawer__close{background:none;border:0;padding:8px;cursor:pointer;color:var(--ink-900)}
.drawer__close .i{width:22px;height:22px}
.drawer__nav{display:flex;flex-direction:column;gap:var(--space-1);margin-bottom:var(--space-6)}
.drawer__nav a{
  padding:var(--space-3) 0;font-family:var(--font-display);font-size:var(--text-lg);
  color:var(--ink-900);border-bottom:1px solid var(--border-subtle);
}
.drawer__nav a[aria-current="page"]{color:var(--gold-700)}
.drawer__foot{display:flex;flex-direction:column;gap:var(--space-3);margin-top:auto}
body.is-locked{overflow:hidden}

/* ---------- Footer ---------- */
.mh-footer{background:var(--ink-900);color:var(--text-inverse-muted);padding-top:var(--space-9);padding-bottom:var(--space-6)}
.mh-footer__grid{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:var(--space-7);padding-bottom:var(--space-8);border-bottom:1px solid var(--border-inverse)}
.mh-footer__logo{height:52px;width:auto;margin:0 0 var(--space-5);display:block}
.mh-footer p{font-size:var(--text-sm);line-height:var(--leading-relaxed);color:var(--text-inverse-muted);max-width:280px}
.mh-footer h4{font-family:var(--font-body);font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--gold-500);margin:0 0 var(--space-4);font-weight:400}
.mh-footer ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
.mh-footer ul a{color:var(--text-inverse-muted);font-size:var(--text-sm)}
.mh-footer ul a:hover{color:var(--gold-500)}
.mh-footer__legal{display:flex;align-items:center;justify-content:space-between;padding-top:var(--space-5);flex-wrap:wrap;gap:var(--space-4)}
.mh-footer__legal span{font-size:var(--text-xs);color:var(--stone-400)}
.mh-footer__social{display:flex;gap:var(--space-4);color:var(--gold-500)}
.mh-footer__social a{color:var(--gold-500);display:inline-flex}
.mh-footer__social a:hover{color:var(--gold-400)}

/* ---------- Hero ---------- */
.hero{
  position:relative;overflow:hidden;
  min-height:clamp(520px,78vh,760px);
  display:flex;align-items:flex-end;
  background:linear-gradient(135deg,var(--ink-900),var(--ink-700));
  color:var(--cream);
}
.hero__bg{position:absolute;inset:0;z-index:0}
.hero__bg img{width:100%;height:100%;object-fit:cover;display:block;will-change:transform}
.hero__scrim{position:absolute;inset:0;z-index:1;background:linear-gradient(to top,rgba(12,20,30,.82),rgba(12,20,30,.35) 55%,rgba(12,20,30,.45))}
.hero__mark{position:absolute;right:-4%;top:50%;transform:translateY(-50%);height:115%;opacity:.06;z-index:1;pointer-events:none}
.hero__inner{position:relative;z-index:2;padding-top:var(--space-9);padding-bottom:var(--space-9)}
.hero__title{
  font-size:clamp(2.5rem,6.2vw,var(--text-5xl));line-height:1.02;color:var(--cream);
  margin:var(--space-4) 0 var(--space-5);max-width:16ch;
}
.hero__lead{font-size:var(--text-md);line-height:var(--leading-relaxed);color:var(--text-inverse-muted);max-width:54ch;margin:0 0 var(--space-6)}
.hero__actions{display:flex;gap:var(--space-3);flex-wrap:wrap}

/* Page header (interior pages) */
.page-head{
  position:relative;overflow:hidden;background:linear-gradient(135deg,var(--ink-900),var(--ink-700));
  color:var(--cream);padding-top:var(--space-9);padding-bottom:var(--space-9);
}
.page-head__bg{position:absolute;inset:0;z-index:0}
.page-head__bg img{width:100%;height:100%;object-fit:cover;display:block}
.page-head__scrim{position:absolute;inset:0;z-index:1;background:linear-gradient(to top,rgba(12,20,30,.86),rgba(12,20,30,.55))}
.page-head__inner{position:relative;z-index:2}
.page-head h1{color:var(--cream);font-size:clamp(2.25rem,5vw,var(--text-4xl));margin:var(--space-4) 0 0;max-width:18ch}
.page-head p{color:var(--text-inverse-muted);font-size:var(--text-md);line-height:var(--leading-relaxed);max-width:56ch;margin:var(--space-4) 0 0}

/* ---------- Feature list (icon + label) ---------- */
.feature-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-4);margin-top:var(--space-6)}
.feature{display:flex;align-items:center;gap:var(--space-3)}
.feature__icon{display:inline-flex;width:44px;height:44px;flex:none;align-items:center;justify-content:center;background:var(--gold-100);border-radius:var(--radius-sm);color:var(--gold-700)}
.feature__icon .i{width:20px;height:20px}
.feature span{font-size:var(--text-sm);color:var(--ink-900)}

/* ---------- How We Build — sticky intro, cycling phase cards ----------
   The heading holds still on the left while the phases move through the right
   column. Every card shares ONE sticky top and they are all the same height, so
   each card rises and covers the one before it exactly — a single phase in view
   at a time. Patterned on the scroll accordion at oliviaharperhomes.com.

   Equal height is load-bearing: a short card cannot fully cover a taller one,
   and the taller one's foot would show below it. */
.buildflow{
  display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
  gap:clamp(2rem,5vw,5rem);align-items:start;
}
.buildflow__intro{position:sticky;top:calc(var(--header-h) + var(--subnav-h) + var(--space-6))}
.buildflow__title{font-size:var(--text-3xl)}
.buildflow__cards{display:grid;gap:var(--space-6)}

.phasecard{
  position:sticky;top:calc(var(--header-h) + var(--subnav-h) + var(--space-6));
  display:flex;flex-direction:column;overflow:hidden;
  height:clamp(26rem, calc(100vh - 15rem), 36rem);
  background:var(--surface-raised);border-radius:var(--radius-md);
  box-shadow:var(--shadow-lg);
}
/* The picture takes whatever the copy leaves, so a long phase never clips. */
.phasecard__media{position:relative;flex:1 1 auto;min-height:6rem;overflow:hidden;background:var(--stone-200)}
.phasecard__media img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.phasecard__step{
  position:absolute;left:var(--space-5);top:var(--space-5);
  padding:6px 14px;border-radius:var(--radius-pill);
  background:rgba(19,33,49,.82);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  color:var(--cream);font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;
}
.phasecard__body{flex:none;padding:var(--space-5) var(--space-6) var(--space-6)}
.phasecard__meta{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-4)}
.phasecard__meta h3{margin:0;font-size:var(--text-xl)}
.phasecard__count{
  font-family:var(--font-display);font-size:var(--text-sm);color:var(--gold-700);
  font-variant-numeric:tabular-nums;flex:none;
}
.phasecard__body .eyebrow{margin:var(--space-2) 0 var(--space-3)}
.phasecard__body p{margin:0;color:var(--text-secondary);font-size:var(--text-sm);line-height:var(--leading-relaxed)}

.step__num{
  font-family:var(--font-display);font-size:var(--text-lg);color:var(--gold-700);
  width:56px;flex:none;font-variant-numeric:tabular-nums;
  border-top:var(--rule-accent) solid var(--gold-600);padding-top:var(--space-3);
}
.step h3{margin:0 0 var(--space-2);font-size:var(--text-2xl)}
.step p{margin:0;color:var(--text-secondary);max-width:60ch}

/* ---------- Accordion ---------- */
.accordion{border-top:1px solid var(--border-subtle)}
.acc__item{border-bottom:1px solid var(--border-subtle)}
.acc__trigger{
  width:100%;display:flex;align-items:center;justify-content:space-between;gap:var(--space-4);
  background:none;border:0;cursor:pointer;text-align:left;
  padding:var(--space-5) 0;font-family:var(--font-display);font-weight:600;
  font-size:var(--text-md);color:var(--ink-900);
}
.acc__trigger .i{flex:none;color:var(--gold-700);transition:transform var(--dur-base) var(--ease-standard)}
.acc__item.is-open .acc__trigger .i{transform:rotate(45deg)}
.acc__panel{overflow:hidden;height:0;transition:height var(--dur-base) var(--ease-standard)}
.acc__panel p{margin:0 0 var(--space-5);color:var(--text-secondary);max-width:68ch}

/* ---------- Filters ---------- */
.filters{display:flex;flex-wrap:wrap;gap:var(--space-2);margin-bottom:var(--space-7)}
.filter{
  padding:8px 18px;font-size:var(--text-xs);letter-spacing:var(--tracking-wide);
  background:transparent;border:1px solid var(--border-default);border-radius:var(--radius-pill);
  color:var(--text-secondary);cursor:pointer;
  transition:background var(--dur-base) var(--ease-standard),color var(--dur-base) var(--ease-standard),border-color var(--dur-base) var(--ease-standard);
}
.filter:hover{border-color:var(--ink-900);color:var(--ink-900)}
.filter.is-active{background:var(--ink-900);border-color:var(--ink-900);color:var(--cream)}
.is-hidden{display:none !important}
.filter-empty{padding:var(--space-8) 0;text-align:center;color:var(--text-muted)}

/* ---------- Forms ---------- */
.field{display:flex;flex-direction:column;gap:var(--space-2);margin-bottom:var(--space-5)}
.field label{font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--text-secondary)}
.field .req{color:var(--gold-700)}
.field input,.field select,.field textarea{
  font-family:var(--font-body);font-size:var(--text-base);color:var(--ink-900);
  padding:14px 16px;background:var(--white);
  border:1px solid var(--border-default);border-radius:var(--radius-sm);
  transition:border-color var(--dur-base) var(--ease-standard),box-shadow var(--dur-base) var(--ease-standard);
  width:100%;
}
.field textarea{min-height:140px;resize:vertical}
.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--gold-600);box-shadow:var(--ring)}
.field input::placeholder,.field textarea::placeholder{color:var(--stone-400)}
.field.has-error input,.field.has-error select,.field.has-error textarea{border-color:#b0402f}
.field__error{font-size:var(--text-xs);color:#b0402f;display:none;text-transform:none;letter-spacing:0}
.field.has-error .field__error{display:block}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-4)}
.form-note{font-size:var(--text-xs);color:var(--text-muted);margin-top:var(--space-4)}
.form-success{
  display:none;padding:var(--space-7);text-align:center;
  background:var(--gold-100);border-radius:var(--radius-md);
}
.form-success.is-visible{display:block}
.form-success h3{margin:var(--space-4) 0 var(--space-2)}
.form-success p{color:var(--text-secondary);margin:0}

/* ---------- Contact detail rows ---------- */
.contact-row{display:flex;gap:var(--space-4);align-items:flex-start;padding:var(--space-5) 0;border-bottom:1px solid var(--border-subtle)}
.contact-row:last-child{border-bottom:0}
.contact-row .i{color:var(--gold-700);flex:none;margin-top:3px}
.contact-row dt{font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--text-muted);margin:0 0 4px}
.contact-row dd{margin:0;font-size:var(--text-md);color:var(--ink-900)}

/* ---------- Sticky rail (project detail) ---------- */
.rail{position:sticky;top:calc(var(--header-h) + var(--space-5))}

/* ---------- Gallery ---------- */
.gallery{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--space-3)}
.gallery__main{grid-column:span 4}
.gallery figure{margin:0}

/* ---------- Spec strip ---------- */
.spec-strip{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--space-5);padding:var(--space-6) 0;border-top:1px solid var(--border-subtle);border-bottom:1px solid var(--border-subtle)}
.spec__label{font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--text-muted);display:block;margin-bottom:var(--space-2)}
.spec__value{font-family:var(--font-display);font-weight:600;font-size:var(--text-lg);color:var(--ink-900);font-variant-numeric:tabular-nums}

/* ---------- Timeline ---------- */
.timeline{position:relative;padding-left:var(--space-7);margin-top:var(--space-7)}
.timeline::before{content:"";position:absolute;left:6px;top:8px;bottom:8px;width:1px;background:var(--border-default)}
.timeline__item{position:relative;padding-bottom:var(--space-7)}
.timeline__item:last-child{padding-bottom:0}
.timeline__item::before{
  content:"";position:absolute;left:calc(-1 * var(--space-7) + 2px);top:7px;
  width:9px;height:9px;background:var(--gold-600);border-radius:50%;
}
.timeline__year{font-family:var(--font-display);font-weight:600;font-size:var(--text-lg);color:var(--gold-700);display:block;margin-bottom:var(--space-1)}
.timeline__item p{margin:0;color:var(--text-secondary);max-width:60ch}

/* ---------- CTA band ---------- */
.cta-band{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:var(--space-5)}
.cta-band h2{margin:0 0 6px;color:var(--ink-900)}
.cta-band p{margin:0;color:var(--ink-800);font-size:var(--text-md)}

/* ---------- Person card ---------- */
.person__media{aspect-ratio:4/5;border-radius:var(--radius-md);overflow:hidden;background:var(--stone-200);margin-bottom:var(--space-4)}
.person__media img{width:100%;height:100%;object-fit:cover;display:block}
.person h3{margin:0 0 2px;font-size:var(--text-md)}
.person span{font-size:var(--text-xs);letter-spacing:var(--tracking-wide);color:var(--text-muted)}

/* ---------- Scroll reveal ---------- */
[data-reveal]{opacity:0;transform:translateY(18px);transition:opacity var(--dur-slow) var(--ease-out),transform var(--dur-slow) var(--ease-out)}
[data-reveal].is-in{opacity:1;transform:none}

/* ---------- Skip link ---------- */
.skip-link{position:absolute;left:-9999px;top:0;z-index:100;background:var(--ink-900);color:var(--cream);padding:12px 20px;font-size:var(--text-xs);letter-spacing:var(--tracking-wider);text-transform:uppercase}
.skip-link:focus{left:0;color:var(--cream)}

/* ============================================================
   Dropdown navigation
   ============================================================ */
.navitem{position:relative}
.navitem__panel{
  position:absolute;top:100%;left:50%;transform:translateX(-50%) translateY(6px);
  min-width:250px;padding:var(--space-3);
  background:var(--cream);border:1px solid var(--border-subtle);
  border-radius:var(--radius-md);box-shadow:var(--shadow-lg);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity var(--dur-base) var(--ease-standard),transform var(--dur-base) var(--ease-standard),visibility var(--dur-base);
  display:flex;flex-direction:column;gap:2px;
}
.navitem:hover .navitem__panel,
.navitem:focus-within .navitem__panel{opacity:1;visibility:visible;pointer-events:auto;transform:translateX(-50%) translateY(0)}
.navitem__panel a{
  padding:10px 12px;border:0;border-radius:var(--radius-sm);
  font-size:var(--text-xs);letter-spacing:var(--tracking-wide);text-transform:none;
  color:var(--text-secondary);white-space:nowrap;
}
.navitem__panel a:hover{background:var(--stone-100);color:var(--ink-900)}
.navitem__panel a[aria-current="page"]{color:var(--text-accent)}
/* Hover-bridge: keeps the panel open while the cursor crosses the gap. */
.navitem::after{content:"";position:absolute;left:0;right:0;top:100%;height:14px}
.drawer__sub{display:flex;flex-direction:column;padding-left:var(--space-4)}
.drawer__sub a{font-family:var(--font-body);font-size:var(--text-sm);color:var(--text-secondary);padding:10px 0}

/* ============================================================
   Hero video
   ============================================================ */
.hero__video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;opacity:0;transition:opacity 1.2s var(--ease-out)}
.hero__video.is-ready{opacity:1}
.hero__poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0}
.hero__eyebrow{display:inline-flex;align-items:center;gap:var(--space-3);color:var(--gold-500);font-size:var(--text-xs);letter-spacing:var(--tracking-wider);text-transform:uppercase}
.hero__eyebrow::before{content:"";width:40px;height:2px;background:var(--gold-600);display:block}
.hero__scroll{
  position:absolute;left:50%;bottom:var(--space-6);transform:translateX(-50%);z-index:3;
  display:flex;flex-direction:column;align-items:center;gap:var(--space-2);
  color:var(--text-inverse-muted);font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;
}
.hero__scroll span{display:block;width:1px;height:44px;background:linear-gradient(to bottom,var(--gold-600),transparent);animation:scrollpulse 2.4s var(--ease-standard) infinite}
@keyframes scrollpulse{0%{opacity:.2;transform:scaleY(.4);transform-origin:top}50%{opacity:1;transform:scaleY(1);transform-origin:top}100%{opacity:.2;transform:scaleY(.4);transform-origin:top}}

/* Staggered hero text entrance */
.hero [data-hero]{opacity:0;transform:translateY(22px);animation:heroIn .9s var(--ease-out) forwards}
.hero [data-hero="1"]{animation-delay:.15s}
.hero [data-hero="2"]{animation-delay:.3s}
.hero [data-hero="3"]{animation-delay:.45s}
.hero [data-hero="4"]{animation-delay:.6s}
@keyframes heroIn{to{opacity:1;transform:none}}

/* ============================================================
   Editorial full-bleed band
   ============================================================ */
.bleed{position:relative;min-height:clamp(420px,60vh,620px);display:flex;align-items:center;overflow:hidden;color:var(--cream)}
.bleed__bg{position:absolute;inset:0;z-index:0}
.bleed__bg img{width:100%;height:100%;object-fit:cover;display:block;will-change:transform}
.bleed__scrim{position:absolute;inset:0;z-index:1;background:linear-gradient(90deg,rgba(12,20,30,.88),rgba(12,20,30,.45) 60%,rgba(12,20,30,.2))}
.bleed__inner{position:relative;z-index:2;padding-top:var(--space-9);padding-bottom:var(--space-9);max-width:620px}
/* A band carrying no copy — shorter, and evenly scrimmed rather than darkened
   down one side for text that is no longer there. */
.bleed--quiet{min-height:clamp(240px,32vh,380px)}
.bleed--quiet .bleed__scrim{background:linear-gradient(180deg,rgba(12,20,30,.34),rgba(12,20,30,.18))}
.bleed h2{color:var(--cream)}
.bleed p{color:var(--text-inverse-muted);font-size:var(--text-md);line-height:var(--leading-relaxed)}

/* ============================================================
   Project cards (Projects page)
   ============================================================ */
.projcard{
  position:relative;display:block;width:100%;text-align:left;padding:0;border:0;cursor:pointer;
  background:var(--surface-raised);border-radius:var(--radius-md);overflow:hidden;
  box-shadow:var(--shadow-sm);
  transition:box-shadow var(--dur-base) var(--ease-standard),transform var(--dur-base) var(--ease-standard);
  height:100%;
}
/* Two across, four down. The height budget now applies per CELL rather than per
   card: the media is a fixed 16/9 box, so capping the grid's width caps each
   image's height. Two cells plus the gap is the widest the grid may be. */
.projects-grid{
  display:grid;grid-template-columns:repeat(2,1fr);gap:var(--space-7);
  max-width:min(var(--width-wide), calc(2 * var(--media-max-h) * 16 / 9 + var(--space-7)));
  margin-inline:auto;
}
/* Below this the two columns get too narrow to read a blurb in. */
@media (max-width:900px){
  .projects-grid{grid-template-columns:1fr;gap:var(--space-6)}
}
.projcard:hover{box-shadow:var(--shadow-xl);transform:translateY(-3px)}
.projcard__media{position:relative;aspect-ratio:16/9;overflow:hidden;background:var(--stone-200)}
.projcard__media img{width:100%;height:100%;object-fit:cover;display:block;transition:transform 700ms var(--ease-standard)}
.projcard:hover .projcard__media img{transform:scale(1.045)}
.projcard__overlay{position:absolute;inset:0;background:linear-gradient(to top,rgba(12,20,30,.86),rgba(12,20,30,.1) 62%);display:flex;align-items:flex-end;padding:var(--space-6)}
.projcard__meta{color:var(--cream);width:100%}
.projcard__meta h3{color:var(--cream);margin:0 0 4px;font-size:var(--text-2xl)}
.projcard__sub{display:flex;align-items:center;gap:var(--space-4);flex-wrap:wrap;font-size:var(--text-sm);color:var(--text-inverse-muted)}
.projcard__count{
  display:inline-flex;align-items:center;gap:8px;padding:8px 16px;
  border:1px solid rgba(255,255,255,.4);border-radius:var(--radius-pill);
  font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--cream);
  transition:background var(--dur-base) var(--ease-standard),border-color var(--dur-base) var(--ease-standard);
}
.projcard:hover .projcard__count{background:var(--gold-600);border-color:var(--gold-600);color:var(--ink-900)}
.projcard__body{padding:var(--space-5) var(--space-6) var(--space-6)}
.projcard__body p{margin:0;color:var(--text-secondary);max-width:70ch}
.projcard--soon .projcard__media{display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,var(--stone-200),var(--stone-300))}
.projcard--soon .projcard__media img{width:auto;height:64px;object-fit:contain;opacity:.28}

/* ============================================================
   Lightbox
   ============================================================ */
.lightbox{position:fixed;inset:0;z-index:60;visibility:hidden;pointer-events:none}
.lightbox__scrim{position:absolute;inset:0;background:rgba(12,20,30,.88);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);opacity:0;transition:opacity var(--dur-base) var(--ease-standard)}
.lightbox__panel{
  position:absolute;inset:0;overflow-y:auto;overscroll-behavior:contain;
  opacity:0;transform:translateY(20px);
  transition:opacity var(--dur-base) var(--ease-out),transform var(--dur-slow) var(--ease-out);
}
.lightbox.is-open{visibility:visible;pointer-events:auto}
.lightbox.is-open .lightbox__scrim{opacity:1}
.lightbox.is-open .lightbox__panel{opacity:1;transform:none}
.lightbox__head{
  position:sticky;top:0;z-index:2;display:flex;align-items:center;justify-content:space-between;gap:var(--space-5);
  padding:var(--space-5) var(--gutter-page);
  background:rgba(12,20,30,.82);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  border-bottom:1px solid var(--border-inverse);
}
.lightbox__title{color:var(--cream);margin:0;font-size:var(--text-xl)}
.lightbox__sub{display:block;margin-top:4px;font-size:var(--text-xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--gold-500)}
.lightbox__close{background:none;border:1px solid rgba(255,255,255,.3);border-radius:var(--radius-sm);color:var(--cream);padding:10px;cursor:pointer;display:inline-flex;flex:none;transition:background var(--dur-base) var(--ease-standard)}
.lightbox__close:hover{background:rgba(255,255,255,.12)}
/* A mosaic of uniform 3:2 tiles. Every fifth photo leads across two columns AND
   two rows, which keeps the lead itself ~3:2 while leaving the column beside it
   to be filled by two stacked tiles — so the grid packs solid, with no cell
   stretched taller than its picture.

   This is the part that matters: grid items stretch to their row by default. If
   a tile keeps `height:auto` next to a taller lead, the image stops short and
   .shot's own dark ground shows through as a blue bar under it. Giving every
   tile a fixed ratio and letting the image fill it is what removes that.

   Width is derived from the height budget: with 3 columns the tallest thing is
   the two-row lead (4/3 of a column plus a gap), so this cap keeps it in frame. */
.lightbox__grid{
  --lb-gap:var(--space-4);
  padding:var(--space-6) var(--gutter-page) var(--space-9);
  display:grid;grid-template-columns:repeat(3,1fr);gap:var(--lb-gap);
  grid-auto-flow:dense;
  max-width:min(1500px, calc(var(--media-max-h) * 2.25 - var(--lb-gap) * 0.25));
  margin:0 auto;
}
.lightbox__grid .shot{aspect-ratio:3/2}
/* 1.485 is the ratio a 2-column, 2-row tile actually has: (2c+g) wide over
   (4c/3+g) tall, which works out between 1.478 and 1.487 for every realistic
   column width. Setting it explicitly matters — left on `auto`, a lead with no
   single-row tile beside it sized its rows from its OWN image instead, so a 4:3
   photograph pushed those two rows 30px taller than every other row. */
.lightbox__grid .shot--wide{grid-row:span 2;aspect-ratio:1.485}
/* Absolute, so no tile can ever derive its height from its photograph: every
   height comes from the ratio above and the rows stay uniform. Filling the tile
   crops a little, which is fine — clicking opens the zoom view, and that uses
   `contain` and shows the whole frame. */
.lightbox__grid .shot img{position:absolute;inset:0;width:100%;height:100%;max-height:none;object-fit:cover}
.lightbox__foot{padding:0 var(--gutter-page) var(--space-9);text-align:center}

/* Figure with hover caption (area name on cursor hover) */
.shot{position:relative;margin:0;overflow:hidden;border-radius:var(--radius-sm);background:var(--ink-800);cursor:zoom-in}
/* height:auto is required — the width/height attributes are set for CLS, and
   without it the literal height attribute wins and stretches the image. */
.shot img{width:100%;height:auto;display:block;transition:transform 600ms var(--ease-standard)}
.shot:hover img{transform:scale(1.03)}
.shot figcaption{
  position:absolute;left:var(--space-4);bottom:var(--space-4);
  padding:8px 14px;border-radius:var(--radius-xs);
  background:rgba(12,20,30,.82);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  color:var(--cream);font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;
  opacity:0;transform:translateY(8px);
  transition:opacity var(--dur-base) var(--ease-standard),transform var(--dur-base) var(--ease-standard);
  pointer-events:none;
}
.shot:hover figcaption,.shot:focus-within figcaption{opacity:1;transform:none}

/* Gallery caption names the PROJECT, not the room. */
.gal .shot{cursor:pointer;color:inherit}
.shot__cap{
  position:absolute;left:0;right:0;bottom:0;
  padding:var(--space-6) var(--space-4) var(--space-4);
  background:linear-gradient(to top,rgba(12,20,30,.86),transparent);
  color:var(--cream);font-size:var(--text-2xs);
  letter-spacing:var(--tracking-wider);text-transform:uppercase;
  opacity:0;transform:translateY(6px);
  transition:opacity var(--dur-base) var(--ease-standard),transform var(--dur-base) var(--ease-standard);
  pointer-events:none;
}
.shot__cap strong{
  display:block;font-family:var(--font-display);font-weight:600;
  font-size:var(--text-md);letter-spacing:0;text-transform:none;
  color:var(--white);margin-bottom:2px;
}
.shot:hover .shot__cap,.shot:focus-visible .shot__cap{opacity:1;transform:none}
.shot--tall{grid-row:span 2}
.shot--wide{grid-column:span 2}

/* Single-image zoom view stacked above the lightbox */
.zoom{position:fixed;inset:0;z-index:70;display:none;align-items:center;justify-content:center;background:rgba(12,20,30,.95);padding:var(--space-5)}
.zoom.is-open{display:flex}
/* Leaves room for the close button, the caption and a margin at both ends,
   rather than 88vh which on a short window put the caption over the picture. */
.zoom img{max-width:100%;max-height:calc(100vh - 6.5rem);object-fit:contain;border-radius:var(--radius-sm)}
@supports (height:100dvh){ .zoom img{max-height:calc(100dvh - 6.5rem)} }
.zoom__close{position:absolute;top:var(--space-5);right:var(--space-5);background:none;border:1px solid rgba(255,255,255,.3);border-radius:var(--radius-sm);color:var(--cream);padding:10px;cursor:pointer;display:inline-flex}
.zoom__cap{position:absolute;bottom:var(--space-6);left:50%;transform:translateX(-50%);color:var(--text-inverse-muted);font-size:var(--text-xs);letter-spacing:var(--tracking-wider);text-transform:uppercase}

/* ============================================================
   Gallery (Portfolio page 1)
   ============================================================ */
.gal{columns:3;column-gap:var(--space-4)}
/* Wider containers would otherwise stretch each masonry column too far. */
@media (min-width:1500px){ .gal{columns:4} }
.gal .shot{break-inside:avoid;margin-bottom:var(--space-4);display:block}

/* ============================================================
   Marquee — communities
   ============================================================ */
.marquee{position:relative;overflow:hidden;padding:var(--space-5) 0;border-top:1px solid var(--border-subtle);border-bottom:1px solid var(--border-subtle);-webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent)}
.marquee__track{display:flex;gap:var(--space-6);width:max-content;animation:marquee 44s linear infinite}
.marquee:hover .marquee__track{animation-play-state:paused}
.marquee__item{display:inline-flex;align-items:center;gap:var(--space-6);font-family:var(--font-display);font-size:var(--text-lg);color:var(--ink-900);white-space:nowrap}
.marquee__item::after{content:"";width:6px;height:6px;background:var(--gold-600);border-radius:50%;display:block}
@keyframes marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* ============================================================
   Locations — image card beside the county and its towns, two across
   ============================================================ */
.locations{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-8) var(--space-7)}
/* stretch, not start — the photograph matches the height of its text block */
.loc{display:grid;grid-template-columns:minmax(180px,36%) 1fr;gap:var(--space-6);align-items:stretch}
.loc__media{
  height:100%;min-height:220px;
  border-radius:var(--radius-lg);overflow:hidden;
  background:var(--stone-200);box-shadow:var(--shadow-sm);
}
.loc__media img{width:100%;height:100%;object-fit:cover;display:block;transition:transform 600ms var(--ease-standard)}
.loc:hover .loc__media img{transform:scale(1.04)}
.loc__body h3{margin:0 0 var(--space-4);font-size:var(--text-xl);color:var(--text-primary)}
.loc__links{margin:0;line-height:2.1}
/* Towns become links to location landing pages in a later phase; styled as
   links now, but not anchors, so there are no dead hrefs in the meantime. */
.loc__links span{
  display:inline-block;           /* so nowrap applies per town */
  white-space:nowrap;             /* "Cape Coral" must never split */
  font-size:var(--text-sm);color:var(--text-secondary);
  text-decoration:underline;text-decoration-color:var(--stone-300);
  text-underline-offset:4px;text-decoration-thickness:1px;
  transition:color var(--dur-fast) var(--ease-standard),text-decoration-color var(--dur-fast) var(--ease-standard);
}
.loc__links span:not(:last-child){margin-right:var(--space-4)}
.loc__links span:hover{color:var(--text-primary);text-decoration-color:var(--gold-600)}

/* ============================================================
   Sticky in-page subnav
   ============================================================ */
.subnav{position:sticky;top:var(--header-h);z-index:30;background:rgba(240,236,228,.92);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-bottom:1px solid var(--border-subtle)}
/* Centred. `justify-content:center` alone would clip the first link once the
   row overflows and starts scrolling, so the centring is done with auto margins
   on the end items — those collapse to zero when there is no spare room. */
.subnav__inner{display:flex;gap:var(--space-6);overflow-x:auto;padding:var(--space-4) 0;scrollbar-width:none}
.subnav__inner > :first-child{margin-inline-start:auto}
.subnav__inner > :last-child{margin-inline-end:auto}
.subnav__inner::-webkit-scrollbar{display:none}
.subnav a{white-space:nowrap;font-size:var(--text-xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--text-muted);padding-bottom:4px;border-bottom:2px solid transparent}
.subnav a:hover{color:var(--ink-900)}
.subnav a.is-active{color:var(--ink-900);border-bottom-color:var(--gold-600)}

/* ============================================================
   Awards
   ============================================================ */
.awardlist{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-1)}
.award{display:grid;grid-template-columns:auto 1fr;gap:var(--space-5);padding:var(--space-5) 0;border-bottom:1px solid var(--border-subtle)}
.award:last-child{border-bottom:0}
.award__icon{display:inline-flex;width:44px;height:44px;flex:none;align-items:center;justify-content:center;background:var(--gold-100);color:var(--gold-700);border-radius:var(--radius-sm)}
.award h3{margin:0 0 4px;font-size:var(--text-md)}
.award p{margin:0;color:var(--text-secondary);font-size:var(--text-sm);max-width:70ch}
/* Photographed trophies sit under their entry, small — evidence, not a feature. */
.award__photo{display:block;margin-top:var(--space-4);width:200px;max-width:60%;height:auto;border-radius:var(--radius-sm)}

/* ============================================================
   Team + partners
   ============================================================ */
.teamgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--space-5)}
.person--todo .person__media{display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,var(--stone-200),var(--stone-300))}
.person--todo .person__media img{width:38%;height:auto;object-fit:contain;opacity:.3}
.partners{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--space-5)}
.partner{
  display:flex;align-items:center;justify-content:center;aspect-ratio:3/2;
  background:var(--white);border:1px dashed var(--border-default);border-radius:var(--radius-md);
  color:var(--text-muted);font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;text-align:center;padding:var(--space-4);
}

/* ============================================================
   Lead magnet band
   ============================================================ */
.magnet{display:grid;grid-template-columns:1.2fr 1fr;gap:var(--space-8);align-items:center}
.magnet__card{background:var(--white);border:1px solid var(--border-subtle);border-radius:var(--radius-md);padding:var(--space-6);box-shadow:var(--shadow-md)}

/* ============================================================
   Misc
   ============================================================ */
.lede{font-size:var(--text-md);line-height:var(--leading-relaxed);color:var(--text-secondary);max-width:64ch}
.center{text-align:center;margin-left:auto;margin-right:auto}
.stack > * + *{margin-top:var(--space-5)}
.pill-row{display:flex;flex-wrap:wrap;gap:var(--space-2);margin-top:var(--space-5)}
.underline-gold{text-decoration:underline;text-decoration-color:var(--gold-600);text-decoration-thickness:2px;text-underline-offset:5px}
.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width:1024px){
  .mh-footer__grid{grid-template-columns:1fr 1fr;gap:var(--space-6)}
  .grid--4{grid-template-columns:repeat(2,1fr)}
  .gallery{grid-template-columns:repeat(2,1fr)}
  /* Three columns get cramped on a tablet. At two columns a two-row lead would
     leave a hole beside it, so the lead becomes a plain tile and every cell is
     a uniform 3:2 — still packs solid, still inside the height budget. */
  .lightbox__grid{grid-template-columns:repeat(2,1fr)}
  .lightbox__grid .shot--wide{grid-column:auto;grid-row:auto;aspect-ratio:3/2}
  .teamgrid,.partners{grid-template-columns:repeat(2,1fr)}
  .gal{columns:2}
}
@media (max-width:900px){
  .mh-nav,.mh-header__cta{display:none}
  .nav-toggle{display:inline-flex}
  .grid--3{grid-template-columns:repeat(2,1fr)}
  .split,.split--wide-left,.split--wide-right{grid-template-columns:1fr;gap:var(--space-6)}
  .split .media{order:-1}
  .rail{position:static}
  .spec-strip{grid-template-columns:repeat(2,1fr)}
  .locations{grid-template-columns:1fr;gap:var(--space-7)}
  .magnet{grid-template-columns:1fr;gap:var(--space-7)}
  /* One column, and the sticky stack becomes a plain list — there is not enough
     height on a phone for a card to pin without swallowing the whole screen. */
  .buildflow{grid-template-columns:1fr;gap:var(--space-7)}
  .buildflow__intro{position:static}
  .phasecard{position:static;height:auto}
  .phasecard__media{flex:none;aspect-ratio:16/9;min-height:0}
  .bleed__scrim{background:linear-gradient(to top,rgba(12,20,30,.9),rgba(12,20,30,.5))}
  .bleed--quiet .bleed__scrim{background:linear-gradient(180deg,rgba(12,20,30,.34),rgba(12,20,30,.18))}
  /* .subnav used to be pinned to top:0 here. The header is sticky at top:0
     with z-index:40 on mobile too, so the subnav pinned UNDERNEATH it and
     looked like it had stopped sticking. It keeps the base rule's
     top:var(--header-h) at every width. */
}
@media (max-width:640px){
  .gal{columns:1}
  .lightbox__grid{grid-template-columns:1fr;gap:var(--space-3)}
  .shot--wide,.shot--tall{grid-column:auto;grid-row:auto}
  .lightbox__title{font-size:var(--text-md)}
  .teamgrid,.partners{grid-template-columns:1fr 1fr}
  .loc{grid-template-columns:1fr;gap:var(--space-4)}
  .loc__media{aspect-ratio:16/9}
  .projcard__meta h3{font-size:var(--text-xl)}
  .projcard__overlay{padding:var(--space-5)}
  .marquee__item{font-size:var(--text-base)}
  .hero__scroll{display:none}
  :root{--header-h:72px}
  .mh-header__logo img{height:34px}
  .section{padding-top:var(--space-8);padding-bottom:var(--space-8)}
  /* Restated AFTER .section. Both are (0,1,0), so the modifier only wins on
     source order - without this line --tight was silently dead below 640 and
     tight bands rendered at full section height. */
  .section--tight{padding-top:var(--space-6);padding-bottom:var(--space-6)}
  .grid--2,.grid--3,.grid--4{grid-template-columns:1fr}
  .field-row{grid-template-columns:1fr}
  .feature-grid{grid-template-columns:1fr}
  .stat-row{gap:var(--space-5)}
  .stat-row > *{flex:1 1 40%}
  .stat__value{font-size:var(--text-2xl)}
  .mh-footer__grid{grid-template-columns:1fr}
  .mh-footer__logo{height:44px}
  .gallery{grid-template-columns:1fr}
  .gallery__main{grid-column:span 1}
  .step p{max-width:none}
  .cta-band{flex-direction:column;align-items:flex-start}
  .hero__actions .btn{flex:1 1 100%}
}

/* ---------- Motion preference ---------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important;scroll-behavior:auto !important}
  [data-reveal]{opacity:1;transform:none}
  .hero__bg img{transform:none !important}
}

/* ---------- Print ---------- */
@media print{
  .mh-header,.drawer,.nav-toggle,.mh-footer__social{display:none}
  body{background:#fff}
}


/* ============================================================
   Astra + Elementor compatibility
   Loaded after both, so equal-specificity rules win. Everything here
   exists to stop the theme and the builder re-imposing their own
   width, padding and typography over the design system above.
   ============================================================ */

/* Astra wraps everything in .ast-container and #content with its own max-width
   and padding. Our sections are full-bleed and manage their own gutters, so the
   wrappers have to become transparent pass-throughs on builder pages. */
.mh-page #content,
.mh-page .ast-container,
.mh-page .site-content .ast-container{
  max-width:none; padding-left:0; padding-right:0; margin-left:0; margin-right:0;
}
.mh-page #primary,
.mh-page .site-main,
.mh-page .entry-content{ margin:0; padding:0; }
.mh-page .entry-header,
.mh-page .ast-single-post-order,
.mh-page .ast-archive-description{ display:none; }
.mh-page .site-content{ padding-block:0; }

/* Astra sets its own body type; the design system owns it. */
body.mh-page{
  font-family:var(--font-body);
  font-size:var(--text-base);
  line-height:var(--leading-normal);
  color:var(--text-primary);
  background:var(--surface-page);
}
/* Colour is deliberately NOT set here. Forcing --text-primary onto every
   heading overrode .section--dark h2 and .mh-footer h4, which paints
   #132131 text on the #132131 dark band — the footer headings were
   invisible at a contrast ratio of 1.00. Headings inherit their colour from
   their section, exactly as the design intends. */
.mh-page h1,.mh-page h2,.mh-page h3,.mh-page h4{
  font-family:var(--font-display);
  font-weight:var(--weight-display);
}

/* Elementor containers default to a boxed max-width and 10px padding. Our
   .section / .container pair already handles both, so the container itself
   must not add a second set. Widths come from the kit, these are the resets
   that keep a nested container from inheriting a stray gutter. */
.mh-page .e-con{
  --padding-inline-start:0; --padding-inline-end:0;
  /* Block padding too: Elementor's 10px default was stacking on every
     container and adding ~600px to the page height. */
  --padding-block-start:0; --padding-block-end:0;
}
.mh-page .elementor-widget:not(:last-child){ margin-block-end:0; }
.mh-page .elementor-element{ --widgets-spacing:0px 0px; }

/* ---- Container flow ----
   Elementor containers are flex-column by default, which stacks children at
   full width — the same result as the block flow the static build used, so
   it is deliberately left alone. Two things do need correcting.

   1. Direction. The design's flex ROWS relied on the CSS default of row,
      and Elementor overrides it through --flex-direction. Direction is
      handed back for exactly those components. This cannot be done globally:
      Elementor's .e-flex class forces display:flex at a specificity the
      variable cannot reach, so a global row would turn every section into
      one and collapse each child to its content width.

   2. Gap. The design spaces with margins, so Elementor's default container
      gap doubles it. Components that want a gap (.grid, .split) set their
      own, which still wins. */
.mh-page .e-con{ --gap:0px; --row-gap:0px; --column-gap:0px; }

.mh-page .e-con.hero__actions,
.mh-page .e-con.stat-row,
.mh-page .e-con.cta-band,
.mh-page .e-con.section-head-row,
.mh-page .e-con.projcard__meta,
.mh-page .e-con.phasecard__meta,
.mh-page .e-con.contact-row,
.mh-page .e-con.pill-row,
.mh-page .e-con.filters,
.mh-page .e-con.spec-strip,
.mh-page .e-con.subnav__inner,
.mh-page .e-con.mh-header__cta,
.mh-page .e-con.mh-footer__legal,
.mh-page .e-con.field-row{
  --flex-direction:row;
  --container-widget-width:auto;
}

/* In a row, children must size to their content rather than fill the line.
   This has to cover nested containers as well as widgets: Elementor gives a
   child container width:var(--width,100%), so four .stat blocks in a row each
   took the full line and overflowed. */
.mh-page .e-con.hero__actions>*,
.mh-page .e-con.stat-row>*,
.mh-page .e-con.cta-band>*,
.mh-page .e-con.section-head-row>*,
.mh-page .e-con.projcard__meta>*,
.mh-page .e-con.phasecard__meta>*,
.mh-page .e-con.contact-row>*,
.mh-page .e-con.pill-row>*,
.mh-page .e-con.filters>*,
.mh-page .e-con.spec-strip>*,
.mh-page .e-con.subnav__inner>*,
.mh-page .e-con.mh-header__cta>*,
.mh-page .e-con.mh-footer__legal>*,
.mh-page .e-con.field-row>*{ width:auto; }

/* The text half of a two-part row should absorb the slack, not the button. */
.mh-page .e-con.cta-band>*:first-child,
.mh-page .e-con.section-head-row>*:first-child{ flex:1 1 auto; min-width:0; }
.mh-page .e-con.stat-row>*{ flex:1 1 0; }

/* Elementor 4.2 renders the <img> directly inside the widget. Killing the
   line-box descender still matters: .media boxes are ratio-locked, so the gap
   would show as a seam. */
.mh-page .elementor-widget-image img{ display:block; }

/* Heading and text widgets inherit their own colour/size from the kit; the
   design system's semantic classes must be able to override them. */
.mh-page .elementor-heading-title{ font-family:inherit; font-weight:inherit; color:inherit; font-size:inherit; line-height:inherit; }
.mh-page .elementor-widget-text-editor{ font-family:inherit; color:inherit; }

/* Xpro header/footer templates sit outside .mh-page's content wrappers, so the
   design tokens are attached at :root and the header styles apply globally. */
.xpro-header-wrapper,.xpro-footer-wrapper{ background:transparent; }

/* Astra's own header/footer are replaced by the Xpro templates. */
.ast-main-header-wrap,.site-primary-footer-wrap,.site-below-footer-wrap,.ast-mobile-header-wrap{ display:none !important; }

/* Skip link has to clear the fixed header. */
.skip-link:focus{ z-index:99999; }

/* ============================================================
   Sticky header
   .mh-header is position:sticky in the design, but sticky resolves against
   the nearest scroll container — and Xpro renders the header inside its own
   wrapper, which was the containing block. The wrapper has to become the
   sticky element for it to stick to the viewport.
   ============================================================ */
.xpro-header-wrapper,
.xpro-theme-builder-header{
  position:sticky; top:0; z-index:40;
}
.mh-page .xpro-header-wrapper .mh-header{ position:static; }

/* ============================================================
   Secondary nav (About / Custom Home Building)
   .subnav__inner is a flex row with gap:var(--space-6), but every link ended
   up inside ONE text widget, so there was a single flex child and the gap
   had nothing to act between — the labels ran together. Collapsing the
   widget wrapper makes each <a> a flex item again.
   ============================================================ */
.mh-page .e-con.subnav__inner>.elementor-widget-text-editor,
.mh-page .e-con.subnav__inner>.elementor-widget-text-editor>p,
.mh-page .e-con.hero__actions>.elementor-widget-text-editor,
.mh-page .e-con.hero__actions>.elementor-widget-text-editor>p{
  display:contents;
}
.mh-page .subnav__inner{ gap:var(--space-6); }
.mh-page .subnav a{ display:inline-block; }

/* ============================================================
   Phase cards (Custom Home Building)
   Each card is a fixed height with the picture taking the slack
   (flex:1 1 auto) and the copy taking only what it needs. The image widget
   sat between .phasecard__media and its <img>, so the media box could not
   flex and the picture was neither filling nor cropping correctly — hence
   dead space under the copy and a clipped photograph.
   ============================================================ */
.mh-page .phasecard__media{ position:relative; flex:1 1 auto; min-height:6rem; overflow:hidden; }
.mh-page .phasecard__media .elementor-widget-image{
  position:absolute; inset:0; height:100%; width:100%; margin:0;
}
.mh-page .phasecard__media img{ width:100%; height:100%; object-fit:cover; display:block; }
.mh-page .phasecard__body{ flex:none; }

/* Full-bleed background photographs (.bleed and the interior page headers)
   have the same wrapper problem the hero poster had: the design positions the
   <img>, but Elementor buries it two elements deep. Without this the band
   renders as flat colour and its cream headline sits on warm paper at a
   contrast ratio of 1.04 - invisible. */
.mh-page .bleed__bg,
.mh-page .page-head__bg{ position:absolute; inset:0; overflow:hidden; }
.mh-page .bleed__bg .elementor-widget-image,
.mh-page .page-head__bg .elementor-widget-image{ position:absolute; inset:0; height:100%; width:100%; margin:0; }
.mh-page .bleed__bg img,
.mh-page .page-head__bg img{ width:100%; height:100%; object-fit:cover; display:block; }
/* The card is the flex column those two rules depend on. */
.mh-page .e-con.phasecard{ display:flex; --flex-direction:column; }

/* ============================================================
   Cards — uniform text and button spacing
   .property__body and .projcard__body are flex columns with a fixed gap and
   the action pinned to the bottom, so every card in a row reads identically
   regardless of how long its blurb runs.
   ============================================================ */
.mh-page .e-con.property__body,
.mh-page .e-con.projcard__body{
  --flex-direction:column;
  display:flex;
  gap:var(--space-3);
  padding:var(--space-5);
  flex:1 1 auto;
}
.mh-page .e-con.property__body>*,
.mh-page .e-con.projcard__body>*{ width:100%; }
/* The button sits at the foot of the card, so buttons line up across a row. */
.mh-page .e-con.property__body>.elementor-widget-button,
.mh-page .e-con.projcard__body>.elementor-widget-button{
  margin-top:auto;
  width:auto;
  align-self:flex-start;
}
/* --flex-direction is an Elementor container variable: it only resolves on an
   .e-con. The property cards are containers, but the projects grid is still the
   static build's markup, where .projcard is a plain <button> — so the variable
   was inert there and the card fell back to flex-direction:row, standing the
   photograph beside its blurb instead of above it. The real property is set
   alongside the variable so the rule holds for both kinds of card. */
.mh-page .card.property,
.mh-page .projcard{ display:flex; --flex-direction:column; flex-direction:column; height:100%; }
.mh-page .property__name{ margin:0; }

/* ============================================================
   Secondary nav — centred
   The design centres with auto margins on the first and last child, but
   those children are now widget wrappers rather than the links themselves,
   so the margins had nothing to push. Since the row wraps instead of
   scrolling, centring it directly is safe.
   ============================================================ */
.mh-page .subnav__inner{
  justify-content:center;
  flex-wrap:wrap;
  row-gap:var(--space-3);
  /* .container's gutter is zeroed by the .mh-page .e-con reset, which left the
     links touching both screen edges on a phone. Restate it as real padding so
     the row keeps the same side margin as every other band. */
  padding-inline:var(--gutter-page);
}
.mh-page .subnav__inner>:first-child{ margin-inline-start:0; }
.mh-page .subnav__inner>:last-child{ margin-inline-end:0; }

/* ============================================================
   Our History — static image beside a scrolling timeline
   Mirrors How We Build: the picture holds still on the left while the
   entries move past on the right, set right-aligned as requested.
   ============================================================ */
/* The vertical rule and node dots belong to the left-aligned original. */

/* ============================================================
   Mobile
   ============================================================ */
@media (max-width:900px){
  /* Counter band: an even 2x2 instead of an uneven wrapped row. */
  .mh-page .stat-row{
    display:grid;
    grid-template-columns:repeat(2,1fr);
    gap:var(--space-6) var(--space-4);
    text-align:center;
  }
  .mh-page .stat-row>*{ width:auto; }

  /* History stacks; the image stops being sticky. */
        
  /* Cards keep the same rhythm at one column. */
  .mh-page .e-con.property__body,
  .mh-page .e-con.projcard__body{ padding:var(--space-5); gap:var(--space-3); }
  /* Wrapped rather than one cramped scrolling row. The bar is sticky under an
     already-sticky header, so it is kept as short as the labels allow: tighter
     block padding and gaps, all still on the scale. */
  .mh-page .subnav__inner{
    flex-wrap:wrap;
    justify-content:center;
    padding-block:var(--space-3);
    row-gap:var(--space-2);
    column-gap:var(--space-4);
    overflow-x:visible;
  }
  .mh-page .subnav__inner>:first-child{ margin-inline-start:0; }
  .mh-page .subnav__inner>:last-child{ margin-inline-end:0; }

  /* Buttons stack full width with real breathing room between them. */
  .mh-page .hero__actions{
    flex-wrap:wrap;
    gap:var(--space-4);
    width:100%;
  }
  .mh-page .hero__actions>*{ width:100%; }
    .mh-page .hero__actions .elementor-button{ width:100%; justify-content:center; }
  .mh-page .cta-band{ flex-wrap:wrap; gap:var(--space-5); }

  /* The toggle lives inside the header's actions group, which the design
     hides on mobile, so it inherited that column's position and sat in the
     middle of the bar. Pinning it to the header's own box puts it in the
     top-right corner regardless of which grid cell it came from. */
  .mh-page .mh-header__inner{ position:relative; }
  .mh-page .nav-toggle{
    display:inline-flex;
    position:absolute;
    top:50%;
    right:var(--gutter-page);
    transform:translateY(-50%);
    z-index:50;
  }
  /* The drawer is a sibling of the toggle inside that hidden group, so it
     has to opt back into being displayed. */
  .mh-page .mh-header__cta:has(#navToggle){ display:block; }

  /* A full-width button still carries 34px of horizontal padding, which
     pushed it past the viewport. */
  .mh-page .elementor-button,
  .mh-page .btn{ max-width:100%; box-sizing:border-box; }
}

/* ============================================================
   Contrast
   Measured against the real backgrounds; every pair below failed WCAG AA
   on the live page. Only the semantic TEXT tokens move — surfaces, brand
   blue and the gold accent used as a rule or fill are untouched, so the
   palette is unchanged and only legibility improves.
   ============================================================ */
:root.mh-contrast, body.mh-page{
  /* was #8e99a4 -> 2.46:1 on warm paper. Now ~5.0:1. */
  /* 2026-08-26: one step darker, from #5c6874. That value cleared 4.5:1 on
     the bone page but landed at 4.41:1 on the sunken bone-deep band - which is
     exactly where the award records sit, so the years, the decade counts and
     the back-link all measured as failures on the live page. Now 5.21:1 on
     bone and 4.76:1 on bone-deep. */
  --text-muted:#57636f;
  /* was #a98a28 -> 2.81:1 for gold TEXT on paper. The deepest gold in the
     ramp reads as the same accent but passes at ~6.4:1. Gold as a fill or
     a rule is unaffected. */
  --text-accent:var(--gold-900);
}
/* Eyebrows ran at 3.83:1 on paper against a 4.5 requirement. The INVERSE
   eyebrow is excluded: it sits on the dark brand band, where darkening it
   drops it to 2.34:1 instead of raising it. */
.mh-page .eyebrow:not(.eyebrow--inverse){ color:var(--text-secondary); }
.mh-page .eyebrow--inverse{ color:var(--gold-300); }

/* Gold as TEXT on warm paper was 2.81:1. The deepest gold reads as the same
   accent and passes. On the dark bands the design already switches this to
   cream, and that rule is more specific, so it still wins there. */
.mh-page .btn--outline-gold .elementor-button,
.mh-page .btn--ghost .elementor-button{ color:var(--gold-900); }
.mh-page .btn--outline-gold .elementor-button{ border-color:var(--gold-700); }
.mh-page .form-note{ color:var(--text-muted); }
.mh-page .req{ color:var(--gold-900); }

/* ============================================================
   Non-brand colour removal
   Xpro's widgets ship their own palette — network-brand social colours and
   a neutral grey menu — none of which is in the Marvin system.
   ============================================================ */
.mh-page .xpro-social-icon,
.mh-page .mh-footer__social .xpro-social-icon{
  background-color:transparent;
  color:var(--text-inverse-muted);
  border:1px solid var(--border-inverse);
}
/* Horizontal row of icon buttons directly under the company statement.
   Xpro stacks its social list by default, which was the single biggest
   contributor to the footer's height. */
.mh-page .mh-footer__social{ margin-top:var(--space-5); }
.mh-page .mh-footer__social .xpro-social-icon-wrapper,
.mh-page .mh-footer__social ul,
.mh-page .mh-footer__social .xpro-social-icon-list{
  display:flex; flex-direction:row; flex-wrap:wrap; gap:10px;
  margin:0; padding:0; list-style:none;
}
.mh-page .mh-footer__social li{ margin:0; }
.mh-page .mh-footer__social .xpro-social-icon{
  width:38px; height:38px; display:inline-flex;
  align-items:center; justify-content:center; border-radius:var(--radius-sm);
}
.mh-page .mh-footer__legal{ align-items:center; }

.mh-page .xpro-social-icon:hover,
.mh-page .mh-footer__social .xpro-social-icon:hover{
  background-color:var(--gold-600);
  color:var(--ink-900);
  border-color:var(--gold-600);
}
.mh-page .xpro-elementor-horizontal-menu-close,
.mh-page .xpro-elementor-horizontal-menu-close:hover{
  color:var(--ink-900);
  background-color:transparent;
  border-color:var(--border-default);
}
.mh-page .xpro-menu-list a,
.mh-page .xpro-menu-list a:hover{ color:inherit; }

/* Astra's default link blue (#0170B9) and Xpro's input grey (#808285). */
.mh-page a{ color:inherit; }
.mh-page .entry-content a:not(.elementor-button):not([class*="btn"]){ color:var(--text-brand); }
.mh-page input,.mh-page textarea,.mh-page select{
  color:var(--text-primary);
  border-color:var(--border-default);
  background:var(--surface-raised);
}
.mh-page input::placeholder,.mh-page textarea::placeholder{ color:var(--text-muted); }

/* ============================================================
   Gallery tiles
   The .gal block is emitted as authored markup so the .shot anchors keep
   data-area (filters) and data-full (lightbox). Collapsing the widget
   wrapper makes those anchors direct children of .gal again, so the CSS
   multi-column flow and the design's tile rules both still apply.
   ============================================================ */
.mh-page .e-con.gal>.elementor-widget-text-editor,
.mh-page .e-con.projects-grid>.elementor-widget-text-editor,
.mh-page .e-con.lightbox>.elementor-widget-text-editor,
.mh-page .e-con.zoom>.elementor-widget-text-editor{
  display:contents;
}

/* ============================================================
   Divider widget
   hr.rule-gold is a 2px filled bar, not a border. Elementor's divider draws
   its OWN separator line inside a wrapper with its own padding, so the page
   showed two rules — a gold one and a black one — and the wrapper's fixed
   2px height meant the separator overflowed and struck through the heading
   beneath it. Elementor's internals are hidden and the wrapper becomes the
   bar, exactly as the design defines it.
   ============================================================ */
.mh-page .elementor-widget-divider.rule-gold{
  height:var(--rule-accent,2px);
  width:56px;
  background:var(--gold-600);
  border:0;
  margin:var(--space-4) 0;
  padding:0;
  overflow:hidden;
  --divider-pattern-height:0;
}
.mh-page .elementor-widget-divider.rule-gold .elementor-divider,
.mh-page .elementor-widget-divider.rule-gold .elementor-divider-separator{
  display:none;
}
/* Any other divider keeps a single hairline and real spacing. */
.mh-page .elementor-widget-divider:not(.rule-gold) .elementor-divider{ padding:0; }
.mh-page .elementor-widget-divider:not(.rule-gold) .elementor-divider-separator{
  border-top:1px solid var(--border-subtle);
}

/* ============================================================
   Card link colour
   Project and gallery tiles wrap their content in a link, so Astra's link
   and link-hover blue (#0170B9) bled onto the card text on hover. Tiles
   carry their own colour from the design.
   ============================================================ */
.mh-page .projcard,.mh-page .projcard:hover,
.mh-page .projcard a,.mh-page .projcard a:hover,
.mh-page .property,.mh-page .property:hover,
.mh-page .property a,.mh-page .property a:hover,
.mh-page .shot,.mh-page .shot:hover,
.mh-page .loc a,.mh-page .loc a:hover,
.mh-page .e-con-link,.mh-page .e-con-link:hover{
  color:inherit;
  background-color:transparent;
}
.mh-page .projcard__overlay,.mh-page .projcard__overlay *{ color:var(--cream); }


/* ============================================================
   Widget bridge — generated from the .btn rules above.
   19 rules, re-scoped to Elementor's button markup.
   ============================================================ */
.mh-page .elementor-widget-button .elementor-button{display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:12px 24px;
  font-family:var(--font-body);font-size:var(--text-xs);font-weight:400;
  letter-spacing:var(--tracking-wider);text-transform:uppercase;line-height:1;
  border-radius:var(--radius-sm);border:1px solid transparent;cursor:pointer;
  white-space:nowrap;
  transition:background var(--dur-base) var(--ease-standard),
             color var(--dur-base) var(--ease-standard),
             border-color var(--dur-base) var(--ease-standard);}
.mh-page .elementor-widget-button.btn--sm .elementor-button{padding:8px 16px;font-size:var(--text-2xs);gap:6px}
.mh-page .elementor-widget-button.btn--lg .elementor-button{padding:16px 34px;font-size:var(--text-sm);gap:10px}
.mh-page .elementor-widget-button.btn--full .elementor-button{display:flex;width:100%}
.mh-page .elementor-widget-button.btn--primary .elementor-button{background:var(--ink-900);color:var(--cream);border-color:var(--ink-900)}
.mh-page .elementor-widget-button.btn--primary .elementor-button:hover{background:var(--ink-800);border-color:var(--ink-800);color:var(--cream)}
.mh-page .elementor-widget-button.btn--accent .elementor-button{background:var(--gold-600);color:var(--ink-900);border-color:var(--gold-600)}
.mh-page .elementor-widget-button.btn--accent .elementor-button:hover{background:var(--gold-700);border-color:var(--gold-700);color:var(--ink-900)}
.mh-page .elementor-widget-button.btn--secondary .elementor-button{background:var(--stone-800);color:var(--cream);border-color:var(--stone-800)}
.mh-page .elementor-widget-button.btn--secondary .elementor-button:hover{background:var(--ink-900);border-color:var(--ink-900);color:var(--cream)}
.mh-page .elementor-widget-button.btn--outline .elementor-button{background:transparent;color:var(--ink-900);border-color:var(--ink-900)}
.mh-page .elementor-widget-button.btn--outline .elementor-button:hover{background:var(--ink-900);color:var(--cream)}
.mh-page .elementor-widget-button.btn--outline-gold .elementor-button{background:transparent;color:var(--gold-700);border-color:var(--gold-600)}
.mh-page .elementor-widget-button.btn--outline-gold .elementor-button:hover{background:var(--gold-600);color:var(--ink-900)}
.mh-page .elementor-widget-button.btn--ghost .elementor-button{background:transparent;color:var(--ink-900)}
.mh-page .elementor-widget-button.btn--ghost .elementor-button:hover{background:var(--stone-100);color:var(--ink-800)}
.mh-page .elementor-widget-button .elementor-button .elementor-button-icon, .elementor-button .i{width:1em;height:1em;flex:none;stroke-width:1.75}
.mh-page .elementor-widget-button.btn--lg .elementor-button .elementor-button-icon, .elementor-button .i{width:18px;height:18px}
.mh-page .elementor-widget-button.btn--sm .elementor-button .elementor-button-icon, .elementor-button .i{width:14px;height:14px}

/* Context-scoped heading rules, re-scoped to Elementor's heading markup
   (18 rules). */
.mh-page .elementor-widget-heading h1.elementor-heading-title,
.mh-page .elementor-widget-heading h2.elementor-heading-title,
.mh-page .elementor-widget-heading h3.elementor-heading-title,
.mh-page .elementor-widget-heading h4.elementor-heading-title,
.mh-page .elementor-widget-heading h5.elementor-heading-title{font-family:var(--font-display); font-weight:var(--weight-display);
  line-height:var(--leading-snug);
  margin:0 0 .5em; text-wrap:balance;}
.mh-page .elementor-widget-heading h1.elementor-heading-title{font-size:var(--text-3xl);line-height:var(--leading-tight)}
.mh-page .elementor-widget-heading h2.elementor-heading-title{font-size:var(--text-2xl)}
.mh-page .elementor-widget-heading h3.elementor-heading-title{font-size:var(--text-xl)}
.mh-page .elementor-widget-heading h4.elementor-heading-title{font-size:var(--text-lg)}
.mh-page .section--dark h1.elementor-heading-title,
.mh-page .section--dark h2.elementor-heading-title,
.mh-page .section--dark h3.elementor-heading-title{color:var(--cream)}
.mh-page .mh-footer h4.elementor-heading-title{font-family:var(--font-body);font-size:var(--text-2xs);letter-spacing:var(--tracking-wider);text-transform:uppercase;color:var(--gold-500);margin:0 0 var(--space-4);font-weight:400}
.mh-page .page-head h1.elementor-heading-title{color:var(--cream);font-size:clamp(2.25rem,5vw,var(--text-4xl));margin:var(--space-4) 0 0;max-width:18ch}
.mh-page .phasecard__meta h3.elementor-heading-title{margin:0;font-size:var(--text-xl)}
.mh-page .step h3.elementor-heading-title{margin:0 0 var(--space-2);font-size:var(--text-2xl)}
.mh-page .form-success h3.elementor-heading-title{margin:var(--space-4) 0 var(--space-2)}
.mh-page .cta-band h2.elementor-heading-title{margin:0 0 6px;color:var(--ink-900)}
.mh-page .person h3.elementor-heading-title{margin:0 0 2px;font-size:var(--text-md)}
.mh-page .bleed h2.elementor-heading-title{color:var(--cream)}
.mh-page .projcard__meta h3.elementor-heading-title{color:var(--cream);margin:0 0 4px;font-size:var(--text-2xl)}
.mh-page .loc__body h3.elementor-heading-title{margin:0 0 var(--space-4);font-size:var(--text-xl);color:var(--text-primary)}
.mh-page .award h3.elementor-heading-title{margin:0 0 4px;font-size:var(--text-md)}
.mh-page .projcard__meta h3.elementor-heading-title{font-size:var(--text-xl)}

/* ---- Stop the button painting twice ----
   The widget wrapper carries the btn / btn--* classes purely so the rules
   above can target the inner <a>. But the design system's own .btn rules
   match that wrapper as well, so every button rendered its box twice: an
   outer border and padding on the wrapper, and a second border and padding
   on the anchor inside it — a border around the button and another around
   the text.

   The wrapper is reset to a bare layout box. Only the paint is removed;
   display and width are untouched so .btn--full still stretches. At (0,3,0)
   this outscores the design's own .btn / .btn--* rules at (0,1,0), and the
   anchor keeps everything from the generated rules above. */
.mh-page .elementor-widget-button.btn{
  background:none;
  border:0;
  border-radius:0;
  padding:0;
  box-shadow:none;
  min-height:0;
  color:inherit;
  font-size:inherit;
  line-height:normal;
  letter-spacing:normal;
  text-transform:none;
  white-space:normal;
  transition:none;
}

/* Elementor wraps the anchor in a block-level div that would break an
   inline-flex button sitting next to another one. */
.mh-page .elementor-widget-button .elementor-button-content-wrapper{ display:inline-flex; align-items:center; gap:inherit; }
.mh-page .elementor-widget-button .elementor-button-text{ flex-grow:0; }

/* ---- Image widget ----
   The design system wrote its image rules for the <img> itself
   (.hero__poster, .projcard__media img, .shot img…), but Elementor puts a
   widget's custom class on the OUTER wrapper and buries the image two
   elements deeper. So the wrapper becomes the box those rules describe —
   position, inset and size all land on it correctly — and the figure and
   image are then made to fill that box completely.

   Without this, .hero__poster positioned an empty div while the photograph
   inside kept its intrinsic size, which is why the hero image covered only
   part of the screen. */
.mh-page .elementor-widget-image{
  height:100%; margin:0; padding:0; line-height:0; display:block;
}
/* The fill rule must not touch the logos: it ties with the design's own
   .mh-header__logo img rule on specificity and, loading later, was winning —
   which is why both lockups rendered at exactly twice their intended size. */
.mh-page .elementor-widget-image:not(.mh-header__logo):not(.mh-footer__logo) img{
  width:100%; height:100%; object-fit:cover; display:block;
}

/* Logo lockups sit at their design size (matched to the template: 179x44
   in the header, 210x52 in the footer) rather than filling a box. */
.mh-page .mh-header__logo,
.mh-page .mh-footer__logo{ height:auto; line-height:0; }
.mh-page .mh-header__logo img{ height:44px; width:auto; object-fit:contain; }
.mh-page .mh-footer__logo img{ height:52px; width:auto; object-fit:contain; }

/* ---- Masonry gallery ----
   .gal lays out with CSS multi-column, which only applies to a block box.
   Elementor's .e-flex forces display:flex on every container and silently
   kills the column count, so the 107 tiles stacked in one line instead of
   flowing into a grid. */
.mh-page .e-con.gal{ display:block; }
.mh-page .e-con.gal>.e-con{ width:auto; }

/* ---- Heading widget type ----
   Elementor's kit types .elementor-heading-title directly, at a specificity
   a plain h1..h6 rule cannot reach. The design system's own heading defaults
   therefore have to be re-asserted here.

   Size, colour, tracking and case still come from the wrapper class
   (.hero__title, .section-heading__title, .eyebrow…) via inherit, which is
   what keeps those classes meaningful. Family and weight are then set BY TAG,
   so a real heading gets the display serif while a div/span heading — the
   eyebrows and stat figures — keeps inheriting the body font from its wrapper.

   Using the font shorthand here instead was the bug that put every headline
   in the body sans: it inherits family from the wrapper, and the wrapper
   inherits it from <body>. */
.mh-page .elementor-widget-heading .elementor-heading-title{
  font-family:inherit; font-weight:inherit; font-size:inherit;
  line-height:inherit; letter-spacing:inherit; text-transform:inherit;
  color:inherit; margin:0;
}
.mh-page .elementor-widget-heading h1.elementor-heading-title,
.mh-page .elementor-widget-heading h2.elementor-heading-title,
.mh-page .elementor-widget-heading h3.elementor-heading-title,
.mh-page .elementor-widget-heading h4.elementor-heading-title,
.mh-page .elementor-widget-heading h5.elementor-heading-title,
.mh-page .elementor-widget-heading h6.elementor-heading-title{
  font-family:var(--font-display);
  font-weight:var(--weight-display);
}
.mh-page .elementor-widget-text-editor p:last-child{ margin-bottom:0; }
.mh-page .elementor-widget-text-editor p:first-child{ margin-top:0; }

/* Icon-list widget carries the gold check lists on the lead-magnet section. */
.mh-page .elementor-widget-icon-list .elementor-icon-list-icon svg{ fill:var(--gold-600); }
.mh-page .elementor-widget-icon-list .elementor-icon-list-text{ color:inherit; font-size:inherit; }

/* nav-toggle-anchor-fix */
@media (max-width:900px){
  .mh-page .mh-header__inner .elementor-widget:has(.nav-toggle){ position:static; }
  }

/* gold-text-contrast-final */
.mh-page .elementor-widget-button.btn--outline-gold .elementor-button,
.mh-page .elementor-widget-button.btn--ghost .elementor-button{ color:var(--gold-900); }
.mh-page .elementor-widget-button.btn--outline-gold .elementor-button{ border-color:var(--gold-700); }
.mh-page .section--dark .elementor-widget-button.btn--outline-gold .elementor-button{ color:var(--cream); border-color:rgba(255,255,255,.4); }


/* ============================================================
   Revision — 14 August 2026
   Footer icons, FAQ accordion, hero entrance, gold buttons.
   ============================================================ */

/* ---- Footer social icons ----
   Xpro renders each network as an inline SVG, and the SVG's own fill was
   still black, so the icons stayed invisible on the dark footer no matter
   what the link colour said. Fill is what actually paints them. */
.mh-page .xpro-social-icon,
.mh-page .mh-footer__social .xpro-social-icon{ color:var(--white); }
.mh-page .xpro-social-icon svg,
.mh-page .mh-footer__social .xpro-social-icon svg{ fill:var(--white); }
.mh-page .mh-footer__social .xpro-social-icon:hover{
  color:var(--white);
  border-color:rgba(255,255,255,.55);
  background-color:rgba(255,255,255,.10);
}
.mh-page .mh-footer__social .xpro-social-icon:hover svg{ fill:var(--white); }

/* ---- FAQ accordion ----
   Three things on the one component:
   (1) The questions are centred. The +/- is lifted out of the flex row and
       pinned right, so centring the label does not drag the icon inward.
   (2) The accordion gets its own raised surface. It used to be bare rules on
       the section's cream, which read as loose text rather than a control;
       ink-900 on white is 15.9:1, well above AA.
   (3) Astra paints button:hover with its own global blue and white text and
       nothing here ever overrode it, which is where the off-brand blue on the
       FAQ rows came from. Brand blue with cream instead. */
.mh-page .accordion{
  background:var(--surface-raised);
  border:1px solid var(--border-subtle);
  border-radius:var(--radius-md);
  overflow:hidden;
  max-width:60rem;
  margin-inline:auto;
}
.mh-page .accordion .acc__item:last-child{ border-bottom:0; }
.mh-page .accordion .acc__trigger{
  position:relative;
  justify-content:center;
  text-align:center;
  padding:var(--space-5) var(--space-8);
  transition:background var(--dur-base) var(--ease-standard),
             color var(--dur-base) var(--ease-standard);
}
.mh-page .accordion .acc__trigger .i{
  position:absolute; right:var(--space-5); top:50%; transform:translateY(-50%);
}
.mh-page .accordion .acc__item.is-open .acc__trigger .i{
  transform:translateY(-50%) rotate(45deg);
}
.mh-page .accordion .acc__trigger:hover,
.mh-page .accordion .acc__trigger:focus-visible{
  background:var(--ink-900); color:var(--cream);
}
.mh-page .accordion .acc__trigger:hover .i,
.mh-page .accordion .acc__trigger:focus-visible .i{ color:var(--gold-400); }
.mh-page .accordion .acc__panel{ padding-inline:var(--space-8); }
.mh-page .accordion .acc__panel p{ margin-inline:auto; }

/* ---- Hero entrance ----
   The hero copy and buttons rise on load. The inner container has the same
   shape on every page (eyebrow, heading, lead, actions), so one pair of
   selectors covers all eight. It animates elements that are already painted,
   so it never gates the LCP image, and reduced motion switches it off. */
@keyframes mh-rise{
  from{ opacity:0; transform:translateY(20px); }
  to{ opacity:1; transform:none; }
}
.mh-page .hero__inner > *,
.mh-page .page-head__inner > *{
  animation:mh-rise 640ms var(--ease-standard) both;
}
.mh-page .hero__inner > :nth-child(1),
.mh-page .page-head__inner > :nth-child(1){ animation-delay:80ms; }
.mh-page .hero__inner > :nth-child(2),
.mh-page .page-head__inner > :nth-child(2){ animation-delay:180ms; }
.mh-page .hero__inner > :nth-child(3),
.mh-page .page-head__inner > :nth-child(3){ animation-delay:280ms; }
.mh-page .hero__inner > :nth-child(4),
.mh-page .page-head__inner > :nth-child(4){ animation-delay:380ms; }
@media (prefers-reduced-motion:reduce){
  .mh-page .hero__inner > *,
  .mh-page .page-head__inner > *{ animation:none; }
}

/* ---- Gold buttons ----
   The gold fill carried ink text at 2.8:1, and over photography the outline
   variant became a smoked-glass panel with a gold edge — the cloudy button.
   Both are now one thing: a solid beige plate with deep gold lettering.
   #6d5514 on #f0ece4 is 5.9:1, and a solid plate reads the same over a
   photograph as it does on paper, so the hero and dark-band special cases
   are no longer needed. No border: the plate carries itself, and hover is a
   slight darkening of the plate, the same move --primary makes from ink-900
   to ink-800 rather than a colour swap. */
.btn--accent,
.btn--outline-gold,
.hero .btn--outline-gold,
.page-head .btn--outline-gold,
.section--dark .btn--outline-gold,
.mh-page .elementor-widget-button.btn--accent .elementor-button,
.mh-page .elementor-widget-button.btn--outline-gold .elementor-button,
.mh-page .hero .elementor-widget-button.btn--outline-gold .elementor-button,
.mh-page .page-head .elementor-widget-button.btn--outline-gold .elementor-button,
.mh-page .section--dark .elementor-widget-button.btn--outline-gold .elementor-button{
  background:var(--bone);
  color:var(--gold-900);
  border-color:transparent;
  -webkit-backdrop-filter:none;
  backdrop-filter:none;
}
.btn--accent:hover,
.btn--outline-gold:hover,
.hero .btn--outline-gold:hover,
.page-head .btn--outline-gold:hover,
.section--dark .btn--outline-gold:hover,
.mh-page .elementor-widget-button.btn--accent .elementor-button:hover,
.mh-page .elementor-widget-button.btn--outline-gold .elementor-button:hover,
.mh-page .hero .elementor-widget-button.btn--outline-gold .elementor-button:hover,
.mh-page .page-head .elementor-widget-button.btn--outline-gold .elementor-button:hover,
.mh-page .section--dark .elementor-widget-button.btn--outline-gold .elementor-button:hover{
  background:var(--bone-deep);
  color:var(--gold-900);
  border-color:transparent;
}

/* ============================================================
   Astra global colours — removed from the palette entirely
   Astra ships two blues of its own, --ast-global-color-0 (#046bd2) and
   --ast-global-color-1 (#045cb4), and 54 rules in the theme paint with them:
   link colour, a:hover, a:focus, button:hover, BUTTON:FOCUS, ::selection,
   checked inputs, input:focus borders, pagination, entry meta. None of it is
   in the Marvin palette, and patching one state at a time only moves the
   problem to the next state — clicking an FAQ row fired button:focus, not
   :hover, and went blue again. Redefining the two variables retires every one
   of those rules at once, so there is no off-brand blue left to find.
   !important because Astra emits its own :root block inline in the head.
   ============================================================ */
:root{
  --ast-global-color-0:#132131 !important;  /* was #046bd2 — brand blue */
  --ast-global-color-1:#24394f !important;  /* was #045cb4 — brand blue, one step up for hover/focus */
}

/* Astra paints a filled background on any button it can reach, on both hover
   and focus. The design system's buttons own their own states, so the theme's
   fill is refused outright rather than recoloured. */
.mh-page .btn:hover,
.mh-page .btn:focus,
.mh-page .elementor-button:hover,
.mh-page .elementor-button:focus,
.mh-page .acc__trigger:hover,
.mh-page .acc__trigger:focus{
  background-color:inherit;
  color:inherit;
}
/* …then each component re-states its own, after the reset above. */
.mh-page .accordion .acc__trigger:hover,
.mh-page .accordion .acc__trigger:focus,
.mh-page .accordion .acc__trigger:focus-visible,
.mh-page .accordion .acc__item.is-open .acc__trigger{
  background-color:var(--ink-900);
  color:var(--cream);
}
.mh-page .accordion .acc__trigger:hover .i,
.mh-page .accordion .acc__trigger:focus .i,
.mh-page .accordion .acc__item.is-open .acc__trigger .i{ color:var(--gold-400); }

/* Focus stays visible for keyboard users, in the brand's gold rather than a
   browser/theme blue ring. */
.mh-page a:focus-visible,
.mh-page button:focus-visible,
.mh-page .elementor-button:focus-visible,
.mh-page input:focus-visible,
.mh-page textarea:focus-visible,
.mh-page select:focus-visible{
  outline:2px solid var(--focus-ring);
  outline-offset:2px;
}

/* ============================================================
   Button alignment and spacing
   ============================================================ */

/* ---- Alignment ----
   The widget wrapper carries the .btn class so the paint rules can reach the
   inner <a>, but .btn also brings justify-content:center. The wrapper is a
   full-width flex container, so every standalone button was centred inside
   its own column — sitting 160-220px right of the paragraph above it while
   the copy ran hard left. (There is no .elementor-button-wrapper in this
   Elementor version, so the older rules aimed at it never applied.)

   Only the PACKING is changed. An earlier attempt switched the wrapper to
   display:block and the anchor to inline-flex so text-align would position
   it; that also discarded the wrapper's align-items:center, which is what
   held buttons centred on their cross axis, and it moved things that were
   previously fine — including the header. Changing justify-content alone
   leaves display, align-items and width untouched, so nothing shifts
   vertically and --full still stretches.

   Containers the design marks .center keep centred buttons. */
.mh-page .elementor-widget-button.btn{ justify-content:flex-start; }
.mh-page .center .elementor-widget-button.btn,
.mh-page .center.elementor-widget-button.btn{ justify-content:center; }
/* Header and footer are Xpro theme-builder templates with their own layout;
   this is a page-content fix and must not reach them. */
.mh-page .mh-header .elementor-widget-button.btn,
.mh-page .mh-footer .elementor-widget-button.btn{ justify-content:center; }

/* ---- Spacing ----
   A button directly after a paragraph or heading sat flush against it — the
   text widget's bottom margin is zeroed by the Elementor reset, so there was
   nothing between them. Cards already space their own buttons via the
   container gap, so this only reaches buttons that follow copy directly. */
.mh-page .elementor-widget-text-editor + .elementor-widget-button.btn,
.mh-page .elementor-widget-text + .elementor-widget-button.btn,
.mh-page .elementor-widget-heading + .elementor-widget-button.btn,
.mh-page .elementor-widget-icon-list + .elementor-widget-button.btn{
  margin-top:var(--space-6);
}
/* Buttons are just as often grouped in their own container (.hero__actions and
   the like) as they are direct siblings of the copy. That container is the one
   the adjacency rule above cannot see, which is why the hero pair still sat
   flush against the lead paragraph at a 0px gap. */
.mh-page .elementor-widget-text-editor + .e-con:has(> .elementor-widget-button),
.mh-page .elementor-widget-text + .e-con:has(> .elementor-widget-button),
.mh-page .elementor-widget-heading + .e-con:has(> .elementor-widget-button),
.mh-page .elementor-widget-icon-list + .e-con:has(> .elementor-widget-button){
  margin-top:var(--space-6);
}
/* Both rules above assume the button sits BELOW the copy. In the header the
   phone number and the button sit side by side in a row, so the adjacency
   matched and dropped 32px on top of the button — knocking it 16px below the
   phone it is supposed to line up with. Header and footer are theme-builder
   templates and own their own spacing. */
.mh-page .mh-header .elementor-widget-button.btn,
.mh-page .mh-footer .elementor-widget-button.btn,
.mh-page .mh-header .e-con:has(> .elementor-widget-button),
.mh-page .mh-footer .e-con:has(> .elementor-widget-button){
  margin-top:0;
}

/* ============================================================
   Approach band — calls to action moved onto the photograph
   The two CTAs used to sit in a cream section of their own beneath the image.
   They now live inside the band, so the band's composition changes with them:
   the copy column centres, and the scrim goes even rather than weighted down
   the left edge — that weighting only existed to back left-set text. Scoped
   with :has() so the other .bleed bands, which are still left-set, are
   untouched.
   ============================================================ */
.mh-page .bleed:has(.hero__actions) .bleed__inner{
  max-width:820px;
  margin-inline:auto;
  text-align:center;
}
.mh-page .bleed:has(.hero__actions) .bleed__scrim{
  background:linear-gradient(180deg,rgba(12,20,30,.62),rgba(12,20,30,.74));
}
.mh-page .bleed:has(.hero__actions) .bleed__inner p{ margin-inline:auto; }
.mh-page .bleed:has(.hero__actions) .elementor-widget-divider{ margin-inline:auto; }
.mh-page .bleed:has(.hero__actions) .elementor-widget-divider .elementor-divider{
  justify-content:center;
}
/* Breathing room between the copy and the buttons. */
.mh-page .bleed:has(.hero__actions) .hero__actions{
  justify-content:center;
  margin-top:var(--space-7);
}

/* A .center actions row was only ever centred by text-align, which does
   nothing to flex items — so the pair sat hard left. Centre the row itself. */
.mh-page .e-con.hero__actions.center{ justify-content:center; }

/* Over a photograph both buttons are solid plates — nothing translucent, and
   nothing that depends on the image behind it. Cream on ink is 15.0:1 and ink
   on cream is the same pair inverted, so the two read as a clear primary and
   secondary while both stay legible against any frame of the picture. */
.mh-page .bleed .elementor-widget-button.btn--primary .elementor-button{
  background:var(--cream); color:var(--ink-900); border-color:var(--cream);
}
.mh-page .bleed .elementor-widget-button.btn--primary .elementor-button:hover{
  background:var(--white); border-color:var(--white); color:var(--ink-900);
}
.mh-page .bleed .elementor-widget-button.btn--outline .elementor-button{
  background:var(--ink-900); color:var(--cream); border-color:var(--cream);
}
.mh-page .bleed .elementor-widget-button.btn--outline .elementor-button:hover{
  background:var(--ink-800); border-color:var(--white); color:var(--cream);
}

/* ============================================================
   Contact — one screen per section
   The right-hand column ran 1006px against a 900px viewport, so the enquiry
   section could not be seen in one go. The detail rows carried 24px of
   padding top and bottom each — nearly 100px per row for a single line of
   text — and the photograph beneath added another 445px. Both are pulled in
   until the column fits alongside the form.
   ============================================================ */
/* .mh-page is the BODY element itself, so page-id scoping has to be a
   compound selector — .page-id-289 .mh-page (descendant) matches nothing. */
.page-id-289.mh-page .contact-row{ padding:10px 0; gap:var(--space-3); }
.page-id-289.mh-page .card--pad dl{ margin-top:var(--space-3); }
.page-id-289.mh-page .card--pad{ padding:var(--space-5); }
.page-id-289.mh-page .split .media--4x3{ max-height:16rem; }
.page-id-289.mh-page .split .media--4x3 img{ height:100%; object-fit:cover; }

/* ---- Mobile nav toggle wrapper ----
   The hamburger is a text-editor widget, so Elementor wraps the <button> in a
   widget div. Hiding the button alone leaves that wrapper in the header grid
   as an unplaced fourth child, which wraps to a second row and adds dead
   height under the bar. The wrapper itself is hidden above the mobile
   breakpoint; below it the existing header rules place it as normal. */
@media (min-width:901px){
  .mh-page .mh-header__inner > .elementor-widget:has(.nav-toggle){ display:none; }
}

/* ============================================================
   Anchor buttons — restore their own text colour
   The Elementor reset carries .mh-page a{color:inherit} so widget links take
   their colour from context. At (0,1,1) that also outranks .btn--primary
   (0,1,0), so any hand-written <a class="btn"> inherited the surrounding ink
   instead — ink text on an ink fill, i.e. an invisible label. It hit the
   drawer's "Start Building" and the lightbox's closing CTA. Restated per
   variant at (0,2,1) so the anchor wins its colour back.
   ============================================================ */
.mh-page a.btn--primary,
.mh-page a.btn--secondary{ color:var(--cream); }
.mh-page a.btn--accent,
.mh-page a.btn--outline-gold{ color:var(--gold-900); }
.mh-page a.btn--outline,
.mh-page a.btn--ghost{ color:var(--ink-900); }
.mh-page .bleed a.btn--outline{ color:var(--cream); }

/* ============================================================
   Drawer footer (mobile)
   Three faults, all visible at once: the CTA label was invisible (above), the
   phone number was 11px of unstyled text that gave no sign of being tappable,
   and the block was pinned to the bottom of a full-height panel by an auto
   margin — 192px of dead space below "Contact".

   The foot now follows the menu with a rule to separate it, and the phone is
   a proper outlined button above the filled one: two stacked controls, both
   full width, both at a 48px+ tap target.
   ============================================================ */
.mh-page .drawer__foot{
  margin-top:var(--space-6);
  padding-top:var(--space-5);
  border-top:1px solid var(--border-subtle);
  gap:var(--space-3);
}
.mh-page .drawer__foot .mh-header__phone{
  display:flex;
  align-items:center;
  justify-content:center;
  min-height:48px;
  padding:12px 20px;
  border:1px solid var(--ink-900);
  border-radius:var(--radius-sm);
  color:var(--ink-900);
  font-family:var(--font-body);
  font-size:var(--text-base);
  font-weight:500;
  letter-spacing:var(--tracking-normal);
  text-decoration:underline;
  text-underline-offset:3px;
}
.mh-page .drawer__foot .mh-header__phone:hover,
.mh-page .drawer__foot .mh-header__phone:focus{
  background:var(--ink-900);
  color:var(--cream);
  text-decoration:none;
}
.mh-page .drawer__foot .btn{
  min-height:52px;
  font-size:var(--text-sm);
}

/* =========================================================================
   2026-08-18 - Editor parity for contextual heading colour

   Elementor emits heading colour at two different specificities. The static
   front-end file (post-<id>.css) carries only the kit-level rule

       .elementor-widget-heading .elementor-heading-title  (0,2,0)

   which the design system's contextual rules at (0,3,1) already outrank. The
   EDITOR canvas instead generates a per-element rule

       .elementor-<page> .elementor-element.elementor-element-<id> .elementor-heading-title   (0,4,0)

   for the same value, and (0,4,0) beats (0,3,1). Identical CSS, identical
   markup, different specificity - which is why display headings read cream on
   the live site and navy in the editor.

   Compounding on the body's own .elementor-page class takes these to (0,4,1),
   one step above Elementor's per-element rule, without resorting to
   !important - which would only start an escalation the next widget setting
   could re-open.

   Consequence worth knowing: inside .page-head and .section--dark the design
   system now OWNS heading colour outright, so a per-widget colour set in the
   editor will not take effect there. That is deliberate - those two contexts
   sit on dark ground and must stay legible.
   ========================================================================= */

.mh-page.elementor-page .page-head h1.elementor-heading-title,
.mh-page.elementor-page .page-head h2.elementor-heading-title {
	color: var(--cream);
}

.mh-page.elementor-page .section--dark h1.elementor-heading-title,
.mh-page.elementor-page .section--dark h2.elementor-heading-title,
.mh-page.elementor-page .section--dark h3.elementor-heading-title {
	color: var(--cream);
}

/* .hero__title is carried on the widget wrapper on some pages and on the
   heading itself on others; cover both so the home hero cannot regress. */
.mh-page.elementor-page .hero__title h1.elementor-heading-title,
.mh-page.elementor-page .hero__title h2.elementor-heading-title,
.mh-page.elementor-page h1.hero__title.elementor-heading-title,
.mh-page.elementor-page h2.hero__title.elementor-heading-title {
	color: var(--cream);
}


/* =========================================================================
   2026-08-18 - Light cards standing on dark ground

   .magnet__card is a WHITE card sitting inside a .section--dark band, but it
   only ever declared background/border/shadow - never a text colour. So its
   contents inherited the band's cream and the "Get the report" heading has
   been rendering off-white on white, effectively invisible, on Home, Custom
   Home Building and Contact.

   The editor happened to look correct only because Elementor's per-element
   rule (0,4,0) outranked the old contextual rule at (0,3,1). Once the block
   above lifted the contextual rules to (0,4,1) the editor started agreeing
   with the (wrong) live rendering, which is what surfaced this.

   Fixed at the CARD, so headings, labels and helper text all recover
   together. The heading selectors are restated explicitly because
   .elementor-heading-title is painted by Elementor's own per-element rule at
   (0,4,0), which plain inheritance cannot outrank.
   ========================================================================= */

.mh-page.elementor-page .magnet__card,
.mh-page.elementor-page .section--dark .magnet__card {
	color: var(--text-primary);
}

.mh-page.elementor-page .section--dark .magnet__card h1.elementor-heading-title,
.mh-page.elementor-page .section--dark .magnet__card h2.elementor-heading-title,
.mh-page.elementor-page .section--dark .magnet__card h3.elementor-heading-title,
.mh-page.elementor-page .section--dark .magnet__card h4.elementor-heading-title,
.mh-page.elementor-page .magnet__card h1.elementor-heading-title,
.mh-page.elementor-page .magnet__card h2.elementor-heading-title,
.mh-page.elementor-page .magnet__card h3.elementor-heading-title,
.mh-page.elementor-page .magnet__card h4.elementor-heading-title {
	color: var(--text-primary);
}

/* Plain (non-widget) headings inside the card, for the static-build markup. */
.mh-page.elementor-page .section--dark .magnet__card h1,
.mh-page.elementor-page .section--dark .magnet__card h2,
.mh-page.elementor-page .section--dark .magnet__card h3,
.mh-page.elementor-page .section--dark .magnet__card h4 {
	color: var(--text-primary);
}


/* =========================================================================
   2026-08-18 - Editor parity round 3, plus stat-row centring

   Same root cause as the H1 case: Elementor's per-element rule (0,4,0) beats
   the design system's contextual rules, so anything whose colour comes from
   CONTEXT rather than from a widget setting reads wrong in the canvas. Each
   block below restates the live value one specificity step higher.
   ========================================================================= */

/* 1. Hero eyebrow - drop the gold dash that preceded the label. */
.mh-page .hero__eyebrow::before { display: none; }

/* 2. Impact metrics. Live: numerals gold on the dark band, labels cream.
      The numerals sit in text-editor widgets, so the widget itself has to be
      targeted - Elementor paints the widget div and inheritance cannot win. */
.mh-page.elementor-page .section--dark .stat__value,
.mh-page.elementor-page .section--dark .stat__value .elementor-widget-text-editor,
.mh-page.elementor-page .section--dark .stat__value p {
	color: var(--gold-500);
}

.mh-page.elementor-page .section--dark .stat > .elementor-widget-text-editor,
.mh-page.elementor-page .section--dark .stat > .elementor-widget-text-editor p {
	color: var(--cream);
}

/* Centre each figure over its descriptor, and the row as a whole. auto-fit
   means the row re-balances itself to however many stats exist - three now
   that "10-20 custom homes a year" is gone, four again if one is re-added. */
.mh-page.elementor-page .stat-row {
	justify-items: center;
	text-align: center;
}

.mh-page.elementor-page .stat,
.mh-page.elementor-page .stat__value {
	--align-items: center;
	align-items: center;
	text-align: center;
}

@media (min-width: 900px) {
	.mh-page.elementor-page .stat-row {
		grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
	}
}

/* 3. Our Approach is a .bleed section - photo, dark scrim, cream type. */
.mh-page.elementor-page .bleed h1.elementor-heading-title,
.mh-page.elementor-page .bleed h2.elementor-heading-title,
.mh-page.elementor-page .bleed h3.elementor-heading-title,
.mh-page.elementor-page .bleed .elementor-widget-text-editor {
	color: var(--cream);
}

/* 4. Beige buttons. Elementor's per-element rule ties with the design
      system's .mh-page .elementor-widget-button.btn--x rule at (0,4,0) and
      wins on source order inside the canvas, which is why they read gold
      there. Compounding on .elementor-page settles it at (0,5,0). */
.mh-page.elementor-page .elementor-widget-button.btn--outline .elementor-button {
	background: transparent;
	color: var(--ink-900);
	border-color: var(--ink-900);
}
.mh-page.elementor-page .elementor-widget-button.btn--outline .elementor-button:hover {
	background: var(--ink-900);
	color: var(--cream);
	border-color: var(--ink-900);
}

.mh-page.elementor-page .elementor-widget-button.btn--secondary .elementor-button {
	background: var(--stone-800);
	color: var(--cream);
	border-color: var(--stone-800);
}
.mh-page.elementor-page .elementor-widget-button.btn--secondary .elementor-button:hover {
	background: var(--ink-900);
	color: var(--cream);
	border-color: var(--ink-900);
}


/* =========================================================================
   2026-08-18 - Social icons live in the legal bar

   Moved out of the first footer column and into .mh-footer__legal, which is
   already display:flex / justify-content:space-between - so the copyright
   sits left and the icons sit right with no positioning tricks. The old
   margin-top existed to separate them from the about paragraph above; in the
   legal row it just pushes them off the baseline.
   ========================================================================= */

.mh-page .mh-footer__legal .mh-footer__social {
	margin-top: 0;
}

.mh-page .mh-footer__legal .mh-footer__social .xpro-social-icon-wrapper,
.mh-page .mh-footer__legal .mh-footer__social ul {
	justify-content: flex-end;
}


/* =========================================================================
   2026-08-18 - History flow re-proportioned for a landscape image

   The media column was aspect-ratio:4/5 with object-fit:cover, which suited a
   portrait photograph and cropped anything else. The brochure scan is 2194x1628
   landscape, so the column now takes two thirds, the timeline cards take one
   third, and the image is shown WHOLE rather than filled to a fixed box.

   The img selector carries five classes on purpose: the global image rule
   .mh-page .elementor-widget-image:not(.mh-header__logo):not(.mh-footer__logo) img
   scores (0,4,1) because each :not() counts a class, so a shorter selector
   here would lose and the image would still be cropped.
   ========================================================================= */





/* =========================================================================
   2026-08-18 - Counter widgets in the impact bar

   The stat figures are now Elementor counter widgets rather than text
   editors. Two things follow from that.

   1. ORDER IS ALREADY CORRECT - do not 'fix' it again. The markup prints
      .elementor-counter-title BEFORE .elementor-counter-number-wrapper, which
      looks inverted in the DOM, but Elementor's widget-counter.min.css sets
      .elementor-counter{flex-direction:column-reverse}, so the figure already
      renders above the label. An order/flex-direction override here is a
      no-op that merely cancels itself out.

   2. TYPOGRAPHY. The old figures inherited the display serif from
      .stat__value; the counter brings its own type, so the face, weight,
      size and tabular numerals are restated here.

   Colour is deliberately NOT set: the number and title colours come from the
   widget's own settings, so they stay editable in Elementor and read the
   same in the canvas as on the site.
   ========================================================================= */

.mh-page.elementor-page .stat .elementor-counter {
	align-items: center;
	text-align: center;
	gap: var(--space-2);
}

.mh-page.elementor-page .stat .elementor-counter-number-wrapper {
	font-family: var(--font-display);
	font-weight: 600;
	font-size: var(--text-3xl);
	line-height: 1;
	font-variant-numeric: tabular-nums;
	display: flex;
	align-items: baseline;
	justify-content: center;
}

.mh-page.elementor-page .stat .elementor-counter-title {
	font-family: var(--font-body);
	font-size: var(--text-xs);
	letter-spacing: var(--tracking-wider);
	text-transform: uppercase;
	line-height: 1.3;
	margin: 0;
}


/* =========================================================================
   2026-08-18 - History media: hold centred in the viewport, not at the top

   position:sticky pins an element at its `top` offset, so the photograph sat
   just under the header and stayed there while the timeline scrolled past -
   reading as "stuck to the top" rather than as a companion to the text.

   A sticky box cannot centre itself: percentage `top` resolves against the
   containing block, not the element, so there is no way to express "half my
   own height". The fix is to make the STICKY BOX the full height of the
   viewport and centre the picture inside it with flex. The box is what
   sticks; the image floats in the middle of it, gaining even space above and
   below, and stays vertically centred for the whole scroll.

   padding-block supplies the top and bottom margins, and max-height keeps a
   tall image inside the viewport so the sticky never outgrows its own frame -
   which is the one thing that silently breaks sticky positioning.

   Two columns only: below 900px the layout is a single column and the media
   is static, where sticky would make no sense.
   ========================================================================= */

@media (min-width: 901px) {
	
	
	}





/* =========================================================================
   2026-08-18 - Secondary-counties line under the locations grid

   "We also build in Charlotte County, DeSoto County and Hendry County..." is
   a sibling AFTER .locations, so it already spans the full width - but it
   carried no styling of its own, so it sat left-aligned, at body-copy size,
   flush against the grid. Beneath the left-hand card that reads as a caption
   on that one image rather than as a statement about the whole section.

   Centred across both cards, given real space above, and sized up so it
   carries as a sentence. Adjacent-sibling selector means this holds on all
   eight pages that share the communities partial, with no per-page edits.
   ========================================================================= */

.mh-page.elementor-page .locations + .elementor-widget-text-editor {
	margin-top: var(--space-7);
	text-align: center;
}

.mh-page.elementor-page .locations + .elementor-widget-text-editor p {
	/* .form-note also sets --text-xs and --text-muted; both are overridden
	   here, and its margin-top is zeroed because the widget above already
	   supplies the separation. */
	font-size: var(--text-md);
	line-height: var(--leading-relaxed);
	color: var(--text-secondary);
	max-width: 60ch;
	margin: 0 auto;
	text-align: center;
}


/* =========================================================================
   2026-08-18 - THE BUTTON SYSTEM. One place. Read this before editing buttons.

   Every button resolves to one of two families, and which one depends only on
   whether it stands on a LIGHT or a DARK ground:

     LIGHT ground   solid  = brand blue  #132131 -> hover #1b2c3f (lighter blue)
                    outline= transparent + blue  -> hover fills blue, cream text
     DARK ground    solid  = brand beige #f4f1ea -> hover #ffffff
                    outline= transparent + cream -> hover fills cream, blue text

   Dark grounds are .section--dark, .bleed, .page-head and .hero. Everything
   else is light (.section--cream, .section--ivory and .section--accent are all
   var(--surface-sunken)).

   Rules folded in and retired here:
     - .btn--secondary was background:var(--stone-800) #33414e, a grey-blue that
       matched nothing else, and it went DARKER on hover - the reverse of every
       other button. It is now identical to .btn--primary.
     - .btn--ghost was declared twice, colour:var(--ink-900) in one rule and
       colour:var(--gold-900) #6d5514 in a later one. The gold is gone.
     - .btn--outline-gold's gold fill on hover is gone; on photographic grounds
       it now behaves as the cream outline it already looked like at rest.

   Written at (0,5,0) and (0,6,0) so it also governs the Elementor EDITOR,
   whose per-element rules land at (0,4,0). Anything lower loses in the canvas
   while looking correct on the front end.
   ========================================================================= */

/* ---- SOLID, light ground ---- */
.mh-page.elementor-page .elementor-widget-button.btn--primary .elementor-button,
.mh-page.elementor-page .elementor-widget-button.btn--secondary .elementor-button,
.mh-page.elementor-page a.btn--primary,
.mh-page.elementor-page a.btn--secondary {
	background: var(--ink-900);
	color: var(--cream);
	border-color: var(--ink-900);
}
.mh-page.elementor-page .elementor-widget-button.btn--primary .elementor-button:hover,
.mh-page.elementor-page .elementor-widget-button.btn--secondary .elementor-button:hover,
.mh-page.elementor-page a.btn--primary:hover,
.mh-page.elementor-page a.btn--secondary:hover {
	background: var(--ink-800);
	color: var(--cream);
	border-color: var(--ink-800);
}

/* ---- OUTLINE + GHOST, light ground ---- */
.mh-page.elementor-page .elementor-widget-button.btn--outline .elementor-button,
.mh-page.elementor-page .elementor-widget-button.btn--outline-gold .elementor-button,
.mh-page.elementor-page a.btn--outline {
	background: transparent;
	color: var(--ink-900);
	border-color: var(--ink-900);
}
.mh-page.elementor-page .elementor-widget-button.btn--outline .elementor-button:hover,
.mh-page.elementor-page .elementor-widget-button.btn--outline-gold .elementor-button:hover,
.mh-page.elementor-page a.btn--outline:hover {
	background: var(--ink-900);
	color: var(--cream);
	border-color: var(--ink-900);
}

.mh-page.elementor-page .elementor-widget-button.btn--ghost .elementor-button,
.mh-page.elementor-page a.btn--ghost {
	background: transparent;
	color: var(--ink-900);
	border-color: transparent;
}
.mh-page.elementor-page .elementor-widget-button.btn--ghost .elementor-button:hover,
.mh-page.elementor-page a.btn--ghost:hover {
	background: var(--stone-100);
	color: var(--ink-800);
	border-color: transparent;
}

/* ---- SOLID, dark ground: beige, because blue on blue is not contrast ---- */
.mh-page.elementor-page .section--dark .elementor-widget-button.btn--primary .elementor-button,
.mh-page.elementor-page .section--dark .elementor-widget-button.btn--secondary .elementor-button,
.mh-page.elementor-page .bleed .elementor-widget-button.btn--primary .elementor-button,
.mh-page.elementor-page .bleed .elementor-widget-button.btn--secondary .elementor-button,
.mh-page.elementor-page .page-head .elementor-widget-button.btn--primary .elementor-button,
.mh-page.elementor-page .page-head .elementor-widget-button.btn--secondary .elementor-button,
.mh-page.elementor-page .hero .elementor-widget-button.btn--primary .elementor-button,
.mh-page.elementor-page .hero .elementor-widget-button.btn--secondary .elementor-button {
	background: var(--cream);
	color: var(--ink-900);
	border-color: var(--cream);
}
.mh-page.elementor-page .section--dark .elementor-widget-button.btn--primary .elementor-button:hover,
.mh-page.elementor-page .section--dark .elementor-widget-button.btn--secondary .elementor-button:hover,
.mh-page.elementor-page .bleed .elementor-widget-button.btn--primary .elementor-button:hover,
.mh-page.elementor-page .bleed .elementor-widget-button.btn--secondary .elementor-button:hover,
.mh-page.elementor-page .page-head .elementor-widget-button.btn--primary .elementor-button:hover,
.mh-page.elementor-page .page-head .elementor-widget-button.btn--secondary .elementor-button:hover,
.mh-page.elementor-page .hero .elementor-widget-button.btn--primary .elementor-button:hover,
.mh-page.elementor-page .hero .elementor-widget-button.btn--secondary .elementor-button:hover {
	background: var(--white);
	color: var(--ink-900);
	border-color: var(--white);
}

/* ---- OUTLINE, dark ground ---- */
.mh-page.elementor-page .section--dark .elementor-widget-button.btn--outline .elementor-button,
.mh-page.elementor-page .section--dark .elementor-widget-button.btn--outline-gold .elementor-button,
.mh-page.elementor-page .bleed .elementor-widget-button.btn--outline .elementor-button,
.mh-page.elementor-page .bleed .elementor-widget-button.btn--outline-gold .elementor-button,
.mh-page.elementor-page .page-head .elementor-widget-button.btn--outline .elementor-button,
.mh-page.elementor-page .page-head .elementor-widget-button.btn--outline-gold .elementor-button,
.mh-page.elementor-page .hero .elementor-widget-button.btn--outline .elementor-button,
.mh-page.elementor-page .hero .elementor-widget-button.btn--outline-gold .elementor-button {
	background: rgba(12, 20, 30, .28);
	color: var(--cream);
	border-color: rgba(255, 255, 255, .55);
}
.mh-page.elementor-page .section--dark .elementor-widget-button.btn--outline .elementor-button:hover,
.mh-page.elementor-page .section--dark .elementor-widget-button.btn--outline-gold .elementor-button:hover,
.mh-page.elementor-page .bleed .elementor-widget-button.btn--outline .elementor-button:hover,
.mh-page.elementor-page .bleed .elementor-widget-button.btn--outline-gold .elementor-button:hover,
.mh-page.elementor-page .page-head .elementor-widget-button.btn--outline .elementor-button:hover,
.mh-page.elementor-page .page-head .elementor-widget-button.btn--outline-gold .elementor-button:hover,
.mh-page.elementor-page .hero .elementor-widget-button.btn--outline .elementor-button:hover,
.mh-page.elementor-page .hero .elementor-widget-button.btn--outline-gold .elementor-button:hover {
	background: var(--cream);
	color: var(--ink-900);
	border-color: var(--cream);
}

/* =========================================================================
   2026-08-18 - Editor parity sweep for context-coloured text

   Same principle as the buttons. Any text whose colour comes from its CONTEXT
   rather than from a widget setting must be restated at (0,5,0) or it loses to
   Elementor's per-element rule inside the canvas.
   ========================================================================= */

.mh-page.elementor-page .section--dark .elementor-widget-text-editor,
.mh-page.elementor-page .bleed .elementor-widget-text-editor,
.mh-page.elementor-page .page-head .elementor-widget-text-editor {
	color: var(--cream);
}

.mh-page.elementor-page .section--dark .elementor-widget-heading .elementor-heading-title,
.mh-page.elementor-page .bleed .elementor-widget-heading .elementor-heading-title,
.mh-page.elementor-page .page-head .elementor-widget-heading .elementor-heading-title,
.mh-page.elementor-page .hero .elementor-widget-heading .elementor-heading-title {
	color: var(--cream);
}

/* The secondary-counties line: .form-note colours it --text-muted, and
   Elementor repaints the widget in the canvas, so both the widget and the
   container are restated alongside the paragraph. */
.mh-page.elementor-page .locations + .elementor-widget-text-editor,
.mh-page.elementor-page .locations + .elementor-widget-text-editor p.form-note {
	color: var(--text-secondary);
}


/* =========================================================================
   2026-08-18 - Footer logo needs air beneath it

   WHY THE ELEMENTOR MARGIN DID NOTHING. The reset a few hundred lines above,

       .mh-page .elementor-widget:not(:last-child) { margin-block-end: 0 }

   scores (0,3,0) - :not(:last-child) counts its argument as a class. Elementor
   writes a widget's own margin as

       .elementor-<tpl> .elementor-element.elementor-element-<id> { margin: ... }

   which is ALSO (0,3,0). design-system.css loads at position 18 and the
   per-template sheet at 17, so the reset wins on source order and flattens the
   widget's bottom margin to zero. margin-block-end maps onto margin-bottom, so
   it overrides the shorthand's bottom value specifically.

   CONSEQUENCE WORTH KNOWING: setting a bottom margin on ANY widget in the
   Elementor panel has no effect on this site unless that widget is the last
   child of its container. Spacing has to come from the design system, which is
   what this rule does. (0,4,0) clears the reset.
   ========================================================================= */

.mh-page.elementor-page .mh-footer__logo.elementor-widget {
	margin-block-end: var(--space-6);
}


/* =========================================================================
   2026-08-18 - Service-area link + developer tag

   Site-wide, a { text-decoration:none }, so the link added to "Ask us about
   your site" was indistinguishable from the sentence around it. Underlined
   with an offset so the descenders stay legible.

   General sibling (~) rather than adjacent (+): the note is authored as one
   text widget but has been split into two paragraphs, and a later edit could
   as easily put another element between it and the grid.
   ========================================================================= */

.mh-page.elementor-page .locations ~ .elementor-widget-text-editor a {
	text-decoration: underline;
	text-underline-offset: 0.18em;
	text-decoration-thickness: 1px;
}

.mh-page.elementor-page .locations ~ .elementor-widget-text-editor a:hover {
	text-decoration-thickness: 2px;
}

/* ---- Developer tag, last line of the footer ---- */

.mh-page .mh-footer__dev {
	text-align: center;
	padding-top: var(--space-5);
}

.mh-page .mh-footer__dev p {
	margin: 0;
	font-size: var(--text-xs);
	letter-spacing: var(--tracking-wide);
	color: var(--text-inverse-muted);
}

.mh-page .mh-footer__dev a {
	color: var(--text-inverse-muted);
	text-decoration: underline;
	text-underline-offset: 0.18em;
}

.mh-page .mh-footer__dev a:hover {
	color: var(--cream);
}


/* =========================================================================
   2026-08-18 - Raw form buttons + the footer legal row

   THE FORM SUBMIT. The magnet and contact forms are hand-written HTML inside
   text-editor widgets, so their submit is a bare
   <button class="btn btn--primary btn--full"> - not an Elementor button widget,
   which means the widget-scoped button system does not reach it.

   On hover it was picking up background-color:inherit from the rule that
   refuses Astra's button fill. On the white .magnet__card that inherits to
   WHITE, while the colour still came from .btn--primary:hover = var(--cream).
   Cream on white: the label vanished. Colour and background were being decided
   by two different rules.

   Both are now stated together, so the pair can never drift apart again.
   ========================================================================= */

.mh-page.elementor-page form button.btn--primary,
.mh-page.elementor-page .magnet__card button.btn--primary {
	background: var(--ink-900);
	color: var(--cream);
	border-color: var(--ink-900);
}

.mh-page.elementor-page form button.btn--primary:hover,
.mh-page.elementor-page form button.btn--primary:focus,
.mh-page.elementor-page form button.btn--primary:focus-visible,
.mh-page.elementor-page .magnet__card button.btn--primary:hover,
.mh-page.elementor-page .magnet__card button.btn--primary:focus,
.mh-page.elementor-page .magnet__card button.btn--primary:focus-visible {
	background: var(--white);
	color: var(--ink-900);
	border-color: var(--ink-900);
}

/* =========================================================================
   2026-08-18 - Footer legal row: social left, copyright centre, credit right

   Three items on one line. Grid rather than space-between because with three
   flex children the middle one centres only when both outer items happen to be
   the same width - 1fr auto 1fr centres the copyright against the row itself.
   ========================================================================= */

.mh-page .mh-footer__legal {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	gap: var(--space-4);
}

.mh-page .mh-footer__legal .mh-footer__social {
	order: 1;
	justify-self: start;
	margin-top: 0;
}

.mh-page .mh-footer__legal > .elementor-widget-text-editor {
	order: 2;
	justify-self: center;
	text-align: center;
}

.mh-page .mh-footer__legal .mh-footer__dev {
	order: 3;
	justify-self: end;
	text-align: right;
	padding-top: 0;
}

@media (max-width: 780px) {
	.mh-page .mh-footer__legal {
		grid-template-columns: 1fr;
		justify-items: center;
		text-align: center;
	}
	.mh-page .mh-footer__legal .mh-footer__social,
	.mh-page .mh-footer__legal .mh-footer__dev {
		justify-self: center;
		text-align: center;
	}
}


/* =========================================================================
   2026-08-18 - Light cards win back their own ink (regression fix)

   The editor-parity sweep earlier today set every heading and text widget
   inside .section--dark to cream at (0,4,0)/(0,5,0). That is right for content
   sitting on the dark band - and wrong for content inside .magnet__card, which
   is a WHITE card standing on that band. It re-broke the exact bug fixed this
   morning, and it is also what the form's submit button inherited on hover.

   The card's contents are restated here one step higher. Same trap as before:
   a rule scoped to a dark section reaches through any light card nested in it.
   ========================================================================= */

.mh-page.elementor-page .section--dark .magnet__card,
.mh-page.elementor-page .section--dark .magnet__card .elementor-widget-text-editor,
.mh-page.elementor-page .section--dark .magnet__card .elementor-widget-text-editor p,
.mh-page.elementor-page .section--dark .magnet__card label,
.mh-page.elementor-page .section--dark .magnet__card .form-note {
	color: var(--text-primary);
}

.mh-page.elementor-page .section--dark .magnet__card .elementor-widget-heading .elementor-heading-title {
	color: var(--text-primary);
}


/* =========================================================================
   2026-08-18 - Mobile drawer: brand interaction colours + collapsed groups

   THE OFF-BRAND FLASH. --focus-ring is already gold, so the stray colour was
   never the focus ring: it is -webkit-tap-highlight-color, which no rule had
   ever set, so phones painted their own translucent grey-blue over the
   hamburger and the close control on every tap. Text selection had the same
   problem - the browser default blue - on a control there is no reason to
   select at all.

   THE HEIGHT. The drawer listed nine links, which no phone shows without
   scrolling. The two sections with children are <details> groups now, so the
   closed menu is four rows. overflow-y stays only as a safety net for a small
   handset with a group expanded.
   ========================================================================= */

.mh-page .nav-toggle,
.mh-page .drawer__close,
.mh-page .drawer__nav a,
.mh-page .drawer__group > summary,
.mh-page .drawer__foot a {
	-webkit-tap-highlight-color: rgba(197, 161, 50, .28);
}

.mh-page .nav-toggle,
.mh-page .drawer__close,
.mh-page .drawer__group > summary {
	-webkit-user-select: none;
	user-select: none;
}

.mh-page .nav-toggle:active,
.mh-page .drawer__close:active,
.mh-page .nav-toggle:focus-visible,
.mh-page .drawer__close:focus-visible {
	color: var(--gold-600);
}

.mh-page ::selection {
	background: rgba(197, 161, 50, .32);
	color: var(--ink-900);
}

/* ---- Collapsible groups ---- */

.mh-page .drawer__group {
	border-bottom: 1px solid var(--border-subtle);
}

.mh-page .drawer__group > summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	padding: var(--space-3) 0;
	font-family: var(--font-display);
	font-size: var(--text-lg);
	color: var(--ink-900);
	cursor: pointer;
	list-style: none;
}

.mh-page .drawer__group > summary::-webkit-details-marker {
	display: none;
}

.mh-page .drawer__group > summary::marker {
	content: '';
}

.mh-page .drawer__chev {
	width: 20px;
	height: 20px;
	flex: none;
	color: var(--gold-700);
	transition: transform var(--dur-base) var(--ease-standard);
}

.mh-page .drawer__group[open] > summary .drawer__chev {
	transform: rotate(180deg);
}

.mh-page .drawer__group .drawer__sub {
	padding-bottom: var(--space-2);
}

.mh-page .drawer__group .drawer__sub a:last-child {
	border-bottom: 0;
}

.mh-page .drawer__panel {
	overflow-y: auto;
	-webkit-overflow-scrolling: touch;
}


/* =========================================================================
   2026-08-18 - Astra repaints icon buttons white on :focus

   The real cause of the off-brand hamburger / close colour, and it was never
   the tap highlight. Astra's main.min.css ships:

       button:focus, button:hover, .button:focus, ... { color:#fff }
       .ast-button, .button, button, ...            { background:#e6e6e6; border:1px solid }

   button:focus scores (0,1,1) and outranks .nav-toggle { color:var(--ink-900) }
   at (0,1,0). A tap on a phone leaves the control in :focus - not :hover, and
   frequently not :focus-visible either - so the icon turned WHITE and stayed
   white until something else took focus. Styling only :active and
   :focus-visible, as the previous attempt did, misses exactly the state touch
   leaves behind.

   Every interactive state is now stated explicitly for both controls, and the
   brand gold is re-applied afterwards so press and keyboard focus still read
   as deliberate feedback.
   ========================================================================= */

.mh-page .nav-toggle,
.mh-page .nav-toggle:hover,
.mh-page .nav-toggle:focus,
.mh-page .nav-toggle:focus-within,
.mh-page .nav-toggle:focus-visible,
.mh-page .nav-toggle:active,
.mh-page .drawer__close,
.mh-page .drawer__close:hover,
.mh-page .drawer__close:focus,
.mh-page .drawer__close:focus-within,
.mh-page .drawer__close:focus-visible,
.mh-page .drawer__close:active {
	background: none;
	border: 0;
	box-shadow: none;
	color: var(--ink-900);
}

/* Deliberate feedback, applied after the reset above so it wins on order. */
.mh-page .nav-toggle:active,
.mh-page .nav-toggle:focus-visible,
.mh-page .drawer__close:active,
.mh-page .drawer__close:focus-visible {
	color: var(--gold-600);
}

/* The icon inherits currentColor, but Astra can reach the svg too. */
.mh-page .nav-toggle .i,
.mh-page .drawer__close .i {
	color: inherit;
	stroke: currentColor;
}


/* ============================================================
   2026-08-19 - Awards, president bio and partner directory
   Ported from the static build after the client's "Marvin Homes
   Info" sheet replaced the discovery-call content.
   Context-colouring rules are written at (0,5,0)+ per the
   specificity note: .mh-page.elementor-page + widget class.
   ============================================================ */

/* ---- Partner tiles (now real outbound links) ---- */
.mh-page .partners { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--space-5); }
.mh-page .partner {
	display: flex; align-items: center; justify-content: center;
	aspect-ratio: 3 / 2; text-decoration: none;
	background: var(--white); border: 1px solid var(--border-default);
	border-radius: var(--radius-md); padding: var(--space-5);
	transition: border-color .25s ease, transform .25s ease, box-shadow .25s ease;
}
/* Logo wall. Each tile is an identical box and the logo is CONTAINED inside a
   fixed optical area, so seven very different aspect ratios (ACRA is 5.4:1,
   D. Peck 1.5:1) still read as one evenly-weighted row. Logos are supplied as
   trimmed PNGs with transparent backgrounds, plus one SVG (FineMark). */
.mh-page .partner img {
	max-width: 100%; max-height: 56px; width: auto; height: auto;
	object-fit: contain; display: block; background: transparent;
}
/* Elementor wraps widget images in figure/div that can impose their own box. */
.mh-page .partner figure,
.mh-page .partner .elementor-widget-image,
.mh-page .partner .elementor-image { margin: 0; padding: 0; background: transparent; line-height: 0; }
/* Two lenders should not stretch to fill a five-wide row. */
.mh-page .partners--finance {
	grid-template-columns: repeat(auto-fit, minmax(180px, 240px));
	justify-content: center;
}
.mh-page .partner:hover, .mh-page .partner:focus-visible {
	border-color: var(--gold-500); transform: translateY(-3px);
	box-shadow: 0 6px 20px rgba(0, 0, 0, .08);
}
/* .mh-page a{color:inherit} would blank these, so restate them explicitly. */
.mh-page.elementor-page .partner .partner__name {
	display: block; font-family: var(--font-display); font-size: var(--text-sm);
	line-height: 1.25; color: var(--text-primary);
}
.mh-page.elementor-page .partner .partner__trade {
	display: block; font-size: var(--text-2xs); letter-spacing: var(--tracking-wider);
	text-transform: uppercase; color: var(--text-muted);
}

/* Financing partners are now logo tiles too (.partners--finance above);
   the text-card .lenders/.lender rules were removed 2026-08-19. */

/* ---- President portrait ----
   Scoped to the section, not a widget class: Elementor widgets take their
   custom classes from `_css_classes` (underscore), while CONTAINERS use
   `css_classes`. Targeting #president avoids depending on either.
   Sits in the LEFT column (2026-08-19); capped so the 1097x1536 source does
   not tower over the copy beside it. */
/* Deliberately NOT `.media` - that class carries a stone-200 ground, which
   showed as a 64px grey band beside a portrait narrower than its column.
   In an Elementor column-flex `.e-con`, horizontal centring is align-items,
   not justify-content (justify runs the vertical axis there). */
.mh-page #president .president__media {
	display: flex; flex-direction: column;
	align-items: center; justify-content: flex-start;
	background: none; overflow: visible;
}
.mh-page #president .elementor-widget-image img,
.mh-page .president__photo {
	width: 100%; max-width: 460px; height: auto;
	border-radius: var(--radius-md); display: block;
}

/* ---- Featured award cards (home + about) ---- */

/* ---- Full award record ---- */
.mh-page .rec { display: grid; gap: var(--space-8); }
.mh-page.elementor-page .rec .rec__heading {
	margin: 0 0 var(--space-4); font-size: var(--text-lg); color: var(--gold-700);
	border-bottom: 1px solid var(--border-subtle); padding-bottom: var(--space-3);
}
.mh-page .rec__table { width: 100%; border-collapse: collapse; }
.mh-page .rec__table tr { border-bottom: 1px solid var(--border-subtle); }
.mh-page .rec__table tr:last-child { border-bottom: 0; }
.mh-page .rec__table td {
	padding: var(--space-4) var(--space-3); vertical-align: top;
	font-size: var(--text-sm); color: var(--text-primary); background: transparent;
}
.mh-page .rec__table .rec__year { width: 72px; font-variant-numeric: tabular-nums; color: var(--text-muted); white-space: nowrap; }
.mh-page .rec__table .rec__project { display: block; font-size: var(--text-xs); color: var(--gold-700); margin-top: 2px; }
.mh-page .rec__table .rec__org { width: 34%; color: var(--text-secondary); font-size: var(--text-xs); }

@media (max-width: 640px) {
	.mh-page .rec__table .rec__org { display: none; }
	.mh-page .rec__table .rec__year { width: 56px; }
}


/* ============================================================
   2026-08-19b - Partner logo wall without cards, + vertical rhythm
   Overrides the block above (same specificity, later in file).
   ============================================================ */

/* Freestanding marks, no cards. Each logo sits in an identical fixed-height
   optical area so seven very different aspect ratios (Caloosa is 6:1, D. Peck
   1.5:1) read as one evenly-weighted row, name labelled beneath. */
/* Centred flex wrap, not a grid: 7 logos in a 6-column grid orphaned the last
   one on its own row. A wider basis plus a lower height cap also stops wide
   marks (Caloosa is 6:1) being squeezed to a third the height of square ones
   (D. Peck is 1.5:1) - measured 26px vs 64px before this change. */
.mh-page .partners {
	display: flex; flex-wrap: wrap;
	justify-content: center; align-items: flex-start;
	gap: var(--space-8) var(--space-7);
	margin-top: var(--space-8);
}
.mh-page .partner {
	flex: 0 1 200px;
	display: flex; flex-direction: column; align-items: center;
	gap: var(--space-4); text-decoration: none;
	padding: 0;
	/* reset the card treatment from the 2026-08-19 block */
	background: none; border: 0; border-radius: 0; aspect-ratio: auto;
	box-shadow: none;
}
.mh-page .partner:hover, .mh-page .partner:focus-visible {
	background: none; border: 0; transform: none; box-shadow: none;
}
.mh-page .partner .partner__logo {
	display: flex; align-items: center; justify-content: center;
	height: 60px; width: 100%;
}
.mh-page .partner img {
	max-height: 56px; max-width: 100%; width: auto; height: auto;
	object-fit: contain; display: block; background: transparent;
	transition: transform .25s ease;
}
.mh-page.elementor-page .partner .partner__name {
	display: block; font-family: var(--font-body);
	font-size: var(--text-xs); letter-spacing: var(--tracking-wide);
	text-transform: none; color: var(--text-secondary);
	text-align: center; line-height: 1.4;
}
.mh-page .partner:hover img, .mh-page .partner:focus-visible img { transform: translateY(-3px); }
.mh-page.elementor-page .partner:hover .partner__name,
.mh-page.elementor-page .partner:focus-visible .partner__name { color: var(--text-primary); }

/* ---- Vertical rhythm ----
   Two spacing mechanisms applied to the same stack. The design system spaces
   eyebrow / gold rule / heading / lead with ELEMENT margins; the Elementor
   port spaces them with container row-gap. Wherever both landed the gaps
   ADDED - #partners measured 32px above the gold bar and 48px below it - and
   where neither applied they collapsed to 0 (About's #awards sat flush).
   One mechanism owns it now: the container supplies the gap and every child's
   block-axis margin is zeroed, so nothing can stack on top. margin-inline is
   deliberately untouched; that is what centres the bar under
   .section-heading--center. */
.mh-page .e-con:has(> .rule-gold),
.mh-page .e-con.section-heading { row-gap: var(--space-4); }

.mh-page .e-con:has(> .rule-gold) > *,
.mh-page .e-con.section-heading > * { margin-block: 0; }

/* A .section-heading ends in a lede that belongs to its H2, so the stack runs
   tighter there: the container gap drops to 12 and the gold bar takes the 4px
   back through its own margin, which keeps every bar on the site at exactly
   16px above and below regardless of which rhythm its container uses. */
.mh-page .e-con.section-heading { row-gap: var(--space-3); }
.mh-page .e-con.section-heading > .rule-gold { margin-block: var(--space-1); }

/* ...and real air between the heading block and the content it introduces.
   Previously the outer container had row-gap:0, so the lede sat flush against
   the locations grid on all seven Service Area sections. */
.mh-page .e-con:has(> .e-con.section-heading) { row-gap: var(--space-7); }

.mh-page #record .rec { margin-top: var(--space-8); }
.mh-page .rec { gap: var(--space-9); }

/* The stat row under Richard's bio needs its own air. */
.mh-page #president .stat-row { margin-top: var(--space-7); }


/* ============================================================
   2026-08-19c - Award columns by association, awards subpage,
   and the approach->partners seam
   ============================================================ */

/* "What sets us apart" is about the trade relationships and Partners is the
   list of them - they read as one thought, so drop the seam between them. */
.mh-page #partners.section--flush-top,

/* ---- One column per granting association (About) ---- */

/* ---- Per-association tallies (Awards subpage) ---- */
.mh-page .orgtallies { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-8) var(--space-9); }
.mh-page .orgtally { display: flex; align-items: center; gap: var(--space-5); }
.mh-page .orgtally img { max-height: 56px; max-width: 150px; width: auto; object-fit: contain; display: block; }
.mh-page .orgtally div { display: grid; gap: 2px; }
.mh-page.elementor-page .orgtally strong { font-family: var(--font-display); font-size: var(--text-xl); line-height: 1; color: var(--gold-700); }
.mh-page.elementor-page .orgtally span { font-size: var(--text-2xs); letter-spacing: var(--tracking-wider); text-transform: uppercase; color: var(--text-muted); }

/* ---- Decade headings on the Awards subpage ---- */
.mh-page .rec__decadehead {
	display: flex; align-items: baseline; justify-content: space-between;
	gap: var(--space-5); border-bottom: 1px solid var(--border-subtle);
	padding-bottom: var(--space-3); margin-bottom: var(--space-4);
}
.mh-page.elementor-page .rec .rec__heading { margin: 0; border-bottom: 0; padding-bottom: 0; font-size: var(--text-lg); color: var(--gold-700); }
.mh-page.elementor-page .rec__count { font-size: var(--text-2xs); letter-spacing: var(--tracking-wider); text-transform: uppercase; color: var(--text-muted); }

@media (max-width: 900px) {
	}


/* ============================================================
   2026-08-19d - Partners trimmed to a short centred coda, and
   awards reduced to two floating association logos
   ============================================================ */

/* Partners is a short coda to "What sets us apart", not a full stop. */
.mh-page #partners { padding-top: 0; padding-bottom: var(--space-7); }
/* The logo wall used to sit 130px below "The people behind every home": a 64px
   container row-gap plus its own 48px margin-top, stacked. The generic
   heading-block separation above supplies the gap now, so the margin goes. */
.mh-page #partners .partners { margin-top: 0; gap: var(--space-7); }

/* Centred section heading. The heading container is max-width 640px, so it
   needs centring itself - text-align alone leaves the text centred inside a
   box that is still hard left. Elementor's divider carries its own alignment,
   so the rule has to be centred separately. */
.mh-page .section-heading--center {
	margin-inline: auto; text-align: center; align-items: center;
}
/* The divider widget IS the 56px gold bar (.rule-gold sets its width and
   background). Do NOT give it width:100% to centre it - that stretched it to
   the heading's full 640px. Centre with auto margins and leave width alone. */
.mh-page .section-heading--center .rule-gold,
.mh-page .section-heading--center .elementor-widget-divider.rule-gold {
	margin-inline: auto;
}
.mh-page .section-heading--center .elementor-divider { justify-content: center; }

/* A hand-written <hr class="rule-gold"> (as opposed to a divider WIDGET) is
   repainted #ccc by Astra's base `hr` rule AND zeroed by Astra's inline
   `body .elementor hr{margin:0}` (0,1,2) - both outrank .rule-gold at (0,1,0),
   which is why About's #awards eyebrow sat flush on top of its bar. Restate
   colour and margin together at (0,2,1) so a hand-written rule carries the
   same 16px above and below that a divider widget does. */
.mh-page hr.rule-gold {
	height: var(--rule-accent); width: 56px;
	background: var(--gold-600); background-color: var(--gold-600);
	border: 0; opacity: 1;
	margin-block: var(--space-4);
}

/* ---- Featured associations (About) ----
   Each association's logo sits to the LEFT of the awards it granted, so the
   pair reads as one row and the section is roughly a third shorter than the
   stacked version it replaces. Explicitly NOT a card: the 2026-08-19c
   .orgcard treatment is retired. */
/* Sizing note. The logo height cannot be derived from the text in CSS: the
   text height depends on the width the logo leaves, and a stretched <img> with
   width:auto falls back to its NATURAL width, which sends the row to 241px and
   crushes the copy to nothing. So the text column is fixed and the logo height
   is a variable tuned to the height that column produces - 136px against two
   awards here, 80px against the single award on Home. Measured Δ = 0 for both
   rows. If the award copy changes materially, retune --orgfeature-logo-h.
   Columns are `auto` and the track is centred, so the block sits centred in the
   section, and align-items:center puts every logo on its text's midline. */
.mh-page .orgfeature {
	--orgfeature-logo-h: 120px;
	--orgfeature-text-w: 400px;
	display: grid; grid-template-columns: auto auto;
	justify-content: center; align-items: center;
	gap: var(--space-7) var(--space-7);
	margin-top: 0;
	max-width: 100%;
}
.mh-page .orgfeature__item {
	display: flex; align-items: center; justify-content: center;
	gap: var(--space-6);
	text-align: left;
	background: none; border: 0; padding: 0;
	max-width: 100%;
}
.mh-page .orgfeature__logo {
	flex: 0 0 auto;
	height: var(--orgfeature-logo-h); width: auto;
	max-height: none; max-width: 100%;
	object-fit: contain; object-position: center; display: block;
}
.mh-page .orgfeature__list {
	list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4);
	/* 0 0, not 0 1: allowing the column to shrink let the wider logo squeeze its
	   own text into an extra line, so the two rows stopped matching. */
	flex: 0 0 var(--orgfeature-text-w); width: var(--orgfeature-text-w);
	max-width: var(--orgfeature-text-w); min-width: 0;
}
.mh-page .orgfeature__list li { display: grid; gap: var(--space-1); justify-items: start; }
.mh-page.elementor-page .orgfeature .orgfeature__year {
	font-size: var(--text-2xs); letter-spacing: var(--tracking-wider);
	text-transform: uppercase; color: var(--gold-700);
}
.mh-page.elementor-page .orgfeature .orgfeature__title {
	font-size: var(--text-sm); line-height: 1.45; color: var(--text-primary); max-width: none;
}
.mh-page.elementor-page .orgfeature .orgfeature__project {
	display: block; font-size: var(--text-xs); color: var(--text-muted); margin-top: 2px;
}

/* Home leads with three associations rather than About's two, and each carries
   ONE award instead of two - so its text block is shorter and the logo height
   that matches it is smaller. */
.mh-page .orgfeature--three {
	--orgfeature-logo-h: 80px;
	--orgfeature-text-w: 280px;
	grid-template-columns: auto auto auto;
}
.mh-page .orgfeature--three .orgfeature__item { gap: var(--space-5); }

/* The widget now sits outside .section-heading, which is where the centring
   lived, so restate the text alignment the rows need for themselves. */
.mh-page .orgfeature, .mh-page .orgfeature * { text-align: left; }


/* ============================================================
   2026-08-19e - Readability of copy set OVER PHOTOGRAPHY
   ------------------------------------------------------------
   Overlay copy was using --text-inverse-muted (#a7b6c6). That token is fine on
   a SOLID .section--dark band (~6.9:1) but here it sits on unpredictable
   photographs. Measured against a bright sky BEFORE this change:
       hero mid-scrim      1.39:1
       bleed right edge    1.03:1
       page-head top       2.42:1
   all far below the 4.5:1 floor for body text. Colour alone could not rescue
   1.03:1, so this fixes three axes together - stronger scrims, cream ink, and
   a larger/heavier face with a shadow to absorb whatever the photo does.
   After: page-head 7.58:1, hero 4.85:1, bleed (within the text box) ~7.8:1.
   ============================================================ */

:root {
	--text-overlay: var(--cream);
	--text-overlay-size: clamp(1.0625rem, .35vw + .98rem, 1.1875rem);
	--shadow-overlay-text: 0 1px 2px rgba(8, 14, 22, .42);
	--shadow-overlay-heading: 0 1px 6px rgba(8, 14, 22, .35);
}

/* Stronger scrims. These are the load-bearing part of the fix. */
.mh-page .page-head__scrim {
	background: linear-gradient(to top, rgba(12,20,30,.90), rgba(12,20,30,.72));
}
.mh-page .hero__scrim {
	background: linear-gradient(to top, rgba(12,20,30,.88), rgba(12,20,30,.58) 55%, rgba(12,20,30,.62));
}
.mh-page .bleed__scrim {
	background: linear-gradient(90deg, rgba(12,20,30,.92), rgba(12,20,30,.70) 60%, rgba(12,20,30,.50));
}
/* .bleed--quiet carries no text - it stays a light decorative wash. */
.mh-page .bleed--quiet .bleed__scrim {
	background: linear-gradient(180deg, rgba(12,20,30,.34), rgba(12,20,30,.18));
}

/* Body copy over photography. Written at (0,5,1) so Elementor's per-element
   rule at (0,4,0) cannot repaint it - see the specificity note above. */
.mh-page.elementor-page .page-head .elementor-widget.elementor-widget-text-editor p,
.mh-page.elementor-page .hero .elementor-widget.elementor-widget-text-editor p,
.mh-page.elementor-page .bleed .elementor-widget.elementor-widget-text-editor p,
.mh-page.elementor-page .page-head .elementor-widget.elementor-widget-text-editor,
.mh-page.elementor-page .hero .elementor-widget.elementor-widget-text-editor,
.mh-page.elementor-page .bleed .elementor-widget.elementor-widget-text-editor,
.mh-page .page-head p, .mh-page .page-head .lede,
.mh-page .hero__inner p, .mh-page .hero__inner .lede,
.mh-page .bleed__inner p, .mh-page .bleed__inner .lede {
	color: var(--text-overlay);
	font-size: var(--text-overlay-size);
	font-weight: 400;
	line-height: 1.6;
	text-shadow: var(--shadow-overlay-text);
}

/* Eyebrows over photography are small, letterspaced and thin, so they get the
   size/weight/shadow lift - but they stay GOLD, matching .hero__eyebrow. The
   2026-08-19e pass turned these cream, which broke the brand accent.
   --gold-500 measures 4.87:1 at the worst sampled backdrop, 6.95:1 typical,
   and 7.6:1 on a solid .section--dark band - the accent costs no legibility. */
.mh-page.elementor-page .page-head .elementor-widget-text-editor .eyebrow,
.mh-page.elementor-page .hero .elementor-widget-text-editor .eyebrow,
.mh-page.elementor-page .bleed .elementor-widget-text-editor .eyebrow,
.mh-page.elementor-page .page-head .elementor-widget-text-editor .eyebrow--inverse,
.mh-page.elementor-page .bleed .elementor-widget-text-editor .eyebrow--inverse,
.mh-page .eyebrow--inverse,
.mh-page .page-head .eyebrow, .mh-page .page-head .eyebrow--inverse,
.mh-page .hero__inner .eyebrow,
.mh-page .bleed__inner .eyebrow {
	color: var(--gold-500);
	font-size: var(--text-sm);
	font-weight: 500;
	text-shadow: var(--shadow-overlay-text);
}
/* The hero's own gold eyebrow keeps its brand colour. */
.mh-page .hero__eyebrow,
.mh-page.elementor-page .hero .elementor-widget-text-editor .hero__eyebrow {
	font-size: var(--text-sm);
	font-weight: 500;
	text-shadow: var(--shadow-overlay-text);
}

/* Headings are large enough for the 3:1 threshold, but they sit on the same
   photographs - a shadow keeps them off a blown-out highlight. */
.mh-page.elementor-page .page-head .elementor-heading-title,
.mh-page.elementor-page .hero .elementor-heading-title,
.mh-page.elementor-page .bleed .elementor-heading-title,
.mh-page .page-head h1, .mh-page .hero__inner h1,
.mh-page .hero__inner h2, .mh-page .bleed__inner h2 {
	text-shadow: var(--shadow-overlay-heading);
}

@media (max-width: 900px) {
	.mh-page .orgfeature,
	.mh-page .orgfeature--three { grid-template-columns: auto; gap: var(--space-7); }
}
/* A phone cannot hold a full-height logo AND a readable award title on one
   line, so the logo steps down and the text column becomes fluid. The
   logo-left orientation and the shared midline are kept at every width. */
@media (max-width: 640px) {
	.mh-page .orgfeature,
	.mh-page .orgfeature--three {
		--orgfeature-logo-h: 56px;
		--orgfeature-text-w: auto;
		grid-template-columns: minmax(0, 1fr);
	}
	.mh-page .orgfeature__item { gap: var(--space-4); }
	.mh-page .orgfeature__logo { max-width: 96px; }
	.mh-page .orgfeature__list { flex: 1 1 auto; width: auto; max-width: none; }
}


/* ============================================================
   2026-08-26 — UX pass
   Body copy, award metadata, focus, tap targets, image loading.
   ============================================================ */

/* ---- Body copy: 18px / 1.6 ----
   Raised at the token rather than on a blanket `p` selector, so every
   component that asks for "body size" moves together while the deliberately
   smaller labels — eyebrows, field labels, captions — stay where they were
   put. Copy set over photography keeps its own --text-overlay-size. */
:root{
	--text-base: 1.125rem;   /* 16px -> 18px */
	--leading-normal: 1.6;   /* 1.5  -> 1.6  */
}

/* Two blocks of running prose had been sized with a label token. They are
   paragraphs, so they take the body size. */
.mh-page .projcard__body p,
.mh-page .award p{
	font-size: var(--text-base);
	line-height: var(--leading-normal);
}

/* ---- Award metadata: 14px floor ----
   The year, the project attribution, the per-association tallies and the
   decade counts on the Awards page all ran at 11px or 12px. The selectors
   mirror the originals exactly, so they win on source order rather than by
   piling on weight. */
.mh-page.elementor-page .orgfeature .orgfeature__year,
.mh-page.elementor-page .orgfeature .orgfeature__project,
.mh-page .rec__table .rec__project,
.mh-page .rec__table .rec__org,
.mh-page.elementor-page .rec__count,
.mh-page.elementor-page .orgtally span{
	font-size: var(--text-sm);   /* 14px */
}

/* ---- Contrast ----
   Both failures sat in that same metadata, measured against the bone page:
     --text-muted  #8e99a4  2.46:1   (year, project, tallies, counts)
     --gold-700    #a98a28  2.81:1   (the project name in the record table)
   Neither reaches the 4.5:1 that text this size needs. The muted grey moves
   to a blue-grey measuring 4.98:1 on bone and 4.55:1 on the sunken bone-deep
   band, still a visible step lighter than --text-secondary (5.92:1) so the
   hierarchy the design wanted survives. The gold drops two steps to
   --gold-900 (6.02:1) — same hue, dark enough to read. */
/* Gold TEXT on the paper page. --gold-700 (#a98a28) measures 2.56:1 there, so
   every one of these was failing: the decade heading on the Awards page at
   22px/600 (large-text relief starts at 24px, so it needed 4.5:1), the project
   attribution in the record table, and the big per-association tallies at
   28px/700 (2.81:1 against the 3:1 a heading needs). All three drop to
   --gold-900 (#6d5514) - the same accent, read as the same accent, at 6.02:1.
   Gold used as a rule, a fill or a border is untouched. */
.mh-page .rec__table .rec__project,
.mh-page .rec__heading,
.mh-page.elementor-page .rec .rec__heading,
.mh-page .orgtally strong,
.mh-page.elementor-page .orgtally strong,
.mh-page.elementor-page .orgfeature .orgfeature__year,
.mh-page .step__num,
.mh-page .step__num .elementor-widget-text-editor,
.mh-page .phasecard__count{
	color: var(--gold-900);
}

/* ============================================================
   Focus indicators
   ============================================================ */

/* Two things had been hiding them.

   The base rule traded the outline for a box-shadow ring, and a box-shadow is
   clipped by every `overflow:hidden` ancestor — which is most cards and every
   media frame on this site, so on a card or a gallery tile there was nothing
   left to see.

   And --focus-ring was --gold-600 (#c5a132), which measures 2.09:1 against the
   bone page. A non-text indicator needs 3:1, so even where it did draw it
   barely registered.

   The ring is now ink with a cream halo: 13.8:1 on the page, and the halo
   carries it over photography too. Outline, not box-shadow, so nothing clips
   it. Elements sitting on dark bands invert the pair. */
:root{ --focus-ring: var(--ink-900); }

.mh-page :focus-visible,
.mh-page a:focus-visible,
.mh-page button:focus-visible,
.mh-page summary:focus-visible,
.mh-page .elementor-button:focus-visible,
.mh-page input:focus-visible,
.mh-page textarea:focus-visible,
.mh-page select:focus-visible,
.mh-page [tabindex]:focus-visible{
	outline: 3px solid var(--ink-900);
	outline-offset: 2px;
	box-shadow: 0 0 0 6px rgba(244, 241, 234, .92);
	border-radius: var(--radius-sm);
}

.mh-page .section--dark :focus-visible,
.mh-page .hero :focus-visible,
.mh-page .page-head :focus-visible,
.mh-page .bleed :focus-visible,
.mh-page .drawer :focus-visible,
.mh-page .lightbox :focus-visible,
.mh-page .zoom :focus-visible,
.mh-page .mh-header :focus-visible,
.mh-page .mh-footer :focus-visible{
	outline-color: var(--cream);
	box-shadow: 0 0 0 6px rgba(19, 33, 49, .92);
}

/* The skip link paints its own ink chip, so it takes the inverse ring — and
   it is reached by :focus rather than :focus-visible. */
.mh-page .skip-link:focus,
.mh-page .skip-link:focus-visible{
	outline: 3px solid var(--cream);
	outline-offset: 2px;
	box-shadow: 0 0 0 6px rgba(19, 33, 49, .92);
}

/* A focused card must not be clipped by its own overflow. */
.mh-page .projcard:focus-visible,
.mh-page .shot:focus-visible{ outline-offset: -3px; box-shadow: none; }

/* ============================================================
   Tap targets — 44px minimum
   ============================================================ */

/* .btn was 12px of padding around a 12px cap-height line, so it rendered at
   36px; .btn--sm at 27px. Height is set as a minimum rather than by inflating
   the padding, so the horizontal rhythm of every button is untouched. */
.mh-page .btn,
.mh-page .btn--sm,
.mh-page .elementor-button,
.mh-page .elementor-widget-button.btn--sm .elementor-button,
.mh-page .filter,
.mh-page .acc__trigger,
.mh-page .nav-toggle,
.mh-page .drawer__close,
.mh-page .lightbox__close,
.mh-page .zoom__close,
.mh-page .skip-link{
	min-height: 44px;
}
.mh-page .skip-link{ display: inline-flex; align-items: center; }

/* Form controls. The 18px body size already lifts these past the iOS
   zoom-on-focus threshold; the minimum guarantees the box. */
.mh-page .field input,
.mh-page .field select,
.mh-page .field textarea,
.mh-page input[type="text"],
.mh-page input[type="email"],
.mh-page input[type="tel"],
.mh-page select{
	min-height: 44px;
}
.mh-page .field textarea{ min-height: 120px; }

/* Navigation links are inline text, so they get the height as a flex box
   rather than as padding, which would move the rules and underlines they sit
   against. */
.mh-page .mh-header .menu-link,
.mh-page .mh-nav .menu-link,
.mh-page .drawer__nav > a,
.mh-page .drawer__group > summary,
.mh-page .drawer__sub a,
.mh-page .mh-header__phone{
	display: flex;
	align-items: center;
	min-height: 44px;
}

/* ---- The footer is the exception ----
   Putting 44px under each of the fourteen footer links, on top of the row gap
   already between them, stretched the three link columns past the point where
   they read as lists at all - the footer grew by about 90px and went visibly
   loose. The footer is a dense utility block, not a place anyone is trying to
   hit a control mid-scroll, so it takes the 24px minimum from WCAG 2.5.8
   (Target Size, Minimum, AA) rather than the 44px from 2.5.5 (AAA). With the
   10px row gap that is 34px of clear space per link and the columns sit back
   at the density they had. Buttons and form controls keep the full 44px
   everywhere, footer included. */
.mh-page .mh-footer li > a,
.mh-page .mh-footer__legal a{
	display: flex;
	align-items: center;
	min-height: 24px;
}

/* And the footer keeps the old 16px/1.5. The 18px body size was raised for
   running prose; applied to four columns of links, an address and a legal
   line it only spreads them out. */
.mh-page .mh-footer{
	font-size: 1rem;
	line-height: 1.5;
}

/* The sticky section nav: the hit area grows to 44px and the active underline
   travels with the bottom of that box, so the bar's own padding comes down to
   keep its overall height where it was. */
.mh-page .subnav a{
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	padding-bottom: 0;
}
.mh-page .subnav__inner{ padding-top: var(--space-2); padding-bottom: var(--space-2); }

/* The footer link columns are plain lists inside a text widget; flex items
   would otherwise stretch full width and swallow clicks either side of the
   word. */
.mh-page .mh-footer li > a,
.mh-page .drawer__sub a{ width: fit-content; }

/* The phone and email in the contact block are standalone destinations, not
   links inside a sentence, so they take the height too. */
.mh-page .contact-row dd > a{
	display: inline-flex; align-items: center;
	min-height: 44px; width: fit-content;
}

/* Same reasoning for a note that is nothing but a link, like "Back to About"
   at the foot of the Awards page. :only-child is what separates it from a link
   sitting inside a sentence, which WCAG exempts and which would look wrong
   with 44px of leading forced around it. */
.mh-page .form-note > a:only-child{
	display: inline-flex; align-items: center;
	min-height: 44px; width: fit-content;
}

/* Checkbox and radio.
   The control itself goes to 24px, which is the size WCAG asks of a target
   that sits inside a larger clickable area, and the label it lives in becomes
   that larger area at the full 44px. A literal 44px checkbox next to 14px
   type reads as a mistake; a 44px row you can hit anywhere does not.
   !important because the opt-in checkbox carries `width:auto` inline, written
   into the Elementor widget's own markup. */
.mh-page form label:has(> input[type="checkbox"]),
.mh-page form label:has(> input[type="radio"]){
	min-height: 44px;
	align-items: center;
}
.mh-page form input[type="checkbox"],
.mh-page form input[type="radio"]{
	width: 24px !important;
	height: 24px !important;
	min-height: 24px;
	flex: none;
}

/* ============================================================
   Image loading
   ============================================================ */

/* The pop-in was two things arriving together, not a slow asset.

   Native lazy-loading starts the fetch only once the image is close to the
   viewport, and the scroll-reveal observer flipped the card visible at very
   nearly the same moment — so the card faded in around a grey box and the
   photograph landed a beat later. On a portfolio grid that is the whole first
   impression.

   Two changes. site.js now promotes lazy images to eager about a screen and a
   half out (see the img-preload block there), so the fetch is normally
   finished before the card is anywhere near the viewport. And what sits
   behind an image while it loads is no longer flat --stone-200 grey but the
   page's own bone, with a slow sheen across it — so on a genuinely slow
   connection the grid reads as paper waiting, not as broken boxes. */
.mh-page .projcard__media,
.mh-page .shot,
.mh-page .lightbox__grid .shot{
	background-color: var(--bone-deep);
	animation: mhWaiting 2.4s var(--ease-standard) infinite;
}

/* .shot sits on ink inside the lightbox, where bone would flash white. */
.mh-page .lightbox .shot{
	background-color: var(--ink-800);
	animation: mhWaitingDark 2.4s var(--ease-standard) infinite;
}

/* Once the photograph is decoded the placeholder stops, so nothing keeps
   animating behind an opaque image. */
.mh-page .projcard__media.is-loaded,
.mh-page .shot.is-loaded{
	animation: none;
}

/* The wait is a slow breath of tone rather than the usual diagonal sweep.
   A sweep would want a gradient, and Elementor's own container lazy-load
   ships `background-image: none !important` for everything inside the third
   and later top-level containers until it marks them loaded - which is
   exactly where a portfolio grid sits, so any gradient placeholder there is
   silently erased. Animating the colour alone is out of that rule's reach. */
@keyframes mhWaiting{
	0%, 100%{ background-color: var(--bone-deep); }
	50%     { background-color: var(--stone-100); }
}
@keyframes mhWaitingDark{
	0%, 100%{ background-color: var(--ink-800); }
	50%     { background-color: var(--ink-700); }
}

/* The image itself dissolves rather than snapping. The hiding class is added
   by site.js and only ever to an image that has NOT decoded yet, so an image
   already on screen when the script runs is never blinked off, and a page with
   JavaScript disabled hides nothing at all. */
.mh-page img.mh-fade{
	opacity: 0;
	transition: opacity 420ms var(--ease-out);
}
.mh-page img.mh-fade.is-loaded{ opacity: 1; }

@media (prefers-reduced-motion: reduce){
	.mh-page .projcard__media,
	.mh-page .shot{ animation: none; }
	.mh-page img.mh-fade{ opacity: 1; transition: none; }
}

/* ============================================================
   Project pages
   ============================================================ */

/* Astra's .ast-container is a flex row, so <main> sits in it as a flex item at
   `0 1 auto` and shrinks to its content instead of filling the page. The
   page-builder content layout removes the width cap but not the flex sizing. */
.mh-page .mh-project{ flex: 1 1 100%; width: 100%; min-width: 0; }

.mh-page .projhead{ position: relative; background: var(--ink-900); overflow: hidden; }
.mh-page .projhead__media{ position: absolute; inset: 0; z-index: 0; }
.mh-page .projhead__media img{ width: 100%; height: 100%; object-fit: cover; display: block; }
/* Two gradients rather than one. The vertical pass gives the title and the
   facts a floor to sit on; the horizontal pass darkens the left column only,
   which is where the text actually is, so the right two-thirds of the
   photograph stays a photograph. Lighter overall than the home hero's scrim,
   which has to carry a 70px display line and two buttons. */
.mh-page .projhead__scrim{
	position: absolute; inset: 0; z-index: 1;
	background:
		linear-gradient(to right, rgba(12, 20, 30, .72), rgba(12, 20, 30, .28) 46%, rgba(12, 20, 30, 0) 72%),
		linear-gradient(to top, rgba(12, 20, 30, .78), rgba(12, 20, 30, .12) 58%, rgba(12, 20, 30, .34));
}

/* Tall enough to read as a header rather than as a banner, capped so it never
   pushes the first paragraph off a laptop screen. */
.mh-page .projhead__inner{
	position: relative; z-index: 2;
	display: flex; flex-direction: column; justify-content: flex-end;
	min-height: min(56vh, 520px);
	padding-top: var(--space-9); padding-bottom: var(--space-8);
}
.mh-page .projhead h1{
	color: var(--cream); margin: var(--space-4) 0 var(--space-4);
	text-shadow: var(--shadow-overlay-heading);
}
/* The back link is a real tap target, not a caption, so it gets the height -
   as an inline-flex box so the eyebrow's letterspacing and rule stay put. */
.mh-page .projhead a.eyebrow--inverse{
	display: inline-flex; align-items: center;
	min-height: 44px; width: fit-content;
	text-shadow: var(--shadow-overlay-text);
}

/* The facts sit low on the photograph where the scrim is heaviest, but a
   bright sky or a white elevation can still come up underneath them, so they
   carry the same shadow the hero copy uses and the value line is cream rather
   than the muted blue-grey. */
.mh-page .projhead__facts{
	display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-6);
	margin: 0; padding: 0; list-style: none;
	color: var(--cream); font-size: var(--text-sm);
	text-shadow: var(--shadow-overlay-text);
}
.mh-page .projhead__facts strong{
	display: block; color: var(--gold-400);
	font-size: var(--text-xs); font-weight: 500;
	letter-spacing: var(--tracking-wider); text-transform: uppercase;
	margin-bottom: 2px;
	text-shadow: var(--shadow-overlay-text);
}

.mh-page .projbody{ max-width: var(--width-prose); }
.mh-page .projbody p{ font-size: var(--text-base); line-height: var(--leading-relaxed); color: var(--text-secondary); }

/* The gallery reuses .gal / .shot, so a project page and the Gallery page are
   the same object at two scales. */
.mh-page .projgal__count{
	font-size: var(--text-sm); letter-spacing: var(--tracking-wider);
	text-transform: uppercase; color: var(--text-muted);
}

/* The previous/next pair at the foot of a project page. */
.mh-page .projnav{
	display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4);
	border-top: 1px solid var(--border-subtle); padding-top: var(--space-6);
}
.mh-page .projnav a{
	display: flex; flex-direction: column; justify-content: center;
	min-height: 44px; padding: var(--space-4) 0;
	font-family: var(--font-display); font-size: var(--text-lg); color: var(--ink-900);
}
.mh-page .projnav a span{
	font-family: var(--font-body); font-size: var(--text-xs);
	letter-spacing: var(--tracking-wider); text-transform: uppercase;
	color: var(--text-muted); margin-bottom: 4px;
}
.mh-page .projnav a:hover{ color: var(--gold-900); }
.mh-page .projnav__next{ text-align: right; align-items: flex-end; }
@media (max-width: 640px){
	.mh-page .projnav{ grid-template-columns: 1fr; }
	.mh-page .projnav__next{ text-align: left; align-items: flex-start; }
}




/* ============================================================
   2026-08-26b — Testimonial carousel

   Replaces the 2×2 grid of hairline-and-serif blocks, which read as four
   paragraphs of documentation rather than as people talking.

   ONE DELIBERATE DEPARTURE from the token scale: --radius-bubble is 18px,
   where the scale stops at --radius-lg (8px). A speech bubble is legible as a
   speech bubble because of its tail and its roundness together; at 8px with a
   tail it reads as a card with a bug on the bottom edge. The radius is scoped
   to this one component and named, so it cannot leak into .card.
   ============================================================ */

.mh-page .tcarousel{
	--radius-bubble: 18px;
	--bubble-surface: var(--surface-raised);
	--bubble-border: var(--border-subtle);
	--bubble-ink: var(--text-primary);
	--bubble-quiet: var(--text-muted);
	--arrow-ink: var(--ink-900);
	--arrow-line: var(--border-strong);
	position: relative;
}

/* On the dark band the bubbles stay light — white speech on navy is the whole
   reason this section reads at a glance — but the controls have to invert. */
.mh-page .section--dark .tcarousel{
	--bubble-quiet: var(--stone-600);
	--arrow-ink: var(--cream);
	--arrow-line: rgba(255, 255, 255, .32);
}

/* ---------- Track ----------
   Scroll-snap does the carousel. The arrows only call scrollBy, so touch
   swipe, trackpad, shift-scroll and keyboard all work before a line of
   JavaScript runs, and the whole thing degrades to a scrollable row if the
   script never loads. */
.mh-page .tcarousel__track{
	display: flex;
	gap: var(--space-6);
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;
	scrollbar-width: none;
	-ms-overflow-style: none;
	/* Room for the lift on hover and for the shadow, which would otherwise be
	   clipped by the scroll container. */
	padding: var(--space-2) var(--space-1) var(--space-5);
	margin: 0;
	list-style: none;
	/* Bubbles hug their own text rather than stretching to the tallest one in
	   the row. Equal heights would line the names up, but it also leaves a
	   short quote sitting in a tall empty box - and messages of different
	   lengths being different sizes is the whole visual logic of a bubble. */
	align-items: flex-start;
}
.mh-page .tcarousel__track::-webkit-scrollbar{ display: none; }

/* The row bleeds off both edges instead of stopping at a hard crop, which is
   what tells you there is more to scroll to. Desktop only: on a phone one
   bubble fills the width and a fade would just dim its own edges. */
@media (min-width: 900px){
	.mh-page .tcarousel__track{
		-webkit-mask-image: linear-gradient(to right, transparent 0, #000 3%, #000 97%, transparent 100%);
		mask-image: linear-gradient(to right, transparent 0, #000 3%, #000 97%, transparent 100%);
	}
}

.mh-page .tcarousel__slide{
	flex: 0 0 min(52%, 640px);
	/* start, not center. With two-and-a-bit slides visible, centre-alignment
	   means the track at scrollLeft 0 has slide TWO nearest its middle - so the
	   carousel opens reporting itself as being on the second testimonial - and
	   the last slide's centre sits past the end of the scroll range, so it can
	   never become current at all. Aligning to the start makes position and
	   index the same thing. */
	scroll-snap-align: start;
	margin: 0;
	display: flex;
	flex-direction: column;
}
@media (max-width: 900px){
	.mh-page .tcarousel__slide{ flex-basis: min(84vw, 460px); }
	/* One slide per screen here, and a flex row is always as tall as its
	   tallest child - so a short testimonial left a slab of empty background
	   between its name and the arrows, sized by the longest quote in the set.
	   Stretching the bubbles means that reserved height is filled by the
	   bubble itself. The height stays constant either way, which is what stops
	   the arrows jumping around as you swipe. */
	.mh-page .tcarousel__track{ align-items: stretch; }
}

/* ---------- Bubble ---------- */
.mh-page .tbubble{
	position: relative;
	background: var(--bubble-surface);
	border: 1px solid var(--bubble-border);
	border-radius: var(--radius-bubble);
	box-shadow: var(--shadow-md);
	padding: var(--space-6) var(--space-6) var(--space-5);
	flex: 1 1 auto;
	transition:
		box-shadow var(--dur-base) var(--ease-standard),
		transform var(--dur-base) var(--ease-standard);
}

/* The tail. A rotated square inheriting the bubble's own fill and border, with
   the two inner edges hidden behind the bubble body. */
.mh-page .tbubble::after{
	content: "";
	position: absolute;
	left: var(--space-6);
	bottom: -11px;
	width: 20px;
	height: 20px;
	background: var(--bubble-surface);
	border-right: 1px solid var(--bubble-border);
	border-bottom: 1px solid var(--bubble-border);
	border-bottom-right-radius: 4px;
	transform: rotate(45deg);
}

/* Matches .card--hover, so a bubble behaves like every other raised surface
   on the site. */
.mh-page .tbubble:hover{
	box-shadow: var(--shadow-xl);
	transform: translateY(-3px);
}

/* The opening quote is set as type, not as an image or a pseudo-element the
   screen reader has to guess at: a real Gelasio glyph, gold, sitting above the
   text rather than washed behind it where it would fight the first line. */
.mh-page .tbubble__mark{
	display: block;
	font-family: var(--font-display);
	font-weight: 700;
	font-size: 38px;
	line-height: .6;
	color: var(--gold-600);
	margin-bottom: var(--space-3);
	user-select: none;
}

.mh-page .tbubble__text{
	font-family: var(--font-display);
	font-weight: 400;
	/* 20px on a phone up to 26px on a wide screen. This is the whole point of
	   the redesign: the quote is the content, so it is set at reading size. */
	font-size: clamp(1rem, 0.9rem + 0.32vw, 1.1875rem);
	line-height: 1.55;
	color: var(--bubble-ink);
	/* Astra styles bare <blockquote> as its own pull-quote — italic, 5px left
	   rule, 20px padding. All three fight this component. */
	font-style: normal;
	margin: 0;
	padding: 0;
	border: 0;
}

/* ---------- Attribution ----------
   Outside the bubble and under the tail, the way a name sits under a message
   rather than inside it. Name and community run on ONE line: stacked they cost
   another 20px of height in a band that has to fit a screen, and there is no
   avatar beside them any more to justify the two-line block.  */
.mh-page .tbubble__who{
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 0 var(--space-3);
	margin-top: var(--space-4);
	padding-left: var(--space-6);
}
.mh-page .tbubble__name{
	font-family: var(--font-body);
	font-size: var(--text-base);
	font-weight: 500;
	color: var(--bubble-ink);
	line-height: 1.3;
}
.mh-page .section--dark .tbubble__name{ color: var(--cream); }
.mh-page .tbubble__place{
	font-family: var(--font-body);
	font-size: var(--text-sm);
	letter-spacing: var(--tracking-wider);
	text-transform: uppercase;
	color: var(--bubble-quiet);
}
.mh-page .section--dark .tbubble__place{ color: var(--text-inverse-muted); }

/* ---------- Controls ---------- */
.mh-page .tcarousel__controls{
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-5);
	margin-top: var(--space-3);
}

.mh-page .tcarousel__arrow{
	flex: none;
	width: 48px;
	height: 48px;
	min-height: 48px;
	border-radius: var(--radius-pill);
	border: 1px solid var(--arrow-line);
	background: transparent;
	color: var(--arrow-ink);
	display: grid;
	place-items: center;
	cursor: pointer;
	transition:
		background var(--dur-base) var(--ease-standard),
		border-color var(--dur-base) var(--ease-standard),
		color var(--dur-base) var(--ease-standard),
		opacity var(--dur-base) var(--ease-standard);
}
.mh-page .tcarousel__arrow svg{ width: 20px; height: 20px; }
.mh-page .tcarousel__arrow:hover:not(:disabled){
	background: var(--gold-600);
	border-color: var(--gold-600);
	color: var(--ink-900);
}
.mh-page .tcarousel__arrow:disabled{
	opacity: .3;
	cursor: default;
}

/* The dot is 8px of paint inside a 44px target. */
.mh-page .tcarousel__dots{ display: flex; align-items: center; gap: var(--space-1); }
.mh-page .tcarousel__dot{
	appearance: none;
	border: 0;
	background: none;
	padding: 0 6px;
	width: 32px;
	height: 44px;
	min-height: 44px;
	display: grid;
	place-items: center;
	cursor: pointer;
	/* Astra gives every <button> a 4px radius and a soft drop shadow, which on
	   a transparent 32px hit area draws a faint rounded rectangle around each
	   dot - four little ghost boxes under the carousel. */
	border-radius: 0;
	box-shadow: none;
}
.mh-page .tcarousel__dot::before{
	content: "";
	display: block;
	width: 8px;
	height: 8px;
	border-radius: var(--radius-pill);
	background: var(--arrow-line);
	transition:
		width var(--dur-base) var(--ease-out),
		background var(--dur-base) var(--ease-standard);
}
.mh-page .tcarousel__dot[aria-current="true"]::before{
	width: 26px;
	background: var(--gold-600);
}

/* ---------- Heading ---------- */
.mh-page .testimonials-head{
	max-width: 720px;
	margin: 0 auto clamp(1rem, 2.4vh, 1.5rem);
	text-align: center;
}
.mh-page .testimonials-head .rule-gold{ margin-left: auto; margin-right: auto; }
.mh-page .testimonials-head .section-heading__title{ margin-top: var(--space-4); }

@media (prefers-reduced-motion: reduce){
	.mh-page .tcarousel__track{ scroll-behavior: auto; }
	.mh-page .tbubble,
	.mh-page .tcarousel__dot::before{ transition: none; }
	.mh-page .tbubble:hover{ transform: none; }
}


/* ============================================================
   2026-08-26c — Header navigation in the body sans
   ============================================================ */

/* The header menu was rendering in Gelasio at 500/16px, because the Xpro
   navbar widget takes its face from Elementor's global "Primary" typography,
   which the kit points at Gelasio. That is a display serif doing a UI job:
   at 16px, mixed case, it is the one place on the site where the serif reads
   as decoration rather than as voice.

   Moved to the body sans, and to the nav idiom the design system already
   describes for .mh-nav a - 14px, uppercase, wide tracking, secondary ink -
   so the header now matches the eyebrows, buttons and section labels it sits
   above. The selectors are heavier than they look because Xpro's own rule is
   .xpro-elementor-horizontal-navbar .xpro-elementor-dropdown-menu .menu-link,
   which a two-class selector loses to. */
.mh-page .mh-header .xpro-elementor-horizontal-navbar .menu-link,
.mh-page .mh-nav .xpro-elementor-horizontal-navbar .menu-link,
.mh-page .mh-header .menu-link,
.mh-page .mh-nav .menu-link{
	font-family: var(--font-body);
	font-size: var(--text-sm);
	font-weight: 500;
	letter-spacing: var(--tracking-wider);
	text-transform: uppercase;
}

/* The dropdown panels are a reading list rather than a nav bar, so they keep
   sentence case and drop the tracking - same as .navitem__panel a. */
.mh-page .mh-header .xpro-elementor-horizontal-navbar .sub-menu .menu-link,
.mh-page .mh-nav .xpro-elementor-horizontal-navbar .sub-menu .menu-link,
.mh-page .mh-header .sub-menu .menu-link{
	font-family: var(--font-body);
	font-size: var(--text-sm);
	font-weight: 400;
	letter-spacing: var(--tracking-wide);
	text-transform: none;
}

/* The mobile drawer is the same navigation and has to agree with it. */
.mh-page .drawer__nav > a,
.mh-page .drawer__group > summary{
	font-family: var(--font-body);
	font-weight: 500;
	letter-spacing: var(--tracking-wider);
	text-transform: uppercase;
}
.mh-page .drawer__sub a{
	font-family: var(--font-body);
	font-weight: 400;
	letter-spacing: var(--tracking-wide);
	text-transform: none;
}


/* ---------- Fitting one screen ----------
   The band has to hold its heading, a bubble and the controls without the
   visitor scrolling, and the tallest testimonial runs to nine lines. Rather
   than shrink the type everywhere for the sake of short laptops, the whole
   component steps down once the viewport itself is short. The band's own
   padding is on the section so it can shrink with it. */
.mh-page .testimonials-band{
	padding-top: clamp(1.75rem, 4vh, 3rem);
	padding-bottom: clamp(1.75rem, 4vh, 3rem);
}

@media (max-height: 820px){
	.mh-page .tbubble__text{ font-size: clamp(0.9375rem, 0.85rem + 0.3vw, 1.0625rem); }
	.mh-page .tbubble{ padding: var(--space-5) var(--space-5) var(--space-4); }
	.mh-page .tbubble::after{ left: var(--space-5); }
	.mh-page .tbubble__mark{ font-size: 30px; margin-bottom: var(--space-2); }
	.mh-page .tbubble__who{ padding-left: var(--space-5); margin-top: var(--space-3); }
	.mh-page .tcarousel__track{ padding-bottom: var(--space-4); }
}


/* ============================================================
   2026-08-26e — Project pages: hero lede, metric band, dark foot

   The page used to open with a photograph, a stack of four small facts
   overlaid on it, and then a full screen of prose. It now opens with the
   headline and one sentence, and the facts move off the photograph into
   their own band underneath, where they can be read rather than squinted at.

   Both navigation controls — "All Projects" in the hero and the previous /
   next pair at the foot — were text that happened to be clickable. They are
   plates now, and they move on hover, so the affordance does not depend on
   the visitor guessing.
   ============================================================ */

/* ---- Hero ---- */

/* The back control is a real button sitting in a flex column, so it has to
   opt out of the column's stretch or it spans the container. */
.mh-page .projhead__back{
	align-self: flex-start;
	margin-bottom: var(--space-5);
	text-shadow: none;
	transition: background var(--dur-base) var(--ease-standard),
	            color var(--dur-base) var(--ease-standard),
	            transform var(--dur-base) var(--ease-out),
	            box-shadow var(--dur-base) var(--ease-out);
}
.mh-page .projhead__back:hover,
.mh-page .projhead__back:focus-visible{
	transform: translateY(-2px);
	box-shadow: 0 10px 24px rgba(12, 20, 30, .38);
}
.mh-page .projhead__back-arrow{
	transition: transform var(--dur-base) var(--ease-out);
}
.mh-page .projhead__back:hover .projhead__back-arrow,
.mh-page .projhead__back:focus-visible .projhead__back-arrow{
	transform: translateX(-3px);
}

.mh-page .projhead h1{ margin: 0 0 var(--space-3); }

/* One sentence, held to a readable measure so it never runs the full width of
   a 1440 hero. Cream on the scrim, with the same shadow the H1 carries. */
.mh-page .projhead__lede{
	max-width: 58ch;
	margin: 0;
	color: var(--cream);
	font-size: var(--text-md);
	line-height: var(--leading-relaxed);
	text-shadow: var(--shadow-overlay-text);
}

/* ---- Metric band ---- */

/* Four facts, each under its own gold rule. The rule is what makes the row
   read as a specification rather than as four stray words. */
.mh-page .projmetrics{
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--space-6) var(--space-5);
	margin: 0;
	padding: 0;
}
.mh-page .projmetric{
	border-top: 2px solid var(--gold-600);
	padding-top: var(--space-4);
	min-width: 0;
}
.mh-page .projmetric dt{
	margin: 0 0 6px;
	font-family: var(--font-body);
	font-size: var(--text-xs);
	font-weight: 500;
	letter-spacing: var(--tracking-wider);
	text-transform: uppercase;
	color: var(--text-muted);
}
.mh-page .projmetric dd{
	margin: 0;
	font-family: var(--font-display);
	font-size: var(--text-xl);
	line-height: var(--leading-snug);
	color: var(--ink-900);
}
@media (max-width: 900px){
	.mh-page .projmetrics{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 420px){
	.mh-page .projmetrics{ grid-template-columns: 1fr; }
}

/* ---- Dark foot: previous / next ---- */

.mh-page .projfoot .projnav{
	border-top-color: rgba(255, 255, 255, .16);
	gap: var(--space-5);
}
.mh-page .projfoot .projnav a{
	padding: var(--space-4) var(--space-5);
	border: 1px solid rgba(255, 255, 255, .22);
	border-radius: var(--radius-sm);
	background: rgba(255, 255, 255, .05);
	color: var(--cream);
	transition: background var(--dur-base) var(--ease-standard),
	            border-color var(--dur-base) var(--ease-standard),
	            transform var(--dur-base) var(--ease-out),
	            box-shadow var(--dur-base) var(--ease-out);
}
.mh-page .projfoot .projnav a span{
	display: flex;
	align-items: center;
	gap: 8px;
	margin-bottom: 6px;
	color: var(--gold-400);
}
.mh-page .projfoot .projnav__next span{ justify-content: flex-end; }
.mh-page .projfoot .projnav a strong{
	font-family: var(--font-display);
	font-weight: 400;
	font-size: var(--text-lg);
	color: var(--cream);
}
.mh-page .projfoot .projnav__arrow{
	width: 16px; height: 16px; flex: none;
	transition: transform var(--dur-base) var(--ease-out);
}
/* Beats the flat `.mh-page .projnav a:hover{color:var(--gold-900)}` above,
   which would paint deep gold text onto the dark band. */
.mh-page .projfoot .projnav a:hover,
.mh-page .projfoot .projnav a:focus-visible{
	background: rgba(255, 255, 255, .10);
	border-color: var(--gold-500);
	color: var(--cream);
	transform: translateY(-2px);
	box-shadow: 0 12px 26px rgba(0, 0, 0, .32);
}
.mh-page .projfoot .projnav__prev:hover .projnav__arrow,
.mh-page .projfoot .projnav__prev:focus-visible .projnav__arrow{ transform: translateX(-4px); }
.mh-page .projfoot .projnav__next:hover .projnav__arrow,
.mh-page .projfoot .projnav__next:focus-visible .projnav__arrow{ transform: translateX(4px); }

@media (prefers-reduced-motion: reduce){
	.mh-page .projhead__back,
	.mh-page .projhead__back-arrow,
	.mh-page .projfoot .projnav a,
	.mh-page .projfoot .projnav__arrow{ transition: none; }
	.mh-page .projhead__back:hover,
	.mh-page .projhead__back:focus-visible,
	.mh-page .projfoot .projnav a:hover,
	.mh-page .projfoot .projnav a:focus-visible{ transform: none; }
	.mh-page .projhead__back:hover .projhead__back-arrow,
	.mh-page .projfoot .projnav__prev:hover .projnav__arrow,
	.mh-page .projfoot .projnav__next:hover .projnav__arrow{ transform: none; }
}
