/* =========================================================================
   Pastrix — Cleaning Portal theme
   Single stylesheet. All rules live here, nothing inline in the markup.

   TABLE OF CONTENTS
   01. Design tokens
   02. Reset & base
   03. Typography
   04. Layout (container, section, grid)
   05. Buttons
   06. Forms
   07. Badges & tags
   08. Header & navigation
   09. Hero
   09b. Request bar (the price strip under the hero)
   09c. Hero stage (slider and video)
   09d. Hero - centred
   09e. Filter bar
   10. Request wizard
   10b. Checkout
   11. Section head
   12. Service card
   12b. Service rail
   12c. Offer card
   13. Feature blocks & category tiles
   14. Steps
   15. Stats
   16. Company card
   17. Reviews
   18. Trust strip
   19. CTA band
   19b. App band
   20. Blog card
   21. Newsletter
   22. Footer
   23. Page header & breadcrumb
   24. Filter sidebar
   25. Toolbar & pagination
   26. Service detail
   26b. Gallery mosaic
   26c. Lightbox
   27. Accordion
   28. Contact & map
   29. Coverage (areas)
   30. Pricing table
   31. Article body
   32. Back to top
   33. Utilities
   34. Elements page (style guide)
   35. Responsive
   ========================================================================= */


/* =========================================================================
   01. DESIGN TOKENS
   Brand stays deliberately narrow: one teal, one ink, cool neutrals. The
   trade sells "clean", so the palette is water and daylight rather than the
   scrubbed-out grey a supplies catalogue would use.
   ========================================================================= */
:root {

    /* brand + ink */
    --brand:            #16A9A0;
    --brand-fill:       #0E8C86;
    --brand-hover:      #0A6F6B;
    --brand-dark:       #0B7A75;
    --brand-soft:       #E2F4F2;
    --ink:              #0F2A2E;
    --ink-2:            #3A504F;
    --muted:            #6C8482;

    /* surfaces */
    --paper:            #FFFFFF;
    --sand:             #F0F6F5;
    --mist:             #F7FAFA;
    --line:             #E0E8E7;
    --line-soft:        #EDF2F1;

    /* state */
    --gold:             #F0B429;
    --danger:           #C0483C;
    --ok:               #2F9E60;

    /* typography */
    --font-body:        'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --font-display:     'Plus Jakarta Sans', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --font-mono:        ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;

    /* rhythm */
    --container:        1200px;
    --container-sm:     720px;
    --container-narrow: 820px;
    --container-md:     960px;
    --container-lg:     1360px;
    --container-xl:     1600px;
    --gutter:           24px;
    --section-y:        clamp(64px, 8vw, 120px);

    /* shape */
    --r-sm:             8px;
    --r:                12px;
    --r-lg:             20px;
    --r-pill:           999px;

    /* elevation — used sparingly, the theme leans on borders */
    --shadow-sm:        0 1px 2px rgba(15, 42, 46, .05);
    --shadow:           0 8px 24px rgba(15, 42, 46, .07);
    --shadow-lg:        0 24px 60px rgba(15, 42, 46, .12);

    /* motion */
    --t:                .25s cubic-bezier(.4, 0, .2, 1);

    /* layering */
    --z-header:         100;
    --header-h:         79px;   /* header 78 + the 1px rule under it */
    --z-drawer:         200;
    --z-top:            300;
}


/* =========================================================================
   02. RESET & BASE
   ========================================================================= */
*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
}

body {
    margin: 0;
    background: var(--paper);
    color: var(--ink-2);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.7;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* stop the page jumping when a drawer or modal locks scrolling */
body.is-locked {
    overflow: hidden;
}

img,
svg,
video {
    max-width: 100%;
    height: auto;
    display: block;
}

/* any class that sets display outranks the browser's own [hidden] rule,
   so hiding a flex or grid child needs saying out loud */
[hidden] {
    display: none !important;
}

a {
    color: var(--brand-dark);
    text-decoration: none;
    transition: color var(--t);
}

a:hover {
    color: var(--ink);
}

ul,
ol {
    margin: 0;
    padding: 0;
    list-style: none;
}

button {
    font: inherit;
    color: inherit;
    cursor: pointer;
}

table {
    width: 100%;
    border-collapse: collapse;
}

hr {
    border: 0;
    border-top: 1px solid var(--line);
    margin: 32px 0;
}

/* visible keyboard focus everywhere — never remove without a replacement */
:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 3px;
    border-radius: 4px;
}

/* screen-reader only, but focusable (skip link) */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.skip-link {
    position: absolute;
    left: 16px;
    top: -60px;
    z-index: var(--z-top);
    padding: 10px 18px;
    border-radius: var(--r-sm);
    background: var(--brand-fill);
    color: #fff;
    transition: top var(--t);
}

.skip-link:focus {
    top: 16px;
    color: #fff;
}


/* =========================================================================
   03. TYPOGRAPHY
   ========================================================================= */
h1, h2, h3, h4, h5, h6,
.as-h1 {
    margin: 0 0 .5em;
    color: var(--ink);
    font-family: var(--font-display);
    font-weight: 600;
    line-height: 1.14;
    letter-spacing: -.02em;
}

/* the bigger the type, the tighter it is set */
h1,
.as-h1 { font-size: clamp(2.25rem, 5vw, 3.75rem); letter-spacing: -.035em; }
h2 { font-size: clamp(1.75rem, 3.4vw, 2.6rem); letter-spacing: -.03em; }
h3 { font-size: clamp(1.3rem, 2.2vw, 1.75rem); letter-spacing: -.025em; }
h4 { font-size: 1.2rem; }
h5 { font-size: 1.05rem; }
h6 { font-size: .95rem; }

p {
    margin: 0 0 1.1em;
}

p:last-child {
    margin-bottom: 0;
}

/* small uppercase label that sits above a heading */
.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 14px;
    color: var(--brand-dark);
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .16em;
    text-transform: uppercase;
}

.eyebrow::before {
    content: "";
    width: 26px;
    height: 1px;
    background: currentColor;
}

.eyebrow--center::before {
    display: none;
}

.lead {
    font-size: 1.075rem;
    color: var(--muted);
}

.text-muted {
    color: var(--muted);
}

/* a word or two of the headline picked out in the accent colour */
.accent {
    color: var(--brand-dark);
}


/* =========================================================================
   04. LAYOUT
   Wrap any section's content in .container. The modifiers only change the
   max width — the gutter is shared, so nothing ever touches the viewport
   edge. Every width is a token, so the scale is changed in one place.
   ========================================================================= */
.container {
    width: 100%;
    max-width: var(--container);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

.container--sm     { max-width: var(--container-sm); }
.container--narrow { max-width: var(--container-narrow); }
.container--md     { max-width: var(--container-md); }
.container--lg     { max-width: var(--container-lg); }
.container--xl     { max-width: var(--container-xl); }

/* full width, gutters kept */
.container--fluid {
    max-width: none;
}

/* full bleed — no max width and no gutter, for edge-to-edge media */
.container--flush {
    max-width: none;
    padding-inline: 0;
}

/* Put one of these on <body> to reset the page's default width in a single
   place. Every .container follows, and so does anything else reading the
   token, so nothing falls out of line. */
.page--sm { --container: var(--container-sm); }
.page--md { --container: var(--container-md); }
.page--lg { --container: var(--container-lg); }
.page--xl { --container: var(--container-xl); }

.section {
    padding-block: var(--section-y);
}

.section--tight {
    padding-block: clamp(48px, 5vw, 72px);
}

/* for a section that continues the one above it — without this the two
   paddings stack and leave a band twice the intended rhythm */
.section--flush-top {
    padding-top: 0;
}

/* for a page that opens straight onto its content - enough to breathe
   under the page header without a full section gap */
.section--half-top {
    padding-top: calc(var(--section-y) / 2);
}

.section--sand {
    background: var(--sand);
}

.section--mist {
    background: var(--mist);
}

.section--ink {
    background: var(--ink);
    color: rgba(255, 255, 255, .78);
}

.section--ink h1,
.section--ink h2,
.section--ink h3,
.section--ink h4 {
    color: #fff;
}

/* generic auto-fit grid — column count comes from a modifier class */
.grid {
    display: grid;
    gap: 28px;
}

/* col-1 is what the list view switches to, so it earns its place */
.grid.col-1 { grid-template-columns: 1fr; }
.grid.col-2 { grid-template-columns: repeat(2, 1fr); }
.grid.col-3 { grid-template-columns: repeat(3, 1fr); }
.grid.col-4 { grid-template-columns: repeat(4, 1fr); }
.grid.col-5 { grid-template-columns: repeat(5, 1fr); }

/* Two fields that are one answer - a day and an hour - and stay side by side on a
   phone, where every other pair gives up and stacks. Short enough to fit half a
   narrow screen, and read as one question rather than two. */
.grid.col-2.grid--pair {
    grid-template-columns: 1fr 1fr;
}

/* two-column content/media split */
.split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(32px, 5vw, 72px);
    align-items: center;
}

/* A split that leans one way: the form on contact, the words on join.

   A class rather than an inline style on the page. An inline style beats every rule in
   here, media query included, so a page that set its columns that way stayed in two
   columns on a phone and pushed itself off the screen. */
.split--end-wide {
    grid-template-columns: 1fr 1.1fr;
}

.split--start-wide {
    grid-template-columns: 1.1fr 1fr;
}

.split--media-first .split__media {
    order: -1;
}

.split__media img {
    width: 100%;
    border-radius: var(--r-lg);

    /* the box is reserved before the file arrives: without it the column has no
       height until the image loads and everything under it jumps down */
    aspect-ratio: 4 / 3;
    object-fit: cover;
}

/* content column with a rail beside it that follows the scroll */
.layout-sidebar {
    display: grid;
    grid-template-columns: 300px 1fr;
    gap: clamp(28px, 3vw, 44px);
    align-items: start;
}

.layout-sidebar--right {
    grid-template-columns: 1fr 330px;
}

.sidebar {
    position: sticky;
    top: calc(var(--header-h) + 20px);
}


/* =========================================================================
   05. BUTTONS
   ========================================================================= */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 13px 26px;
    border: 1px solid transparent;
    border-radius: var(--r-pill);
    background: var(--brand-fill);
    color: #fff;
    font-size: .93rem;
    font-weight: 600;
    line-height: 1.2;
    text-align: center;
    white-space: nowrap;
    transition: background var(--t), color var(--t), border-color var(--t), transform var(--t);
}

.btn:hover {
    background: var(--brand-hover);
    color: #fff;
    transform: translateY(-1px);
}

.btn svg {
    width: 17px;
    height: 17px;
    flex: none;
}

.btn--outline {
    background: transparent;
    border-color: var(--line);
    color: var(--ink);
}

.btn--outline:hover {
    background: var(--ink);
    border-color: var(--ink);
    color: #fff;
}

/* solid dark button — what btn--outline only showed on hover */
.btn--ink {
    background: var(--ink);
    border-color: var(--ink);
    color: #fff;
}

.btn--ink:hover {
    background: var(--ink-2);
    border-color: var(--ink-2);
    color: #fff;
}

.btn--ghost {
    background: transparent;
    color: var(--ink);
    padding-inline: 8px;
}

.btn--ghost:hover {
    background: transparent;
    color: var(--brand-dark);
}

.btn--light {
    background: #fff;
    color: var(--ink);
}

.btn--light:hover {
    background: var(--brand-soft);
    color: var(--brand-dark);
}

/* the one green button in the theme — whatsapp owns that colour, and a
   teal button pretending to be it is a button nobody recognises */
.btn--whatsapp {
    background: #25D366;
    color: var(--ink);
}

.btn--whatsapp:hover {
    background: #1EB855;
    color: var(--ink);
}

.btn--sm {
    padding: 9px 18px;
    font-size: .85rem;
}

.btn--lg {
    padding: 16px 34px;
    font-size: 1rem;
}

.btn--block {
    width: 100%;
}

.btn[disabled],
.btn.is-busy {
    opacity: .6;
    pointer-events: none;
}

/* text link that carries an arrow */
.link-arrow {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
    font-size: .92rem;
}

.link-arrow svg {
    width: 16px;
    height: 16px;
    transition: transform var(--t);
}

.link-arrow:hover svg {
    transform: translateX(4px);
}

/* small round icon button (share, slider arrows, close) */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    background: #fff;
    color: var(--ink);
    transition: background var(--t), color var(--t), border-color var(--t);
}

.icon-btn:hover {
    background: var(--ink);
    border-color: var(--ink);
    color: #fff;
}

.icon-btn svg {
    width: 18px;
    height: 18px;
}

.icon-btn[disabled] {
    opacity: .4;
    cursor: not-allowed;
}

/* social buttons, shared by the footer and the contact page */
.socials {
    display: flex;
    gap: 10px;
}

.socials a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    color: var(--ink-2);
    transition: background var(--t), border-color var(--t), color var(--t);
}

.socials a:hover {
    background: var(--brand-fill);
    border-color: var(--brand-fill);
    color: #fff;
}

.socials svg {
    width: 17px;
    height: 17px;
}


/* =========================================================================
   06. FORMS
   ========================================================================= */
.field {
    display: block;
    margin-bottom: 18px;
}

.field__label {
    display: block;
    margin-bottom: 7px;
    color: var(--ink);
    font-size: .82rem;
    font-weight: 600;
    letter-spacing: .02em;
}

.input,
.select,
.textarea {
    width: 100%;
    padding: 13px 16px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: #fff;
    color: var(--ink);
    font: inherit;
    font-size: .93rem;
    transition: border-color var(--t), box-shadow var(--t);
}

.input::placeholder,
.textarea::placeholder {
    color: #9FADAB;
}

.input:focus,
.select:focus,
.textarea:focus {
    border-color: var(--brand);
    box-shadow: 0 0 0 3px rgba(22, 169, 160, .14);
    outline: none;
}

.textarea {
    min-height: 150px;
    resize: vertical;
}

/* native select needs its own caret since appearance is stripped */
.select {
    appearance: none;
    padding-right: 42px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%233A504F' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 14px center;
    background-size: 16px;
    cursor: pointer;
}

/* Several components make the select itself transparent so it can sit
   inside a pill or a filled field. Some browsers then paint the native
   popup transparent as well and the options become unreadable, so they
   get their own colours here — once, for every select in the theme. */
option {
    background-color: var(--paper);
    color: var(--ink);
}

.check {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 11px;
    font-size: .9rem;
    cursor: pointer;
}

.check input {
    width: 17px;
    height: 17px;
    margin: 4px 0 0;
    accent-color: var(--brand);
    flex: none;
}

.form-note {
    margin-top: 14px;
    font-size: .82rem;
    color: var(--muted);
}

/* the field only a script fills in. Off the page rather than display:none, which
   is the first thing a bot checks for */
.form-trap {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* --- 27. THE COMPANY'S OWN HEADER --------------------------------------- */
.company-header {
    padding-block: clamp(28px, 4vw, 44px) clamp(28px, 4vw, 40px);
    border-bottom: 1px solid var(--line);
    background: var(--mist);
}

.company-header__row {
    display: flex;
    align-items: center;
    gap: clamp(16px, 2vw, 24px);
    margin-top: 18px;
}

/* no logo on a tenant row, so the initial stands in for one */
.company-header__logo {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 76px;
    height: 76px;
    flex: none;

    /* an edge of its own: the band behind it is tinted, and a white logo on a
       tinted ground has nothing to sit against */
    border: 1px solid var(--line);
    border-radius: var(--r);
    overflow: hidden;
    background: var(--brand-soft);
    color: var(--brand-dark);
    font-family: var(--font-display);
    font-size: 2rem;
    font-weight: 600;
}

/* A mark rather than a letter, where there is one.
   Cropped rather than fitted: what arrives is whatever the office exported - a
   square icon, a wide wordmark, a screenshot with white round it - and fitting
   those leaves the slot mostly empty. Filling it reads as deliberate. */
.company-header__logo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.company-header__body {
    min-width: 0;
}

.company-header__name {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0;
    font-size: clamp(1.6rem, 3vw, 2.2rem);
}

.company-header__name svg {
    width: 20px;
    height: 20px;
    flex: none;
    color: var(--ok);
}

.company-header__lede {
    margin: 4px 0 0;
    color: var(--ink-2);
}

/* the three things worth knowing before reading any further */
.company-header__facts {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 22px;
    margin-top: 12px;
    font-size: .9rem;
    color: var(--ink-2);
}

.company-header__facts li {
    display: flex;
    align-items: center;
    gap: 7px;
}

.company-header__facts svg {
    width: 15px;
    height: 15px;
    flex: none;
    color: var(--brand-fill);
}

.company-header__facts span {
    color: var(--muted);
}

@media (max-width: 640px) {

    .company-header__logo {
        width: 58px;
        height: 58px;
        font-size: 1.5rem;
    }
}


/* the towns a company will go to, and what the drive adds where it is named */
.town-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 10px 24px;
    margin-top: 20px;
}

.town-list li {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: .92rem;
}

.town-list svg {
    width: 15px;
    height: 15px;
    flex: none;
    color: var(--brand-fill);
}

.town-list span {
    color: var(--muted);
    font-size: .82rem;
}

/* where they are, rather than somewhere they will drive to */
.town-list__base {
    padding: 2px 8px;
    border-radius: var(--r-pill);
    background: var(--brand-soft);
    color: var(--brand-dark) !important;
    font-weight: 600;
}

/* a map that is only looked at carries no pin to drag */
.map-pick--static {
    margin-top: 20px;
    cursor: default;
}

/* the map somebody drops a pin on. Tall enough to place a door on a street,
   short enough not to push the rest of the form off a phone */
.map-pick {
    height: 260px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--mist);
    overflow: hidden;
}

@media (max-width: 640px) {

    .map-pick {
        height: 220px;
    }
}

/* an input with its unit printed inside it — m2, hours, rooms */
.input-affix {
    position: relative;
}

.input-affix .input {
    padding-right: 58px;
}

.input-affix__unit {
    position: absolute;
    top: 50%;
    right: 16px;
    transform: translateY(-50%);
    color: var(--muted);
    font-size: .85rem;
    pointer-events: none;
}

/* validation feedback rendered by main.js */
.field.is-invalid .input,
.field.is-invalid .select,
.field.is-invalid .textarea {
    border-color: var(--danger);
}

.field__error {
    display: none;
    margin-top: 6px;
    color: var(--danger);
    font-size: .8rem;
}

.field.is-invalid .field__error,
.check.is-invalid .field__error {
    display: block;
}

/* the box itself, when nothing else on the row has gone red */
.check.is-invalid {
    color: var(--danger);
}

.check.is-invalid input {
    accent-color: var(--danger);
    outline: 2px solid var(--danger);
    outline-offset: 2px;
}

.form-alert {
    display: none;
    margin-bottom: 20px;
    padding: 14px 18px;
    border: 1px solid var(--brand-soft);
    border-radius: var(--r-sm);
    background: var(--brand-soft);
    color: var(--brand-dark);
    font-size: .9rem;
}

/* the same box carries a failure, in the error colour */
.form-alert.is-error {
    border-color: var(--danger);
    background: rgba(192, 72, 60, .08);
    color: var(--danger);
}

.form-alert.is-visible {
    display: block;
}

/* the card a form sits in, on contact and on the request page */
.form-card {
    padding: clamp(26px, 3vw, 36px);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: #fff;
    box-shadow: var(--shadow-sm);
}


/* =========================================================================
   07. BADGES & TAGS
   ========================================================================= */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 13px;
    border-radius: var(--r-pill);
    background: var(--brand-fill);
    color: #fff;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
}

.badge--soft     { background: var(--brand-soft); color: var(--brand-dark); }
.badge--ink      { background: var(--ink); color: #fff; }
.badge--verified { background: var(--ok); color: #fff; }
.badge--popular  { background: var(--gold); color: var(--ink); }

.badge svg {
    width: 13px;
    height: 13px;
}

.tag {
    display: inline-block;
    padding: 5px 13px;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    color: var(--muted);
    font-size: .8rem;
}

a.tag:hover {
    border-color: var(--brand-dark);
    color: var(--brand-dark);
}

/* a row of filter pills, one of them current */
.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 8px 16px;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    background: #fff;
    color: var(--ink-2);
    font-size: .86rem;
    font-weight: 500;
    transition: background var(--t), border-color var(--t), color var(--t);
}

.chip:hover {
    border-color: var(--brand);
    color: var(--brand-dark);
}

.chip.is-active {
    background: var(--ink);
    border-color: var(--ink);
    color: #fff;
}

.chip svg {
    width: 15px;
    height: 15px;
}


/* =========================================================================
   08. HEADER & NAVIGATION
   ========================================================================= */
.topbar {
    background: var(--ink);
    color: rgba(255, 255, 255, .7);
    font-size: .82rem;
}

.topbar__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    min-height: 44px;
}

.topbar__list {
    display: flex;
    align-items: center;
    gap: 24px;
}

/* svg is display:block in the reset, so each item lays its own icon out */
.topbar__list li {
    display: inline-flex;
    align-items: center;
}

.topbar a {
    color: rgba(255, 255, 255, .7);
}

.topbar a:hover {
    color: #fff;
}

.topbar svg {
    width: 15px;
    height: 15px;
    flex: none;
    margin-right: 7px;
}

.site-header {
    position: sticky;
    top: 0;
    z-index: var(--z-header);
    background: rgba(255, 255, 255, .92);
    backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid var(--line-soft);
    transition: box-shadow var(--t);
}

/* main.js adds this once the page scrolls past the header */
.site-header.is-stuck {
    box-shadow: var(--shadow-sm);
}

/* --- header 2: sits over the hero -----------------------------------------
   Transparent with white type at the top of the page. The header keeps
   position: sticky, so the moment main.js adds .is-stuck every override drops
   away and it looks exactly like the default header again.
   -------------------------------------------------------------------------- */
.site-header--overlay:not(.is-stuck) {
    background: transparent;
    backdrop-filter: none;
    border-bottom-color: transparent;
}

/* the hero slides up under both bars. Targeted by hero class rather than
   main's first child, because a builder page opens with a <style> tag. */
.site-header--overlay ~ main .hero,
.site-header--overlay ~ main .hero--media,
.site-header--overlay ~ main .hero-stage {
    margin-top: calc(-1 * var(--header-h));
}

.site-header--overlay:not(.is-stuck) .brand__name,
.site-header--overlay:not(.is-stuck) .nav__link,
.site-header--overlay:not(.is-stuck) .nav__link.is-active,
.site-header--overlay:not(.is-stuck) .header-phone strong,
.site-header--overlay:not(.is-stuck) .nav-toggle {
    color: #fff;
}

/* the toggle is a solid white box by default — fine on a white header, a
   white slab over the hero, with its now-white icon lost inside it */
.site-header--overlay:not(.is-stuck) .nav-toggle {
    border-color: rgba(255, 255, 255, .45);
    background: transparent;
}

.site-header--overlay:not(.is-stuck) .nav-toggle:hover {
    background: rgba(255, 255, 255, .16);
}

.site-header--overlay:not(.is-stuck) .header-phone span,
.site-header--overlay:not(.is-stuck) .nav__link:hover {
    color: rgba(255, 255, 255, .78);
}

/* the outline button needs a light edge to read on artwork */
.site-header--overlay:not(.is-stuck) .btn--outline {
    border-color: rgba(255, 255, 255, .55);
    color: #fff;
}

.site-header--overlay:not(.is-stuck) .btn--outline:hover {
    background: #fff;
    border-color: #fff;
    color: var(--ink);
}

/* a photo can be light anywhere, so lay a soft scrim behind the type */
.site-header--overlay:not(.is-stuck)::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(to bottom, rgba(0, 0, 0, .42), rgba(0, 0, 0, .12));
    pointer-events: none;
}

/* once it sticks the scrim is not wanted - the solid background is back */
.site-header--overlay.is-stuck::before {
    content: none;
}

.site-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    min-height: 78px;
}

/* --- brand ------------------------------------------------------------ */
.brand {
    display: inline-flex;
    align-items: center;
    gap: 11px;
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.4rem;
    letter-spacing: -.02em;
}

.brand:hover {
    color: var(--ink);
}

.brand__mark {
    width: 38px;
    height: 38px;
    flex: none;
}

.brand__name strong {
    font-weight: 600;
}

/* --- primary nav ------------------------------------------------------ */
.nav {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-inline: auto;

    /* the row is what gives way when the labels will not: the language item made
       it one item longer than the space allowed for */
    min-width: 0;
}

.nav__item {
    position: relative;
}

.nav__link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 10px 15px;
    border-radius: var(--r-sm);
    color: var(--ink-2);
    font-size: .93rem;
    font-weight: 500;

    /* a label is one thing, however many words it is made of: broken over two
       lines it reads as two menu items and drags the caret away from its own */
    white-space: nowrap;
}

.nav__link:hover,
.nav__item.is-open > .nav__link {
    color: var(--brand-dark);
}

/* current page marker */
.nav__link.is-active {
    color: var(--ink);
    font-weight: 600;
}

.nav__link.is-active::after {
    content: "";
    position: absolute;
    left: 15px;
    right: 15px;
    bottom: 2px;
    height: 2px;
    border-radius: 2px;
    background: var(--brand);
}

.nav__caret {
    width: 14px;
    height: 14px;

    /* Never shrunk. The labels stopped wrapping, so a nav with more items than
       room puts all of that pressure on its flex children - and the caret, being
       the only one without text holding it open, was squeezed to nothing. */
    flex: none;

    transition: transform var(--t);
}

.nav__item.is-open .nav__caret {
    transform: rotate(180deg);
}

/* a narrow desktop window trims the padding rather than the words */
@media (max-width: 1240px) {

    .nav__link {
        padding-inline: 10px;
    }

    .nav {
        gap: 0;
    }
}

/* --- dropdown --------------------------------------------------------- */
.dropdown {
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    min-width: 220px;
    padding: 10px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
    box-shadow: var(--shadow);
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    transition: opacity var(--t), transform var(--t), visibility var(--t);
}

.nav__item.is-open .dropdown {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.dropdown a {
    display: block;
    padding: 9px 14px;
    border-radius: var(--r-sm);
    color: var(--ink-2);
    font-size: .9rem;
}

.dropdown a:hover {
    background: var(--mist);
    color: var(--brand-dark);
}

/* --- header actions --------------------------------------------------- */
.header-actions {
    display: flex;
    align-items: center;
    gap: 12px;
}

.header-phone {
    display: flex;
    align-items: center;
    gap: 10px;
}

.header-phone svg {
    width: 20px;
    height: 20px;
    color: var(--brand);
}

.header-phone span {
    display: block;
    color: var(--muted);
    font-size: .72rem;
    line-height: 1.3;
}

.header-phone strong {
    display: block;
    color: var(--ink);
    font-size: .93rem;
}

/* --- mobile toggle + drawer ------------------------------------------- */
.nav-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: #fff;
}

.nav-toggle svg {
    width: 20px;
    height: 20px;
}

.nav-backdrop {
    position: fixed;
    inset: 0;
    z-index: var(--z-drawer);
    background: rgba(15, 42, 46, .5);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--t), visibility var(--t);
}

.nav-backdrop.is-open {
    opacity: 1;
    visibility: visible;
}

.mobile-nav {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: calc(var(--z-drawer) + 1);
    width: min(360px, 86vw);
    padding: 24px;
    background: #fff;
    overflow-y: auto;
    transform: translateX(100%);
    transition: transform var(--t);
}

.mobile-nav.is-open {
    transform: translateX(0);
}

.mobile-nav__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-bottom: 20px;
    margin-bottom: 12px;
    border-bottom: 1px solid var(--line);
}

.mobile-nav a {
    display: block;
    padding: 12px 4px;
    border-bottom: 1px solid var(--line-soft);
    color: var(--ink);
    font-size: 1rem;
    font-weight: 500;
}

.mobile-nav a:hover {
    color: var(--brand-dark);
}

.mobile-nav .dropdown-mobile a {
    padding-left: 18px;
    color: var(--muted);
    font-size: .92rem;
    font-weight: 400;
}

/* .mobile-nav a is more specific than .btn, so it flattens the button into a
   plain block link — icon adrift on the left, ink text, menu-row padding.
   Put the button back to being a button. */
.mobile-nav .btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-top: 22px;
    padding: 13px 26px;
    border-bottom: 0;
    color: #fff;
    font-size: .93rem;
    font-weight: 600;
}

.mobile-nav .btn:hover {
    color: #fff;
}


/* the language, last in the row: a flag and a code rather than a word, because
   it is a control and not a destination */
.nav__item--lang .nav__link {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

.nav__item--lang img,
.nav__item--lang .dropdown img {
    width: 18px;
    height: 18px;
    border-radius: 3px;
    object-fit: cover;
}

.nav__item--lang .dropdown a {
    display: flex;
    align-items: center;
    gap: 9px;
}

/* On a phone the drawer has the room for them side by side.

   No rule of its own above them: every row in the drawer already draws a line under
   itself, so one here made two lines with a gap between them. */
.mobile-nav__langs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 20px;
}

/* a chip is a pill, and the drawer's row border would flatten its underside */
.mobile-nav__langs .chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    border-bottom-color: var(--line);
}

.mobile-nav__langs .chip.is-active {
    border-color: var(--brand);
    background: var(--brand-soft);
    color: var(--brand-dark);
}

.mobile-nav__langs img {
    width: 18px;
    height: 18px;
    border-radius: 3px;
    object-fit: cover;
}


/* =========================================================================
   09. HERO
   ========================================================================= */
.hero {
    position: relative;
    padding-block: clamp(56px, 7vw, 96px) clamp(40px, 5vw, 64px);
    background: linear-gradient(180deg, var(--mist) 0%, var(--paper) 100%);
    overflow: hidden;
}

.hero__grid {
    display: grid;
    grid-template-columns: 1.05fr 1fr;
    gap: clamp(32px, 5vw, 64px);
    align-items: center;
}

.hero__title {
    margin-bottom: 20px;
}

.hero__text {
    max-width: 46ch;
    margin-bottom: 32px;
    color: var(--muted);
    font-size: 1.075rem;
}

.hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    align-items: center;
}

/* small proof row under the hero copy */
.hero__proof {
    display: flex;
    flex-wrap: wrap;
    gap: 36px;
    margin-top: 44px;
    padding-top: 30px;
    border-top: 1px solid var(--line);
}

.hero__proof strong {
    display: block;
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.85rem;
    line-height: 1.1;
}

.hero__proof span {
    color: var(--muted);
    font-size: .85rem;
}

.hero__media {
    position: relative;
}

.hero__media img {
    width: 100%;
    border-radius: var(--r-lg);
}

/* floating card overlapping the hero image */
.hero__card {
    position: absolute;
    left: -28px;
    bottom: 32px;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 20px;
    border-radius: var(--r);
    background: #fff;
    box-shadow: var(--shadow-lg);
}

.hero__card svg {
    width: 22px;
    height: 22px;
    color: var(--brand);
}

.hero__card strong {
    display: block;
    color: var(--ink);
    font-size: .95rem;
}

.hero__card span {
    color: var(--muted);
    font-size: .8rem;
}

/* compact hero used on inner pages that still want the request bar */
.hero--compact {
    padding-block: clamp(48px, 5vw, 72px);
}

/* --- hero over a photograph ------------------------------------------- */
.hero--media {
    display: flex;
    align-items: center;
    min-height: min(640px, 86vh);
    padding-block: clamp(96px, 12vw, 160px) clamp(64px, 8vw, 110px);
    background: var(--ink);
}

.hero--media .hero__bg {
    position: absolute;
    inset: 0;
    z-index: 0;
}

.hero--media .hero__bg img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 0;
}

/* the scrim is what makes white type readable on any photograph */
.hero--media .hero__bg::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg, rgba(15, 42, 46, .88) 0%, rgba(15, 42, 46, .62) 46%, rgba(15, 42, 46, .28) 100%);
}

.hero--media .container {
    position: relative;
    z-index: 1;
}

/* Every hero that lays type over media inverts the same way, so the rules are
   written once for all of them. Adding a sixth variant means adding its class
   to these lists and nothing else. */
.hero--media .hero__title,
.hero--media .hero__card strong,
.hero-stage .hero__title {
    color: #fff;
}

.hero--media .hero__text,
.hero-stage .hero__text {
    color: rgba(255, 255, 255, .82);
}

.hero--media .eyebrow,
.hero-stage .eyebrow {
    color: #7FD9D0;
}

.hero--media .hero__proof,
.hero-stage .hero__proof {
    border-top-color: rgba(255, 255, 255, .18);
}

.hero--media .hero__proof strong,
.hero-stage .hero__proof strong {
    color: #fff;
}

.hero--media .hero__proof span,
.hero-stage .hero__proof span {
    color: rgba(255, 255, 255, .7);
}


/* =========================================================================
   09b. REQUEST BAR
   The one thing every visitor came to do: say where, say what, get a price.
   Lives inside the hero on the homepage and under the page header elsewhere.
   ========================================================================= */
.request-bar {
    padding: 10px;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: #fff;
    box-shadow: var(--shadow-lg);

    /* The bar is a form, not copy. The centred heroes set text-align on the
       whole block, and a label would follow while the field under it would not
       - inputs and selects ignore an inherited alignment - leaving the two
       halves of the same cell out of line. Stated here so every hero gets the
       same bar, whatever it does with its own type. */
    text-align: left;
}

.request-bar__form {
    display: grid;
    grid-template-columns: 1fr 1fr .8fr auto;
    align-items: center;
}

/* a hairline between the cells rather than four boxed inputs */
.request-bar__cell + .request-bar__cell {
    box-shadow: inset 1px 0 0 var(--line-soft);
}

.request-bar__cell {
    padding: 10px 18px;
}

.request-bar__cell label,
.request-bar__cell .request-bar__caption {
    display: block;
    margin-bottom: 2px;
    color: var(--muted);
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
}

/* the fields lose their own chrome — the bar is the box */
.request-bar__cell .input,
.request-bar__cell .select {
    padding: 0;
    border: 0;
    border-radius: 0;
    background-color: transparent;
    font-size: .95rem;
    font-weight: 500;
}

.request-bar__cell .select {
    padding-right: 24px;
    background-position: right center;
    background-size: 15px;
}

.request-bar__cell .input:focus,
.request-bar__cell .select:focus {
    box-shadow: none;
}

/* the field that opens a panel, dressed as the selects beside it: the bar is the
   box, so this carries no chrome of its own either */
.request-bar__picker {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    color: var(--ink);
    font: inherit;
    font-size: .95rem;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
}

.request-bar__caret {
    width: 15px;
    height: 15px;
    flex: none;
    color: var(--muted);
    transition: transform var(--t);
}

.filter-drop-wrap.is-open .request-bar__caret {
    transform: rotate(180deg);
}

/* The panel is taller than the room under the bar, and every hero clips its own
   overflow so a slide cannot bleed out of it - which cuts the panel off at the
   fold. The clip is lifted only while a panel is open: everything else in there
   is inset to the hero anyway, so there is nothing else to escape. */
.hero:has(.filter-drop-wrap.is-open),
.hero-stage:has(.filter-drop-wrap.is-open) {
    overflow: visible;
}

.request-bar__submit {
    padding: 4px;
}

.request-bar__submit .btn {
    height: 100%;
    padding-inline: 30px;
}

/* the shortcuts under the bar — one tap into a common search */
.request-bar__pills {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 20px;
}

.request-bar__pills span {
    align-self: center;
    margin-right: 4px;
    color: var(--muted);
    font-size: .84rem;
}

/* on a hero that lays type over media the pills sit on the scrim */
.hero--media .request-bar__pills span,
.hero-stage .request-bar__pills span {
    color: rgba(255, 255, 255, .75);
}

.hero--media .request-bar__pills .chip,
.hero-stage .request-bar__pills .chip {
    border-color: rgba(255, 255, 255, .3);
    background: rgba(255, 255, 255, .1);
    color: #fff;
}

.hero--media .request-bar__pills .chip:hover,
.hero-stage .request-bar__pills .chip:hover {
    background: #fff;
    border-color: #fff;
    color: var(--ink);
}


/* =========================================================================
   09c. HERO STAGE — slider and video
   Both put media behind the words and the request bar, so they share the
   stage: swapping one hero for the other cannot change the height of the
   page. The stage is a flex box rather than an absolute overlay, so a long
   headline on a phone makes it taller instead of spilling out of it.
   ========================================================================= */
.hero-stage {
    position: relative;
    display: flex;
    align-items: center;

    /* 88vh rather than a full 100: the sliver of the next section showing
       under the fold is what tells a reader there is more page. The floor
       keeps the request bar comfortable on a short laptop window, the
       ceiling stops the hero ballooning on a tall monitor. */
    min-height: clamp(620px, 88vh, 900px);

    /* the bottom is deeper than the top: the dots and arrows live down there */
    padding-block: clamp(88px, 11vw, 150px) clamp(104px, 12vw, 165px);
    background: var(--ink);
    overflow: hidden;
}

.hero-stage__media {
    position: absolute;
    inset: 0;
    z-index: 0;
}

.hero-stage__overlay {
    position: relative;
    z-index: 2;
    width: 100%;
}

/* the copy is centred over the media, and held to a measure — full-width
   type over a photograph is unreadable however dark the wash is */
.hero-stage__inner {
    max-width: 820px;
    margin-inline: auto;
    text-align: center;
}

.hero-stage__inner .hero__text {
    max-width: 56ch;
    margin-inline: auto;
}

.hero-stage__inner .request-bar__pills {
    justify-content: center;
}

/* --- slides ----------------------------------------------------------- */
/* they stack on top of each other and cross-fade; only the active one is
   painted, so nothing behind it can bleed through mid-transition */
.hero-slide {
    position: absolute;
    inset: 0;
    overflow: hidden;
    opacity: 0;
    visibility: hidden;
    transition: opacity .9s ease, visibility .9s ease;
}

.hero-slide.is-active {
    opacity: 1;
    visibility: visible;
}

.hero-slide__media {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* slow push-in while a slide is on screen */
.hero-slide.is-active .hero-slide__media {
    animation: hero-zoom 10s ease-out forwards;
}

@keyframes hero-zoom {

    from { transform: scale(1); }
    to   { transform: scale(1.07); }
}

/* even wash — the copy sits centred, so no side is favoured. The number is
   the top stop, 0-100; the other two hold their relative weight so the
   gradient keeps its shape whatever level the widget asks for. */
.hero-slide::after,
.hero-video__frame::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
        rgba(15, 42, 46, calc(var(--scrim, 62) * 1%)) 0%,
        rgba(15, 42, 46, calc(var(--scrim, 62) * .7%)) 44%,
        rgba(15, 42, 46, calc(var(--scrim, 62) * 1.1%)) 100%);
}

/* --- video ------------------------------------------------------------ */
.hero-video__frame {
    position: absolute;
    inset: 0;
    overflow: hidden;
}

/* shown until the frame paints, and on its own when no link is set */
.hero-video__poster {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* held back until the player reports it is playing at the right offset, so
   the poster covers the buffering frame and the seek. A hero with no offset
   gets the class immediately, and so does one where the api never loads. */
[data-hero-video] .hero-video__player {
    opacity: 0;
    transition: opacity .4s ease;
}

[data-hero-video].is-playing .hero-video__player {
    opacity: 1;
}

/* youtube only ever gives back 16:9, so the frame is oversized on whichever
   axis is short and centred — the overflow is clipped by the frame */
.hero-video__player {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 100vw;
    height: 56.25vw;
    min-width: 177.78vh;
    min-height: 100%;
    border: 0;
    transform: translate(-50%, -50%);
    pointer-events: none;
}

/* --- arrows + dots ---------------------------------------------------- */
.hero-slider__controls {
    position: absolute;
    z-index: 6;
    left: 50%;
    bottom: 34px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    width: min(100%, var(--container));
    padding-inline: var(--gutter);
    transform: translateX(-50%);
}

.hero-slider__dots {
    display: flex;
    gap: 8px;
}

.hero-slider__dot {
    width: 28px;
    height: 4px;
    padding: 0;
    border: 0;
    border-radius: var(--r-pill);
    background: rgba(255, 255, 255, .35);
    transition: width var(--t), background var(--t);
}

.hero-slider__dot:hover {
    background: rgba(255, 255, 255, .6);
}

.hero-slider__dot.is-active {
    width: 46px;
    background: #fff;
}

.hero-slider__arrows {
    display: flex;
    gap: 10px;
}

.hero-slider__arrow {
    border-color: rgba(255, 255, 255, .32);
    background: rgba(255, 255, 255, .14);
    color: #fff;
}

.hero-slider__arrow:hover {
    background: #fff;
    border-color: #fff;
    color: var(--ink);
}


/* =========================================================================
   09d. HERO — CENTRED
   No photograph at all. What a portal uses before it has any imagery worth
   showing, and what reads best when the request bar is the whole point.
   ========================================================================= */
.hero--centred {
    text-align: center;
    background: linear-gradient(180deg, var(--brand-soft) 0%, var(--mist) 46%, var(--paper) 100%);
}

.hero--centred .hero__inner {
    max-width: 860px;
    margin-inline: auto;
}

.hero--centred .hero__text {
    max-width: 56ch;
    margin-inline: auto;
}

.hero--centred .hero__actions,
.hero--centred .hero__proof,
.hero--centred .request-bar__pills {
    justify-content: center;
}

/* the rule above a centred proof row has to be centred too, or it reads as
   a left-aligned block that happens to sit under centred type */
.hero--centred .hero__proof {
    max-width: 640px;
    margin-inline: auto;
}


/* =========================================================================
   09e. FILTER BAR
   A row of pill controls, each under its own caption, for a page whose whole
   job is narrowing a list. A control too rich for a pill - a range, a long
   list of towns - opens a panel underneath rather than pushing the page down.

   Named for what it does rather than where it first appeared, so the search
   page and anything else that filters can both wear it.
   ========================================================================= */
.filter-bar {
    border-bottom: 1px solid var(--line);
    background: var(--paper);
}

.filter-bar__inner {
    --pill-h: 46px;

    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 10px;
    padding-block: 18px;
}

/* each control sits under its own caption */
.filter-field {
    display: flex;
    flex-direction: column;
}

/* the one field that takes whatever room is left - the town, usually */
.filter-field--grow {
    flex: 1 1 240px;
    min-width: 200px;
}

.filter-field__label {
    margin-bottom: 6px;
    color: var(--muted);
    font-size: .76rem;
    letter-spacing: .02em;
}

.filter-pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: var(--pill-h, auto);
    padding: 9px 16px;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    background: var(--paper);
    color: var(--ink);
    font-size: .88rem;
    font-weight: 500;
    white-space: nowrap;
    transition: background var(--t), border-color var(--t), color var(--t);
}

.filter-pill:hover {
    border-color: var(--muted);
}

.filter-pill:focus-within {
    border-color: var(--brand);
    box-shadow: 0 0 0 3px rgba(22, 169, 160, .14);
}

.filter-pill > svg {
    width: 16px;
    height: 16px;
    flex: none;
    color: var(--muted);
}

/* a filter that is actually narrowing the results says so */
.filter-pill--set {
    border-color: var(--brand);
    background: var(--brand-soft);
    color: var(--brand-dark);
}

.filter-pill--set > svg,
.filter-pill--set .filter-pill__caret {
    color: var(--brand-dark);
}

.filter-pill--button {
    justify-content: space-between;
    cursor: pointer;
    text-align: left;
}

.filter-pill__caret {
    width: 14px;
    height: 14px;
    flex: none;
    margin-left: auto;
    color: var(--muted);
    transition: transform var(--t);
}

/* a control simple enough to live in the pill itself, with no panel */
.filter-pill__input {
    width: 100%;
    min-width: 0;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
}

.filter-pill__input:focus {
    outline: none;
}

.filter-pill__unit {
    color: var(--muted);
    font-size: .85rem;
}

/* the way back to an empty field, shown only once there is something to undo */
.filter-pill__clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    flex: none;
    border: 0;
    border-radius: 50%;

    /* the pill it sits in is tinted once a date is set, and a muted mark on a tint
       reads as decoration - a white disc with black on it reads as a button */
    background: var(--paper);
    color: var(--ink);
    cursor: pointer;
    transition: background var(--t), color var(--t);
}

.filter-pill__clear:hover {
    background: var(--ink);
    color: var(--paper);
}

.filter-pill__clear svg {
    width: 11px;
    height: 11px;
}

/* the search button lines up with the pills rather than with their captions */
.filter-bar__submit {
    min-height: var(--pill-h);
    padding-inline: 26px;
}


/* --- the phone's version of all that --------------------------------------
   The bar is six fields deep on a narrow screen, which is the whole first
   view before a single result. So it collapses to a line saying what is being
   searched for, and the fields open as a sheet over the results. */
.filter-summary,
.filter-sheet__head,
.filter-sheet__clear {
    display: none;
}

@media (max-width: 900px) {

    .filter-bar.has-sheet .filter-summary {
        display: flex;
        align-items: center;
        gap: 10px;
        width: 100%;
        padding: 14px 20px;
        border: 0;
        background: none;
        color: var(--ink);
        font: inherit;
        font-size: .92rem;
        font-weight: 500;
        text-align: left;
        cursor: pointer;
    }

    .filter-summary > svg {
        width: 17px;
        height: 17px;
        flex: none;
        color: var(--brand-fill);
    }

    /* the search can be long; the way in must never be pushed off the edge */
    .filter-summary__text {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }

    .filter-summary__more {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        flex: none;
        padding: 5px 12px;
        border: 1px solid var(--line);
        border-radius: var(--r-pill);
        font-size: .8rem;
        font-weight: 600;
    }

    .filter-summary__more svg {
        width: 15px;
        height: 15px;
        flex: none;
        color: var(--muted);
    }

    .filter-summary__count {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 18px;
        height: 18px;
        padding-inline: 5px;
        border-radius: 999px;
        background: var(--brand-fill);
        color: #fff;
        font-size: .72rem;
    }

    /* the form is the sheet */
    .filter-bar.has-sheet .filter-bar__inner {
        position: fixed;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: calc(var(--z-drawer) + 1);
        display: block;
        max-height: 86vh;
        padding: 0 20px calc(20px + env(safe-area-inset-bottom));
        border-radius: var(--r-lg) var(--r-lg) 0 0;
        background: var(--paper);
        box-shadow: 0 -10px 40px rgba(15, 42, 46, .18);
        overflow-y: auto;
        overscroll-behavior: contain;
        transform: translateY(100%);
        visibility: hidden;
        transition: transform var(--t), visibility var(--t);
    }

    .filter-bar.has-sheet.is-open .filter-bar__inner {
        transform: none;
        visibility: visible;
    }

    .filter-bar.has-sheet .filter-sheet__head {
        position: sticky;
        top: 0;
        z-index: 1;
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-bottom: 6px;
        padding-block: 18px 14px;
        border-bottom: 1px solid var(--line-soft);
        background: var(--paper);
        font-size: 1.05rem;
    }

    .filter-sheet__close {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 32px;
        height: 32px;
        padding: 0;
        border: 0;
        border-radius: 50%;
        background: var(--mist);
        color: var(--ink);
        cursor: pointer;
    }

    .filter-sheet__close svg {
        width: 15px;
        height: 15px;
    }

    /* every field is its own row in a sheet */
    .filter-field {
        width: 100%;
        margin-top: 16px;
    }

    /* a panel inside a scrolling sheet cannot float over it */
    .filter-drop {
        position: static;
        width: 100%;
        margin-top: 10px;
        padding: 14px;
        box-shadow: none;
        opacity: 1;
        visibility: visible;
        transform: none;
        display: none;
    }

    .filter-drop-wrap.is-open .filter-drop {
        display: block;
    }

    .filter-bar.has-sheet .filter-sheet__clear,
    .filter-bar__submit {
        display: inline-flex;
        width: 100%;
        margin-top: 14px;
        justify-content: center;
    }

    .filter-sheet__clear {
        order: 1;
    }
}

/* --- the panel under a pill -------------------------------------------- */
.filter-drop-wrap {
    position: relative;
}

.filter-drop-wrap.is-open .filter-pill__caret {
    transform: rotate(180deg);
}

.filter-drop {
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    z-index: 90;
    width: 300px;
    padding: 20px;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--paper);
    box-shadow: var(--shadow-lg);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-6px);
    transition: opacity var(--t), visibility var(--t), transform var(--t);
}

.filter-drop-wrap.is-open .filter-drop {
    opacity: 1;
    visibility: visible;
    transform: none;
}

/* for a pill near the right edge of the bar */
.filter-drop--right {
    left: auto;
    right: 0;
}

.filter-drop__title {
    display: block;
    margin-bottom: 12px;
    color: var(--muted);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
}

.filter-drop__row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}

/* type-to-filter above a long choice list */
.filter-drop__filter {
    position: relative;
    margin-bottom: 12px;
}

.filter-drop__filter > svg {
    position: absolute;
    top: 50%;
    left: 12px;
    width: 15px;
    height: 15px;
    color: var(--muted);
    pointer-events: none;
    transform: translateY(-50%);
}

.filter-drop__filter input {
    width: 100%;
    padding: 9px 12px 9px 34px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: .88rem;
}

.filter-drop__filter input:focus {
    border-color: var(--brand);
    box-shadow: 0 0 0 3px rgba(22, 169, 160, .14);
    outline: none;
}

.filter-drop__none {
    padding: 8px 2px;
    color: var(--muted);
    font-size: .88rem;
}

/* .check is display:flex, so it needs telling that hidden means hidden */
.check[hidden] {
    display: none;
}

/* a choice list inside a panel - scrolls once it outgrows the box */
.filter-drop__list {
    max-height: 230px;
    padding-right: 6px;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--line) transparent;
}

.filter-drop__list::-webkit-scrollbar {
    width: 6px;
}

.filter-drop__list::-webkit-scrollbar-thumb {
    border-radius: var(--r-pill);
    background: var(--line);
}

/* The rows read as a list rather than as a form. The radio is still what the
   browser submits and what a screen reader announces; it is simply not what
   anybody needs to look at, because the row itself says which one is chosen. */
.filter-drop__list .check {
    margin-bottom: 2px;
    padding: 8px 10px;
    border-radius: var(--r-sm);
    transition: background var(--t), color var(--t);
}

.filter-drop__list .check:last-child {
    margin-bottom: 0;
}

/* off the page rather than display:none, which would take it out of the tab order */
.filter-drop__list .check input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.filter-drop__list .check:hover {
    background: var(--mist);
}

.filter-drop__list .check:focus-within {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
}

/* where you are in a long list */
.filter-drop__list .check:has(input:checked) {
    background: var(--brand-soft);
    color: var(--brand-dark);
    font-weight: 600;
}

.filter-drop__foot {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--line-soft);
}

/* amount field with the currency sitting inside it */
.money {
    position: relative;
}

.money__sign {
    position: absolute;
    top: 50%;
    left: 13px;
    color: var(--muted);
    font-size: .85rem;
    pointer-events: none;
    transform: translateY(-50%);
}

.money__input {
    width: 100%;
    padding: 11px 12px 11px 42px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: .9rem;
}

.money__input::placeholder {
    color: var(--muted);
}

.money__input:focus {
    border-color: var(--brand);
    box-shadow: 0 0 0 3px rgba(22, 169, 160, .14);
    outline: none;
}


/* =========================================================================
   10. REQUEST WIZARD
   The quote form, broken into steps so nobody meets fourteen fields at once.
   Every step is in the DOM from the start; main.js only shows one at a time,
   so a visitor with no javascript still sees — and can send — the whole form.
   ========================================================================= */
.wizard {
    display: grid;
    grid-template-columns: 1fr 380px;
    gap: clamp(28px, 4vw, 56px);
    align-items: start;
}

.wizard__steps {
    display: flex;
    gap: 8px;
    margin-bottom: 32px;
}

.wizard__step {
    flex: 1;
    padding-top: 14px;
    border-top: 3px solid var(--line);
    color: var(--muted);
    font-size: .82rem;
    font-weight: 600;
    letter-spacing: .04em;
    transition: border-color var(--t), color var(--t);
}

.wizard__step.is-current,
.wizard__step.is-done {
    border-top-color: var(--brand);
    color: var(--ink);
}

.wizard__step small {
    display: block;
    color: var(--muted);
    font-size: .74rem;
    font-weight: 500;
    letter-spacing: .1em;
    text-transform: uppercase;
}

/* one panel of the form; hidden panels are still submitted */
.wizard__panel[hidden] {
    display: none !important;
}

.wizard__panel h2 {
    margin-bottom: 6px;
    font-size: clamp(1.4rem, 2.4vw, 1.9rem);
}

.wizard__panel > p {
    margin-bottom: 26px;
    color: var(--muted);
}

.wizard__nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    margin-top: 30px;
    padding-top: 24px;
    border-top: 1px solid var(--line);
}

/* one button left in the row, so it sits at the end rather than the middle */
.wizard__nav--end {
    justify-content: flex-end;
}

/* --- pickable tiles: services, property type, hours ------------------- */
/* auto-fill rather than auto-fit: with one tile in the row, auto-fit throws away the
   empty tracks and the tile stretches across the page. The tracks stay, so a single
   place looks like a place rather than a banner. */
.picks {
    display: grid;
    gap: 12px;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
}

.pick {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 16px 18px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
    cursor: pointer;
    transition: border-color var(--t), background var(--t), box-shadow var(--t);
}

.pick:hover {
    border-color: var(--brand);
}

/* how many of a counted extra, inside the card that ticks it */
.pick__count {
    width: 62px;
    margin-left: auto;
    padding: 6px 8px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: #fff;
    color: var(--ink);
    font: inherit;
    font-size: .88rem;
    text-align: center;
}

.pick__count:focus {
    border-color: var(--brand);
    outline: none;
}

/* the same number, set by tapping. The box keeps its place in the middle, because it is
   still what carries the value and what somebody ordering eight of something types into */
.stepper {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
}

.stepper .pick__count {
    width: 46px;
    margin-left: 0;
    padding-inline: 4px;
}

.stepper__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    flex: none;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 50%;
    background: #fff;
    color: var(--ink);
    transition: background var(--t), border-color var(--t), color var(--t);
}

.stepper__btn:hover {
    background: var(--ink);
    border-color: var(--ink);
    color: #fff;
}

.stepper__btn svg {
    width: 12px;
    height: 12px;
}


/* the same card where there is nothing to choose: it is telling somebody what a
   company sells, so it does not invite a click it cannot answer */
.pick--static {
    cursor: default;
}

.pick--static:hover {
    border-color: var(--line);
}

/* The tick itself is only there to carry the value and the keyboard focus.

   Named by type rather than "every input in here": a card that counts something has a
   second input, and hiding that one left an extra nobody could ask for twice. */
.pick input[type="checkbox"],
.pick input[type="radio"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.pick input:checked ~ .pick__body {
    color: var(--ink);
}

.pick:has(input:checked) {
    border-color: var(--brand);
    background: var(--brand-soft);
    box-shadow: 0 0 0 1px var(--brand);
}

.pick input:focus-visible ~ .pick__icon {
    outline: 2px solid var(--brand);
    outline-offset: 3px;
}

.pick__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex: none;
    border-radius: var(--r-sm);
    background: var(--mist);
    color: var(--brand-dark);
}

.pick:has(input:checked) .pick__icon {
    background: #fff;
}

.pick__icon svg {
    width: 20px;
    height: 20px;
}

.pick__body strong {
    display: block;
    color: var(--ink);
    font-size: .95rem;
    line-height: 1.35;
}

.pick__body span {
    color: var(--muted);
    font-size: .82rem;
}

/* --- the running summary beside the form ------------------------------ */
.summary {
    position: sticky;
    top: calc(var(--header-h) + 20px);
    padding: 26px;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--mist);
}

.summary h3 {
    margin-bottom: 4px;
    font-size: 1.15rem;
}

.summary > p {
    margin-bottom: 20px;
    color: var(--muted);
    font-size: .88rem;
}

.summary__list li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding-block: 11px;
    border-top: 1px solid var(--line);
    font-size: .9rem;
}

.summary__list li:first-child {
    border-top: 0;
}

/* The lines of what is being booked: a name, how much of it, and what it comes to.

   How much sits beside the name rather than under it - a card of five lines does not need
   ten, and "x 2" is two characters. */
.summary__lines em {
    margin-left: 6px;
    color: var(--muted);
    font-size: .82rem;
    font-style: normal;
    white-space: nowrap;
}

.summary__lines strong {
    white-space: nowrap;
}

.summary__list dt,
.summary__list span:first-child {
    color: var(--muted);
}

.summary__list strong {
    color: var(--ink);
    font-weight: 600;
    text-align: right;
}

/* the estimate, when the services picked are all priced per unit */
.summary__total {
    margin-top: 18px;
    padding-top: 18px;
    border-top: 2px solid var(--ink);
}

.summary__total span {
    display: block;
    color: var(--muted);
    font-size: .8rem;
    letter-spacing: .08em;
    text-transform: uppercase;
}

.summary__total strong {
    display: block;
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.9rem;
    line-height: 1.2;
}

.summary__note {
    margin-top: 12px;
    color: var(--muted);
    font-size: .8rem;
}

/* the one note that is not a footnote: it is about the figure above it, not about
   what happens afterwards */
.summary__note--caution {
    padding: 9px 12px;
    border-radius: var(--r-sm);
    background: rgba(240, 180, 41, .14);
    color: var(--ink);
    font-size: .84rem;
}

/* what the visitor sees once the form has gone */
.thanks {
    max-width: 560px;
    margin-inline: auto;
    text-align: center;
}

.thanks__mark {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 78px;
    height: 78px;
    margin: 0 auto 26px;
    border-radius: var(--r-pill);
    background: var(--brand-soft);
    color: var(--brand-dark);
}

.thanks__mark svg {
    width: 34px;
    height: 34px;
}


/* =========================================================================
   10b. CHECKOUT
   The second half of booking, on a page of its own. The choices that make the
   price were made on the offer page and are said back here rather than asked
   again - so this page is one form, in the order somebody fills it in.
   ========================================================================= */
/* what has been chosen, with the fields that set it behind the button */
.chosen {
    padding: 16px 20px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--mist);
}

.chosen__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.chosen__body strong {
    display: block;
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.05rem;
    line-height: 1.3;
}

.chosen__body span {
    color: var(--muted);
    font-size: .88rem;
}

/* the button stays a pill however long the line beside it runs */
.chosen .btn {
    flex: none;
}

/* the fields, once somebody asks for them */
.chosen__fields {
    margin-top: 18px;
    padding-top: 18px;
    border-top: 1px solid var(--line);
}

/* one question at a time down the form: when, who, what else, how it is paid */
.checkout-step {
    margin-top: 30px;
    padding-top: 28px;
    border-top: 1px solid var(--line);
}

.checkout-step__title {
    margin-bottom: 18px;
    font-size: 1.2rem;
}

/* a field holding two or three digits, which does not need the width of the form */
.field--short {
    max-width: 240px;
}

@media (max-width: 640px) {

    /* the line and the button stop sharing a row, rather than the line losing its
       tail to make room for one word */
    .chosen__head {
        flex-direction: column;
        align-items: flex-start;
        gap: 12px;
    }
}


/* =========================================================================
   11. SECTION HEAD
   ========================================================================= */
.section-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 32px;
    margin-bottom: clamp(32px, 4vw, 52px);
}

.section-head__title {
    max-width: 34ch;
    margin-bottom: 0;
}

.section-head__text {
    max-width: 52ch;
    margin-top: 14px;
    color: var(--muted);
}

.section-head--center {
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.section-head--center .section-head__title,
.section-head--center .section-head__text {
    max-width: 56ch;
}


/* =========================================================================
   12. SERVICE CARD
   ========================================================================= */
/* position:relative so the title link can stretch over the whole card */
.service-card {
    position: relative;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
    overflow: hidden;
    transition: border-color var(--t), box-shadow var(--t), transform var(--t);
}

.service-card:hover {
    border-color: transparent;
    box-shadow: var(--shadow);
    transform: translateY(-3px);
}

.service-card__media {
    position: relative;
    aspect-ratio: 3 / 2;
    background: var(--mist);
    overflow: hidden;
}

.service-card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .5s ease;
}

.service-card:hover .service-card__media img {
    transform: scale(1.04);
}

.service-card__badges {
    position: absolute;
    top: 14px;
    left: 14px;
    display: flex;
    gap: 8px;
}

.service-card__body {
    display: flex;
    flex-direction: column;
    flex: 1;
    padding: 22px;
}

/* the icon variant carries no photograph, so the icon opens the card */
.service-card__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    margin-bottom: 18px;
    border-radius: var(--r);
    background: var(--brand-soft);
    color: var(--brand-dark);
}

.service-card__icon svg {
    width: 24px;
    height: 24px;
}

.service-card__title {
    margin-bottom: 8px;
    font-size: 1.15rem;
}

.service-card__title a {
    color: var(--ink);
}

.service-card__title a:hover {
    color: var(--brand-dark);
}

/* The title link covers the whole card, so the image, price and blurb are
   all clickable without a second anchor and a second tab stop. Anything that
   must stay clickable on top of it carries z-index 2. */
.service-card__title a::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
}

.service-card p {
    margin-bottom: 18px;
    color: var(--muted);
    font-size: .92rem;
}

.service-card__foot {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
    margin-top: auto;
    padding-top: 16px;
    border-top: 1px solid var(--line-soft);
}

.service-card__price {
    display: flex;
    align-items: baseline;
    gap: 5px;
    color: var(--brand-dark);
    font-family: var(--font-display);
    font-size: 1.3rem;
    font-weight: 600;
}

.service-card__price small {
    color: var(--muted);
    font-family: var(--font-body);
    font-size: .8rem;
    font-weight: 400;
}

/* "from 4.5 lek" needs the qualifier to read smaller than the number */
.service-card__price em {
    color: var(--muted);
    font-family: var(--font-body);
    font-size: .78rem;
    font-style: normal;
    font-weight: 500;
    letter-spacing: .06em;
    text-transform: uppercase;
}

.service-card__duration {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--muted);
    font-size: .84rem;
}

.service-card__duration svg {
    width: 15px;
    height: 15px;
}

/* horizontal variant used by the list view on the services page */
.service-card--row {
    flex-direction: row;
}

.service-card--row .service-card__media {
    flex: 0 0 38%;
    aspect-ratio: auto;
}

.service-card--row .service-card__body {
    padding: 26px;
}


/* =========================================================================
   12b. SERVICE RAIL
   A horizontal scroller for a set too long to grid and too short to page.
   ========================================================================= */
.rail {
    position: relative;
}

.rail__head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 24px;
    margin-bottom: 28px;
}

.rail__nav {
    display: flex;
    gap: 10px;
}

.rail__track {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: calc((100% - 56px) / 3);
    gap: 28px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;

    /* the cards lift on hover, and a clipped overflow cuts the lift off */
    padding-block: 4px;
}

.rail__track::-webkit-scrollbar {
    display: none;
}

/* A rail that runs to the edge of the screen.

   Inside a container the last card stops where the text does, and a row that ends
   tidily reads as a row that has ended - nobody drags it. Here the track is as wide
   as the window and carries the gutter itself, so the first card still lines up with
   the heading while the ones after it are cut by the edge of the screen.

   The padding is what the container would have left: half of whatever the window has
   over the measure, and never less than the page gutter. Written against 100% of the
   track rather than the viewport, because 100vw counts the scrollbar and would push
   the whole page sideways by its width.

   Cards are sized off the content box, which the padding has just made exactly the
   container's width - so four across still means four across the text above them. */
.rail--bleed .rail__track {
    padding-inline: max(var(--gutter), calc((100% - var(--container)) / 2));

    /* and a snapped card lands against the heading, not against the window */
    scroll-padding-inline: max(var(--gutter), calc((100% - var(--container)) / 2));
}

/* --- one company's answer, sized for a rail ---------------------------- */
.offer-mini {
    display: flex;
    flex-direction: column;
    height: 100%;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
    overflow: hidden;
    transition: border-color var(--t), box-shadow var(--t), transform var(--t);
}

.offer-mini:hover {
    border-color: transparent;
    box-shadow: var(--shadow);
    transform: translateY(-2px);
}

/* their own photograph where there is one, the initial where there is not */
.offer-mini__media {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 16 / 9;
    background: var(--brand-soft);
    color: var(--brand-dark);
    font-family: var(--font-display);
    font-size: 2rem;
    font-weight: 600;
    overflow: hidden;
}

.offer-mini__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .5s ease;
}

.offer-mini:hover .offer-mini__media img {
    transform: scale(1.04);
}

.offer-mini__body {
    flex: 1;
    padding: 18px 20px 0;
}

.offer-mini__name {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-bottom: 3px;
    font-size: 1.05rem;
}

/* the company's own mark, where the initial would otherwise be */
.offer-mini__logo {
    width: 22px;
    height: 22px;
    flex: none;
    border-radius: 5px;
    object-fit: cover;
}

.offer-mini__name svg {
    width: 15px;
    height: 15px;
    flex: none;
    color: var(--ok);
}

/* what the visit covers, in the company's own words */
.offer-mini__list {
    margin-top: 14px;
    font-size: .85rem;
    color: var(--ink-2);
}

.offer-mini__list li {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-bottom: 6px;
}

.offer-mini__list svg {
    width: 13px;
    height: 13px;
    margin-top: 4px;
    flex: none;
    color: var(--brand-fill);
}

.offer-mini__more {
    color: var(--muted);
    font-size: .8rem;
}

.offer-mini__terms {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-top: 12px;
    color: var(--muted);
    font-size: .82rem;
}

.offer-mini__terms svg {
    width: 14px;
    height: 14px;
    flex: none;
}

/* the money and the way in, held to the bottom so a row of cards lines up */
.offer-mini__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 16px;
    padding: 14px 20px 18px;
    border-top: 1px solid var(--line-soft);
}

.offer-mini__price span {
    display: block;
    color: var(--muted);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
}

.offer-mini__price strong {
    font-family: var(--font-display);
    font-size: 1.2rem;
    white-space: nowrap;
}

/* four of these read better than the three the rail was built for, and a widget
   that offers a column count sets its own through --rail-cols */
@media (min-width: 1101px) {

    .rail__track {
        grid-auto-columns: calc((100% - (var(--rail-cols, 4) - 1) * 28px) / var(--rail-cols, 4));
    }
}

@media (max-width: 1100px) {

    /* fewer cards in view rather than narrower ones */
    .rail__track {
        grid-auto-columns: calc((100% - 28px) / 2);
    }
}

@media (max-width: 640px) {

    .rail__track {
        grid-auto-columns: 78%;
    }
}

.rail__track > * {
    scroll-snap-align: start;
}


/* =========================================================================
   12c. OFFER CARD
   One company's answer to a job: who they are, what they promise, what it
   costs. Laid out in three columns so the eye can run straight down the
   prices - a marketplace where the figures do not line up is a marketplace
   nobody can compare.
   ========================================================================= */
.offers {
    display: grid;
    gap: 16px;
}

/* while the next set is on its way. Dimmed rather than emptied: a list that
   vanishes and comes back moves the page under whoever is reading it */
[data-results],
[data-offer],
[data-checkout-summary] {
    transition: opacity var(--t);
}

[data-results].is-loading,
[data-offer].is-loading,
[data-checkout-summary].is-loading {
    opacity: .45;
    pointer-events: none;
}

.offer {
    display: grid;
    grid-template-columns: 1.05fr 1.35fr 210px;
    gap: clamp(20px, 3vw, 36px);

    /* the columns are different heights now, so they hang from the top rather
       than floating in the middle of the tallest one */
    align-items: start;
    padding: 24px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
    transition: border-color var(--t), box-shadow var(--t);
}

.offer:hover {
    border-color: transparent;
    box-shadow: var(--shadow);
}

/* what the card is an offer for. Only on a mixed list - where the page is one
   service the header above it has already said so */
.offer__service {
    display: inline-block;
    margin-bottom: 12px;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--brand-soft);
    color: var(--brand-dark);
    font-size: .78rem;
    font-weight: 600;
}

.offer__head {
    display: flex;
    align-items: center;
    gap: 16px;
}

.offer__name {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 3px;
    font-size: 1.15rem;
}

.offer__name svg {
    width: 17px;
    height: 17px;
    flex: none;
    color: var(--ok);
}

/* --- who they are ------------------------------------------------------ */
/* the three scores a cleaning customer actually argues about. Shown only when
   reviews carried them, so a company with plain star ratings loses the row
   rather than showing three dashes */
.offer__scores {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--line-soft);
}

.offer__scores li {
    display: flex;
    align-items: baseline;
    gap: 6px;
    font-size: .8rem;
}

.offer__scores span {
    color: var(--muted);
}

.offer__scores strong {
    color: var(--ink);
    font-weight: 600;
}

/* one line of what somebody said, which is what turns a 4.4 into a person */
.offer__quote {
    margin: 14px 0 0;
    padding-left: 12px;
    border-left: 2px solid var(--brand-soft);
    color: var(--ink-2);
    font-size: .87rem;
    font-style: italic;
    line-height: 1.55;
}

.offer__quote cite {
    display: block;
    margin-top: 4px;
    color: var(--muted);
    font-size: .78rem;
    font-style: normal;
}

.offer__quote cite::before {
    content: "— ";
}

/* --- what the visit covers -------------------------------------------- */
.offer__included {
    margin-bottom: 16px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--line-soft);
}

.offer__included-title {
    display: block;
    margin-bottom: 8px;
    color: var(--muted);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
}

.offer__included li {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-bottom: 5px;
    color: var(--ink-2);
    font-size: .87rem;
    line-height: 1.45;
}

.offer__included svg {
    width: 15px;
    height: 15px;
    flex: none;
    margin-top: 3px;
    color: var(--brand);
}

/* the tail of a longer list, indented to sit under the ticked lines */
.offer__included-more {
    padding-left: 23px;
    color: var(--muted);
    font-size: .82rem;
}


/* --- the promises, the same three for everybody ----------------------- */
.offer__terms {
    display: grid;
    gap: 8px 20px;
}

.offer__terms li {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--ink-2);
    font-size: .87rem;
}

.offer__terms svg {
    width: 16px;
    height: 16px;
    flex: none;
    color: var(--brand);
}

.offer__note {
    margin-top: 12px;
    color: var(--muted);
    font-size: .82rem;
}

/* --- the money -------------------------------------------------------- */
/* the border is what makes the column read as a column all the way down */
.offer__price {
    align-self: stretch;
    padding-left: clamp(20px, 3vw, 32px);
    border-left: 1px solid var(--line-soft);
    text-align: right;
}

.offer__price-label {
    display: block;
    color: var(--muted);
    font-size: .76rem;
    letter-spacing: .08em;
    text-transform: uppercase;
}

.offer__price strong {
    display: block;
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.85rem;
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -.02em;
}

/* the top of a range is the softer half of the number */
.offer__price-to {
    color: var(--muted);
    font-size: 1.35rem;
}

.offer__price-unit {
    display: block;
    color: var(--muted);
    font-size: .85rem;
}

/* the working under the total - the rate, the quantity and the journey. Small
   on purpose: it is there to be checked, not to be read first */
.offer__price-calc {
    margin: 6px 0 0;
    color: var(--muted);
    font-size: .78rem;
    line-height: 1.45;
}


/* a pick that carries a price sits its money on the right, like the card does */
.pick--wide {
    align-items: center;
}

.pick__price {
    margin-left: auto;
    padding-left: 16px;
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
    white-space: nowrap;
}

/* the picks on the booking form are a list, not a grid of tiles */
.picks--list {
    grid-template-columns: 1fr;
}

/* Two to a row, whatever is in them.

   A card that counts something is wider than a plain tick, and left to fit itself the row
   came out ragged. Halves keep it a grid: the name, the price and the box to type in all
   have room, and every card is the same size whether it carries a box or not. */
.picks--half {
    grid-template-columns: repeat(2, 1fr);
}

/* on a phone two of them are two narrow columns of wrapped words */
@media (max-width: 560px) {

    .picks--half {
        grid-template-columns: 1fr;
    }
}

/* a section that runs straight into the one under it */
.section--flush-bottom {
    padding-bottom: 0;
}


/* =========================================================================
   13. FEATURE BLOCKS & CATEGORY TILES
   ========================================================================= */
.feature {
    padding: 30px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
    transition: border-color var(--t), box-shadow var(--t);
}

.feature:hover {
    border-color: transparent;
    box-shadow: var(--shadow);
}

.feature__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 54px;
    height: 54px;
    margin-bottom: 20px;
    border-radius: var(--r);
    background: var(--brand-soft);
    color: var(--brand-dark);
}

.feature__icon svg {
    width: 24px;
    height: 24px;
}

.feature__title {
    margin-bottom: 8px;
    font-size: 1.15rem;
}

.feature p {
    color: var(--muted);
    font-size: .93rem;
}

/* the bordered variant reads as a list rather than a set of cards */
.feature--plain {
    padding: 0;
    border: 0;
    background: transparent;
}

.feature--plain:hover {
    box-shadow: none;
}

/* category tile (homes, offices, after-builders, …) */
.category {
    position: relative;
    display: flex;
    align-items: flex-end;
    min-height: 240px;
    padding: 24px;
    border-radius: var(--r);
    background: var(--mist);
    overflow: hidden;
}

.category img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .5s ease;
}

.category:hover img {
    transform: scale(1.05);
}

.category__body {
    position: relative;
    width: 100%;
    padding: 16px 18px;
    border-radius: var(--r-sm);
    background: rgba(255, 255, 255, .93);
}

.category__body h3 {
    margin-bottom: 2px;
    font-size: 1.1rem;
}

.category__body span {
    color: var(--muted);
    font-size: .84rem;
}


/* =========================================================================
   14. STEPS
   ========================================================================= */
.steps {
    counter-reset: step;
}

.step {
    position: relative;
    padding-top: 28px;
    border-top: 2px solid var(--line);
}

.step::before {
    counter-increment: step;
    content: "0" counter(step);
    display: block;
    margin-bottom: 14px;
    color: var(--brand-dark);
    font-family: var(--font-display);
    font-size: 1.5rem;
}

/* the first step keeps the accent rule */
.step:first-child {
    border-top-color: var(--brand);
}

.step h3 {
    margin-bottom: 8px;
    font-size: 1.2rem;
}

.step p {
    color: var(--muted);
    font-size: .93rem;
}


/* =========================================================================
   15. STATS
   ========================================================================= */
.stat {
    text-align: center;
}

.stat__value {
    display: block;
    color: #fff;
    font-family: var(--font-display);
    font-size: clamp(2.1rem, 4vw, 3rem);
    line-height: 1.1;
}

.section:not(.section--ink) .stat__value {
    color: var(--ink);
}

.stat__label {
    display: block;
    margin-top: 6px;
    font-size: .88rem;
    letter-spacing: .04em;
}


/* =========================================================================
   16. COMPANY CARD
   A cleaning firm as the portal shows it: who they are, where they go, what
   the people they cleaned for said.
   ========================================================================= */
.company-card {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: 26px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
    transition: border-color var(--t), box-shadow var(--t), transform var(--t);
}

.company-card:hover {
    border-color: transparent;
    box-shadow: var(--shadow);
    transform: translateY(-3px);
}

.company-card__head {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 18px;
}

.company-card__logo {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 62px;
    height: 62px;
    flex: none;
    border: 1px solid var(--line-soft);
    border-radius: var(--r);
    background: var(--mist);
    overflow: hidden;
    color: var(--brand-dark);
    font-family: var(--font-display);
    font-size: 1.3rem;
    font-weight: 600;
}

.company-card__logo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.company-card__name {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 3px;
    font-size: 1.15rem;
}

.company-card__name a {
    color: var(--ink);
}

.company-card__name a:hover {
    color: var(--brand-dark);
}

.company-card__name a::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
}

/* the verified tick sits beside the name, so it must not stretch the row */
.company-card__name svg {
    width: 17px;
    height: 17px;
    flex: none;
    color: var(--ok);
}

.company-card__rating {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--muted);
    font-size: .85rem;
}

.company-card__rating strong {
    color: var(--ink);
}

.company-card p {
    margin-bottom: 18px;
    color: var(--muted);
    font-size: .92rem;
}

.company-card__areas {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    margin-bottom: 20px;
}

/* what the company is, in the three lines somebody chooses on */
.company-card__facts {
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--line-soft);
    font-size: .87rem;
    color: var(--ink-2);
}

.company-card__facts li {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin-bottom: 9px;
}

.company-card__facts li:last-child {
    margin-bottom: 0;
}

.company-card__facts svg {
    width: 15px;
    height: 15px;
    margin-top: 2px;
    flex: none;
    color: var(--brand-fill);
}

/* the cheapest thing they publish, which is what the card leads the foot with */
.company-card__from {
    font-size: .85rem;
    color: var(--muted);
}

.company-card__from strong {
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.05rem;
}

.company-card__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    margin-top: auto;
    padding-top: 18px;
    border-top: 1px solid var(--line-soft);
}

/* the button has to beat the stretched name link to stay clickable */
.company-card__foot .btn {
    position: relative;
    z-index: 2;
}


/* =========================================================================
   17. REVIEWS
   ========================================================================= */
.quote {
    padding: 32px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
}

.quote__mark {
    width: 34px;
    height: 34px;
    margin-bottom: 18px;
    color: var(--brand-soft);
}

.quote p {
    margin-bottom: 24px;
    color: var(--ink-2);
    font-size: 1rem;
}

.quote__author {
    display: flex;
    align-items: center;
    gap: 13px;
    padding-top: 20px;
    border-top: 1px solid var(--line-soft);
}

.quote__author img {
    width: 46px;
    height: 46px;
    border-radius: var(--r-pill);
    object-fit: cover;
}

/* no photograph on a review left through the portal, so an initial stands in */
.quote__initial {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    height: 46px;
    flex: none;
    border-radius: var(--r-pill);
    background: var(--brand-soft);
    color: var(--brand-dark);
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
}

.quote__author strong {
    display: block;
    color: var(--ink);
    font-size: .95rem;
}

.quote__author span {
    color: var(--muted);
    font-size: .82rem;
}

.rating {
    display: flex;
    gap: 3px;
    margin-bottom: 14px;
    color: var(--gold);
}

.rating svg {
    width: 16px;
    height: 16px;
}

/* a star that was not earned still holds its place in the row */
.rating svg.is-empty {
    color: var(--line);
}

/* the score block on a service or company page */
.score {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 22px 26px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--mist);
}

.score__value {
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 2.6rem;
    font-weight: 600;
    line-height: 1;
}

.score__meta span {
    display: block;
    color: var(--muted);
    font-size: .85rem;
}


/* --- the rating in full ------------------------------------------------ */
/* The spread beside the category scores. An average on its own hides whether
   it is made of fours or of fives and twos, which for a cleaning company is
   the whole question. */
.score-summary {
    display: grid;
    grid-template-columns: 1fr 1.1fr;
    gap: clamp(24px, 4vw, 48px);
    padding: 26px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--mist);
}

.score-spread__title,
.score-cats__title {
    display: block;
    margin-bottom: 14px;
    color: var(--muted);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
}

.score-spread__row {
    display: grid;
    grid-template-columns: 12px 1fr 24px;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
}

.score-spread__star,
.score-spread__count {
    color: var(--muted);
    font-size: .82rem;
}

.score-spread__count {
    text-align: right;
}

.score-spread__bar {
    height: 6px;
    border-radius: var(--r-pill);
    background: var(--line);
    overflow: hidden;
}

.score-spread__fill {
    height: 100%;
    border-radius: var(--r-pill);
    background: var(--gold);
}

/* --- what they were rated on ------------------------------------------- */
.score-cats {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 4px;
}

.score-cat {
    display: grid;
    grid-template-columns: 34px 1fr auto;
    align-items: center;
    gap: 12px;
    padding-block: 9px;
}

.score-cat + .score-cat {
    border-top: 1px solid var(--line);
}

.score-cat__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: var(--r-sm);
    background: var(--paper);
    color: var(--brand-dark);
}

.score-cat__icon svg {
    width: 17px;
    height: 17px;
}

.score-cat__name {
    color: var(--ink-2);
    font-size: .92rem;
}

.score-cat__score {
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
}


/* =========================================================================
   18. TRUST STRIP
   The reassurances that belong near a price: insured, vetted, guaranteed.
   ========================================================================= */
.trust {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 28px;
}

.trust__item {
    display: flex;
    align-items: center;
    gap: 12px;
    color: var(--ink-2);
    font-size: .92rem;
    font-weight: 500;
}

.trust__item svg {
    width: 22px;
    height: 22px;
    flex: none;
    color: var(--brand);
}

/* the logo row, when a client has partners to show */
.partners {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 32px;
}

.partners span {
    color: var(--muted);
    font-family: var(--font-display);
    font-size: 1.35rem;
    letter-spacing: .02em;
    opacity: .65;
    transition: opacity var(--t);
}

.partners span:hover {
    opacity: 1;
}


/* =========================================================================
   19. CTA BAND
   ========================================================================= */
.cta {
    display: grid;
    grid-template-columns: 1.4fr auto;
    gap: 40px;
    align-items: center;
    padding: clamp(36px, 5vw, 64px);
    border-radius: var(--r-lg);
    background: var(--ink);
    color: rgba(255, 255, 255, .75);
}

.cta h2 {
    max-width: 22ch;
    margin-bottom: 12px;
    color: #fff;
}

.cta p {
    max-width: 48ch;
}

.cta__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

/* the teal variant, for the band that asks a company to join the portal */
.cta--brand {
    background: linear-gradient(120deg, var(--brand-fill) 0%, var(--brand-hover) 100%);
    color: rgba(255, 255, 255, .85);
}


.app-card__soon {
    color: var(--muted);
    font-size: .9rem;
}

/* on the dark band the muted ink would disappear */
.section--ink .app-card__soon {
    color: rgba(255, 255, 255, .6);
}

/* the handset is portrait, so it is held to a width the split can carry */
/* --- store badges ----------------------------------------------------- */
/* =========================================================================
   AN APPLICATION, ON A PAGE OF THEM
   One card per app: the mark, who it is for, what it does, where to get it.
   ========================================================================= */
.app-card {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 26px;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: #fff;
}

.app-card__head {
    display: flex;
    align-items: center;
    gap: 16px;
}

/* the icon as the stores show it: square, rounded, never stretched */
.app-card__icon {
    width: 64px;
    height: 64px;
    flex: none;
    border-radius: 16px;
    border: 1px solid var(--line);
    object-fit: cover;
}

.app-card__who {
    display: block;
    margin-bottom: 2px;
    color: var(--brand-dark);
    font-size: .76rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
}

.app-card h3 {
    font-size: 1.2rem;
}

.app-card p {
    flex: 1 1 auto;
    color: var(--ink-2);
    font-size: .95rem;
}

/* the badges share the width of the card rather than stacking */
.app-card .store {
    flex: 1 1 140px;
}

.stores {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

.store {
    display: inline-flex;
    align-items: center;
    gap: 11px;
    padding: 10px 20px;
    border: 1px solid var(--ink);
    border-radius: var(--r);
    background: var(--ink);
    color: #fff;
    transition: background var(--t), border-color var(--t), transform var(--t);
}

.store:hover {
    color: #fff;
    transform: translateY(-1px);
}

/* on the ink band the badge would vanish, so it inverts to an outline */
.section--ink .store {
    border-color: rgba(255, 255, 255, .3);
    background: transparent;
}

.section--ink .store:hover {
    border-color: #fff;
    background: rgba(255, 255, 255, .08);
}.store svg {
    width: 26px;
    height: 26px;
    flex: none;
}

.store small {
    display: block;
    font-size: .68rem;
    line-height: 1.3;
    letter-spacing: .04em;
    opacity: .75;
}

.store strong {
    display: block;
    font-family: var(--font-display);
    font-size: 1.02rem;
    font-weight: 600;
    line-height: 1.2;
}

/* --- the app band's own, where the badges are the point ------------------
   Everywhere else a store badge is a footnote under some copy. Here it is
   what the section is asking for, so it is sized to be pressed: a filled
   mark rather than the outline the ink band gives the others, because an
   outline on a dark ground reads as a border round nothing. */
/* --- the app band -------------------------------------------------------
   A line, a second line, and the two marks somebody presses. The badges are
   the section rather than a footnote under it, so they take the full width
   and are sized to be pressed from across a room. */
.app-band__inner {
    max-width: 880px;
    margin-inline: auto;
    text-align: center;
}

.app-band .stores {
    display: grid;

    /* one store configured fills the row, two share it - a lone badge half the
       width of the band looks like the other one failed to load */
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 20px;
    margin-top: clamp(28px, 4vw, 44px);
}

.app-band .store {
    justify-content: center;
    gap: 18px;
    padding: 22px 30px;
    border-radius: var(--r-lg);
}

.app-band .store svg {
    width: 44px;
    height: 44px;
}

.app-band .store small {
    font-size: .82rem;
}

.app-band .store strong {
    font-size: 1.45rem;
}

/* on the band it is centred under the headline; in a card it sits where it falls */
.app-band .app-card__soon {
    margin-top: 18px;
    text-align: center;
}

/* the light badge is the one the stores themselves publish for dark grounds */
.section--ink.app-band .store {
    border-color: #fff;
    background: #fff;
    color: var(--ink);
}

.section--ink.app-band .store:hover {
    background: #fff;
    color: var(--ink);
    box-shadow: 0 10px 28px rgba(0, 0, 0, .28);
}@media (max-width: 640px) {

    /* one under the other: side by side they stop being pressable long before
       they stop fitting */
    .app-band .stores {
        grid-template-columns: 1fr;
    }

    .app-band .store {
        padding: 18px 24px;
    }
}


/* =========================================================================
   20. BLOG CARD
   ========================================================================= */
.post-card {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.post-card__media {
    aspect-ratio: 3 / 2;
    margin-bottom: 20px;
    border-radius: var(--r);
    background: var(--mist);
    overflow: hidden;
}

.post-card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .5s ease;
}

.post-card:hover .post-card__media img {
    transform: scale(1.04);
}

.post-card__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    margin-bottom: 10px;
    color: var(--muted);
    font-size: .8rem;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.post-card__title {
    margin-bottom: 10px;
    font-size: 1.25rem;
}

.post-card__title a {
    color: var(--ink);
}

.post-card__title a:hover {
    color: var(--brand-dark);
}

.post-card p {
    margin-bottom: 16px;
    color: var(--muted);
    font-size: .93rem;
}

.post-card .link-arrow {
    margin-top: auto;
}


/* =========================================================================
   21. NEWSLETTER
   ========================================================================= */
.newsletter {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 40px;
    align-items: center;
}

.newsletter__form {
    display: flex;
    gap: 10px;
}

.newsletter__form .input {
    flex: 1;
    padding-inline: 22px;
    border-radius: var(--r-pill);
}


/* =========================================================================
   22. FOOTER
   ========================================================================= */
.site-footer {
    padding-top: clamp(56px, 6vw, 88px);
    background: var(--ink);
    color: rgba(255, 255, 255, .65);
    font-size: .92rem;
}

.site-footer .brand,
.site-footer .brand:hover {
    color: #fff;
}

/* headings sit on the dark band, so they invert */
.site-footer h1,
.site-footer h2,
.site-footer h3,
.site-footer h4 {
    color: #fff;
}

.site-footer hr {
    border-top-color: rgba(255, 255, 255, .1);
}

.footer-grid {
    display: grid;
    grid-template-columns: 1.6fr 1fr 1fr 1.2fr;
    gap: 40px;
    padding-bottom: 56px;
}

.footer-about p {
    max-width: 34ch;
    margin: 20px 0 24px;
}

.footer-col__title {
    margin-bottom: 20px;
    color: #fff;
    font-family: var(--font-body);
    font-size: .8rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
}

.footer-links li + li {
    margin-top: 11px;
}

/* the phone and email in the contact list are links too, so they follow the
   same rule as the nav lists rather than the page-wide link colour */
.footer-links a,
.footer-contact a {
    color: rgba(255, 255, 255, .65);
}

.footer-links a:hover,
.footer-contact a:hover {
    color: #fff;
}

.footer-contact li {
    display: flex;
    gap: 12px;
    margin-bottom: 15px;
}

.footer-contact svg {
    width: 18px;
    height: 18px;
    flex: none;
    margin-top: 3px;
    color: var(--brand);
}

.site-footer .socials a {
    border-color: rgba(255, 255, 255, .16);
    color: rgba(255, 255, 255, .7);
}

.site-footer .socials a:hover {
    background: var(--brand-fill);
    border-color: var(--brand-fill);
    color: #fff;
}

.footer-bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding-block: 24px;
    border-top: 1px solid rgba(255, 255, 255, .1);
    font-size: .85rem;
}

.footer-bottom ul {
    display: flex;
    gap: 22px;
}

.footer-bottom a {
    color: rgba(255, 255, 255, .65);
}

.footer-bottom a:hover {
    color: #fff;
}


/* =========================================================================
   23. PAGE HEADER & BREADCRUMB
   ========================================================================= */
.page-header {
    padding-block: clamp(44px, 5vw, 72px);
    border-bottom: 1px solid var(--line-soft);
    background: var(--mist);
}

.page-header__title {
    margin-bottom: 10px;
}

.page-header p {
    max-width: 100ch;
    color: var(--muted);
}

.breadcrumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 9px;
    margin-bottom: 16px;
    color: var(--muted);
    font-size: .85rem;
}

.breadcrumb li:not(:last-child)::after {
    content: "/";
    margin-left: 9px;
    color: var(--line);
}

.breadcrumb a {
    color: var(--muted);
}

.breadcrumb a:hover {
    color: var(--ink);
}


/* =========================================================================
   24. FILTER SIDEBAR
   ========================================================================= */
.filters {
    padding: 24px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
}

.filters__group + .filters__group {
    margin-top: 24px;
    padding-top: 24px;
    border-top: 1px solid var(--line-soft);
}

.filters__title {
    margin-bottom: 14px;
    color: var(--ink);
    font-family: var(--font-body);
    font-size: .8rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
}

.filters__actions {
    display: flex;
    gap: 10px;
    margin-top: 26px;
}

/* opens the same panel as a drawer once the columns stack */
.filters-trigger {
    display: none;
}


/* =========================================================================
   25. TOOLBAR & PAGINATION
   ========================================================================= */
.toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 28px;
}

.toolbar__count {
    color: var(--muted);
    font-size: .9rem;
}

.toolbar__count strong {
    color: var(--ink);
}

.toolbar__right {
    display: flex;
    align-items: center;
    gap: 12px;
}

.toolbar .select {
    width: auto;
    padding-block: 9px;
    font-size: .87rem;
}

/* grid / list switch */
.view-switch {
    display: flex;
    gap: 4px;
    padding: 4px;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    background: #fff;
}

.view-switch button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 0;
    border-radius: var(--r-pill);
    background: transparent;
    color: var(--muted);
    transition: background var(--t), color var(--t);
}

.view-switch button.is-active {
    background: var(--ink);
    color: #fff;
}

.view-switch svg {
    width: 16px;
    height: 16px;
}

.pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-top: 48px;
}

.pagination a,
.pagination span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 42px;
    height: 42px;
    padding-inline: 12px;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    color: var(--ink-2);
    font-size: .9rem;
    font-weight: 500;
    transition: background var(--t), border-color var(--t), color var(--t);
}

.pagination a:hover {
    border-color: var(--brand);
    color: var(--brand-dark);
}

.pagination .is-current {
    background: var(--ink);
    border-color: var(--ink);
    color: #fff;
}

.pagination .is-disabled {
    opacity: .45;
    pointer-events: none;
}

/* nothing matched the filters */
.empty {
    padding: clamp(40px, 6vw, 72px) 24px;
    border: 1px dashed var(--line);
    border-radius: var(--r-lg);
    text-align: center;
}

.empty svg {
    width: 46px;
    height: 46px;
    margin: 0 auto 18px;
    color: var(--line);
}

.empty h3 {
    margin-bottom: 8px;
    font-size: 1.25rem;
}

.empty p {
    max-width: 46ch;
    margin-inline: auto;
    color: var(--muted);
}


/* =========================================================================
   26. SERVICE DETAIL
   ========================================================================= */
.detail {
    display: grid;
    grid-template-columns: 1fr 360px;
    gap: clamp(28px, 4vw, 56px);
    align-items: start;
}

/* The rail beside the content is as tall as the content is.

   Everything else in the grid hangs from the top, which is what align-items does - but the
   column holding the price card cannot, or the card has nowhere to travel: a sticky box is
   stuck inside its own parent, and a parent exactly as tall as the box scrolls away with it. */
.detail > aside {
    align-self: stretch;
}

.detail__cover {
    aspect-ratio: 16 / 9;
    margin-bottom: 32px;
    border-radius: var(--r-lg);
    background: var(--mist);
    overflow: hidden;
}

.detail__cover img,
.detail__cover iframe {
    width: 100%;
    height: 100%;
    border: 0;
    object-fit: cover;
}

.detail__head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 20px;
    padding-bottom: 24px;
    margin-bottom: 28px;
    border-bottom: 1px solid var(--line);
}

.detail__title {
    margin-bottom: 8px;
}

.detail__facts {
    display: grid;

    /* three to a row at most: the floor is a third of the width, so a fourth
       option wraps instead of squeezing four names into one line. Fewer than
       three still stretch to fill it, and the 150px keeps a narrow window from
       forcing three columns nobody can read. */
    grid-template-columns: repeat(auto-fit, minmax(max(150px, calc((100% - 2px) / 3)), 1fr));
    gap: 1px;
    margin-bottom: 34px;
    border: 1px solid var(--line);
    border-radius: var(--r);

    /* White, not the line colour. The separators used to be this background
       showing through the gaps, which works only while the last row is full -
       four options in a three-wide grid left two empty tracks painted grey.
       The cells draw their own edges instead, so a part-filled row is empty. */
    background: var(--paper);
    overflow: hidden;
}

.detail__fact {
    padding: 20px;
    background: #fff;

    /* its own hairline, meeting its neighbour's in the 1px gap between them */
    box-shadow: 0 0 0 1px var(--line);
}

.detail__fact span {
    display: block;
    margin-bottom: 4px;
    color: var(--muted);
    font-size: .78rem;
    letter-spacing: .08em;
    text-transform: uppercase;
}

.detail__fact strong {
    display: block;
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 600;
}

/* the sum behind the figure above it. The element selector is carried so this
   outweighs the label rule above, whose uppercase and tracking it undoes */
.detail__fact span.detail__fact-rate {
    margin-top: 2px;
    margin-bottom: 0;
    font-size: .8rem;
    letter-spacing: normal;
    text-transform: none;
}

/* what the crew actually does, straight off the service checklist */
.checklist {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 12px 28px;
}

.checklist li {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    color: var(--ink-2);
    font-size: .95rem;
}

.checklist svg {
    width: 19px;
    height: 19px;
    flex: none;
    margin-top: 4px;
    color: var(--brand);
}

/* A section somebody jumps to stops below the header rather than under it.
   The header is sticky, so the browser's own idea of "the top" is behind it. */
.section[id] {
    scroll-margin-top: calc(var(--header-h, 76px) + 12px);
}

/* the booking rail that follows the page down */
.book-card {
    position: sticky;
    top: calc(var(--header-h) + 20px);
    padding: 26px;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: #fff;
    box-shadow: var(--shadow);
}

.book-card__price {
    display: flex;
    align-items: baseline;
    gap: 7px;
    padding-bottom: 20px;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--line-soft);
}

.book-card__price strong {
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 2.1rem;
    font-weight: 600;
    line-height: 1;
}

.book-card__price span {
    color: var(--muted);
    font-size: .88rem;
}

/* the controls that decide the figure above them, kept tight so the card stays
   a card rather than becoming a form */
.book-card__form {
    padding-bottom: 18px;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--line-soft);
}

.book-card__form .field {
    margin-bottom: 12px;
}

.book-card__form .select,
.book-card__form .input {
    padding-block: 10px;
}

.book-card__list li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding-block: 10px;
    font-size: .9rem;
}

.book-card__list li + li {
    border-top: 1px solid var(--line-soft);
}

.book-card__list span {
    color: var(--muted);
}

.book-card__list strong {
    color: var(--ink);
    font-weight: 600;
}

.book-card .btn {
    margin-top: 22px;
}

.book-card__note {
    margin-top: 14px;
    color: var(--muted);
    font-size: .8rem;
    text-align: center;
}


/* =========================================================================
   26b. GALLERY MOSAIC
   Five frames, one large and four small, any of which opens the viewer.
   The main frame takes exactly half the width; the fr columns split what is
   left after the gaps, so the two side columns stay equal. Row height comes
   from the side cells, so the ratio below drives the whole mosaic.
   ========================================================================= */
.gallery-mosaic {
    display: grid;
    grid-template-columns: 50% 1fr 1fr;
    grid-template-rows: auto auto;
    gap: 12px;
}

/* 3:2 is what interior photography is shot at - 16:9 would slice the ceiling
   and the floor off a room shot */
.gallery-mosaic__cell {
    position: relative;
    aspect-ratio: 3 / 2;
    padding: 0;
    border: 0;
    border-radius: var(--r);
    background: var(--mist);
    overflow: hidden;
    cursor: zoom-in;
}

.gallery-mosaic__cell img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .5s ease;
}

.gallery-mosaic__cell:hover img {
    transform: scale(1.04);
}

/* spans both rows and stretches to their combined height, which lands it on
   the same 3:2 as the cells that set them */
.gallery-mosaic__main {
    grid-row: span 2;
    aspect-ratio: auto;
    min-height: 0;
    border-radius: var(--r-lg);
}

/* out of flow on purpose: in normal flow the photo's own ratio becomes the
   cell's content height, and since this cell spans both rows it would drag the
   whole grid taller or shorter with every company */
.gallery-mosaic__main img {
    position: absolute;
    inset: 0;
}

/* The grid, the cell sizes and the height stay exactly what they are at five
   frames - the cells with no photo behind them are simply not there. With no
   full row of tiles to set the row height, the ratio has to come from here:
   3:1 is what the five-frame mosaic works out to. */
.gallery-mosaic--1,
.gallery-mosaic--2,
.gallery-mosaic--3,
.gallery-mosaic--4 {
    grid-template-rows: 1fr 1fr;
    aspect-ratio: 3 / 1;
}

/* that ratio already fixes the row height - a per-cell ratio fights it */
.gallery-mosaic--1 .gallery-mosaic__cell,
.gallery-mosaic--2 .gallery-mosaic__cell,
.gallery-mosaic--3 .gallery-mosaic__cell,
.gallery-mosaic--4 .gallery-mosaic__cell {
    aspect-ratio: auto;
}

/* frames beyond the five on show - the viewer still counts them */
.gallery-mosaic__cell--more {
    display: none;
}

.gallery-mosaic__all {
    position: absolute;
    right: 16px;
    bottom: 16px;
    display: inline-flex;
    align-items: center;
    gap: 9px;
    padding: 11px 18px;
    border-radius: var(--r-pill);
    background: rgba(255, 255, 255, .92);
    color: var(--ink);
    font-size: .86rem;
    font-weight: 600;
    box-shadow: var(--shadow-sm);
    transition: background var(--t), color var(--t);
}

.gallery-mosaic__main:hover .gallery-mosaic__all {
    background: var(--brand-fill);
    color: #fff;
}

.gallery-mosaic__all svg {
    width: 16px;
    height: 16px;
}


/* =========================================================================
   26c. LIGHTBOX
   Full-screen viewer for the mosaic. One instance per page.
   ========================================================================= */
.lightbox {
    position: fixed;
    inset: 0;
    z-index: var(--z-top);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: clamp(10px, 2vw, 30px);
    padding: clamp(56px, 6vw, 80px) clamp(16px, 4vw, 48px);
    background: rgba(8, 20, 22, .96);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--t), visibility var(--t);
}

/* visibility keeps the controls out of the tab order while it is closed */
.lightbox.is-open {
    opacity: 1;
    visibility: visible;
}

.lightbox__stage {
    display: flex;
    flex-direction: column;
    align-items: center;
    max-width: min(1240px, 100%);
    margin: 0;
}

.lightbox__image {
    width: auto;
    max-width: 100%;
    max-height: 78vh;
    border-radius: var(--r);
    background: var(--ink-2);
}

.lightbox__caption {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-top: 18px;
    color: rgba(255, 255, 255, .7);
    font-size: .86rem;
}

.lightbox__counter {
    padding: 4px 12px;
    border-radius: var(--r-pill);
    background: rgba(255, 255, 255, .12);
    color: #fff;
    font-family: var(--font-mono);
    font-size: .78rem;
}

.lightbox__nav,
.lightbox__close {
    flex: none;
    border-color: rgba(255, 255, 255, .28);
    background: rgba(255, 255, 255, .12);
    color: #fff;
}

.lightbox__nav:hover,
.lightbox__close:hover {
    background: var(--brand-fill);
    border-color: var(--brand-fill);
    color: #fff;
}

.lightbox__nav {
    width: 52px;
    height: 52px;
}

.lightbox__nav svg {
    width: 20px;
    height: 20px;
}

.lightbox__close {
    position: absolute;
    top: clamp(16px, 3vw, 28px);
    right: clamp(16px, 3vw, 28px);
}

/* a single photo has nothing to step through */
.lightbox--solo .lightbox__nav,
.lightbox--solo .lightbox__counter {
    display: none;
}


/* =========================================================================
   27. ACCORDION
   ========================================================================= */
.accordion__item {
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
}

.accordion__item + .accordion__item {
    margin-top: 12px;
}

.accordion__trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    width: 100%;
    padding: 20px 24px;
    border: 0;
    background: transparent;
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.08rem;
    text-align: left;
}

.accordion__trigger svg {
    width: 18px;
    height: 18px;
    flex: none;
    color: var(--brand);
    transition: transform var(--t);
}

.accordion__item.is-open .accordion__trigger svg {
    transform: rotate(45deg);
}

/* height animated from a max-height so nothing has to be measured */
.accordion__panel {
    max-height: 0;
    overflow: hidden;
    transition: max-height var(--t);
}

.accordion__item.is-open .accordion__panel {
    max-height: 400px;
}

.accordion__panel p {
    padding: 0 24px 22px;
    color: var(--muted);
    font-size: .94rem;
}


/* =========================================================================
   28. CONTACT & MAP
   ========================================================================= */
.contact-card {
    display: flex;
    gap: 16px;
    padding: 26px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: #fff;
}

.contact-card__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    height: 46px;
    flex: none;
    border-radius: var(--r-sm);
    background: var(--brand-soft);
    color: var(--brand-dark);
}

.contact-card__icon svg {
    width: 20px;
    height: 20px;
}

.contact-card h3 {
    margin-bottom: 4px;
    font-size: 1.05rem;
}

.contact-card p {
    color: var(--muted);
    font-size: .92rem;
}

.map-frame {
    position: relative;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    overflow: hidden;
}

.map-frame img,
.map-frame iframe {
    display: block;
    width: 100%;
    height: 440px;
    border: 0;
    object-fit: cover;
}


/* =========================================================================
   29. COVERAGE (areas)
   The country as the portal knows it: region, district, town. A column list
   rather than a map, because somebody looking for their own town wants to
   read it, not hunt for a pin.
   ========================================================================= */
.coverage {
    columns: 4;
    column-gap: 32px;
}

.coverage__group {
    display: inline-block;
    width: 100%;
    margin-bottom: 30px;
    break-inside: avoid;
}

/* the coverage map: a frame that keeps its shape before the tiles of the map arrive */
.areas-map {
    height: clamp(280px, 42vw, 460px);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--mist);
    overflow: hidden;
}

/* how many companies go there, beside the name rather than under it */
.coverage__count {
    margin-left: 6px;
    color: var(--muted);
    font-size: .82rem;
}

.coverage__group h3 {
    padding-bottom: 10px;
    margin-bottom: 12px;
    border-bottom: 1px solid var(--line);
    font-size: 1.05rem;
}

.coverage__group li + li {
    margin-top: 8px;
}

.coverage__group a {
    color: var(--ink-2);
    font-size: .92rem;
}

.coverage__group a:hover {
    color: var(--brand-dark);
}

/* the count beside a town, when there is one worth showing */
.coverage__group small {
    color: var(--muted);
    font-size: .8rem;
}


/* =========================================================================
   30. PRICING TABLE
   ========================================================================= */
.price-card {
    display: flex;
    flex-direction: column;
    padding: 32px;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: #fff;
}

/* the middle plan is the recommendation, so it is the one that stands up */
.price-card--featured {
    border-color: var(--ink);
    box-shadow: var(--shadow);
}

.price-card__head {
    padding-bottom: 22px;
    margin-bottom: 22px;
    border-bottom: 1px solid var(--line-soft);
}

.price-card__name {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
    font-size: 1.2rem;
}

.price-card__amount {
    display: flex;
    align-items: baseline;
    gap: 6px;
}

.price-card__amount strong {
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 2.5rem;
    font-weight: 600;
    line-height: 1;
}

.price-card__amount span {
    color: var(--muted);
    font-size: .88rem;
}

.price-card ul {
    margin-bottom: 26px;
}

.price-card li {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    margin-bottom: 11px;
    font-size: .93rem;
}

.price-card li svg {
    width: 18px;
    height: 18px;
    flex: none;
    margin-top: 4px;
    color: var(--brand);
}

/* a line the plan does not include still reads, in grey with a cross */
.price-card li.is-off {
    color: var(--muted);
}

.price-card li.is-off svg {
    color: var(--line);
}

.price-card .btn {
    margin-top: auto;
}

/* the rate table on the pricing page */
.rate-table th,
.rate-table td {
    padding: 15px 18px;
    border-bottom: 1px solid var(--line-soft);
    text-align: left;
    font-size: .93rem;
}

.rate-table th {
    color: var(--muted);
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
}

.rate-table td strong {
    color: var(--ink);
}

.rate-table td:last-child,
.rate-table th:last-child {
    text-align: right;
}

/* a table is the one block that may scroll sideways on a phone */
.table-scroll {
    overflow-x: auto;
    border: 1px solid var(--line);
    border-radius: var(--r);
}

.table-scroll .rate-table {
    min-width: 560px;
}

.table-scroll tr:last-child td {
    border-bottom: 0;
}


/* =========================================================================
   31. ARTICLE BODY
   Long-form typography for the single post page and for anything the page
   builder's editor widget writes.
   ========================================================================= */
.article__cover {
    aspect-ratio: 2 / 1;
    margin-bottom: 36px;
    border-radius: var(--r-lg);
    background: var(--mist);
    overflow: hidden;
}

.article__cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.article__body {
    font-size: 1.02rem;
}

.article__body h2 {
    margin-top: 40px;
    font-size: 1.7rem;
}

.article__body h3 {
    margin-top: 30px;
    font-size: 1.3rem;
}

.article__body ul,
.article__body ol {
    margin: 0 0 1.2em;
    padding-left: 22px;
    list-style: disc;
}

.article__body ol {
    list-style: decimal;
}

.article__body li {
    margin-bottom: 8px;
}

.article__body img {
    margin-block: 28px;
    border-radius: var(--r);
}

.article__body blockquote {
    margin: 32px 0;
    padding: 4px 0 4px 26px;
    border-left: 3px solid var(--brand);
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.3rem;
    line-height: 1.5;
}

.article__footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    margin-top: 44px;
    padding-top: 26px;
    border-top: 1px solid var(--line);
}

.article__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}


/* =========================================================================
   32. BACK TO TOP
   ========================================================================= */
.to-top {
    position: fixed;
    right: 24px;
    bottom: 24px;
    z-index: var(--z-header);
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px);
    transition: opacity var(--t), transform var(--t), visibility var(--t);
}

.to-top.is-visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

/* the whatsapp button, when the install has a number for it */
.floating-whatsapp {
    position: fixed;
    right: 24px;
    bottom: 78px;
    z-index: var(--z-header);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: var(--r-pill);
    background: #25D366;
    color: var(--ink);
    box-shadow: var(--shadow);
    transition: transform var(--t);
}

.floating-whatsapp:hover {
    color: var(--ink);
    transform: translateY(-2px);
}

.floating-whatsapp svg {
    width: 26px;
    height: 26px;
}


/* =========================================================================
   33. UTILITIES
   ========================================================================= */
.d-none         { display: none !important; }
.text-center    { text-align: center; }
.text-right     { text-align: right; }
.mt-0           { margin-top: 0; }
.mb-0           { margin-bottom: 0; }
.mt-16          { margin-top: 16px; }
.mt-24          { margin-top: 24px; }
.mt-32          { margin-top: 32px; }
.mt-40          { margin-top: 40px; }
.mb-16          { margin-bottom: 16px; }
.mb-24          { margin-bottom: 24px; }
.mb-32          { margin-bottom: 32px; }
.gap-16         { gap: 16px; }
.flex-center    { display: flex; align-items: center; }
.justify-center { display: flex; justify-content: center; }
.stack-16       { display: flex; flex-direction: column; gap: 16px; }

/* elements revealed on scroll by main.js */
.reveal {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity .6s ease, transform .6s ease;
}

.reveal.is-visible {
    opacity: 1;
    transform: none;
}

/* somebody who would rather nothing moved gets a page where nothing moves */
@media (prefers-reduced-motion: reduce) {

    html {
        scroll-behavior: auto;
    }

    *,
    *::before,
    *::after {
        animation-duration: .01ms !important;
        transition-duration: .01ms !important;
    }

    .reveal {
        opacity: 1;
        transform: none;
    }
}


/* =========================================================================
   34. ELEMENTS PAGE (style guide)
   Every component on one page, so a change to the system can be checked in
   one place rather than hunted across the site.
   ========================================================================= */
.ui-block {
    padding-block: 48px;
    border-top: 1px solid var(--line);
}

.ui-block:first-of-type {
    border-top: 0;
}

.ui-block__title {
    margin-bottom: 26px;
    color: var(--muted);
    font-family: var(--font-body);
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
}

.ui-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px;
}

.ui-swatches {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 16px;
}

.ui-swatch__chip {
    height: 78px;
    margin-bottom: 10px;
    border: 1px solid var(--line);
    border-radius: var(--r);
}

.ui-swatch code {
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: .78rem;
}


/* =========================================================================
   35. RESPONSIVE
   Breakpoints: 1100 (tablet landscape), 900 (tablet), 640 (phone)
   ========================================================================= */
/* --- 12d. the phone's booking bar -------------------------------------- */
/* The price card is sticky beside the content on a wide screen and scrolls
   away on a narrow one, taking the only booking button with it. This is that
   card reduced to the figure and the button, held to the bottom of the
   screen. Desktop never sees it. */
.book-bar {
    display: none;
}

.book-bar__price {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.25;
}

.book-bar__label {
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted);
}

.book-bar__price strong {
    font-size: 1.2rem;
    white-space: nowrap;
}

.book-bar__note {
    display: flex;
    align-items: center;
    gap: 5px;
    margin-top: 2px;
    font-size: .78rem;
    color: var(--muted);

    /* a long promise on a narrow phone loses its tail rather than pushing the
       button off the edge */
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.book-bar__note svg {
    width: 13px;
    height: 13px;
    flex: none;
    color: var(--gold);
}


@media (max-width: 1100px) {

    .request-bar__form {
        grid-template-columns: 1fr 1fr;
    }

    /* the hairline divider only makes sense while the cells are in one row */
    .request-bar__cell + .request-bar__cell {
        box-shadow: none;
    }

    .request-bar__submit {
        grid-column: 1 / -1;
        padding: 4px 8px 8px;
    }

    .request-bar__submit .btn {
        width: 100%;
    }

    .wizard {
        grid-template-columns: 1fr;
    }

    .summary {
        position: static;
    }

    .detail {
        grid-template-columns: 1fr;
    }

    /* a page whose aside carries the price and the controls puts them first here:
       stacked the other way they sit under everything there is to read */
    .detail--priced > aside {
        order: -1;
    }

    .book-card {
        position: static;
    }

    .book-bar {
        position: fixed;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: var(--z-header);
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 16px;
        padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
        border-top: 1px solid var(--line);
        background: var(--paper);
        box-shadow: 0 -6px 24px rgba(15, 42, 46, .08);
        transition: transform var(--t);
    }

    .book-bar .btn {
        flex: none;
    }

    /* the bar sits over the last of the page, so the page ends above it */
    body.has-book-bar {
        padding-bottom: 84px;
    }

    body.has-book-bar .to-top {
        bottom: 96px;
    }

    body.has-book-bar .floating-whatsapp {
        bottom: 150px;
    }

    .layout-sidebar,
    .layout-sidebar--right {
        grid-template-columns: 1fr;
    }

    .sidebar {
        position: static;
    }

    .rail__track {
        grid-auto-columns: calc((100% - 28px) / 2);
    }

    .coverage {
        columns: 3;
    }

    .footer-grid {
        grid-template-columns: 1fr 1fr;
    }

    .grid.col-4 {
        grid-template-columns: repeat(2, 1fr);
    }

    .grid.col-5 {
        grid-template-columns: repeat(3, 1fr);
    }
}

@media (max-width: 900px) {

    /* the header runs out of room next to the toggle, so the button keeps
       its icon and drops the word */
    .header-actions .btn__label {
        display: none;
    }

    .header-actions .btn {
        padding: 9px 12px;
    }

    /* swap desktop nav for the drawer */
    .nav,
    .header-phone,
    .topbar {
        display: none;
    }

    .nav-toggle {
        display: inline-flex;
    }

    .site-header__inner {
        min-height: 68px;
    }

    /* the top bar is hidden here and the header is shorter */
    :root {
        --header-h: 69px;
    }

    .hero__grid,
    .split,
    .split--end-wide,
    .split--start-wide,
    .newsletter {
        grid-template-columns: 1fr;
    }

    /* on one column the picture belongs under the words it illustrates */
    .split--media-first .split__media {
        order: 0;
    }

    .hero__card {
        left: 16px;
        bottom: 16px;
    }

    .grid.col-3 {
        grid-template-columns: repeat(2, 1fr);
    }

    .cta {
        grid-template-columns: 1fr;
        gap: 26px;
    }

    /* the sidebar panel becomes a drawer opened from the toolbar */
    .filters {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        z-index: calc(var(--z-drawer) + 1);
        width: min(340px, 88vw);
        border: 0;
        border-radius: 0;
        overflow-y: auto;
        transform: translateX(-100%);
        transition: transform var(--t);
    }

    .filters.is-open {
        transform: translateX(0);
    }

    .filters-trigger {
        display: inline-flex;
    }

    .offer {
        grid-template-columns: 1fr;
        gap: 20px;
    }

    /* the money stops being a column, so it stops being bordered like one */
    .offer__price {
        padding-left: 0;
        padding-top: 20px;
        border-left: 0;
        border-top: 1px solid var(--line-soft);
        text-align: left;
    }

    /* the amount and what it is in read as one line rather than stacking into
       three, which on a phone is most of the card's height for two words */
    .offer__price strong,
    .offer__price-unit {
        display: inline;
    }

    .offer__price strong {
        font-size: 1.6rem;
    }

    /* Two blocks that make the card long for what a phone can do with them: three
       lines of somebody's sentence, where the stars above already say it, and the
       task list, which is for choosing between two firms side by side rather than
       scrolling one. Both are on the company's page and on the booking step.

       The scores stay - they are the part you actually compare. */
    .offer__quote,
    .offer__included {
        display: none;
    }


    .service-card--row {
        flex-direction: column;
    }

    .service-card--row .service-card__media {
        flex: none;
        aspect-ratio: 3 / 2;
    }

    .detail__head {
        align-items: flex-start;
    }

    .coverage {
        columns: 2;
    }

    .map-frame img,
    .map-frame iframe {
        height: 340px;
    }
}

@media (max-width: 640px) {

    :root {
        --gutter: 18px;
    }

    .grid {
        gap: 20px;
    }

    .grid.col-2,
    .grid.col-3,
    .grid.col-4,
    .grid.col-5 {
        grid-template-columns: 1fr;
    }

    .request-bar__form {
        grid-template-columns: 1fr;
    }

    /* every pill takes the full width, so its panel does too */
    .filter-field {
        flex: 1 1 100%;
    }

    .filter-drop,
    .filter-drop--right {
        left: 0;
        right: 0;
        width: auto;
    }

    .filter-bar__submit {
        width: 100%;
    }

    .rail__track {
        grid-auto-columns: 84%;
    }

    .section-head,
    .rail__head {
        flex-direction: column;
        align-items: flex-start;
        gap: 18px;
    }

    /* stacked, the arrows keep the corner they had beside the heading - they point
       into the rail, and a rail is dragged from its right-hand end */
    .rail__head .rail__nav {
        align-self: flex-end;
    }

    .hero__proof {
        gap: 24px;
    }

    .hero__proof strong {
        font-size: 1.5rem;
    }

    /* overlapping the image needs room the phone does not have */
    .hero__card {
        position: static;
        margin-top: 16px;
        box-shadow: var(--shadow);
    }

    .wizard__steps {
        gap: 6px;
    }

    /* the words under each step number will not fit four across */
    .wizard__step span {
        display: none;
    }

    .picks {
        grid-template-columns: 1fr;
    }

    .wizard__nav {
        flex-direction: column-reverse;
    }

    .wizard__nav .btn {
        width: 100%;
    }

    .footer-grid {
        grid-template-columns: 1fr;
    }

    /* the coverage list is a column layout, not a grid — it collapses its own way */
    .coverage {
        columns: 1;
    }

    .footer-bottom {
        flex-direction: column;
        align-items: flex-start;
        gap: 12px;
    }

    .footer-bottom ul {
        flex-wrap: wrap;
        gap: 16px;
    }

    .newsletter__form {
        flex-direction: column;
    }

    .quote,
    .feature,
    .price-card {
        padding: 24px;
    }

    /* the spread and the scores stack rather than squeezing into two columns */
    .score-summary {
        grid-template-columns: 1fr;
        gap: 26px;
        padding: 22px;
    }

    .detail__facts {
        grid-template-columns: 1fr 1fr;
    }

    /* three columns of photographs on a phone is three thumbnails nobody can
       see. The big frame carries it, and the viewer holds the rest */
    .gallery-mosaic,
    .gallery-mosaic--1,
    .gallery-mosaic--2,
    .gallery-mosaic--3,
    .gallery-mosaic--4 {
        grid-template-columns: 1fr 1fr;
        grid-template-rows: auto;
        aspect-ratio: auto;
    }

    .gallery-mosaic__main {
        grid-column: 1 / -1;
        grid-row: auto;
        aspect-ratio: 3 / 2;
    }

    .gallery-mosaic__main img {
        position: static;
    }

    .gallery-mosaic--1 .gallery-mosaic__cell,
    .gallery-mosaic--2 .gallery-mosaic__cell,
    .gallery-mosaic--3 .gallery-mosaic__cell,
    .gallery-mosaic--4 .gallery-mosaic__cell {
        aspect-ratio: 3 / 2;
    }

    /* one wide frame and the pair under it, and no more: a fourth photo starts a
       row it cannot fill and the gallery turns into a column of the whole set.
       The rest are still in the page for the viewer to count and page through,
       which is what the pill on the first frame offers. */
    .gallery-mosaic__cell:nth-child(n + 4) {
        display: none;
    }

    .to-top,
    .floating-whatsapp {
        right: 16px;
    }
}


/* ---------------------------------------------------------------- house rules
   The portal's terms sit under the company's own, in the same shape but a step
   quieter - they are the same kind of promise made by somebody else. */
.terms-house__title {
    font-size: 1.0625rem;
    font-weight: 600;
    margin-bottom: 10px;
    color: var(--muted);
}

.checklist--muted li,
.checklist--muted svg {
    color: var(--muted);
}
