/* Generated by wordpress-bestnear/tools/build-theme-assets.cjs from the static repository source/styles/*.css (order: source/lib/styles.cjs, 27 files) + assets/css/wp-adapter.css. Do not edit. */
/* 00-tokens.css. Design tokens (design/step-2.md §1): the Manrope web font, brand colours, surfaces, type scale and
   spacing. Only tokens change at a breakpoint (--text-lead, once, at 800 px); components never redefine a font size
   in a media query. Keep the --text-* prefix for the type scale only (the type checks read it). */
@font-face{font-family:Manrope;src:url('../fonts/manrope-latin.woff2') format('woff2');font-weight:400 800;font-display:swap}

/* Arabic webfont (S5-03, final QA Q-01; design/step-5.md §0.1/§1.1, ARCHITECTURE §5.4). Self-hosting is ACTIVE:
   the owner approved the IBM Plex Sans Arabic download (OPS-NOTES.md, 09:30 local 28 Sep), content/site.cjs
   flags.arabicWebfont is true, and dist/shared/assets/ibm-plex-sans-arabic-{400,700}.woff2 (plus the OFL
   licence, -OFL.txt) are committed. unicode-range on both rules is copied verbatim from the subset's own
   assets/fonts/ibm-plex-sans-arabic/sources.tsv (the Arabic block, presentation forms and the few extra
   Unicode ranges IBM Plex Sans Arabic itself covers), not the shorter placeholder range an earlier draft of
   this file wrote from memory: it must match the subset actually downloaded, or a character in the subset's
   coverage but outside a too-narrow range would silently fall back to the next font in --font-ar. The range
   still excludes Latin, so these rules never intercept an EN page even though the stylesheet is shared. */
@font-face{font-family:"IBM Plex Sans Arabic";src:url('../fonts/ibm-plex-sans-arabic-400.woff2') format('woff2');font-weight:400;font-display:swap;unicode-range:U+0600-06FF,U+0750-077F,U+0870-088E,U+0890-0891,U+0897-08E1,U+08E3-08FF,U+200C-200E,U+2010-2011,U+204F,U+2E41,U+FB50-FDFF,U+FE70-FE74,U+FE76-FEFC,U+102E0-102FB,U+10E60-10E7E,U+10EC2-10EC4,U+10EFC-10EFF,U+1EE00-1EE03,U+1EE05-1EE1F,U+1EE21-1EE22,U+1EE24,U+1EE27,U+1EE29-1EE32,U+1EE34-1EE37,U+1EE39,U+1EE3B,U+1EE42,U+1EE47,U+1EE49,U+1EE4B,U+1EE4D-1EE4F,U+1EE51-1EE52,U+1EE54,U+1EE57,U+1EE59,U+1EE5B,U+1EE5D,U+1EE5F,U+1EE61-1EE62,U+1EE64,U+1EE67-1EE6A,U+1EE6C-1EE72,U+1EE74-1EE77,U+1EE79-1EE7C,U+1EE7E,U+1EE80-1EE89,U+1EE8B-1EE9B,U+1EEA1-1EEA3,U+1EEA5-1EEA9,U+1EEAB-1EEBB,U+1EEF0-1EEF1}
@font-face{font-family:"IBM Plex Sans Arabic";src:url('../fonts/ibm-plex-sans-arabic-700.woff2') format('woff2');font-weight:700;font-display:swap;unicode-range:U+0600-06FF,U+0750-077F,U+0870-088E,U+0890-0891,U+0897-08E1,U+08E3-08FF,U+200C-200E,U+2010-2011,U+204F,U+2E41,U+FB50-FDFF,U+FE70-FE74,U+FE76-FEFC,U+102E0-102FB,U+10E60-10E7E,U+10EC2-10EC4,U+10EFC-10EFF,U+1EE00-1EE03,U+1EE05-1EE1F,U+1EE21-1EE22,U+1EE24,U+1EE27,U+1EE29-1EE32,U+1EE34-1EE37,U+1EE39,U+1EE3B,U+1EE42,U+1EE47,U+1EE49,U+1EE4B,U+1EE4D-1EE4F,U+1EE51-1EE52,U+1EE54,U+1EE57,U+1EE59,U+1EE5B,U+1EE5D,U+1EE5F,U+1EE61-1EE62,U+1EE64,U+1EE67-1EE6A,U+1EE6C-1EE72,U+1EE74-1EE77,U+1EE79-1EE7C,U+1EE7E,U+1EE80-1EE89,U+1EE8B-1EE9B,U+1EEA1-1EEA3,U+1EEA5-1EEA9,U+1EEAB-1EEBB,U+1EEF0-1EEF1}
:root{
 /* Brand colours (unchanged values). */
 --navy:#0b2545;--blue:#0068b0;--cyan:#00c0e0;--ink:#102e49;--muted:#546b7e;--ice:#edf5f8;--line:#d9e5eb;--white:#fff;--radius:8px;--radius-sm:4px;
 /* Arabic font stack (S5-03, design/step-5.md §1.1): the same list is used whether the self-hosted face above is
    registered or not — CSS font matching falls through to the next name when "IBM Plex Sans Arabic" resolves to
    nothing (no @font-face yet, and no OS ships a system font under that exact name), so this token and the rule
    that applies it below are NOT behind the flag and need no change when the flag flips true. */
 --font-ar:"IBM Plex Sans Arabic","Noto Sans Arabic","Geeza Pro","Segoe UI",Tahoma,Manrope,sans-serif;
 /* Surfaces and roles (DESIGN-AUDIT §3.2). Links and icons use --blue and the WhatsApp action --cyan directly (the
    --accent and --cta aliases had no user and were removed in the step-2 review). */
 --surface:var(--white);--surface-alt:var(--ice);--surface-strong:var(--navy);
 --ink-on-strong:#e2eef5;--line-on-strong:rgb(255 255 255 / .15);--focus:#007dad;--focus-on-strong:#6ee7ff;
 /* Type scale (DESIGN-AUDIT §2.2), rem so the browser text-size setting works. */
 --text-caption:.8125rem;--text-ui:.9375rem;--text-body:1rem;--text-lead:1.125rem;
 --text-h3:clamp(1.25rem,1rem + .6vw,1.5rem);--text-h2:clamp(1.875rem,1.1rem + 2.2vw,2.75rem);
 --lh-caption:1.45;--lh-caps:1.3;--lh-ui:1.3;--lh-body:1.6;--lh-body-strong:1.65;--lh-lead:1.55;--lh-h3:1.25;--lh-heading:1.12;
 --track-caps:.12em;--track-h3:-.01em;--track-h2:-.03em;
 /* Spacing, 4 px base (DESIGN-AUDIT §3.5). px on purpose: spacing follows zoom, not the text-size setting. The whole
    scale is kept, 3xl to 5xl included, for the page templates of steps 3 and 4. */
 --space-2xs:4px;--space-xs:8px;--space-sm:12px;--space-md:16px;--space-lg:24px;--space-xl:32px;--space-2xl:48px;--space-3xl:64px;--space-4xl:96px;--space-5xl:128px;
 --section-y:clamp(64px,40px + 5vw,112px);--section-y-tight:clamp(48px,36px + 3vw,72px);--section-y-loose:clamp(80px,48px + 7vw,144px);
 --stack-heading:clamp(32px,24px + 2vw,48px);--stack-text:clamp(16px,12px + 1vw,24px);--gap-split:clamp(40px,6vw,96px);
 /* Motion (.impeccable.md): the step-3 process accordion uses it (design/step-3.md). */
 --ease-out:cubic-bezier(.22,1,.36,1);
 /* Elevation of the panels that hang under the header (the burger menu, the Services drop-down): navy-tinted. */
 --shadow-panel:0 14px 16px #0b25451a;
}
@media(max-width:800px){:root{--text-lead:1.0625rem}}
/* S5-03: Arabic body font-family, both locales' rule kept out of 01-base.css's body{} declaration (owned by
   S5-01a) by specificity, not file order (:root[lang=ar] body is (0,2,1), stronger than a bare body{} at any
   position in the cascade). */
:root[lang=ar] body{font-family:var(--font-ar)}
/* Arabic body line-height (design/step-5.md §1.3): joined script and diacritics need more room than Latin text.
   --lh-body (every paragraph, list item and card text) and --lh-body-strong (the navy surfaces) are both 1.9;
   captions, eyebrows and leads keep their English values. */
:root[lang=ar]{--lh-body:1.9;--lh-body-strong:1.9}
/* 01-base.css. Base: element defaults, layout primitives (.wrap, .section, .section-heading, .eyebrow), buttons and
   links, then the frozen-area shield. Shared by every page. Font sizes come from the tokens only (design/step-2.md §2). */
*{box-sizing:border-box}
html{scroll-behavior:smooth;scroll-padding-block-start:var(--space-lg)}
body{margin:0;color:var(--ink);background:var(--surface);font-family:Manrope,Arial,sans-serif;font-size:var(--text-body);line-height:var(--lh-body);-webkit-font-smoothing:antialiased}
button,input,select{font:inherit}
button,a,input,select,summary{-webkit-tap-highlight-color:transparent}
a{color:inherit;text-decoration:none}
a,button,input,select,summary{touch-action:manipulation}
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,summary:focus-visible{outline:3px solid var(--focus);outline-offset:5px}
/* The light ring everywhere (the scroll hero included: 4.23:1 on its ice), the cyan ring on navy surfaces only. */
.team :focus-visible,.process :focus-visible,.package-featured :focus-visible,.closing :focus-visible,.footer :focus-visible{outline-color:var(--focus-on-strong)}
button{cursor:pointer}
img{display:block;max-width:100%;height:auto}
svg{display:block}
.icon{width:22px;height:22px;flex-shrink:0}
h1,h2,h3,p,figure{margin:0}
h1,h2,h3{font-weight:700;text-wrap:balance}
h1{font-size:clamp(2.5rem,2.08rem + 1.714vw,3.625rem);line-height:var(--lh-heading);letter-spacing:-.038em;margin-block-end:var(--space-lg)}
h2{font-size:var(--text-h2);line-height:var(--lh-heading);letter-spacing:var(--track-h2)}
h3{font-size:var(--text-h3);line-height:var(--lh-h3);letter-spacing:var(--track-h3)}
p{color:var(--muted);max-width:65ch}
.wrap{width:calc(100% - 96px);max-width:1280px;margin-inline:auto}
.section{padding-block:var(--section-y);scroll-margin-block-start:var(--space-lg)}
/* Section rhythm (design/step-2.md §3): every section of <main> uses --section-y, except the services (tight on
   top: the Why band already separates) and the bands that set their own token (team: loose; closing: tight). */
.services{padding-block-start:var(--section-y-tight)}
.eyebrow{font-size:var(--text-caption);font-weight:800;line-height:var(--lh-caps);letter-spacing:var(--track-caps);color:var(--blue);margin-block-end:var(--space-sm)}
/* Arabic ships 400 and 700 only: 800 maps to 700 (design/step-5.md §1.2). */
:root[lang=ar] .eyebrow{font-weight:700}
.section-heading{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--gap-split);margin-block-end:var(--stack-heading)}
.section-heading>div{max-inline-size:720px}
.section-description{flex:0 1 25rem;max-inline-size:25rem;font-size:var(--text-lead);line-height:var(--lh-lead)}
.button{min-height:52px;display:inline-flex;align-items:center;justify-content:center;gap:10px;padding-block:14px;padding-inline:20px;border:1px solid transparent;border-radius:5px;font-size:var(--text-ui);font-weight:800;line-height:var(--lh-ui);transition:background .18s,transform .18s,color .18s}
:root[lang=ar] .button{font-weight:700}
.button .icon{width:20px;height:20px}
.button .end-icon{width:18px;margin-inline-start:6px}
.button-primary{background:var(--cyan);color:var(--navy)}
.button-primary:hover{background:#61dfef;transform:translateY(-2px)}
.button-outline{color:var(--blue);border-color:#a4c8de;background:var(--surface)}
.button-outline:hover{background:var(--ice);border-color:var(--blue)}
/* Text link: [icon] label [arrow] in one grid row, the row centred in the 44 px box (align-content), so a one-line
   link sits exactly where the former flex row put it. Each icon is centred on the label's FIRST line (its line box
   is 1lh tall), so when the label wraps on a phone the icons stay beside that line instead of floating between the
   two (a flex row would centre them on the whole label). Layouts that set their own display (30-services.css
   inline flow, 46-legal.css and 31-packages.css grid) are written against this rule. */
.text-link{display:inline-grid;grid-auto-flow:column;justify-content:start;align-content:center;align-items:center;gap:var(--space-xs);min-height:44px;color:var(--blue);font-size:var(--text-ui);font-weight:800;line-height:var(--lh-ui)}
:root[lang=ar] .text-link{font-weight:700}
.text-link .icon{width:18px;height:18px;align-self:start;margin-block-start:calc((1lh - 18px) / 2)}
.text-link:hover span,.text-link:hover{text-decoration:underline;text-underline-offset:5px}
.text-link .end-icon{margin-inline-start:2px}
/* Pause / play glyph of the Why band toggle: the size of its 15 px label, centred on it. */
.pause-symbol{font-size:var(--text-ui);line-height:1;letter-spacing:-2px;width:12px}
/* Media queries: layout only. No font-size in a media query (the tokens change instead). */
@media(max-width:1150px){
 .wrap{width:calc(100% - 64px)}
}
@media(max-width:1000px) and (min-width:801px){
 .wrap{width:calc(100% - 48px)}
}
@media(max-width:800px){
 .wrap{width:calc(100% - 40px)}
 body{padding-block-end:calc(67px + env(safe-area-inset-bottom,0px))}
 /* Keyboard focus and anchors scroll to just above the fixed mobile action bar, never under it (WCAG 2.4.11). */
 html{scroll-padding-block-end:calc(67px + env(safe-area-inset-bottom,0px))}
 .section-heading{display:block}
 .section-description{margin-block-start:var(--stack-text);max-inline-size:32.5rem}
}
@media(prefers-reduced-motion:reduce){
 html{scroll-behavior:auto}
 *,*:before,*:after{animation:none!important;transition:none!important}
 .button-primary:hover{transform:none}
}
@media print{
 body{padding-block-end:0}
 .section{padding-block:30px}
}

/* ---- Step 3 additions (design/step-3.md §3.0, Appendix A.1): section surfaces, stacked heading, in-text links.
   The light service hero (.hero-service, S3-01a) keeps the light ring: it is not in the focus-ring list above. */
.section.is-alt{background:var(--surface-alt)}
.section.has-rule{border-block-start:1px solid var(--line)}
.section-heading.is-stacked{display:block}
.section-heading.is-stacked .section-description{flex:none;max-inline-size:40rem;margin-block-start:var(--stack-text)}
/* A link inside a sentence (WCAG 2.5.8 inline exception, no 44 px box). wa() writes icons: hidden here. */
p .inline-link{color:var(--blue);font-weight:700;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:4px}
p .inline-link .icon{display:none}

/* ---- Frozen-area shield (design/step-2.md §7.2) ----
   The scroll hero (.hero-scroll and its fallback .hero-static) and the Why band are approved and must stay
   pixel-identical (hero-guard, why-guard, verify/checks/frozen.cjs). The step-2 base above would reach them through
   inheritance and shared classes, so these rules put back the step-1 values inside them, and only there. Exempt
   from the step-2 type rules (px values). Keep them here, before 20-hero-photo.css and 80-hero-scroll.css, and keep
   each line at the specificity of the base rule it undoes: `.hero .eyebrow` (0,2,0, 21 px margin at 560 px and
   below) and `.hero-scroll h1` (0,1,1, 14 px margin at 800 px and below) must still win, exactly as in step 1,
   hence :where() on the eyebrow line; :where() also keeps the p reset at 0,0,1. S2-06 (owner branch) overrides the
   hero lines it replaces. In the Why band only the eyebrow (13 px, the min-font-size floor) and the S2-05 Pause
   button change; its title keeps the step-1 metrics below until the owner decides (owner/why-band, Q7). */
.hero-scroll,.hero-static,.why{font-size:.9375rem;line-height:1.7}
:where(.hero-scroll,.hero-static,.why) p{max-width:none}
:where(.hero-scroll,.hero-static) .eyebrow{line-height:1.5;margin-block-end:16px}
.hero-scroll .button,.hero-static .button{font-size:.875rem;line-height:1.4}
/* The step-1 h2 of the Why band: the base h2 token would make it 30 px at 390 (31), 33 at 700 (35), 40 at 1024 (32)
   and 44 at 1440 (43), with tighter lines and tracking. Left out of distinct-font-sizes (verify/checks/type.cjs,
   FROZEN_PENDING.sizes) while it waits for the owner. */
.why-head h2{font-size:clamp(30px,3.15vw,43px);line-height:1.18;letter-spacing:-1.5px}
@media(max-width:800px){.why-head h2{font-size:35px;letter-spacing:-1.2px}}
@media(max-width:560px){.why-head h2{font-size:31px;line-height:1.2;letter-spacing:-1.1px}}
/* 10-header.css. Skip link, utility bar, site header, main navigation, collapsible menu (1100 px and below) and the
   mobile service chip row (lib/layout/header.cjs). Sizes come from the tokens only, never from a media query
   (design/step-2.md §4). The header keeps its step-1 height at every width: 109 px up to 800, 123 from 801 to 1150
   and 133 above. The scroll hero starts under it and hero-scroll.js derives --hero-offset from its top edge
   (hero-guard, verify/checks/frozen.cjs, §4.1). Do not change the utility bar min-height, .header-inner min-height
   or the logo width. */
.skip-link{position:fixed;inset-inline-start:20px;inset-block-start:12px;z-index:1000;padding-block:12px;padding-inline:20px;background:var(--surface);transform:translateY(-160%)}
.skip-link:focus{transform:translateY(0)}
.utility{position:relative;z-index:31;background:var(--blue);color:#fff;font-size:var(--text-caption);line-height:var(--lh-caption)}
.utility>.wrap,.utility span{display:flex;align-items:center;gap:var(--space-xs)}
.utility>.wrap{min-height:34px;justify-content:space-between}
.utility .icon{width:14px;height:14px}
.utility-divider{opacity:.55;margin-inline:4px}
/* The desktop phone link: its box stays 24 px tall because the 34 px bar is part of the header height the hero
   depends on (§4.1). A transparent ::after grows its hit area to 44 px, from the top of the page (5 px above the
   box) to 10 px into the header, which has no target in its top 20 px; the bar is stacked above the header for it.
   touch-targets measures that hit area.
   Its focus ring is white and fits inside the bar (24 + 2 x 2 offset + 2 x 3 ring = 34 px): the light ring ran
   under the header and reached 1.26:1 on the blue bar. */
.utility a{position:relative;display:inline-flex;align-items:center;min-block-size:24px;margin-inline-start:var(--space-md);font-weight:700}
.utility a::after{content:"";position:absolute;inset-block:-5px -15px;inset-inline:-4px}
.utility a:focus-visible{outline-color:#fff;outline-offset:2px}
/* Language switcher (lib/layout/header.cjs langSwitch(), design/step-5.md §3): its link keeps the bar's 24 px box and
   phone-link hit area, widened to 44 px and more by a transparent inline extension ("العربية" is 29 px wide at
   13 px). Nothing is drawn: the bar looks the same. */
.utility .lang-switch a::after{inset-inline:-10px}
.site-header{background:var(--surface);position:relative;z-index:30;border-block-end:1px solid #f1f4f6}
.header-inner{display:flex;justify-content:space-between;align-items:center;gap:var(--space-xl);min-height:98px}
.brand{display:flex;align-items:center;width:234px;min-block-size:44px;flex-shrink:0}
#main-nav{display:flex;align-items:center;gap:28px;font-size:var(--text-ui);font-weight:800;line-height:var(--lh-ui)}
:root[lang=ar] #main-nav{font-weight:700}
#main-nav>a:not(.button),.nav-group-link{display:inline-flex;align-items:center;min-inline-size:44px;min-block-size:44px}
#main-nav>a:not(.button):hover,#main-nav>[aria-current],.nav-group-link:hover,.nav-group-link[aria-current]{color:var(--blue)}
.button-header{background:var(--blue);color:#fff;min-height:46px;padding-block:var(--space-sm);padding-inline:var(--space-md)}
.button-header:hover{background:var(--navy)}
.button-header .end-icon{display:none}
/* Services group (owner request, 29 Sep 2026; lib/layout/header.cjs servicesGroup(), dist/ui.js menu block).
   Without JavaScript the group is only its link to the services hub, laid out exactly as before (the wrapper is
   display:contents; the button and the panel draw nothing). With html.js, set before the first paint, the link gives
   way to the disclosure button, same label plus a chevron. Above 1100 px the panel drops from the header's bottom
   edge under the button, absolutely positioned: the header keeps its height (§4.1) and the panel never covers it.
   The nav and the wrapper stretch over the full header height, so the pointer stays inside the group on its way
   from the button to the panel (ui.js also waits before closing a panel that hover opened). The panel's inline
   start is pulled back by its border, padding and row padding, so the icon column lines up with the "Services"
   label; logical properties only, so it mirrors on /ar/. */
.nav-group{display:contents}
.nav-group-toggle{display:none}
.js .nav-group-link{display:none}
.js #main-nav{align-self:stretch}
.js .nav-group{position:relative;display:flex;align-items:center;align-self:stretch}
.js .nav-group-toggle{display:inline-flex;align-items:center;gap:var(--space-2xs);min-block-size:44px;padding:0;border:0;background:none;color:inherit}
.nav-group-toggle .icon{width:16px;height:16px;transition:transform .2s var(--ease-out)}
.nav-group-toggle[aria-expanded=true] .icon{transform:rotate(180deg)}
.nav-group-toggle:hover,.nav-group-toggle[aria-expanded=true],.nav-group-toggle.is-current{color:var(--blue)}
.nav-group-panel{display:none;position:absolute;z-index:1;inset-block-start:calc(100% + 1px);inset-inline-start:calc(-1 * (var(--space-xs) + var(--space-sm) + 1px));inline-size:max-content;min-inline-size:16rem;max-inline-size:calc(100vw - 2 * var(--space-md));margin:0;padding:var(--space-xs);list-style:none;background:var(--surface);border:1px solid var(--line);border-block-start:0;border-end-start-radius:var(--radius);border-end-end-radius:var(--radius);box-shadow:var(--shadow-panel);transition:opacity .16s var(--ease-out)}
.js .nav-group-panel:not([hidden]){display:block}
/* A short fade in, no slide: a slide would pass over the header's bottom edge. */
@starting-style{.nav-group-panel{opacity:0}}
.nav-group-panel a{display:flex;align-items:center;gap:var(--space-sm);min-block-size:44px;padding-inline:var(--space-sm);border-radius:var(--radius-sm);color:var(--ink);font-weight:700;white-space:nowrap;transition:background-color .15s,color .15s}
.nav-group-panel .icon{width:20px;height:20px;color:var(--blue)}
.nav-group-panel a:focus-visible{outline-offset:-3px}
.nav-group-panel a[aria-current]{background:var(--ice);color:var(--blue)}
.nav-group-all{margin-block-end:var(--space-xs);padding-block-end:var(--space-xs);border-block-end:1px solid var(--line)}
.nav-group-all a{font-weight:800}
:root[lang=ar] .nav-group-all a{font-weight:700}
.nav-group-all .end-icon{width:18px;height:18px}
@media(hover:hover){
 .nav-group-panel a:hover{background:var(--ice);color:var(--blue)}
}
.menu-toggle{display:none;border:0;background:var(--ice);color:var(--navy);padding:13px;border-radius:4px;width:46px;height:46px}
.menu-toggle span{display:block;background:currentColor;height:2px;width:20px;margin-block:4px;transition:transform .2s}
/* Collapsible menu from 1100 px down (DESIGN-AUDIT §2.2: the menu collapses instead of shrinking its links).
   The breakpoint is 68.75em (1100 px at the default text size) so that it follows the browser text-size setting,
   like the rem nav labels; dist/ui.js uses the same query (MENU_RANGE). ui.js closes the menu when the width
   leaves this range (keyboard focus moves to a visible control), on Escape (focus back on the button), on an
   outside click and on a link click. Without JavaScript the links wrap under the logo. */
@media(max-width:68.75em){
 .header-inner{min-height:80px;flex-wrap:wrap;gap:0}
 .brand{width:202px}
 .js .menu-toggle{display:block}
 #main-nav{width:100%;flex-wrap:wrap;gap:var(--space-xs) var(--space-md);padding-block-end:var(--space-md)}
 .js #main-nav{display:none;position:absolute;inset-inline:0;inset-block-start:100%;width:100%;background:var(--surface);padding-block:var(--space-md) var(--space-lg);padding-inline:var(--space-lg);box-shadow:var(--shadow-panel);flex-direction:column;align-items:stretch;gap:0;border-block-start:1px solid var(--line)}
 .js #main-nav.is-open{display:flex}
 .js #main-nav>a:not(.button){min-height:48px;border-block-end:1px solid var(--line)}
 .js #main-nav>.button{margin-block-start:var(--space-md);justify-content:center}
 /* Services group in the panel: the same button, full width like the links, expands the list in place, indented
    under it; the rows keep their 44 px and wrap if a label ever needs to. */
 .js .nav-group{display:block;position:static}
 .js .nav-group-toggle{display:flex;justify-content:space-between;inline-size:100%;min-block-size:48px;border-block-end:1px solid var(--line);text-align:start}
 /* In the panel, blue marks the current page or section only; an expanded group says so with its chevron. */
 .js .nav-group-toggle[aria-expanded=true]:not(.is-current,:hover){color:inherit}
 .js .nav-group-panel{position:static;inline-size:auto;min-inline-size:0;max-inline-size:none;padding-block:var(--space-2xs) var(--space-xs);padding-inline:var(--space-xs) 0;border:0;border-block-end:1px solid var(--line);border-radius:0;box-shadow:none;transition:none}
 .nav-group-panel a{white-space:normal}
 .menu-toggle[aria-expanded=true] span:first-child{transform:translateY(6px) rotate(45deg)}
 .menu-toggle[aria-expanded=true] span:nth-child(2){opacity:0}
 .menu-toggle[aria-expanded=true] span:last-child{transform:translateY(-6px) rotate(-45deg)}
}
/* Tablet: the panel hangs under the burger at the inline end instead of stretching across the page. */
@media(max-width:68.75em) and (min-width:801px){
 .js #main-nav{inset-inline:auto 0;width:min(100%,380px);border-inline-start:1px solid var(--line);border-end-start-radius:var(--radius)}
}
/* 801 to 1150 px: the step-1 header height (88 px, header bottom at 123 px) with or without the burger, so the frozen
   scroll hero keeps its step-1 offset there too (it moved 8 px up at 801-1100 and 10 px down at 1101-1150). */
@media(min-width:801px) and (max-width:1150px){
 .header-inner{min-height:88px}
}
@media(max-width:800px){
 .utility>.wrap{justify-content:center;min-height:28px}
 .utility>.wrap>span:last-child{display:none}
}
/* Mobile service chip row (DESIGN-AUDIT C11, design spec step-1 §2). A sibling of .site-header, before <main>.
   Shown only at 800 px or less on screens at least 700 px tall, where it takes the utility bar's place: on
   shorter phones the page keeps today's header so the frozen hero does not move (spec §6). A page without the
   row (the scroll hero page, until content/site.cjs flags.chipsAboveScrollHero) keeps its utility bar: only
   .utility.with-chips gives way. No JavaScript: the list scrolls inside the row; the cut last visible chip is
   the scroll cue. Unchanged in step 2 except the tokens. */
.service-chips{display:none;background:var(--surface);padding-block:6px}
.service-chips ul{display:flex;gap:var(--space-xs);margin:0;padding-block:0;padding-inline:20px;list-style:none;overflow-x:auto;overflow-y:hidden;overscroll-behavior-inline:contain;scroll-snap-type:x proximity;scroll-padding-inline:20px;scrollbar-width:none}
.service-chips ul::-webkit-scrollbar{display:none}
.service-chips li{flex:none;scroll-snap-align:start}
/* The current page's chip is the row's first view (design/step-3.md §11 P3, §12 item 7): from the fourth service
   on it started off-screen at 390 px. Browsers without scroll-initial-target keep the row at its start. */
.service-chips li:has(>a[aria-current=page]){scroll-initial-target:nearest}
.service-chips a{display:inline-flex;align-items:center;min-height:44px;padding-inline:16px;border:1px solid var(--line);border-radius:5px;background:var(--ice);color:var(--navy);font-size:var(--text-ui);font-weight:700;line-height:var(--lh-ui);white-space:nowrap;transition:background-color .15s,border-color .15s,color .15s}
.service-chips a:active{background:var(--line)}
.service-chips a:focus-visible{outline:3px solid var(--focus);outline-offset:-4px}
.service-chips a[aria-current=page]{background:var(--navy);border-color:var(--navy);color:#fff}
.service-chips a[aria-current=page]:focus-visible{outline-color:var(--focus-on-strong)}
@media(hover:hover){
 .service-chips a:hover{border-color:var(--blue);color:var(--blue)}
 .service-chips a[aria-current=page]:hover{border-color:var(--navy);color:#fff}
}
@media(max-width:800px) and (min-height:700px){
 .service-chips{display:block}
 .utility.with-chips{display:none}
}
@media print{
 .utility,.menu-toggle,.service-chips{display:none!important}
}
/* 20-hero-photo.css. The shared .hero classes of the frozen scroll hero (lib/sections/hero-scroll.cjs: .hero,
   .hero-content, .hero-copy, .hero .eyebrow, .hero-description, .hero-actions, .hero-secondary, .hero-assurances;
   approved, change only on the owner branch S2-06), then the light hero .hero-service of the service and company
   pages (lib/sections/hero-photo.cjs heroService()), which shares no class with them. The step-2 navy photo hero
   (photo, shade, airflow, caption row and Pause button) is gone (C18, design/step-3.md §3.1). */
.hero{position:relative;min-height:610px;overflow:hidden;background:var(--navy);isolation:isolate;color:#fff;display:flex;align-items:center}
.hero-content{padding-top:66px;padding-bottom:96px}
.hero-copy{max-width:660px}
.hero .eyebrow{display:flex;align-items:center;gap:9px;color:#d5f4fc;font-size:10px;letter-spacing:1.6px}
.hero .eyebrow>span{display:inline-block;width:24px;height:2px;background:var(--cyan)}
.hero-description{max-width:510px;font-size:16px;line-height:1.8;color:#e1edf4}
.hero-actions{display:flex;align-items:center;gap:26px;flex-wrap:wrap;margin-top:30px}
.hero-secondary{display:inline-flex;align-items:center;gap:10px;min-height:44px;font-size:13px;font-weight:700;color:#fff}
.hero-secondary .icon{width:18px;height:18px}
.hero-secondary:hover{text-decoration:underline;text-underline-offset:4px}
.hero-assurances{display:flex;gap:25px;flex-wrap:wrap;font-size:12px;color:#e1edf4;margin-top:27px}
.hero-assurances span{display:flex;align-items:center;gap:8px}
.hero-assurances .icon{color:#74d6e8;width:17px;height:17px}
@media(min-width:1600px){
 .hero{min-height:640px}
}
@media(max-width:1150px){
 .hero{min-height:590px}
 .hero-copy{max-width:620px}
}
@media(max-width:1000px) and (min-width:801px){
 .hero-copy{max-width:600px}
}
@media(max-width:800px){
 .hero{min-height:580px}
 .hero-content{padding-block:52px 76px}
 .hero-copy{max-width:530px}
 .hero-description{font-size:15px;max-width:440px}
 .hero .eyebrow{font-size:9px}
 .hero-actions{gap:14px 22px;margin-top:25px}
 .hero-assurances{gap:17px;font-size:11px}
}
@media(max-width:560px){
 .hero{min-height:617px;align-items:flex-start}
 .hero-content{padding-top:42px;padding-bottom:91px}
 .hero-description{font-size:14px;line-height:1.85;max-width:350px}
 .hero .eyebrow{font-size:8px;letter-spacing:1.15px;gap:7px;margin-bottom:21px}
 .hero .eyebrow>span{width:15px}
 .hero-actions{align-items:flex-start;flex-direction:column;gap:10px;margin-top:25px}
 .hero .button{padding:15px 17px;min-height:52px;font-size:12px}
 /* Logical conversion only (ARCHITECTURE §5.5): same 10px gap in LTR, mirrors for step 5 without a [dir=rtl]
    override. Not a redesign of the frozen shared .hero rules above (S2-06 still owns their visual values). */
 .hero .button .end-icon{margin-inline-start:10px}
 .hero-secondary{font-size:12px}
 .hero-assurances{margin-top:19px;gap:11px;font-size:9px}
 .hero-assurances .icon{width:15px;height:15px}
}
@media print{
 .hero{min-height:450px}
}
/* ---- Light service hero (.hero-service), step 3 (design/step-3.md §3.1, Appendix A.2) ----
   Its own class family: the root is not a .hero, so none of the shared .hero* rules above (frozen scroll hero)
   reach it, and nothing here reaches the scroll hero. Ice surface, copy at the inline start, framed media at the
   inline end (a real photo, or an illustration in a white frame). No airflow, no pause button, no overlay.
   Company pages (design/step-4.md §1.6) may add one eyebrow after the breadcrumb (base .eyebrow, no rule here).
   The compact variant (.hero-service.hero-compact, the Contact page) is sized in 47-contact.css (design/step-4.md
   A.2); the renderer loads its photo lazily, so the picture hidden at 800 px and below is never fetched. */
.hero-service{background:var(--surface-alt);padding-block:var(--section-y-tight)}
.hero-service-grid{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);align-items:center;gap:var(--space-xl) var(--gap-split)}
.hero-service-copy{min-inline-size:0}
.hero-service .breadcrumb{margin-block:calc(-1 * var(--space-sm)) var(--space-sm)}
.hero-service h1{margin-block-end:0;max-inline-size:13em}
.hero-service-lead{margin-block-start:var(--stack-text);max-inline-size:34rem;font-size:var(--text-lead);line-height:var(--lh-lead)}
.hero-service-actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-sm) var(--space-lg);margin-block-start:var(--space-xl)}
/* The soft shadow of the home hero's primary button (80-hero-scroll.css), so both heroes' main actions match. */
.hero-service-actions .button-primary{box-shadow:0 10px 24px rgb(0 104 176 / .18)}
/* Assurances are short UI labels (15 px), not running text: spans in a div, as in the step-2 hero (a <li> would
   make them running text for type.cjs body-text-size, 16 px minimum above 800 px). */
.hero-service-assurances{display:flex;flex-wrap:wrap;gap:var(--space-xs) var(--space-lg);margin-block-start:var(--space-lg);font-size:var(--text-ui);line-height:var(--lh-ui);color:var(--ink)}
.hero-service-assurances>span{display:flex;align-items:center;gap:var(--space-xs)}
.hero-service-assurances .icon{inline-size:18px;block-size:18px;color:var(--blue)}
.hero-media{margin:0;min-inline-size:0}
.hero-media>img,.hero-art{display:block;inline-size:100%;block-size:auto;aspect-ratio:4/3;object-fit:cover;border-radius:var(--radius)}
.hero-art{background:var(--surface);border:1px solid var(--line);overflow:hidden}
.hero-art>svg{inline-size:100%;block-size:100%}
.hero-media figcaption{margin-block-start:var(--space-sm);font-size:var(--text-caption);line-height:var(--lh-caption);color:var(--muted)}
.hero-media .is-team{font-weight:800;line-height:var(--lh-caps);letter-spacing:var(--track-caps)}
:root[lang=ar] .hero-media .is-team{font-weight:700}
@media(max-width:800px){
 .hero-service-grid{grid-template-columns:minmax(0,1fr)}
 .hero-media{max-inline-size:32rem}
}
@media(max-width:560px){
 .hero-service-actions{flex-direction:column;align-items:flex-start}
 .hero-media>img,.hero-art{aspect-ratio:3/2}
}
/* 30-services.css. Services grid of the home page (lib/sections/services-grid.cjs, design/step-2.md §5.1). Vertical
   padding: 01-base (--section-y-tight on top). Type from the tokens only; media queries change layout. */
/* The white Why band ends with its Pause control, not with a card: a 1 px line marks where it stops (§3.1). */
.services{border-block-start:1px solid var(--line)}
.service-gallery{display:grid;grid-template-columns:1.22fr 1fr 1fr;gap:var(--space-lg)}
.service-card{min-width:0}
.service-image{height:255px;position:relative;overflow:hidden;border-radius:var(--radius)}
.service-image img{width:100%;height:100%;object-fit:cover;transition:transform .45s}
.service-featured .service-image img{object-position:50% 33%}
#home-cleaning .service-image img{object-position:50% 36%}
.service-card:hover .service-image img{transform:scale(1.025)}
.service-content{padding-block-start:var(--space-lg)}
.service-content h3{margin-block-end:var(--space-xs)}
.service-content p{max-inline-size:40ch}
/* Service links flow as text: when a label wraps, the arrow follows its last word instead of the column edge. */
/* align-content and the icons' block margin belong to the base grid row (01-base.css): reset for this inline flow. */
.services .text-link{display:inline-block;align-content:normal;min-height:44px;padding-block:12px;padding-inline-end:22px;margin-block-start:var(--space-2xs)}
.services .text-link .icon{display:inline-block;vertical-align:-4px;margin-block-start:0}
.services .text-link .icon:first-child:not(:last-child){margin-inline-end:var(--space-xs)}
/* The arrow hangs in the 22 px end padding (net advance 0), so it never wraps alone onto a new line. */
.services .text-link .icon:last-child{margin-inline-start:var(--space-2xs);margin-inline-end:-22px}
/* Mini grid (services without a photo): 24 px icon | title, copy and link. 4 columns, 2 up to 1100 px, 1 at 560. */
.service-additional{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--space-xl) var(--space-lg);padding-block-start:var(--space-xl);margin-block-start:var(--space-xl);border-block-start:1px solid var(--line)}
.service-additional article{display:grid;grid-template-columns:24px minmax(0,1fr);column-gap:var(--space-sm);align-content:start;min-width:0;scroll-margin-block-start:36px}
.service-additional>article>.icon{width:24px;height:24px;color:var(--blue);margin-block-start:2px}
.service-additional h3{font-size:var(--text-lead);line-height:1.4;letter-spacing:0}
.service-additional p{margin-block-start:var(--space-2xs)}
/* The WhatsApp icon only (a page link's single icon is its arrow and stays). */
.service-additional .text-link .icon:first-child:not(:last-child){display:none}
@media(max-width:1150px){
 .service-image{height:235px}
}
@media(max-width:1100px){
 .service-additional{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:800px){
 .service-gallery{grid-template-columns:1.1fr 1fr 1fr;gap:var(--space-md)}
 .service-image{height:200px}
 .service-content{padding-block-start:var(--space-md)}
 .service-content .text-link .icon:first-child:not(:last-child){display:none}
}
/* Up to 720 px (phones, and a 1280 px window at 200 % zoom) three columns get too narrow for 16 px text: the
   featured card spans the width and the others become rows, photo | text. */
@media(max-width:720px){
 .service-gallery{display:flex;flex-direction:column;gap:var(--space-lg)}
 .service-card{display:grid;grid-template-columns:112px minmax(0,1fr);gap:var(--space-md)}
 .service-featured{display:block}
 .service-image{height:156px}
 .service-featured .service-image{height:220px}
 .service-content{padding-block-start:0}
 .service-featured .service-content{padding-block-start:var(--space-md)}
}
@media(max-width:560px){
 .service-additional{grid-template-columns:minmax(0,1fr);gap:var(--space-md)}
}
@media(prefers-reduced-motion:reduce){
 .service-card:hover .service-image img{transform:none}
}
/* 31-packages.css. Packages, #packages (lib/sections/packages.cjs, design/step-2.md §5.2). Ice section, white cards,
   navy Premium card. Type from the base and the tokens only; media queries change layout. */
.pricing{background:var(--surface-alt)}
.package-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-lg);align-items:stretch}
.package{display:flex;flex-direction:column;min-width:0;padding-block:var(--space-xl);padding-inline:var(--space-lg);background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);transition:box-shadow .2s}
.package:hover{box-shadow:0 12px 26px #0b25450b}
/* Name (base h3) and badge; the row wraps instead of reserving a fixed height. */
.package-label{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:var(--space-xs) var(--space-sm);margin-block-end:var(--space-2xs)}
.package-label>span{padding-block:var(--space-2xs);padding-inline:var(--space-xs);border-radius:var(--radius-sm);background:var(--ice);color:var(--blue);font-size:var(--text-caption);font-weight:700;line-height:var(--lh-caption)}
.package>.button{margin-block-start:var(--space-lg);width:100%;min-height:48px;padding-block:var(--space-sm);padding-inline:var(--space-md);justify-content:flex-start}
.package>.button .end-icon{margin-inline-start:auto}
.feature-list{list-style:none;display:flex;flex-direction:column;gap:var(--space-sm);margin:0;margin-block-start:var(--space-lg);padding:0;padding-block-start:var(--space-lg);border-block-start:1px solid var(--line)}
.feature-list li{display:flex;gap:var(--space-xs)}
.feature-list .icon{width:16px;height:16px;margin-block-start:var(--space-2xs);color:var(--blue)}
.scope-note{margin-block-start:auto;padding-block-start:var(--space-md);border-block-start:1px solid var(--line)}
/* The note is pinned to the bottom (margin-block-start:auto) and never closer than 24 px to the last feature, even
   in the tallest card, where auto resolves to 0. The list is the last child when a card has no note. */
.package .feature-list:not(:last-child){margin-block-end:var(--space-lg)}
.package-featured{background:var(--surface-strong);color:#fff;border-color:var(--surface-strong)}
.package-featured .package-label>span{background:var(--cyan);color:var(--navy)}
.package-featured p{color:var(--ink-on-strong)}
.package-featured li{line-height:var(--lh-body-strong)}
.package-featured .feature-list,.package-featured .scope-note{border-color:var(--line-on-strong)}
.package-featured .feature-list .icon{color:var(--cyan)}
/* "How to get your price" row + AC links (S1-06, design/step-1.md §3.4). Deliberately not aligned with the 3
   package cards above (h3 + 3-column list = 4 columns), so step 1 does not read as "Basic". */
.price-steps{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));column-gap:var(--space-lg);row-gap:var(--space-xl);margin-block-start:var(--space-2xl);padding-block-start:var(--space-xl);border-block-start:1px solid var(--line)}
.price-steps h3{grid-column:1;color:var(--ink)}
.price-steps-list{grid-column:2/-1;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-lg);margin:0;padding:0;list-style:none}
.price-steps-list li{display:grid;grid-template-columns:40px minmax(0,1fr);column-gap:var(--space-md);align-items:start}
.price-step-n{width:40px;height:40px;border-radius:50%;background:var(--surface);border:1px solid var(--line);display:grid;place-items:center;color:var(--blue);font-weight:800;font-size:var(--text-ui);font-variant-numeric:tabular-nums}
:root[lang=ar] .price-step-n{font-weight:700}
.price-steps-list li>div{padding-block-start:var(--space-xs)}
.price-step-title{line-height:1.4;font-weight:700;color:var(--navy)}
.price-steps-list li>div>p:last-child{margin-block-start:var(--space-2xs)}
/* Step 1: "Not sure?" then the 44 px "Ask our team" link on its own line, so the link neither makes the first line
   taller nor sits off its baseline (the three step texts start at the same height). */
.price-steps-list .text-link{display:grid;width:fit-content}
.price-links{grid-column:1/-1;display:flex;flex-wrap:wrap;column-gap:var(--space-xl);margin:0}
@media(max-width:1100px){
 .package-grid{gap:var(--space-md)}
 .package{padding-inline:var(--space-md)}
}
@media(max-width:800px){
 .package-grid{grid-template-columns:minmax(0,40rem)}
 .package{padding-inline:var(--space-lg)}
 .price-steps{display:block;margin-block-start:var(--space-xl);padding-block-start:var(--space-lg)}
 .price-steps-list{grid-template-columns:minmax(0,1fr);margin-block-start:var(--space-md);gap:var(--space-md)}
 .price-links{flex-direction:column;align-items:flex-start;margin-block-start:var(--space-md)}
}
@media(max-width:560px){
 .package{padding-block:var(--space-lg)}
}
@media print{
 .package{break-inside:avoid}
}
/* 33-process.css. Process, #process (lib/sections/process.cjs): the mid-page navy band of every service page
   (design/step-2.md §3.3, §5.4; design/step-3.md §3.8): white and --ink-on-strong text, cyan numbers, 15 % white
   lines. Full variant: phases of numbered steps (AC 4 x 16, pest control 4 x 8), folded by phase on the AC page at
   800 px or less (.is-accordion). Compact variant: 3 to 5 steps (.process-compact). Sizes come from the tokens and
   the base (h2, h3, body); no font size in a media query. */
.process{background:var(--surface-strong);color:#fff}
.process h2,.process h3{color:#fff}
.process .eyebrow{color:var(--cyan)}
.process p,.process li{color:var(--ink-on-strong)}
/* Running text on navy at 1.65. :where() keeps this at 0,0,1 so the roles keep their own line heights here too
   (.eyebrow 1.3, .section-description 1.55): at 0,1,1 it overrode them. */
:where(.process) :is(p,li){line-height:var(--lh-body-strong)}
.process .section-heading>div{max-inline-size:660px}
.process-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--space-xl) var(--space-lg)}
.phase-index{display:flex;align-items:center;gap:var(--space-md);margin-block-end:var(--space-lg)}
.phase-index>span{font-size:var(--text-h3);line-height:var(--lh-h3);font-weight:700;color:var(--cyan);font-variant-numeric:tabular-nums}
/* transform-origin has no logical keyword: step 5 mirrors it in 90-rtl.css (ARCHITECTURE §5.5). */
.phase-index i{display:block;flex:1;height:1px;background:var(--line-on-strong);transform-origin:left}
.process-phase>p{margin-block-start:var(--space-xs)}
.process-phase ol{list-style:none;display:grid;gap:var(--space-sm);margin:0;margin-block-start:var(--space-lg);padding:0}
.process-phase li{display:flex;gap:var(--space-sm)}
.process-phase li>span{flex-shrink:0;padding-block-start:3px;font-size:var(--text-caption);line-height:var(--lh-caption);font-weight:700;color:var(--cyan);font-variant-numeric:tabular-nums}
.process-tail{display:flex;align-items:center;gap:var(--space-sm);margin-block-start:var(--space-xl);padding-block-start:var(--space-lg);border-block-start:1px solid var(--line-on-strong);color:var(--ink-on-strong)}
.process-tail .icon{color:var(--cyan)}
.process-phase.is-visible .phase-index i{animation:draw-line .8s ease both}
.process-phase:nth-child(2) .phase-index i{animation-delay:.1s}
.process-phase:nth-child(3) .phase-index i{animation-delay:.2s}
.process-phase:nth-child(4) .phase-index i{animation-delay:.3s}
@keyframes draw-line{from{transform:scaleX(.25)}to{transform:scaleX(1)}}
@media(max-width:1100px){
 .process-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-2xl) var(--space-lg)}
}
@media(max-width:560px){
 .process-grid{grid-template-columns:minmax(0,1fr);gap:var(--space-xl)}
 .process-phase{display:grid;grid-template-columns:48px minmax(0,1fr);column-gap:var(--space-md)}
 .phase-index{grid-column:1;grid-row:1/4;display:block;margin:0;border-inline-end:1px solid var(--line-on-strong)}
 .phase-index>i{display:none}
 .process-phase h3,.process-phase>p,.process-phase ol{grid-column:2}
 .process-phase ol{margin-block-start:var(--space-md)}
 .process-tail{align-items:flex-start}
}
/* ---- Step 3 additions (design/step-3.md §3.8, Appendix A.4) ----
   Compact process (.process.process-compact): 3 to 5 steps without phases, on the same navy band. A row of
   numbered circles joined by a 1 px line above 1100 px; a vertical timeline at 1100 px or less. The <ol> gives the
   order to assistive technology, so the visible number is aria-hidden. --disc is the circle (compact steps, the
   size of the packages' .price-step-n) and the phase-number column (accordion); every offset below derives from it
   and the spacing tokens. */
.process{--disc:40px}
.steps{display:grid;grid-template-columns:repeat(var(--steps,4),minmax(0,1fr));gap:var(--space-lg);margin:0;padding:0;list-style:none}
.steps[data-steps="3"]{--steps:3}
.steps[data-steps="5"]{--steps:5}
.steps>li{position:relative;min-inline-size:0;padding-block-start:calc(var(--disc) + var(--space-md))}
.step-n{position:absolute;inset-block-start:0;inset-inline-start:0;display:grid;place-items:center;inline-size:var(--disc);block-size:var(--disc);border:1px solid var(--line-on-strong);border-radius:50%;color:var(--cyan);font-size:var(--text-ui);font-weight:800;font-variant-numeric:tabular-nums}
:root[lang=ar] .step-n{font-weight:700}
/* The connector starts 12 px after this circle and stops 12 px before the next one (column gap 24 px). */
.steps>li::before{content:"";position:absolute;inset-block-start:calc(var(--disc) / 2);inset-inline-start:calc(var(--disc) + var(--space-sm));inset-inline-end:calc(var(--space-sm) - var(--space-lg));block-size:1px;background:var(--line-on-strong)}
.steps>li:last-child::before{display:none}
.steps h3{font-size:var(--text-lead);line-height:1.4;letter-spacing:0}
.steps p{margin-block-start:var(--space-xs)}
/* Accordion by phase (.process.is-accordion, AC page, C21): every phase is a <details>, open in the HTML. At 800 px
   or less dist/shared/accordion.js closes all but the first; above, it keeps them open and inert (data-static on
   the phase, the summary out of the tab order). The summary holds the phase number, the name, a step count and a
   chevron; the count and the chevron show at 800 px or less only. */
.process-phase>summary{display:block;list-style:none}
.process-phase>summary::-webkit-details-marker{display:none}
.phase-count,.phase-chevron{display:none}
.phase-count{font-size:var(--text-caption);line-height:var(--lh-caption);color:var(--ink-on-strong)}
.process-phase[data-static]>summary{cursor:default}
@media(max-width:1100px){
 .steps{grid-template-columns:minmax(0,1fr);max-inline-size:40rem;gap:0}
 .steps>li{padding-block:0 var(--space-xl);padding-inline-start:calc(var(--disc) + var(--space-lg))}
 .steps>li:last-child{padding-block-end:0}
 .steps>li::before{inset-block:calc(var(--disc) + var(--space-xs)) var(--space-xs);inset-inline:calc(var(--disc) / 2) auto;inline-size:1px;block-size:auto}
}
@media(max-width:800px){
 .process.is-accordion .process-grid{grid-template-columns:minmax(0,1fr);gap:0;border-block-start:1px solid var(--line-on-strong)}
 .process.is-accordion .process-phase{display:block;border-block-end:1px solid var(--line-on-strong)}
 .process.is-accordion .process-phase>summary{display:grid;grid-template-columns:var(--disc) minmax(0,1fr) 24px;column-gap:var(--space-sm);align-items:center;min-block-size:calc(var(--disc) + 2 * var(--space-md));padding-block:var(--space-md);cursor:pointer}
 .process.is-accordion .phase-index{grid-column:1;grid-row:1/3;display:block;margin:0;border:0}
 .process.is-accordion .phase-index>i{display:none}
 .process.is-accordion .process-phase h3{grid-column:2}
 .process.is-accordion .phase-count{display:block;grid-column:2}
 .process.is-accordion .phase-chevron{display:block;grid-column:3;grid-row:1/3;inline-size:24px;block-size:24px;color:var(--cyan);transition:transform .15s var(--ease-out)}
 .process.is-accordion .process-phase[open] .phase-chevron{transform:rotate(180deg)}
 .process.is-accordion .process-phase>.phase-label{margin:0;padding-inline-start:calc(var(--disc) + var(--space-sm))}
 .process.is-accordion .process-phase ol{margin-block:var(--space-md) 0;padding-block-end:var(--space-lg);padding-inline-start:calc(var(--disc) + var(--space-sm))}
 .process.is-accordion .process-tail{border-block-start:0;padding-block-start:0}
}
@media print{
 .process{background:none;color:var(--ink)}
 .process h2,.process h3,.process p,.process li{color:var(--ink)}
 .process-phase{break-inside:avoid}
}
/* 34-proof.css. Before/after comparison and Service Report, #proof (lib/sections/proof.cjs). White section; the
   report is an ice panel (design/step-2.md §5.5). The comparison geometry stays physical on purpose (forced
   dir=ltr at step 5, ARCHITECTURE §5.5): .comparison-line, .before-label and .after-label are logical-properties
   exceptions (verify/checks/css-lint.cjs). */
.proof .section-heading>div{max-inline-size:720px}
.proof-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--gap-split);align-items:start}
/* Comparison hidden (c.real false): the report panel alone, capped for readability and aligned with the heading
   column at the inline start, like every other block of the page. */
.proof-grid-solo{grid-template-columns:minmax(0,1fr)}
.proof-grid-solo .report-panel{max-inline-size:40rem}
.comparison{min-width:0}
.comparison-canvas{position:relative;width:100%;aspect-ratio:600/320;overflow:hidden;border-radius:var(--radius);background:var(--ice)}
.comparison-before,.comparison-after{position:absolute;inset:0}
/* The "after" (clean) layer is revealed from the right edge as --reveal grows, so the default 50%
   keeps Before (dirty, background layer) on the left and After (clean) on the right, reading order.
   The range runs right to left (direction:rtl below), so its thumb moves the same way as the divider, while
   the value stays the clean share that aria-valuetext announces (interactions.js).
   Step 5 (RTL pages): mirror the labels and the reveal edge together with this. */
.comparison-after{clip-path:inset(0 0 0 calc(100% - var(--reveal,50%)))}
.comparison-canvas svg{width:100%;height:100%}
.comparison-line{position:absolute;inset-block:0;left:calc(100% - var(--reveal,50%));width:2px;background:white;box-shadow:0 0 8px #0003}
.comparison-line:after{content:'↔';display:grid;place-items:center;position:absolute;top:50%;left:0;transform:translate(-50%,-50%);width:38px;height:38px;background:white;border-radius:50%;color:var(--blue);font-size:20px;box-shadow:0 4px 12px #0002}
.comparison-label{position:absolute;inset-block-start:14px;padding-block:var(--space-2xs);padding-inline:var(--space-xs);border-radius:var(--radius-sm);background:var(--surface);font-size:var(--text-caption);line-height:var(--lh-caption);font-weight:700}
.before-label{left:14px}
.after-label{right:14px}
.comparison-control{display:flex;gap:var(--space-md);align-items:center;padding-block:var(--space-md) var(--space-xs)}
.comparison-control label{font-size:var(--text-ui);font-weight:700}
.comparison-control input{min-inline-size:80px;flex:1;min-block-size:44px;accent-color:var(--blue);direction:rtl}
.comparison figcaption{max-inline-size:480px;color:var(--muted)}
.report-panel{padding:var(--space-xl);border-radius:var(--radius);background:var(--surface-alt)}
.report-title{display:flex;align-items:center;gap:var(--space-xs);margin-block-end:var(--space-md);color:var(--blue);font-size:var(--text-caption);line-height:var(--lh-caps);font-weight:800;letter-spacing:var(--track-caps)}
:root[lang=ar] .report-title{font-weight:700}
.report-title .icon{width:18px;height:18px}
.report-panel>p:not(.report-note){margin-block-start:var(--space-xs)}
/* Icon | title and text | scope tag. The tag stays visible at every width; at 560 px and below it moves under the text. */
.report-row{display:grid;grid-template-columns:20px minmax(0,1fr) auto;align-items:start;gap:var(--space-xs) var(--space-sm);margin-block-start:var(--space-md);padding-block-start:var(--space-md);border-block-start:1px solid var(--line)}
.report-row>.icon{width:20px;height:20px;margin-block-start:3px;color:var(--blue)}
.report-row strong{display:block;font-weight:700;color:var(--ink)}
.report-row span{display:block;margin-block-start:var(--space-2xs);color:var(--muted)}
.report-row small{justify-self:end;padding-block:var(--space-2xs);padding-inline:var(--space-xs);border-radius:var(--radius-sm);background:var(--surface);color:var(--blue);font-size:var(--text-caption);line-height:var(--lh-caption);font-weight:700}
.report-note{margin-block-start:var(--space-lg)}
@media(max-width:800px){
 .proof-grid{grid-template-columns:minmax(0,1fr)}
 .comparison-control{flex-wrap:wrap}
}
@media(max-width:560px){
 .report-panel{padding:var(--space-lg)}
 .report-row{grid-template-columns:20px minmax(0,1fr)}
 .report-row small{grid-column:2;justify-self:start}
}
/* 35-reviews.css. Reviews band (lib/sections/reviews.cjs), rendered only with site.flags.reviewsUrl. White,
   tight rhythm, placed after the packages (ice), no side rule (design/step-2.md §5.8). The h2 and the eyebrow
   come from the base. */
.reviews{padding-block:var(--section-y-tight);background:var(--surface)}
.reviews-inner{display:flex;align-items:center;justify-content:space-between;gap:var(--gap-split)}
.review-placeholder{max-inline-size:28rem;color:var(--ink)}
.review-placeholder span{display:block;margin-block-start:var(--space-2xs);color:var(--muted)}
@media(max-width:800px){
 .reviews-inner{display:block}
 .review-placeholder{margin-block-start:var(--space-md)}
}
/* 37-faq.css. FAQ, #faq (lib/sections/faq.cjs). White section with a 1 px top line (it follows a white or ice
   section); vertical padding: 01-base (--section-y). Questions at lead 700, answers at body (design/step-2.md §5.6). */
.faq{background:var(--surface);border-block-start:1px solid var(--line)}
.faq-grid{display:grid;grid-template-columns:.8fr 1.2fr;gap:var(--gap-split)}
.faq-grid>div:first-child>p{margin-block-start:var(--stack-text);font-size:var(--text-lead);line-height:var(--lh-lead)}
.faq-grid .text-link{margin-block-start:var(--space-md)}
.faq-list{border-block-start:1px solid var(--line)}
.faq details{border-block-end:1px solid var(--line)}
.faq summary{list-style:none;display:flex;justify-content:space-between;align-items:center;gap:var(--space-md);cursor:pointer;padding-block:var(--space-md);font-size:var(--text-lead);line-height:1.4;font-weight:700;color:var(--ink)}
.faq summary::-webkit-details-marker{display:none}
.faq-plus{position:relative;width:14px;height:14px;flex-shrink:0;color:var(--blue)}
.faq-plus:before,.faq-plus:after{content:'';position:absolute;background:currentColor;width:12px;height:1.5px;inset-block-start:6px;inset-inline-start:1px}
.faq-plus:after{transform:rotate(90deg)}
.faq [open] .faq-plus:after{transform:rotate(0)}
.faq details>p{padding-block-end:var(--space-lg);padding-inline-end:var(--space-xl)}
@media(max-width:800px){
 .faq-grid{display:block}
 .faq-list{margin-block-start:var(--space-xl)}
 .faq details>p{padding-inline-end:var(--space-md)}
}
/* 38-intro-split.css. Text and visual split, .ac-intro (lib/sections/intro-split.cjs), the second section of a
   service page. White section; the visual is the AC page's duct panel, a named 4:3 illustration panel with a key
   or a compare legend (design/step-3.md §3.7, Appendix A.7), or a list panel (.list-panel, 45-lists.css).
   Vertical padding: 01-base (--section-y). The key is a caption-role legend (13 px, 700) and the illustration note
   or figcaption a caption (13 px, 400), design/step-2.md §5.7. */
.ac-intro-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--gap-split);align-items:center}
.ac-intro-grid>div:first-child>p:not(.eyebrow){margin-block-start:var(--stack-text);max-inline-size:34rem;font-size:var(--text-lead);line-height:var(--lh-lead)}
.ac-intro .text-link{margin-block-start:var(--space-md)}
.system-visual{border-radius:var(--radius);background:var(--surface-alt);overflow:hidden;padding-block-end:var(--space-md)}
.system-duct{max-height:235px;overflow:hidden}
.system-duct svg{width:100%;height:250px}
.system-key{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--space-xs) var(--space-md);padding-inline:var(--space-md);font-size:var(--text-caption);line-height:var(--lh-caption);font-weight:700;color:var(--ink)}
.system-key span{display:flex;align-items:center;gap:6px}
.system-key .icon{width:16px;height:16px;color:var(--blue)}
.system-visual>:is(p,figcaption){margin-block-start:var(--space-sm);margin-inline:auto;padding-inline:var(--space-md);text-align:center;font-size:var(--text-caption);line-height:var(--lh-caption);color:var(--muted)}
@media(max-width:800px){
 .ac-intro-grid{display:block}
 .system-visual,.ac-intro-grid>.list-panel{margin-block-start:var(--space-xl)}
 .system-duct{max-height:200px}
 .system-duct svg{height:215px}
}
/* ---- Step 3: named 4:3 illustrations with a key or a compare legend (design/step-3.md §3.7, Appendix A.7) ----
   Scoped to the new .system-art panel, so the AC page's duct visual (.system-duct + .system-key) keeps its step-2
   spacing (an unscoped ".system-visual > .system-key" rule measured +16 px on the AC intro). The legend is the
   .feature-columns.is-compare block of 45-lists.css, inset in the ice panel. */
.system-art{aspect-ratio:4/3}
.system-art>svg{display:block;inline-size:100%;block-size:100%}
.system-art+.system-key{margin-block-start:var(--space-md)}
.system-art~.feature-columns{padding-block-start:var(--space-lg);padding-inline:var(--space-lg)}
/* 39-team.css. Local team band, #team (lib/sections/team.cjs, S1-05, DESIGN-AUDIT C8,
   design spec docs/phase-3/design/step-1.md §1). Navy surface with the photo under a navy veil; the text
   sits on the physical right on desktop (the technicians are left of centre) and under a photo strip on mobile.
   Video variant (.is-video, owner decision 28 Sep 2026 21:40): no photo and no veil, solid navy, the real-team clip
   in a 4:5 frame in the free column (block at the end of this file).
   Spacing, type and colours from the step-2 tokens (S2-03, design/step-2.md §5.3). Media queries change layout and
   display only.
   Physical exceptions (spec §1.9): the desktop veil stays at 90deg and, in RTL, the text column stays on the
   right, because the photo is never mirrored (the logo on the uniform would read backwards). The same holds for
   the clip: its frame stays on the physical left of the text in both directions. */
.team{position:relative;isolation:isolate;overflow:hidden;background:var(--navy);color:#fff;padding-block:var(--section-y-loose)}
.team-media{position:absolute;inset:0;z-index:-1}
.team-media img{width:100%;height:100%;object-fit:cover;object-position:50% 20%}
.team-media::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg, rgb(11 37 69 / .70) 0%, rgb(11 37 69 / .70) 30%, rgb(11 37 69 / .85) 52%, rgb(11 37 69 / .85) 100%)}
.team-inner{display:grid;grid-template-columns:minmax(0, 1fr) min(520px, 45%)}
.team-body{grid-column:2;display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-xl)}
.team-title{margin:0;color:#fff;text-wrap:balance}
.team-facts{display:grid;gap:var(--space-sm);margin:0;padding:0;list-style:none}
.team-facts li{display:flex;gap:var(--space-sm);font-size:var(--text-body);line-height:var(--lh-body-strong);font-weight:400;color:var(--ink-on-strong)}
.team-facts .icon{width:20px;height:20px;margin-block-start:3px;color:var(--cyan)}
/* Secondary action: outline button on navy (cyan stays for the primary WhatsApp buttons). Base .button size. */
.team-cta{background:transparent;border-color:var(--ink-on-strong);color:#fff}
.team-cta .icon{transition:color .18s}
.team-cta .icon:first-child{color:var(--cyan)}
@media (hover:hover){
 .team-cta:hover{background:#fff;color:var(--navy)}
 .team-cta:hover .icon{color:var(--navy)}
}
.team-cta:active{background:var(--ink-on-strong);color:var(--navy)}
.team-cta:active .icon{color:var(--navy)}
.team :focus-visible{outline-color:var(--focus-on-strong)}
[dir=rtl] .team-inner{grid-template-columns:min(520px, 45%) minmax(0, 1fr)}
[dir=rtl] .team-body{grid-column:1}
@media (max-width:800px){
 .team-media{inset:0 0 auto;height:clamp(220px, 56vw, 320px)}
 .team-media img{object-position:40% 25%}
 .team-media::after{background:linear-gradient(180deg, rgb(11 37 69 / .70) 0%, rgb(11 37 69 / .70) 45%, rgb(11 37 69 / .90) 80%, var(--navy) 100%)}
 .team-inner{display:block}
 /* The heading starts 32 px above the bottom of the strip, over the >= 90 % part of its veil. */
 .team-body{gap:var(--space-lg);margin-block-start:calc(clamp(220px, 56vw, 320px) - 32px - var(--section-y-loose))}
}
@media (max-width:560px){
 .team-hours .team-sep{display:none}
 .team-hours>span>span:not(.team-sep){display:block}
}
/* Video variant. The frame is centred in the free column (the photo variant's empty side), the text column keeps
   its place, size and content, and both are centred on each other vertically. --gap-split keeps the frame off the
   text at 801 px, where the free column is narrowest. The <button> has no chrome of its own: the video carries the
   radius, a placeholder tint until the poster decodes, and a soft shadow in a deeper navy (a navy shadow would not
   show on the navy band); the button only shows the on-navy focus ring, on keyboard focus (01-base.css
   :focus-visible, .team :focus-visible). Without JavaScript the button would do nothing, so it is hidden and the
   video, visible inside it, is a still poster (the same rule as the Why band's Pause button, 81-why-band.css). */
.team.is-video .team-inner{column-gap:var(--gap-split);align-items:center}
.team-video-toggle{grid-column:1;grid-row:1;justify-self:center;display:block;inline-size:min(100%, 360px);padding:0;border:0;border-radius:var(--radius);background:none;color:inherit}
.team.is-video .team-body{grid-row:1}
.team-video{display:block;inline-size:100%;block-size:auto;aspect-ratio:4 / 5;object-fit:cover;border-radius:var(--radius);background:var(--line-on-strong);box-shadow:0 2px 6px rgb(4 13 24 / .35),0 24px 48px -16px rgb(4 13 24 / .7)}
html:not(.js) .team-video-toggle{visibility:hidden}
html:not(.js) .team-video{visibility:visible}
/* RTL: the free column is the grid's second track, on the physical left (never mirrored, spec §1.9). */
[dir=rtl] .team-video-toggle{grid-column:2}
@media (max-width:800px){
 /* The frame above the text, at the inline start like the text. */
 .team.is-video .team-inner{display:flex;flex-direction:column;align-items:stretch;gap:var(--space-xl)}
 .team.is-video .team-body{margin-block-start:0}
 .team-video-toggle{align-self:flex-start;inline-size:min(100%, 320px)}
}
@media (forced-colors:active){
 .team-media,.team-video-toggle{display:none}
}
@media print{
 .team{background:none;color:var(--ink);padding-block:30px}
 .team-media,.team-video-toggle{display:none}
 .team-inner{display:block}
 .team-body{margin-block-start:0}
 .team-title,.team-facts li,.team-cta{color:var(--ink)}
 .team-cta{border-color:var(--ink)}
}
/* 40-closing.css. Closing band, #contact (lib/layout/closing.cjs): the top of the navy closing + footer block
   (design/step-2.md §4.4, DESIGN-AUDIT C15). The cyan WhatsApp button sits on navy at 7.05:1 (it was 2.67:1 on
   blue); secondary text is --ink-on-strong (13.03:1). The end padding is 0: the footer continues the same navy
   surface under a 1 px line. Sizes come from the tokens only, never from a media query. */
.closing{background:var(--surface-strong);color:#fff;padding-block:var(--section-y-tight) 0}
.closing-inner{display:flex;justify-content:space-between;align-items:center;gap:var(--gap-split);padding-block-end:var(--space-2xl)}
.closing-inner>div:first-child{max-inline-size:44rem}
.closing h2{color:#fff}
.closing p{margin-block-start:var(--stack-text);font-size:var(--text-lead);line-height:var(--lh-body-strong);color:var(--ink-on-strong)}
.closing-inner>div:last-child{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-xs);flex-shrink:0}
.closing-call{display:inline-flex;align-items:center;gap:var(--space-xs);min-block-size:44px;font-size:var(--text-ui);font-weight:700;line-height:var(--lh-ui);color:#fff}
.closing-call .icon{width:18px;height:18px;color:var(--cyan)}
.closing-call:hover{text-decoration:underline;text-underline-offset:5px}
.hours{font-size:var(--text-caption);line-height:var(--lh-caption);color:var(--ink-on-strong)}
@media(max-width:800px){
 .closing-inner{display:block}
 .closing-inner>div:last-child{margin-block-start:var(--space-xl)}
}
/* Print: browsers drop backgrounds, so the text on navy goes back to ink. */
@media print{
 .closing{background:none;color:var(--ink)}
 .closing h2,.closing-call{color:var(--ink)}
 .closing p,.hours{color:var(--muted)}
}
/* 41-footer.css. Footer (the bottom of the navy closing + footer block, design/step-2.md §4.4), floating WhatsApp
   button and mobile action bar (lib/layout/footer.cjs). Every link is a 44 px target. The logo sits on a white
   plate so it keeps the owner's colours on navy. The floating button and the mobile bar keep their step-1
   geometry (hero-guard: the bar covers the bottom 66 px of every 390 px hero capture, §4.5). Sizes come from the
   tokens only, never from a media query.
   Columns (PLAN S3-10, S4-09): brand, Services (7 links), Explore (5), Get in touch. Four across above 1100 px; the
   brand on its own row and three columns from 1100 px; two columns at 800 px and below: Services on the start
   side, Explore then Get in touch on the end side (the shortest stack for 12 links of 44 px). */
.footer{background:var(--surface-strong);color:var(--ink-on-strong)}
.footer-grid{display:grid;grid-template-columns:minmax(0,1.2fr) repeat(3,minmax(0,1fr));gap:var(--space-xl) var(--gap-split);padding-block:var(--space-2xl);border-block-start:1px solid var(--line-on-strong)}
/* The rule on top separates the footer from the navy closing band. A page that ends without one (contact, legal
   pages, 404: design/step-4.md decision 1) meets the footer on a light surface, so the rule goes. */
main:not(:has(> .closing)) + .footer .footer-grid{border-block-start:0}
.footer-logo{display:inline-block;padding-block:var(--space-sm);padding-inline:var(--space-md);margin-block-end:var(--space-md);background:var(--surface);border-radius:var(--radius)}
.footer-logo img{width:200px}
.footer p{font-size:var(--text-body);line-height:var(--lh-body-strong);color:var(--ink-on-strong);max-inline-size:34ch}
.footer h3{font-size:var(--text-body);line-height:var(--lh-ui);letter-spacing:0;color:#fff;margin-block-end:var(--space-xs)}
.footer-grid>div>a:not(.footer-logo){display:flex;align-items:center;inline-size:fit-content;min-inline-size:44px;min-block-size:44px;font-size:var(--text-ui);line-height:var(--lh-ui);color:var(--ink-on-strong)}
.footer-grid>div>a:not(.footer-logo):hover,.footer-bottom a:hover{color:#fff;text-decoration:underline;text-underline-offset:5px}
.footer-bottom{display:flex;align-items:center;flex-wrap:wrap;column-gap:var(--space-lg);min-block-size:68px;padding-block:var(--space-sm);border-block-start:1px solid var(--line-on-strong);font-size:var(--text-caption);line-height:var(--lh-caption);color:var(--ink-on-strong)}
.footer-bottom>span:first-child{margin-inline-end:auto}
.footer-bottom a{display:inline-flex;align-items:center;min-block-size:44px;color:#fff;font-weight:700}
/* Language switcher link (design/step-5.md §3.2): 44 px tall like the other bottom-row links, and at least 44 px wide
   ("العربية" is 29 px wide at 13 px): 10 px of inline padding widen its box, the same negative margin gives the space
   back, so the row lays out and draws exactly as without it. */
.footer-bottom .lang-switch a{padding-inline:10px;margin-inline:-10px}
.preview-label{padding-block:var(--space-2xs);padding-inline:var(--space-xs);border-radius:var(--radius-sm);background:rgb(255 255 255 / .1);color:#fff}
.floating-wa{position:fixed;inset-inline-end:24px;inset-block-end:24px;z-index:50;display:grid;place-items:center;width:52px;height:52px;border-radius:50%;background:#0b7951;color:white;box-shadow:0 4px 20px #0b25452b;border:3px solid white}
.floating-wa .icon{width:27px;height:27px}
.floating-wa:hover{background:#07633f}
.mobile-actions{display:none}
/* The bar's label size sits outside the media query (no font size in a media query); its layout stays inside. */
.mobile-actions>a{font-size:var(--text-ui);font-weight:800;line-height:var(--lh-ui)}
:root[lang=ar] .mobile-actions>a{font-weight:700}
@media(max-width:1100px){
 .footer-grid{grid-template-columns:repeat(3,minmax(0,1fr))}
 .footer-brand{grid-column:1/-1}
}
@media(max-width:800px){
 .footer-grid{grid-template-columns:repeat(2,minmax(0,1fr));grid-template-areas:"brand brand" "services explore" "services contact";column-gap:var(--space-lg);padding-block:var(--space-xl)}
 .footer-brand{grid-area:brand}
 .footer-services{grid-area:services}
 .footer-explore{grid-area:explore}
 .footer-contact{grid-area:contact}
 .footer-bottom>span:first-child{inline-size:100%;padding-block-start:var(--space-xs)}
 .floating-wa{display:none}
 .mobile-actions{display:grid;grid-template-columns:.8fr 1.4fr;position:fixed;inset-block-end:0;inset-inline:0;z-index:60;padding-block:9px calc(9px + env(safe-area-inset-bottom,0px));padding-inline:var(--space-md);background:var(--surface);border-block-start:1px solid var(--line);gap:10px;box-shadow:0 -3px 20px #0b25450d}
 .mobile-actions>a{display:flex;justify-content:center;align-items:center;gap:9px;min-height:47px;border:1px solid #c5dbe7;border-radius:4px}
 .mobile-actions .mobile-whatsapp{background:var(--blue);color:#fff;border-color:var(--blue)}
 .mobile-actions .end-icon{display:none}
 .mobile-actions .icon{width:20px;height:20px}
}
/* Print: browsers drop backgrounds, so the text on navy goes back to ink (the address and phone stay legible). */
@media print{
 .mobile-actions,.floating-wa{display:none!important}
 .footer{background:none;color:var(--ink)}
 .footer h3,.footer-bottom a,.preview-label{color:var(--ink)}
 .footer p,.footer-grid>div>a:not(.footer-logo),.footer-bottom{color:var(--muted)}
 .footer-grid,.footer-bottom{border-color:var(--line)}
}
/* 42-related.css. Related services, #related (lib/sections/related-services.cjs, S1-10, DESIGN-AUDIT C9,
   design spec docs/phase-3/design/step-1.md §4). Ice section, three white cards; each card's single link is
   stretched over the card (::after), so the whole card is clickable. Three columns above 1100 px, one column
   below; a card at least 560 px wide lays out as a row (icon | title and copy | action).
   Spacing, surfaces and colours from the step-2 tokens; the card title and copy take the base h3 and body sizes
   (S2-03, design/step-2.md §5.3). Media and container queries change layout and display only; logical
   properties throughout. */
.related{background:var(--surface-alt);padding-block:var(--section-y)}
.related h2{margin-block-end:var(--stack-heading)}
.related-grid{display:grid;grid-template-columns:minmax(0, 1fr);gap:var(--space-sm);margin:0;padding:0;list-style:none}
.related-grid>li{container-type:inline-size}
/* Rows: title, copy (takes the free height), action. In the 3-column row the cards share one height, so every
   action sits at the bottom of its card, on one line across the three. */
.related-card{position:relative;height:100%;display:grid;grid-template-columns:24px minmax(0, 1fr);grid-template-rows:auto 1fr auto;column-gap:var(--space-sm);align-content:start;padding:var(--space-lg);background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);transition:border-color .15s}
.related-card>.icon{width:24px;height:24px;margin-block-start:3px;color:var(--blue)}
.related-card h3{color:var(--ink)}
.related-card p{grid-column:2;align-self:start;margin-block-start:var(--space-xs);color:var(--muted)}
.related-card .text-link{grid-column:2;justify-self:start;margin-block-start:var(--space-xs)}
/* Stretched link: the link's hit area covers the whole card. */
.related-card .text-link::after{content:"";position:absolute;inset:0;border-radius:inherit}
@media (hover:hover){
 .related-card:hover{border-color:var(--blue)}
}
.related-card:active{border-color:var(--navy)}
/* Focus ring on the card rather than on the (stretched) link. Without :has(), the link keeps its own ring. */
@supports selector(:has(*)){
 .related-card:has(.text-link:focus-visible){outline:3px solid var(--focus);outline-offset:4px}
 .related-card .text-link:focus-visible{outline:none}
}
/* Row variant for a wide single-column card (tablet widths): the action moves beside the text. */
@container (min-width:560px){
 .related-card{grid-template-columns:24px minmax(0, 1fr) auto;align-items:center}
 .related-card>.icon{align-self:start}
 .related-card .text-link{grid-column:3;grid-row:1 / span 2;margin:0}
}
@media (min-width:1101px){
 .related-grid{grid-template-columns:repeat(3, minmax(0, 1fr));gap:var(--space-lg)}
}
@media (max-width:560px){
 .related-card{padding:20px}
}
@media (forced-colors:active){
 .related-card:has(.text-link:focus-visible){outline-color:Highlight}
}
@media print{
 .related{background:none;padding-block:30px}
 .related-card .text-link::after{content:none}
}
/* 43-breadcrumb.css. Breadcrumb (lib/sections/breadcrumb.cjs), in the eyebrow slot of the light hero and in the legal
   page head (design/step-3.md §3.2 and A.3). Sentence case, caption size; each link is a 44 x 44 target whose extra
   width is taken back with a negative margin, so the text keeps its rhythm. The current page is a span.text-caption
   (a caption role for verify type.cjs body-text-size), never a link. The separator is a neutral slash drawn in CSS: it
   needs no mirroring in RTL, and the empty alternative text of `content` keeps it out of the accessibility tree (the
   plain declaration before it is the fallback for a browser without that syntax). */
.breadcrumb ol{display:flex;flex-wrap:wrap;align-items:center;margin:0;padding:0;list-style:none;font-size:var(--text-caption);line-height:var(--lh-caption);color:var(--muted)}
.breadcrumb li{display:flex;align-items:center;min-inline-size:0}
.breadcrumb li+li::before{content:"/";content:"/" / "";padding-inline:var(--space-xs);color:var(--muted)}
.breadcrumb a{display:inline-flex;align-items:center;justify-content:center;min-block-size:44px;min-inline-size:44px;padding-inline:var(--space-2xs);margin-inline:calc(-1 * var(--space-2xs));color:var(--blue);font-weight:700}
.breadcrumb a:hover{text-decoration:underline;text-underline-offset:4px}
.breadcrumb [aria-current]{padding-block:var(--space-sm)}
/* 44-cards.css. Card grids of the service pages (lib/sections/cards.cjs, S3-01b; design/step-3.md §3.3, §3.4,
   §3.11, Appendix A.5). Values as measured in the spec; min-width, min-height, width and height are written as
   their logical twins.
   Icon cards: a tile per case (symptom, pest, property type, surface), icon | title, copy, optional action.
     On a white section the tile is ice; on an ice section (.is-alt) it is white with a 1 px line.
     With an action, the link is stretched over the tile and the focus ring is drawn on the tile.
   Scope cards: the price-free twin of .package (same padding, line, radius): title (optional icon), optional
     subtitle, check list, optional action pinned to the bottom. Never a badge, never a price. The item cards of
     the furniture page are scope cards with an item icon and an outline WhatsApp button.
   Column count comes from data-cols (2, 3 or 4), set by the renderer from the content or the item count.
   The note under a grid is .cards-note, not .scope-note (the package card's pinned note, with its top rule); its
   in-text links are 01-base.css `p .inline-link`. Font sizes: tokens only, none in a media query. */
.icon-cards,.scope-grid{display:grid;grid-template-columns:repeat(var(--cols,3),minmax(0,1fr));margin:0;padding:0;list-style:none}
.icon-cards{gap:var(--space-md)}
.scope-grid{gap:var(--space-lg)}
:is(.icon-cards,.scope-grid)[data-cols="2"]{--cols:2}
:is(.icon-cards,.scope-grid)[data-cols="4"]{--cols:4}
.icon-cards>li,.scope-grid>li{display:flex;min-inline-size:0}
.icon-cards>li.is-wide{grid-column:1/-1}
/* Rows: title, copy (takes the free height), action. Tiles of one row share a height, so their links line up. */
.icon-card{position:relative;flex:1;display:grid;grid-template-columns:24px minmax(0,1fr);grid-template-rows:auto 1fr auto;column-gap:var(--space-sm);align-content:start;padding:var(--space-lg);background:var(--surface-alt);border:1px solid var(--surface-alt);border-radius:var(--radius);transition:border-color .15s}
.is-alt .icon-card{background:var(--surface);border-color:var(--line)}
.icon-card>.icon{inline-size:24px;block-size:24px;margin-block-start:2px;color:var(--blue)}
.icon-card h3{font-size:var(--text-lead);line-height:1.4;letter-spacing:0;color:var(--ink)}
.icon-card p{grid-column:2;margin-block-start:var(--space-2xs)}
.icon-card .text-link{grid-column:2;justify-self:start;margin-block-start:var(--space-xs)}
/* Stretched link: the link's hit area covers the whole tile. */
.icon-card .text-link::after{content:"";position:absolute;inset:0;border-radius:inherit}
@media(hover:hover){.icon-card:has(.text-link):hover{border-color:var(--blue)}}
.icon-card:has(.text-link):active{border-color:var(--navy)}
/* Focus ring on the tile rather than on the (stretched) link. Without :has(), the link keeps its own ring. */
@supports selector(:has(*)){
 .icon-card:has(.text-link:focus-visible){outline:3px solid var(--focus);outline-offset:4px}
 .icon-card .text-link:focus-visible{outline:none}
}
.scope-card{flex:1;display:flex;flex-direction:column;min-inline-size:0;padding-block:var(--space-xl);padding-inline:var(--space-lg);background:var(--surface);border:1px solid var(--line);border-radius:var(--radius)}
.scope-card-title{display:flex;align-items:center;gap:var(--space-sm)}
.scope-card-title .icon{inline-size:24px;block-size:24px;color:var(--blue)}
.scope-card>p{margin-block-start:var(--space-2xs)}
.scope-card .feature-list{margin-block-start:var(--space-lg)}
/* The action is pinned to the bottom, so the buttons of one row line up whatever the list lengths. */
.scope-action{margin-block-start:auto;padding-block-start:var(--space-lg)}
.scope-action .button{inline-size:100%;min-block-size:48px;padding-block:var(--space-sm);padding-inline:var(--space-md);justify-content:flex-start}
.scope-action .button .end-icon{margin-inline-start:auto}
.cards-note{margin-block-start:var(--space-lg);max-inline-size:44rem}
@media(max-width:1100px){
 .icon-cards[data-cols="3"],.icon-cards[data-cols="4"],.scope-grid[data-cols="4"]{--cols:2}
 .scope-grid{gap:var(--space-md)}
 .scope-card{padding-inline:var(--space-md)}
}
@media(max-width:800px){
 .scope-grid{grid-template-columns:minmax(0,40rem)}
 .scope-card{padding-inline:var(--space-lg)}
}
@media(max-width:560px){
 .icon-cards{grid-template-columns:minmax(0,1fr);gap:var(--space-sm)}
 .icon-card{padding:var(--space-md)}
 .scope-card{padding-block:var(--space-lg)}
}
@media(forced-colors:active){
 .icon-card:has(.text-link:focus-visible){outline-color:Highlight}
}
@media print{
 .icon-card,.scope-card{break-inside:avoid}
 .icon-card .text-link::after{content:none}
}
/* 45-lists.css. Lists of the service pages (lib/sections/feature-columns.cjs, design/step-3.md §3.5 to §3.9,
   Appendix A.6). Logical properties only; sizes from the tokens; no font size in a media query.
   Side grid: heading column (.8fr) beside a content column (1.2fr), the FAQ proportions.
   Icon list: icon | title and copy, two columns (one inside a side grid), no boxes, no rules between items.
   Feature columns: two titled check lists; .is-compare mutes the first one ("a regular clean": shown as less,
     never crossed out or red).
   List panel: an ice panel holding a titled check list, used as the visual of an intro split.
   Preparation list: .report-row rows (34-proof.css, the Service Report's rows) in an ice panel, two columns above
     800 px; the tag says when the row applies (Before, On the day, After).
   Panels follow the surface rule (design/step-3.md §1.1): ice on a white section, white on an ice one. */
.side-grid{display:grid;grid-template-columns:.8fr 1.2fr;gap:var(--gap-split);align-items:start}
.side-grid>div:first-child>p{margin-block-start:var(--stack-text);font-size:var(--text-lead);line-height:var(--lh-lead)}
.side-grid>div:first-child>.text-link{margin-block-start:var(--space-md)}
.icon-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-xl) var(--gap-split);margin:0;padding:0;list-style:none}
.side-grid .icon-list{grid-template-columns:minmax(0,1fr);gap:var(--space-lg)}
.icon-list>li{display:grid;grid-template-columns:24px minmax(0,1fr);column-gap:var(--space-sm);align-content:start}
.icon-list .icon{inline-size:24px;block-size:24px;color:var(--blue)}
.icon-list h3{font-size:var(--text-lead);line-height:1.4;letter-spacing:0}
.icon-list p{grid-column:2;margin-block-start:var(--space-2xs)}
.feature-columns{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-xl) var(--gap-split)}
.feature-columns h3{display:flex;align-items:center;gap:var(--space-sm);font-size:var(--text-lead);line-height:1.4;letter-spacing:0}
.feature-columns h3 .icon{inline-size:24px;block-size:24px;color:var(--blue)}
.feature-columns>div>p{margin-block-start:var(--space-xs)}
.feature-columns .feature-list{margin:0;margin-block-start:var(--space-md);padding-block-start:var(--space-md)}
.feature-columns .text-link{margin-block-start:var(--space-sm)}
.feature-columns.is-compare>div:first-child h3,.feature-columns.is-compare>div:first-child .feature-list .icon{color:var(--muted)}
.list-panel{padding:var(--space-xl);border-radius:var(--radius);background:var(--surface-alt)}
.list-panel h3{font-size:var(--text-lead);line-height:1.4;letter-spacing:0}
.list-panel .feature-list{margin:0;margin-block-start:var(--space-md);padding-block-start:var(--space-md)}
.prep-panel{padding:var(--space-xl);border-radius:var(--radius);background:var(--surface-alt)}
.section.is-alt :is(.list-panel,.prep-panel){background:var(--surface)}
.prep-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--gap-split);margin:0;padding:0;list-style:none}
.prep-list>.report-row:nth-child(-n+2){margin-block-start:0;padding-block-start:0;border-block-start:0}
@media(max-width:800px){
 .side-grid{display:block}
 .side-grid>div+*{margin-block-start:var(--space-xl)}
 .icon-list,.feature-columns{grid-template-columns:minmax(0,1fr);gap:var(--space-lg)}
 .prep-list{grid-template-columns:minmax(0,1fr)}
 .prep-list>.report-row:nth-child(2){margin-block-start:var(--space-md);padding-block-start:var(--space-md);border-block-start:1px solid var(--line)}
}
@media(max-width:560px){
 .list-panel,.prep-panel{padding:var(--space-lg)}
}
/* 46-legal.css. Page head of the utility pages, the long-form legal layout (templates/legal.cjs: privacy-policy,
   terms-of-service; lib/sections/prose.cjs, toc.cjs) and the 404 page (templates/404.cjs, S4-09). Design spec
   docs/phase-3/design/step-4.md §2 and §6. Step-2 tokens only; no font-size in a media query; logical properties. */

/* Page head: ice band under the header. Breadcrumb (S3-01a, in the eyebrow slot as in the service hero), H1 at
   the h2 size, one lead line, "Last updated". The utility pages have no photo hero. */
.page-head{background:var(--surface-alt);padding-block:var(--section-y-tight)}
.page-head .breadcrumb{margin-block:calc(-1 * var(--space-sm)) var(--space-sm)}
.page-head h1{max-inline-size:20ch;font-size:var(--text-h2);line-height:var(--lh-heading);letter-spacing:var(--track-h2);margin-block-end:0}
.page-lead{margin-block-start:var(--stack-text);font-size:var(--text-lead);line-height:var(--lh-lead)}
.page-updated{margin-block-start:var(--space-md);font-size:var(--text-caption);line-height:var(--lh-caption);color:var(--muted)}

/* Body: white. Desktop (> 1100 px): contents on the inline start (sticky), text column of 44rem.
   1100 px and below: one column, in DOM order: In short, contents, sections. */
.legal{padding-block:var(--section-y-tight) var(--section-y)}
.legal-grid{display:grid;grid-template-columns:minmax(0,44rem);row-gap:var(--space-xl)}
@media(min-width:1101px){
 .legal-grid{grid-template-columns:minmax(0,16rem) minmax(0,44rem);grid-template-areas:"toc short" "toc body";column-gap:var(--gap-split);row-gap:var(--space-2xl);align-items:start}
 .legal-short{grid-area:short}
 .legal-toc{grid-area:toc;grid-row:1/span 2;position:sticky;inset-block-start:var(--space-lg);max-block-size:calc(100vh - 2 * var(--space-lg));overflow-y:auto;overscroll-behavior:contain}
 .legal-body{grid-area:body}
}

/* "In short": ice card, 3 lines with a check. */
.legal-short{padding-block:var(--space-lg);padding-inline:var(--space-lg);background:var(--surface-alt);border-radius:var(--radius)}
.legal-short h2{font-size:var(--text-lead);line-height:var(--lh-lead);letter-spacing:0}
.legal-short ul{display:grid;gap:var(--space-sm);margin:0;margin-block-start:var(--space-sm);padding:0;list-style:none}
.legal-short li{display:flex;gap:var(--space-xs);color:var(--ink)}
.legal-short li p{margin:0}
.legal-short .icon{width:16px;height:16px;margin-block-start:var(--space-2xs);color:var(--blue)}

/* Contents. Title in the caption role (caps); numbered links, 44 px each. A box at 1100 px and below, in two
   columns from 561 to 1100 px. */
.legal-toc h2{font-size:var(--text-caption);font-weight:800;line-height:var(--lh-caps);letter-spacing:var(--track-caps);text-transform:uppercase;color:var(--blue)}
:root[lang=ar] .legal-toc h2{font-weight:700}
.legal-toc ol{margin:0;margin-block-start:var(--space-xs);padding:0;list-style:none}
.legal-toc a{display:flex;align-items:center;gap:var(--space-xs);min-block-size:44px;padding-block:var(--space-2xs);font-size:var(--text-ui);line-height:var(--lh-ui);color:var(--ink)}
.legal-toc a>span{flex:none;min-inline-size:1.6em;color:var(--muted);font-variant-numeric:tabular-nums}
.legal-toc a:hover{color:var(--blue);text-decoration:underline;text-underline-offset:4px}
.legal-toc a:hover>span{text-decoration:none}
@media(max-width:1100px){
 .legal-toc{padding-block:var(--space-md);padding-inline:var(--space-lg);border:1px solid var(--line);border-radius:var(--radius)}
}
@media(max-width:1100px) and (min-width:561px){
 .legal-toc ol{columns:2;column-gap:var(--space-xl)}
 .legal-toc li{break-inside:avoid}
}

/* Numbered sections. The number is generated by the renderer (never typed in content) and repeated in the contents. */
.legal-body>section+section{margin-block-start:var(--space-2xl)}
/* Contents links target the section ids; html{scroll-padding-block-start} (01-base.css) leaves 24 px above them. */
.legal-body h2{font-size:var(--text-h3);line-height:var(--lh-h3);letter-spacing:var(--track-h3)}
.legal-n{color:var(--blue);font-variant-numeric:tabular-nums}
.legal-body h3{margin-block-start:var(--space-lg);font-size:var(--text-lead);line-height:var(--lh-lead);letter-spacing:0}
.legal-body p,.legal-body li{color:var(--ink)}
.legal-body h2+p,.legal-body h2+ul{margin-block-start:var(--space-sm)}
.legal-body h3+p,.legal-body h3+ul{margin-block-start:var(--space-xs)}
.legal-body p+p,.legal-body p+ul,.legal-body ul+p{margin-block-start:var(--space-md)}
.legal-body ul{display:grid;gap:var(--space-xs);max-inline-size:65ch;margin:0;padding-inline-start:1.25em}
.legal-body li::marker{color:var(--blue)}
.legal-body p a,.legal-body li a{color:var(--blue);font-weight:700;text-decoration:underline;text-underline-offset:3px}

/* Last section "Contact us" (id="contact"): an ice box with three 44 px actions. The box is an inner div: a
   top-level <section> of <main> may only pad with a --section-y* token or 0 (type.cjs section-padding-tokens). */
.legal-contact-box{padding:var(--space-xl);background:var(--surface-alt);border-radius:var(--radius)}
.legal-actions{display:flex;flex-wrap:wrap;gap:0 var(--space-xl);margin-block-start:var(--space-sm)}
.legal-contact address{margin-block-start:var(--space-sm);font-style:normal;color:var(--muted)}
.legal-contact address+p{margin-block-start:var(--space-sm)}
@media(max-width:560px){
 .legal-contact-box{padding-inline:var(--space-lg)}
 .legal-actions{flex-direction:column}
}

/* 404: one ice band. The media column (mascot, step 6) is added only when the slot is filled: the template adds
   .has-media (site.flags.mascot). The figure itself (square, radius, caption) is styled by 49-mascot.css (S6-01). */
.error-page{background:var(--surface-alt);padding-block:var(--section-y)}
.error-grid{display:grid;grid-template-columns:minmax(0,40rem);gap:var(--space-2xl) var(--gap-split);align-items:center}
.error-grid.has-media{grid-template-columns:minmax(0,40rem) minmax(0,22rem);justify-content:space-between}
.error-media{margin:0;min-inline-size:0}
.error-page h1{font-size:var(--text-h2);line-height:var(--lh-heading);letter-spacing:var(--track-h2);margin-block-end:0}
.error-actions{margin-block-start:var(--space-xl)}
.error-links{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--space-lg);margin:0;margin-block-start:var(--space-xl);padding:0;list-style:none;border-block-start:1px solid var(--line)}
.error-links li{border-block-end:1px solid var(--line)}
.error-links .text-link{display:grid;justify-content:space-between;min-block-size:48px}
@media(max-width:800px){
 .error-grid.has-media{grid-template-columns:minmax(0,1fr)}
 .error-media{inline-size:min(100%,15rem)}
}
@media(max-width:560px){
 .error-links{grid-template-columns:minmax(0,1fr)}
}
@media print{
 .legal-toc{position:static}
 .legal-contact-box{background:none;border:1px solid var(--line)}
}
/* 47-contact.css. Contact page components (lib/sections/contact-cards.cjs, wa-chips.cjs: tiles() and
   "start the conversation"), the tiles reused by the About service index, and the compact variant of the
   service hero. Design spec docs/phase-3/design/step-4.md §3. No form (PLAN Q2 default). Logical properties
   throughout; tokens only, no new literal (design §1.1). */

/* Compact hero (S3-01a hero with compact: true): a smaller 4:3 frame on desktop and no photo at 800 px and
   below, so the WhatsApp button is in the first screen on a phone. The photo is lazy and without
   fetchpriority, so a phone never fetches the hidden image. The .hero-service rules of 20-hero-photo.css
   stay untouched. The hero-photo.cjs "compact" option is S3-01a's / the integrator's (design §9 item 3):
   these rules are dormant until it lands. */
.hero-service.hero-compact .hero-media{justify-self:end;inline-size:100%;max-inline-size:29rem}
@media(max-width:800px){
 .hero-service.hero-compact .hero-media{display:none}
}

/* Four ways to reach us: WhatsApp (navy, first), phone, email, office. White section, ice cards. Desktop: a
   column per card (disc, title, value, line, action pinned to the bottom); 560 px and below: disc beside
   the text. */
.contact-ways{padding-block:var(--section-y-tight) var(--section-y)}
.contact-cards{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--space-lg);margin:0;padding:0;list-style:none}
.contact-card{display:flex;flex-direction:column;align-items:flex-start;block-size:100%;padding-block:var(--space-lg);padding-inline:var(--space-lg);background:var(--surface-alt);border-radius:var(--radius)}
.contact-disc{display:grid;place-items:center;flex:none;inline-size:44px;block-size:44px;border-radius:50%;background:var(--surface);color:var(--blue)}
.contact-disc .icon{width:22px;height:22px}
.contact-card-body{flex:1 1 auto;padding-block:var(--space-md) var(--space-sm)}
.contact-card h2{font-size:var(--text-h3);line-height:var(--lh-h3);letter-spacing:var(--track-h3)}
.contact-value{margin-block-start:var(--space-xs);font-weight:700;color:var(--ink);overflow-wrap:anywhere}
.contact-card-body>p:not(.contact-value){margin-block-start:var(--space-xs)}
/* WhatsApp card: navy, cyan link (7.05:1). Blue never sits on navy. */
.contact-card-wa{background:var(--surface-strong);color:var(--white)}
.contact-card-wa h2,.contact-card-wa .contact-value{color:var(--white)}
.contact-card-wa .contact-card-body>p:not(.contact-value){color:var(--ink-on-strong);line-height:var(--lh-body-strong)}
.contact-card-wa .contact-disc{background:var(--line-on-strong);color:var(--cyan)}
.contact-card-wa .text-link{color:var(--cyan)}
.contact-card-wa :focus-visible{outline-color:var(--focus-on-strong)}
@media(max-width:1100px){
 .contact-cards{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:560px){
 .contact-cards{grid-template-columns:minmax(0,1fr);gap:var(--space-sm)}
 .contact-card{display:grid;grid-template-columns:44px minmax(0,1fr);column-gap:var(--space-md);padding-block:var(--space-md) var(--space-xs);padding-inline:var(--space-md)}
 .contact-card-body{padding-block:var(--space-xs) 0}
 .contact-card .text-link{grid-column:2}
}

/* Tiles: 52 px link rows with an icon, a label and an arrow. The WhatsApp topics (wa() links) and the About
   service index (page links) share them. White with a 1 px line, on ice or on white. */
.tiles{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-sm);margin:0;padding:0;list-style:none}
.tile{display:flex;align-items:center;gap:var(--space-sm);block-size:100%;min-block-size:52px;padding-block:var(--space-sm);padding-inline:var(--space-md);background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-sm);font-size:var(--text-ui);font-weight:700;line-height:var(--lh-ui);color:var(--navy);transition:border-color .15s,color .15s}
.tile .icon{width:20px;height:20px;color:var(--blue)}
.tile .end-icon{width:18px;height:18px;margin-inline-start:auto}
.tile:active{border-color:var(--navy)}
.tile-all{background:var(--surface-alt);border-color:var(--surface-alt);color:var(--blue)}
@media(hover:hover){
 .tile:hover{border-color:var(--blue);color:var(--blue)}
}
@media(min-width:1101px){
 .tiles-4{grid-template-columns:repeat(4,minmax(0,1fr))}
}
@media(max-width:560px){
 .tiles{grid-template-columns:minmax(0,1fr);gap:var(--space-xs)}
}

/* Start the conversation: ice section, the topic tiles beside "What to send us" (white card). */
.contact-start{background:var(--surface-alt)}
.contact-start-grid{display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);gap:var(--space-2xl) var(--gap-split);align-items:start}
.send-card{padding-block:var(--space-xl);padding-inline:var(--space-xl);background:var(--surface);border-radius:var(--radius)}
.send-card h3{color:var(--ink)}
.send-card>p{margin-block-start:var(--space-xs)}
.send-list{display:grid;gap:var(--space-sm);margin:0;margin-block-start:var(--space-md);padding:0;list-style:none}
.send-list li{display:flex;gap:var(--space-xs);color:var(--ink)}
.send-list .icon{width:16px;height:16px;margin-block-start:var(--space-2xs);color:var(--blue)}
.send-card .text-link{margin-block-start:var(--space-md)}
@media(max-width:1100px){
 .contact-start-grid{grid-template-columns:minmax(0,1fr)}
}
@media(max-width:560px){
 .send-card{padding-inline:var(--space-lg)}
}
@media print{
 .contact-card,.contact-card-wa,.send-card{background:none;color:var(--ink);border:1px solid var(--line)}
 .contact-card-wa h2,.contact-card-wa .contact-value,.contact-card-wa p:not(.contact-value){color:var(--ink)}
}
/* 48-offer.css. Offer slot, #current-offer (lib/sections/offer-slot.cjs). Two states, chosen at build time:
   an active offer (white section, ice card, placed after the hero) or the evergreen line (slim ice band, placed
   before the FAQ). Never a price, a percentage, a countdown or a "limited time" badge. Design spec step-4.md §4. */
.offer{padding-block:var(--section-y-tight)}

/* Active offer: label and name, the four facts, one action. Desktop: facts on the inline end; phones: stacked,
   action last. */
.offer-card{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);grid-template-areas:"head facts" "action facts";grid-template-rows:auto 1fr;gap:0 var(--gap-split);padding-block:var(--space-xl);padding-inline:var(--space-xl);background:var(--surface-alt);border-radius:var(--radius)}
.offer-label{display:inline-block;padding-block:var(--space-2xs);padding-inline:var(--space-xs);margin-block-end:var(--space-sm);border-radius:var(--radius-sm);background:var(--surface);color:var(--blue);font-size:var(--text-caption);font-weight:700;line-height:var(--lh-caption)}
.offer-head{grid-area:head}
.offer-card h2{max-inline-size:16ch}
.offer-action{grid-area:action;padding-block-start:var(--space-xl)}
.offer-facts{grid-area:facts;display:grid;margin:0;border-block-start:1px solid var(--line)}
.offer-facts>div{display:grid;grid-template-columns:minmax(0,10rem) minmax(0,1fr);gap:var(--space-2xs) var(--space-lg);padding-block:var(--space-md);border-block-end:1px solid var(--line)}
.offer-facts dt{font-weight:700;color:var(--ink)}
.offer-facts dd{margin:0;color:var(--muted)}
@media(max-width:800px){
 .offer-card{grid-template-columns:minmax(0,1fr);grid-template-areas:"head" "facts" "action";grid-template-rows:none;padding-inline:var(--space-lg)}
 .offer-facts{margin-block-start:var(--space-lg)}
 .offer-action{padding-block-start:var(--space-lg)}
 .offer-facts>div{grid-template-columns:minmax(0,1fr)}
}

/* Evergreen line (no active offer): heading on the inline start, text and link on the inline end. */
.offer-empty{background:var(--surface-alt)}
.offer-empty-grid{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);gap:var(--space-md) var(--gap-split);align-items:start}
.offer-empty-grid p{font-size:var(--text-lead);line-height:var(--lh-lead)}
.offer-empty-grid .text-link{margin-block-start:var(--space-sm)}
@media(max-width:800px){
 .offer-empty-grid{grid-template-columns:minmax(0,1fr)}
}
@media print{
 .offer-card{background:none;border:1px solid var(--line)}
}
/* 49-mascot.css. The BestNear robot mascot (step 6, PLAN §9, design/step-6.md §3): figure.mascot-pose
   (lib/sections/mascot-pose.cjs), one square photo and its caption, written only while content/site.cjs
   flags.mascot is true. No video, no control, no script of its own.
   - Two placements. AC page intro: the figure is the ice panel of 38-intro-split.css (.system-visual), padded all
     round (the duct drawing touched the panel's edges on purpose, a photo does not), with the two scope chips and
     the caption; pushed to the column's outer edge above 800 px, centred under the text below. 404 page: the
     .error-media column of 46-legal.css places and sizes it; this file only draws the photo and the caption.
   - Box: 22rem (352 px) at most above 800 px, 15rem (240 px) at 800 px and below: the 404 column's own cap, one
     scale for the robot on both pages (design/step-6.md §0.4). The width and height attributes plus aspect-ratio
     reserve the square before the file arrives: no layout shift.
   - Edge: a 1 px --line border on the photo itself (.impeccable.md "Lines"; no shadow, the photo does not float).
     Both photos are full-bleed squares with their own light backdrop, close to --ice (the AC room's wall reads
     about #edf6ff against the #edf5f8 panel; the 404 studio white about #fefefe on the #edf5f8 band), so the
     frame's boundary is drawn on purpose instead of depending on the photo's tone (step-6 review, P1/P2).
     box-sizing:border-box (01-base.css) keeps the reserved square and the 22/15 rem caps unchanged.
   - Never mirrored: the photo carries the brand wordmark. Nothing here or in 90-rtl.css transforms it; logical
     properties only, so the Arabic grid places it on the other side by itself.
   - Entrance (AC page only, [data-reveal]): the site's existing one-time hook (dist/shared/interactions.js adds
     .is-visible once, when the figure enters the viewport). Hidden only with JavaScript and without a reduced-motion
     preference; under reduced motion, without JavaScript or with the class added, the photo is simply there.
   Block margins are left to 38-intro-split.css and 46-legal.css (their media queries set the gap above the figure
   when the grid stacks; a later rule here would override them at every width). */
.mascot-pose img{inline-size:100%;block-size:auto;aspect-ratio:1/1;object-fit:cover;border:1px solid var(--line);border-radius:var(--radius);background:var(--surface)}
.mascot-pose figcaption{margin-block-start:var(--space-sm);font-size:var(--text-caption);line-height:var(--lh-caption);color:var(--muted)}
.system-visual.mascot-pose{inline-size:100%;max-inline-size:22rem;padding:var(--space-md);margin-inline-start:auto}
.system-visual.mascot-pose>.system-key{margin-block-start:var(--space-md);padding-inline:0}
.system-visual.mascot-pose>figcaption{padding-inline:0}
@media(max-width:800px){
 .system-visual.mascot-pose{max-inline-size:15rem;margin-inline:auto}
}
@media(prefers-reduced-motion:no-preference){
 .js .mascot-pose[data-reveal]{transition:opacity .32s var(--ease-out),transform .32s var(--ease-out)}
 .js .mascot-pose[data-reveal]:not(.is-visible){opacity:0;transform:translateY(8px)}
}
/* 50-about.css. About page components not owned by any other step-4 task (design/step-4.md §9 item 2):
   lib/sections/about-story.cjs ("Who we are", also reusable for a page's own text+photo split) and
   lib/sections/care-list.cjs ("The way we work"). Logical properties only; tokens from 00-tokens.css, no
   new literal. "What we look after" needs no new rule here: it reuses the .tiles/.tile/.tiles-4 grid of
   47-contact.css through lib/sections/wa-chips.cjs's tiles(). */

/* Who we are: photo on the inline start, text on the inline end (design §5.3); centred vertically. The photo
   sits first in the DOM (so a single column below 800 px reads text, then photo) and is pulled to the start
   on wider screens with `order`. */
.about-story-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--gap-split);align-items:center}
.about-story-media{order:-1}
.about-story-media img{inline-size:100%;block-size:auto;aspect-ratio:3/2;object-fit:cover;border-radius:var(--radius)}
.about-story-body>p{margin-block-start:var(--stack-text);max-inline-size:36rem}
.about-story-body>p+p{margin-block-start:var(--space-sm)}
.about-story-body>.text-link{margin-block-start:var(--space-md)}
@media(max-width:800px){
 .about-story-grid{display:block}
 .about-story-media{margin-block-start:var(--space-xl)}
}

/* The way we work: rows, not cards (design §5.4). A 1 px line above the first row and under each row; the
   icon column keeps its own alignment so the title and text baselines never depend on the icon's height. */
.care-list{display:grid;margin:0;padding:0;list-style:none;border-block-start:1px solid var(--line)}
.care-row{display:grid;grid-template-columns:24px 17rem minmax(0,1fr);column-gap:var(--space-lg);align-items:start;padding-block:var(--space-lg);border-block-end:1px solid var(--line)}
.care-row>.icon{margin-block-start:2px;color:var(--blue)}
.care-row h3{font-size:var(--text-lead);font-weight:700;line-height:1.4;letter-spacing:0;color:var(--ink)}
.care-row p{grid-column:3;margin:0;max-inline-size:60ch}
@media(max-width:800px){
 .care-row{grid-template-columns:24px minmax(0,1fr);column-gap:var(--space-md)}
 .care-row h3{grid-column:2}
 .care-row p{grid-column:2;margin-block-start:var(--space-2xs)}
}
/* 80-hero-scroll.css. FROZEN (PLAN §2.3): scroll-driven hero of the home page (lib/sections/hero-scroll.cjs, dist/hero-scroll.js).
   Its rendering must not change without the owner's approval (hero-guard). The dead .hero-caption-static
   rule moved to 79-legacy.css. S1-11 (frozen: exception, guarded by hero-guard) removed the unused
   .hero-scroll .hero-caption rule below and in the 800px media query: hero-scroll.cjs never renders an
   element with class .hero-caption, so neither rule ever matched anything; the hero-guard captures at
   0/35/70/95% (390 and 1440px) confirm no pixel changed. */
/* ---- Scroll-driven hero (home) ---- */
.hero-scroll{--hero-length:250vh;display:block;height:var(--hero-length);min-height:0;overflow:visible;background:#eef6fb;color:var(--navy)}
.hero-stage{position:sticky;top:0;height:100vh;min-height:560px;overflow:hidden;background:#eef6fb}
.hero-frame-first,.hero-canvas{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:74% 52%}
.hero-frame-first{z-index:0}
.hero-canvas{z-index:1}
.hero-scrim{position:absolute;inset:0;z-index:2;background:linear-gradient(90deg,rgba(238,246,251,.96) 0%,rgba(238,246,251,.78) 30%,rgba(238,246,251,0) 54%)}
.hero-steps{position:relative;z-index:3;height:100%;display:grid;grid-template-columns:minmax(0,560px) 1fr;align-items:center;padding-top:0;padding-bottom:0}
.hero-step{grid-area:1/1;opacity:0;transform:translateY(12px);transition:opacity .18s ease-in,transform .18s ease-in;pointer-events:none;max-width:560px}
.hero-step[data-from="0"]{padding-bottom:var(--hero-offset,0px)}
.hero-step.is-on{opacity:1;transform:none;pointer-events:auto;transition:opacity .32s ease-out .14s,transform .32s ease-out .14s}
.hero-scroll .eyebrow,.hero-static .eyebrow{color:var(--blue)}
.hero-scroll .eyebrow>span,.hero-static .eyebrow>span{background:var(--blue)}
.hero-title{color:var(--navy);font-size:clamp(38px,4vw,58px);letter-spacing:-2px;line-height:1.1;font-weight:700;margin-bottom:20px;text-wrap:balance}
.hero-scroll .hero-description,.hero-static .hero-description{color:var(--ink);opacity:.86}
.hero-scroll .hero-secondary,.hero-static .hero-secondary{color:var(--navy)}
.hero-scroll .hero-assurances,.hero-static .hero-assurances{color:var(--ink)}
.hero-scroll .hero-assurances .icon{color:var(--blue)}
.hero-scroll .button-primary{box-shadow:0 10px 24px rgba(0,104,176,.18)}
.hero-hint{position:absolute;left:50%;bottom:20px;transform:translateX(-50%);z-index:3;font-size:11px;font-weight:700;letter-spacing:1px;color:var(--muted);text-transform:uppercase;display:flex;align-items:center;gap:8px}
.hero-hint::after{content:"";width:1px;height:24px;background:var(--navy);opacity:.4;animation:hero-drop 1.4s infinite}
@keyframes hero-drop{0%{transform:scaleY(0);transform-origin:top}50%{transform:scaleY(1);transform-origin:top}51%{transform-origin:bottom}100%{transform:scaleY(0);transform-origin:bottom}}
.hero-progress{position:absolute;left:0;right:0;bottom:0;height:3px;z-index:3;background:rgba(11,37,69,.08)}
.hero-progress i{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--blue),var(--cyan))}
.hero-static{display:none;background:#eef6fb;color:var(--navy);min-height:0}
.hero-static .hero-content{padding-top:64px;padding-bottom:64px}
.hero-static .hero-copy{max-width:none}
.hero-pair{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin:26px 0}
.hero-pair img{width:100%;border-radius:var(--radius);border:1px solid var(--line)}
html:not(.js) .hero-scroll,html.hero-fallback .hero-scroll{display:none}
html:not(.js) .hero-static,html.hero-fallback .hero-static{display:flex}
.hero-h1{text-transform:uppercase;text-wrap:initial}
.hero-points{list-style:none;margin:24px 0 0;padding:0;display:grid;gap:16px;max-width:480px}
.hero-points li{display:flex;align-items:flex-start;gap:14px;font-size:16px;line-height:1.55;color:var(--ink)}
.hero-points strong{color:var(--navy);font-weight:800}
.hero-point-icon{flex:0 0 40px;height:40px;border-radius:50%;background:#fff;border:1px solid var(--line);display:grid;place-items:center;box-shadow:0 6px 16px rgba(11,37,69,.08)}
.hero-point-icon .icon{width:20px;height:20px;color:var(--blue)}
@media (max-width:800px){
  .hero-points{gap:10px;margin-top:16px}
  .hero-points li{font-size:14px;line-height:1.5;gap:12px}
  .hero-point-icon{flex-basis:32px;height:32px}
  .hero-point-icon .icon{width:17px;height:17px}
}
@media (prefers-reduced-motion:reduce){.hero-hint::after{animation:none}.hero-step{transition:none}}
@supports (height:100svh){.hero-scroll{--hero-length:250svh}}
@media (max-width:800px){
  .hero-stage{min-height:0}
  .hero-frame-first{object-fit:contain;object-position:50% 12%}
  .hero-scrim{background:linear-gradient(180deg,rgba(238,246,251,0) 38%,rgba(238,246,251,.86) 58%,rgba(238,246,251,.98) 100%)}
  .hero-steps{grid-template-columns:1fr;align-items:end;padding-bottom:calc(92px + env(safe-area-inset-bottom,0px))}
  .hero-scroll .hero-assurances,.hero-scroll .button+.hero-secondary,.hero-step[data-from="0"] .hero-actions{display:none}
  .hero-step{max-width:none}
  .hero-scroll h1,.hero-title{font-size:clamp(30px,8.5vw,40px);letter-spacing:-1.2px;margin-bottom:14px}
  .hero-scroll .hero-description{font-size:15px;line-height:1.65}
      .hero-scroll .hero-actions{margin-top:20px;gap:16px}
  .hero-scroll .hero-assurances{margin-top:16px}
  .hero-hint{display:none}
  .hero-pair{grid-template-columns:1fr}
}
/* 81-why-band.css. FROZEN (PLAN §2.3): "Why BestNear" drifting band (lib/sections/why-band.cjs, dist/ui.js).
   Its rendering must not change without the owner's approval. The dead .why-foot p rule moved to 79-legacy.css. */
/* ---- Why choose BestNear: infinite band ---- */
.why{padding-top:88px;padding-bottom:72px;overflow:hidden}
.why-head{text-align:center;margin-bottom:34px}
.why-head .eyebrow{margin-bottom:12px}
.why-head h2{display:flex;flex-direction:column;align-items:center;gap:6px;text-wrap:balance}
.why-kicker{font-size:clamp(18px,1.6vw,22px);font-weight:600;letter-spacing:-.3px;color:var(--muted)}
.why-band{position:relative;padding:28px 0;border-block:1px solid var(--line);background:linear-gradient(90deg,var(--ice),rgba(237,245,248,0) 30%,rgba(237,245,248,0) 70%,var(--ice))}
.why-rail{display:flex;gap:42px;width:max-content;padding-inline:21px;will-change:transform}
.why-item{flex:0 0 300px;margin:0}
.why-item img{width:100%;height:auto;aspect-ratio:4/3;object-fit:cover;border-radius:var(--radius);border:1px solid var(--line);background:#e7f0f5;user-select:none;-webkit-user-drag:none}
.why-item figcaption{display:flex;align-items:center;gap:10px;margin-top:14px;font-size:17px;font-weight:700;letter-spacing:-.3px;color:var(--navy)}
.why-icon{flex:0 0 34px;height:34px;border-radius:50%;display:grid;place-items:center;background:#fff;border:1px solid var(--line)}
.why-icon .icon{width:18px;height:18px;color:var(--blue)}
.why-edge{position:absolute;top:0;bottom:0;width:160px;pointer-events:none;z-index:2;-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.why-edge-left{left:0;background:linear-gradient(90deg,#fff 0%,rgba(255,255,255,.6) 40%,rgba(255,255,255,0));-webkit-mask-image:linear-gradient(90deg,#000 20%,transparent);mask-image:linear-gradient(90deg,#000 20%,transparent)}
.why-edge-right{right:0;background:linear-gradient(270deg,#fff 0%,rgba(255,255,255,.6) 40%,rgba(255,255,255,0));-webkit-mask-image:linear-gradient(270deg,#000 20%,transparent);mask-image:linear-gradient(270deg,#000 20%,transparent)}
.why-foot{display:flex;justify-content:flex-end;align-items:center;gap:16px;margin-top:16px}
.why-toggle{display:inline-flex;align-items:center;gap:8px;min-height:44px;padding-block:6px;padding-inline:12px;border:1px solid var(--line);border-radius:4px;background:#fff;color:var(--navy);font-size:var(--text-ui);font-weight:700}
.why-toggle:hover{border-color:var(--blue)}
/* static mode: no JS, reduced motion, or paused by preference */
.why-band:not(.is-moving){overflow-x:auto;scrollbar-width:thin}
.why-band:not(.is-moving) .why-item[aria-hidden="true"]{display:none}
.why-band:not(.is-moving) .why-edge{display:none}
html:not(.js) .why-toggle{display:none}
@media (max-width:800px){
  .why{padding-top:64px;padding-bottom:56px}
  .why-band{padding:20px 0}
  .why-rail{gap:22px;padding-inline:11px}
  .why-item{flex-basis:220px}
  .why-item figcaption{font-size:15px;margin-top:12px}
  .why-icon{flex-basis:30px;height:30px}
  .why-edge{width:48px}
}
/* 82-brands.css. Brands band under the home scroll hero, "AC & control systems we service" (lib/sections/brands-band.cjs,
   owner decision 28 Sep 2026). White surface, --section-y-tight, full-bleed logo marquee driven by dist/ui.js
   [data-marquee] (the Why band's engine). Logos at one optical height: --brand-h times each logo's --brand-scale (set
   inline from the content module). Logos always in their own colours, no Pause button (owner decision, 28 Sep 2026
   evening): the drift slows under the pointer and stops on focus or under reduced motion. Never mirrored under RTL. */
.brands{--brand-h:30px;--brand-gap:var(--space-3xl);--brand-fade:clamp(48px,12vw,176px);padding-block:var(--section-y-tight)}
.brands-head{text-align:center;margin-block-end:var(--space-md)}
.brands-title{font-size:var(--text-lead);line-height:var(--lh-lead);letter-spacing:0;font-weight:700;color:var(--navy)}
/* Moving layout: one row wider than the screen, soft fades at both ends (symmetric, so direction-neutral). */
.brands-band{overflow:hidden;padding-block:var(--space-md);-webkit-mask-image:linear-gradient(90deg,transparent,#000 var(--brand-fade),#000 calc(100% - var(--brand-fade)),transparent);mask-image:linear-gradient(90deg,transparent,#000 var(--brand-fade),#000 calc(100% - var(--brand-fade)),transparent)}
.brands-rail{display:flex;align-items:center;gap:var(--brand-gap);inline-size:max-content;margin:0;padding-block:0;padding-inline:calc(var(--brand-gap) / 2);list-style:none;will-change:transform}
.brands-item{flex:none;display:flex;align-items:center;min-block-size:calc(var(--brand-h) * 1.4)}
.brands-item img{block-size:calc(var(--brand-h) * var(--brand-scale,1));inline-size:auto;max-inline-size:none;user-select:none;-webkit-user-drag:none}
/* Static layout (no JavaScript, reduced motion, and before ui.js runs): the list once, centred, in even rows:
   4 columns (two rows of four), 2 up to 560 px (the widest pair, Daikin and Mitsubishi Heavy Industries, fits at 360). */
.brands-band:not(.is-moving){-webkit-mask-image:none;mask-image:none}
.brands-band:not(.is-moving) .brands-rail{display:grid;grid-template-columns:repeat(4,auto);justify-content:center;justify-items:center;column-gap:var(--space-xl);row-gap:var(--space-md);inline-size:auto;padding-inline:var(--space-lg)}
.brands-band:not(.is-moving) .brands-item[aria-hidden="true"]{display:none}
/* Arabic: ui.js forces the band to dir="ltr" (its drift is measured and moved on the physical x axis), but the rail
   itself lays the logos out right to left, moving or static, so they read in the owner's order from the inline start
   (first brand at the right) and the drift brings the next brand in from the inline end. ui.js measures the loop
   width on either side. Direction only: the images themselves are never flipped. */
[dir="rtl"] .brands-rail{direction:rtl}
.brands-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:var(--space-xs) var(--space-lg);margin-block-start:var(--space-sm)}
.brands-note{font-size:var(--text-caption);line-height:var(--lh-caption);color:var(--muted);text-align:center}
@media (max-width:1100px){
  .brands-band:not(.is-moving) .brands-rail{column-gap:var(--space-2xl)}
}
@media (max-width:800px){
  .brands{--brand-h:28px;--brand-gap:var(--space-2xl)}
  .brands-band:not(.is-moving) .brands-rail{column-gap:var(--space-lg)}
}
@media (max-width:560px){
  .brands-band:not(.is-moving) .brands-rail{grid-template-columns:repeat(2,auto);padding-inline:var(--space-sm)}
}
/* 90-rtl.css. RTL overrides for the Arabic pages (step 5): only the physical-direction rules that have no
   logical-property equivalent (ARCHITECTURE.md §5.5; design/step-5.md §1.2, §1.4-1.5, §2.3-2.4). Everything
   else -- inset-inline-*, margin-inline-*, text-align:start/end, grid/flex reordering -- already lives in each
   component's own file as logical properties, or as an explicit [dir=rtl] grid override next to the rule it
   changes (e.g. 39-team.css's .team-inner, kept unmirrored on purpose: the photo is never mirrored and its
   text column stays physically on the right in both directions). source/verify/checks/css-lint.cjs's
   "logical-properties" check enforces this for every rule touched since p3-step-1, with a short, reasoned
   EXCEPTIONS list for what stays physical (this file, plus named selectors in 80-hero-scroll.css,
   81-why-band.css and 34-proof.css).

   Loaded last in source/lib/styles.cjs ORDER; every selector below also out-specifies the plain-class rule it
   overrides on its own ([dir=rtl] / :root[lang=ar] adds specificity a bare class or type selector does not
   have), so the load order is a belt-and-braces, not a requirement the letter-spacing rule still needs
   !important for the reason given below (design/step-5.md §8 point 3).

   Every selector here requires [dir=rtl] or :root[lang=ar] on <html> (or, for :root[lang=ar] *, is scoped from
   there): an EN page never sets either, so nothing in this file is reachable, still less able to change
   anything, on an EN page. */

/* ---- Frozen scroll hero (80-hero-scroll.css, untouched by this file): the AC-unit canvas and its first
   poster mirror with scaleX(-1) so the illustrated unit sits on the visitor's left. The text column already
   moves to the right on its own -- .hero-steps is a plain two-column grid with no explicit left/right
   placement, so dir=rtl alone reorders it, no rule needed for that part -- so canvas and text never overlap.
   The veil and the progress bar are mirrored to the same colour stops (270deg, not a different gradient), to
   keep the same lighting/composition logic now that the photo itself is flipped (design/step-5.md §2.4;
   ARCHITECTURE.md §5.3). Mobile (<=800px) is already unit-on-top / text-below with a vertical (180deg) scrim:
   nothing to mirror there. */
[dir=rtl] .hero-canvas,[dir=rtl] .hero-frame-first{transform:scaleX(-1)}
[dir=rtl] .hero-scrim{background:linear-gradient(270deg,rgba(238,246,251,.96) 0%,rgba(238,246,251,.78) 30%,rgba(238,246,251,0) 54%)}
[dir=rtl] .hero-progress i{background:linear-gradient(270deg,var(--blue),var(--cyan))}
/* .hero-points strong sits in the frozen file at font-weight:800 (the Latin 400/700/800 scale); Arabic uses
   400/700 only, 800 mapped to 700 (design/step-5.md §1.2 table). This selector's specificity already beats the
   frozen rule, so 80-hero-scroll.css stays byte-for-byte unchanged (hero-guard unaffected). */
:root[lang=ar] .hero-points strong{font-weight:700}

/* ---- Directional icon: the arrow glyph is the site's one spatial cue (every wa()/.text-link end-icon), so it
   mirrors; wa, phone, check and the logo never do -- they mean the same thing read from either direction, and
   mirroring a real photograph or the brand mark would misrepresent it (design/step-5.md §2.2-2.3: no rule
   needed for "never mirrored", the absence of one is correct). lib/icons.cjs icon() writes an icon-<name>
   class on every icon (design/step-5.md §2.3), so this one rule reaches every arrow: wa() buttons, text links,
   tiles, related cards, the scroll hero's secondary links. */
[dir=rtl] .icon-arrow{transform:scaleX(-1)}

/* ---- Process band phase line (33-process.css .phase-index i): transform-origin has no logical keyword. */
[dir=rtl] .phase-index i{transform-origin:right}

/* ---- Legal contents-nav heading (46-legal.css .legal-toc h2): text-transform:uppercase has no visual effect
   on Arabic script (Arabic has no letter case), but the site's other eyebrow-style labels are set apart by
   weight and colour only, never a transform -- dropped here for consistency (design/step-5.md §1.5;
   .impeccable.md "eyebrows"). Cosmetic, not required for correctness. */
:root[lang=ar] .legal-toc h2{text-transform:none}

/* ---- Letter-spacing: Arabic's joined script breaks under any positive or negative tracking. One rule for
   every non-zero letter-spacing declaration in the stylesheet -- headings, .eyebrow, .hero-title, buttons and
   others, 41 declarations at last count (ARCHITECTURE.md §5.4) -- including the frozen .hero-title and
   anything added to the stylesheet after this file. !important is deliberate: several of those declarations
   sit in files this rule does not otherwise out-order or out-specify (base tokens, component files, the frozen
   hero), so relying on cascade position alone would make correctness depend on source/lib/styles.cjs's ORDER
   placing 90-rtl.css strictly last; !important removes that dependency (design/step-5.md §1.4). */
:root[lang=ar] *{letter-spacing:0!important}

/* WordPress adapter (theme/bestnear/assets/css/wp-adapter.css, committed; appended to the generated site.css by
   tools/build-theme-assets.cjs). The static stylesheet is used unchanged; these few rules only cancel what WordPress
   adds around the same markup (ARCHITECTURE-WP.md §5).
   - .wp-site-blocks: the block-theme wrapper around the template (wp-includes/template-canvas.php). display:contents
     makes the skip link, utility bar, header, chips, <main>, footer, bubble and mobile bar behave as children of
     <body>, as on the static site (the sticky hero stage, the fixed mobile bar). */
.wp-site-blocks{display:contents}

/* Owner, 1 Oct 2026: the home grid can hold 2 photo cards (Home deep cleaning card removed): no empty third column. */
.service-gallery:has(> .service-card:nth-child(2):last-child){grid-template-columns:repeat(2,minmax(0,1fr))}
