/* ==========================================================================
   Beck & Co Design — design system
   Mobile-first. Two breakpoints. No framework, no build step.
   ========================================================================== */

/* --- Fonts: self-hosted variable woff2, latin subset (63KB total) --------- */
@font-face {
  font-family: 'Cormorant Garamond';
  src: url('/assets/fonts/cormorant-garamond-var.woff2') format('woff2-variations'),
       url('/assets/fonts/cormorant-garamond-var.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  /* Metric-matched to Georgia so the pre-swap render does not shift. */
  size-adjust: 106%;
  ascent-override: 92%;
  descent-override: 26%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Jost';
  src: url('/assets/fonts/jost-var.woff2') format('woff2-variations'),
       url('/assets/fonts/jost-var.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  size-adjust: 104%;
  ascent-override: 96%;
  descent-override: 24%;
  line-gap-override: 0%;
}

/* --- Tokens --------------------------------------------------------------- */
:root {
  --font-display: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  --font-body: 'Jost', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;

  /* Warm neutral ground. Photography carries the colour; the page does not. */
  --bone: #F7F4EF;
  --paper: #FFFFFF;
  --ink: #24211D;
  --ink-soft: #6E665C;
  --ink-faint: #A79D91;
  --line: #E2DBD0;
  --line-soft: #EFE9E1;
  --clay: #9A7B5C;          /* decorative only: rules, borders, numerals */
  --clay-text: #886A4C;      /* clay-coloured TEXT below 24px — meets 4.5:1 on bone */
  --clay-deep: #6E5843;
  --flag: #A2432F;          /* placeholders needing a real fact */

  /* Fluid type, 375px → 1440px. The rem term in the middle is deliberate:
     a pure-vw middle term breaks browser zoom. */
  --t-display: clamp(2rem,      1.032rem + 4.131vw, 4.75rem);
  --t-h1:      clamp(1.75rem,   1.222rem + 2.254vw, 3.25rem);
  --t-h2:      clamp(1.5rem,    1.192rem + 1.315vw, 2.375rem);
  --t-h3:      clamp(1.25rem,   1.096rem + 0.657vw, 1.6875rem);
  --t-h4:      clamp(1.0625rem, 0.996rem + 0.282vw, 1.25rem);
  --t-lead:    clamp(1.1875rem, 1.099rem + 0.376vw, 1.4375rem);
  --t-body:    clamp(1.0625rem, 1.018rem + 0.188vw, 1.1875rem);
  --t-small:   clamp(0.875rem,  0.853rem + 0.094vw, 0.9375rem);
  --t-micro:   clamp(0.75rem,   0.727rem + 0.094vw, 0.8125rem);

  --lh-display: 1.02;
  --lh-heading: 1.12;
  --lh-lead: 1.45;
  --lh-body: 1.62;

  /* Fluid space */
  --s-2: clamp(0.25rem, 0.24rem + 0.05vw, 0.3125rem);
  --s-1: clamp(0.5rem,  0.478rem + 0.094vw, 0.625rem);
  --s0:  clamp(0.75rem, 0.706rem + 0.188vw, 0.9375rem);
  --s1:  clamp(1rem,    0.941rem + 0.25vw,  1.25rem);
  --s2:  clamp(1.5rem,  1.412rem + 0.376vw, 1.875rem);
  --s3:  clamp(2rem,    1.765rem + 1vw,     2.75rem);
  --s4:  clamp(2.75rem, 2.279rem + 2.01vw,  4.25rem);
  --s5:  clamp(3.5rem,  2.559rem + 4.01vw,  6.5rem);
  --s6:  clamp(4.5rem,  2.853rem + 7.02vw,  9.75rem);

  --gutter: clamp(1.25rem, 0.897rem + 1.5vw, 2.75rem);
  --measure: 62ch;
  --max: 82.5rem;          /* 1320px */

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  color-scheme: light;
}

/* --- Reset ---------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-padding-top: 5.5rem; }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
body {
  margin: 0;
  background: var(--bone);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--t-body);
  font-weight: 300;
  line-height: var(--lh-body);
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img, picture, video, svg { display: block; max-width: 100%; }
img { height: auto; }
/* Placeholder tint while a photograph loads — scoped to photos, never to the
   brand mark, which is a transparent PNG and would get a grey box behind it. */
.media img, picture img { background: var(--line-soft); }
button, input, select, textarea { font: inherit; color: inherit; }
h1, h2, h3, h4, p, figure, blockquote, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--clay); outline-offset: 3px; border-radius: 2px; }
::selection { background: var(--clay); color: var(--bone); }

/* --- Type ----------------------------------------------------------------- */
/* Cormorant has display-grade stroke contrast: its hairlines vanish below
   ~22px on a phone. It is permitted only at h2 and above until 48rem, where
   h3 finally crosses the threshold. Weight 300 is never used anywhere. */
.t-display, h1 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--t-display);
  line-height: var(--lh-display);
  letter-spacing: -0.015em;
  text-wrap: balance;
}
h1 { font-size: var(--t-h1); }
h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--t-h2);
  line-height: var(--lh-heading);
  letter-spacing: -0.01em;
  text-wrap: balance;
}
h3 {
  font-family: var(--font-body);   /* Jost on phone — Cormorant too fragile at 20px */
  font-weight: 400;
  font-size: var(--t-h3);
  line-height: var(--lh-heading);
}
@media (min-width: 48rem) {
  h3 { font-family: var(--font-display); font-weight: 500; }
}
h4 {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--t-h4);
  line-height: var(--lh-heading);
}
p { text-wrap: pretty; }
.lead { font-size: var(--t-lead); line-height: var(--lh-lead); color: var(--ink-soft); }
.small { font-size: var(--t-small); }
.muted { color: var(--ink-soft); }
.measure { max-width: var(--measure); }

/* A heading that sits directly in a layout container owns the space beneath it.
   The reset zeroes all heading margins and only .head restored them, so 32 bare
   headings across the site had their following content butted right up against
   them — on the homepage the steps grid's top border read as an underline. */
.wrap > h2, .wrap > h3,
.prose > h2, .prose > h3 { margin-bottom: var(--s2); }
.wrap > .t-display { margin-bottom: var(--s1); }
/* Inside these, the container manages spacing — do not double it. */
.stack > h2, .stack > h3,
.head h2, .head h3,
.card__body h3, .steps h3, .quote h3 { margin-bottom: 0; }
.vh { margin-bottom: 0 !important; }

.eyebrow {
  font-size: var(--t-micro);
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--clay-text);
}
.flag { color: var(--flag); font-size: 0.85em; letter-spacing: 0.04em; }

/* --- Layout --------------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap--wide { max-width: 96rem; }
.wrap--narrow { max-width: 46rem; }
.section { padding-block: var(--s5); }
.section--tight { padding-block: var(--s4); }
.section--flush { padding-block: 0; }
.rule { border-top: 1px solid var(--line); }
/* Flex, not margin: margin-top is ignored on inline children, which silently
   collapsed every footer link list onto a single line. */
.stack { display: flex; flex-direction: column; align-items: flex-start; gap: var(--flow, var(--s1)); }
.stack > * + * { margin-top: 0; }
.stack-lg { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s2); }

.grid { display: grid; gap: var(--s2); }
/* Order matters: equal specificity, so the wider breakpoint must come last. */
@media (min-width: 48rem) { .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 48rem) { .grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 62rem) { .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* --- Buttons -------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s0);
  min-height: 3rem;                 /* 48px touch target */
  padding: var(--s1) var(--s3);
  font-size: var(--t-small);
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--bone);
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: color .45s var(--ease), border-color .45s var(--ease);
}
/* Fill-wipe on hover — pointer devices only, never on touch. */
.btn::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--bone);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .45s var(--ease);
  z-index: 0;
}
.btn > * { position: relative; z-index: 1; }
@media (hover: hover) and (pointer: fine) {
  .btn:hover { color: var(--ink); }
  .btn:hover::after { transform: scaleX(1); transform-origin: left; }
}
.btn--ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.btn--ghost::after { background: var(--ink); }
@media (hover: hover) and (pointer: fine) {
  .btn--ghost:hover { color: var(--bone); border-color: var(--ink); }
}
.btn--light { background: var(--bone); color: var(--ink); border-color: var(--bone); }
.btn--light::after { background: transparent; }
.btn--block { display: flex; width: 100%; }

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  min-height: 2.75rem;
  font-size: var(--t-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--clay-text);
}
.link-arrow svg { transition: transform .4s var(--ease); }
@media (hover: hover) { .link-arrow:hover svg { transform: translateX(0.35em); } }

/* --- Header / nav --------------------------------------------------------- */
.hdr {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bone) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
.hdr[data-scrolled='true'] { border-bottom-color: var(--line); }
.hdr__in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s1);
  min-height: 4.25rem;
}
.wordmark {
  font-family: var(--font-display);
  font-weight: 500;
  /* Steep slope with a low floor: the lockup must clear the hamburger on a
     320px phone (where it was being clipped) but reach full size by ~670px. */
  font-size: clamp(1.125rem, 0.553rem + 2.86vw, 1.75rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding-block: var(--s-2);
}
/* Name over tagline. The tagline is body-font mixed case on purpose: set in
   letterspaced caps it runs wider than the name and overflows a 320px phone. */
.wordmark__txt { display: flex; flex-direction: column; gap: 0.08em; min-width: 0; }
.wordmark__name { white-space: nowrap; line-height: 1.12; }
.wordmark__tag {
  font-family: var(--font-body);
  /* em, not rem: the tagline has to scale with the NAME so the two lines keep
     the same width ratio at every viewport. A rem clamp drifts out of step. */
  font-size: 0.5em;
  font-weight: 400;
  /* Tracked so the line renders the same width as the name above it. NOT
     justified: justification needs break opportunities, which means the line
     can wrap — and a wrapped justified tagline breaks into three ragged rows.
     nowrap makes it behave exactly like the name. The negative margin cancels
     the trailing letter-space so the visible ink, not the box, matches. */
  letter-spacing: 0.2166em;
  margin-right: -0.2166em;
  white-space: nowrap;
  text-transform: none;
  color: var(--clay-text);
  line-height: 1.3;
}
.nav { display: none; }
/* Phone sits on its own line above the nav. In one row with five nav links and
   the CTA it was the first thing to wrap, breaking across three lines. */
.hdr__right { display: none; }
/* Phone stacked above the Inquire button, same width, always. Keeping it out
   of the horizontal run is also what stops the brand colliding with the nav:
   inline it cost ~140px and the lockup had nowhere left to go. */
.hdr__contact { display: flex; flex-direction: column; align-items: stretch; gap: 0.3rem; }
.tel { position: relative; }
.tel__btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45em;
  padding: 0.15rem 0.2rem;
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--ink);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  list-style: none;
}
.tel__btn::-webkit-details-marker { display: none; }
@media (hover: hover) { .tel__btn:hover { color: var(--clay-text); } }
.hdr__tel-i { flex: none; opacity: 0.8; }
/* Call / text chooser. tel: is useless on a desktop without a softphone and
   sms: is the one most people actually want, so ask rather than guess. */
.tel__menu {
  position: absolute;
  top: calc(100% + 0.35rem);
  right: 0;
  z-index: 60;
  min-width: 100%;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line);
  box-shadow: 0 10px 30px -12px rgba(36, 33, 29, 0.28);
}
.tel__menu a {
  padding: 0.6rem 1rem;
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  white-space: nowrap;
  text-align: right;
}
.tel__menu a + a { border-top: 1px solid var(--line-soft); }
@media (hover: hover) { .tel__menu a:hover { background: var(--bone); color: var(--ink); } }
@media (hover: hover) { .hdr__tel:hover { color: var(--ink); } }
/* Declared BEFORE the 62rem block so the media query can override them. */
.hdr__cta { display: none; min-height: 2.6rem; padding: var(--s-1) var(--s2); }
.navtoggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem; height: 3rem;
  margin-right: calc(var(--s0) * -1);
  background: none; border: 0; cursor: pointer;
}
.navtoggle span { display: block; width: 22px; height: 1px; background: var(--ink); position: relative; }
.navtoggle span::before, .navtoggle span::after {
  content: ''; position: absolute; left: 0; width: 22px; height: 1px; background: var(--ink);
  transition: transform .35s var(--ease);
}
.navtoggle span::before { top: -7px; }
.navtoggle span::after { top: 7px; }

@media (min-width: 66rem) {
  /* flex: none on the right cluster + nowrap on each link. Without both, flex
     shrinks the nav and "Interior Design" breaks across two lines. */
  .hdr__right { display: block; flex: none; }
  .hdr__row { display: flex; align-items: center; gap: var(--s2); }
  .nav { display: flex; align-items: center; gap: var(--s2); flex: none; }
  .nav a { white-space: nowrap; }
  .nav a {
    font-size: var(--t-micro);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-soft);
    padding-block: var(--s0);
    position: relative;
  }
  .nav a::after {
    content: '';
    position: absolute;
    left: 0; right: 0; bottom: 0.55rem;
    height: 1px;
    background: var(--clay);
    transform: scaleX(0);
    transform-origin: right;
    transition: transform .4s var(--ease);
  }
  .nav a:hover, .nav a[aria-current='page'] { color: var(--ink); }
  .nav a:hover::after, .nav a[aria-current='page']::after { transform: scaleX(1); transform-origin: left; }
  .hdr__cta { display: inline-flex; }
  .navtoggle { display: none; }
}

@media (min-width: 75rem) {
  .hdr__row, .nav { gap: var(--s3); }
}

/* Full-screen menu as a native dialog — focus trap and Escape come free. */
.menu {
  width: 100%; max-width: none; height: 100%; max-height: none;
  margin: 0; padding: 0; border: 0;
  background: var(--bone); color: var(--ink);
}
.menu::backdrop { background: rgba(36, 33, 29, 0.4); }
.menu__in { display: flex; flex-direction: column; min-height: 100%; padding: var(--gutter); }
.menu__top { display: flex; align-items: center; justify-content: space-between; min-height: 4rem; }
.menu__close { width: 3rem; height: 3rem; background: none; border: 0; cursor: pointer; font-size: 1.75rem; line-height: 1; }
.menu__list { margin-top: var(--s4); display: flex; flex-direction: column; }
.menu__list a {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2rem, 1.5rem + 2.4vw, 3rem);
  line-height: 1.25;
  padding-block: var(--s1);
  border-bottom: 1px solid var(--line-soft);
}
.menu__foot { margin-top: auto; padding-top: var(--s3); display: grid; gap: var(--s1); }

/* --- Media ---------------------------------------------------------------- */
.media { position: relative; overflow: hidden; background: var(--line-soft); }
.media > picture { display: block; width: 100%; height: 100%; }
.media img { width: 100%; height: 100%; object-fit: cover; }
.media--portrait { aspect-ratio: 4 / 5; }
.media--square   { aspect-ratio: 1 / 1; }
.media--land     { aspect-ratio: 3 / 2; }
.media--tall     { aspect-ratio: 3 / 4; }
@media (min-width: 48rem) { .media--hero { aspect-ratio: auto; height: 100%; } }

/* Slow zoom on hover, pointer devices only. */
@media (hover: hover) and (pointer: fine) {
  .media--zoom img { transition: transform 1.1s var(--ease-out); }
  a:hover .media--zoom img,
  .media--zoom:hover img { transform: scale(1.045); }
}

figure { margin: 0; }
/* The caption parts are spans, so they must be told to stack — an inline
   element ignores margin-top and the title and location run together. */
figcaption { margin-top: var(--s1); display: flex; flex-direction: column; gap: 0.3rem; }
.cap__title { display: block; font-family: var(--font-display); font-weight: 500; font-size: var(--t-h4); line-height: 1.25; }
@media (max-width: 47.99rem) { .cap__title { font-family: var(--font-body); font-weight: 500; } }
.cap__meta { display: block; font-size: var(--t-micro); letter-spacing: 0.1em; text-transform: uppercase; color: var(--clay-text); line-height: 1.4; }

/* --- Cards ---------------------------------------------------------------- */
.card {
  background: var(--paper);
  border: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  height: 100%;
}
.card__body { padding: var(--s2); display: flex; flex-direction: column; gap: var(--s0); flex: 1; }
@media (min-width: 48rem) { .card__body { padding: var(--s3) var(--s2) var(--s3); } }

/* --- Attachments ---------------------------------------------------------- */
/* The file row is a button in every browser's own dialect, so style the control
   itself rather than hiding it behind a label — a custom trigger loses the
   camera / photo-library sheet that iOS offers here, which is the whole point. */
.input--file { padding: 0.7rem 0.8rem; line-height: 1.4; cursor: pointer; }
.input--file::file-selector-button {
  font: inherit;
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bone);
  background: var(--ink);
  border: 0;
  padding: 0.55rem 0.9rem;
  margin-inline-end: 0.75rem;
  cursor: pointer;
}
@media (hover: hover) { .input--file::file-selector-button:hover { background: var(--clay-text); } }

.filelist { list-style: none; margin: var(--s1) 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.filelist__item {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--s0);
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--line);
  background: var(--paper);
  overflow: hidden;
}
.filelist__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--t-small); }
.filelist__meta { font-size: var(--t-micro); color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.filelist__x {
  appearance: none; border: 0; background: none; cursor: pointer;
  font-size: 1.15rem; line-height: 1; color: var(--ink-soft);
  width: 2rem; height: 2rem; display: grid; place-items: center;
}
@media (hover: hover) { .filelist__x:hover { color: var(--ink); } }
/* Progress paints as a hairline under the row — no extra element, no reflow. */
.filelist__bar { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--line-soft); }
.filelist__bar::before { content: ''; display: block; height: 100%; width: var(--p, 0%); background: var(--ink); transition: width 0.2s linear; }

/* Shared call/text popover for every phone link outside the header. */
.telpop {
  position: fixed;
  z-index: 70;
  display: flex;
  flex-direction: column;
  min-width: 11rem;
  background: var(--paper);
  border: 1px solid var(--line);
  box-shadow: 0 12px 34px -14px rgba(36, 33, 29, 0.32);
}
.telpop__a {
  padding: 0.85rem 1.1rem;
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: center;
  min-height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
}
.telpop__a + .telpop__a { border-top: 1px solid var(--line-soft); }
@media (hover: hover) { .telpop__a:hover { background: var(--bone); color: var(--ink); } }

/* --- Dark band ------------------------------------------------------------ */
.band { background: var(--ink); color: var(--bone); }
.band .lead, .band .muted { color: #C7BFB4; }
.band .eyebrow { color: var(--clay); }

/* --- Forms ---------------------------------------------------------------- */
.fieldset { border: 0; padding: 0; margin: 0; min-inline-size: 0; align-self: stretch; }
/* align-self is load-bearing: the fieldset is a .stack, which sets
   align-items: flex-start, so without this each field shrink-wraps its own
   LABEL. That made "Email" a 192px box next to a 629px location field. */
.field { display: flex; flex-direction: column; gap: var(--s-1); align-self: stretch; }
.field > label { font-size: var(--t-micro); letter-spacing: 0.14em; text-transform: uppercase; }
.field .hint { font-size: var(--t-micro); color: var(--ink-soft); text-transform: none; letter-spacing: 0; }
.input, .select, .textarea {
  width: 100%;
  min-height: 3rem;
  padding: var(--s0) var(--s1);
  font-size: 1.0625rem;             /* >=16px or iOS zooms on focus and never zooms back */
  font-weight: 300;
  background: var(--paper);
  border: 1px solid #C9BEB0;
  border-radius: 0;
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease);
  -webkit-appearance: none;
  appearance: none;
}
.textarea { min-height: 8rem; resize: vertical; }
.select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23A79D91' stroke-width='1.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--s1) center;
  padding-right: var(--s3);
}
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--clay);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--clay) 18%, transparent);
}
.input[aria-invalid='true'], .textarea[aria-invalid='true'] { border-color: var(--flag); }
.err { color: var(--flag); font-size: var(--t-small); }

/* Radio / checkbox as pill choices — big touch targets, no tiny dots. */
.choices { display: flex; flex-wrap: wrap; gap: var(--s-1); }
.choice { position: relative; }
.choice input { position: absolute; opacity: 0; inset: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.choice span {
  display: flex;
  align-items: center;
  min-height: 2.875rem;
  padding: var(--s0) var(--s1);
  font-size: var(--t-small);
  font-weight: 300;
  border: 1px solid var(--line);
  background: var(--paper);
  transition: border-color .2s var(--ease), background .2s var(--ease), color .2s var(--ease);
}
.choice input:checked + span { background: var(--ink); border-color: var(--ink); color: var(--bone); }
.choice input:focus-visible + span { outline: 2px solid var(--clay); outline-offset: 2px; }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* --- Footer --------------------------------------------------------------- */
.foot { border-top: 1px solid var(--line); padding-block: var(--s4) var(--s3); }
.foot a { color: var(--ink-soft); }
@media (hover: hover) { .foot a:hover { color: var(--ink); } }

/* --- Scroll reveal -------------------------------------------------------- */
/* Only applied once JS marks the document; no JS means everything is visible. */
[data-reveal] { will-change: opacity, transform; }
.reveal-on [data-reveal] {
  opacity: 0.001;
  transform: translateY(1.25rem);
  transition: opacity .9s var(--ease-out), transform .9s var(--ease-out);
  transition-delay: var(--d, 0ms);
}
.reveal-on [data-reveal].is-in { opacity: 1; transform: none; }

/* Images are ALWAYS visible. The only entrance they get is a gentle fade of
   the frame, which cannot strand a photograph: even if the class never
   arrives, opacity is inherited from the base rule below, not from 0. */
.reveal-on [data-reveal='wipe'] { opacity: 1; transform: none; }
.reveal-on [data-reveal='wipe'] img { clip-path: none; }

/* Per-line masked reveal for display headings. */
.reveal-on .lines .line { display: block; overflow: hidden; }
.reveal-on .lines .line > span {
  display: block;
  transform: translateY(105%);
  transition: transform 1s var(--ease-out);
  transition-delay: var(--d, 0ms);
}
.reveal-on .lines.is-in .line > span { transform: none; }

@media (prefers-reduced-motion: reduce) {
  /* Movement, scale and parallax go. Opacity stays at 150ms — fades are not what
     causes vestibular symptoms, and a blanket 0.01ms kill breaks transitionend
     listeners including the dialog's allow-discrete exit. */
  .reveal-on [data-reveal],
  .reveal-on [data-reveal].is-in { opacity: 1 !important; transform: none !important; transition: opacity 150ms linear !important; }
  .reveal-on [data-reveal='wipe'] img { clip-path: none !important; transform: none !important; transition: none !important; }
  .reveal-on .lines .line > span { transform: none !important; transition: none !important; }
  .media--zoom img { transition: none !important; }
  .btn::after { transition: none !important; }
  html { scroll-behavior: auto; }
}

/* --- Lightbox ------------------------------------------------------------- */
.lb { width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0; padding: 0; border: 0; background: rgba(24, 22, 19, .96); }
.lb::backdrop { background: rgba(24, 22, 19, .96); }
.lb__fig { display: grid; place-items: center; height: 100%; padding: var(--gutter); grid-template-rows: 1fr auto; gap: var(--s1); }
.lb__fig img { max-width: 100%; max-height: 78dvh; width: auto; object-fit: contain; background: none; }
.lb__cap { color: #C7BFB4; text-align: center; font-size: var(--t-small); }
.lb__cap b { display: block; font-family: var(--font-body); font-weight: 500; font-size: var(--t-h4); color: var(--bone); }
@media (min-width: 48rem) { .lb__cap b { font-family: var(--font-display); } }
.lb__x, .lb__nav {
  position: absolute; top: var(--s1); right: var(--s1);
  width: 3rem; height: 3rem; display: grid; place-items: center;
  background: none; border: 1px solid rgba(247,244,239,.28); color: var(--bone); cursor: pointer;
}
.lb__nav { top: 50%; transform: translateY(-50%); }
.lb__nav--prev { left: var(--s1); right: auto; }
.lb__nav--next { right: var(--s1); }
@media (max-width: 47.99rem) { .lb__nav { display: none; } }  /* swipe instead */

/* --- Utilities ------------------------------------------------------------ */
.vh {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
.skip {
  position: absolute; left: var(--s1); top: -4rem; z-index: 100;
  background: var(--ink); color: var(--bone); padding: var(--s0) var(--s1);
  transition: top .2s var(--ease);
}
.skip:focus { top: var(--s1); }

/* ==========================================================================
   Page-level layout
   ========================================================================== */

/* Header hides on scroll-down past 400px, returns on scroll-up. This replaces
   a sticky CTA bar: same reach, none of the brand cost. */
.hdr { transform: translateY(0); transition: transform .35s var(--ease), border-color .3s var(--ease); }
.hdr[data-hide='true'] { transform: translateY(-100%); }
@media (prefers-reduced-motion: reduce) { .hdr { transition: border-color .3s linear; } .hdr[data-hide='true'] { transform: none; } }
/* Landscape phones and 400% zoom: a sticky header eats the viewport. */
@media (max-height: 30rem) { .hdr { position: static; } }

/* --- Hero ----------------------------------------------------------------- */
/* Full-bleed on phone, where the portrait library actually works. Contained
   from 48rem up — these files cap at 1600px and stretching them upscales. */
.hero__in { display: grid; gap: var(--s2); padding-top: var(--s1); padding-bottom: var(--s4); }
/* On a phone the photograph comes FIRST visually — this is a design studio and
   a screen of prose before any image is the wrong first impression. The DOM
   order is unchanged (h1 and the answer paragraph still lead), so search and
   AI retrieval still read the text first; only the paint order moves. */
.hero__fig { order: -1; margin-inline: calc(var(--gutter) * -1); aspect-ratio: 1 / 1; }
@media (min-width: 30rem) and (max-width: 47.99rem) { .hero__fig { aspect-ratio: 4 / 3; } }
.hero__copy { --flow: var(--s1); }
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--s0); padding-top: var(--s0); }
.hero__cta .btn { flex: 1 1 14rem; }
@media (min-width: 48rem) {
  .hero__in {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    align-items: center;
    gap: var(--s4);
    padding-top: var(--s4);
    padding-bottom: var(--s5);
  }
  .hero__fig { order: 0; margin-inline: 0; aspect-ratio: 4 / 5; }
  .hero__cta .btn { flex: 0 0 auto; }
}

/* Contact leads with the form, not the photograph. A shorter hero image keeps
   the first field near the fold; at 4/5 on desktop it sat three screens down. */
.hero--compact .hero__fig { aspect-ratio: 4 / 3; }
@media (min-width: 48rem) { .hero--compact .hero__fig { aspect-ratio: 1 / 1; } }

/* --- Section heads -------------------------------------------------------- */
.head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s0) var(--s2);
  margin-bottom: var(--s3);
}

/* --- Work grid ------------------------------------------------------------ */
/* Explicit column counts, never auto-fit — a runtime column count makes the
   sizes attribute uncomputable and a wrong sizes is a multi-x overfetch. */
.workgrid { display: grid; gap: var(--s2) var(--s1); grid-template-columns: 1fr; }
@media (min-width: 34rem) { .workgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 62rem) { .workgrid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s3) var(--s2); } }
.work { cursor: zoom-in; }
.work:focus-visible { outline: 2px solid var(--clay); outline-offset: 4px; }

/* --- Split (image + copy) ------------------------------------------------- */
.split { display: grid; gap: var(--s2); }
.split__copy { --flow: var(--s1); }
@media (min-width: 48rem) {
  .split { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); gap: var(--s4); align-items: center; }
  .split--flip .split__fig { order: 2; }
}

/* --- Steps ---------------------------------------------------------------- */
.steps { display: grid; gap: var(--s2); counter-reset: s; }
@media (min-width: 40rem) { .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s3) var(--s2); } }
@media (min-width: 68rem) { .steps { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* align-content: start is load-bearing. These are auto-sized grid rows, so the
   default stretch spreads the three rows to fill the tallest column - which
   pushed the single-line headings DOWN, below the one that wrapped. */
.steps li { border-top: 1px solid var(--line); padding-top: var(--s1); display: grid; gap: var(--s-1); align-content: start; }
/* Multi-column only: reserve two lines per heading so the body copy starts at
   the same height across columns when one heading wraps and the others do not. */
@media (min-width: 40rem) { .steps li h3 { min-height: 2.4em; } }
.steps li:first-child { border-top-color: var(--ink); }
.step__n { font-size: var(--t-micro); letter-spacing: 0.2em; color: var(--clay-text); }

/* --- CTA band ------------------------------------------------------------- */
.ctaband { display: grid; gap: var(--s2); }
.ctaband__actions { display: flex; flex-wrap: wrap; gap: var(--s0); }
.ctaband__actions .btn { flex: 1 1 14rem; }
.band .btn--ghost { color: var(--bone); border-color: rgba(247, 244, 239, .35); }
.band .btn--ghost::after { background: var(--bone); }
@media (hover: hover) and (pointer: fine) { .band .btn--ghost:hover { color: var(--ink); border-color: var(--bone); } }
@media (min-width: 56rem) {
  .ctaband { grid-template-columns: 1fr auto; align-items: center; gap: var(--s4); }
  .ctaband__actions .btn { flex: 0 0 auto; }
}

/* --- Footer --------------------------------------------------------------- */
.footgrid { display: grid; gap: var(--s2); }
.footgrid .stack { --flow: 0px; }
.footgrid nav.stack a, .footgrid .stack > a { padding-block: 0.62rem; min-height: 2.75rem; display: flex; align-items: center; }
.footgrid .eyebrow { margin-bottom: var(--s0); }
.footgrid .stack > p.small { margin-top: var(--s0); }
@media (min-width: 40rem) { .footgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s3) var(--s2); } }
@media (min-width: 62rem) { .footgrid { grid-template-columns: 1.4fr 1fr 1.2fr 1.4fr; } }
.footnote { margin-top: var(--s3); padding-top: var(--s1); border-top: 1px solid var(--line-soft); }

/* --- Prose (guides, case studies) ----------------------------------------- */
.prose { max-width: var(--measure); }
.prose > * + * { margin-top: var(--s1); }
.prose > h2 { margin-top: var(--s3); }
.prose > h3 { margin-top: var(--s2); }
.prose ul { display: grid; gap: var(--s-1); }
.prose ul li { padding-left: 1.35em; position: relative; }
.prose ul li::before { content: ''; position: absolute; left: 0; top: 0.72em; width: 0.5em; height: 1px; background: var(--clay); }
.prose strong { font-weight: 500; }
.prose a { color: var(--clay-text); text-decoration: underline; text-underline-offset: 0.18em; }

/* --- FAQ (details/summary: the answer is in the DOM at rest) -------------- */
.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s1);
  min-height: 3.5rem; padding-block: var(--s1);
  font-size: var(--t-h4); font-weight: 500; cursor: pointer; list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: '+'; font-size: 1.4em; font-weight: 300; color: var(--clay-text); }
.faq details[open] summary::after { content: '\2212'; }
.faq .faq__a { padding-bottom: var(--s2); max-width: var(--measure); color: var(--ink-soft); }
.faq .faq__a > * + * { margin-top: var(--s1); }

/* --- Price block ---------------------------------------------------------- */
.price { display: flex; align-items: baseline; gap: var(--s0); }
.price b { font-family: var(--font-display); font-weight: 400; font-size: var(--t-h2); }

/* --- Filter row ----------------------------------------------------------- */
.filters { display: flex; flex-wrap: wrap; gap: var(--s-1); margin-bottom: var(--s3); }
.filters button {
  min-height: 2.75rem; padding: var(--s0) var(--s1);
  font-size: var(--t-small); font-weight: 300;
  background: transparent; border: 1px solid var(--line); cursor: pointer;
}
.filters button[aria-pressed='true'] { background: var(--ink); border-color: var(--ink); color: var(--bone); }

/* --- Breadcrumbs ---------------------------------------------------------- */
/* align-items: center is load-bearing: the links carry padding-block for the
   44px touch target and the separator and current-page spans do not, so without
   it the link text sits lower than its siblings. */
.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5em 0.75em;
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding-top: var(--s2);
  line-height: 1.2;
}
.crumbs > * { display: inline-flex; align-items: center; padding-block: 0.55rem; }
.crumbs a { color: var(--clay-text); }
.crumbs [aria-hidden] { padding-inline: 0; opacity: 0.55; }



/* --- Brand lockup ---------------------------------------------------------- */
.wordmark { display: inline-flex; align-items: center; gap: 0.5em; min-width: 0; flex: 0 1 auto; }
/* The mark gives back a few px on a 320px phone so the name is not clipped;
   full 2.4rem by 390px. Desktop size is set in the 48rem block below. */
.wordmark img { width: clamp(1.9rem, -0.27rem + 10.86vw, 2.8rem); height: clamp(1.9rem, -0.27rem + 10.86vw, 2.8rem); flex: none; background: none; }
@media (min-width: 48rem) { .wordmark img { width: clamp(2.8rem, 1.5rem + 2.6vw, 3.9rem); height: clamp(2.8rem, 1.5rem + 2.6vw, 3.9rem); } .wordmark { gap: 0.6em; } }
.menu__top .wordmark img { width: 2.25rem; height: 2.25rem; }
/* Footer: the mark gets room to breathe and sits above the name. */
.foot .wordmark { gap: 0.5rem; }
.foot .wordmark img { width: 2.5rem; height: 2.5rem; }
.foot .wordmark { font-size: clamp(1.25rem, 1.15rem + 0.35vw, 1.4rem); }

/* --- Tables ----------------------------------------------------------------
   Mobile first: a five-column money table cannot be read at 375px, so each row
   becomes a card and every figure carries its column name from data-label.
   The real table returns at 48rem, where the columns actually fit. */
.tblwrap { margin-top: var(--s2); margin-bottom: var(--s2); }
.tbl { width: 100%; border-collapse: collapse; font-size: var(--t-small); }
.tbl caption {
  caption-side: top; text-align: left;
  font-size: var(--t-micro); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--clay-text); padding-bottom: var(--s1); line-height: 1.5;
}

/* ---- Phone: stacked cards ---- */
@media (max-width: 47.99rem) {
  .tbl thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .tbl tbody, .tbl tr, .tbl th, .tbl td { display: block; }
  .tbl tr {
    background: var(--paper);
    border: 1px solid var(--line);
    padding: var(--s1) var(--s1) var(--s0);
    margin-bottom: var(--s1);
  }
  .tbl tbody th[scope='row'] {
    font-family: var(--font-body);
    font-weight: 500;
    font-size: var(--t-h4);
    line-height: 1.3;
    color: var(--ink);
    padding: 0 0 var(--s0);
    margin-bottom: var(--s0);
    border-bottom: 1px solid var(--line-soft);
    text-align: left;
  }
  .tbl td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s0) var(--s1);
    flex-wrap: wrap;
    padding: 0.42rem 0;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
  }
  .tbl td + td { border-top: 1px solid var(--line-soft); }
  .tbl td > * { min-width: 0; }
  .tbl td::before {
    content: attr(data-label);
    flex: 0 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
    font-size: var(--t-micro);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-soft);
  }
  /* A row with no per-column labels (two-column tables) reads as a definition. */
  .tbl td:not([data-label]) { display: block; color: var(--ink-soft); }
}

/* ---- Tablet and up: a real table ---- */
@media (min-width: 48rem) {
  .tblwrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .tbl { min-width: 32rem; }
  .tbl caption { padding-bottom: var(--s1); }
  .tbl th, .tbl td {
    text-align: left;
    padding: var(--s1) var(--s2) var(--s1) 0;
    border-bottom: 1px solid var(--line);
    vertical-align: top;
  }
  .tbl thead th {
    font-weight: 500;
    white-space: normal;
    font-size: var(--t-micro);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink);
    border-bottom-color: var(--ink);
  }
  .tbl tbody th[scope='row'] { font-weight: 400; color: var(--ink); padding-right: var(--s3); }
  /* No blanket nowrap: it is right for a money range and catastrophic for a
     prose column, which stretched one table to 2561px inside a 1198px wrap. */
  .tbl td { color: var(--ink-soft); font-variant-numeric: tabular-nums; }
  .tbl td:has(+ td), .tbl td:last-child { hyphens: none; }
  .tbl tbody tr:last-child th, .tbl tbody tr:last-child td { border-bottom: 0; }
  /* Totals rows read as a conclusion, not another line item. */
  .tbl tbody tr:last-child th, .tbl tbody tr:last-child td { font-weight: 500; color: var(--ink); }
}

/* --- Testimonials ----------------------------------------------------------
   Real, attributed Google reviews. Deliberately NOT marked up as Review or
   aggregateRating: Google disallows self-serving review markup on a
   LocalBusiness, and a third-party rating is not ours to claim in schema. */
.quotes { display: grid; gap: var(--s2); }
@media (min-width: 48rem) { .quotes { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 68rem) { .quotes--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.quote {
  background: var(--paper);
  border: 1px solid var(--line);
  padding: var(--s2);
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  height: 100%;
}
@media (min-width: 48rem) { .quote { padding: var(--s3) var(--s2); } }
.quote__stars { display: flex; gap: 0.12em; color: var(--clay); font-size: var(--t-small); letter-spacing: 0.06em; }
.quote blockquote {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--t-h3);
  line-height: 1.42;
  color: var(--ink);
  text-wrap: pretty;
}
@media (max-width: 47.99rem) {
  /* Cormorant loses its texture below 22px on a phone. */
  .quote blockquote { font-family: var(--font-body); font-weight: 300; font-size: var(--t-lead); line-height: 1.55; }
}
.quote__who { margin-top: auto; padding-top: var(--s0); border-top: 1px solid var(--line-soft); }
.quote__name { display: block; font-size: var(--t-small); font-weight: 500; }
.quote__src { display: block; font-size: var(--t-micro); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft); margin-top: 0.2rem; }

/* The aggregate line that introduces them. */
.rating-line { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s0) var(--s1); }
.rating-line__score { font-family: var(--font-display); font-size: var(--t-h2); font-weight: 400; }
.rating-line__stars { color: var(--clay); letter-spacing: 0.08em; }
.rating-line a { color: var(--clay-text); text-decoration: underline; text-underline-offset: 0.18em; }
