/* EcoKlima Montage — site stylesheet.
   Mobile-first: the single-column layout is the base, each breakpoint adds
   columns. Loaded after tokens.css, which owns every value used here.

   Signature element: a technical-documentation rule system. Hairline 1px
   rules instead of shadows; grids built as 1px-gap grids over a border
   coloured background so cells share single-pixel lines; monospace uppercase
   labels for every eyebrow, section number and metadata key. Green is
   structure and action only — never a gradient, glow or decorative field. */

/* ===========================================================================
   1. Base
   ======================================================================== */

*, *::before, *::after { box-sizing: border-box; }

/* German compounds are what break narrow layouts first — `Klimaanlagen-Wartung
   und Reinigung` and `Einsatzgebiet`. Wrapping and hyphenation are set on the
   text itself rather than hidden with overflow-x, so a real overflow stays
   visible during development instead of being silently clipped. */
body { min-width: 0; }
h1, h2, h3, p, li, span, a { overflow-wrap: break-word; }

/* Anchor jumps animate instead of teleporting, so the visitor keeps their
   bearings on a long single-page site. tokens.css already forces
   scroll-behavior: auto under prefers-reduced-motion.

   Scoped to :has(:target) rather than set on <html> unconditionally, so the
   animation applies to a real anchor jump and not to every scroll the browser
   or a script performs. `scroll-behavior` is not just for clicks: set globally
   it also animates scroll restoration and any element.scrollIntoView() that
   does not pass its own behaviour.

   The skip link is the exception. #inhalt exists so a keyboard user can reach
   the content in one keystroke; animating it makes them sit through a scroll
   to do the thing the control exists to make instant, which defeats WCAG 2.4.1
   (Bypass Blocks).

   The back-to-top button needs no exception here: its href="#top" resolves to
   the document start rather than to an element, so nothing ever matches
   :target and the smooth rule never switches on for it. */
html:has(:target) { scroll-behavior: smooth; }
html:has(#inhalt:target) { scroll-behavior: auto; }

img { max-width: 100%; height: auto; display: block; }

/* Content images are not draggable objects.
 *
 * By default every <img> is a drag source. A click with a few pixels of hand
 * drift between press and release therefore does not produce a click -- it
 * starts the browser's native image drag, which is an OS-level modal loop.
 * Repeat that on a large image and Chromium can be left with a drag it never
 * finishes, after which the page receives no further mouse or keyboard input
 * while scrolling still works and even F12 stops responding, because the stall
 * is in the browser rather than in the page.
 *
 * Reported as "the page freezes if I click 10-15 times on the hero image".
 * The hero is the biggest image on the site and sits exactly where a visitor
 * clicks to dismiss or just fidget, which is why it is the one that shows it.
 *
 * -webkit-user-drag is the property Chromium and Safari honour; the
 * `draggable="false"` attribute would work too but would have to be repeated
 * on every tag and every future template. Firefox needs neither.
 *
 * Deliberately not `user-select: none`: selecting and copying text, including
 * an address or a phone number sitting over an image, stays possible. Only the
 * drag-the-picture-out gesture goes, which nothing on a local-business site
 * needs. Right-click "save image as" is unaffected. */
img { -webkit-user-drag: none; }

/* Links are drag sources too, and this was the other half of the same bug.
 *
 * The rule above covers <img> and was written when the hero was the only known
 * trigger. But an <a href> is draggable by default as well -- that is the
 * "drag this link to a tab" gesture -- and it enters the identical OS-level
 * drag loop from the identical accidental press-drift-release. Suppressing it
 * on images alone left every link on the site still able to stall the browser.
 *
 * It surfaced again on Über uns, which has no hero image but is dense in
 * anchors for how little else it has: breadcrumb, the four value cards, two
 * large CTA buttons, plus header nav and footer. Moving the mouse around that
 * page with the button down is almost entirely time spent on an anchor, so it
 * reproduces the freeze the same way the hero did -- without an image being
 * involved at all.
 *
 * Applied to <a> rather than to a blanket `*` so that only the two genuine
 * drag-source element types are affected, and dragging inside form fields --
 * where moving a selection is a real editing gesture -- keeps working.
 *
 * Text selection is untouched here as well: dragging across link text still
 * selects it, because this suppresses the element-drag gesture, not
 * user-select. */
a { -webkit-user-drag: none; }

a { color: var(--c-navy); text-decoration: none; }
a:hover { color: var(--c-green-dark); }

h1, h2, h3 { margin: 0; letter-spacing: var(--ls-h2); font-weight: 700; }
p { margin: 0; }

/* Skip link — first tab stop, invisible until focused. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--c-navy);
  color: #fff;
  padding: var(--space-3) var(--space-5);
  font-weight: 700;
}
.skip-link:focus {
  left: var(--space-3);
  top: var(--space-3);
  color: #fff;
}

/* ===========================================================================
   2. Layout primitives
   ======================================================================== */

.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 20px;
}
.container--narrow { max-width: var(--container-narrow); }

.section { padding-top: var(--space-7); }
.section--band { padding-block: var(--space-7); }

/* The mobile sticky bar overlays the page bottom; reserve its height so it
   never covers the final element. */
.page { padding-bottom: calc(var(--stickybar-h) + var(--space-4)); }

/* .section carries top spacing only -- it separates a section from the one
   above it, and a bottom padding as well would double every gap in the
   stack. That leaves whichever section lands last running flush into the
   navy footer. The homepage and the service pages happen to end on a
   .section--band, which pads both sides, so only those two looked right.
   Close the gap on the last child instead, so the rhythm above it is
   untouched and a page ending on a band is not padded twice. */
.page > *:last-child.section { padding-bottom: var(--space-7); }

/* Section eyebrow: `01 — Leistungen`. The number carries ordering
   information, so it is content, not decoration. */
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  margin-bottom: var(--space-3);
}
.eyebrow--invers { color: var(--c-navy-label); }

.section-head { margin-bottom: var(--space-6); }
.section-head h2 { font-size: var(--fs-h2); color: var(--c-navy); }
.section-head__lead {
  font-size: var(--fs-body);
  color: var(--c-ink-muted);
  margin-top: var(--space-3);
  max-width: var(--measure);
}
/* Heading row with a trailing link, divided by a hairline. */
.section-head--ruled {
  border-bottom: 1px solid var(--c-border);
  padding-bottom: var(--space-4);
}

/* ===========================================================================
   3. Buttons — full state coverage from the components sheet
   ======================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  padding: var(--space-3) var(--space-6);
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-family: inherit;
  font-size: var(--fs-small);
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  cursor: pointer;
  transition: background-color 150ms, border-color 150ms, color 150ms;
}

/* The fill is green-dark, not the identity green: white on #33B54A is 2.68:1,
   which fails AA on the one control the whole site funnels into. green-dark
   carries the same hue at 5.05:1. The identity green still reads as the brand
   everywhere it is not carrying white text (rules, accents, focus ring). */
.btn--primary { background: var(--c-green-dark); color: var(--c-accent-ink); }
.btn--primary:hover { background: var(--c-green-active); color: var(--c-accent-ink); }
.btn--primary:active { background: var(--c-green-deep); }
/* On navy the hover lightens instead of darkening, so it stays visible. */
.on-navy .btn--primary:hover { background: var(--c-green-hover); }

.btn--secondary {
  background: var(--c-surface);
  border-color: var(--c-border-strong);
  color: var(--c-navy);
}
.btn--secondary:hover {
  background: var(--c-surface-raised);
  border-color: var(--c-navy);
  color: var(--c-navy);
}
.btn--secondary:active { background: #E4E9ED; border-color: var(--c-navy); }

.btn--tertiary {
  min-height: var(--tap-min);
  padding: 0;
  background: none;
  color: var(--c-green-dark);
}
.btn--tertiary:hover { color: var(--c-navy); text-decoration: underline; }
.btn--tertiary:active { color: var(--c-green-active); }

.btn--phone { background: var(--c-navy); color: #fff; white-space: nowrap; }
.btn--phone:hover { background: var(--c-navy-hover); color: #fff; }
.btn--phone:active { background: var(--c-navy-active); }

/* Outlined phone CTA, used on navy where a navy fill would vanish. */
.btn--ghost { border-color: #4A6480; color: #fff; }
.btn--ghost:hover {
  border-color: #fff;
  color: #fff;
  background: rgba(255, 255, 255, 0.06);
}

.btn--lg { font-size: var(--fs-body); padding: var(--space-4) var(--space-7); }
.btn--block { width: 100%; }

.btn:disabled,
.btn[aria-disabled="true"] {
  background: #C9D3D9;
  border-color: transparent;
  color: var(--c-ink-disabled);
  cursor: not-allowed;
}
.btn--secondary:disabled {
  background: var(--c-surface);
  border-color: #E1E7EB;
  color: #A8B3BC;
}

/* Loading: the POST takes a moment, so the button says so. Darker than the
   resting fill, which is already green-dark. */
.btn[aria-busy="true"] { background: var(--c-green-active); }
.btn__spinner {
  width: 12px;
  height: 12px;
  border: 2px solid #fff;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 700ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* White focus ring where the element sits on a green fill. */
.btn--primary:focus-visible { outline: var(--focus-ring-invers); }

/* ===========================================================================
   4. Header
   ======================================================================== */

/* Sticky at every width. The brief argued against this on mobile, where the
   header (56px) and the bottom action bar (64px) together hold ~18% of a
   375x667 screen. Kept anyway on the customer's decision: the phone shortcut
   and the menu stay reachable from anywhere on a long single-page site,
   which is worth more here than the reclaimed pixels.

   position: sticky rather than fixed — it stays in normal flow, so nothing
   below needs a compensating margin and engaging it causes no layout shift. */
.header {
  position: sticky;
  top: 0;
  z-index: 30;
  border-bottom: 1px solid var(--c-border);
  background: var(--c-surface);
}
.header__bar {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  height: 56px;
}

/* Anchors must clear the sticky header or a section's own heading lands
   underneath it. Mobile header is 56px; the desktop block overrides this. */
html { scroll-padding-top: calc(56px + var(--space-3)); }

.logo {
  display: flex;
  align-items: center;
  margin-right: auto;
  min-width: 0;
}

/* The logo is one placed file (see _partials/header.html and
   _partials/footer.html in this theme's template directory).
   height drives the box and width follows, so the aspect ratio comes from the
   file rather than from these numbers agreeing with it; the width/height
   attributes in the markup reserve the space during load.

   No max-width. The lockup is an unshrinkable brand element and the icon
   buttons beside it are flex-shrink:0 tap targets, so a percentage cap could
   only ever squash the logo to protect a row that has other ways to give —
   and because height drives width, a capped width silently breaks the ratio.
   The steps below shrink it deliberately instead. */
.logo__lockup {
  height: 44px;
  width: auto;
  flex-shrink: 0;
}

/* <picture> is an inline box by default, so it contributes a baseline and a
   few pixels of descender space inside the flex row. Making it a flex item in
   its own right removes that without needing a line-height override. */
.logo picture { display: flex; }

/* The footer column has no competing controls, so it runs larger. */
.logo__lockup--footer { height: 52px; }

/* Narrow phones. At 320px the bar has roughly 170px left for the logo once
   two 44px tap targets and the gutters are taken out, so the lockup steps down
   rather than pushing the buttons off the edge. It stops at 34px: below that
   MONTAGE stops resolving, and losing the wordmark costs more than the few
   pixels gained. */
@media (max-width: 400px) {
  .logo__lockup { height: 38px; }
  .logo__lockup--footer { height: 46px; }
}
@media (max-width: 340px) {
  .logo__lockup { height: 34px; }
}

/* Icon buttons must hold 44x44 even though the glyph is small. As flex items
   they would otherwise shrink below the minimum tap target — the logo is an
   unshrinkable text run, so without flex-shrink:0 here the buttons collapse
   to a couple of pixels and get pushed off the edge of the viewport. */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--tap-min);
  min-width: var(--tap-min);
  height: var(--tap-min);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
  color: var(--c-navy);
  font-size: 19px;
  cursor: pointer;
}
.icon-btn:hover { border-color: var(--c-green); color: var(--c-green-dark); }
/* `hidden` is an attribute the UA styles as display:none, and any explicit
   display above wins over it. The menu toggle ships hidden and is revealed by
   site.js once the panel works, so without this it stayed visible and inert
   whenever the script failed -- the exact state the baseline navigation exists
   to cover. Applies to every .icon-btn, because the same trap is one
   display declaration away for any of them. */
.icon-btn[hidden] { display: none; }

.header__mobile { display: flex; align-items: center; gap: var(--space-2); flex-shrink: 0; }
.header__desktop { display: none; }

/* Baseline navigation.
 *
 * Always rendered, and removed by site.js once the enhanced panel is wired up.
 * So these rules apply whenever the toggle cannot work: scripting disabled,
 * site.js blocked or failed to parse, or an error before the handlers were
 * attached. Previously this lived in <noscript>, which covered only the first
 * of those.
 *
 * Styled as a plain stacked list rather than a facsimile of the panel: nothing
 * opens or closes it, so it should not look like something that does. That is
 * also what makes it safe to ship visible -- no open/closed state to strand,
 * no focus trap, no scroll lock.
 *
 * Above the desktop breakpoint the real nav is visible anyway, so this is
 * hidden there to avoid showing the links twice. */
.nav-fallback {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4) var(--space-4);
  border-bottom: 1px solid var(--c-border);
  background: var(--c-surface);
}
.nav-fallback a { padding-block: var(--space-2); }

/* Mobile navigation panel: full-height navy, opens without layout shift. */
.mobile-nav {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--c-navy);
  color: #fff;
  display: flex;
  flex-direction: column;
  padding: var(--space-5) 20px var(--space-8);
  overflow-y: auto;
}
.mobile-nav[hidden] { display: none; }
.mobile-nav__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-7);
}
.mobile-nav__close {
  width: var(--tap-min);
  height: var(--tap-min);
  background: none;
  border: 1px solid var(--c-navy-line);
  border-radius: var(--radius);
  color: #fff;
  font-size: 22px;
  cursor: pointer;
}
.mobile-nav__list { display: flex; flex-direction: column; }
.mobile-nav__list a {
  display: flex;
  align-items: center;
  min-height: 52px;
  border-bottom: 1px solid var(--c-navy-line);
  color: #fff;
  font-size: var(--fs-body-lg);
  font-weight: 600;
}
.mobile-nav__list a:hover { color: var(--c-green-hover); }
.mobile-nav__actions { margin-top: var(--space-7); display: grid; gap: var(--space-3); }

/* Language switch, designed but not built — marked so it reads as unbuilt. */
.lang {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
}
.lang a { padding: var(--space-2); border-radius: var(--radius); color: var(--c-ink-muted); }
.lang a[aria-current="true"] { background: var(--c-green-tint); color: var(--c-navy); }
.on-navy .lang a { color: var(--c-navy-label); }
.on-navy .lang a[aria-current="true"] { background: rgba(255,255,255,0.1); color: #fff; }

/* ===========================================================================
   5. Hero
   ======================================================================== */

.hero {
  background: var(--c-navy);
  color: #fff;
  border-bottom: 6px solid var(--c-green); /* the closing green rule */
}
/* padding-block only: these elements also carry .container, and the padding
   shorthand would zero its horizontal gutter. */
.hero__grid { display: grid; gap: var(--space-7); padding-block: var(--space-8); }
.hero__kicker { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-5); }
.hero__kicker::before {
  content: "";
  width: 28px;
  height: 1px;
  background: var(--c-green);
  flex-shrink: 0;
}
.hero h1 {
  font-family: var(--font-display);
  font-size: 31px;
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
  margin-bottom: var(--space-5);
}
.hero h1 em { font-style: normal; color: var(--c-green); }
.hero__sub {
  font-size: var(--fs-body-lg);
  line-height: 1.6;
  color: var(--c-navy-ink-muted);
  margin-bottom: var(--space-7);
  max-width: 46ch;
}
.hero__cta { display: flex; flex-direction: column; gap: var(--space-3); }
.hero__cta .btn { width: 100%; }
.hero__points {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  margin-top: var(--space-6);
  font-size: var(--fs-fine);
  color: var(--c-navy-ink-muted);
}
/* The image follows the CTAs on mobile so the conversion path stays above
   the fold. It is the LCP element. */
.hero__media { order: 2; align-self: stretch; display: flex; align-items: center; }
.hero__media > * { width: 100%; }
/* Matches the placeholder box, so swapping a real photo in causes no shift. */
.hero__img { aspect-ratio: 4 / 5; object-fit: cover; border: 1px solid #2A4A69; }

/* ===========================================================================
   6. Media placeholder — every image box until real photos arrive
   ======================================================================== */

.ph-img {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: var(--space-4);
  background-image: repeating-linear-gradient(
    135deg, #EEF2F5 0, #EEF2F5 6px, #F7F9FB 6px, #F7F9FB 12px
  );
  border: 1px solid var(--c-border);
}
.ph-img__caption {
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  line-height: 1.7;
  color: var(--c-ink-muted);
}
.ph-img--invers {
  background-image: repeating-linear-gradient(
    135deg, #12304F 0, #12304F 6px, #0F2A45 6px, #0F2A45 12px
  );
  border-color: #2A4A69;
}
.ph-img--invers .ph-img__caption { color: #9FC0D6; }
.ph-img__subject { color: var(--c-green); }

.ratio-4-5 { aspect-ratio: 4 / 5; }
.ratio-16-10 { aspect-ratio: 16 / 10; }
.ratio-4-3 { aspect-ratio: 4 / 3; }

/* ===========================================================================
   7. Placeholder state — content the client has not confirmed
   ======================================================================== */

.placeholder {
  border: 1px dashed var(--c-placeholder-border);
  background: var(--c-placeholder-bg);
  border-radius: var(--radius);
  padding: var(--space-5);
  color: var(--c-ink);
}
.placeholder__tag {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-placeholder-ink);
  margin-bottom: var(--space-3);
}
.placeholder__title { font-size: var(--fs-body); font-weight: 700; color: var(--c-navy); }
.placeholder__body {
  font-size: var(--fs-fine);
  line-height: 1.6;
  color: #7A6634;
  margin-top: var(--space-1);
}

/* ===========================================================================
   8. Problem routing — a routing device, not a content section
   ======================================================================== */

.routing { display: grid; gap: var(--space-3); }
.routing__card {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 88px;
  padding: var(--space-4);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
  transition: border-color 150ms, background-color 150ms;
}
.routing__card:hover { border-color: var(--c-green); background: var(--c-green-tint-2); }
.routing__title { font-size: 16px; font-weight: 600; line-height: var(--lh-snug); color: var(--c-ink); }
.routing__target {
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-green-dark);
}

/* ===========================================================================
   9. Service cards — must look correct with and without an image
   ======================================================================== */

.cards { display: grid; gap: var(--space-5); }

.card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
  overflow: hidden;
  transition: border-color 150ms;
}
.card:hover { border-color: #B9C6D1; }
.card__media { border-bottom: 1px solid var(--c-border); }
.card__body { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-5); flex: 1; }
.card__code {
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  letter-spacing: 0.2em;
  color: var(--c-ink-muted);
}
.card__title { font-family: var(--font-display); font-size: var(--fs-h3); color: var(--c-navy); }
.card__text { font-size: var(--fs-small); line-height: 1.6; color: var(--c-ink-muted); }
.card__link { margin-top: auto; }

/* The whole card is one link. Kept as a flex column so the body still fills
   the card and "Mehr erfahren" still sits at the bottom, and the focus ring
   is drawn on the card rather than around a text fragment inside it. */
.card__hit {
  display: flex;
  flex-direction: column;
  flex: 1;
  color: inherit;
  text-decoration: none;
}
.card__hit:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
}
.card:has(.card__hit:hover) { border-color: var(--c-green); }
.card:has(.card__hit:hover) .card__title { color: var(--c-green-dark); }

/* --- Testimonials -------------------------------------------------------- */

/* Same column rhythm as the project cards. figure and blockquote carry a
   40px browser indent each; both are reset here. */
.quotes { display: grid; gap: var(--space-5); grid-template-columns: 1fr; }
@media (min-width: 640px) { .quotes { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1120px) { .quotes { grid-template-columns: repeat(3, 1fr); } }
.quotes > .placeholder { grid-column: 1 / -1; }

.quote {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0;
  padding: var(--space-6);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
}
.quote__mark { color: var(--c-green); }
.quote__text {
  flex: 1;
  margin: 0;
  font-size: var(--fs-body-lg);
  line-height: 1.6;
  color: var(--c-ink);
}
.quote__author {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-top: var(--space-4);
  border-top: 1px solid var(--c-border-subtle);
}
.quote__avatar {
  flex: 0 0 44px;
  display: grid;
  place-items: center;
  height: 44px;
  border-radius: 50%;
  background: var(--c-green-tint);
  color: var(--c-green-dark);
  font-weight: 700;
}
.quote__name { display: block; font-size: var(--fs-small); font-weight: 700; color: var(--c-navy); }
.quote__meta { display: block; font-size: var(--fs-fine); color: var(--c-ink-muted); }

/* ===========================================================================
   10. Why — hairline grid sharing single-pixel lines
   ======================================================================== */

.band { background: var(--c-surface-raised); border-block: 1px solid #E4E9ED; margin-top: var(--space-8); }
.band--navy { background: var(--c-navy); color: #fff; border-block: 0; }

.why { display: grid; gap: var(--space-7); }
.why__lead { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--c-ink-muted); max-width: 44ch; }

/* 1px gaps over a border-coloured background: cells share one hairline. */
.hairline-grid {
  display: grid;
  gap: 1px;
  background: var(--c-border);
  border: 1px solid var(--c-border);
}
.hairline-grid > * {
  background: var(--c-surface);
  padding: var(--space-6) var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.reason__no {
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  letter-spacing: 0.2em;
  /* 10px text needs the full 4.5:1; the identity green is 2.7:1 on white. */
  color: var(--c-green-dark);
}
.reason__title { font-size: var(--fs-body); font-weight: 700; color: var(--c-navy); }
.reason__body { font-size: var(--fs-fine); line-height: 1.6; color: var(--c-ink-muted); }

/* ===========================================================================
   11. Process — visually quiet: reassurance, not spectacle
   ======================================================================== */

.process { display: grid; border-top: 1px solid var(--c-navy); }
.process__step {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5) 0;
  border-bottom: 1px solid var(--c-border);
}
.process__no {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--c-navy);
}
.process__title { font-size: var(--fs-body-lg); font-weight: 700; color: var(--c-navy); }
.process__body { font-size: var(--fs-small); line-height: 1.6; color: var(--c-ink-muted); }

/* ===========================================================================
   12. Service area — static illustration, never a map embed
   ======================================================================== */

.areas { display: grid; gap: var(--space-7); align-items: center; }
.area-chips { display: flex; flex-wrap: wrap; gap: var(--space-3); }
/* Ink on the light surfaces by default; white only on the navy band. The chip
   used to be white everywhere, which on /einsatzgebiet/ and the area pages put
   the town names white on white. */
.area-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius);
  color: var(--c-ink);
  font-size: var(--fs-small);
}
.area-chip:hover { border-color: var(--c-green-dark); background: var(--c-green-tint); color: var(--c-ink); }
.on-navy .area-chip { border-color: #3E5773; color: #fff; }
.on-navy .area-chip:hover { border-color: var(--c-green); background: rgba(51, 181, 74, 0.12); color: #fff; }
.area-chip__tag { font-family: var(--font-mono); font-size: var(--fs-label-sm); color: var(--c-navy-label); }
/* Not a link: the business has not confirmed it serves this town. Dashed to
   read as unconfirmed rather than as a disabled link. */
.area-chip--unconfirmed {
  border-style: dashed;
  border-color: var(--c-placeholder-border);
  color: var(--c-navy-ink-muted);
  cursor: default;
}

/* Map card (_partials/map_card.html): a link out to Google Maps, never an
   embed -- nothing loads from Google until the visitor clicks, so no cookie
   banner (build-spec §11.2). The grid and pin are decoration drawn in CSS;
   colours are set as custom properties so the navy band variant only swaps
   values. Classes rather than inline styles: the CSP forbids style attributes. */
.map-card {
  --map-bg: #EEF2F5;
  --map-grid: #DCE3EA;
  --map-grid-major: #CBD5DE;
  --map-edge: var(--c-border);
  --map-text: var(--c-navy);
  --map-muted: var(--c-ink-muted);
  --map-cta: var(--c-green-dark);
  --map-label: var(--c-ink-muted);
}
.map-card--dark {
  --map-bg: #0A2039;
  --map-grid: #11294A;
  --map-grid-major: #1A365A;
  --map-edge: #2A4A69;
  --map-text: #FFFFFF;
  --map-muted: var(--c-navy-label);
  --map-cta: var(--c-green);
  --map-label: var(--c-navy-label);
}
.map-card__label {
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--map-label);
  margin: 0 0 var(--space-3);
}
.map-card__link {
  display: block;
  border: 1px solid var(--map-edge);
  border-radius: var(--radius);
  overflow: hidden;
  color: var(--map-text);
  text-decoration: none;
  transition: border-color 0.15s ease;
}
.map-card__link:hover { border-color: var(--c-green); }
.map-card__link:focus-visible { outline: var(--focus-ring); outline-offset: 3px; }
.map-card__plot {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 9;
  background-color: var(--map-bg);
  background-image:
    linear-gradient(var(--map-grid-major) 1px, transparent 1px),
    linear-gradient(90deg, var(--map-grid-major) 1px, transparent 1px),
    linear-gradient(var(--map-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--map-grid) 1px, transparent 1px);
  background-size: 96px 96px, 96px 96px, 24px 24px, 24px 24px;
  background-position: center;
}
.map-card__plot--empty { border: 1px dashed var(--map-edge); border-radius: var(--radius); }
.map-card__pin {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  color: #FFFFFF;
  background: var(--c-green-dark);
  box-shadow: 0 0 0 8px rgba(51, 181, 74, 0.22);
  transition: transform 0.15s ease;
}
.map-card__link:hover .map-card__pin { transform: translateY(-3px); }
.map-card__body {
  display: grid;
  gap: 2px;
  padding: var(--space-4);
  border-top: 1px solid var(--map-edge);
}
.map-card__place { font-weight: 700; font-size: 18px; color: var(--map-text); }
.map-card__address { font-size: var(--fs-small); color: var(--map-muted); }
.map-card__cta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: var(--space-2);
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--map-cta);
}
.map-card__link:hover .map-card__cta { text-decoration: underline; text-underline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .map-card__link,
  .map-card__pin { transition: none; }
  .map-card__link:hover .map-card__pin { transform: none; }
}

/* ===========================================================================
   13. FAQ — native <details>, works with no JS
   ======================================================================== */

.faq { display: grid; gap: var(--space-7); }
.faq__list { border-top: 1px solid var(--c-border); }
.faq__item { border-bottom: 1px solid var(--c-border); }
.faq__item > summary {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  min-height: var(--tap-min);
  padding: var(--space-5) 0;
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--c-navy);
  cursor: pointer;
  list-style: none;
}
.faq__item > summary::-webkit-details-marker { display: none; }
/* Firefox and Safari still paint a default triangle on the summary itself. */
.faq__item > summary { display: flex; }
.faq__marker {
  font-family: var(--font-mono);
  font-size: var(--fs-body-lg);
  line-height: 1;
  font-weight: 700;
  /* The +/- glyph is the only open/closed affordance, so it carries meaning
     and needs contrast: 19px bold sits just under the 18.66px large-text
     threshold, where the identity green's 2.7:1 fails. */
  color: var(--c-green-dark);
  flex-shrink: 0;
  width: 12px;
  text-align: center;
  padding-top: 3px;
}
.faq__item[open] .faq__marker::before { content: "−"; }
.faq__item:not([open]) .faq__marker::before { content: "+"; }
.faq__answer {
  padding: 0 0 var(--space-5) calc(var(--space-4) + 11px);
  font-size: var(--fs-body);
  line-height: var(--lh-long);
  color: var(--c-ink-muted);
  max-width: 68ch;
}

/* ===========================================================================
   14. Lead form — must not look like a form
   ======================================================================== */

.enquiry { display: grid; gap: var(--space-7); }
.enquiry__phone-card {
  display: block;
  background: var(--c-navy);
  color: #fff;
  border-radius: var(--radius);
  padding: var(--space-6);
}
.enquiry__phone-card:hover { background: var(--c-navy-hover); color: #fff; }
.enquiry__phone-label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--c-navy-label);
  margin-bottom: var(--space-2);
}
.enquiry__phone-number { display: block; font-size: 26px; font-weight: 700; letter-spacing: -0.01em; }

.form-card {
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  padding: var(--space-6);
}
.form-grid { display: grid; gap: var(--space-5); }

/* min-width:0 stops a long help string from forcing the grid column wider
   than its track — German help text overflows the field without it. */
.field { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.field__label { font-size: var(--fs-small); font-weight: 700; color: var(--c-navy); }
.field__optional { font-weight: 400; color: var(--c-ink-muted); }
.field__help { font-size: var(--fs-fine); color: var(--c-ink-muted); }

/* 16px minimum prevents iOS zooming the page on focus. */
.field input,
.field select,
.field textarea {
  min-height: 50px;
  width: 100%;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  font-family: inherit;
  font-size: 16px;
  color: var(--c-ink);
  background: var(--c-surface);
}
.field textarea { resize: vertical; line-height: var(--lh-body); }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--c-navy); }

/* Error: 2px border AND a `!` glyph AND text. Never colour alone. */
.field--error input,
.field--error select,
.field--error textarea { border: 2px solid var(--c-error); }
.field__error {
  display: flex;
  gap: var(--space-2);
  font-size: var(--fs-fine);
  color: var(--c-error);
}
.field__error::before { content: "!"; font-weight: 700; }

.field input:disabled, .field select:disabled, .field textarea:disabled {
  border-color: #E1E7EB;
  background: var(--c-surface-raised);
  color: var(--c-ink-disabled);
}

/* Wraps because the error message is a third item in this row: without it the
   message shared the line with the box and the consent text and was squeezed
   to ~62px on a 390px screen. It now wraps to its own full-width line. */
.field--check { flex-direction: row; flex-wrap: wrap; align-items: flex-start; gap: var(--space-3); }
.field--check input { width: 20px; height: 20px; min-height: 0; margin-top: 2px; accent-color: var(--c-green); flex-shrink: 0; }
/* Scoped off .field__error: a bare `.field--check span` also beat the error
   rule on specificity and painted the message grey. */
.field--check span:not(.field__error) { font-size: var(--fs-fine); line-height: 1.6; color: var(--c-ink-muted); }
/* The consent text takes the rest of the row beside the 20px box. */
.field--check > span:not(.field__error) { flex: 1 1 0; min-width: 0; }
/* The error drops to its own full-width line under both. */
.field--check > .field__error { flex: 0 0 100%; }
.field--check a { color: var(--c-green-dark); font-weight: 600; text-decoration: underline; }

/* A native checkbox draws no border, so the rule above is invisible on the
   consent box -- the one field a visitor is most likely to miss. Outline
   rather than border: it needs no layout space, so nothing shifts when the
   error appears. The label reddens too, because the box alone is a 20px
   target and colour is never the only signal (the `!` text still shows). */
.field--check.field--error input {
  outline: 2px solid var(--c-error);
  outline-offset: 2px;
}
.field--check.field--error > span:not(.field__error) { color: var(--c-error); }

.form-actions { display: flex; align-items: center; gap: var(--space-5); margin-top: var(--space-6); flex-wrap: wrap; }

/* ===========================================================================
   15. Alerts
   ======================================================================== */

.alert {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-left: 3px solid;
  border-radius: var(--radius);
  font-size: var(--fs-small);
  line-height: 1.6;
}
/* The marker keeps its intrinsic width; the message beside it takes the rest
   of the first line rather than splitting it with any following element. */
.alert::before { flex: 0 0 auto; font-weight: 700; }
/* The first message shares the marker's line and absorbs the leftover width;
   without a basis it would size to its content and any sibling would crowd
   onto the same row. */
.alert > *:not(.alert__detail) { flex: 1 1 0; min-width: 0; }
.alert--success { background: var(--c-success-bg); border-color: var(--c-success); color: #16321C; }
.alert--success::before { content: "✓"; color: var(--c-success); }
.alert--error { background: var(--c-error-bg); border-color: var(--c-error); color: #3E1512; }
.alert--error::before { content: "!"; color: var(--c-error); }
/* A form-level message inside the summary: "phone or e-mail", which belongs
   to no single field. It is a flex item, so `display: block` alone left it
   sharing the row with the marker and the heading text -- about 144px of a
   296px box on a 390px screen, wrapping to four lines. flex-basis: 100% puts
   it on its own full-width line instead. */
.alert__detail {
  flex: 0 0 100%;
  margin-top: 0;
  font-weight: 600;
}
.alert--info { background: var(--c-info-bg); border-color: var(--c-info); color: var(--c-navy); }
.alert--info::before { content: "i"; color: var(--c-info); }

/* ===========================================================================
   16. Empty state — never an empty grid, never skeletons
   ======================================================================== */

.empty {
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface-sunken);
  padding: var(--space-8) var(--space-5);
  text-align: center;
}
.empty__title { font-family: var(--font-display); font-size: var(--fs-h3); color: var(--c-navy); margin-bottom: var(--space-3); }
.empty__body { font-size: var(--fs-body); color: var(--c-ink-muted); max-width: 52ch; margin: 0 auto var(--space-6); }
.empty__actions { display: flex; gap: var(--space-3); justify-content: center; flex-wrap: wrap; }

/* ===========================================================================
   17. Footer
   ======================================================================== */

.footer { background: var(--c-navy); color: var(--c-navy-ink-muted); }

/* Exact values from the design handoff rather than the nearest space token:
   the footer uses 10px, 14px, 6px and 32px, none of which are on the scale.
   Rounding each to a token drifted the whole block by a few pixels per row. */
/* Both footer rows carry `container` as well, and .container sets `padding`
   as a SHORTHAND that is redeclared at every breakpoint -- after these rules.
   A bare `padding-block` here is therefore wiped back to 0 from 640px up,
   which stripped the design's 64px top gap on every desktop width while
   mobile (where no .container override follows) kept it. Declaring the
   padding as one shorthand fixes the vertical axis for good; the inline
   value then ramps with the container at each breakpoint below, reaching
   the artboard's `padding:64px 40px 32px` on desktop. */
.footer__grid {
  display: grid;
  gap: 48px;
  padding: 64px 20px 32px;
}
.footer__group {
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: var(--fs-small);
}
/* Links are set tight. Without this each 15px link inherits --lh-body (1.65)
   from <body> and occupies a 25px box, which is what made the rows tall. */
.footer__group a { line-height: 1.35; }

/* Touch: the tight line-height above left a 20px-tall target with a 10px gap
   between rows. The padding grows the hit area to ~40px and the negative gap
   keeps the designed rhythm, so the rows look unchanged but are reachable.
   Padding rather than min-height: it stays inside the inline-block box and
   does not stretch the link's underline or hover area sideways. */
@media (max-width: 899px) {
  .footer__group { gap: 0; }
  .footer__group a:not(.logo) { padding-block: 10px; }
  /* The phone/e-mail pairing keeps its deliberate spacing (see below), minus
     the padding now carried by the links themselves. */
  .footer__phone { margin-top: 6px; }
  .footer__email { margin-top: 0; }
}
.footer__group .logo { margin-bottom: 14px; }
.footer__about { font-size: var(--fs-small); line-height: 1.7; margin: 0; }
.footer__heading {
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--c-navy-label);
  margin-bottom: 6px;
}
.footer a { color: var(--c-navy-ink-muted); }
.footer a:hover { color: var(--c-green-hover); }
.footer__phone {
  display: inline-block;
  margin-top: 16px;
  font-size: 18px;
  font-weight: 700;
  color: #fff;
  line-height: 1.2;
}

/* Sits directly under .footer__phone as the quieter second contact route, so
   it takes the column's body size rather than the phone's 18px bold. The
   column is a flex stack with gap:10px; 6px here closes that to a deliberate
   pairing, so the two read as one contact block instead of two list items. */
.footer__email {
  display: inline-block;
  margin-top: 6px;
  font-size: var(--fs-small);
  line-height: 1.35;
  color: var(--c-navy-ink-muted);
  word-break: break-word;
}
.footer__email:hover { color: var(--c-green-hover); }

.footer__legal {
  border-top: 1px solid var(--c-navy-line);
  /* Same shorthand reason as .footer__grid above; artboard: 20px 40px 40px.
     The bottom value also clears the fixed sticky bar: the footer is a sibling
     of <main>, so .page's reservation never applied to it and the bar sat on
     top of the copyright line, which could not be scrolled into view. The
     designed 40px is kept and the bar's height added to it, so the line holds
     its gap above the bar rather than resting against it. Above 900px the bar
     is gone and the breakpoint rules below drop back to a plain 40px. */
  padding: 20px 20px calc(40px + var(--stickybar-h));
  font-size: 13px;
  color: #7A96AE;
}
.footer__note {
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  line-height: 1.6;
  color: #5E7B96;
}

/* ===========================================================================
   18. Mobile sticky bar — hidden while the form is in view
   ======================================================================== */

.stickybar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  height: var(--stickybar-h);
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1px solid var(--c-navy-line);
  background: var(--c-navy);
}
.stickybar[hidden] { display: none; }
.stickybar a {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  color: #fff;
  font-size: var(--fs-body);
  font-weight: 700;
}
/* The button fill, not the brand green: white on --c-green is 2.7:1 (tokens.css). */
.stickybar a + a { background: var(--c-green-dark); }
.stickybar a:hover { color: #fff; }

/* ===========================================================================
   18b. Back to top
   ======================================================================== */

/* Square with a hairline border rather than a floating circle with a shadow:
   the signature element is technical-drawing restraint, and a glowing round
   FAB would read as a generic template. */
.to-top {
  position: fixed;
  right: 20px;
  /* Clears the mobile sticky bar. On desktop the bar is gone and the offset
     collapses to a plain margin (see the 900px block). */
  bottom: calc(var(--stickybar-h) + var(--space-4));
  z-index: 35;

  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);

  border: 1px solid var(--c-navy-line);
  border-radius: var(--radius);
  background: var(--c-navy);
  color: #fff;
  font-size: 20px;
  line-height: 1;

  /* Revealed by site.js once the visitor has scrolled. Animating opacity and
     transform only keeps this off the layout path. */
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 180ms, transform 180ms, background-color 150ms;

  /* Invisible must also mean intangible.
   *
   * This is the default state for every page view: site.js removes the
   * `hidden` attribute to activate the control, and until the visitor has
   * scrolled a viewport there is no [data-visible] either -- so the element
   * matches this rule alone. Without this line it is a fully clickable 44x44
   * fixed box at opacity 0, parked in the bottom-right corner of every page,
   * silently swallowing every click that lands on it.
   *
   * That is what "the page is frozen and needs a reload" turned out to be: not
   * a frozen page, a dead zone over the corner. A reload appeared to fix it
   * because the visitor usually scrolled afterwards, which reveals the button
   * and makes the same area behave as the control it looks like.
   *
   * [data-visible] below restores pointer-events when the button is actually
   * on screen, so the working state is unchanged. */
  pointer-events: none;
}
.to-top[hidden] {
  /* Overrides the UA's display:none so the fade can run; pointer-events keeps
     it unclickable while invisible. */
  display: flex;
  pointer-events: none;
}
.to-top[data-visible] {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.to-top:hover { background: var(--c-navy-hover); color: #fff; }
.to-top:active { background: var(--c-navy-active); }

/* ===========================================================================
   19. Breakpoints — each adds columns to the mobile base
   ======================================================================== */

@media (min-width: 640px) {
  .container { padding: 0 24px; }
  .footer__grid { padding: 64px 24px 32px; }
  .footer__legal { padding: 20px 24px calc(40px + var(--stickybar-h)); }
  .section { padding-top: var(--space-8); }
  .page > *:last-child.section { padding-bottom: var(--space-8); }
  .section--band { padding-block: var(--space-8); }
  .hero h1 { font-size: 38px; }
  .hero__cta { flex-direction: row; flex-wrap: wrap; }
  .hero__cta .btn { width: auto; }

  .routing { grid-template-columns: repeat(2, 1fr); }
  .cards { grid-template-columns: repeat(2, 1fr); }
  .hairline-grid { grid-template-columns: repeat(2, 1fr); }
  .process { grid-template-columns: repeat(2, 1fr); }
  .footer__grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 900px) {
  .container { padding: 0 32px; }
  .footer__grid { padding: 64px 32px 32px; }
  .footer__legal { padding: 20px 32px 40px; }
  .section { padding-top: var(--space-9); }
  .page > *:last-child.section { padding-bottom: var(--space-9); }
  .section--band { padding-block: var(--space-9); }
  .page { padding-bottom: 0; } /* sticky bar is gone from here up */
  .stickybar { display: none; }
  /* No bottom bar to clear, so the button sits on a plain margin. */
  .to-top { bottom: var(--space-6); right: var(--gutter); }


  .hero__grid { grid-template-columns: 1fr 1fr; gap: var(--space-9); align-items: center; min-height: 480px; }
  .hero h1 { font-size: 44px; }
  .hero__media { order: 0; } /* beside the copy once there is room */

  .routing { grid-template-columns: repeat(3, 1fr); }
  .why { grid-template-columns: 1fr 1fr; }
  .process { grid-template-columns: repeat(4, 1fr); }
  .process__step { padding: var(--space-5) var(--space-6) var(--space-6) 0; border-bottom: 0; border-right: 1px solid var(--c-border); }
  .process__step:last-child { border-right: 0; }
  .areas { grid-template-columns: 1fr 1fr; }
  .faq { grid-template-columns: 1fr 1.6fr; }
  .enquiry { grid-template-columns: 1fr 1.25fr; }
  .form-grid { grid-template-columns: 1fr 1fr; }
  .form-grid .field--wide { grid-column: span 2; }
  .footer__grid { grid-template-columns: 1.3fr 1fr 1fr 1fr; }
}

/* The desktop header needs ~1220px measured: logo (184px, never shrinks) +
   six nav labels + language switch + phone block + CTA, none of which wrap.
   Swapping at 900px overflowed the bar by up to 143px and crushed the logo.
   Trimming the gaps only moved the failure a little; the honest fix is to
   keep the mobile bar until the row genuinely fits. */
/* 1220px is --bp-header in tokens.css. A media query cannot read a custom
   property, so the number is repeated here -- but it is declared there, and
   site.js reads it from there rather than hard-coding its own copy. Changing
   the header breakpoint means changing --bp-header and this query together;
   the script follows automatically.

   That coupling is the fix for a real bug: the script used to watch 900px
   while this query switched at 1220px, so a resize between the two hid the
   panel by CSS while the DOM still held it open and the body stayed
   scroll-locked. */
@media (min-width: 1220px) {
  /* Desktop header row replaces the mobile bar. */
  .header__bar { height: var(--header-h); gap: var(--space-6); }
  .header__mobile { display: none; }
  /* The wordmark is the brand mark: it must never be squeezed to make room
     for navigation. Without this it collapses to ~15px just above the
     breakpoint, because everything to its right refuses to wrap. */
  .logo { flex-shrink: 0; }

  /* The header is 88px from here up, so anchors need more clearance than the
     56px mobile bar requires. */
  html { scroll-padding-top: calc(var(--header-h) + var(--space-4)); }
  /* .logo keeps its margin-right:auto from the mobile rules, which together
     with .header__desktop's margin-left:auto splits the free space. Measured
     gap at 1280px is 52px. */
  .header__desktop { display: flex; align-items: center; gap: var(--space-4); margin-left: auto; }
  .mobile-nav { display: none !important; }
  .nav-fallback { display: none; }

  /* Tight but readable. The header carries logo + six labels + language
     switch + phone + CTA, none of which wrap, so the nav gap is the one place
     with slack; at var(--space-5) the row needed ~1380px to fit. */
  .nav { display: flex; gap: var(--space-4); font-size: var(--fs-small); }
  /* Nav labels, the CTA and the phone number are the one place nowrap is
     correct — everything else wraps freely. */
  .nav a {
    white-space: nowrap;
    flex-shrink: 0;
    padding: var(--space-2) 0;
    border-bottom: 2px solid transparent;
    color: var(--c-ink);
  }
  .nav a:hover { color: var(--c-navy); border-bottom-color: var(--c-green); }
  .nav a[aria-current="page"] { border-bottom-color: var(--c-green); }

  .header__phone {
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-align: right;
    white-space: nowrap;
    flex-shrink: 0;
    padding-right: var(--space-4);
    border-right: 1px solid var(--c-border);
  }
  .header__phone-label {
    font-family: var(--font-mono);
    font-size: var(--fs-label-sm);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--c-ink-muted);
  }
  .header__phone-number { font-size: var(--fs-body); font-weight: 700; color: var(--c-navy); }
  .header__cta { white-space: nowrap; flex-shrink: 0; }
}

@media (min-width: 1120px) {
  .container { padding: 0 var(--gutter); }
  .footer__grid { padding: 64px var(--gutter) 32px; }
  .footer__legal { padding: 20px var(--gutter) 40px; }
  .section { padding-top: var(--space-10); }
  .page > *:last-child.section { padding-bottom: var(--space-10); }
  .section--band { padding-block: var(--space-10); }

  .hero__grid { grid-template-columns: 1.05fr 1fr; min-height: 560px; padding-block: var(--space-9); }
  .hero h1 { font-size: var(--fs-display-1); }

  .routing { grid-template-columns: repeat(4, 1fr); }
  .cards { grid-template-columns: repeat(4, 1fr); }
  .why { grid-template-columns: 1fr 1.15fr; gap: var(--space-10); }
  .enquiry { gap: var(--space-10); }
}

/* Desktop type scale arrives with the desktop header so the two never
   disagree. */
@media (min-width: 900px) {
  .section-head h2 { font-size: var(--fs-h2); }
}

/* --- Honeypot ------------------------------------------------------------
   A field only an automated client fills. Hidden without display:none, which
   some bots detect and skip: kept in the layout, moved out of view, and taken
   out of the tab order in the markup. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ===========================================================================
   16. Service pages — overview rows, detail head, sidebar
   Mobile-first: single column everywhere, columns added at the breakpoints
   the handoff specifies (--bp-m 900, --bp-l 1120).
   ======================================================================== */

.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--c-ink-muted);
  margin-bottom: var(--space-4);
}
.breadcrumb a { color: var(--c-ink-muted); }
.breadcrumb a:hover { color: var(--c-green-dark); }
.breadcrumb [aria-current] { color: var(--c-navy); }

.eyebrow--green { color: var(--c-green-dark); }

/* --- Overview: hairline rows sharing single-pixel lines ----------------- */

.srv-rows {
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--c-border);
  border: 1px solid var(--c-border);
  margin-bottom: var(--space-6);
}

.srv-row {
  background: var(--c-surface);
  display: grid;
  gap: var(--space-4);
  padding: var(--space-5);
  color: inherit;
  text-decoration: none;
  align-items: center;
}
.srv-row:hover { background: var(--c-green-tint); }
.srv-row:focus-visible { outline: var(--focus-ring); outline-offset: -2px; }

.srv-row__media img,
.srv-row__media .ph-img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--c-border);
}

.srv-row__body { display: flex; flex-direction: column; gap: var(--space-2); }
.srv-row__code {
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  letter-spacing: 0.2em;
  color: var(--c-ink-muted);
}
.srv-row__title {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  color: var(--c-navy);
}
.srv-row__text { font-size: var(--fs-small); line-height: 1.65; color: var(--c-ink-muted); }

.srv-row__points { display: flex; flex-direction: column; gap: var(--space-2); }
.srv-point { font-size: var(--fs-small); display: flex; gap: var(--space-2); }
/* The tick states that a point is included, so it is not decoration. */
.srv-point__tick { color: var(--c-green-dark); font-family: var(--font-mono); }
.srv-row__more { font-weight: 700; color: var(--c-green-dark); margin-top: var(--space-2); }

@media (min-width: 900px) {
  .srv-row { grid-template-columns: 220px 1fr; }
  .srv-row__points { grid-column: 1 / -1; flex-direction: row; flex-wrap: wrap; gap: var(--space-4); }
}
@media (min-width: 1120px) {
  .srv-row { grid-template-columns: 300px 1fr 200px; gap: var(--space-6); }
  .srv-row__points { grid-column: auto; flex-direction: column; gap: var(--space-2); }
}

/* --- Detail: title band ------------------------------------------------- */

.srv-head { padding-block: var(--space-6); }
.srv-head__grid { display: grid; gap: var(--space-6); align-items: center; }
.srv-head__lead {
  font-size: var(--fs-body-lg);
  line-height: 1.6;
  color: var(--c-ink-muted);
  max-width: 52ch;
  margin-bottom: var(--space-5);
}
.srv-head__media img,
.srv-head__media .ph-img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--c-border);
}

@media (min-width: 900px) {
  .srv-head__grid { grid-template-columns: 1.1fr 1fr; gap: var(--space-8); }
}

/* --- Detail: body + sidebar --------------------------------------------- */

.srv-body { display: grid; gap: var(--space-7); align-items: start; }
.srv-prose { max-width: var(--measure); }
.srv-prose h2 { font-size: var(--fs-h2); color: var(--c-navy); margin-bottom: var(--space-3); }
.srv-prose h3 {
  font-size: var(--fs-h3);
  color: var(--c-navy);
  margin-top: var(--space-6);
  margin-bottom: var(--space-3);
}
.srv-prose p { font-size: var(--fs-body); line-height: var(--lh-long); color: var(--c-ink); }

.scope-grid {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-6);
  display: grid;
  gap: 1px;
  background: var(--c-border);
  border: 1px solid var(--c-border);
}
.scope-grid__item {
  background: var(--c-surface);
  padding: var(--space-4);
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  font-size: var(--fs-small);
  line-height: 1.5;
}
/* Carries meaning (in scope), so it meets text contrast. */
.scope-grid__tick { color: var(--c-green-dark); font-family: var(--font-mono); }

.srv-process {
  border-block: 1px solid var(--c-border);
  padding-block: var(--space-5);
  margin-bottom: var(--space-6);
}

/* Sidebar: below the body on narrow viewports, sticky only where there is
   room for it. A sticky element on a phone eats the reading area. */
.srv-side { display: flex; flex-direction: column; gap: var(--space-5); }
.srv-side__cta {
  background: var(--c-navy);
  color: var(--c-surface);
  padding: var(--space-5);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.srv-side__cta .srv-side__label { color: var(--c-navy-label); }
.srv-side__pitch { font-size: var(--fs-body-lg); font-weight: 700; line-height: 1.35; }
.srv-side__box { border: 1px solid var(--c-border); border-radius: var(--radius); padding: var(--space-5); }
.srv-side__label {
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--c-ink-muted);
  margin-bottom: var(--space-3);
}
.srv-side__text { font-size: var(--fs-small); line-height: 1.6; color: var(--c-ink-muted); }
.srv-side__links { display: flex; flex-direction: column; }
.srv-side__links a {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--c-navy);
  padding: 13px 0;
  border-bottom: 1px solid var(--c-border-subtle);
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.srv-side__links a:hover { color: var(--c-green-dark); }

@media (min-width: 1120px) {
  .srv-body { grid-template-columns: 1fr 340px; gap: var(--space-8); }
  .srv-side { position: sticky; top: var(--space-5); }
}

/* --- Shared CTA blocks --------------------------------------------------- */

.cta-card {
  background: var(--c-navy);
  color: var(--c-surface);
  border-radius: var(--radius);
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.cta-card__title { font-size: var(--fs-h3); font-weight: 700; }
.cta-card__lead { color: var(--c-navy-ink-muted); }
.cta-card__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); }

.cta-band { display: flex; flex-direction: column; gap: var(--space-4); }

@media (min-width: 900px) {
  .cta-card,
  .cta-band { flex-direction: row; align-items: center; justify-content: space-between; }
  .cta-card__actions { flex-shrink: 0; }
}

/* An unfilled points slot in a service row. Sized like the real thing so the
   row keeps its three-column rhythm while the content is outstanding. */
.srv-row__todo {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--fs-fine);
  color: var(--c-placeholder-ink);
}

/* A navy CTA band ending a page sits directly above the navy footer and the
   two merge into one undifferentiated block. The CTA band is inside <main>,
   so the footer is not its sibling -- the rule goes on the band itself.
   
   The 6px green rule is the theme's own device for closing a navy band
   (design handoff, "signature element"), so it reads as deliberate rather
   than as a patch. */
/* The first block on a page must sit against the header. Both .band and
   .section carry top spacing meant to separate them from what came before,
   which on an inner page is nothing -- so it reads as a gap under the
   header. */
.page > *:first-child.band,
.page > *:first-child.section { margin-top: 0; padding-top: var(--space-6); }



/* ===========================================================================
   18. Projects, About, Contact
   Values are taken from the design handoff directly. Where the design uses a
   size that is not on the token scale (10px, 14px, 26px…) the literal is used:
   rounding each to the nearest token drifts the whole block.
   ======================================================================== */

/* --- Filter chips -------------------------------------------------------- */

.chips {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  padding-bottom: 26px;
  border-bottom: 1px solid var(--c-border);
  margin-bottom: 26px;
}
.chip {
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  padding: 10px 16px;
  min-height: 44px;          /* tap target */
  display: flex;
  align-items: center;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--c-ink);
  background: var(--c-surface);
}
.chip:hover { border-color: var(--c-green); background: var(--c-green-tint); }
.chip--active { border-color: var(--c-navy); background: var(--c-navy); color: var(--c-surface); }
.chip--active:hover { background: var(--c-navy-hover); color: var(--c-surface); }
/* The same chips as page links below the grid: rule above, not below. */
.pagination {
  margin: var(--space-7) 0 0;
  padding: var(--space-6) 0 0;
  border-bottom: 0;
  border-top: 1px solid var(--c-border);
}

/* Filter chips: one swipeable row on phones instead of four wrapped rows that
   push the first project below the fold. Wraps again where there is room. */
.chips--filter { margin-top: var(--space-6); }
@media (max-width: 639px) {
  .chips--filter {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    /* Bleed to the screen edge; 20px is .container's phone padding. */
    margin-inline: -20px;
    padding-inline: 20px;
    scroll-padding-inline: 20px;
  }
  .chips--filter::-webkit-scrollbar { display: none; }
  .chips--filter .chip { flex: 0 0 auto; white-space: nowrap; }
}

.cards--3 { grid-template-columns: 1fr; gap: var(--space-6); }
@media (min-width: 640px) { .cards--3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px) { .cards--3 { grid-template-columns: repeat(3, 1fr); } }

/* --- Project card -------------------------------------------------------- */

/* Photo-led: a fixed 4:3 frame whatever the upload's shape, so a row of
   cards lines up, and every photo is cropped the same way. */
.prj-card { transition: border-color 150ms, box-shadow 200ms, transform 200ms; }
.prj-card:has(.card__hit:hover) { transform: translateY(-3px); box-shadow: var(--shadow-2); }
.prj-card__media {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--c-surface-raised);
}
.prj-card__media img,
.prj-card__media .ph-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border: 0;
  transition: transform 450ms cubic-bezier(.2, .7, .3, 1);
}
.prj-card:has(.card__hit:hover) .prj-card__media img { transform: scale(1.045); }

.prj-card__badge,
.prj-card__count {
  position: absolute;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.3;
  border-radius: var(--radius);
}
.prj-card__badge {
  top: 12px;
  left: 12px;
  max-width: calc(100% - 24px);
  background: rgba(255, 255, 255, 0.95);
  color: var(--c-navy);
  box-shadow: var(--shadow-1);
}
.prj-card__count {
  right: 12px;
  bottom: 12px;
  background: rgba(13, 40, 69, 0.82);
  color: #fff;
}

.prj-card__body { gap: 10px; padding: var(--space-5) var(--space-5) var(--space-6); }
.prj-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  font-size: var(--fs-fine);
  color: var(--c-ink-muted);
}
.prj-card__meta-item { display: inline-flex; align-items: center; gap: 5px; }
.prj-card__meta svg { flex-shrink: 0; color: var(--c-green-dark); }
.prj-card .card__title { line-height: var(--lh-snug); }
.prj-card__text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}
.prj-card__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: auto;
  padding-top: 6px;
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--c-green-dark);
}
.prj-card__link svg { transition: transform 200ms; }
.prj-card:has(.card__hit:hover) .prj-card__link svg { transform: translateX(4px); }

/* Project cards on a service page sit straight under a bare h2. */
.prj-proof { margin-top: var(--space-6); }

/* --- Project detail ------------------------------------------------------ */

.prj-hero { margin-bottom: 34px; }
.prj-hero img,
.prj-hero .ph-img { display: block; width: 100%; height: auto; border: 1px solid var(--c-border); }
.ratio-21-9 { aspect-ratio: 21 / 9; }

/* The hero is cropped to the frame the upload help text promises (21:9 on
   wide screens), taller on phones where 21:9 would be a sliver. */
.prj-hero__link {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius);
  cursor: zoom-in;
}
.prj-hero__link img {
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border: 0;
  transition: transform 600ms cubic-bezier(.2, .7, .3, 1);
}
@media (min-width: 640px) { .prj-hero__link img { aspect-ratio: 16 / 9; } }
@media (min-width: 900px) { .prj-hero__link img { aspect-ratio: 21 / 9; } }
.prj-hero__link:hover img { transform: scale(1.015); }
.prj-hero__link:focus-visible { outline-offset: 3px; }
.prj-hero__all {
  position: absolute;
  right: 16px;
  bottom: 16px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  min-height: var(--tap-min);
  background: rgba(255, 255, 255, 0.96);
  color: var(--c-navy);
  font-size: var(--fs-small);
  font-weight: 700;
  border-radius: var(--radius);
  box-shadow: var(--shadow-2);
  transition: background 150ms;
}
.prj-hero__link:hover .prj-hero__all { background: #fff; color: var(--c-green-dark); }

.prj-body { display: grid; gap: var(--space-7); align-items: start; }
@media (min-width: 1120px) {
  .prj-body { grid-template-columns: 1fr 320px; gap: 64px; }
  .prj-body .srv-side { position: sticky; top: var(--space-5); }
}

.prj-gallery { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin: var(--space-4) 0 30px; }
@media (min-width: 640px) { .prj-gallery { grid-template-columns: repeat(3, 1fr); } }
.prj-gallery img { display: block; width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: cover; }

.prj-gallery__item {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--c-surface-raised);
  cursor: zoom-in;
}
.prj-gallery__item img { transition: transform 400ms cubic-bezier(.2, .7, .3, 1); }
.prj-gallery__item::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(13, 40, 69, 0);
  transition: background 200ms;
}
.prj-gallery__zoom {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.95);
  color: var(--c-navy);
  opacity: 0;
  /* Decorative: while transparent it must not catch clicks. */
  pointer-events: none;
  transform: translate(-50%, -50%) scale(0.85);
  transition: opacity 200ms, transform 200ms;
}
.prj-gallery__item:hover img,
.prj-gallery__item:focus-visible img { transform: scale(1.06); }
.prj-gallery__item:hover::after,
.prj-gallery__item:focus-visible::after { background: rgba(13, 40, 69, 0.28); }
.prj-gallery__item:hover .prj-gallery__zoom,
.prj-gallery__item:focus-visible .prj-gallery__zoom { opacity: 1; transform: translate(-50%, -50%) scale(1); }

/* --- Lightbox ------------------------------------------------------------ */

/* Native modal <dialog> filling the viewport: bar / stage / thumbnails. */
.lightbox {
  width: 100vw;
  max-width: none;
  height: 100vh;
  height: 100dvh;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: rgba(6, 18, 31, 0.97);
  color: #fff;
}
.lightbox[open] { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; }
.lightbox::backdrop { background: rgba(6, 18, 31, 0.9); }
html:has(.lightbox[open]) { overflow: hidden; }

.lightbox__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
}
.lightbox__count {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.14em;
  color: var(--c-navy-ink-muted);
}

.lightbox__btn {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  cursor: pointer;
  transition: background 150ms, border-color 150ms;
}
.lightbox__btn:hover { background: rgba(255, 255, 255, 0.2); border-color: rgba(255, 255, 255, 0.4); }
.lightbox__btn[hidden] { display: none; }

.lightbox__stage {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  padding: 0 80px;
  touch-action: pan-y;
}
.lightbox__figure {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  max-width: 100%;
  max-height: 100%;
  margin: 0;
}
.lightbox__img {
  display: block;
  max-width: 100%;
  max-height: calc(100vh - 220px);
  max-height: calc(100dvh - 220px);
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--radius);
  transition: opacity 220ms;
}
.lightbox__img.is-loading { opacity: 0.3; }
.lightbox__caption {
  max-width: 60ch;
  font-size: var(--fs-small);
  color: var(--c-navy-ink-muted);
  text-align: center;
}
.lightbox__nav { position: absolute; top: 50%; transform: translateY(-50%); }
.lightbox__nav--prev { left: 16px; }
.lightbox__nav--next { right: 16px; }

.lightbox__thumbs {
  display: flex;
  justify-content: flex-start;
  justify-content: safe center;
  gap: 8px;
  overflow-x: auto;
  padding: 12px 16px 18px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
}
.lightbox__thumbs:empty { display: none; }
.lightbox__thumb {
  flex: 0 0 auto;
  width: 76px;
  height: 57px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: var(--radius);
  overflow: hidden;
  background: none;
  opacity: 0.5;
  cursor: pointer;
  transition: opacity 150ms, border-color 150ms;
}
.lightbox__thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.lightbox__thumb:hover { opacity: 0.85; }
.lightbox__thumb[aria-current="true"] { opacity: 1; border-color: var(--c-green); }

@media (max-width: 639px) {
  .lightbox__stage { padding: 0 8px; }
  .lightbox__nav { width: 40px; height: 40px; background: rgba(6, 18, 31, 0.55); }
  .lightbox__nav--prev { left: 12px; }
  .lightbox__nav--next { right: 12px; }
  .lightbox__img { max-height: calc(100dvh - 190px); }
  .lightbox__thumb { width: 60px; height: 45px; }
}

/* Screen-reader-only text. */
.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;
}

.prj-meta { border: 1px solid var(--c-border); border-radius: var(--radius); }
.prj-meta__row {
  padding: 14px 18px;
  border-bottom: 1px solid var(--c-border-subtle);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.prj-meta__row:last-child { border-bottom: 0; }
.prj-meta__value { font-size: var(--fs-small); font-weight: 700; color: var(--c-navy); }
.prj-meta__link { display: flex; flex-direction: column; gap: 6px; }
.prj-meta__link:hover { border-color: var(--c-green); background: var(--c-green-tint); }

/* --- About --------------------------------------------------------------- */

.about-intro { display: grid; gap: var(--space-6); align-items: start; margin-bottom: 44px; }
@media (min-width: 900px) {
  .about-intro { grid-template-columns: 1.15fr 1fr; gap: 64px; }
}
.about-intro__lead {
  font-size: var(--fs-body-lg);
  line-height: var(--lh-long);
  color: var(--c-ink);
  max-width: 62ch;
  margin-bottom: 16px;
}
.about-intro__media img,
.about-intro__media .ph-img { display: block; width: 100%; height: auto; border: 1px solid var(--c-border); }

/* Hairline grid sharing single-pixel lines, as elsewhere in the theme. */
.values {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--c-border);
  border: 1px solid var(--c-border);
  margin-bottom: 34px;
}
@media (min-width: 640px) { .values { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1120px) { .values { grid-template-columns: repeat(4, 1fr); } }
.values__item {
  background: var(--c-surface);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.values__no {
  font-family: var(--font-mono);
  font-size: var(--fs-label-sm);
  letter-spacing: 0.2em;
  /* 10px text needs the full 4.5:1 — see .reason__no. */
  color: var(--c-green-dark);
}
.values__title { font-size: 18px; font-weight: 700; color: var(--c-navy); }
.values__body { font-size: 14px; line-height: 1.65; color: var(--c-ink-muted); }

.about-proof { display: grid; gap: 20px; margin-bottom: var(--space-7); }
/* Two columns only when there are two blocks. The team block is held back
   (see about.html), and a lone block in a 2-column grid left half the row
   empty. */
@media (min-width: 900px) { .about-proof:has(> :nth-child(2)) { grid-template-columns: 1fr 1fr; } }

/* Qualification: one card per certificate (_partials/certifications.html).
   The same block sits full-width on About, in a half column on the homepage
   and in the 320px service sidebar, so the columns follow the block's own
   width (container queries), not the viewport's. */
.certs { container-type: inline-size; }
.certs__title { margin: 6px 0 var(--space-5); font-size: var(--fs-h3); color: var(--c-navy); }
.certs__list {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
}
@container (min-width: 560px) { .certs__list { grid-template-columns: repeat(2, 1fr); } }
@container (min-width: 900px) { .certs__list { grid-template-columns: repeat(3, 1fr); } }
/* Only the homepage block follows a lead paragraph. */
.why .certs { margin-top: var(--space-6); }
.cert {
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
  padding: var(--space-5);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
}
.cert__icon {
  flex: 0 0 44px;
  display: grid;
  place-items: center;
  height: 44px;
  border-radius: 50%;
  background: var(--c-green-tint);
  color: var(--c-green-dark);
}
.cert__body { min-width: 0; }
/* h3 on About, h4 elsewhere; the base reset covers h1-h3 only, so the margin
   and face are set here for both. */
.cert__name {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-body);
  font-weight: 700;
  letter-spacing: var(--ls-h2);
  line-height: var(--lh-snug);
  color: var(--c-navy);
}
.cert__issuer { margin-top: 4px; font-size: var(--fs-small); line-height: 1.55; color: var(--c-ink-muted); }
.cert__facts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--space-3); }
.cert__fact {
  padding: 3px 8px;
  font-size: 12px;
  font-weight: 700;
  color: var(--c-navy);
  background: var(--c-surface-raised);
  border-radius: var(--radius-badge);
}

/* --- Contact ------------------------------------------------------------- */

.contact { display: grid; gap: var(--space-6); align-items: start; }
@media (min-width: 900px) {
  .contact { grid-template-columns: 1fr 1.3fr; gap: 56px; }
}
.contact__aside { display: flex; flex-direction: column; gap: 20px; }
.contact__phone {
  background: var(--c-navy);
  color: var(--c-surface);
  padding: 26px;
  border-radius: var(--radius);
  display: block;
}
.contact__phone:hover { background: var(--c-navy-hover); color: var(--c-surface); }
.contact__phone .srv-side__label { color: var(--c-navy-label); }
.contact__phone-number {
  display: block;
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* Contact details: icon, small label, value. */
.contact-info {
  margin: 0;
  padding: 0;
  list-style: none;
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  background: var(--c-surface);
}
.contact-info__row {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 16px 18px;
  border-bottom: 1px solid var(--c-border-subtle);
}
.contact-info__row:last-child { border-bottom: 0; }
.contact-info__icon {
  flex: 0 0 38px;
  display: grid;
  place-items: center;
  height: 38px;
  border-radius: 50%;
  background: var(--c-green-tint);
  color: var(--c-green-dark);
}
.contact-info__grow { flex: 1; min-width: 0; }
.contact-info__label {
  display: block;
  margin-bottom: 2px;
  font-size: var(--fs-fine);
  color: var(--c-ink-muted);
}
.contact-info__value {
  display: block;
  font-size: var(--fs-body);
  font-weight: 700;
  line-height: 1.5;
  color: var(--c-navy);
  overflow-wrap: anywhere;
}
.contact-info__link { color: var(--c-green-dark); text-decoration: underline; text-underline-offset: 3px; }
.contact-info__link:hover { color: var(--c-green-active); }
.contact-info__route {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--tap-min);
  margin-top: 4px;
  font-size: var(--fs-small);
  font-weight: 700;
  color: var(--c-green-dark);
}
.contact-info__route:hover { color: var(--c-green-active); }

/* Opening hours as a day/time table, so the times line up. */
.contact-hours { width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
.contact-hours th,
.contact-hours td { padding: 3px 0; text-align: left; }
.contact-hours th { font-weight: 400; color: var(--c-ink-muted); }
.contact-hours td { font-weight: 700; color: var(--c-navy); text-align: right; font-variant-numeric: tabular-nums; }

.form-card__intro { margin: 4px 0 var(--space-5); }

/* ===========================================================================
   19. FAQ page and service areas
   ======================================================================== */

/* Design: 260px topic nav + content, 56px apart. Below --bp-m the nav unsticks
   and simply precedes the sections -- a sticky element on a phone eats the
   reading area. */
.faq-page { display: grid; gap: var(--space-6); align-items: start; }
@media (min-width: 900px) {
  .faq-page { grid-template-columns: 260px 1fr; gap: 56px; }
  .faq-nav { position: sticky; top: 24px; }
}

.faq-nav {
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
}
.faq-nav__head { padding: 16px 18px 10px; margin: 0; }
.faq-nav a {
  display: block;
  padding: 13px 18px;
  border-top: 1px solid var(--c-border-subtle);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--c-navy);
  min-height: 44px;          /* tap target */
}
.faq-nav a:hover { color: var(--c-green-dark); background: var(--c-green-tint); }

.faq-groups { display: flex; flex-direction: column; gap: 34px; }
/* 24px in the design, between --fs-h3 (21) and --fs-h2. Set literally so the
   group headings sit clearly above the 17px questions without competing with
   the page H1. */
.faq-group h2 {
  font-size: 24px;
  letter-spacing: -0.02em;
  color: var(--c-navy);
  margin-bottom: 12px;
}
/* Anchor jumps land below the sticky header rather than under it. */
.faq-group { scroll-margin-top: 100px; }
/* The design gives answers a wider measure here than on the homepage: this is
   a reading page, not a teaser section. */
.faq-page .faq__answer { max-width: 72ch; }

/* A CTA that closes a light section: navy text on the raised surface rather
   than a navy block, which would collide with the footer. */
.cta-card--light {
  background: var(--c-surface-raised);
  border: 1px solid #E4E9ED;
  color: var(--c-ink);
}
.cta-card--light .cta-card__title { color: var(--c-navy); }

/* --- Service areas ------------------------------------------------------- */

.areas-intro { display: grid; gap: var(--space-6); align-items: start; margin-bottom: 34px; }
@media (min-width: 900px) {
  .areas-intro { grid-template-columns: 1.1fr 1fr; gap: 56px; }
}
.areas-map__wrap {
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  padding: 20px;
}
.areas-map__wrap .area-chips { margin-top: 12px; }

/* --- Error pages --------------------------------------------------------- */

.error-code {
  font-family: var(--font-mono);
  font-size: 34px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--c-navy);
  margin-bottom: 4px;
}
.error-links { display: flex; flex-direction: column; gap: 8px; margin-bottom: var(--space-6); }
.error-links a { font-size: var(--fs-small); font-weight: 700; color: var(--c-green-dark); }
