/* /site template v1.5.0 (the version this site was built with) */
/* /site 1.0.0: the engine design (LocalBooked factory, Albert's premium-website-factory) as plain CSS for a static,
   multi-page build. Colours come from theme.css (lib/theme.mjs: one accent in site.json), fonts from fonts.css.
   Light/dark rhythm: every section carries .tone-light or .tone-dark (render.mjs decides, site.json overrides only when
   Nikolaj asks). No component hardcodes a colour: light sections use --base/--surface/--ink/--muted/--accent, dark ones
   --deep/--deep-ink/--deep-muted/--deep-accent.
   Sections: A base, B buttons, C header and menus, D bottom bar, E hero, F section heading, G cards with drawings,
   H numbers, I reviews, J steps, K services band, L FAQ, M forms and contact, N closing block, O footer,
   P content blocks (prose, cards, gallery, compare, prices, video, embed, towns, posts, legal, map), Q motion. */

/* ---------- A. Base ---------- */
:root { --radius: 1.75rem; --radius-lg: 2rem; --grid-gap: 1.5rem; --heading-gap: 3rem; --para-gap: 1.25rem; --nav-h: 5rem; --ease-btn: cubic-bezier(0.25, 0.46, 0.45, 0.94); --font-mono: var(--font-body); --font-sans: var(--font-body); --on-deep-accent: var(--deep); }
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 6.5rem; scroll-padding-bottom: 5rem; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
html, body { overflow-x: hidden; }
@supports (overflow: clip) { html, body { overflow-x: clip; } }
body { margin: 0; background: var(--base); color: var(--ink); font-family: var(--font-body); font-size: 1rem; line-height: 1.6; }
img, svg, video, iframe { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
p, ul, ol, figure, blockquote, dl, dd { margin: 0; }
ul, ol { padding: 0; }
h1, h2, h3, h4 { margin: 0; font-family: var(--font-display); font-weight: 800; letter-spacing: -0.025em; line-height: 1.05; }
/* One size per heading level on a page (qa.cjs [heading sizes]): every card, row and block title is an h3 at the engine's
   text-2xl (1.5rem); only the steps' big titles (their own design) and the legal pages' text differ. */
h3 { font-weight: 700; letter-spacing: -0.015em; font-size: 1.5rem; line-height: 1.15; }
button, input, select, textarea { font: inherit; color: inherit; }
::selection { background: var(--primary); color: #1a1a1a; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.tone-dark :focus-visible, .hero :focus-visible, .footer :focus-visible { outline-color: var(--deep-accent); }
/* A phone number never splits at its hyphen or spaces (lib/util.mjs textBreaks; qa.cjs [phone]). */
.nowrap { white-space: nowrap; }
.sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.skip { position: absolute; left: 1rem; top: -4rem; z-index: 100; background: var(--surface); color: var(--ink); padding: 0.75rem 1rem; border-radius: 999px; font-weight: 600; }
.skip:focus { top: 1rem; }
.wrap { width: 100%; max-width: 80rem; margin-inline: auto; padding-inline: 1.5rem; }
@media (min-width: 640px) { .wrap { padding-inline: 2.5rem; } }
@media (min-width: 1024px) { .wrap { padding-inline: 4rem; } }
.section { position: relative; padding-block: var(--sec-y); }
/* 1.1.0 (Nikolaj's review, 12 Nov 2026, A1): a tighter section scale. 1.0.0 had 5rem / 7rem on every side of every
   section, so two light sections in a row stood 224px apart at 1440 (qa.cjs [empty bands]). One gap between two
   sections of the same tone, not two: the second keeps a quarter of its top padding. */
:root { --sec-y: 3.5rem; --head-gap: 2rem; }
@media (min-width: 640px) { :root { --sec-y: 4.5rem; --head-gap: 2.5rem; } }
@media (min-width: 1024px) { :root { --sec-y: 5.25rem; --head-gap: 2.75rem; } }
.tone-light + .tone-light:not(.has-bd) { padding-top: calc(var(--sec-y) * 0.25); }
/* Two dark bands in a row (a sub page's reviews and other services, now that the steps are on the home page only, A4):
   one dark run with a hairline between them, half a gap on each side of it. */
.tone-dark:has(+ .tone-dark) { padding-bottom: calc(var(--sec-y) * 0.5); }
.tone-dark + .tone-dark { padding-top: calc(var(--sec-y) * 0.5); box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.08); }
/* Content above a section's glow and the services mark (the engine's "relative wrap"), never under it. */
.section > .wrap, .mq { position: relative; }
/* Phones: the cards and the numbers read as one run, as the engine's (pt-20 pb-10, then pt-10 pb-20). */
@media (max-width: 639px) { .section[data-qa="specialties"] + .section[data-qa="numbers"] { padding-top: 0.5rem; } }
/* overflow-x: clip keeps a section's glow inside the page at 390 without making it a scroll box (the steps still stick). */
.tone-light { background: var(--base); color: var(--ink); overflow-x: clip; }
.tone-dark { background: var(--deep); color: var(--deep-ink); overflow: hidden; }
/* 1.1.0 (A5): overflow: hidden made every dark band a scroll container, so the services band's sticky aside never
   stuck; clip cuts the glow and the trade mark the same way without one. */
@supports (overflow: clip) { .tone-dark { overflow: clip; } }
.tone-dark .muted, .tone-dark p { color: var(--deep-muted); }
.muted { color: var(--muted); }
.glow-radial { position: absolute; pointer-events: none; background: radial-gradient(closest-side, rgb(var(--primary-rgb) / var(--g, 0.16)), rgb(var(--primary-rgb) / 0)); }
.lead { font-size: 1.125rem; line-height: 1.65; color: var(--muted); max-width: 36rem; }
.tone-dark .lead { color: var(--deep-muted); }
.mono { font-variant-numeric: tabular-nums; }

/* ---------- B. Buttons ---------- */
.btn { position: relative; overflow: hidden; display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; min-height: 2.75rem; padding: 0.875rem 1.75rem; border-radius: 999px; border: 1px solid transparent; font-family: var(--font-body); font-weight: 600; font-size: 1rem; line-height: 1.2; text-decoration: none; cursor: pointer; white-space: nowrap; transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94), background-color 0.3s, color 0.3s; }
.btn svg { width: 1rem; height: 1rem; flex: none; }
.btn::before { content: ''; position: absolute; inset: 0; background: linear-gradient(135deg, rgb(255 255 255 / 0.15), rgb(255 255 255 / 0)); transform: translateY(100%); transition: transform 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94); pointer-events: none; }
.btn:active { transform: scale(0.98); }
@media (hover: hover) { .btn:hover { transform: scale(1.03) translateY(-1px); } .btn:hover::before { transform: translateY(0); } }
.btn--accent { background: var(--accent-fill); color: var(--on-accent); box-shadow: 0 10px 24px -8px rgb(var(--primary-rgb) / 0.45); }
.btn--ghost { background: rgb(255 255 255 / 0.1); color: #fff; border-color: rgb(255 255 255 / 0.25); }
.tone-light .btn--ghost, .btn--line { background: transparent; color: var(--ink); border-color: color-mix(in srgb, var(--ink) 22%, transparent); }
.btn--lg { font-size: 1.0625rem; padding: 1rem 2rem; }
.btn--xl { font-size: 1.125rem; padding: 1.0625rem 2.125rem; }
.btn--xl svg { width: 1.25rem; height: 1.25rem; }
.btn--block { width: 100%; }
.btn[disabled] { opacity: 0.6; cursor: default; }
.link { display: inline-flex; align-items: center; gap: 0.375rem; font-weight: 600; color: var(--accent); text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 0.125rem; }
.link svg { width: 1rem; height: 1rem; }
.tone-dark .link, .hero .link { color: #fff; border-color: rgb(255 255 255 / 0.4); }

/* ---------- C. Header and menus ---------- */
.nav { position: fixed; z-index: 50; top: 1rem; left: 50%; transform: translateX(-50%); width: calc(100% - 2rem); max-width: 76rem; border-radius: 999px; padding: 0.625rem 1rem 0.625rem 1.5rem; border: 1px solid transparent; transition: background-color 0.5s, box-shadow 0.5s, border-color 0.5s; color: #fff; }
.nav__row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.nav__brand { display: flex; align-items: center; gap: 0.625rem; min-width: 0; text-decoration: none; color: inherit; }
.nav__mark { height: 2rem; width: auto; flex: none; }
/* 1.4.0 (Nikolaj, 13 Nov 2026; brand.scrollMark): the name at the top of the page, the client's mark once the page
   scrolls (main.js is-scrolled), a short fade and scale both ways; under reduced motion a plain swap (section Q). The
   link keeps the name's width, so nothing beside it moves. qa.cjs [scroll mark]. */
/* 1.4.1 (Nikolaj, 13 Nov 2026): scrolled, the mark stays and the name stands beside it, a little smaller. The link keeps
   the mark's room at its left all the time (the name slides into it at the top), so nothing beside it moves. */
.nav__brand--swap { position: relative; padding-left: 2.875rem; }
.nav__brand--swap .nav__name { transform: translateX(-2.875rem); transition: transform 0.36s cubic-bezier(0.22, 0.61, 0.36, 1); transform-origin: left center; }
.nav__smark { position: absolute; left: 0; top: 50%; width: 2.375rem; height: 2.25rem; max-width: none; object-fit: contain; object-position: left center; opacity: 0; transform: translateY(-50%) scale(0.7); transform-origin: left center; transition: opacity 0.28s ease, transform 0.32s cubic-bezier(0.22, 0.61, 0.36, 1); pointer-events: none; }
.nav.is-scrolled .nav__brand--swap .nav__name { transform: translateX(0) scale(0.86); }
.nav.is-scrolled .nav__smark { opacity: 1; transform: translateY(-50%) scale(1); }
@media (prefers-reduced-motion: reduce) { .nav__brand--swap .nav__name, .nav__smark { transition: none; } }
.nav__name { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.02em; line-height: 1.15; font-size: 1.125rem; overflow-wrap: anywhere; text-wrap: balance; }
.nav__name--long { font-size: 1rem; }
.nav__name--xlong { font-size: 0.9rem; }
.nav__links { display: none; align-items: center; gap: 0.25rem; list-style: none; }
.nav__item { position: relative; }
.nav__link, .nav__drop-btn { display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.5rem 0.75rem; border-radius: 999px; font-size: 0.9375rem; font-weight: 500; color: inherit; text-decoration: none; background: none; border: 0; cursor: pointer; white-space: nowrap; opacity: 0.9; transition: opacity 0.2s, background-color 0.2s; }
.nav__link:hover, .nav__drop-btn:hover, .nav__link[aria-current="page"] { opacity: 1; }
.nav__link[aria-current="page"] { text-decoration: underline; text-underline-offset: 0.35em; text-decoration-thickness: 1.5px; }
.nav__drop-btn svg { width: 0.875rem; height: 0.875rem; transition: transform 0.25s; }
.nav__item.is-open .nav__drop-btn svg { transform: rotate(180deg); }
.nav__drop { position: absolute; top: calc(100% + 0.75rem); left: 50%; transform: translate(-50%, -0.25rem); min-width: 16rem; max-width: min(46rem, calc(100vw - 3rem)); max-height: min(70vh, 34rem); overflow: auto; background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: 1.5rem; padding: 0.75rem; box-shadow: 0 24px 48px -16px rgb(15 20 25 / 0.28); opacity: 0; visibility: hidden; transition: opacity 0.2s, transform 0.2s, visibility 0s linear 0.2s; }
.nav__drop::before { content: ''; position: absolute; left: 0; right: 0; top: -0.75rem; height: 0.75rem; }
.nav__item.is-open > .nav__drop { opacity: 1; visibility: visible; transform: translate(-50%, 0); transition: opacity 0.2s, transform 0.2s, visibility 0s; }
@media (hover: hover) and (pointer: fine) { .nav__item--drop:hover > .nav__drop { opacity: 1; visibility: visible; transform: translate(-50%, 0); transition: opacity 0.2s, transform 0.2s, visibility 0s; } }
.nav__drop ul { list-style: none; display: grid; gap: 0.125rem; }
.nav__drop--cols ul { grid-template-columns: repeat(var(--cols, 2), minmax(12rem, 1fr)); column-gap: 0.5rem; }
.nav__drop a { display: block; padding: 0.625rem 0.875rem; border-radius: 0.875rem; text-decoration: none; font-size: 0.9375rem; font-weight: 500; line-height: 1.3; color: var(--ink); }
.nav__drop a:hover, .nav__drop a:focus-visible { background: var(--tint); color: var(--accent); }
.nav__drop a[aria-current="page"] { color: var(--accent); font-weight: 600; }
.nav__drop .nav__all { margin-top: 0.375rem; border-top: 1px solid var(--line); padding-top: 0.375rem; }
.nav__drop .nav__all a { color: var(--accent); font-weight: 600; }
.nav__end { display: none; align-items: center; gap: 0.75rem; flex: none; }
.nav__phone { display: inline-flex; align-items: center; gap: 0.4rem; font-weight: 600; font-size: 0.9375rem; text-decoration: none; color: inherit; white-space: nowrap; }
.nav__phone svg { width: 1rem; height: 1rem; }
.nav__cta { padding: 0.625rem 1.125rem; min-height: 2.5rem; font-size: 0.9375rem; }
.nav__burger { display: inline-flex; align-items: center; justify-content: center; width: 2.75rem; height: 2.75rem; border-radius: 999px; border: 0; background: none; color: inherit; cursor: pointer; flex: none; }
.nav__burger svg { width: 1.375rem; height: 1.375rem; }
.nav.is-solid, body.no-hero .nav { background: rgb(249 249 249 / 0.97); border-color: rgb(var(--primary-rgb) / 0.18); box-shadow: 0 10px 30px -12px rgb(var(--primary-rgb) / 0.25); color: var(--ink); }
@media (min-width: 1024px) and (hover: hover) { .nav.is-solid, body.no-hero .nav { background: rgb(249 249 249 / 0.78); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); } }
@media (min-width: 1100px) { .nav__links, .nav__end { display: flex; } .nav__burger { display: none; } }
/* 1.4.0 (Nikolaj, 13 Nov 2026): a slimmer pill on phones (66px tall before, 54px now); the menu button keeps its 44px. */
@media (max-width: 767px) { .nav { top: 0.75rem; width: calc(100% - 1.5rem); padding: 0.25rem 0.375rem 0.25rem 1.25rem; } }
@media (min-width: 1100px) and (max-width: 1279px) { .nav__phone span { display: none; } .nav__link, .nav__drop-btn { padding-inline: 0.5rem; } }

/* phone menu: a sheet from the top */
/* 1.4.1 (Nikolaj, 13 Nov 2026): closing slides the sheet up the way it slid down: the menu stays visible until the
   sheet's transform has run (0.45s), then hides. */
.menu { position: fixed; inset: 0; z-index: 60; visibility: hidden; pointer-events: none; transition: visibility 0s linear 0.45s; }
.menu.is-open { visibility: visible; pointer-events: auto; transition: visibility 0s; }
.menu__shade { position: absolute; inset: 0; background: rgb(15 20 25 / 0.92); opacity: 0; transition: opacity 0.3s; border: 0; width: 100%; padding: 0; cursor: pointer; }
.menu.is-open .menu__shade { opacity: 1; }
.menu__sheet { position: absolute; left: 0; right: 0; top: 0; max-height: 100dvh; overflow-y: auto; background: var(--base); color: var(--ink); border-radius: 0 0 2.5rem 2.5rem; padding: 1.5rem 1.5rem 2.5rem; transform: translateY(-100%); transition: transform 0.45s cubic-bezier(0.22, 0.61, 0.36, 1); }
.menu.is-open .menu__sheet { transform: none; }
.menu__head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.5rem; }
.menu__name { display: flex; align-items: center; gap: 0.625rem; font-family: var(--font-display); font-weight: 700; font-size: 1.25rem; letter-spacing: -0.02em; }
/* 1.4.1: the header's mark (brand.headerMark, else brand.scrollMark) beside the name at the top of the open menu */
.menu__mark { flex: none; width: 2.25rem; height: 2.25rem; object-fit: contain; }
.menu__close { width: 2.75rem; height: 2.75rem; border-radius: 999px; border: 0; background: color-mix(in srgb, var(--line) 50%, transparent); display: inline-flex; align-items: center; justify-content: center; cursor: pointer; color: var(--ink); }
.menu__close svg { width: 1.25rem; height: 1.25rem; }
.menu__list { list-style: none; }
.menu__list > li { border-bottom: 1px solid var(--line); }
.menu__link, .menu__toggle { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.75rem 0; font-family: var(--font-display); font-weight: 500; font-size: 1.75rem; letter-spacing: -0.02em; text-decoration: none; color: var(--ink); background: none; border: 0; cursor: pointer; text-align: left; }
.menu__toggle svg { width: 1.25rem; height: 1.25rem; transition: transform 0.25s; flex: none; }
.menu__toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
/* 1.4.0 (Nikolaj, 13 Nov 2026): Services and Service Areas slide open and closed (main.js sets --h to the list's height);
   under reduced motion they open at once (section Q). The links read in a slight tint of the accent, 4.5:1 or more on
   the sheet (about 9:1 with the template's colours; QA [phone menu]), not the muted grey. */
.menu__sub { list-style: none; display: grid; gap: 0.125rem; padding: 0 0 0 0.25rem; max-height: 0; overflow: hidden; visibility: hidden; opacity: 0; transition: max-height 0.38s cubic-bezier(0.22, 0.61, 0.36, 1), padding-bottom 0.38s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.22s ease, visibility 0s linear 0.38s; }
.menu__sub.is-open { max-height: var(--h, 60rem); padding-bottom: 1rem; visibility: visible; opacity: 1; transition: max-height 0.38s cubic-bezier(0.22, 0.61, 0.36, 1), padding-bottom 0.38s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.3s ease 0.05s, visibility 0s; }
.menu__sub a { display: block; padding: 0.625rem 0; color: color-mix(in srgb, var(--accent) 40%, var(--ink)); text-decoration: none; font-size: 1.0625rem; font-weight: 500; } /* 44px or more to tap (QA [phone menu]) */
.menu__sub a[aria-current="page"] { color: var(--accent); font-weight: 600; }
.menu__actions { display: grid; gap: 0.75rem; margin-top: 1.75rem; }
.menu__sheet .social--menu { margin-top: 1.75rem; } /* 1.4.1: clear of the buttons above */

/* ---------- D. Bottom bar on phones ---------- */
.callbar { position: fixed; z-index: 45; left: 0; right: 0; bottom: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 0.625rem; padding: 0.625rem 0.75rem calc(0.625rem + env(safe-area-inset-bottom)); background: rgb(249 249 249 / 0.97); border-top: 1px solid var(--line); box-shadow: 0 -10px 30px -16px rgb(15 20 25 / 0.35); transition: transform 0.3s, visibility 0s; }
.callbar .btn { min-height: 3rem; padding: 0.75rem 1rem; font-size: 1rem; }
.callbar .btn--line { background: var(--surface); }
.callbar.is-hidden { transform: translateY(110%); visibility: hidden; transition: transform 0.3s, visibility 0s linear 0.3s; }
/* GoHighLevel's chat bubble (integrations.ghlChat) is 58px wide, 20px from the right and bottom edges, over the bar
   (narto-site 3.65.0; its widget cannot be moved from here): once the widget is on the page, the buttons leave it room
   (QA [chat] measures the buttons' right edge against the bubble at 390). */
body:has(> chat-widget) .callbar { padding-right: 5.5rem; }
body:has(> chat-widget) .callbar .btn { padding-inline: 0.625rem; }
body.has-callbar { padding-bottom: calc(4.25rem + env(safe-area-inset-bottom)); }
@media (min-width: 768px) { .callbar { display: none; } body.has-callbar { padding-bottom: 0; } }

/* ---------- E. Hero ---------- */
.hero { position: relative; background: var(--deep); color: #fff; }
.hero__inner { position: relative; }
.hero__stage { position: relative; overflow: hidden; display: flex; justify-content: center; }
.hero__photo { position: absolute; inset: 0; overflow: hidden; }
.hero__photo img { width: 100%; height: 100%; object-fit: cover; }
/* The overlay is the page's own deep colour (the engine's from-deep), so the photo's foot meets the dark band under it
   with no seam. hero.scrim (20 to 85) lays an even shade of it on top. */
.hero__shade { position: absolute; inset: 0; background: linear-gradient(to top, var(--deep), color-mix(in srgb, var(--deep) 30%, transparent) 50%, color-mix(in srgb, var(--deep) 0%, transparent)), linear-gradient(to top right, color-mix(in srgb, var(--deep) 90%, transparent), color-mix(in srgb, var(--deep) 75%, transparent), color-mix(in srgb, var(--deep) 55%, transparent)); }
.hero__photo::after { content: ''; position: absolute; inset: 0; background: var(--deep); opacity: var(--scrim, 0); pointer-events: none; }
.hero__text { position: relative; z-index: 2; max-width: 56rem; padding: 7.5rem 1.5rem 2.75rem; text-align: center; }
.hero__chip { display: inline-flex; align-items: center; gap: 0.5rem; background: rgb(255 255 255 / 0.1); border: 1px solid rgb(255 255 255 / 0.15); border-radius: 999px; padding: 0.375rem 1rem; margin-bottom: 1.25rem; font-size: 0.8125rem; font-weight: 500; color: rgb(255 255 255 / 0.92); }
.stars { display: inline-flex; gap: 0.125rem; color: var(--star); }
.stars svg { width: 1rem; height: 1rem; fill: currentColor; }
.stars svg.off { color: color-mix(in srgb, currentColor 25%, transparent); }
.hero .stars, .tone-dark .stars { color: var(--deep-accent); }
.hero__chip .stars svg { width: 0.875rem; height: 0.875rem; }
.pills { list-style: none; display: flex; flex-wrap: wrap; gap: 0.375rem; }
.pill { font-size: 0.75rem; font-weight: 500; color: rgb(255 255 255 / 0.92); border: 1px solid rgb(255 255 255 / 0.3); border-radius: 999px; padding: 0.125rem 0.625rem; white-space: nowrap; }
.hero__text .pills { justify-content: center; margin: -0.25rem 0 2rem; }
.hero h1 { font-weight: 800; line-height: 0.98; letter-spacing: -0.03em; color: #fff; overflow-wrap: break-word; }
.h1-a { display: block; font-size: clamp(2.25rem, 9vw, 3rem); }
.h1-b { display: block; font-family: var(--font-serif); font-style: italic; font-weight: 500; letter-spacing: -0.01em; color: var(--hero-accent); font-size: clamp(3rem, 13vw, 4.5rem); margin-top: 0.5rem; line-height: 1; }
.hero__sub { margin: 1.75rem auto 0; max-width: 36rem; font-size: 1.0625rem; line-height: 1.65; color: rgb(255 255 255 / 0.85); }
.hero__actions { display: flex; flex-direction: column; gap: 0.875rem; justify-content: center; margin-top: 2.25rem; }
.hero__actions .btn { padding-block: 1rem; }
.hero__rating { display: none; align-items: center; gap: 0.5rem; margin-top: 1.25rem; font-size: 0.9375rem; color: rgb(255 255 255 / 0.9); }
.hero__rating svg { width: 1rem; height: 1rem; fill: var(--deep-accent); color: var(--deep-accent); }
.hero__rating strong { color: #fff; font-weight: 600; }
.hero__form { position: relative; z-index: 2; background: var(--deep); padding: 0.5rem 1.25rem 3rem; }
.hero__form > .card-form { max-width: 28rem; margin-inline: auto; }
@media (min-width: 640px) { .hero__actions { flex-direction: row; } .hero__text { padding-inline: 2.5rem; } }
/* 1.4.0 (Nikolaj, 13 Nov 2026; hero.phoneFold): on a phone the photo part fills the first screen (the bottom bar's
   height kept clear under the buttons) and the form card starts under the fold; qa.cjs [phone fold] at 390x844 and
   390x664. */
/* 1.4.1 (Nikolaj, 13 Nov 2026): the content fills the first screen evenly instead of sitting high: the pills at the top,
   the headline and its line in the middle, the buttons at the foot (the bottom bar is away while the form's card stands
   at the fold, main.js). On a short screen the parts simply follow one another. */
@media (max-width: 767px) {
  .hero--fold .hero__stage { min-height: 100vh; min-height: 100svh; }
  .hero--fold .hero__text { display: flex; flex-direction: column; padding-top: 6.75rem; padding-bottom: 2.75rem; }
  .hero--fold .hero__text > h1 { margin-top: auto; }
  .hero--fold .hero__text > .hero__actions { margin-top: auto; padding-top: 2.25rem; }
  .hero--fold .hero__form { padding-top: 2rem; }
}
@media (min-width: 768px) {
  /* 1.1.0 (A2): a photo hero ends exactly at the foot of the first screen. svh is the screen with the browser's bars
     showing, which is the screen a visitor lands on; min(100svh, 56rem) left a band of the page under it on every
     screen taller than 896px, and 88svh on sub pages a white stripe on every screen (qa.cjs [hero fold]). */
  .hero { min-height: 100vh; min-height: 100svh; overflow: hidden; }
  /* static: the photo (absolute, inset 0) then covers the whole hero edge to edge, as the engine's, not just this column */
  .hero__inner { position: static; display: grid; grid-template-columns: minmax(0, 1fr) 20rem; gap: 2.5rem; align-items: start; max-width: 80rem; margin-inline: auto; padding: min(11rem, 15svh + 3rem) 2.5rem 5rem; }
  .hero__stage { position: static; display: block; overflow: visible; }
  .hero__shade { background: linear-gradient(90deg, color-mix(in srgb, var(--deep) 90%, transparent) 0%, color-mix(in srgb, var(--deep) 78%, transparent) 40%, color-mix(in srgb, var(--deep) 45%, transparent) 75%, color-mix(in srgb, var(--deep) 35%, transparent) 100%), linear-gradient(0deg, color-mix(in srgb, var(--deep) 55%, transparent) 0%, color-mix(in srgb, var(--deep) 0%, transparent) 35%), linear-gradient(180deg, color-mix(in srgb, var(--deep) 60%, transparent) 0%, color-mix(in srgb, var(--deep) 0%, transparent) 25%); }
  .hero__text { padding: 1.5rem 0 0; text-align: left; max-width: 42rem; }
  .hero__chip, .hero__text > .pills { display: none; }
  .h1-a { font-size: 2.6rem; }
  .h1-b { font-size: 3.4rem; margin-top: 0.25rem; }
  .hero__sub { margin: 1.5rem 0 0; }
  .hero__actions { justify-content: flex-start; margin-top: 2.25rem; }
  .hero__rating { display: flex; }
  .hero__meta .pills { justify-content: flex-start; margin: 0.875rem 0 0; }
  .hero__form { background: none; padding: 0; }
  .hero__form > .card-form { max-width: none; }
}
@media (min-width: 1024px) { .hero__inner { grid-template-columns: minmax(0, 1fr) 24rem; gap: 4rem; padding-inline: 4rem; } .h1-a { font-size: 3.75rem; } .h1-b { font-size: 4.75rem; } }
@media (min-width: 1280px) { .h1-a { font-size: 4.5rem; } .h1-b { font-size: 5.5rem; } }
.hero__meta { display: none; }
@media (min-width: 768px) { .hero__meta { display: block; } }
/* A sub page's hero: the same pieces, a little shorter. */
.hero--sub { min-height: 0; }
@media (min-width: 768px) { .hero--sub { min-height: 100vh; min-height: 100svh; } .hero--sub .h1-a { font-size: 2.4rem; } .hero--sub .h1-b { font-size: 3rem; } }
@media (min-width: 1024px) { .hero--sub .h1-a { font-size: 3.25rem; } .hero--sub .h1-b { font-size: 4rem; } }
/* Page heading without a form (About, Contact, legal, posts): a dark band under the menu, over their photo when the page
   has one (.pagehead__photo under its shade), else on the site's dark colour alone (.pagehead--plain: no photo, no
   overlay; the band's own glow only). */
.pagehead { position: relative; background: var(--deep); color: #fff; overflow: hidden; padding: 8.5rem 0 4rem; }
@media (min-width: 640px) { .pagehead { padding: 10rem 0 5rem; } }
/* 1.1.0 (A2, B9, B10, B11): with a photo (About, Contact, gallery, their own pages) the page heading fills the first
   screen exactly, the text at its foot; the service areas overview (pagehead--short) is deliberately shorter, so the
   town cards clearly show under it (about a third of the screen, never a sliver: qa.cjs [hero fold]). */
.pagehead--photo { min-height: 100vh; min-height: 100svh; display: flex; flex-direction: column; justify-content: flex-end; padding-bottom: 3.5rem; }
@media (min-width: 640px) { .pagehead--photo { padding-bottom: 5rem; } }
/* 1.4.0 (visual review of Murermester Mathias, 13 Nov 2026): 56svh, so under the section's heading the town cards really
   show at 1440x900 (66svh left a 50px sliver of them). */
.pagehead--photo.pagehead--short { min-height: 56vh; min-height: 56svh; }
/* 1.4.0: on a phone the bottom bar (about 4.25rem) stands over the foot of a photo heading; its last button stays clear of
   it (the bar covered half of /kontakt/'s phone button at 390x844; qa.cjs [bottom bar]). */
@media (max-width: 639px) { body.has-callbar .pagehead--photo { padding-bottom: calc(3.5rem + 4.25rem + env(safe-area-inset-bottom)); } }
@media (min-width: 640px) and (max-width: 767px) { body.has-callbar .pagehead--photo { padding-bottom: calc(5rem + 4.25rem + env(safe-area-inset-bottom)); } }
.pagehead--photo > .wrap { width: 100%; }
.pagehead__photo { position: absolute; inset: 0; }
.pagehead__photo img { width: 100%; height: 100%; object-fit: cover; }
/* The overlay is the hero's (.hero__shade): the page's deep colour, strong where the text stands and lighter away from it,
   so the photo still shows. hero.scrim (20 to 85, --ps) lays an even shade of the deep colour on top: it only ever makes
   the overlay stronger, as on the hero. */
.pagehead__photo::before, .pagehead__photo::after { content: ''; position: absolute; inset: 0; pointer-events: none; }
.pagehead__photo::before { background: linear-gradient(to top, color-mix(in srgb, var(--deep) 70%, transparent), color-mix(in srgb, var(--deep) 0%, transparent) 55%), linear-gradient(to top right, color-mix(in srgb, var(--deep) 90%, transparent), color-mix(in srgb, var(--deep) 82%, transparent), color-mix(in srgb, var(--deep) 72%, transparent)); }
.pagehead__photo::after { background: var(--deep); opacity: var(--ps, 0); }
@media (min-width: 768px) { .pagehead__photo::before { background: linear-gradient(90deg, color-mix(in srgb, var(--deep) 90%, transparent) 0%, color-mix(in srgb, var(--deep) 82%, transparent) 55%, color-mix(in srgb, var(--deep) 55%, transparent) 85%, color-mix(in srgb, var(--deep) 42%, transparent) 100%), linear-gradient(180deg, color-mix(in srgb, var(--deep) 60%, transparent) 0%, color-mix(in srgb, var(--deep) 0%, transparent) 30%); } }
.pagehead .wrap { position: relative; }
.pagehead h1 { font-size: clamp(2.5rem, 7vw, 4.5rem); line-height: 1.02; max-width: 56rem; overflow-wrap: anywhere; }
.pagehead h1 .h1-b { font-size: 1.15em; margin-top: 0.25rem; }
.pagehead__sub { margin-top: 1.5rem; max-width: 42rem; font-size: 1.125rem; color: rgb(255 255 255 / 0.82); }
.pagehead .hero__actions { justify-content: flex-start; }
.crumbs { list-style: none; display: flex; flex-wrap: wrap; gap: 0.25rem 0.5rem; font-size: 0.875rem; color: rgb(255 255 255 / 0.75); margin-bottom: 1.25rem; }
.crumbs a { color: rgb(255 255 255 / 0.85); }
.crumbs li + li::before { content: '/'; margin-right: 0.5rem; opacity: 0.6; }
.hero .crumbs { justify-content: center; }
@media (min-width: 768px) { .hero .crumbs { justify-content: flex-start; } }

/* ---------- F. Section heading: bold sans line, italic serif accent line ---------- */
.shead { display: flex; flex-direction: column; gap: 1.25rem; margin-bottom: var(--head-gap); }
@media (min-width: 1024px) { .shead { flex-direction: row; align-items: flex-end; justify-content: space-between; gap: 2rem; } }
/* Every section heading has this size, inside .shead or not (the services band and the contact section set theirs
   beside their own content). */
.shead h2, .h2, .svc-band__aside h2, .contact__lead h2 { font-size: clamp(2.25rem, 6vw, 3.75rem); line-height: 1.05; max-width: 48rem; color: var(--ink); overflow-wrap: break-word; }
.tone-dark .shead h2, .tone-dark .h2, .tone-dark .svc-band__aside h2, .tone-dark .contact__lead h2 { color: #fff; }
.h2-b { display: block; font-family: var(--font-serif); font-style: italic; font-weight: 500; letter-spacing: -0.01em; color: var(--accent); font-size: 1em; line-height: 1.05; }
.tone-dark .h2-b { color: var(--deep-accent); }
.shead__aside { max-width: 28rem; }
@media (min-width: 1024px) { .shead__aside { text-align: right; } }
.shead__aside p { font-size: 1.125rem; line-height: 1.65; color: var(--muted); }
.tone-dark .shead__aside p { color: var(--deep-muted); }
.shead--center { align-items: center; text-align: center; }
@media (min-width: 1024px) { .shead--center { flex-direction: column; align-items: center; } }
.section-foot { margin-top: 2.5rem; }

/* ---------- G. Three cards (drawings or photos) ---------- */
.trio { display: grid; gap: 1.5rem; }
@media (min-width: 1024px) { .trio { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.trio__card { background: var(--surface); border: 1px solid var(--line); border-radius: 2rem; overflow: hidden; box-shadow: 0 1px 2px rgb(15 20 25 / 0.04); display: flex; flex-direction: column; text-decoration: none; color: inherit; }
@media (min-width: 768px) and (max-width: 1023px) { .trio__card { display: grid; grid-template-columns: 1fr 1fr; } }
/* The engine's frame: the accent at 6% on the white card, lighter than the drawing's own tint, so its filled parts read. */
.trio__frame { height: 13rem; padding: 1.5rem; background: rgb(var(--primary-rgb) / 0.06); border-bottom: 1px solid var(--line); display: flex; align-items: center; justify-content: center; }
.trio__frame--photo { padding: 0; background: var(--deep); }
.trio__frame--photo img { width: 100%; height: 100%; object-fit: cover; }
@media (min-width: 768px) and (max-width: 1023px) { .trio__frame { height: auto; min-height: 13rem; border-bottom: 0; border-right: 1px solid var(--line); } }
.trio__body { padding: 1.5rem 1.5rem 1.75rem; display: flex; flex-direction: column; gap: 0.75rem; flex: 1; }
@media (min-width: 640px) { .trio__body { padding: 1.75rem 1.75rem 2rem; } }
.trio__body h3 { font-size: 1.5rem; line-height: 1.15; color: var(--ink); }
.trio__body p { color: var(--muted); font-size: 0.9375rem; line-height: 1.65; }
.trio__more { margin-top: auto; padding-top: 0.25rem; align-self: flex-start; }
a.trio__card { transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 0.4s; }
@media (hover: hover) { a.trio__card:hover { transform: translateY(-3px); box-shadow: 0 24px 40px -24px rgb(var(--primary-rgb) / 0.35); } }

/* ---------- H. Numbers ---------- */
.numbers { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 2.5rem; overflow: hidden; box-shadow: 0 24px 50px -24px rgb(var(--primary-rgb) / 0.18); }
@media (min-width: 768px) { .numbers { grid-template-columns: repeat(var(--n, 3), minmax(0, 1fr)); } }
.numbers__item { background: var(--surface); padding: 2rem; }
@media (min-width: 640px) { .numbers__item { padding: 2.5rem; } }
@media (min-width: 1024px) { .numbers__item { padding: 3rem; } }
.numbers__value { display: flex; align-items: flex-end; gap: 0.25rem; line-height: 0.85; }
.numbers__num { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.03em; font-size: 5rem; color: var(--ink); font-variant-numeric: tabular-nums; }
/* The engine's scale: up to 4 characters 5 / 6 / 4.5 / 6 / 7rem at 0 / 640 / 768 / 1024 / 1280px; 5 characters
   (numbers--long) 5 / 6 / 3.5 / 4.75 / 6.5rem; 6 or more (numbers--xlong) 4.5 / 6 / 2.75 / 3.75 / 5rem. */
.numbers--xlong .numbers__num { font-size: 4.5rem; }
@media (max-width: 359px) { .numbers__num { font-size: 4rem; } .numbers--xlong .numbers__num { font-size: 3.5rem; } }
@media (min-width: 640px) { .numbers__num, .numbers--xlong .numbers__num { font-size: 6rem; } }
@media (min-width: 768px) { .numbers__num { font-size: 4.5rem; } .numbers--long .numbers__num { font-size: 3.5rem; } .numbers--xlong .numbers__num { font-size: 2.75rem; } }
@media (min-width: 1024px) { .numbers__num { font-size: 6rem; } .numbers--long .numbers__num { font-size: 4.75rem; } .numbers--xlong .numbers__num { font-size: 3.75rem; } }
@media (min-width: 1280px) { .numbers__num { font-size: 7rem; } .numbers--long .numbers__num { font-size: 6.5rem; } .numbers--xlong .numbers__num { font-size: 5rem; } }
.numbers__suffix { font-family: var(--font-serif); font-style: italic; font-weight: 500; font-size: clamp(2.25rem, 4vw, 3rem); color: var(--accent); margin-bottom: 0.5rem; }
.numbers__label { font-family: var(--font-display); font-weight: 600; font-size: 1.125rem; margin-top: 1.5rem; color: var(--ink); }
.numbers__desc { color: var(--muted); font-size: 0.9375rem; margin-top: 0.5rem; max-width: 20rem; }

/* ---------- I. Reviews ---------- */
.rev-card { display: flex; flex-direction: column; background: rgb(255 255 255 / 0.06); border: 1px solid rgb(255 255 255 / 0.1); border-radius: 2rem; padding: 1.5rem; }
@media (min-width: 640px) { .rev-card { padding: 1.75rem; } }
.rev-card blockquote { margin-top: 1rem; flex: 1; font-size: 0.9375rem; line-height: 1.65; color: rgb(255 255 255 / 0.9); }
.rev-card figcaption { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid rgb(255 255 255 / 0.1); }
.rev-card__name { display: block; font-family: var(--font-display); font-weight: 600; color: #fff; }
.rev-card__meta { display: block; font-size: 0.8125rem; color: rgb(255 255 255 / 0.7); }
.tone-light .rev-card { background: var(--surface); border-color: var(--line); }
.tone-light .rev-card blockquote { color: var(--ink); }
.tone-light .rev-card figcaption { border-color: var(--line); }
.tone-light .rev-card__name { color: var(--ink); }
.tone-light .rev-card__meta { color: var(--muted); }
.mq, .mq * { touch-action: pan-y; }
.mq-view { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent); mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent); }
.mq-track { display: flex; width: max-content; animation: mq-move calc(var(--n, 6) * 11s) linear infinite; will-change: transform; }
.mq-list { display: flex; align-items: stretch; gap: 1.25rem; padding: 0 0.625rem; list-style: none; }
.mq-list > li { width: 18rem; flex: none; display: flex; }
.mq-list > li > .rev-card { width: 100%; }
@media (min-width: 768px) { .mq-list > li { width: 21.25rem; } }
.mq.is-paused .mq-track { animation-play-state: paused; }
@keyframes mq-move { to { transform: translate3d(-50%, 0, 0); } }
@media (prefers-reduced-motion: reduce) { .mq, .mq * { touch-action: auto; } .mq-track { animation: none !important; will-change: auto; } .mq-view { overflow-x: auto; -webkit-mask-image: none; mask-image: none; } .mq-copy { display: none; } }
.rev-static { list-style: none; display: grid; gap: 1.25rem; justify-content: center; }
.rev-static > li { display: flex; max-width: 34rem; }
.rev-static > li > .rev-card { width: 100%; }
@media (min-width: 768px) { .rev-static--2 { grid-template-columns: repeat(2, minmax(0, 26rem)); } }

/* ---------- J. Steps ---------- */
.steps { display: grid; gap: 1.5rem; list-style: none; }
.step { background: linear-gradient(to bottom right, var(--surface), var(--base)); border: 1px solid var(--line); border-radius: 2.5rem; overflow: hidden; box-shadow: 0 24px 50px -24px rgb(var(--primary-rgb) / 0.14); transform-origin: 50% 0%; }
.step__grid { display: grid; }
.step__text { padding: 1.75rem; display: flex; flex-direction: column; justify-content: center; }
.step__num { font-family: var(--font-display); font-weight: 800; font-size: 4.5rem; line-height: 1; letter-spacing: -0.04em; color: rgb(var(--primary-rgb) / 0.16); margin-bottom: -0.5rem; display: block; }
.step__text h3 { font-size: clamp(1.875rem, 5vw, 3.75rem); line-height: 1.02; letter-spacing: -0.03em; color: var(--ink); font-weight: 700; }
.step__tag { font-family: var(--font-serif); font-style: italic; font-weight: 500; font-size: clamp(1.5rem, 3vw, 1.875rem); color: var(--accent); margin-top: 0.75rem; }
.step__text p:last-child { color: var(--muted); font-size: 1.0625rem; line-height: 1.65; max-width: 32rem; margin-top: 1.5rem; }
.step__media { position: relative; overflow: hidden; aspect-ratio: 16 / 10; background: var(--deep); }
.step__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.step__media--art { background: rgb(var(--primary-rgb) / 0.06); display: flex; align-items: center; justify-content: center; padding: 2rem; }
.step__media--art svg { position: relative; height: 100%; max-height: 16rem; }
@media (min-width: 640px) { .step__text { padding: 2.5rem; } }
@media (min-width: 768px) {
  .steps { gap: 2rem; }
  .step { position: sticky; top: 6.5rem; border-radius: 3rem; }
  .step__grid { grid-template-columns: 3fr 2fr; min-height: min(70svh, 44rem); }
  .step__num { font-size: 7rem; margin-bottom: -1rem; }
  .step__media { aspect-ratio: auto; }
  .step__text p:last-child { margin-top: 2.5rem; }
}
@media (min-width: 1024px) { .step__text { padding: 4rem; } .step__num { font-size: 10rem; } }
/* Under reduced motion and without JavaScript the cards stand still, one after another, never sticky. */
/* 1.4.0 (Nikolaj, 13 Nov 2026): on phones the number, the title, the italic line and the text stand evenly spaced (the
   title stood glued to "01" by its -0.5rem, the italic line far under it); qa.cjs [steps spacing]. */
@media (max-width: 767px) {
  .step__num { font-size: 4rem; line-height: 0.82; margin-bottom: 0.875rem; }
  .step__tag { margin-top: 0.5rem; line-height: 1.2; }
  .step__text p:last-child { margin-top: 1.125rem; }
}
@media (prefers-reduced-motion: reduce) { .step { position: relative; top: auto; } }
html:not(.js) .step { position: relative; top: auto; }

/* ---------- K. Services on the dark band ---------- */
.svc-band { display: grid; gap: 2.5rem; }
@media (min-width: 1024px) { .svc-band { grid-template-columns: 5fr 7fr; gap: 4rem; } .svc-band__aside { position: sticky; top: 7rem; align-self: start; } }
.svc-band__aside .lead { margin-top: 1.5rem; }
.svc-band__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem; margin-top: 2rem; }
.svc-band__phone { display: inline-flex; align-items: center; gap: 0.5rem; font-weight: 600; color: #fff; text-decoration: none; }
.svc-band__phone svg { width: 1rem; height: 1rem; color: var(--deep-accent); }
.svc-list { list-style: none; border-top: 1px solid rgb(255 255 255 / 0.1); }
.svc-list > li { border-bottom: 1px solid rgb(255 255 255 / 0.1); }
.svc-row { position: relative; display: flex; align-items: flex-start; gap: 1.25rem; padding: 1.75rem 0; text-decoration: none; color: #fff; outline: none; border-radius: 0.75rem; }
@media (min-width: 640px) { .svc-row { gap: 1.75rem; padding: 2rem 0; } }
.svc-row:focus-visible { box-shadow: 0 0 0 2px var(--deep-accent); }
.svc-row__icon { flex: none; width: 3rem; height: 3rem; border-radius: 1rem; background: rgb(var(--primary-rgb) / 0.15); box-shadow: inset 0 0 0 1px rgb(var(--primary-rgb) / 0.35); display: inline-flex; align-items: center; justify-content: center; color: var(--deep-accent); font-family: var(--font-display); font-weight: 700; font-size: 0.9375rem; transition: transform 0.4s; }
@media (min-width: 640px) { .svc-row__icon { width: 3.5rem; height: 3.5rem; } }
.svc-row__icon svg { width: 1.375rem; height: 1.375rem; }
.svc-row__body { min-width: 0; flex: 1; }
.svc-row__body h3 { font-size: 1.5rem; color: #fff; }
.svc-row__body p { margin-top: 0.5rem; color: rgb(255 255 255 / 0.72); font-size: 0.9375rem; line-height: 1.65; max-width: 36rem; }
.svc-row__arrow { display: none; flex: none; width: 2.75rem; height: 2.75rem; border-radius: 999px; border: 1px solid rgb(255 255 255 / 0.15); align-items: center; justify-content: center; color: rgb(255 255 255 / 0.7); transition: transform 0.4s; }
.svc-row__arrow svg { width: 1.25rem; height: 1.25rem; }
@media (min-width: 640px) { .svc-row__arrow { display: inline-flex; } }
.svc-row__line { position: absolute; left: 0; right: 0; bottom: -1px; height: 1px; background: var(--deep-accent); transform: scaleX(0); transform-origin: left; transition: transform 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94); }
@media (hover: hover) { .svc-row:hover .svc-row__line, .svc-row:focus-visible .svc-row__line { transform: scaleX(1); } .svc-row:hover .svc-row__arrow { transform: translate(3px, -3px); } .svc-row:hover .svc-row__icon { transform: translateY(-2px); } }
.svc-band__mark { position: absolute; left: -4rem; bottom: -4rem; width: 22rem; height: 22rem; color: rgb(255 255 255 / 0.035); pointer-events: none; }
.svc-band__mark svg { width: 100%; height: 100%; stroke-width: 1; }
@media (min-width: 1024px) { .svc-band__mark { width: 30rem; height: 30rem; } }
/* 1.4.0 (Nikolaj, 13 Nov 2026): masonry: a fine running-bond brick wall in hairlines (bricks about 3.7 to 1, every course
   offset by half a brick, as a real wall is laid), faint, fading out from the band's lower left corner. */
.svc-band__mark--bricks { left: 0; bottom: 0; width: 70%; height: 80%; max-width: 52rem; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='52' height='28'%3E%3Cpath d='M0 .5H52M0 14.5H52M.5 0V14M26.5 14V28' fill='none' stroke='%23fff' stroke-opacity='.09'/%3E%3C/svg%3E"); background-size: 52px 28px; background-position: left bottom; -webkit-mask-image: radial-gradient(ellipse 75% 85% at 0% 100%, #000 15%, transparent 70%); mask-image: radial-gradient(ellipse 75% 85% at 0% 100%, #000 15%, transparent 70%); }
@media (min-width: 1024px) { .svc-band__mark--bricks { width: 60%; height: 85%; } }

/* ---------- L. FAQ ---------- */
/* 1.4.1 (Nikolaj, 13 Nov 2026): a tighter gap between the FAQ's heading and its first question (it was the grid gap
   plus the heading's own margin, 72px at 390). */
.faq { display: grid; gap: 1.5rem; }
.faq > .shead { margin-bottom: 0; }
/* 1.1.0 (A6): the questions on the left, the heading on the right and sticky, from 1024px; on phones the heading first. */
@media (min-width: 1024px) { .faq { grid-template-columns: 7fr 5fr; gap: 4rem; } .faq .shead { order: 2; position: sticky; top: 7rem; align-self: start; margin-bottom: 0; flex-direction: column; align-items: flex-start; } .faq__list { order: 1; } .faq .shead__aside { text-align: left; } }
.faq__list { display: grid; gap: 0.875rem; }
.faq__item { background: var(--surface); border: 1px solid var(--line); border-radius: 1.5rem; overflow: hidden; }
.faq__item summary { list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1.25rem 1.5rem; font-family: var(--font-display); font-weight: 600; font-size: 1.125rem; line-height: 1.35; color: var(--ink); }
.faq__item summary::-webkit-details-marker { display: none; }
.faq__icon { flex: none; width: 2rem; height: 2rem; border-radius: 999px; background: var(--tint); color: var(--accent); display: inline-flex; align-items: center; justify-content: center; transition: transform 0.3s; }
.faq__icon svg { width: 1rem; height: 1rem; }
.faq__item[open] .faq__icon { transform: rotate(45deg); }
.faq__item.is-closing .faq__icon { transform: none; } /* 1.4.1: main.js slides the answer shut, then closes it */
/* 1.4.0 (Nikolaj, 13 Nov 2026): the answer is body text on the white card, near the ink (about 9.7:1), never the muted
   grey and never the dark band's light grey (.tone-dark p reached into the card: "Samme dag. Ring på ..." read light grey
   on white on Murermester Mathias). QA [faq] opens every answer and measures it. */
.faq__a { padding: 0 1.5rem 1.375rem; line-height: 1.7; }
.faq__item .faq__a, .faq__item .faq__a p, .faq__item .faq__a li { color: color-mix(in srgb, var(--ink) 82%, var(--surface)); }
.faq__a p + p { margin-top: 0.75rem; }

/* ---------- M. Forms and contact ---------- */
.card-form { background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: 2rem; padding: 1.5rem; box-shadow: 0 30px 60px -20px rgb(15 20 25 / 0.35); }
@media (min-width: 640px) { .card-form { padding: 1.75rem; } }
.card-form__title { font-family: var(--font-display); font-weight: 700; font-size: 1.5rem; line-height: 1.2; letter-spacing: -0.02em; color: var(--ink); }
.form { display: grid; gap: 1rem; }
.card-form .form { margin-top: 1.25rem; }
.form__row { display: grid; gap: 1rem; }
@media (min-width: 640px) { .form__row--2 { grid-template-columns: 1fr 1fr; } }
.field { display: grid; gap: 0.375rem; }
.field label, .field__label { font-size: 0.875rem; font-weight: 600; color: var(--ink); }
.field .req { color: var(--muted); font-weight: 500; }
.field input, .field select, .field textarea { width: 100%; background: var(--field); border: 1px solid var(--line); border-radius: 1rem; padding: 0.8125rem 1rem; color: var(--ink); font-size: 1rem; line-height: 1.4; outline: none; transition: border-color 0.2s, box-shadow 0.2s; }
.field textarea { min-height: 8rem; resize: vertical; }
.field input::placeholder, .field textarea::placeholder { color: color-mix(in srgb, var(--muted) 80%, transparent); }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--primary); box-shadow: 0 0 0 4px rgb(var(--primary-rgb) / 0.15); }
.field.is-bad input, .field.is-bad textarea, .field.is-bad select { border-color: #B42318; }
.field__err { font-size: 0.8125rem; color: #B42318; display: none; }
.field.is-bad .field__err { display: block; }
.upload { position: relative; border: 2px dashed var(--line); border-radius: 1.5rem; padding: 1.5rem; text-align: center; transition: border-color 0.2s, background-color 0.2s; }
.upload:hover, .upload.is-over { border-color: rgb(var(--primary-rgb) / 0.6); background: rgb(var(--primary-rgb) / 0.05); }
.upload input { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%; }
.upload svg { width: 1.5rem; height: 1.5rem; margin: 0 auto 0.5rem; color: var(--accent); }
.upload__title { display: block; font-family: var(--font-display); font-weight: 600; font-size: 0.875rem; }
.upload__hint { display: block; font-size: 0.75rem; color: var(--muted); margin-top: 0.25rem; }
.upload__files { list-style: none; display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem; margin-top: 0.75rem; }
.upload__files li { font-size: 0.75rem; background: rgb(var(--primary-rgb) / 0.1); color: var(--accent); border-radius: 999px; padding: 0.25rem 0.75rem; }
.form__note { font-size: 0.8125rem; line-height: 1.5; color: var(--muted); }
.card-form .form__note { text-align: center; }
.form__note a { color: inherit; }
.form__foot { display: flex; flex-direction: column; gap: 1rem; }
/* The full form (not .form--short): the note on the left, the button on the right, as the engine's quote form. */
@media (min-width: 640px) { .form:not(.form--short) .form__foot { flex-direction: row-reverse; align-items: center; justify-content: space-between; } .form:not(.form--short) .form__foot .btn { flex: none; } }
.form__consent { display: flex; gap: 0.625rem; align-items: flex-start; font-size: 0.8125rem; line-height: 1.5; color: var(--muted); }
.form__consent input { margin-top: 0.2rem; flex: none; width: 1.125rem; height: 1.125rem; accent-color: var(--accent-fill); }

.form__sms { display: grid; gap: 0.75rem; font-size: 0.8125rem; line-height: 1.45; color: var(--muted); }
.form__check { display: grid; grid-template-columns: auto 1fr; gap: 0.65rem; align-items: start; cursor: pointer; }
.form__check input { width: 1.125rem; height: 1.125rem; margin: 0.1rem 0 0; accent-color: var(--accent-fill); cursor: pointer; }
.form__legal a { color: inherit; text-decoration: underline; text-underline-offset: 0.15em; }
.form__done { display: none; text-align: center; padding: 2rem 0.5rem; }
.form__done:focus { outline: none; }
.form__done-icon { width: 3.5rem; height: 3.5rem; border-radius: 999px; background: rgb(var(--primary-rgb) / 0.15); color: var(--accent); display: inline-flex; align-items: center; justify-content: center; margin-bottom: 1.25rem; }
.form__done-icon svg { width: 1.75rem; height: 1.75rem; }
.form__done h3 { font-size: 1.5rem; color: var(--ink); margin-bottom: 0.5rem; }
.form__done p { color: var(--muted); }
.form__done a { color: var(--accent); font-weight: 600; }
.form.is-sent > *:not(.form__done) { display: none; }
.form.is-sent .form__done { display: block; }
.form.is-sending .btn { opacity: 0.7; cursor: progress; }
.form__fail { display: none; padding: 1.25rem; border-radius: 1rem; background: var(--surface); border: 2px solid var(--accent); }
.form__fail:focus { outline: none; }
.form__fail h3 { font-size: 1.125rem; margin-bottom: 0.5rem; }
.form__fail a { font-weight: 600; }
.form.is-failed .form__fail { display: block; }
.form__hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.form-done { text-align: center; padding: 2.5rem 0.5rem; }
.form-done__icon { width: 3.5rem; height: 3.5rem; border-radius: 999px; background: rgb(var(--primary-rgb) / 0.15); color: var(--accent); display: inline-flex; align-items: center; justify-content: center; margin-bottom: 1.25rem; }
.form-done__icon svg { width: 1.75rem; height: 1.75rem; }
.form-done h3, .form-done p:first-of-type { font-family: var(--font-display); font-weight: 700; font-size: 1.5rem; color: var(--ink); }
.form-done p { color: var(--muted); margin-top: 0.5rem; }
.hp { position: absolute !important; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.contact { display: grid; gap: 2.5rem; }
@media (min-width: 1024px) { .contact { grid-template-columns: 5fr 7fr; gap: 4rem; } }
.contact .lead { margin-top: 1.5rem; }
.contact__list { list-style: none; display: grid; gap: 1rem; margin-top: 2.5rem; }
.contact__row { display: flex; align-items: center; gap: 1rem; text-decoration: none; color: inherit; }
.contact__row--top { align-items: flex-start; }
.contact__icon { flex: none; width: 3rem; height: 3rem; border-radius: 1rem; background: rgb(var(--primary-rgb) / 0.1); border: 1px solid rgb(var(--primary-rgb) / 0.2); color: var(--accent); display: inline-flex; align-items: center; justify-content: center; transition: background-color 0.3s, color 0.3s; }
.contact__icon svg { width: 1.25rem; height: 1.25rem; }
a.contact__row:hover .contact__icon { background: var(--accent-fill); color: var(--on-accent); }
.contact__k { display: block; font-size: 0.875rem; color: var(--muted); }
.contact__v { display: block; font-family: var(--font-display); font-weight: 600; font-size: 1.125rem; color: var(--ink); overflow-wrap: break-word; }
/* An email wraps right before its "@" (lib/util.mjs emailHtml; Nikolaj, 13 Nov 2026: "murermestermathias1" / "@gmail.com").
   The "@" and the part after it are one inline-block: it breaks inside, at its <wbr> before a ".", only when it is itself
   wider than the line, and mid-word only when one piece alone is (qa.cjs [email]). It takes its link's underline, which does not reach into an inline-block by itself. */
a[href^="mailto:"], .email__d { overflow-wrap: break-word; }
.email__d { display: inline-block; text-decoration: inherit; }
.contact__hours { display: block; font-weight: 600; font-family: var(--font-display); }
.contact__hours span { font-family: var(--font-body); font-weight: 400; color: var(--muted); }
.contact__safe { margin-top: 2.5rem; padding: 1.25rem; border-radius: 1.5rem; background: rgb(var(--primary-rgb) / 0.05); border: 1px solid rgb(var(--primary-rgb) / 0.15); }
.contact__safe strong { display: block; font-family: var(--font-display); font-weight: 600; margin-bottom: 0.25rem; }
.contact__safe p { font-size: 0.875rem; color: var(--muted); }
.form-card { background: var(--surface); border: 1px solid var(--line); border-radius: 2.5rem; padding: 1.5rem; box-shadow: 0 24px 50px -24px rgb(var(--primary-rgb) / 0.16); }
@media (min-width: 640px) { .form-card { padding: 2.5rem; } }
.map { margin-top: 0; }
.map iframe { width: 100%; height: 22rem; border: 1px solid var(--line); border-radius: 1.75rem; }
@media (min-width: 640px) { .map iframe { height: 26rem; } }
.map__note { margin-top: 0.75rem; font-size: 0.875rem; color: var(--muted); }

/* ---------- N. Closing block above the footer (sub pages): Mathias v2's card ---------- */
.closer-sec { padding-block: 3.5rem; }
@media (min-width: 640px) { .closer-sec { padding-block: 5rem; } }
.closer { position: relative; overflow: hidden; background: var(--surface); border: 1px solid var(--line); border-radius: 2.5rem; padding: 2rem; box-shadow: 0 20px 25px -5px rgb(var(--primary-rgb) / 0.05), 0 8px 10px -6px rgb(var(--primary-rgb) / 0.05); }
@media (min-width: 640px) { .closer { border-radius: 3rem; padding: 3.5rem; } }
.closer__glow { position: absolute; top: -6rem; right: -6rem; width: 36rem; height: 24rem; --g: var(--glow-a, 0.16); }
.closer__grid { position: relative; display: grid; gap: 2rem; align-items: center; }
@media (min-width: 1024px) { .closer__grid { grid-template-columns: minmax(0, 1fr) 24rem; gap: 3.5rem; } }
.closer h2 { font-size: clamp(2.25rem, 6vw, 3.75rem); line-height: 1.02; color: var(--ink); }
.closer__text { margin-top: 1.25rem; font-size: 1.125rem; line-height: 1.65; color: var(--muted); max-width: 36rem; }
.closer__call { margin-top: 2rem; }
.closer .card-form { box-shadow: none; background: var(--base); padding: 1.5rem; border-radius: 1.75rem; }
.closer .card-form .form { margin-top: 0; }

/* ---------- O. Footer ---------- */
.footer { position: relative; background: var(--deep); color: #fff; overflow: hidden; border-top: 1px solid rgb(255 255 255 / 0.1); padding: 4rem 0 2.5rem; }
@media (min-width: 640px) { .footer { padding-top: 5rem; } }
/* The columns: the name, Pages, Services, Contact, and Service Areas last (render.mjs footer). Under 1280px Service Areas
   is one wrapped row under the others; from 1280px it is the fifth column for any number of town pages and every column
   stands in one row (qa.cjs footerProbe). Nikolaj, 13 Nov 2026: with 9 to 20 town pages (footer__grid--towns2) or 21 to
   30 (--towns3) the fifth column is wider and the others give a little; the contact column stays the widest of them, so
   a long email or the hours still fit. The fifth column never pushes the others (minmax(0, ...)): a long town name wraps
   inside it. */
.footer__grid { position: relative; display: grid; gap: 2.5rem; }
@media (min-width: 640px) { .footer__grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1024px) { .footer__grid { grid-template-columns: 4fr 2fr 3fr 3fr; } }
@media (min-width: 1280px) {
  .footer__grid--towns { grid-template-columns: 3fr 2fr 3fr 3fr minmax(0, 2.5fr); }
  .footer__grid--towns2 { grid-template-columns: 2.75fr 1.5fr 2.25fr 3.25fr minmax(0, 4.25fr); }
  .footer__grid--towns3 { column-gap: 2rem; grid-template-columns: 2.1fr 1.7fr 2.2fr 3.2fr minmax(0, 5.3fr); }
}
.footer__name { font-family: var(--font-display); font-weight: 700; font-size: 1.125rem; letter-spacing: -0.02em; }
.footer__about { margin-top: 1rem; color: rgb(255 255 255 / 0.72); font-size: 0.875rem; line-height: 1.65; max-width: 20rem; text-wrap: pretty; }
.footer h2 { font-family: var(--font-body); font-weight: 600; font-size: 0.875rem; letter-spacing: 0; margin-bottom: 1rem; color: #fff; }
.footer ul { list-style: none; display: grid; gap: 0.625rem; font-size: 0.875rem; }
.footer a { color: rgb(255 255 255 / 0.72); text-decoration: none; transition: color 0.2s; }
.footer a:hover { color: var(--deep-accent); }
.footer li { color: rgb(255 255 255 / 0.72); }
.footer address { font-style: normal; font-size: 0.875rem; line-height: 1.6; color: rgb(255 255 255 / 0.72); margin-bottom: 0.625rem; }
.footer address strong { color: #fff; font-weight: 600; }
/* Their town pages: under 1280px one wrapped row under the columns (the whole grid's width). From 1280px the fifth
   column: up to 8 in one list, 9 to 20 in 2 columns and 21 to 30 in 3 (footer__towns--c2, --c3), filled top to bottom,
   --town-rows lines each (render.mjs footerTownCols), so no list is longer than 10 lines (Nikolaj, 13 Nov 2026). A town
   name wraps inside its own column, a single long word too, never into the next. */
.footer__towns { grid-column: 1 / -1; padding-top: 0.5rem; }
.footer__towns ul { display: flex; flex-wrap: wrap; gap: 0.625rem 1.5rem; }
.footer__towns li { min-width: 0; overflow-wrap: anywhere; }
@media (min-width: 1280px) {
  .footer__towns--col { grid-column: auto; padding-top: 0; }
  .footer__towns--col ul { display: grid; }
  .footer__towns--c2 ul, .footer__towns--c3 ul { grid-auto-flow: column; grid-template-rows: repeat(var(--town-rows, 10), auto); column-gap: 1.5rem; }
  .footer__towns--c2 ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__towns--c3 ul { grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 1.25rem; }
}
/* Every line of the contact column is the size and colour of the footer's links; the hours label stands clear of the
   line above it, as a column heading does at the top. */
.footer__h-hours { margin-top: 1.75rem; }
.footer__hours, .footer__hours p, .footer .hours { font-size: 0.875rem; line-height: 1.6; color: rgb(255 255 255 / 0.72); }
.footer .hours dd { font-size: 1em; }
.footer__social { display: flex; gap: 0.5rem; margin-top: 1.25rem; }
.footer__social a { width: 2.5rem; height: 2.5rem; border-radius: 999px; border: 1px solid rgb(255 255 255 / 0.15); display: inline-flex; align-items: center; justify-content: center; }
.footer__social svg { width: 1.125rem; height: 1.125rem; }
.footer__bottom { position: relative; margin-top: 3.5rem; padding-top: 2rem; border-top: 1px solid rgb(255 255 255 / 0.1); display: flex; flex-direction: column; gap: 1rem; font-size: 0.8125rem; color: rgb(255 255 255 / 0.65); }
@media (min-width: 1024px) { .footer__bottom { flex-direction: row; align-items: center; justify-content: space-between; } }
.footer__bottom ul { display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; }
.footer__bottom a { color: rgb(255 255 255 / 0.7); }

/* ---------- P. Content blocks ---------- */
.prose { max-width: 46rem; font-size: 1.0625rem; line-height: 1.75; color: color-mix(in srgb, var(--ink) 88%, var(--base)); }
.prose > * + * { margin-top: 1.1em; }
.prose h2 { font-size: clamp(2.25rem, 6vw, 3.75rem); color: var(--ink); margin-bottom: 0.6em; } /* one size per heading level: as .shead h2 (QA [heading sizes]) */
.prose h3 { font-size: 1.5rem; color: var(--ink); margin-top: 1.75em; }
.prose h4 { font-size: 1.125rem; margin-top: 1.5em; }
.prose ul, .prose ol { padding-left: 1.25rem; }
.prose li + li { margin-top: 0.4em; }
.prose ul li::marker { color: var(--accent); }
/* Text links only: a filled button in the prose (a block's `button`) keeps its own colours (.btn--accent's text on its
   fill read 1.40:1 under `.prose a`, Groves Electric; QA [button text]). */
/* 1.1.0 (C16): the underline of a text link is drawn, not the font's: one 1px line at a fixed distance under the
   text, the same before, during and after hover (text-decoration-thickness: auto let browsers redraw it thicker and
   lower at some sizes and positions). Hover changes only its colour; nothing moves (qa.cjs [link hover]). */
.prose a:not(.btn), .faq__a a, .closer__text a, .lead a { color: var(--accent); text-decoration: none; background-image: linear-gradient(currentColor, currentColor); background-size: 100% 1px; background-position: 0 calc(100% - 0.05em); background-repeat: no-repeat; padding-bottom: 0.1em; -webkit-box-decoration-break: clone; box-decoration-break: clone; transition: color 0.2s; }
@media (hover: hover) { .prose a:not(.btn):hover, .faq__a a:hover, .closer__text a:hover, .lead a:hover { color: color-mix(in srgb, var(--accent) 78%, var(--ink)); } }
.prose strong { color: var(--ink); }
.prose blockquote { border-left: 3px solid var(--primary); padding-left: 1.25rem; font-family: var(--font-serif); font-style: italic; font-size: 1.375rem; color: var(--ink); }
.tone-dark .prose, .tone-dark .prose h2, .tone-dark .prose h3, .tone-dark .prose strong { color: #fff; }
.tone-dark .prose { color: rgb(255 255 255 / 0.85); }
.tone-dark .prose a:not(.btn) { color: var(--deep-accent); }
@media (hover: hover) { .tone-dark .prose a:not(.btn):hover { color: #fff; } }
.split { display: grid; gap: 2.5rem; align-items: start; }
/* 1.1.0 (A3): every text block stands beside a photo, the sides alternating down the page (render.mjs data-side); a
   short text sits level with the middle of its photo instead of leaving an empty band under it. */
@media (min-width: 960px) { .split { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 4rem; align-items: center; } .split--rev { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); } .split--rev > .figure { order: -1; } }
.figure { position: relative; }
.figure img { width: 100%; border-radius: 2rem; aspect-ratio: 4 / 3; object-fit: cover; object-position: var(--focus, 50% 50%); }
/* From 960px the photo is as tall as its text (cropped to it), never under 18rem and never over 40rem, so a short text
   never stands beside a tall photo (qa.cjs [split]: never more than twice the text) and a long one gets its photo along. */
@media (min-width: 960px) {
  .split > .figure { align-self: center; height: 100%; min-height: 18rem; max-height: 40rem; }
  .split > .figure img { position: absolute; inset: 0; height: 100%; aspect-ratio: auto; }
  .split > .figure:has(figcaption) img { height: calc(100% - 2.25rem); }
  .split > .figure figcaption { position: absolute; left: 0; right: 0; bottom: 0; }
}
.figure figcaption, .gallery figcaption { margin-top: 0.75rem; font-size: 0.875rem; color: var(--muted); }
.grid { display: grid; gap: 1.5rem; }
@media (min-width: 768px) { .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } .grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.grid--1 { max-width: 42rem; }
.card { background: var(--surface); border: 1px solid var(--line); border-radius: 2rem; overflow: hidden; display: flex; flex-direction: column; text-decoration: none; color: inherit; }
.card__img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; }
.card__portrait { width: 7.5rem; height: 7.5rem; border-radius: 999px; object-fit: cover; margin: 1.75rem 1.75rem 0; }
.card__body { padding: 1.5rem 1.75rem 1.75rem; display: flex; flex-direction: column; gap: 0.625rem; flex: 1; }
.card__body h3 { font-size: 1.5rem; color: var(--ink); }
.card__body p { color: var(--muted); font-size: 0.9375rem; line-height: 1.65; }
.card__more { margin-top: auto; padding-top: 0.5rem; align-self: flex-start; }
.card__btn { margin-top: auto; align-self: flex-start; }
.card--link { transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 0.4s; }
@media (hover: hover) { .card--link:hover { transform: translateY(-3px); box-shadow: 0 24px 40px -24px rgb(var(--primary-rgb) / 0.35); } }
.tone-dark .card { background: rgb(255 255 255 / 0.06); border-color: rgb(255 255 255 / 0.1); }
.tone-dark .card__body h3 { color: #fff; }
.tone-dark .card__body p { color: rgb(255 255 255 / 0.75); }
/* The service areas page (render.mjs towns): one card per town, the name and, for a town page, its summary line under
   it and the arrow; a town without a page is a plain card with its name. Nothing inside a card has a border of its own. */
.towns { list-style: none; display: grid; gap: 0.75rem; grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr)); }
.towns__item { display: flex; }
.towns__card { flex: 1; display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem; padding: 1.125rem 1.25rem; border-radius: 1.25rem; background: var(--surface); border: 1px solid var(--line); text-decoration: none; color: var(--ink); transition: border-color 0.3s; }
.towns__text { display: grid; gap: 0.25rem; min-width: 0; }
.towns__name { font-family: var(--font-display); font-weight: 600; font-size: 1.0625rem; line-height: 1.3; color: var(--ink); }
.towns__sum { font-size: 0.875rem; line-height: 1.55; color: var(--muted); }
.towns__card > svg { flex: none; width: 1rem; height: 1rem; margin-top: 0.25rem; color: var(--accent); }
/* 1.1.0 (B11): every town has a face: a photo of that town (scripts/place-photos.mjs; 1.2.0: credited in the terms
   page's photo credits, never on the photo) or, with no real photo of it, a drawn card (a map sketch and a pin with its
   letter, in the accent). A town page's card is one link (its name, stretched over the card). */
/* Nikolaj, 13 Nov 2026: no card alone on the last row. The columns per width band come from render.mjs townGridCols (on
   the list: --tc2, --tc3, --tc4 for the bands from 600, 960 and 1200px; one column on phones), the maxima the old
   auto-fill grid of 16.5rem cards had. Where no count avoids a lone card, --ts* 2 lets the first card span two columns,
   and its picture keeps the height of the others in its row (100cqi: the list's width; 2px: the card's border).
   qa.cjs [town grid]. */
.towns { --tc: 1; --ts: 1; gap: 1.25rem; grid-template-columns: repeat(var(--tc), minmax(0, 1fr)); container-type: inline-size; }
@media (min-width: 600px) { .towns { --tc: var(--tc2, 2); --ts: var(--ts2, 1); } }
@media (min-width: 960px) { .towns { --tc: var(--tc3, 3); --ts: var(--ts3, 1); } }
@media (min-width: 1200px) { .towns { --tc: var(--tc4, 4); --ts: var(--ts4, 1); } }
.towns > .towns__item:first-child { grid-column: span var(--ts); }
@supports (height: 1cqi) { .towns > .towns__item:first-child :is(.towns__fig, .towns__art) { aspect-ratio: auto; height: calc(((100cqi - (var(--tc) - 1) * 1.25rem) / var(--tc) - 2px) / 1.5); } }
.towns__card--photo, .towns__card--drawn { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto 1fr; align-items: start; gap: 0; padding: 0; overflow: hidden; border-radius: 1.75rem; transition: border-color 0.3s, transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 0.4s; }
.towns__fig, .towns__art { grid-column: 1 / -1; position: relative; margin: 0; aspect-ratio: 3 / 2; overflow: hidden; }
.towns__fig { background: var(--deep); }
.towns__fig img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.7s cubic-bezier(0.25, 0.46, 0.45, 0.94); }
.towns__art { display: block; color: var(--accent); border-bottom: 1px solid var(--line); background: radial-gradient(circle at 50% 42%, rgb(var(--primary-rgb) / 0.16), rgb(var(--primary-rgb) / 0) 62%), radial-gradient(rgb(var(--primary-rgb) / 0.16) 1px, transparent 1.4px) 0 0 / 1rem 1rem, rgb(var(--primary-rgb) / 0.05); }
.towns__art svg { display: block; width: 100%; height: 100%; }
.towns__card--photo .towns__text, .towns__card--drawn .towns__text { padding: 1.125rem 0 1.25rem 1.25rem; }
.towns__card--photo > svg, .towns__card--drawn > svg { margin: 1.4rem 1.25rem 0 0.75rem; }
.towns__card--photo .towns__name, .towns__card--drawn .towns__name { font-size: 1.1875rem; font-weight: 700; color: var(--ink); text-decoration: none; }
.towns__link::after { content: ''; position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
.towns__link:focus-visible { outline: none; }
.towns__card--link:has(.towns__link:focus-visible) { outline: 2px solid var(--accent); outline-offset: 3px; }
@media (hover: hover) { .towns__card--link:hover { border-color: rgb(var(--primary-rgb) / 0.5); transform: translateY(-3px); box-shadow: 0 24px 40px -24px rgb(var(--primary-rgb) / 0.35); } .towns__card--link:hover .towns__fig img { transform: scale(1.04); } }
.posts { list-style: none; display: grid; gap: 1.25rem; }
@media (min-width: 768px) { .posts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.posts a { display: block; padding: 1.75rem; border-radius: 1.75rem; background: var(--surface); border: 1px solid var(--line); text-decoration: none; color: inherit; height: 100%; }
.posts h3 { font-size: 1.5rem; color: var(--ink); }
.posts p { margin-top: 0.625rem; color: var(--muted); }
.posts time { display: block; font-size: 0.8125rem; color: var(--muted); margin-bottom: 0.5rem; }
.legal { max-width: 46rem; }
.legal h2 { font-size: 1.5rem; margin: 2.5rem 0 1rem; color: var(--ink); }
.legal h2:first-child { margin-top: 0; }
.legal h3 { font-size: 1.125rem; margin: 1.75rem 0 0.75rem; }
.legal p, .legal li { color: color-mix(in srgb, var(--ink) 82%, var(--base)); line-height: 1.75; }
.legal p + p { margin-top: 1rem; }
.legal ul, .legal ol { padding-left: 1.25rem; margin: 1rem 0; }
.legal a { color: var(--accent); }
/* The logos row (render.mjs logos): drawn as lib/logos.mjs measures it (LOGO_ROW): every logo --lg-h tall (40px from
   768px, 32px under it) at its own width, muted (greyscale at 70%), in full colour on hover; when the build put the row
   on plates (logos--plates), every logo on its own plate (--lg-plate). Change LOGO_ROW and this together; qa.cjs
   logosStatic measures the drawn row against LOGO_ROW. */
.logos { --lg-h: 32px; --lg-gap: 1.4; list-style: none; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: calc(var(--lg-h) * 0.6) calc(var(--lg-h) * var(--lg-gap)); }
@media (min-width: 768px) { .logos { --lg-h: 40px; } }
.logos--plates { --lg-gap: 0.6; }
.lg__item { flex: none; display: flex; align-items: center; justify-content: center; }
.logos--plates .lg__item { background: var(--lg-plate, var(--surface)); padding: calc(var(--lg-h) * 0.3) calc(var(--lg-h) * 0.5); border-radius: 1rem; }
.lg__img { display: block; height: var(--lg-h); width: calc(var(--lg-h) * var(--ar, 2)); max-width: none; filter: grayscale(1); opacity: 0.7; transition: filter 0.3s ease, opacity 0.3s ease; }
@media (hover: hover) { .lg__item:hover .lg__img { filter: none; opacity: 1; } }

/* ---------- R. Ported content blocks ---------- */
/* ---- From narto-site 3.106.0 (base.css), with the engine radii: gallery, offices and hours, before/after, prices,
   locations, embeds, video, social icons. Their markup in render.mjs is unchanged. ---- */
/* v3.63.2: render.mjs plans full rows for each width: up to 2 photos a row from 40rem, 3 from 58rem, 4 from 76rem (where
   the 17rem tiles of auto-fill gave 2, 3 and 4), in a grid of --gM tracks, each photo spanning --sM of them */
.gallery { display: grid; gap: 1rem; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 40rem) { .gallery { grid-template-columns: repeat(var(--g2, 2), minmax(0, 1fr)); } .gallery > img { grid-column: span var(--s2, 1); } }
@media (min-width: 58rem) { .gallery { grid-template-columns: repeat(var(--g3, 3), minmax(0, 1fr)); } .gallery > img { grid-column: span var(--s3, 1); } }
@media (min-width: 76rem) { .gallery { grid-template-columns: repeat(var(--g4, 4), minmax(0, 1fr)); } .gallery > img { grid-column: span var(--s4, 1); } }
.gallery img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; border-radius: var(--radius); }
/* v3.46.0: two photos: stacked on a phone; from 40rem one centred row of two, each the size of a tile in a row of three
   (never two of four tracks with the rest empty) */
@media (min-width: 40rem) { .gallery--two { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 52rem; margin-inline: auto; } }
.offices { display: grid; gap: var(--grid-gap); grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
.office { padding: 1.75rem; display: grid; gap: 0.5rem; align-content: start; }
.office address { font-style: normal; color: var(--muted); }
.office .mono { color: var(--ink); }
/* v3.18.0: six offices and an email card make narrow columns; a long address or email breaks instead of overflowing. */
.office a { overflow-wrap: break-word; }
/* v3.62.0: opening hours as rows (lib/hours.mjs), wherever they show: a small table, the days left, the times right, one
   row per day group, spaced, not ruled. The days share one column, so every time starts at the same place; a long time
   wraps inside its own column. The row's div only groups its dt and dd (valid in a dl).
   A time range never breaks (lib/hours.mjs joins it across its dash), so where a range does not fit beside the days,
   the days wrap at a space instead of breaking it (Svendsens EL's footer broke "10:00-17:00" after its dash beside
   "mandag, tirsdag, lørdag, søndag"; qa.cjs hoursRows). Where both fit, nothing moves: the days as wide as they are. */
.hours { display: grid; grid-template-columns: auto 1fr; gap: 0.4rem 1rem; align-items: baseline; width: 100%; max-width: 28rem; }
.hours > div { display: contents; }
.hours dd { font-size: 0.92em; }
.footer address .hours { margin: 0.35rem 0 0; }

/* The footer's Hours column takes a little from the brand and Pages columns when it holds the table. */


/* v3.18.0: before/after sliders of their own jobs (render.mjs compare, backlog 33). Without JavaScript, or until main.js
   wires a frame (is-live), the two photos stand side by side, each with its label. Live, the after photo is clipped at
   --pos over the before photo; a drag, a touch (sideways; scrolling up and down still works) or the arrow keys on the
   focused slider move the divider. */
/* v3.94.3: rows planned by render.mjs (a pair side by side counts as two photos). From 48rem a row is one flex line in
   which each item grows by its shape (--cmp-g: width/height, twice that for a pair, whose basis is its 0.5rem inner
   gap), so every frame in the row has the same height and the row is full: no empty field under a pair beside a
   slider. The row's width is capped so that height stays under the live frame's 80svh. Below 48rem each item stands
   alone, full width. */
.cmp-grid, .cmp-row { display: grid; gap: var(--grid-gap); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 48rem) {
  .cmp-row { display: flex; align-items: flex-start; max-width: calc(var(--cmp-s) * 80svh + (var(--cmp-n) - 1) * var(--grid-gap) + var(--cmp-p) * 0.5rem); }
  .cmp-row > .cmp { flex: var(--cmp-g) 1 0%; min-width: 0; }
  .cmp-row > .cmp--pair { flex-basis: 0.5rem; }
  /* v3.98.3: a lone item fills its row (capped at its 80svh width above); grown by a --cmp-g under 1 it took only that
     share (sydfyns-haveservice's single 3:4 slider was 405x540 at 1440x900, not 540x720) */
  .cmp-row--1 > .cmp { flex-grow: 1; }
}
.cmp-row--1 { max-width: min(64rem, var(--cmp-s) * 80svh + var(--cmp-p) * 0.5rem); }
/* v3.100.3: one pair (render.mjs .compare--solo) has the heading and text on its left from 48rem, against the column's
   right edge and centred on the text, only when the text's minimum width fits beside the pair at its full size: this is
   one wrapping flex line, so a portrait slider that left 676px empty at 1440 (sydfyns-haveservice) moves up beside the
   text, and a wide pair goes to the next line and is drawn exactly as before, under the heading (3.100.2 shrank it to fit:
   1024x677 became 792x523). No pair is ever made smaller. qa.cjs compareRows holds the same numbers. Below 48rem the
   heading stands above it, as ever. */
@media (min-width: 48rem) {
  .compare--solo > .wrap { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; column-gap: clamp(2rem, 5vw, 5rem); row-gap: var(--heading-gap); }
  .compare--solo .section-head { flex: 1 1 min(22rem, 36%); min-width: 0; margin-bottom: 0; }
  .compare--solo h2 { overflow-wrap: break-word; }
  .compare--solo .cmp-grid { flex: 0 1 min(64rem, var(--cmp-s) * 80svh + var(--cmp-p) * 0.5rem); min-width: 0; }
}
/* Each item keeps its own photo's shape (render.mjs): on a phone, where it stands alone at full width, a tall photo is
   narrowed to what 80svh allows instead of being cut by the frame's max-height. */
.cmp-row > .cmp { max-width: calc(var(--cmp-g) * 80svh); }
.cmp-row > .cmp--pair { max-width: calc(var(--cmp-g) * 80svh + 0.5rem); }
.cmp { display: grid; gap: 0.75rem; align-content: start; }
.cmp figcaption { font-size: 0.95rem; color: var(--muted); }
.cmp__frame { position: relative; display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
.cmp__half { position: relative; overflow: hidden; border-radius: var(--radius); }
.cmp__img { display: block; width: 100%; height: auto; aspect-ratio: var(--cmp-ar); object-fit: cover; }
.cmp__tag { position: absolute; top: 0.75rem; left: 0.75rem; font-size: 0.78rem; padding: 0.28rem 0.7rem; border-radius: 999px; background: color-mix(in srgb, var(--hero-base) 72%, transparent); color: var(--hero-ink); }
.cmp__line, .cmp__range { display: none; }
.cmp__frame.is-live { display: block; aspect-ratio: var(--cmp-ar); max-height: 80svh; overflow: hidden; border-radius: var(--radius); touch-action: pan-y; cursor: ew-resize; -webkit-user-select: none; user-select: none; }
.cmp__frame.is-live .cmp__half { position: absolute; inset: 0; border-radius: 0; }
.cmp__frame.is-live .cmp__img { aspect-ratio: auto; height: 100%; -webkit-user-drag: none; }
.cmp__frame.is-live .cmp__half--after { clip-path: inset(0 0 0 var(--pos, 50%)); }
.cmp__frame.is-live .cmp__half--after .cmp__tag { left: auto; right: 0.75rem; }
.cmp__frame.is-live .cmp__line { display: block; position: absolute; top: 0; bottom: 0; left: var(--pos, 50%); width: 2px; margin-left: -1px; background: var(--hero-ink); pointer-events: none; }
.cmp__knob { position: absolute; top: 50%; left: 50%; width: 2.6rem; height: 2.6rem; margin: -1.3rem 0 0 -1.3rem; border-radius: 50%; background: var(--hero-ink); box-shadow: 0 0.4rem 1rem rgb(0 0 0 / 0.35); }
.cmp__knob::before, .cmp__knob::after { content: ''; position: absolute; top: 50%; width: 0.45rem; height: 0.45rem; border-left: 2px solid var(--hero-base); border-bottom: 2px solid var(--hero-base); }
.cmp__knob::before { left: 0.65rem; transform: translateY(-50%) rotate(45deg); }
.cmp__knob::after { right: 0.65rem; transform: translateY(-50%) rotate(-135deg); }
/* The range is the keyboard and screen-reader control: focusable, not hit by the pointer (the frame takes the drag). */
.cmp__frame.is-live .cmp__range { display: block; position: absolute; left: 0; bottom: 0; width: 100%; height: 1px; margin: 0; opacity: 0; pointer-events: none; }
.cmp__frame.is-live:focus-within { outline: 3px solid var(--accent); outline-offset: 3px; }

/* v3.18.0: the business's own prices (render.mjs prices, backlog 45): the service and its price on one line, options
   under it, the booking link beside the list. */
.prices__loc { color: var(--muted); margin: -0.75rem 0 1.5rem; }
.prices { display: grid; gap: 2rem var(--grid-gap); max-width: 56rem; }
/* v3.18.1: two columns only when the groups split evenly (render.mjs priceColumns); otherwise one column. The groups
   flowed in CSS columns, and a group never splits, so EverCutz' 1 + 12 + 3 rows stood 13 beside 3. */
.prices__col { display: grid; gap: 2rem; align-content: start; }
@media (min-width: 60rem) { .prices--cols { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: none; } }
.prices__group h3 { margin-bottom: 0.5rem; }
.prices__list { list-style: none; display: grid; }
.price { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0.25rem 1.25rem; align-items: baseline; padding: 0.85rem 0; border-bottom: 1px solid var(--line); }
.price__name { font-weight: 700; text-align: left; }
/* dir="auto" keeps a mixed-script name in its reading order; the row still starts on the left (EverCutz's names that
   begin in Arabic stood at the right edge). */
.price__opts li > span:first-child { text-align: left; }
.price__val { color: var(--ink); white-space: nowrap; }
.price__opts { grid-column: 1 / -1; list-style: none; display: grid; gap: 0.3rem; color: var(--muted); font-size: 0.95rem; }
.price__opts li { display: flex; justify-content: space-between; gap: 1.25rem; padding-left: 1rem; }
.price__opts .mono { color: var(--ink); white-space: nowrap; }
.prices__act { margin-top: 2rem; }
.prices__act .btn { max-width: 100%; }

/* v3.18.0: several locations (backlog 35): each with its own phone, hours and booking link in the CTA. */
.locs { list-style: none; display: grid; gap: 1.25rem; }
.loc { display: grid; gap: 0.4rem; padding-bottom: 1.25rem; border-bottom: 1px solid var(--line); }
.loc:last-child { border-bottom: 0; padding-bottom: 0; }
.loc__name { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.75rem; }
.loc__acts { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem 1.25rem; margin-top: 0.35rem; }
.loc__acts .btn { max-width: 100%; }
.menu-locs { list-style: none; display: grid; gap: 0.6rem; }

.menu-locs .btn { width: 100%; }

.embed { display: grid; gap: 1.25rem; justify-items: start; padding: clamp(1.5rem, 3vw, 2.5rem); }
.embed__slot { width: 100%; }
/* v3.34.0: the client's own form, calendar or video in an iframe, loaded on the button or when scrolled near (main.js) */
.embed--frame { padding: 0; gap: 1rem; width: 100%; }
/* the frame's height is held before it loads, so loading it never moves the page under a pinned section.
   v3.63.1: until then the space is a quiet panel with the button in its middle; the loaded frame takes the panel's
   place (main.js), and a Gymdesk widget's own height replaces --embed-h, so no empty band stays under it. */
.js .embed--frame .embed__slot { display: grid; place-items: center; min-height: var(--embed-h, 760px); padding: 1.5rem; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); }
.js .embed--video .embed__slot { min-height: 0; aspect-ratio: 16 / 9; }
.js .embed--frame.is-loaded .embed__slot { display: block; padding: 0; background: none; border: 0; }
.embed--frame.is-loaded .embed__start { display: none; }
.embed--frame iframe { display: block; width: 100%; height: var(--embed-h, 760px); border: 0; border-radius: var(--radius); background: var(--base); }
.embed--video iframe { height: auto; aspect-ratio: 16 / 9; }
.embed__note { color: var(--muted); }
.embed__note a { color: var(--accent); text-underline-offset: 0.2em; }
.cta__embed { min-width: 0; }
.video { margin: 0; display: grid; gap: 0.75rem; }
.video__start, .video__slot iframe { position: relative; display: grid; place-items: center; width: 100%; aspect-ratio: 16 / 9; border-radius: var(--radius-lg); overflow: hidden; background: var(--deep, #111); color: #fff; text-decoration: none; border: 0; }
.video__poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0.85; }
.video__play { position: relative; display: grid; place-items: center; width: 4.5rem; height: 4.5rem; border-radius: 50%; background: var(--accent-fill); color: var(--on-accent); }
.video__play svg { width: 2rem; height: 2rem; margin-left: 0.2rem; }
.video__title { position: absolute; left: 1.25rem; bottom: 1rem; right: 1.25rem; font-weight: 700; text-shadow: 0 1px 8px rgb(0 0 0 / 0.6); }
.video.is-playing .video__start { display: none; }
.video__slot:empty { display: none; }
.video figcaption { color: var(--muted); font-size: 0.95rem; }
/* v3.40.0: social icons in the footer and the menu panel (render.mjs socialLinks) */
ul.social { display: flex; flex-wrap: wrap; gap: 0.5rem; list-style: none; padding: 0; }
.social li + li { border-top: 0 !important; }
.social a.social__icon { display: inline-grid; place-items: center; width: 2.75rem; height: 2.75rem; border-radius: 50%; box-shadow: inset 0 0 0 1px var(--line); color: inherit; text-decoration: none; padding: 0 !important; }
.social a.social__icon svg { width: 1.25rem; height: 1.25rem; }
.social a.social__text { display: inline-flex; align-items: center; min-height: 2.75rem; padding: 0 0.9rem !important; border-radius: 999px; box-shadow: inset 0 0 0 1px var(--line); text-decoration: none; font-size: 0.95rem !important; font-weight: 600 !important; }
@media (hover: hover) { .social a:hover { box-shadow: inset 0 0 0 1px currentColor; } }

/* ---------- Q. Motion: fade-ins (only with JavaScript and without reduced motion) ---------- */
html.js.motion [data-reveal] > * { opacity: 0; transform: translateY(24px); transition: opacity 0.7s cubic-bezier(0.22, 0.61, 0.36, 1), transform 0.7s cubic-bezier(0.22, 0.61, 0.36, 1); transition-delay: calc(var(--i, 0) * 90ms); }
html.js.motion [data-reveal].is-in > * { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } }

/* ---------- S. Nikolaj's review, 12 Nov 2026 (1.1.0) ---------- */
/* B7: the backdrops. The home contact section, the contact page's form section and the closing block above the footer
   stand on the light page with one of these behind them, so each reads as a new section without a dark band next to
   the dark footer. One set, tinted from the accent, one kind per site (brand.backdrop: grid, the default, dots or orbs;
   render.mjs: .has-bd and its .bd). Behind the content (z-index -1 in the section's own stacking context), never over
   it: the text keeps its 4.5:1 on the light colour (qa.cjs [backdrop]). The orbs drift slowly, and stand still under
   reduced motion. */
.has-bd { isolation: isolate; --accent: var(--accent-bd, var(--accent-ink)); }
.bd { position: absolute; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; }
.bd::before { content: ''; position: absolute; inset: 0; }
.bd::after { content: ''; position: absolute; top: 0; left: 10%; right: 10%; height: 1px; background: linear-gradient(90deg, rgb(var(--primary-rgb) / 0), rgb(var(--primary-rgb) / 0.45), rgb(var(--primary-rgb) / 0)); }
.bd > span { position: absolute; border-radius: 50%; background: radial-gradient(closest-side, rgb(var(--primary-rgb) / var(--glow-a, 0.16)), rgb(var(--primary-rgb) / 0)); }
.bd > span:nth-child(1) { width: 44rem; height: 30rem; top: -12rem; right: -10rem; }
.bd > span:nth-child(2) { width: 34rem; height: 26rem; bottom: -10rem; left: -10rem; opacity: 0.8; }
.bd--grid::before { background-image: linear-gradient(rgb(var(--primary-rgb) / calc(var(--glow-a, 0.16) * 0.875)) 1px, transparent 1px), linear-gradient(90deg, rgb(var(--primary-rgb) / calc(var(--glow-a, 0.16) * 0.875)) 1px, transparent 1px); background-size: 3rem 3rem; background-position: center top; -webkit-mask-image: radial-gradient(ellipse 75% 70% at 50% 0%, #000 20%, transparent 72%); mask-image: radial-gradient(ellipse 75% 70% at 50% 0%, #000 20%, transparent 72%); }
.bd--dots::before { background-image: radial-gradient(rgb(var(--primary-rgb) / calc(var(--glow-a, 0.16) * 1.6)) 1.1px, transparent 1.6px); background-size: 1.375rem 1.375rem; -webkit-mask-image: radial-gradient(ellipse 80% 75% at 50% 0%, #000 15%, transparent 70%); mask-image: radial-gradient(ellipse 80% 75% at 50% 0%, #000 15%, transparent 70%); }
.bd--orbs > span { background: radial-gradient(closest-side, rgb(var(--primary-rgb) / calc(var(--glow-a, 0.16) * 1.3)), rgb(var(--primary-rgb) / 0)); animation: bd-drift 22s ease-in-out infinite alternate; }
.bd--orbs > span:nth-child(2) { animation-duration: 28s; animation-direction: alternate-reverse; }
@keyframes bd-drift { to { transform: translate3d(-4rem, 3rem, 0) scale(1.12); } }
@media (prefers-reduced-motion: reduce) { .bd > span { animation: none !important; } }
/* The closing block's card is white on the backdrop; the home contact section's form card already is. */
.closer-sec.has-bd .closer { box-shadow: 0 30px 60px -30px rgb(var(--primary-rgb) / 0.28), 0 8px 10px -6px rgb(15 20 25 / 0.04); }

/* B8: their photos large. 4 or more: a marquee that runs left to right, against the reviews (right to left); 1 to 3:
   large, side by side. No pause control; main.js holds it only while it is off screen. Under reduced motion: a still
   row the visitor can scroll. */
.gal-mq, .gal-mq * { touch-action: pan-y; }
.gal-mq { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 3%, #000 97%, transparent); mask-image: linear-gradient(90deg, transparent, #000 3%, #000 97%, transparent); }
.gal-mq__track { display: flex; width: max-content; animation: gal-move calc(var(--n, 6) * 7s) linear infinite; will-change: transform; }
.gal-mq__list { display: flex; gap: 1rem; padding: 0 0.5rem; list-style: none; }
.gal-mq__item { flex: none; width: min(82vw, 22rem); }
@media (min-width: 768px) { .gal-mq__item { width: 30rem; } .gal-mq__list { gap: 1.25rem; padding: 0 0.625rem; } }
.gal-mq__item figure { position: relative; }
.gal-mq__item img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius); }
.gal-mq.is-paused .gal-mq__track { animation-play-state: paused; }
@keyframes gal-move { from { transform: translate3d(-50%, 0, 0); } to { transform: translate3d(0, 0, 0); } }
@media (prefers-reduced-motion: reduce) { .gal-mq, .gal-mq * { touch-action: auto; } .gal-mq__track { animation: none !important; will-change: auto; } .gal-mq { overflow-x: auto; -webkit-mask-image: none; mask-image: none; } .gal-mq__list[aria-hidden="true"] { display: none; } }
.gallery.gallery--large { display: grid; gap: 1rem; grid-template-columns: minmax(0, 1fr); max-width: none; }
.gallery--large figure { position: relative; margin: 0; }
.gallery--large img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius); }
@media (min-width: 640px) { .gallery.gallery--n2 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem; } }
@media (min-width: 900px) { .gallery.gallery--n3 { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.25rem; } .gallery--n3 img { aspect-ratio: 4 / 5; } }
.gallery--n1 img { aspect-ratio: 16 / 9; max-height: 40rem; }
/* Nikolaj, 13 Nov 2026: "swipe" (2 or 3 tall photos, render.mjs gallery). Under 640px one row the visitor swipes instead
   of a stack: each photo about 80% of the screen wide and 4:5, the next one peeking in, snapped, no scrollbar shown,
   running to the screen's edges inside the section (never wider than the page: qa.cjs [gallery swipe]); the keyboard
   scrolls it (tabindex). From 640px exactly as the other galleries of 2 or 3. */
@media (max-width: 639.98px) {
  .gallery.gallery--swipe { display: flex; gap: 0.75rem; margin-inline: -1.5rem; padding-inline: 1.5rem; scroll-padding-inline: 1.5rem; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scrollbar-width: none; touch-action: pan-x pan-y pinch-zoom; }
  .gallery--swipe::-webkit-scrollbar { display: none; }
  .gallery--swipe > figure { flex: 0 0 80vw; scroll-snap-align: start; }
  .gallery--swipe img { aspect-ratio: 4 / 5; }
}

/* B9: the About cards (and any cards block): a line drawing or an icon in the accent, every card of a row the same
   size and colour (validate.mjs: one kind per block). */
.card--icon, .card--art { position: relative; transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 0.4s; }
.card--icon { background: linear-gradient(180deg, rgb(var(--primary-rgb) / 0.07), var(--surface) 55%); }
.card--icon::before { content: ''; position: absolute; top: 0; left: 1.75rem; right: 1.75rem; height: 3px; border-radius: 0 0 3px 3px; background: linear-gradient(90deg, var(--primary), rgb(var(--primary-rgb) / 0)); }
.card__icon { align-self: flex-start; width: 3.75rem; height: 3.75rem; margin: 2rem 1.75rem 0; border-radius: 1.25rem; display: inline-flex; align-items: center; justify-content: center; background: var(--surface); color: var(--accent); box-shadow: inset 0 0 0 1px rgb(var(--primary-rgb) / 0.3), 0 12px 24px -12px rgb(var(--primary-rgb) / 0.45); }
.card__icon svg { width: 1.75rem; height: 1.75rem; }
.card__art { height: 11rem; padding: 1.25rem; background: rgb(var(--primary-rgb) / 0.06); border-bottom: 1px solid var(--line); display: flex; align-items: center; justify-content: center; }
.card__art svg { height: 100%; width: auto; }
@media (hover: hover) { .card--icon:hover, .card--art:hover { transform: translateY(-3px); box-shadow: 0 24px 40px -24px rgb(var(--primary-rgb) / 0.35); } }
.tone-dark .card--icon { background: linear-gradient(180deg, rgb(var(--primary-rgb) / 0.16), rgb(255 255 255 / 0.04) 55%); }
.tone-dark .card__icon { background: rgb(255 255 255 / 0.06); color: var(--deep-accent); }

/* 1.2.0 (Nikolaj, 12 Nov 2026): no credit text on a photo. The photo credits (lib/credits.mjs; since Nikolaj, 13 Nov
   2026, the last section of the terms page) list each licensed photo the site shows, one entry a line. */
.legal .credits { list-style: none; padding-left: 0; display: grid; gap: 0.875rem; }
.credits__item { overflow-wrap: anywhere; }
.credits__what { color: var(--ink); font-weight: 600; }

/* B12 and 1.4.0 (Nikolaj, 13 Nov 2026): the client's logo to the right of the title of every hero form card, on the same
   line, at every width, as the preview engine's quote card (lib/logo-check.mjs passes it in a 112 x 48 box). */
.card-form__head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.card-form__head .card-form__title { min-width: 0; }
/* No width/height here: the img's own width and height (the checked size) hold its box before it loads, so nothing moves
   when it arrives (a lazy footer logo of 0px grew the page by 48px at its end; qa.cjs [bottom bar]). */
.card-form__logo { display: block; flex: none; max-width: 7rem; max-height: 3rem; }
/* 1.4.0: the client's logo above the name in the footer, when it reads on the dark footer (build.mjs ctx.footerLogo). */
/* 1.4.1 (Nikolaj, 13 Nov 2026): a soft light glow behind it, so the mark stands out on the dark footer. */
.footer__mark { position: relative; display: inline-block; margin-bottom: 1rem; isolation: isolate; }
.footer__mark::before { content: ''; position: absolute; left: 50%; top: 50%; width: 6.5rem; height: 6.5rem; transform: translate(-50%, -50%); border-radius: 50%; background: radial-gradient(closest-side, rgb(255 255 255 / 0.2), rgb(255 255 255 / 0.07) 60%, rgb(255 255 255 / 0)); z-index: -1; pointer-events: none; }
.footer__logo { display: block; max-width: 7rem; max-height: 3rem; }

/* The client's own video (render.mjs video, lib/video.mjs): its own shape, at most 80% of the screen's height */
.video--own .video__frame { position: relative; width: min(100%, calc(80vh * var(--video-ar))); width: min(100%, calc(80svh * var(--video-ar))); aspect-ratio: var(--video-ar); margin-inline: auto; border-radius: var(--radius-lg); overflow: hidden; background: var(--deep, #111); }
.video--own .video__media { display: block; width: 100%; height: 100%; object-fit: cover; }
.video__toggle { position: absolute; right: 0.75rem; bottom: 0.75rem; display: grid; place-items: center; width: 3rem; height: 3rem; padding: 0; border: 0; border-radius: 50%; background: rgb(0 0 0 / 0.55); color: #fff; cursor: pointer; }
.video__toggle[hidden] { display: none; }
.video__toggle svg { width: 1.25rem; height: 1.25rem; }
.video--own.is-still .video__toggle { right: auto; bottom: auto; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 4.5rem; height: 4.5rem; background: var(--accent-fill); color: var(--on-accent); }
.video--own.is-still .video__toggle svg { width: 2rem; height: 2rem; margin-left: 0.2rem; }
.video__toggle .video__pause, .video--own.is-playing .video__toggle .video__play-i { display: none; }
.video--own figcaption { text-align: center; }
.video--own.is-playing .video__toggle .video__pause { display: block; }

/* An own video with "text" (render.mjs video): under 960px the heading, the text, then the video. From 960px the heading
   and the text on the left, the video on the right, centred against each other. The video keeps its shape: its column is
   at most 55% of the row and at most 80% of the screen's height tall, so a 9:16 clip stands narrow (qa.cjs [video text]) */
.video-split { display: grid; gap: var(--head-gap); }
.video-split__lead .lead { margin-top: 1.25rem; }
.video-split__lead > :first-child { margin-top: 0; }
@media (min-width: 960px) {
  .video-split { grid-template-columns: minmax(0, 1fr) min(55%, calc(80vh * var(--video-ar))); grid-template-columns: minmax(0, 1fr) min(55%, calc(80svh * var(--video-ar))); align-items: center; column-gap: clamp(2.5rem, 5vw, 5rem); }
}

.sa *{vector-effect:non-scaling-stroke}.sa-m{transform-box:fill-box;transform-origin:center}.sa-drop{animation:sa-drop 3.2s ease-in infinite}@keyframes sa-drop{0%{transform:translateY(-4px);opacity:0}25%{transform:none;opacity:1}80%{transform:translateY(12px);opacity:1}100%{transform:translateY(16px);opacity:0}}.sa-flow{animation:sa-flow 2.4s ease-in-out infinite}@keyframes sa-flow{0%,100%{opacity:1}50%{opacity:.45}}.sa-spin{animation:sa-spin 16s linear infinite}@keyframes sa-spin{to{transform:rotate(360deg)}}.sa-blink{animation:sa-blink 3s ease-in-out infinite}@keyframes sa-blink{0%,100%{opacity:1}50%{opacity:.25}}.sa-glow{animation:sa-glow 4s ease-in-out infinite}@keyframes sa-glow{0%,100%{opacity:1}50%{opacity:.4}}.sa-rise{animation:sa-rise 4s ease-in-out infinite}@keyframes sa-rise{0%{transform:translateY(3px);opacity:.2}40%,70%{transform:none;opacity:1}100%{transform:translateY(-3px);opacity:.2}}.sa-rain{animation:sa-rain 1.8s linear infinite}@keyframes sa-rain{0%{transform:translate(1px,-3px);opacity:0}30%,70%{opacity:1}100%{transform:translate(-1px,3px);opacity:0}}.sa-dash{animation:sa-dash 2.2s ease-in-out infinite}@keyframes sa-dash{0%{transform:translateX(5px);opacity:0}40%,60%{opacity:1}100%{transform:translateX(-5px);opacity:0}}.sa-slide{animation:sa-slide 2.6s ease-in-out infinite alternate}@keyframes sa-slide{from{transform:translateX(-6px)}to{transform:translateX(6px)}}.sa-bob{animation:sa-bob 3.6s ease-in-out infinite alternate}@keyframes sa-bob{to{transform:translateY(-2px)}}.sa-pop{animation:sa-pop 5s ease-out infinite}@keyframes sa-pop{0%,10%{transform:scale(.6);opacity:0}28%,100%{transform:none;opacity:1}}.sa-sweep{animation:sa-sweep 6s ease-in-out infinite}@keyframes sa-sweep{0%{transform:rotate(-90deg)}50%,100%{transform:none}}@media (prefers-reduced-motion:reduce){.sa-m{animation:none!important}}

:root { --site-template: "1.5.0"; }
