@charset "UTF-8";
/* ==========================================================================
   ART Building & Interiors
   Built to Brand Guidelines v1.0, Part 4 (Visual Identity) and Part 5 (Website).
   Palette: Lead & Chalk. Flat colour only, no gradients, no red.
   The only 2px line in the system is the chalk line.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens  (verbatim from tokens/*.css in the design system)
   -------------------------------------------------------------------------- */
:root {
  /* Colour - core */
  --lead: #26343C;
  --bitumen: #141C21;
  --chalk-blue: #1573CB;
  --chalk-blue-deep: #0F5A9E;
  --chalk-white: #F2F4F5;
  --zinc: #7C8A93;
  --zinc-deep: #5A6870;
  --copper: #8C5A2B;          /* RESTRICTED: guarantee seal + credential badges only */
  --white: #FFFFFF;

  /* Colour - semantic */
  --surface-page: var(--chalk-white);
  --surface-card: var(--white);
  --surface-inverse: var(--lead);
  --text-primary: var(--bitumen);
  --text-secondary: var(--zinc-deep);
  --text-inverse: var(--white);
  --text-muted: var(--zinc);
  --accent: var(--chalk-blue);
  --accent-deep: var(--chalk-blue-deep);
  --brand-primary: var(--lead);
  --border-subtle: rgba(124, 138, 147, 0.4);
  --border-inverse: rgba(255, 255, 255, 0.24);
  --focus-ring: var(--chalk-blue);

  /* Type */
  /* The three faces named in Part 4.4. Archivo is a grotesque with enough
     structural weight to hold at van-door scale and at 14px; IBM Plex Sans is
     engineered rather than neutral. Plex Sans now carries figures and labels too:
     IBM Plex Mono was dropped so the whole site reads in one text face. */
  --font-display: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
  /* Small UI text that is neither a figure nor an all-caps label. Aliased so
     those rules cannot drift away from the body face. */
  --font-label: var(--font-body);

  /* Leading tightens as the sizes climb - big type needs proportionally less
     line spacing than body copy, or the lines drift apart and stop reading as
     a single headline. Tracking tightens with it for the same reason. */
  --display-size: 66px;  --display-line: 70px;  --display-weight: 700;  --display-tracking: -0.025em;
  --h1-size: 54px;       --h1-line: 60px;       --h1-weight: 700;       --h1-tracking: -0.025em;
  --h2-size: 42px;       --h2-line: 50px;       --h2-weight: 700;       --h2-tracking: -0.015em;
  --h3-size: 29px;       --h3-line: 37px;       --h3-weight: 700;
  --h4-size: 22px;       --h4-line: 30px;       --h4-weight: 600;
  --body-lg-size: 18px;  --body-lg-line: 30px;
  --body-size: 16px;     --body-line: 27px;
  --small-size: 14px;    --small-line: 22px;
  --label-size: 13px;    --label-line: 16px;    --label-weight: 600;   --label-tracking: 0.05em;
  --descriptor-tracking: 0.04em;
  --measure: 68ch;

  /* Spacing - 8px base */
  --space-4: 4px;   --space-8: 8px;   --space-12: 12px; --space-16: 16px; --space-24: 24px;
  --space-32: 32px; --space-48: 48px; --space-64: 64px; --space-96: 96px; --space-128: 128px;

  --container-max: 1200px;
  --gutter-mobile: 24px;
  --gutter-desktop: 48px;
  --grid-gap: 24px;
  --section-padding: 96px;
  --radius: 4px;              /* 4.5: one radius, on everything */

  /* Effects */
  --shadow-card: 0 1px 2px rgba(20, 28, 33, 0.08);
  --shadow-raised: 0 10px 24px rgba(20, 28, 33, 0.12);   /* card lifted under the cursor */
  --chalk-line-color: var(--chalk-blue);
  --chalk-line-height: 2px;
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --duration-fast: 180ms;
  --duration-reveal: 500ms;   /* scroll-reveal fade; shared so the two transition rules cannot drift */

  --nav-height: 76px;
}

@media (max-width: 767px) {
  :root {
    --display-size: 42px; --display-line: 46px;
    --h1-size: 36px;      --h1-line: 42px;
    --h2-size: 30px;      --h2-line: 38px;
    --h3-size: 25px;      --h3-line: 32px;
    --section-padding: 56px;
  }
}

/* Tablets get an intermediate step. Without it the full desktop sizes land in a
   container several hundred pixels narrower and the longer headlines cramp. */
@media (min-width: 768px) and (max-width: 1023px) {
  :root {
    --display-size: 52px; --display-line: 58px;
    --h1-size: 44px;      --h1-line: 50px;
    --h2-size: 35px;      --h2-line: 43px;
    --h3-size: 26px;      --h3-line: 34px;
  }
}

/* Narrow desktops hold back h1 alone. The container only reaches its 1200px
   maximum above this, and until it does the home hero headline shares its row
   with the enquiry form - at full size it runs to six lines in that column.
   Section headings sit in a 760px measure and are unaffected, so they scale. */
@media (min-width: 1024px) and (max-width: 1199px) {
  :root { --h1-size: 46px; --h1-line: 52px; }
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-primary);
  font: 400 var(--body-size)/var(--body-line) var(--font-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg, picture { max-width: 100%; display: block; }
h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }

a { color: var(--accent-deep); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--lead); }

/* Never italicise - italics are the category default and read as cheap (4.4) */
i, em, cite, address { font-style: normal; }

::selection { background: var(--chalk-blue); color: var(--white); }

/* Focus - visible on every interactive element (5.5) */
:focus-visible {
  outline: var(--chalk-line-height) solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: 2px;
}
.on-lead :focus-visible, .site-footer :focus-visible { outline-color: var(--white); }

.skip-link {
  position: absolute; left: var(--space-16); top: -100px; z-index: 200;
  background: var(--lead); color: var(--white); padding: var(--space-12) var(--space-24);
  border-radius: var(--radius); font-weight: 600; text-decoration: none;
  transition: top var(--duration-fast) var(--ease-out);
}
.skip-link:focus { top: var(--space-16); color: var(--white); }

/* Browsers give buttons and form controls their own system font rather than
   the page one. Inherit it, so nothing on the site falls back to Arial. */
button, input, select, textarea { font-family: inherit; }

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

/* --------------------------------------------------------------------------
   3. Type scale
   -------------------------------------------------------------------------- */
.ds-display { font: var(--display-weight) var(--display-size)/var(--display-line) var(--font-display); letter-spacing: var(--display-tracking); }
.ds-h1      { font: var(--h1-weight) var(--h1-size)/var(--h1-line) var(--font-display); letter-spacing: var(--h1-tracking); }
.ds-h2      { font: var(--h2-weight) var(--h2-size)/var(--h2-line) var(--font-display); letter-spacing: var(--h2-tracking); }
.ds-h3      { font: var(--h3-weight) var(--h3-size)/var(--h3-line) var(--font-display); }
.ds-h4      { font: var(--h4-weight) var(--h4-size)/var(--h4-line) var(--font-body); }
.ds-body-lg { font: 400 var(--body-lg-size)/var(--body-lg-line) var(--font-body); max-width: var(--measure); }
.ds-body    { font: 400 var(--body-size)/var(--body-line) var(--font-body); max-width: var(--measure); }
.ds-small   { font: 400 var(--small-size)/var(--small-line) var(--font-body); }

/* Mono label - the Accuracy device. Figures, measurements, eyebrows. */
.ds-label {
  font: var(--label-weight) var(--label-size)/var(--label-line) var(--font-body);
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
}
.ds-descriptor {
  font: 600 var(--small-size)/1.4 var(--font-display);
  letter-spacing: var(--descriptor-tracking);
}
.mono { font-family: var(--font-body); font-variant-numeric: tabular-nums; }

.eyebrow { color: var(--accent-deep); margin-bottom: var(--space-12); }
.on-lead .eyebrow, .site-footer .eyebrow { color: var(--chalk-blue); }

.lede { color: var(--text-secondary); }

/* --------------------------------------------------------------------------
   4. Layout
   -------------------------------------------------------------------------- */
.container {
  width: 100%; max-width: var(--container-max);
  margin-inline: auto; padding-inline: var(--gutter-mobile);
}
@media (min-width: 768px) { .container { padding-inline: var(--gutter-desktop); } }

.section { padding-block: var(--section-padding); }
.section--tight { padding-block: var(--space-64); }
.section--inverse { background: var(--lead); color: var(--text-inverse); }
/* Sections no longer alternate. The page is one continuous Chalk White surface,
   which is also what keeps the white cards, reviews, dockets and forms reading
   as raised objects - on an all-white page they would flatten into it. The
   class stays in the markup so restoring the banding is this one line. */
.section--card { background: var(--surface-page); }

.section--inverse h1, .section--inverse h2, .section--inverse h3, .section--inverse h4 { color: var(--white); }
.section--inverse p, .section--inverse li { color: rgba(255, 255, 255, 0.85); }
.section--inverse p.eyebrow { color: #7DB8EC; }

.stack > * + * { margin-top: var(--space-16); }
.stack-lg > * + * { margin-top: var(--space-32); }

.grid { display: grid; gap: var(--grid-gap); }
/* Grid items default to min-width:auto, so one long word or a wide image
   would push a column past the screen edge. */
.grid > * { min-width: 0; }
/* A single item still wants a readable measure rather than the full container. */
.grid-1 { grid-template-columns: 1fr; max-width: 860px; }
.grid-2 { grid-template-columns: 1fr; }
.grid-3 { grid-template-columns: 1fr; }
.grid-4 { grid-template-columns: 1fr; }
@media (min-width: 560px) { .grid-4 { grid-template-columns: 1fr 1fr; } }
@media (min-width: 768px) {
  .grid-2 { grid-template-columns: repeat(2, 1fr); }
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
}
/* Three across from 1024px: at tablet width "Conservatory" did not fit a third. */
@media (min-width: 1024px) { .grid-3 { grid-template-columns: repeat(3, 1fr); } }
/* Four across only once the cards are wide enough for a word like
   "Conservatory" at heading size; on tablets it overflowed the card. */
@media (min-width: 1200px) { .grid-4 { grid-template-columns: repeat(4, 1fr); } }
.grid-split { display: grid; gap: var(--space-48); grid-template-columns: 1fr; align-items: center; }
@media (min-width: 900px) { .grid-split { grid-template-columns: 1fr 1fr; gap: var(--space-64); } }

.section-head { max-width: 760px; margin-bottom: var(--space-48); }
.section-head p:not(.eyebrow) { margin-top: var(--space-16); color: var(--text-secondary); }
/* The 760px measure stays - centring the block, not widening it, is what keeps
   a centred heading readable rather than spread across the full container. */
.section-head--center { margin-inline: auto; text-align: center; }
/* Closing action for a section, centred under whatever grid sits above it. */
.section-cta { display: flex; justify-content: center; margin-top: var(--space-48); }

/* --------------------------------------------------------------------------
   5. The chalk line - the signature device (4.2)
   Always horizontal. Never diagonal, never curved, never decorative.
   Never a border on all four sides of anything.
   -------------------------------------------------------------------------- */
.chalk-line {
  display: block;
  height: var(--chalk-line-height);
  background: var(--chalk-line-color);
  border: 0;
  width: 100%;
  transform-origin: left center;
}

/* The one animated flourish in the system: drawn left to right on enter (4.9).
   Gated behind .js so that if the script never runs, every line renders at full
   width rather than staying invisible. */
.js .chalk-line--draw { transform: scaleX(0); }
.js .is-revealed .chalk-line--draw,
.js .chalk-line--draw.is-revealed { transform: scaleX(1); transition: transform 600ms var(--ease-out); }

.rule-divider { margin-block: var(--space-64); }

/* A snapped line runs past the work - it may extend beyond its content */
.chalk-line--overrun { width: calc(100% + var(--space-48)); }

/* --------------------------------------------------------------------------
   6. Buttons (5.3)
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-8);
  padding: 14px 28px;
  font: 600 var(--body-size)/1.2 var(--font-body);
  border-radius: var(--radius);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
  text-align: center;
}

.btn-primary { background: var(--chalk-blue-deep); color: var(--white); }
.btn-primary:hover { background: #0C4E8A; color: var(--white); }   /* darkens 8% */

.btn-secondary { background: transparent; color: var(--lead); border-color: var(--lead); }
.btn-secondary:hover { background: var(--lead); color: var(--white); }

.btn-reversed { background: transparent; color: var(--white); border-color: rgba(255,255,255,0.5); }
.btn-reversed:hover { background: var(--white); color: var(--lead); }

.btn-group { display: flex; flex-wrap: wrap; gap: var(--space-16); }

/* Chevron-free text link with a chalk-line underline on hover */
.text-link {
  display: inline-block; position: relative;
  font-weight: 600; color: var(--accent-deep); text-decoration: none;
  padding-bottom: var(--space-4);
}
.text-link::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: var(--chalk-line-height);
  width: 100%; background: var(--chalk-line-color);
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--duration-fast) var(--ease-out);
}
.text-link:hover::after, .text-link:focus-visible::after { transform: scaleX(1); }
/* Wraps a text link and the punctuation straight after it (added at build),
   so a full stop or comma never drops onto a line of its own. */
.link-glue { white-space: nowrap; }

/* --------------------------------------------------------------------------
   7. Navigation (5.3)
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: var(--surface-page);
  border-bottom: 1px solid var(--border-subtle);
}
.nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-32); min-height: var(--nav-height);
}

/* The logo is an image (assets/img/logo.png, 1668 x 276). One width rule sizes
   it everywhere; the height follows from the aspect ratio. */
.wordmark { display: inline-flex; text-decoration: none; padding-block: var(--space-12); flex-shrink: 0; }
.wordmark img { display: block; width: 264px; height: auto; }
/* On a phone the full-size logo and the menu button overran the 24px gutter. */
@media (max-width: 419px) {
  .wordmark img { width: 222px; }
}

.nav__links { display: none; align-items: center; gap: 14px; }
/* The full header (wordmark, five items, phone, button) has to fit the 1104px
   container, which never grows wider. With the longer "ART Building and
   Interiors LTD" wordmark it measured 1148px, so the link gap, the gap between
   the three groups and the wordmark name all come down a little: about 1094px. */
/* The full menu needs about 1200px: below that it ran off the right edge of
   small laptops and landscape iPads, so they get the drawer menu instead. */
@media (min-width: 1200px) {
  .nav__links { display: flex; }
  .nav { gap: 20px; }
  .nav .wordmark img { width: 250px; }
}

.nav__item { position: relative; }
.nav__link {
  display: block; padding-block: var(--space-8);
  font: 500 15px/1.4 var(--font-body); color: var(--lead); text-decoration: none;
  white-space: nowrap;
}
.nav__link:hover { color: var(--accent-deep); }
.nav__item .chalk-line {
  position: absolute; left: 0; right: 0; bottom: -2px;
  transform: scaleX(0); transition: transform var(--duration-fast) var(--ease-out);
}
.nav__item[data-active="true"] .chalk-line, .nav__item:hover .chalk-line { transform: scaleX(1); }

.nav__actions { display: flex; align-items: center; gap: var(--space-16); }

/* Phone number - persistent right-hand CTA, tap-to-call (5.4) */
.nav__phone {
  display: none; align-items: center; gap: var(--space-8);
  font: 500 15px/1 var(--font-body); color: var(--chalk-blue-deep); text-decoration: none;
  white-space: nowrap;
}
@media (min-width: 600px) { .nav__phone { display: inline-flex; } }
.nav__phone:hover { color: var(--lead); }
.nav__cta { display: none; }
@media (min-width: 1200px) { .nav__cta { display: inline-flex; } }

/* Dropdown. Driven by [aria-expanded] on a real <button>, so it opens by click
   and by keyboard. Hover is layered on only for devices that actually hover. */
.nav__link--toggle {
  display: inline-flex; align-items: center; gap: 7px;
  background: none; border: 0; cursor: pointer;
  font: 500 15px/1.4 var(--font-body); color: var(--lead);
}
.nav__chevron {
  width: 8px; height: 8px; flex: none;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--duration-fast) var(--ease-out);
}
.nav__link--toggle[aria-expanded="true"] .nav__chevron { transform: translateY(1px) rotate(-135deg); }

.nav__submenu {
  position: absolute; top: calc(100% + 14px); left: -20px; width: 306px;
  background: var(--white); border: 1px solid var(--border-subtle); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(20, 28, 33, 0.10);
  padding: 0 var(--space-8) var(--space-8);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out),
              visibility 0s linear var(--duration-fast);
  z-index: 110;
}
.nav__item--has-menu.is-open .nav__submenu {
  opacity: 1; visibility: visible; transform: translateY(0);
  transition: opacity var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out),
              visibility 0s linear 0s;
}
/* The panel sits under a snapped chalk line, running the full width */
.nav__submenu-rule { position: absolute; left: 0; right: 0; top: 0; }

/* A hover bridge so the pointer can cross the gap without the panel closing */
.nav__item--has-menu.is-open::after {
  content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 14px;
}

.nav__submenu a {
  display: block; padding: var(--space-12) var(--space-16);
  text-decoration: none; color: var(--lead);
  border-bottom: 1px solid var(--border-subtle);
  transition: background-color var(--duration-fast) var(--ease-out);
}
.nav__submenu a:last-child { border-bottom: 0; }
.nav__submenu a:hover, .nav__submenu a:focus-visible { background: var(--chalk-white); }
.nav__submenu-label { display: block; font: 500 15px/1.4 var(--font-body); color: var(--lead); }
.nav__submenu-desc { display: block; margin-top: 3px; font: 400 12px/1.4 var(--font-label); color: var(--text-secondary); }
.nav__submenu a:hover .nav__submenu-label { color: var(--accent-deep); }

.nav__submenu-all {
  font: 600 var(--label-size)/1 var(--font-body) !important;
  letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: var(--accent-deep) !important;
  padding-top: var(--space-16) !important;
}

/* Mobile menu toggle */
.nav__toggle {
  display: inline-flex; flex-direction: column; justify-content: center; gap: 5px;
  position: relative;
  width: 44px; height: 44px; padding: 0 10px;
  background: transparent; border: 1px solid var(--border-subtle); border-radius: var(--radius);
  cursor: pointer;
}
@media (min-width: 1200px) { .nav__toggle { display: none; } }
/* :not() matters: the hidden "Menu" label is also a span, and width:100% here
   used to beat .visually-hidden and stretch it off the right of the screen,
   making every page wider than the phone. */
.nav__toggle span:not(.visually-hidden) {
  display: block; height: 2px; width: 100%; background: var(--lead);
  transition: transform var(--duration-fast) var(--ease-out), opacity var(--duration-fast) var(--ease-out);
}
.nav__toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Mobile drawer */
.mobile-menu {
  position: fixed; inset: 0; z-index: 150;
  background: var(--lead); color: var(--white);
  padding: var(--space-24);
  overflow-y: auto;
  transform: translateX(100%);
  visibility: hidden;
  /* Visibility must flip instantly on open, or the panel is still `hidden` when
     we move focus into it and the focus trap silently fails. On close it is
     delayed until the slide-out finishes. */
  transition: transform 260ms var(--ease-out), visibility 0s linear 260ms;
}
.mobile-menu.is-open {
  transform: translateX(0);
  visibility: visible;
  transition: transform 260ms var(--ease-out), visibility 0s linear 0s;
}
@media (min-width: 1200px) { .mobile-menu { display: none; } }

.mobile-menu__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-16); margin-bottom: var(--space-32); }
.mobile-menu__close {
  width: 44px; height: 44px; flex: none;
  background: transparent; border: 1px solid var(--border-inverse); border-radius: var(--radius);
  color: var(--white); font-size: 22px; line-height: 1; cursor: pointer;
}
.mobile-menu__list > li { border-bottom: 1px solid var(--border-inverse); }
.mobile-menu__list a {
  display: block; padding: var(--space-16) 0;
  font: 600 18px/1.3 var(--font-display); color: var(--white); text-decoration: none;
}
.mobile-menu__list a:hover { color: var(--chalk-blue); }
.mobile-menu__list .is-sub a { font: 400 16px/1.3 var(--font-body); padding-left: var(--space-16); color: rgba(255,255,255,0.8); }
.mobile-menu__foot { margin-top: var(--space-32); display: grid; gap: var(--space-12); }

body.menu-open { overflow: hidden; }

/* --------------------------------------------------------------------------
   8. Hero
   -------------------------------------------------------------------------- */
.hero {
  position: relative; background: var(--lead); color: var(--white);
  overflow: hidden;
  padding-block: var(--space-64) 0;
}
@media (min-width: 900px) { .hero { padding-block: var(--space-96) 0; } }

.hero__grid { display: grid; gap: var(--space-48); grid-template-columns: 1fr; align-items: center; }
@media (min-width: 900px) { .hero__grid { grid-template-columns: 1.05fr 0.95fr; gap: var(--space-64); } }

.hero__content { position: relative; z-index: 2; padding-bottom: var(--space-64); }
.hero h1 { color: var(--white); margin-bottom: var(--space-24); }
.hero__lede { color: rgba(255, 255, 255, 0.85); margin-bottom: var(--space-32); max-width: 54ch; }
.hero .eyebrow { color: var(--chalk-blue); }
.hero__art { position: relative; align-self: end; }
.hero__art img, .hero__art svg { width: 100%; height: auto; }

/* The hero photograph. A flat scrim, never a gradient (3.3), carries the
   white type to AA over any part of the image. */
.hero__media { position: absolute; inset: 0; z-index: 0; }
.hero__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero__media::after {
  content: ""; position: absolute; inset: 0;
  background: rgba(20, 28, 33, 0.80);
}
.hero__grid { position: relative; z-index: 2; }

/* The hairline crossing the hero image (4.2) */
.hero__chalkline { position: absolute; left: 0; right: 0; bottom: 0; z-index: 3; }

.hero__meta { display: flex; flex-wrap: wrap; gap: var(--space-24); margin-top: var(--space-32); }
.hero__meta-item { display: flex; align-items: baseline; gap: var(--space-8); color: rgba(255,255,255,0.75); font: 400 14px/1.4 var(--font-label); }
.hero__meta-item::before { content: ""; width: 6px; height: 6px; background: var(--chalk-blue); flex: none; }

/* Compact hero for inner pages */
.page-hero { background: var(--lead); color: var(--white); position: relative; padding-block: var(--space-64); }
.page-hero h1 { color: var(--white); margin-bottom: var(--space-16); }
.page-hero p { color: rgba(255, 255, 255, 0.85); }
.page-hero .eyebrow { color: var(--chalk-blue); }
.page-hero__inner { max-width: 780px; position: relative; z-index: 2; }

/* A photograph behind a page hero. Flat scrim, never a gradient (3.3). */
.page-hero--photo { overflow: hidden; }
/* Desktop only: extra depth so more of the job photograph shows behind the heading */
@media (min-width: 900px) { .page-hero--photo { padding-block: 128px; } }
.page-hero__media { position: absolute; inset: 0; z-index: 0; }
.page-hero__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.page-hero__media::after { content: ""; position: absolute; inset: 0; background: rgba(20, 28, 33, 0.82); }
.page-hero--photo > .container { position: relative; z-index: 2; }
.page-hero .chalk-line { position: absolute; left: 0; right: 0; bottom: 0; }

/* Breadcrumbs */
.breadcrumb { padding-block: var(--space-16); border-bottom: 1px solid var(--border-subtle); }
.breadcrumb ol { display: flex; flex-wrap: wrap; gap: var(--space-8); font: 400 13px/1.4 var(--font-label); color: var(--text-secondary); }
.breadcrumb li::after { content: "/"; margin-left: var(--space-8); color: var(--zinc); }
.breadcrumb li:last-child::after { content: ""; }
.breadcrumb a { color: var(--text-secondary); text-decoration: none; }
.breadcrumb a:hover { color: var(--accent-deep); }

/* --------------------------------------------------------------------------
   9. Trust bar (5.3) - Lead background, white mono labels, chalk line above
   -------------------------------------------------------------------------- */
.trust-bar { background: var(--lead); color: var(--white); border-top: var(--chalk-line-height) solid var(--chalk-blue); }
.trust-bar__list {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-16) var(--space-24);
  padding-block: var(--space-24);
}
@media (min-width: 768px) { .trust-bar__list { grid-template-columns: repeat(4, 1fr); } }
.trust-bar__item {
  display: flex; align-items: center; gap: var(--space-12);
  font: 600 var(--label-size)/1.3 var(--font-body);
  letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: rgba(255, 255, 255, 0.92);
}
.trust-bar__item svg { flex: none; width: 20px; height: 20px; stroke: var(--chalk-blue); }

/* --------------------------------------------------------------------------
   9b. Credibility ribbon - the case, compressed to one line, above the fold
   -------------------------------------------------------------------------- */
/* Continuous marquee. The list is rendered RIBBON_COPIES times (5, set in
   _build/layout.js) and the track is shifted by exactly one copy - 100/5 =
   20% of its own width - before snapping back, so the loop is seamless.
   Shifting by a percentage of the track means the distance stays exactly one
   copy whatever the copy measures, so a font swap cannot desynchronise it.
   Change the constant and this percentage together, or the bar will jump.
   Pauses on hover and on keyboard focus. */
.ribbon { background: var(--bitumen); color: rgba(255, 255, 255, 0.72); overflow: hidden; }
.ribbon__track {
  display: flex; width: max-content;
  animation: ribbon-scroll 48s linear infinite;
}
.ribbon:hover .ribbon__track,
.ribbon:focus-within .ribbon__track { animation-play-state: paused; }

@keyframes ribbon-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-20%); }   /* one copy of five */
}

.ribbon__list {
  display: flex; flex-wrap: nowrap; align-items: center; gap: var(--space-24);
  padding-block: var(--space-8); padding-right: var(--space-24);
  font: 400 12px/1.5 var(--font-label); letter-spacing: 0.04em;
}
.ribbon__list li { display: flex; align-items: center; gap: var(--space-24); white-space: nowrap; }
.ribbon__list li::after {
  content: ""; width: 4px; height: 4px; background: var(--chalk-blue); flex: none;
}

@media (prefers-reduced-motion: reduce) {
  .ribbon { overflow-x: auto; scrollbar-width: none; }
  .ribbon::-webkit-scrollbar { display: none; }
  .ribbon__track { animation: none; }
  .ribbon__list[aria-hidden="true"] { display: none; }
}

/* --------------------------------------------------------------------------
   9c. Stats bar - specific numbers, set in mono, directly under the hero
   -------------------------------------------------------------------------- */
.stats-bar { background: var(--lead); color: var(--white); border-top: var(--chalk-line-height) solid var(--chalk-blue); }
.stats-bar__list {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-24);
  padding-block: var(--space-16);
}
@media (min-width: 768px) { .stats-bar__list { grid-template-columns: repeat(4, 1fr); } }
.stat { display: flex; flex-direction: column; gap: var(--space-8); }
.stat__value {
  font: 600 30px/1 var(--font-display); color: var(--white);
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
}
.stat__label { font: 400 13px/1.5 var(--font-body); color: rgba(255, 255, 255, 0.68); max-width: 30ch; }

/* --------------------------------------------------------------------------
   9d. Intent router - three doors, phrased as the visitor's own situation
   -------------------------------------------------------------------------- */
.router__head { margin-bottom: var(--space-32); max-width: 20ch; }
.route {
  display: flex; flex-direction: column; gap: var(--space-12);
  padding: var(--space-32); background: var(--white);
  border: 1px solid var(--border-subtle); border-radius: var(--radius);
  text-decoration: none; color: inherit;
  transition: border-color var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}
.route:hover { border-color: var(--chalk-blue); color: inherit; }
.route > .chalk-line { width: 40px; }
.route__title { font: 600 var(--h3-size)/1.25 var(--font-display); color: var(--lead); }
.route__body { font: 400 15px/1.6 var(--font-body); color: var(--text-secondary); flex: 1; }
.route__go {
  font: 600 var(--label-size)/1 var(--font-body);
  letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: var(--accent-deep);
}
.route:hover .route__go { color: var(--lead); }

/* --------------------------------------------------------------------------
   9e. Price card - the docket treatment applied to indicative figures
   -------------------------------------------------------------------------- */
.pricecard {
  background: var(--white); border: 1px solid var(--border-subtle);
  border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-card);
}
.pricecard__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-16);
  background: var(--lead); padding: var(--space-16) var(--space-24);
}
.pricecard__mark { font: 700 15px/1 var(--font-display); color: var(--white); }
.pricecard__doc {
  font: 600 11px/1 var(--font-body); letter-spacing: 0.1em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
}
.pricetable { width: 100%; border-collapse: collapse; }
.pricetable th, .pricetable td {
  text-align: left; padding: var(--space-16) var(--space-24);
  border-bottom: 1px solid var(--border-subtle);
}
.pricetable th { font: 400 15px/1.4 var(--font-body); color: var(--lead); font-weight: 400; }
.pricetable td {
  font: 500 15px/1.4 var(--font-body); color: var(--text-primary);
  text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums;
}
.pricetable tr:last-child th, .pricetable tr:last-child td { border-bottom: 0; }
.pricecard__note {
  padding: var(--space-16) var(--space-24);
  background: var(--chalk-white);
  font: 400 13px/1.6 var(--font-body); color: var(--text-secondary);
}

.callout--inverse { border-left-color: var(--chalk-blue); }
.callout--inverse p { color: rgba(255, 255, 255, 0.85); }

/* Hero phone - tappable, mono, sits under the two CTAs */
.hero__phone {
  /* 44px tall so the number is an easy tap target on a phone. */
  display: inline-flex; align-items: center; gap: var(--space-12); min-height: 44px;
  margin-top: var(--space-24); text-decoration: none;
}
.hero__phone-label {
  font: 600 11px/1 var(--font-body); letter-spacing: 0.1em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}
.hero__phone-number { font: 500 20px/1 var(--font-body); color: var(--white); }
.hero__phone:hover .hero__phone-number { color: var(--chalk-blue); }

/* --------------------------------------------------------------------------
   10. Cards
   -------------------------------------------------------------------------- */
.card {
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  display: flex; flex-direction: column;
  transition: border-color var(--duration-fast) var(--ease-out);
}
.card:hover { border-color: var(--zinc); }
.card__media { background: var(--lead); aspect-ratio: 4 / 3; overflow: hidden; }
.card__media img, .card__media svg { width: 100%; height: 100%; object-fit: cover; }
.card__body { padding: var(--space-32); display: flex; flex-direction: column; gap: var(--space-12); flex: 1; }
.card__body h3 { color: var(--lead); }
.card__body p { color: var(--text-secondary); }
.card__body .text-link { margin-top: auto; align-self: flex-start; }

/* The two hero service cards - equal size, equal weight (5.2) */
.service-card__media { aspect-ratio: 16 / 10; }
.service-card__list {
  display: flex; flex-wrap: wrap; gap: var(--space-8);
  font: 400 13px/1.4 var(--font-label); color: var(--text-secondary);
}
.service-card__list li { display: flex; align-items: center; gap: var(--space-8); }
.service-card__list li::after { content: "·"; color: var(--zinc); }
.service-card__list li:last-child::after { content: ""; }

/* Compact link card used on hub pages */
.link-card {
  display: block; padding: var(--space-32); background: var(--white);
  border: 1px solid var(--border-subtle); border-radius: var(--radius);
  text-decoration: none; color: inherit;
  /* transition lives with the shared card-lift block below. */
}
.link-card:hover { border-color: var(--chalk-blue); color: inherit; }
.link-card h3 { color: var(--lead); margin-bottom: var(--space-8); }
.link-card p { color: var(--text-secondary); font-size: var(--small-size); line-height: var(--small-line); }
.link-card .chalk-line { width: 40px; margin-bottom: var(--space-16); }

/* --------------------------------------------------------------------------
   11. Pillar block (5.3) - chalk line, mono letter, H3, body, proof
   -------------------------------------------------------------------------- */
/* A Lead card rather than a bare column. The letter sits where a numeral would
   in a generic three-step block - A/R/T is the standard itself, so it carries
   more than 01/02/03 would. Cards stretch to the tallest in the row, and the
   proof line is pinned to the bottom so those rules align across all three. */
.pillar {
  background: var(--white);
  border-radius: var(--radius);
  padding: var(--space-32);
  display: flex; flex-direction: column;
  box-shadow: var(--shadow-card);
}
.pillar h3 { color: var(--lead); margin-bottom: var(--space-12); }
.pillar p { color: var(--text-secondary); }
/* Both of these are <p>, so they must out-rank `.pillar p` (0,1,1) above -
   hence the doubled class rather than a bare `.pillar__letter`. */
.pillar .pillar__letter {
  font: 600 var(--label-size)/1 var(--font-body);
  letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: var(--accent-deep); margin-bottom: var(--space-24);
}
.pillar .pillar__proof {
  margin-top: auto; padding-top: var(--space-16);
  /* Reserve two lines (2 x 1.5 line-height = 3em) so the rules above the proofs
     align across the row even though the sentences wrap differently. Everything
     is border-box here, so the padding and rule have to be added back in. */
  min-height: calc(3em + var(--space-16) + 1px);
  border-top: 1px solid var(--border-subtle);
  font: 400 14px/1.5 var(--font-label); color: var(--lead);
}

/* Hover lift, shared by both card sets.
   These cards are also scroll-reveal targets, and `.js .reveal.is-revealed`
   (0,3,0) sets both `transform` and its own `transition` - out-ranking a plain
   `:hover` (0,2,0). So the lift uses the independent `translate` property,
   leaving `transform` to the reveal and avoiding the collision outright; and
   this restates the reveal's timing alongside the hover's in one declaration,
   at a specificity that wins, so translate and box-shadow stay in the list
   instead of being dropped and snapping.
   Gated on (hover: hover) so a touch device never gets a stuck raised card. */
.why__block, .pillar, .svc, .review, .link-card,
.js .why__block.reveal.is-revealed,
.js .pillar.reveal.is-revealed,
.js .svc.reveal.is-revealed,
.js .review.reveal.is-revealed {
  transition: opacity var(--duration-reveal) var(--ease-out),
              transform var(--duration-reveal) var(--ease-out),
              translate var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
}
@media (hover: hover) {
  .why__block:hover, .pillar:hover, .svc:hover, .review:hover, .link-card:hover {
    translate: 0 -4px;
    box-shadow: var(--shadow-raised);
  }
}

/* --------------------------------------------------------------------------
   12. Before / after slider (5.3) - draggable, chalk-blue handle
   -------------------------------------------------------------------------- */
.ba { display: flex; flex-direction: column; gap: var(--space-12); }
.ba__frame {
  position: relative; aspect-ratio: 4 / 3;
  border-radius: var(--radius); overflow: hidden;
  background: var(--lead); user-select: none; touch-action: pan-y;
}
.ba__layer { position: absolute; inset: 0; }
.ba__layer img, .ba__layer svg { width: 100%; height: 100%; object-fit: cover; display: block; }
.ba__layer--before { width: 50%; overflow: hidden; border-right: 0; }
/* max-width: none overrides the global img cap, which otherwise squeezes the
   before photo to the clip width so it re-crops as the divider moves. */
.ba__layer--before > * { width: var(--ba-frame-width, 100%); max-width: none; }
.ba__tag {
  position: absolute; top: var(--space-12); z-index: 4;
  padding: 4px 10px; border-radius: var(--radius);
  font: 600 11px/1.4 var(--font-body); letter-spacing: 0.08em; text-transform: uppercase;
  background: rgba(20, 28, 33, 0.75); color: var(--white);
}
.ba__tag--before { left: var(--space-12); }
.ba__tag--after { right: var(--space-12); }
.ba__divider { position: absolute; top: 0; bottom: 0; width: var(--chalk-line-height); background: var(--chalk-blue); transform: translateX(-1px); z-index: 5; pointer-events: none; }
.ba__handle {
  position: absolute; top: 50%; width: 40px; height: 40px; z-index: 6;
  transform: translate(-50%, -50%); border-radius: 50%;
  background: var(--chalk-blue); border: 2px solid var(--white);
  display: grid; place-items: center; pointer-events: none;
  box-shadow: var(--shadow-card);
}
.ba__handle::before, .ba__handle::after {
  content: ""; width: 0; height: 0; border-block: 5px solid transparent;
}
.ba__handle::before { border-right: 6px solid var(--white); margin-right: 3px; }
.ba__handle::after { border-left: 6px solid var(--white); margin-left: 3px; }
.ba__range {
  position: absolute; inset: 0; z-index: 7; width: 100%; height: 100%;
  opacity: 0; cursor: ew-resize; margin: 0;
}
.ba__range:focus-visible { opacity: 0; }
.ba__frame:has(.ba__range:focus-visible) { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.ba__caption { font: 600 var(--label-size)/1.4 var(--font-label); letter-spacing: 0.06em; color: var(--text-secondary); text-transform: uppercase; }

/* Gallery filter */
.filter-bar { display: flex; flex-wrap: wrap; gap: var(--space-8); margin-bottom: var(--space-48); }
.filter-btn {
  padding: 10px 20px; border-radius: var(--radius);
  border: 1px solid var(--border-subtle); background: var(--white);
  font: 500 14px/1 var(--font-body); color: var(--lead); cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);
}
.filter-btn:hover { border-color: var(--chalk-blue); }
.filter-btn[aria-pressed="true"] { background: var(--lead); color: var(--white); border-color: var(--lead); }
.is-hidden { display: none !important; }

/* --------------------------------------------------------------------------
   13. Guarantee seal - the 25-year trust badge artwork (assets/img/icons/trust-badge.png)
   -------------------------------------------------------------------------- */
.seal { display: block; flex: none; width: 168px; height: 168px; border-radius: 50%; }
.seal--sm { width: 122px; height: 122px; }
/* thin light ring so the navy edge reads on the dark enquiry section */
.enquiry__assure .seal { box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.55); }

/* --------------------------------------------------------------------------
   14. Forms (5.3, 5.4) - max five fields, labelled, never placeholder-only
   -------------------------------------------------------------------------- */
.form { display: grid; gap: var(--space-24); }
.form__row { display: grid; gap: var(--space-24); grid-template-columns: 1fr; }
@media (min-width: 640px) { .form__row { grid-template-columns: 1fr 1fr; } }

.field { display: flex; flex-direction: column; gap: var(--space-8); }
.field label { font: 500 14px/1.4 var(--font-body); color: var(--lead); }
.field .req { color: var(--accent-deep); }
.field input, .field select, .field textarea {
  width: 100%; min-height: 48px; padding: 12px var(--space-16);
  background: var(--white); color: var(--text-primary);
  border: 1px solid var(--border-subtle); border-radius: var(--radius);
  font: 400 var(--body-size)/1.4 var(--font-body);
  transition: border-color var(--duration-fast) var(--ease-out);
}
.field textarea { min-height: 128px; resize: vertical; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--zinc); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--chalk-blue);
  box-shadow: 0 0 0 var(--chalk-line-height) var(--chalk-blue);
}
.field__hint { font: 400 13px/1.4 var(--font-body); color: var(--text-secondary); }
.field select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%2326343C' stroke-width='2'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 16px center; padding-right: 44px; }

/* The empty "Please select service" prompt reads as a placeholder, not an answer. */
.field select:invalid { color: var(--text-secondary); }
.field select option { color: var(--text-primary); }

.form__note { font: 400 13px/1.6 var(--font-body); color: var(--text-secondary); }
.form__privacy { padding: 0 var(--space-24) var(--space-16); text-align: center; font: 400 12px/1.4 var(--font-body); }
.form__privacy a { color: var(--text-secondary); opacity: 0.7; text-decoration: underline; text-underline-offset: 2px; }
.form__privacy a:hover, .form__privacy a:focus-visible { opacity: 1; }
.form-status { padding: var(--space-16); border-radius: var(--radius); font-size: var(--small-size); }
.form-status--ok { background: rgba(21, 115, 203, 0.08); border: 1px solid var(--chalk-blue); color: var(--lead); }
.form-status--err { background: rgba(140, 90, 43, 0.08); border: 1px solid var(--copper); color: var(--lead); }

/* ---------------------------------------------------------------------------
   Enquiry block + the survey docket (5.4, 6.4)
   The docket is the site's signature component: the front page of an ART
   survey, not a generic contact box.
   --------------------------------------------------------------------------- */
.enquiry { background: var(--lead); color: var(--white); }

.enquiry__grid { display: grid; gap: var(--space-48); grid-template-columns: 1fr; align-items: start; }
@media (min-width: 940px) {
  .enquiry__grid { grid-template-columns: 1fr 440px; gap: var(--space-64); }
}
.enquiry__lede { margin-top: var(--space-24); color: rgba(255, 255, 255, 0.85); }

/* Numbered stages - a real sequence, so the numbers carry information */
.stages { margin-top: var(--space-32); display: grid; gap: 0; }
.stage {
  display: grid; grid-template-columns: 46px 1fr; gap: var(--space-16);
  padding: var(--space-16) 0;
  border-top: 1px solid var(--border-inverse);
}
.stage:last-child { border-bottom: 1px solid var(--border-inverse); }
.stage__num {
  font: 500 var(--label-size)/1.5 var(--font-body);
  letter-spacing: var(--label-tracking); color: var(--chalk-blue);
}
.stage__text { font: 400 15px/1.6 var(--font-body); color: rgba(255, 255, 255, 0.75); }
.stage__text b { display: block; font-weight: 600; color: var(--white); }

.enquiry__assure { display: flex; align-items: center; gap: var(--space-24); margin-top: var(--space-32); }
.enquiry__assure p { color: rgba(255, 255, 255, 0.7); max-width: 34ch; }

/* --- the docket --- */
.docket {
  position: relative;
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: 0 12px 32px rgba(20, 28, 33, 0.22);
  overflow: hidden;
}
.docket__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-16);
  background: var(--lead); padding: var(--space-16) var(--space-24);
}
.docket__mark {
  font: 700 15px/1 var(--font-display); letter-spacing: -0.01em; color: var(--white);
}
.docket__doc {
  font: 600 11px/1 var(--font-label); letter-spacing: 0.1em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
}
.docket__meta {
  display: flex; flex-wrap: wrap; gap: var(--space-16);
  padding: var(--space-12) var(--space-24);
  background: var(--chalk-white);
  border-bottom: 1px solid var(--border-subtle);
  font: 500 11px/1.4 var(--font-label); letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-secondary);
}
.docket__meta b { color: var(--lead); font-weight: 500; }

.docket__body { padding: var(--space-8) var(--space-24) var(--space-24); }

/* Ruled fields - the input sits on a line, the way a form on paper does.
   No boxed inputs: that is what made the old panel read as a generic widget. */
.field--ruled { gap: 0; padding-top: var(--space-16); }
.field--ruled label {
  font: 600 11px/1.4 var(--font-label); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-secondary); margin-bottom: 2px;
}
.field--ruled input, .field--ruled select, .field--ruled textarea {
  border: 0; border-bottom: 1px solid var(--zinc); border-radius: 0;
  /* background-color, not the background shorthand: the shorthand also
     cleared the select's chevron, so the dropdown looked like a text field. */
  padding: 0 0 12px; min-height: 44px; background-color: transparent;
  font: 400 16px/1.5 var(--font-body); color: var(--text-primary);
  transition: border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}
.field--ruled select { padding-right: 28px; background-position: right 2px center; }
.field--ruled textarea { min-height: 72px; padding-top: 4px; }
.field--ruled input:hover, .field--ruled select:hover, .field--ruled textarea:hover { border-bottom-color: var(--lead); }
.field--ruled input:focus, .field--ruled select:focus, .field--ruled textarea:focus {
  outline: none;
  border-bottom-color: var(--chalk-blue);
  box-shadow: 0 var(--chalk-line-height) 0 0 var(--chalk-blue);   /* the chalk line, snapped under the field */
}
.field--ruled .field__hint { margin-top: var(--space-8); font-size: 12px; }

.docket__foot {
  display: flex; flex-direction: column; gap: var(--space-16);
  padding: 0 var(--space-24) var(--space-16);
}
.btn-block { width: 100%; }

.docket__call {
  display: flex; align-items: center; justify-content: center; gap: var(--space-8); min-height: 44px;
  text-decoration: none; padding: var(--space-4);
}
.docket__call-label {
  font: 600 11px/1 var(--font-label); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-secondary);
}
.docket__call-number { font: 500 17px/1 var(--font-label); color: var(--accent-deep); }
.docket__call:hover .docket__call-number { color: var(--lead); }

.docket .form__note {
  padding: 0 var(--space-24) var(--space-24);
  color: var(--text-secondary);
}
.docket .form-status { margin: 0 var(--space-24) var(--space-16); }

/* --------------------------------------------------------------------------
   15. Content blocks
   -------------------------------------------------------------------------- */
.prose { max-width: var(--measure); }
.prose > * + * { margin-top: var(--space-24); }
.prose h2 { margin-top: var(--space-48); color: var(--lead); }
.prose h3 { margin-top: var(--space-32); color: var(--lead); }
.prose p:not(.eyebrow), .prose li { color: var(--text-secondary); }
.prose strong { color: var(--text-primary); font-weight: 600; }

.tick-list { display: grid; gap: var(--space-12); }
.tick-list li { display: grid; grid-template-columns: 20px 1fr; gap: var(--space-12); align-items: start; color: var(--text-secondary); }
.tick-list li::before {
  content: ""; width: 14px; height: 8px; margin-top: 8px;
  border-left: 1.5px solid var(--chalk-blue); border-bottom: 1.5px solid var(--chalk-blue);
  transform: rotate(-45deg);
}
/* .tick-list li sets --text-secondary further down this file than the general
   ".section--inverse li" rule and matches at the same specificity, so it won
   and left the list dark grey on the dark panel. Scoped here to beat both. */
.section--inverse .tick-list li { color: var(--white); }
.section--inverse .tick-list li::before { border-color: var(--chalk-blue); }

/* Numbered process steps - figures in mono, per 4.4 */
.steps { display: grid; gap: var(--space-32); counter-reset: step; }
@media (min-width: 768px) { .steps { grid-template-columns: repeat(4, 1fr); } }
.step > .chalk-line { margin-bottom: var(--space-16); }
.step__num { font: 500 var(--label-size)/1 var(--font-body); letter-spacing: var(--label-tracking); color: var(--accent-deep); margin-bottom: var(--space-12); }
.step h3 { font: 600 var(--h4-size)/var(--h4-line) var(--font-body); color: var(--lead); margin-bottom: var(--space-8); }
.step p { color: var(--text-secondary); font-size: var(--small-size); line-height: var(--small-line); }
/* On the lead panel the .step rules above would otherwise win over the
   .section--inverse defaults (same specificity, later in the file), leaving
   the titles lead-on-lead. Chalk blue itself is only 2.7:1 on lead, so the
   step number uses a lighter tint of it (6.1:1). */
.section--inverse .step h3 { color: var(--white); }
.section--inverse .step p { color: rgba(255, 255, 255, 0.85); }
.section--inverse .step .step__num { color: #7DB8EC; }

/* Reviews */
.review { background: var(--white); border: 1px solid var(--border-subtle); border-radius: var(--radius); padding: var(--space-32); display: flex; flex-direction: column; gap: var(--space-16); box-shadow: var(--shadow-card); }
.review blockquote { color: var(--text-primary); font-size: var(--body-lg-size); line-height: var(--body-lg-line); }
.review__meta { margin-top: auto; padding-top: var(--space-16); border-top: 1px solid var(--border-subtle); font: 500 13px/1.5 var(--font-label); color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.06em; }

/* Areas grid - mono, on the grid (5.2) */
.areas-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-12) var(--space-24); }
@media (min-width: 640px) { .areas-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 900px) { .areas-grid { grid-template-columns: repeat(5, 1fr); } }
.areas-grid a, .areas-grid span {
  display: block; padding-block: var(--space-8);
  border-top: 1px solid var(--border-subtle);
  font: 400 14px/1.5 var(--font-label); color: var(--text-secondary); text-decoration: none;
}
.areas-grid a:hover { color: var(--accent-deep); border-top-color: var(--chalk-blue); }
.section--inverse .areas-grid a, .section--inverse .areas-grid span { color: rgba(255,255,255,0.8); border-top-color: var(--border-inverse); }
.section--inverse .areas-grid a:hover { color: var(--white); border-top-color: var(--chalk-blue); }

/* FAQ */
.faq { display: grid; gap: 0; max-width: 860px; }
.faq__item { border-bottom: 1px solid var(--border-subtle); }
.faq__q {
  width: 100%; display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-24);
  padding: var(--space-24) 0; background: none; border: 0; cursor: pointer; text-align: left;
  font: 600 var(--h4-size)/var(--h4-line) var(--font-body); color: var(--lead);
}
.faq__q:hover { color: var(--accent-deep); }
.faq__icon { position: relative; flex: none; width: 16px; height: 16px; margin-top: 6px; }
.faq__icon::before, .faq__icon::after {
  content: ""; position: absolute; background: var(--chalk-blue);
  transition: transform var(--duration-fast) var(--ease-out), opacity var(--duration-fast) var(--ease-out);
}
.faq__icon::before { left: 0; top: 7px; width: 16px; height: 2px; }
.faq__icon::after { left: 7px; top: 0; width: 2px; height: 16px; }
.faq__q[aria-expanded="true"] .faq__icon::after { transform: rotate(90deg); opacity: 0; }
.faq__a { display: none; padding-bottom: var(--space-24); }
.faq__a p { color: var(--text-secondary); max-width: var(--measure); }
.faq__a ul { color: var(--text-secondary); max-width: var(--measure); padding-left: var(--space-24); list-style: disc; }
.faq__a li + li { margin-top: var(--space-8); }
.faq__a > * + * { margin-top: var(--space-16); }
.faq__item.is-open .faq__a { display: block; }

/* Roof comparison (conservatory page): before/after by season.
   Three cards side by side on desktop, stacked on smaller screens. */
.cmp__legend {
  display: flex; flex-wrap: wrap; gap: var(--space-8) var(--space-24);
  margin: calc(var(--space-24) * -1) 0 var(--space-24);
  font: var(--label-weight) var(--label-size)/var(--label-line) var(--font-label);
  letter-spacing: var(--label-tracking); text-transform: uppercase; color: var(--text-secondary);
}
.cmp__legend span { display: inline-flex; align-items: center; gap: var(--space-8); }
.cmp { display: grid; gap: var(--space-16); }
@media (min-width: 900px) { .cmp { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-24); } }
.cmp__season {
  background: var(--white); border-radius: var(--radius); box-shadow: var(--shadow-card);
  border-top: var(--chalk-line-height) solid var(--chalk-blue);
  padding: var(--space-16) var(--space-24) var(--space-8);
}
.cmp__head { display: flex; align-items: center; gap: var(--space-12); padding-bottom: var(--space-12); }
.cmp__head svg { flex: none; color: var(--chalk-blue); }
.cmp__head h3 { font: 700 22px/1.2 var(--font-display); letter-spacing: -0.01em; color: var(--lead); }
.cmp__list li { padding: var(--space-12) 0; border-top: 1px solid var(--border-subtle); }
.cmp__before, .cmp__after { display: flex; align-items: flex-start; gap: 10px; }
.cmp__mark { flex: none; margin-top: 2px; }
.cmp__before { font: 400 14px/1.45 var(--font-body); color: var(--text-secondary); }
.cmp__after { margin-top: 6px; font: 500 15px/1.45 var(--font-body); color: var(--bitumen); }
.cmp__before strong { font-weight: 600; color: var(--lead); }
.cmp__value {
  display: flex; align-items: center; gap: var(--space-12); margin-top: var(--space-32);
  font: 600 20px/1.3 var(--font-display); color: var(--lead);
}
.cmp__value svg { flex: none; color: var(--chalk-blue); }
@media (max-width: 559px) {
  .cmp__season { padding-inline: var(--space-16); }
  .cmp__after { font-size: 16px; }
  .cmp__value { align-items: flex-start; font-size: 18px; }
}

/* Callout */
.callout { border-left: var(--chalk-line-height) solid var(--chalk-blue); padding: var(--space-16) 0 var(--space-16) var(--space-24); background: transparent; }
.callout p { color: var(--text-secondary); }

/* Media figure with mono caption */
/* height:auto so a photograph keeps its own proportions - the markup carries a
   height attribute that would otherwise squash it to a fixed 400px box. */
.figure-media img, .figure-media svg { width: 100%; height: auto; border-radius: var(--radius); }
/* Photographs beside the opening copy share one 4:3 frame, so a tall phone
   shot cannot push the column out of line with the text. */
.figure-media--photo img { aspect-ratio: 4 / 3; object-fit: cover; }
.figure-media figcaption { margin-top: var(--space-12); font: 400 13px/1.5 var(--font-label); color: var(--text-secondary); }

/* --------------------------------------------------------------------------
   16. Footer (5.3) - Lead, three columns, service area in mono
   -------------------------------------------------------------------------- */
.site-footer { background: var(--lead); color: rgba(255, 255, 255, 0.8); border-top: var(--chalk-line-height) solid var(--chalk-blue); }
.site-footer .container { padding-block: var(--space-64) var(--space-32); }
.footer__grid { display: grid; gap: var(--space-48); grid-template-columns: 1fr; }
@media (min-width: 768px) { .footer__grid { grid-template-columns: 1.2fr 1fr 1fr; } }
.footer__col h2 { font: 600 var(--label-size)/1 var(--font-label); letter-spacing: var(--label-tracking); text-transform: uppercase; color: var(--chalk-blue); margin-bottom: var(--space-24); }
.footer__col li + li { margin-top: var(--space-12); }
.footer__col a { color: rgba(255, 255, 255, 0.8); text-decoration: none; font-size: var(--small-size); }
.footer__col a:hover { color: var(--white); }
.footer__areas { font-family: var(--font-label); font-size: 13px; line-height: 2; color: rgba(255,255,255,0.7); }
/* Phone, email and address read as a contact record, not prose. */
/* Same face as the rest of the footer. It was set in mono, which made the
   contact block look like a different site from the columns beside it. */
.footer__contact a, .footer__contact p { font-family: var(--font-body); }
.footer__social a { display: inline-flex; align-items: center; gap: var(--space-8); }
.footer__social svg { width: 18px; height: 18px; stroke: currentColor; flex: none; }
.footer__bottom {
  margin-top: var(--space-48); padding-top: var(--space-24);
  border-top: 1px solid var(--border-inverse);
  display: flex; flex-wrap: wrap; gap: var(--space-16); justify-content: space-between;
  font: 400 13px/1.6 var(--font-body); color: rgba(255, 255, 255, 0.6);
}
.footer__bottom a { color: rgba(255, 255, 255, 0.6); }

/* --------------------------------------------------------------------------
   17. Sticky mobile call bar (5.4)
   -------------------------------------------------------------------------- */
.sticky-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 120;
  display: grid; grid-template-columns: 1fr 1fr;
  background: var(--lead); border-top: var(--chalk-line-height) solid var(--chalk-blue);
  padding: var(--space-12); gap: var(--space-12);
  padding-bottom: calc(var(--space-12) + env(safe-area-inset-bottom));
}
@media (min-width: 1200px) { .sticky-bar { display: none; } }
.sticky-bar .btn { padding: 12px 16px; font-size: 15px; }
body { padding-bottom: 0; }
@media (max-width: 1199px) { body { padding-bottom: 76px; } }

/* --------------------------------------------------------------------------
   17b. Cookie consent banner
        A card, not a modal: the page stays usable behind it. Sits above the
        sticky call bar below 1200px, bottom left on desktop.
   -------------------------------------------------------------------------- */
.consent {
  position: fixed; z-index: 130;
  left: var(--space-16); right: var(--space-16);
  bottom: calc(76px + var(--space-12) + env(safe-area-inset-bottom));
  max-width: 440px;
  background: var(--surface-card); color: var(--text-primary);
  border-top: var(--chalk-line-height) solid var(--chalk-blue);
  border-radius: var(--radius);
  box-shadow: var(--shadow-raised), 0 0 0 1px var(--border-subtle);
  padding: var(--space-24);
}
.consent[hidden] { display: none; }
@media (min-width: 1200px) { .consent { left: var(--space-24); right: auto; bottom: var(--space-24); } }
.consent__title {
  font: var(--h4-weight) 18px/24px var(--font-display);
  margin: 0 0 var(--space-8);
}
.consent__text { font: 400 var(--small-size)/var(--small-line) var(--font-body); color: var(--text-secondary); margin: 0; }
.consent__text a { font-weight: 600; }
.consent__actions {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-12);
  margin-top: var(--space-16);
}
.consent__actions .btn { padding: 12px 16px; font-size: 15px; justify-content: center; }

/* "Cookie settings" in the footer and privacy page: a button that reads as a link */
.footer__link-btn, button.text-link {
  background: none; border: 0; padding: 0; margin: 0; cursor: pointer;
  font: inherit; color: inherit;
}
.footer__link-btn:hover, .footer__link-btn:focus-visible { color: var(--white); text-decoration: underline; }
button.text-link { font-weight: 600; color: var(--accent-deep); padding-bottom: var(--space-4); }

/* --------------------------------------------------------------------------
   18. Placeholder tokens - deliberately conspicuous.
        Every one is listed in PLACEHOLDERS.md and filled by fill-details.ps1
   -------------------------------------------------------------------------- */
.placeholder {
  border-bottom: 2px dotted var(--copper);
  background: rgba(140, 90, 43, 0.07);
  padding: 0 2px;
}
.on-lead .placeholder, .section--inverse .placeholder, .site-footer .placeholder, .hero .placeholder, .sticky-bar .placeholder {
  border-bottom-color: #D89A5C; background: rgba(216, 154, 92, 0.16); color: inherit;
}

/* --------------------------------------------------------------------------
   18b. Owner portrait - the one face on the site
   4.7: square or 4:3, hard to the grid, never circular, never rounded past 4px.
   -------------------------------------------------------------------------- */
.owner { margin: 0; }
.owner__frame {
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--lead);
}
.owner__frame img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Held open until the photograph exists, at the exact ratio it will occupy, so
   dropping the file in shifts nothing on the page. */
.owner__slot {
  height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-12); padding: var(--space-32); text-align: center;
  border: 1px dashed rgba(255, 255, 255, 0.28);
  color: rgba(255, 255, 255, 0.62);
}
.owner__slot .ds-label { color: var(--chalk-blue); }
.owner__slot-note { font: 400 13px/1.6 var(--font-body); max-width: 34ch; }
.owner__slot-note .mono { color: rgba(255, 255, 255, 0.82); font-size: 12px; }
.owner__caption {
  margin-top: var(--space-12);
  font: 400 13px/1.5 var(--font-body); color: var(--text-secondary);
}

/* --------------------------------------------------------------------------
   19. Scroll reveal - measured, not lively (4.9)
   -------------------------------------------------------------------------- */
/* Content is visible by default. Only once JS confirms it is running do we hide
   it to animate it in - otherwise a script failure would blank the whole site. */
.js .reveal { opacity: 0; transform: translateY(12px); }
.js .reveal.is-revealed { opacity: 1; transform: none; transition: opacity var(--duration-reveal) var(--ease-out), transform var(--duration-reveal) var(--ease-out); }

/* Section headings rise in as they enter view. The children animate rather than
   the block, so the strapline, headline and lede arrive in reading order - the
   eye follows the same path it would take anyway, one beat behind. */
.js .section-head > * { opacity: 0; transform: translateY(12px); }
.js .section-head.is-revealed > * {
  opacity: 1; transform: none;
  transition: opacity 500ms var(--ease-out), transform 500ms var(--ease-out);
}
.js .section-head.is-revealed > *:nth-child(2) { transition-delay: 70ms; }
.js .section-head.is-revealed > *:nth-child(3) { transition-delay: 140ms; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; animation-iteration-count: 1 !important; }
  .js .reveal, .reveal { opacity: 1; transform: none; }
  .js .section-head > *, .section-head > * { opacity: 1; transform: none; }
  .js .chalk-line--draw, .chalk-line--draw { transform: scaleX(1); }   /* renders immediately at full width */
}

/* --------------------------------------------------------------------------
   20. Print
   -------------------------------------------------------------------------- */
@media print {
  .site-header, .sticky-bar, .mobile-menu, .filter-bar, .consent { display: none !important; }
  body { background: #fff; padding-bottom: 0; }
  .section { padding-block: 24px; }
}

/* Review attribution - source named, so the quote is checkable */
.review__meta { display: flex; flex-wrap: wrap; gap: var(--space-8) var(--space-16); align-items: baseline; }
.review__source { color: var(--zinc); }

/* --------------------------------------------------------------------------
   21. Landing page - compact hero with the enquiry form in it
   The hero is deliberately short so the stats bar is reachable without
   scrolling on a laptop.
   -------------------------------------------------------------------------- */
.hero--compact { padding-block: var(--space-32) 0; }
@media (min-width: 900px) { .hero--compact { padding-block: var(--space-48) 0; } }

.hero--compact .hero__grid { grid-template-columns: 1fr; gap: var(--space-32); align-items: start; }
@media (min-width: 980px) {
  .hero--compact .hero__grid { grid-template-columns: 1fr 400px; gap: var(--space-64); }
}
.hero--compact .hero__content { padding-bottom: var(--space-48); }
.hero--compact .hero__lede { margin-bottom: var(--space-32); max-width: 52ch; }
.hero--compact h1 { margin-bottom: var(--space-16); }

/* The service spread - states the whole business without repeating the H1 */
.hero__services {
  color: var(--chalk-blue);
  line-height: 1.7;
  margin-bottom: var(--space-16);
  max-width: 46ch;
}

.hero__form { padding-bottom: var(--space-48); }
@media (min-width: 980px) { .hero__form { padding-bottom: var(--space-64); } }
.docket--hero { box-shadow: 0 16px 40px rgba(20, 28, 33, 0.28); }
.docket--hero .docket__body { padding-bottom: var(--space-16); }
.docket--hero .form__row { gap: var(--space-16); }

/* --------------------------------------------------------------------------
   22. Four reasons
   -------------------------------------------------------------------------- */
/* White on the Chalk White page - the same figure-on-ground the service cards
   and reviews use. These previously carried the page colour itself, so once the
   sections stopped alternating they had nothing to stand away from. */
.why__block {
  background: var(--white);
  border-radius: var(--radius);
  padding: var(--space-32);
  display: flex; flex-direction: column; gap: var(--space-12);
  box-shadow: var(--shadow-card);
}
.why__icon svg { width: 40px; height: 40px; stroke: var(--zinc); }
/* A fixed-height slot, so a wide icon (the spirit level) can be shown larger
   without pushing its heading out of line with the others. */
.why__icon { display: flex; align-items: center; height: 56px; }
.why__icon img { display: block; }
.why__title {
  font: 600 var(--h4-size)/1.3 var(--font-display);
  color: var(--lead); margin-top: var(--space-8);
}
.why__body { font: 400 15px/1.6 var(--font-body); color: var(--text-secondary); }

/* --------------------------------------------------------------------------
   23. Service groups + the wider offer
   -------------------------------------------------------------------------- */
.svc {
  background: var(--white);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius);
  padding: var(--space-32);
  display: flex; flex-direction: column; gap: var(--space-12);
  box-shadow: var(--shadow-card);
}
.svc:hover { border-color: var(--chalk-blue); }

/* Card artwork. Sits flush to the card edge, above the padding, so the photo
   reads as the card's own subject rather than an inset thumbnail. */
.svc { padding-top: 0; overflow: hidden; }
.svc__media {
  display: block; margin: 0 calc(var(--space-32) * -1) var(--space-24);
  aspect-ratio: 4 / 3; overflow: hidden; background: var(--lead);
}
.svc__media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
@media (prefers-reduced-motion: reduce) {
  .svc__media img, .svc:hover .svc__media img { transition: none; transform: none; }
}
.svc > .chalk-line { width: 40px; }
.svc__title { font: 600 var(--h3-size)/1.25 var(--font-display); color: var(--lead); }
.svc__body { font: 400 15px/1.6 var(--font-body); color: var(--text-secondary); }
.svc__list {
  display: grid; gap: 0;
  margin-top: var(--space-8); padding-top: var(--space-8);
  border-top: 1px solid var(--border-subtle);
  flex: 1;
}
/* Sized as touch targets, not as inline text - these are real destinations. */
.svc__list a {
  display: flex; align-items: center; min-height: 44px;
  font: 400 13px/1.5 var(--font-label); color: var(--text-secondary); text-decoration: none;
  border-bottom: 1px solid var(--border-subtle);
}
.svc__list li:last-child a { border-bottom: 0; }
.svc__list a:hover { color: var(--accent-deep); }
.svc .text-link { margin-top: var(--space-8); align-self: flex-start; }

/* --------------------------------------------------------------------------
   23b. Finished-work carousel
   -------------------------------------------------------------------------- */
.cw { display: flex; flex-direction: column; gap: var(--space-12); margin: 0; }
.cw__frame { position: relative; border-radius: var(--radius); overflow: hidden; background: var(--lead); }

/* The track is the whole component without JavaScript: a scroll-snapping,
   swipeable list. Buttons are an enhancement layered on top. */
.cw__track {
  display: flex; margin: 0; padding: 0; list-style: none;
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
}
.cw__track::-webkit-scrollbar { display: none; }
.cw__track:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.cw__slide { flex: 0 0 100%; scroll-snap-align: center; }
/* height:auto matters. The <img> carries a height attribute, and aspect-ratio
   is ignored when both dimensions are already resolved - which was rendering
   every slide as a 1:2 portrait and cropping the roof out of frame.
   contain, not cover: these are mixed portrait and landscape phone shots and
   the whole frame has to be visible. */
/* Landscape photographs fill the 3:2 frame edge to edge and take the small
   crop that costs. Only portrait frames are fitted inside it, which is the one
   place bars are wanted - and then only down the sides. */
.cw__slide img {
  width: 100%; height: auto; aspect-ratio: 3 / 2;
  object-fit: cover; display: block;
}
.cw__slide img.is-portrait { object-fit: contain; background: var(--lead); }
/* A carousel sharing a row with a before/after slider takes its 4:3 frame,
   so the two line up at the same height. */
.grid:has(> .ba) > .cw .cw__slide img { aspect-ratio: 4 / 3; }

/* Wrapping the photograph in a button is what makes enlarging reachable from
   the keyboard. It must leave no visual trace of being a button. */
.cw__zoom {
  display: block; width: 100%; padding: 0; margin: 0;
  border: 0; background: none; cursor: zoom-in; font: inherit; color: inherit;
}
.cw__zoom:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }

.cw__nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 44px; height: 44px; padding: 0;
  display: none; align-items: center; justify-content: center;
  background: rgba(20, 28, 33, 0.72); border: 0; border-radius: var(--radius);
  cursor: pointer; transition: background var(--duration-fast) var(--ease-out);
}
.cw--ready .cw__nav { display: flex; }
.cw__nav:hover { background: rgba(20, 28, 33, 0.9); }
.cw__nav:focus-visible { outline: 2px solid var(--white); outline-offset: 2px; }
.cw__nav[disabled] { opacity: 0.3; cursor: default; }
.cw__nav--prev { left: var(--space-12); }
.cw__nav--next { right: var(--space-12); }
.cw__nav::before {
  content: ""; width: 0; height: 0;
  border-top: 7px solid transparent; border-bottom: 7px solid transparent;
}
.cw__nav--prev::before { border-right: 9px solid var(--white); margin-right: 3px; }
.cw__nav--next::before { border-left: 9px solid var(--white); margin-left: 3px; }

.cw__count {
  position: absolute; right: var(--space-12); bottom: var(--space-12); z-index: 3;
  padding: 4px 10px; border-radius: var(--radius);
  background: rgba(20, 28, 33, 0.72); color: var(--white);
  font: 500 12px/1 var(--font-body); letter-spacing: 0.06em;
}

.cw__caption { display: flex; flex-wrap: wrap; gap: var(--space-8) var(--space-16); align-items: baseline; }
.cw__job {
  font: 600 var(--label-size)/1.4 var(--font-label); letter-spacing: 0.06em;
  color: var(--text-secondary); text-transform: uppercase;
}
.cw__meta { font: 400 12px/1.4 var(--font-label); color: var(--text-tertiary, var(--text-secondary)); opacity: 0.75; }

@media (prefers-reduced-motion: reduce) { .cw__track { scroll-behavior: auto; } }

/* Single finished-work frames: one photograph, no sequence behind it. */
.wcard { display: flex; flex-direction: column; gap: var(--space-12); margin: 0; }
.wcard__frame { border-radius: var(--radius); overflow: hidden; background: var(--lead); }
.wcard__frame img {
  width: 100%; height: auto; aspect-ratio: 3 / 2;
  object-fit: cover; display: block;
}
.wcard__frame img.is-portrait { object-fit: contain; background: var(--lead); }
.wcard__caption {
  font: 600 var(--label-size)/1.4 var(--font-label); letter-spacing: 0.06em;
  color: var(--text-secondary); text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   23c. Enquiry section photograph
   -------------------------------------------------------------------------- */
.enquiry { position: relative; overflow: hidden; }
.enquiry__media { position: absolute; inset: 0; z-index: 0; overflow: hidden; }

/* The section is wider than the photograph's own proportions, so cover crops it
   vertically and object-position has no horizontal slack to give. Scaling up
   first creates that slack; the translate then shifts the roof left, out from
   under the enquiry form. Overflow each side is 7%, the shift 4.5%, so the
   frame can never pull away from an edge. */
.enquiry__media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transform: scale(1.14) translateX(-4.5%);
  transform-origin: center;
}

/* Two layers, painted top-down:
   1. a dark panel down the right-hand side so the form sits on near-solid
      ground, easing off to nothing by a third of the way across;
   2. a flat scrim over everything, carrying the white type.
   The brand rules out gradients as a decorative device (3.3). This one is
   doing legibility work behind a form, not decorating - worth knowing it is a
   deliberate exception rather than an oversight. */
.enquiry__media::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to left,
      rgba(20, 28, 33, 0.96) 0%,
      rgba(20, 28, 33, 0.96) 38%,
      rgba(20, 28, 33, 0) 68%),
    rgba(20, 28, 33, 0.72);
}

/* Below the two-column breakpoint the form sits under the text rather than
   beside it, so a right-hand panel would darken the wrong half. */
@media (max-width: 980px) {
  .enquiry__media::after { background: rgba(20, 28, 33, 0.82); }
  .enquiry__media img { transform: none; }
}

.enquiry > .container { position: relative; z-index: 2; }

/* --------------------------------------------------------------------------
   23d. Lightbox
   -------------------------------------------------------------------------- */
.lb { border: 0; padding: 0; background: none; max-width: 100vw; max-height: 100vh; width: 100%; height: 100%; }
.lb::backdrop { background: rgba(20, 28, 33, 0.92); }
.lb__panel {
  position: relative; width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-48) var(--space-24);
}
.lb__figure { margin: 0; max-width: min(1400px, 92vw); max-height: 82vh; display: flex; flex-direction: column; gap: var(--space-16); }
.lb__img {
  max-width: 100%; max-height: 72vh; width: auto; height: auto;
  object-fit: contain; display: block; margin: 0 auto; border-radius: var(--radius);
}
.lb__cap {
  font: 400 14px/1.5 var(--font-body); color: rgba(255, 255, 255, 0.82);
  text-align: center; max-width: 70ch; margin: 0 auto;
}
.lb__count {
  font: 500 12px/1 var(--font-label); letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.6); text-align: center; margin: 0;
}
.lb__nav, .lb__close {
  position: absolute; z-index: 3; width: 48px; height: 48px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, 0.12); border: 0; border-radius: var(--radius); cursor: pointer;
}
.lb__nav:hover, .lb__close:hover { background: rgba(255, 255, 255, 0.24); }
.lb__nav:focus-visible, .lb__close:focus-visible { outline: 2px solid var(--white); outline-offset: 2px; }
.lb__nav[hidden], .lb__close[hidden] { display: none; }
.lb__nav--prev { left: var(--space-16); top: 50%; transform: translateY(-50%); }
.lb__nav--next { right: var(--space-16); top: 50%; transform: translateY(-50%); }
.lb__close { top: var(--space-16); right: var(--space-16); }
.lb__nav::before { content: ""; width: 0; height: 0; border-top: 8px solid transparent; border-bottom: 8px solid transparent; }
.lb__nav--prev::before { border-right: 11px solid var(--white); margin-right: 3px; }
.lb__nav--next::before { border-left: 11px solid var(--white); margin-left: 3px; }
.lb__close::before, .lb__close::after {
  content: ""; position: absolute; width: 20px; height: 2px; background: var(--white);
}
.lb__close::before { transform: rotate(45deg); }
.lb__close::after { transform: rotate(-45deg); }

body.lb-open { overflow: hidden; }

@media (max-width: 700px) {
  .lb__nav--prev { left: var(--space-8); }
  .lb__nav--next { right: var(--space-8); }
  .lb__img { max-height: 64vh; }
}

.also { margin-top: var(--space-64); padding-top: var(--space-32); border-top: var(--chalk-line-height) solid var(--chalk-blue); }
.also__label { color: var(--accent-deep); margin-bottom: var(--space-24); }
.also__grid { display: grid; gap: 0 var(--space-32); grid-template-columns: 1fr; }
@media (min-width: 640px) { .also__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .also__grid { grid-template-columns: repeat(3, 1fr); } }
.also__grid a {
  display: block; padding: var(--space-16) 0;
  border-top: 1px solid var(--border-subtle); text-decoration: none;
}
.also__name { display: block; font: 600 16px/1.4 var(--font-body); color: var(--lead); }
.also__desc { display: block; margin-top: 2px; font: 400 14px/1.5 var(--font-body); color: var(--text-secondary); }
.also__grid a:hover .also__name { color: var(--accent-deep); }

/* --------------------------------------------------------------------------
   24. Header CTA - one line, with breathing room above and below
   -------------------------------------------------------------------------- */
.nav { padding-block: var(--space-12); }
.nav__cta {
  white-space: nowrap;
  padding: 13px 24px;
  line-height: 1;
  align-self: center;
}
.nav__actions { align-items: center; }

/* The service spread sits on two lines, not three */
.hero__services { max-width: 68ch; }

/* --------------------------------------------------------------------------
   25. File attachment control
   The native input is hidden but still focusable via its paired label, so the
   control stays fully keyboard operable.
   -------------------------------------------------------------------------- */
.field--file { display: flex; flex-direction: column; gap: var(--space-8); padding-top: var(--space-16); }
.field--file > label:first-child {
  font: 600 11px/1.4 var(--font-label); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-secondary);
}
.field--file input[type="file"] {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.filebtn {
  display: inline-flex; align-items: center; gap: var(--space-12);
  min-height: 44px; padding: 0 var(--space-16);
  border: 1px dashed var(--zinc); border-radius: var(--radius);
  background: var(--chalk-white);
  font: 500 14px/1.3 var(--font-body); color: var(--lead);
  cursor: pointer;
  transition: border-color var(--duration-fast) var(--ease-out),
              background-color var(--duration-fast) var(--ease-out);
}
.filebtn:hover { border-color: var(--chalk-blue); background: var(--white); }
.field--file input[type="file"]:focus-visible + .filebtn {
  outline: var(--chalk-line-height) solid var(--focus-ring);
  outline-offset: 2px;
}
.filebtn__icon svg { width: 20px; height: 20px; stroke: var(--zinc-deep); }
.filebtn:hover .filebtn__icon svg { stroke: var(--accent-deep); }
.filebtn.has-files { border-style: solid; border-color: var(--chalk-blue); background: var(--white); }
.filebtn.has-files .filebtn__icon svg { stroke: var(--chalk-blue); }

/* Spam honeypot. Off-screen rather than display:none, which some bots detect.
   aria-hidden + tabindex="-1" keep it away from real users entirely. */
.honeypot {
  position: absolute; left: -9999px; top: auto;
  width: 1px; height: 1px; overflow: hidden;
}
