/* ==========================================================================
   Celtic Heritage Kitchens & Interiors, Google Ads landing page.
   One stylesheet: tokens, base, shared components, five sections, the dialog.

   Rebuilt from the Claude Design export (Celtic Heritage Design System v1).
   Token values are carried across verbatim from tokens/*.css. Every colour below
   the :root block resolves through a token, no literals, with the two documented
   exceptions marked HERO INK.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Fonts, self-hosted. @fontsource variable faces, latin subset.
   Both are variable, so one file covers every weight the page uses.
   Loaded from our own origin: no third-party request before consent, and no
   extra DNS + TLS handshake in front of the LCP.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "Petrona";
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url("../fonts/petrona-latin-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Petrona";
  font-style: italic;
  font-display: swap;
  font-weight: 100 900;
  src: url("../fonts/petrona-latin-wght-italic.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Hanken Grotesk";
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url("../fonts/hanken-grotesk-latin-wght-normal.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

/* --------------------------------------------------------------------------
   2. Tokens. Verbatim from the export's tokens/*.css.
   Measured WCAG ratios are recomputed and recorded in the build notes; every
   figure in these comments was verified against the delivered hex values.
   -------------------------------------------------------------------------- */
:root {
  --font-display: "Petrona", Georgia, "Times New Roman", serif;
  --font-ui: "Hanken Grotesk", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;

  /* Grounds */
  --ground-limewash: #F6F2EA;
  --ground-plaster:  #EDE6DA;   /* NOT a CTA ground: coral sits on it at only 2.92 */
  --ground-heritage: #1B2E27;   /* locked: baked into the block-printed illustrations */
  --ground-forest:   #14231D;

  /* Ink on light */
  --ink-forest: #14231D;        /* 14.60 on limewash, 13.15 on plaster */
  --ink-moss:   #3F5148;        /*  7.58 on limewash,  6.82 on plaster */
  --ink-slate:  #4C5F66;        /*  6.00 on limewash,  5.40 on plaster */

  /* Ink on dark */
  --ink-light:       #F6F2EA;   /* 14.60 on forest, 12.82 on heritage */
  --ink-light-muted: #B9C4BB;   /*  9.07 on forest,  7.96 on heritage */

  /* Accents */
  --accent-coral:  #F04860;     /* 3.24 limewash, 4.50 forest, 3.96 heritage. Never on plaster */
  --accent-madder: #8E2438;     /* 7.65 on limewash. hover fill and error ink */
  --accent-brass:  #966B27;     /* 4.25 on limewash: LARGE numerals only, never body */

  /* Semantic */
  --surface-page:     var(--ground-limewash);
  --surface-inset:    var(--ground-plaster);
  --surface-deep:     var(--ground-forest);
  --surface-heritage: var(--ground-heritage);

  --text-heading:       var(--ink-forest);
  --text-body:          var(--ink-moss);
  --text-lead:          var(--ink-moss);
  --text-label:         var(--ink-slate);
  --text-numeral:       var(--accent-brass);
  --text-on-deep:       var(--ink-light);
  --text-on-deep-muted: var(--ink-light-muted);

  --cta-fill:       var(--accent-coral);
  --cta-ink:        var(--ink-forest);   /* 4.50 on coral. On the line: do not nudge either hex */
  --cta-fill-hover: var(--accent-madder);
  --cta-ink-hover:  var(--ink-light);    /* 7.65 */
  --cta-fill-press: var(--ink-forest);
  --cta-ink-press:  var(--ink-light);    /* 14.60 */

  /* Scrim, four layers. Not optional: every hero frame in the set is mid-tone. */
  --scrim-flat:   rgba(20,35,29,0.30);
  --scrim-top:    rgba(20,35,29,0.34);
  --scrim-mid:    rgba(20,35,29,0.60);
  --scrim-bottom: rgba(20,35,29,0.90);
  --scrim-nav:    rgba(20,35,29,0.66);  /* raised from the export's 0.60: at 0.60 the candlelight lockup measured 4.49 on the rendered slide 2 nav band at 1440x655 */
  --scrim-left:   rgba(20,35,29,0.42);

  /* Type */
  --display-xl: 84px; --display-xl-lh: 0.96; --display-xl-ls: -0.012em;
  --display-l:  56px; --display-l-lh:  1.02; --display-l-ls:  -0.008em;
  --display-m:  40px; --display-m-lh:  1.10; --display-m-ls:  -0.004em;
  --display-s:  26px; --display-s-lh:  1.22; --display-s-ls:  0;

  --lead:   20px; --lead-lh:   1.62;
  --body:   17px; --body-lh:   1.68;
  --body-s: 15px; --body-s-lh: 1.62;
  --foot:   18px; --foot-lh:   1.55;

  --label:   12px; --label-ls:   0.18em;
  --label-s: 11px; --label-s-ls: 0.22em;

  --weight-display: 300;
  --weight-display-solid: 400;
  --weight-lead: 300;
  --weight-body: 400;
  --weight-label: 500;

  /* Spacing */
  --s-1:4px;  --s-2:8px;  --s-3:12px; --s-4:16px; --s-5:20px; --s-6:24px;
  --s-8:32px; --s-10:40px; --s-12:48px; --s-14:56px; --s-18:72px;
  --s-24:96px; --s-32:128px; --s-40:160px;

  --section-y: 128px;
  --gutter: 40px;
  --measure: 1200px;
  --stack-head: 20px;
  --stack-lead: 24px;

  /* Lines and plates */
  --radius-none: 0px;
  --radius-matte: 2px;
  --line-on-light: #DDD3C2;         /* decorative only, 1.33 on limewash */
  --line-on-light-strong: #4C5F66;  /* 6.00 on limewash: perceptible boundaries */
  --line-on-deep: #33453C;          /* decorative only, 1.60 on forest */
  --line-on-deep-strong: #B9C4BB;   /* 9.07 on forest */
  --plate-paper: #EDE6D5;
  --plate-border: 28px;
  --plate-line: #DFD4BE;
  --shadow-modal: 0 24px 64px rgba(20,35,29,0.30);
  --focus-ring: 0 0 0 2px var(--ground-limewash), 0 0 0 4px var(--ink-forest);
  --focus-ring-deep: 0 0 0 2px var(--ground-forest), 0 0 0 4px var(--ink-light);

  /* Motion */
  --ease-soft: cubic-bezier(0.22,0.61,0.36,1);
  --dur-ink: 520ms;
  --dur-slide: 900ms;
  --dur-hover: 180ms;
  --dur-modal: 260ms;
}

@media (max-width: 699px) {
  :root {
    --display-xl: 44px;
    --display-l:  32px;
    --display-m:  28px;
    --display-s:  26px;
    --lead:       18px;
    --body:       16px;
    --section-y:  64px;
    --gutter:     20px;
    --plate-border: 18px;
  }
}

/* --------------------------------------------------------------------------
   3. Base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-body);
  font-family: var(--font-ui);
  font-size: var(--body);
  line-height: var(--body-lh);
  font-weight: var(--weight-body);
  -webkit-font-smoothing: antialiased;
  text-wrap: pretty;
  overflow-x: hidden;
}
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  color: var(--text-heading);
  text-transform: lowercase;
  margin: 0;
}
p { margin: 0; }
img, svg { max-width: 100%; }
[hidden] { display: none !important; }
[data-numerals] { font-variant-numeric: lining-nums tabular-nums; }
::selection { background: var(--accent-coral); color: var(--ink-forest); }
:focus-visible { outline: none; box-shadow: var(--focus-ring); }
[data-theme="heritage"] :focus-visible,
[data-theme="forest"] :focus-visible,
.hero :focus-visible { box-shadow: var(--focus-ring-deep); }

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

/* The <use> fill trap: a <use> does not inherit a fill set as a presentation
   attribute on an ancestor <svg>, so the logo silently renders black. Belt (this
   rule), braces (fill="currentColor" on the symbol's own path). */
svg:has(use) { fill: currentColor; }
.logo, .logo use, .logo path { fill: currentColor; }

/* --------------------------------------------------------------------------
   4. Section shell and grounds
   -------------------------------------------------------------------------- */
.section { padding: var(--section-y) 0; background: var(--surface-page); }
.section[data-theme="limewash"] { background: var(--ground-limewash); color: var(--text-body); }
.section[data-theme="heritage"] { background: var(--ground-heritage); color: var(--text-on-deep-muted); }
.section[data-theme="forest"]   { background: var(--ground-forest);   color: var(--text-on-deep-muted); }
.wrap { max-width: var(--measure); margin: 0 auto; padding: 0 var(--gutter); }

/* --------------------------------------------------------------------------
   5. Shared components
   -------------------------------------------------------------------------- */

/* Buttons. The primary CTA is the one element that never recolours. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-3);
  padding: 16px 30px;
  border: 1px solid transparent; border-radius: var(--radius-none);
  font-family: var(--font-ui); font-size: var(--label); font-weight: var(--weight-label);
  letter-spacing: var(--label-ls); text-transform: uppercase; line-height: 1;
  white-space: nowrap; cursor: pointer; text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--dur-hover) var(--ease-soft),
              color var(--dur-hover) var(--ease-soft),
              border-color var(--dur-hover) var(--ease-soft);
}
.btn-lg { padding: 20px 38px; }
.btn-sm { padding: 11px 20px; font-size: var(--label-s); letter-spacing: var(--label-s-ls); }
.btn-full { width: 100%; }
.btn:disabled { cursor: not-allowed; opacity: 0.45; }

.btn-primary { background: var(--cta-fill); color: var(--cta-ink); }
.btn-primary:hover:not(:disabled) { background: var(--cta-fill-hover); color: var(--cta-ink-hover); }
.btn-primary:active:not(:disabled) { background: var(--cta-fill-press); color: var(--cta-ink-press); }

.btn-secondary { background: transparent; color: var(--ink-forest); border-color: var(--line-on-light-strong); }
.btn-secondary:hover { border-color: var(--ink-forest); }
.on-deep .btn-secondary, .btn-secondary.on-deep { color: var(--ink-light); border-color: var(--line-on-deep-strong); }
.on-deep .btn-secondary:hover, .btn-secondary.on-deep:hover { border-color: var(--ink-light); }

/* Eyebrow labels */
.eyebrow {
  margin: 0; color: var(--text-label); font-family: var(--font-ui);
  font-size: var(--label); letter-spacing: var(--label-ls);
  font-weight: var(--weight-label); text-transform: uppercase; line-height: 1.4;
  transition: color var(--dur-ink) var(--ease-soft);
}
.on-deep .eyebrow { color: var(--text-on-deep-muted); }

/* Section head: eyebrow, heading, lead */
.sec-head-h {
  margin: var(--stack-head) 0 0;
  font-family: var(--font-display); font-weight: var(--weight-display);
  font-size: var(--display-l); line-height: var(--display-l-lh);
  letter-spacing: var(--display-l-ls); text-transform: lowercase;
  color: var(--text-heading); max-width: 62ch;
}
.on-deep .sec-head-h { color: var(--text-on-deep); }
.sec-head-lead {
  margin: var(--stack-lead) 0 0; font-family: var(--font-ui);
  font-size: var(--lead); line-height: var(--lead-lh); font-weight: var(--weight-lead);
  color: var(--text-lead); max-width: 62ch;
}
.on-deep .sec-head-lead { color: var(--text-on-deep-muted); }

/* The closing line each section ends on */
.foot-note {
  margin: 0; font-family: var(--font-display); font-style: italic;
  font-weight: 400; font-size: var(--foot); line-height: var(--foot-lh);
  color: var(--ink-moss); max-width: 52ch;
}
.on-deep .foot-note { color: var(--text-on-deep-muted); }

/* The footnote + CTA row every section closes on */
.close-row {
  margin-top: var(--s-14); padding-top: var(--s-8);
  border-top: 1px solid var(--line-on-light);
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-10);
}
.on-deep .close-row { border-top-color: var(--line-on-deep); }
.close-row-cta { flex: none; display: flex; flex-direction: column; gap: var(--s-2); align-items: flex-end; }
.free-line {
  font-family: var(--font-ui); font-weight: 400;
  font-size: var(--body-s); line-height: var(--body-s-lh);
  color: var(--ink-slate); text-align: right;
}
.on-deep .free-line { color: var(--text-on-deep-muted); }

@media (max-width: 699px) {
  .close-row { margin-top: var(--s-10); padding-top: var(--s-6); flex-direction: column; align-items: stretch; gap: var(--s-6); }
  .close-row-cta { align-items: stretch; }
  .free-line { text-align: center; }
}

/* Photograph frames. Ratio is stated so the layout cannot shift as images land. */
.frame {
  position: relative; background: var(--ground-plaster);
  border-radius: var(--radius-matte); overflow: hidden;
}
.on-deep .frame { background: var(--ground-forest); }
/* Descendant, not child: every framed photograph is wrapped in <picture>, so
   ".frame > img" matched nothing and each image overflowed its frame and was
   clipped at the bottom. ".hero-frame img" below was already written this way. */
.frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.frame-4-5 { aspect-ratio: 4 / 5; }
.frame-4-3 { aspect-ratio: 4 / 3; }
.frame-3-2 { aspect-ratio: 3 / 2; }
.frame-1-1 { aspect-ratio: 1 / 1; }
.frame-9-13 { aspect-ratio: 9 / 13; }

/* The cream printed-paper plate the block prints sit inside. Never cropped. */
.plate {
  margin: 0; padding: var(--plate-border); background: var(--plate-paper);
  border: 1px solid var(--plate-line); border-radius: var(--radius-none);
  display: flex; align-items: center; justify-content: center;
}
.plate img { display: block; width: 100%; height: auto; }

/* Placeholder markers. Deliberately loud: nothing here ships by accident. */
.placeholder {
  display: flex; align-items: baseline; gap: var(--s-3);
  margin: 0; padding: var(--s-3) var(--s-4);
  background: var(--ground-plaster); border-left: 2px solid var(--accent-madder);
  color: var(--ink-moss); font-family: var(--font-ui); font-size: var(--body-s); line-height: 1.5;
}
.placeholder b {
  flex: none; color: var(--accent-madder); font-size: var(--label-s);
  letter-spacing: var(--label-s-ls); text-transform: uppercase;
  font-weight: var(--weight-label);
}
/* Deliberately NOT restyled for dark grounds. The export tinted these to
   rgba(246,242,234,0.06) with muted ink, which puts the madder label at 1.5 on
   heritage green and makes the pinned one unreadable over a photograph. They
   keep the plaster ground everywhere, so the label reads at 6.88 and the body
   at 6.82 on every section. */
.placeholder-pin { position: absolute; left: var(--s-3); top: var(--s-3); padding: var(--s-2) var(--s-3); }

/* Trust strip. Marks are drawn in currentColor so the strip recolours whole.
   No stars, no counts, no ratings, anywhere on this page. */
.trust { display: flex; flex-wrap: wrap; gap: var(--s-5) clamp(20px, 2.6vw, 40px); list-style: none; margin: 0; padding: 0; }
.trust-col { flex-direction: column; gap: var(--s-4); }
.trust li { display: flex; align-items: center; gap: var(--s-3); }
.trust svg { width: 20px; height: 20px; flex: none; display: block; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.trust span {
  font-family: var(--font-ui); font-size: var(--label-s);
  letter-spacing: var(--label-s-ls); text-transform: uppercase;
  font-weight: var(--weight-label); line-height: 1.5; white-space: nowrap;
}

/* Phone link */
.phone {
  display: inline-flex; align-items: center; gap: var(--s-2);
  color: var(--ink-forest); font-family: var(--font-ui);
  font-size: var(--label); font-weight: var(--weight-label);
  letter-spacing: var(--label-ls); text-transform: uppercase;
  text-decoration: none; border-bottom: 1px solid transparent;
  padding-bottom: 3px; white-space: nowrap; flex: none;
  transition: border-color var(--dur-hover) var(--ease-soft), color var(--dur-ink) var(--ease-soft);
}
.phone:hover { border-bottom-color: currentColor; }
.on-deep .phone { color: var(--ink-light); }

/* --------------------------------------------------------------------------
   6. Hero
   -------------------------------------------------------------------------- */
.hero {
  position: relative; min-height: min(92vh, 900px);
  display: flex; flex-direction: column;
  background: var(--ground-forest); overflow: hidden;
  /* HERO INK. Literal hex, per slide, sampled from the photograph. A transition
     on `color` whose value is a var() keeps its first computed colour when only
     the property name changes, which silently kills the recolour. */
  --hero-ink: #F8F3E7;
  --hero-ink-muted: #E6E0D0;
}
.hero[data-slide="1"] { --hero-ink: #F5F4EF; --hero-ink-muted: #E4E5DD; }
.hero[data-slide="2"] { --hero-ink: #F8F2E6; --hero-ink-muted: #E6E0D1; }

.hero-frames { position: absolute; inset: 0; }
.hero-frame {
  position: absolute; inset: 0; opacity: 0; pointer-events: none;
  transition: opacity var(--dur-slide) var(--ease-soft);
}
.hero-frame[data-active] { opacity: 1; }
.hero-frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero-frame img { object-position: 50% 44%; }
.hero-frame[data-id="vicarage"] img { object-position: 50% 66%; }
.hero-frame[data-id="lake"] img { object-position: 50% 56%; }
.hero-scrim { position: absolute; inset: 0; }
.hero-scrim-1 { background: var(--scrim-flat); }
.hero-scrim-2 { background: linear-gradient(to bottom, var(--scrim-top) 0%, var(--scrim-top) 28%, var(--scrim-mid) 62%, var(--scrim-bottom) 96%); }
.hero-scrim-3 { background: linear-gradient(to bottom, var(--scrim-nav) 0%, transparent 24%); }
.hero-scrim-4 { background: linear-gradient(to right, var(--scrim-left) 0%, transparent 70%); }

.hero-inner { position: relative; z-index: 2; display: flex; flex-direction: column; flex: 1; }

.hero-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-8); padding: var(--s-6) clamp(20px, 2.4vw, 40px);
  color: var(--hero-ink); transition: color var(--dur-ink) var(--ease-soft);
}
.hero-logo { height: 38px; width: auto; display: block; flex: none; color: #F4E7C6; }
.hero-nav { display: flex; align-items: center; gap: clamp(16px, 2.2vw, 40px); flex: 1 1 auto; min-width: 0; }
.hero-nav a {
  color: currentColor; font-family: var(--font-ui); font-size: var(--label);
  letter-spacing: var(--label-ls); text-transform: uppercase;
  font-weight: var(--weight-label); text-decoration: none; white-space: nowrap;
  border-bottom: 1px solid transparent; padding-bottom: 3px;
  transition: border-color var(--dur-hover) var(--ease-soft);
}
.hero-nav a:hover { border-bottom-color: currentColor; }
.hero-header-right { display: flex; align-items: center; flex: none; gap: clamp(16px, 2vw, 32px); }
.hero-header .phone { color: currentColor; }

.hero-body {
  flex: 1; display: flex; flex-direction: column; justify-content: flex-end;
  padding: var(--s-24) var(--gutter) var(--s-8);
  max-width: var(--measure); width: 100%; margin: 0 auto;
}
.hero-eyebrow { color: var(--hero-ink-muted); transition: color var(--dur-ink) var(--ease-soft); }
.hero h1 {
  margin: var(--stack-head) 0 0; font-family: var(--font-display);
  font-weight: var(--weight-display); font-size: var(--display-xl);
  line-height: var(--display-xl-lh); letter-spacing: var(--display-xl-ls);
  text-transform: lowercase; color: var(--hero-ink); max-width: 18ch;
  transition: color var(--dur-ink) var(--ease-soft);
}
.hero-sub {
  margin: var(--s-6) 0 0; font-family: var(--font-ui);
  font-size: var(--lead); line-height: var(--lead-lh); font-weight: var(--weight-lead);
  color: var(--hero-ink-muted); max-width: 46ch;
  transition: color var(--dur-ink) var(--ease-soft);
}
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-8); margin-top: var(--s-10); }
.hero-secondary {
  display: inline-flex; align-items: baseline; gap: var(--s-2);
  color: var(--hero-ink); font-family: var(--font-ui); font-size: var(--body);
  font-weight: 400; text-decoration: none;
  border-bottom: 1px solid transparent; padding-bottom: 2px; opacity: 0.92;
  transition: border-color var(--dur-hover) var(--ease-soft), opacity var(--dur-hover) var(--ease-soft), color var(--dur-ink) var(--ease-soft);
}
.hero-secondary:hover { border-bottom-color: currentColor; opacity: 1; }
.hero-free {
  margin: var(--s-3) 0 0; font-family: var(--font-ui); font-weight: 400;
  font-size: var(--body-s); line-height: var(--body-s-lh);
  color: var(--hero-ink-muted); transition: color var(--dur-ink) var(--ease-soft);
}
.hero-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-6);
  padding: var(--s-6) var(--gutter);
  max-width: var(--measure); width: 100%; margin: 0 auto;
  border-top: 1px solid rgba(246,242,234,0.22);
  color: var(--hero-ink-muted); transition: color var(--dur-ink) var(--ease-soft);
}

/* The three in-page links are the first thing to go when width runs out. The
   primary CTA must survive every width, so the nav drops before it can push it
   off the page. */
@media (max-width: 1100px) { .hero-nav { display: none; } }
@media (max-width: 699px) {
  .hero { min-height: 620px; }
  .hero-header { padding: var(--s-5) var(--gutter); }
  .hero-logo { height: 30px; }
  .hero-header-cta { display: none; }
  .hero-body { padding: var(--s-18) var(--gutter) var(--s-6); }
  .hero-secondary { display: none; }
  .hero-actions .btn { width: 100%; }
  .hero-foot { border-top: 0; padding-top: var(--s-2); }
  .hero-foot .trust { flex-direction: column; gap: var(--s-4); }
}

/* --------------------------------------------------------------------------
   7. Projects, the alternating ledger
   -------------------------------------------------------------------------- */
.projects-head { max-width: 760px; }
.projects-head .sec-head-h, .projects-head .sec-head-lead { max-width: 34ch; }
.projects-list { list-style: none; margin: var(--s-14) 0 0; padding: 0; }
.projects-item {
  display: grid; grid-template-columns: 0.9fr 1fr; gap: var(--s-12);
  align-items: center; padding: var(--s-10) 0;
  border-bottom: 1px solid var(--line-on-light);
}
.projects-item:first-child { border-top: 1px solid var(--line-on-light); }
/* The close row brings its own rule, so the last row does not need one too:
   two hairlines 14px apart read as a mistake. */
.projects-item:last-child { border-bottom: 0; }
.projects-item > .projects-photo { grid-column: 1; grid-row: 1; }
.projects-item > .projects-text  { grid-column: 2; grid-row: 1; }
.projects-item[data-flip] { grid-template-columns: 1fr 0.9fr; }
.projects-item[data-flip] > .projects-photo { grid-column: 2; }
.projects-item[data-flip] > .projects-text  { grid-column: 1; }
.projects-text { display: flex; flex-direction: column; gap: var(--s-4); }
.projects-num {
  font-family: var(--font-display); font-weight: 300; font-size: 40px;
  line-height: 1; color: var(--text-numeral);
  font-variant-numeric: lining-nums tabular-nums;
}
.projects-town {
  margin: 0; font-family: var(--font-display); font-size: var(--display-m);
  font-weight: 400; line-height: 1.05; text-transform: lowercase; color: var(--text-heading);
}
.projects-detail { margin: 0; font-family: var(--font-ui); font-size: var(--body); line-height: var(--body-lh); color: var(--text-body); max-width: 26ch; }

@media (max-width: 699px) {
  .projects-list { margin-top: var(--s-10); }
  .projects-item, .projects-item[data-flip] {
    grid-template-columns: 1fr; gap: var(--s-5); padding: var(--s-8) 0;
  }
  .projects-item > .projects-photo, .projects-item[data-flip] > .projects-photo { grid-column: 1; grid-row: 1; }
  .projects-item > .projects-text,  .projects-item[data-flip] > .projects-text  { grid-column: 1; grid-row: 2; }
  .projects-item .frame-9-13 { aspect-ratio: 1 / 1; }
  .projects-num { font-size: 26px; }
}

/* --------------------------------------------------------------------------
   8. Craft and workshop
   -------------------------------------------------------------------------- */
.craft-grid { display: grid; grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); gap: var(--s-18); align-items: start; }
.craft-left { display: flex; flex-direction: column; gap: var(--s-5); }
.craft-portrait { outline: 1px solid var(--line-on-deep); outline-offset: 8px; border-radius: var(--radius-matte); }
.craft-caption {
  margin: 0; font-family: var(--font-display); font-style: italic;
  font-size: var(--body-s); line-height: var(--body-s-lh); color: var(--text-on-deep-muted);
}
.craft-copy { margin-top: var(--s-8); display: flex; flex-direction: column; gap: var(--s-5); max-width: 56ch; }
.craft-copy p { margin: 0; font-size: var(--body); line-height: var(--body-lh); color: var(--text-on-deep-muted); }
.craft-points { margin-top: var(--s-12); display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-8) var(--s-10); }
.craft-point { display: flex; flex-direction: column; gap: var(--s-4); }
.craft-rule { display: block; width: 44px; height: 2px; background: var(--accent-brass); }
.craft-point h3 {
  margin: 0; font-family: var(--font-display); font-weight: var(--weight-display-solid);
  font-size: var(--display-s); line-height: 1.2; text-transform: lowercase; color: var(--text-on-deep);
}
.craft-point p { margin: 0; font-family: var(--font-ui); font-size: var(--body); line-height: var(--body-lh); color: var(--text-on-deep-muted); max-width: 40ch; }
.craft-figure { margin: 0; display: flex; flex-direction: column; gap: var(--s-3); }

@media (max-width: 699px) {
  .craft-grid { grid-template-columns: 1fr; gap: var(--s-10); }
  .craft-points { grid-template-columns: 1fr; margin-top: var(--s-10); }
}

/* --------------------------------------------------------------------------
   9. Process. Five steps, no timings anywhere: the client's decision, because
   there are too many variables per job to set them. Do not reintroduce a slot.
   -------------------------------------------------------------------------- */
.process-head { max-width: 820px; }
.process-lead-row {
  margin: var(--s-14) 0 0; padding: var(--s-10) 0;
  border-top: 1px solid var(--line-on-light);
  border-bottom: 1px solid var(--line-on-light);
  display: grid; grid-template-columns: minmax(0, 1fr) 380px; gap: var(--s-14); align-items: center;
}
.process-free {
  margin: var(--s-5) 0 0; font-family: var(--font-display); font-style: italic;
  font-size: var(--lead); line-height: 1.4; color: var(--ink-forest);
}
.process-list {
  list-style: none; margin: var(--s-12) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-10) var(--s-8);
}
.process-step { display: flex; flex-direction: column; gap: var(--s-6); }
.process-step-body { display: flex; gap: var(--s-5); }
.process-num {
  flex: none; font-family: var(--font-display); font-weight: var(--weight-display-solid);
  font-size: var(--display-s); line-height: 1.1; color: var(--text-numeral);
  font-variant-numeric: lining-nums tabular-nums;
}
.process-step h3 {
  margin: 0; font-family: var(--font-display); font-weight: var(--weight-display-solid);
  font-size: var(--display-s); line-height: 1.15; text-transform: lowercase; color: var(--text-heading);
}
.process-step-text { display: flex; flex-direction: column; gap: var(--s-3); }
.process-step p { margin: 0; font-family: var(--font-ui); font-size: var(--body); line-height: var(--body-lh); color: var(--text-body); max-width: 38ch; }

@media (max-width: 699px) {
  .process-lead-row {
    margin-top: var(--s-10); padding: 0; border: 0;
    grid-template-columns: 1fr; gap: var(--s-6);
  }
  .process-lead-row > .plate { order: -1; }
  .process-list { grid-template-columns: 1fr; margin-top: var(--s-12); gap: var(--s-12); }
}

/* --------------------------------------------------------------------------
   10. Closing
   -------------------------------------------------------------------------- */
.close-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--s-18); align-items: center; }
.close-copy { margin-top: var(--s-8); display: flex; flex-direction: column; gap: var(--s-5); max-width: 50ch; }
.close-copy p { margin: 0; color: var(--text-on-deep-muted); }
.close-copy p:first-child { font-size: var(--lead); line-height: var(--lead-lh); font-weight: var(--weight-lead); }
.close-actions { margin-top: var(--s-10); display: flex; flex-direction: column; gap: var(--s-3); align-items: flex-start; }
.close-buttons { display: flex; flex-wrap: wrap; gap: var(--s-4); }
.close-actions .free-line { text-align: left; }
.close-photo { display: flex; flex-direction: column; gap: var(--s-4); }
.close-photo-wrap { position: relative; }

@media (max-width: 699px) {
  .close-grid { grid-template-columns: 1fr; gap: var(--s-10); }
  .close-actions { align-items: stretch; }
  .close-buttons { flex-direction: column; width: 100%; }
  .close-actions .free-line { text-align: center; }
}

/* --------------------------------------------------------------------------
   11. Letterhead foot. Directions target the ADDRESS STRING, never the business
   name: the Google Business Profile is merged with the business park, so
   anything that resolves by name renders the wrong listing. No embedded map
   anywhere on this page, for the same reason.
   -------------------------------------------------------------------------- */
.letterfoot { border-top: 1px solid var(--line-on-deep); padding-top: var(--s-12); margin-top: var(--s-18); color: var(--text-on-deep-muted); }
.letterfoot-grid { display: grid; grid-template-columns: minmax(0,1.1fr) minmax(0,1fr) minmax(0,1fr); gap: var(--s-10); }
.letterfoot-col { display: flex; flex-direction: column; gap: var(--s-5); }
.letterfoot-logo { height: 52px; width: auto; display: block; flex: none; align-self: flex-start; color: var(--ink-light); }
.letterfoot p { margin: 0; font-family: var(--font-ui); font-size: var(--body-s); line-height: 1.7; color: var(--text-on-deep-muted); }
.letterfoot-address { max-width: 30ch; }
.letterfoot-aside { font-family: var(--font-display) !important; font-style: italic; font-size: var(--body) !important; line-height: 1.5 !important; max-width: 30ch; }
.letterfoot-directions {
  color: var(--ink-light); font-family: var(--font-ui); font-size: var(--label-s);
  letter-spacing: var(--label-s-ls); text-transform: uppercase;
  font-weight: var(--weight-label); text-decoration: none;
  border-bottom: 1px solid currentColor; padding-bottom: 3px; align-self: flex-start;
}
.letterfoot-legal { margin-top: var(--s-12); padding-top: var(--s-6); border-top: 1px solid var(--line-on-deep); display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-6); }
.letterfoot-legal a { color: var(--text-on-deep-muted); text-decoration: none; border-bottom: 1px solid currentColor; }
.letterfoot-legal a:hover { color: var(--ink-light); }

@media (max-width: 699px) {
  .letterfoot { padding-top: var(--s-8); margin-top: var(--s-12); }
  .letterfoot-grid { grid-template-columns: 1fr; gap: var(--s-8); }
}

/* --------------------------------------------------------------------------
   12. The enquiry form.

   PROGRESSIVE ENHANCEMENT, and the reason the rules below look inverted:
   with no JavaScript, or if the modal script throws, the <dialog> is styled as
   an ordinary section at the foot of the page with both steps visible, so the
   page can still take a lead. The script sets data-modal-ready on <html> as its
   last act, and only then does the dialog behave as a modal.
   -------------------------------------------------------------------------- */
.enq {
  display: block; position: static; inset: auto;
  width: 100%; max-width: none; max-height: none; height: auto;
  margin: 0; padding: 0; border: 0; background: transparent; color: inherit;
  overflow: visible;
}
.enq::backdrop { background: rgba(20,35,29,0.62); }

.enq-fallback-head { max-width: var(--measure); margin: 0 auto var(--s-8); padding: 0 var(--gutter); }
.enq-card {
  max-width: 600px; margin: 0 auto; background: var(--ground-limewash);
  display: flex; flex-direction: column;
}
.enq-head { background: var(--ground-forest); color: var(--ink-light); padding: var(--s-8) var(--s-10); flex: none; }
.enq-head-top { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-6); }
.enq-step-count {
  font-family: var(--font-ui); font-size: var(--label-s); letter-spacing: var(--label-s-ls);
  text-transform: uppercase; font-weight: var(--weight-label); color: var(--ink-light-muted);
}
.enq-close {
  background: none; border: 0; cursor: pointer; color: var(--ink-light);
  font-size: 24px; line-height: 1; padding: 10px; margin: -10px -10px 0 0; flex: none;
}
.enq-head h2 {
  margin: var(--s-3) 0 0; font-family: var(--font-display); font-weight: var(--weight-display);
  font-size: var(--display-m); line-height: var(--display-m-lh);
  text-transform: lowercase; color: var(--ink-light);
}
.enq-sub { margin: var(--s-3) 0 0; font-family: var(--font-display); font-style: italic; font-size: var(--body); line-height: 1.5; color: var(--ink-light-muted); max-width: 40ch; }
.enq-bar { display: flex; gap: 6px; margin-top: var(--s-5); }
.enq-bar span { width: 30px; height: 2px; background: var(--line-on-deep); }
.enq-bar span:first-child { background: var(--line-on-deep-strong); }
.enq-form { padding: var(--s-8) var(--s-10) var(--s-10); display: flex; flex-direction: column; gap: var(--s-6); flex: 1 1 auto; }
.enq-fieldset { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-6); }
.enq-field { display: flex; flex-direction: column; gap: var(--s-2); }
.enq-field > span:first-child {
  font-family: var(--font-ui); font-size: var(--label-s); letter-spacing: var(--label-s-ls);
  text-transform: uppercase; font-weight: var(--weight-label); color: var(--text-label);
}
.enq-field input, .enq-field textarea {
  width: 100%; padding: 14px 16px;
  background: var(--ground-plaster); color: var(--ink-forest);
  /* line-on-light reads 1.19 against the field fill and 1.33 against the modal
     ground, so at rest nothing identified the field to WCAG 1.4.11. Moved to
     line-on-light-strong, which is 5.40 and 6.00. */
  border: 1px solid var(--line-on-light-strong);
  border-radius: var(--radius-none); font-family: var(--font-ui); font-size: var(--body);
  outline: none;
  transition: border-color var(--dur-hover) var(--ease-soft), background-color var(--dur-hover) var(--ease-soft);
}
.enq-field textarea { resize: vertical; }
.enq-field input:focus, .enq-field textarea:focus { background: var(--ground-limewash); border-color: var(--ink-forest); box-shadow: var(--focus-ring); }
.enq-field input[name="postcode"] { width: 12ch; }
.enq-help { margin: 0; font-family: var(--font-display); font-style: italic; font-size: var(--body-s); line-height: 1.5; color: var(--ink-slate); }
.enq-error { margin: 0; font-family: var(--font-ui); font-style: normal; font-size: var(--body-s); line-height: 1.5; color: var(--accent-madder); }
.enq-field[data-invalid] input, .enq-field[data-invalid] textarea { border-color: var(--accent-madder); }
.enq-actions { margin-top: auto; display: flex; flex-direction: column; gap: var(--s-4); }
.enq-legal-row { display: flex; justify-content: space-between; align-items: baseline; gap: var(--s-5); }
.enq-legal { margin: 0; font-family: var(--font-ui); font-size: var(--body-s); line-height: 1.6; color: var(--ink-slate); max-width: 36ch; }
.enq-legal a { color: var(--ink-slate); text-underline-offset: 3px; }
.enq-back {
  background: none; border: 0; padding: 0 0 2px; cursor: pointer; color: var(--ink-slate);
  font-family: var(--font-ui); font-size: var(--label-s); letter-spacing: var(--label-s-ls);
  text-transform: uppercase; font-weight: var(--weight-label);
  border-bottom: 1px solid currentColor; flex: none;
}
/* The honeypot. Off-screen rather than display:none, so a bot that respects
   display:none still fills it in. */
.enq-hp { position: absolute; left: -9999px; opacity: 0; height: 0; overflow: hidden; }

/* In the fallback state both steps are open at once, so the step counter, the
   step bar and the close control would all be lying. They only exist once the
   dialog is actually a modal. */
.enq-step-count, .enq-bar, .enq-close { display: none; }

/* Modal behaviour, only once the script has proved it runs. */
[data-modal-ready] .enq-step-count { display: inline; }
[data-modal-ready] .enq-bar { display: flex; }
[data-modal-ready] .enq-close { display: block; }
[data-modal-ready] .enq-section { padding: 0; }
[data-modal-ready] .enq-fallback-head { display: none; }
[data-modal-ready] .enq:not([open]) { display: none; }
[data-modal-ready] .enq[open] {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center;
  width: 100%; height: 100%; max-width: none; max-height: none;
  padding: var(--s-10); background: transparent;
}
[data-modal-ready] .enq[open] .enq-card { max-height: 92vh; overflow-y: auto; box-shadow: var(--shadow-modal); }
[data-modal-ready] .enq-bar span.is-on { background: var(--cta-fill); }
[data-modal-ready] .enq-bar span:first-child:not(.is-on) { background: var(--line-on-deep-strong); }

@media (max-width: 699px) {
  .enq-head { padding: var(--s-6) var(--s-5); }
  .enq-form { padding: var(--s-6) var(--s-5) var(--s-8); }
  [data-modal-ready] .enq[open] { padding: 0; place-items: stretch; }
  [data-modal-ready] .enq[open] .enq-card { max-width: none; height: 100%; max-height: 100%; box-shadow: none; }
}

/* --------------------------------------------------------------------------
   13. Reduced motion. The hero has no controls, so this is the only thing that
   stops it. Durations go to zero and the slider stops advancing (in page.js).
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  :root { --dur-ink: 0ms; --dur-slide: 0ms; --dur-hover: 0ms; --dur-modal: 0ms; }
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --------------------------------------------------------------------------
   14. Consent banner. Tokens only, no vendor stylesheet.

   Accept and Reject are the same class, the same size, the same fill and the
   same weight. They differ in one thing, their label. That equality is the
   compliance point and it is the thing a regulator actually looks at, so do
   not restyle one of them and do not turn either into a link.

   Neither of them is coral, deliberately. Coral means exactly one thing on
   this page, "Book your design visit", and the conversion is only countable
   while that stays true.
   -------------------------------------------------------------------------- */
.cc:not([open]) { display: none; }

.cc[open] {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 70;
  display: block;
  width: 100%; max-width: none; max-height: none;
  margin: 0; padding: 0;
  border: 0; border-top: 1px solid var(--line-on-deep-strong);
  border-radius: var(--radius-none);
  background: var(--ground-forest);
  color: var(--ink-light);
  box-shadow: 0 -18px 48px rgba(20,35,29,0.34);
}

/* Light, not a blackout. The page has to stay readable behind it: someone
   deciding about analytics should be able to see what they landed on. */
.cc::backdrop { background: rgba(20,35,29,0.18); }

.cc-card {
  max-width: var(--measure); margin: 0 auto;
  padding: var(--s-5) var(--gutter);
  display: flex; align-items: center; gap: var(--s-8);
}

.cc-h {
  margin: 0 0 var(--s-2);
  font-family: var(--font-ui); font-size: var(--label);
  letter-spacing: var(--label-ls); text-transform: uppercase;
  font-weight: var(--weight-label); line-height: 1.4;
  color: var(--ink-light);
}
.cc-b {
  margin: 0; max-width: 76ch;
  font-family: var(--font-ui);
  font-size: var(--body-s); line-height: var(--body-s-lh);
  color: var(--ink-light-muted);
}
.cc-link { color: var(--ink-light); text-underline-offset: 3px; }

.cc-actions { flex: 0 0 auto; display: flex; gap: var(--s-4); }

.cc-btn {
  flex: 1 1 0; min-width: 152px;
  padding: 16px 30px;
  border: 1px solid var(--ink-light);
  border-radius: var(--radius-none);
  background: var(--ink-light);
  color: var(--ink-forest);            /* 14.60 on the cream fill */
  font-family: var(--font-ui); font-size: var(--label);
  font-weight: var(--weight-label); letter-spacing: var(--label-ls);
  text-transform: uppercase; line-height: 1;
  white-space: nowrap; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--dur-hover) var(--ease-soft),
              color var(--dur-hover) var(--ease-soft);
}
.cc-btn:hover { background: transparent; color: var(--ink-light); }   /* 14.60 on forest */
.cc-btn:focus-visible { outline: none; box-shadow: var(--focus-ring-deep); }

/* The withdrawal control, in the letterhead beside the privacy link. It is a
   button because it opens a dialog, same reasoning as the primary CTA. */
.cc-settings {
  background: none; border: 0; padding: 0;
  font: inherit; color: inherit; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}

@media (max-width: 860px) {
  .cc-card {
    flex-direction: column; align-items: stretch; gap: var(--s-4);
    padding: var(--s-4) var(--s-5) calc(var(--s-4) + env(safe-area-inset-bottom, 0px));
  }
  .cc-h { margin-bottom: var(--s-1); }
  .cc-actions { gap: var(--s-3); }
  .cc-btn { min-width: 0; padding: 14px 10px; }
}

/* Making room for the banner, so "Book your design visit" is never behind it
   on a short screen.

   Reducing the hero's min-height does NOT work and was tried: the hero's
   content is taller than the reduced floor, so min-height stops being the
   binding constraint and nothing moves. The lever that does work is the 96px
   of breathing space above the headline. It is given up only while the banner
   is open, and comes straight back when the visitor answers.

   --cc-h is the banner's measured height, set by consent.js. */
[data-cc-open] .hero-body { padding-top: max(var(--s-8), calc(var(--s-24) - var(--cc-h, 0px))); }
