/* Generated by ABS_Assets from assets/css/*.css. Do not edit. */

/* --- abs.css --- */
/**
 * ABS Tyres — base stylesheet.
 *
 * Every colour and type value here comes from a `--abs-*` custom property. Those
 * are generated from the Elementor Kit and printed inline in <head> by
 * ABS_Kit::css_variables(), so editing Site Settings restyles this file too.
 * Do not hardcode a hex value or a font size in this stylesheet — if a token is
 * missing, add it to ABS_Tokens rather than working around it here.
 *
 * Tokens available:
 *   colour  --abs-red --abs-black --abs-ink --abs-amber
 *           --abs-chrome-light --abs-chrome-mid --abs-white --abs-whatsapp
 *   type    --abs-{h1,h2,h3,body,ui,eyebrow,eta,caption}-{font,size,weight,lh,ls}
 *           --abs-eyebrow-transform
 */

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

body {
	font-family: var(--abs-body-font);
	font-size: var(--abs-body-size);
	font-weight: var(--abs-body-weight);
	line-height: var(--abs-body-lh);
	color: var(--abs-ink);
	background: var(--abs-white);
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 {
	color: var(--abs-black);
	font-family: var(--abs-display-font, var(--abs-h1-font));
	margin-block: 0 0.5em;
	text-wrap: balance;
}

h1 {
	font-family: var(--abs-h1-font);
	font-size: var(--abs-h1-size);
	font-weight: var(--abs-h1-weight);
	line-height: var(--abs-h1-lh);
	letter-spacing: var(--abs-h1-ls);
}

h2 {
	font-family: var(--abs-h2-font);
	font-size: var(--abs-h2-size);
	font-weight: var(--abs-h2-weight);
	line-height: var(--abs-h2-lh);
	letter-spacing: var(--abs-h2-ls);
}

h3 {
	font-family: var(--abs-h3-font);
	font-size: var(--abs-h3-size);
	font-weight: var(--abs-h3-weight);
	line-height: var(--abs-h3-lh);
	letter-spacing: var(--abs-h3-ls);
}

p {
	text-wrap: pretty;
}

a {
	color: var(--abs-red);
}

/* --------------------------------------------------------------------------
   Utility type roles
   -------------------------------------------------------------------------- */

/* Secondary text uses --abs-ink, not --abs-chrome-mid.
   PRD §7.2 gives chrome-mid the "secondary text" role, but #9AA1A8 on white is
   2.61:1 — it cannot satisfy §17's 4.5:1 floor, so the two sections contradict
   each other. --abs-ink is 6.27:1 on white and reads as secondary next to
   --abs-black headings. chrome-mid is still correct on dark surfaces (7.34:1),
   which is what .abs-on-dark below switches it to.
   Run tools/contrast-audit.php for the full matrix. */
.abs-eyebrow {
	font-family: var(--abs-eyebrow-font);
	font-size: var(--abs-eyebrow-size);
	font-weight: var(--abs-eyebrow-weight);
	line-height: var(--abs-eyebrow-lh);
	letter-spacing: var(--abs-eyebrow-ls);
	text-transform: var(--abs-eyebrow-transform);
	color: var(--abs-ink);
}

.abs-on-dark .abs-eyebrow,
.abs-on-dark .abs-caption {
	color: var(--abs-chrome-mid);
}

.abs-eta-figure {
	font-family: var(--abs-eta-font);
	font-size: var(--abs-eta-size);
	font-weight: var(--abs-eta-weight);
	line-height: var(--abs-eta-lh);
	letter-spacing: var(--abs-eta-ls);
	font-variant-numeric: tabular-nums;
}

.abs-caption {
	font-family: var(--abs-caption-font);
	font-size: var(--abs-caption-size);
	line-height: var(--abs-caption-lh);
	color: var(--abs-ink);
}

/* Dark surfaces. Applying this class flips the text tokens rather than leaving
   each component to remember the inversion. */
.abs-on-dark {
	background: var(--abs-black);
	color: var(--abs-white);
}

.abs-on-dark :where(h1, h2, h3, h4, h5, h6) {
	color: var(--abs-white);
}

/* Amber is a signal colour for the response window and is only legible on dark
   (9.40:1). On white it is 2.04:1 and fails even the large-text threshold, so it
   is confined to this context. */
.abs-on-dark .abs-eta-figure {
	color: var(--abs-amber);
}

/* --------------------------------------------------------------------------
   Accessibility floors (PRD § 17)
   -------------------------------------------------------------------------- */

/* A visible focus ring on every interactive element, for keyboard users only.
   Elementor's defaults suppress this on buttons and links. */
/* NOT :where(). A focus ring is the one thing in this stylesheet that must not
   lose a specificity argument — an invisible focus indicator is a keyboard user
   locked out of the page, and it fails silently for everyone testing with a
   mouse. :where() contributes zero, leaving this at 0-1-0, which any plugin
   rule with a single class beats. Written out, each selector scores 0-1-1.

   The card patterns in abs-area-grid.css and abs-service-grid.css deliberately
   move the ring to the parent with `outline: none` at 0-2-0, so they still win
   where they should. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
	outline: 3px solid var(--abs-black);
	outline-offset: 2px;
	border-radius: 2px;
}

/* On dark or red surfaces the black ring disappears — invert it there. */
.abs-on-dark a:focus-visible,
.abs-on-dark button:focus-visible,
.abs-on-dark [tabindex]:focus-visible,
.abs-on-red a:focus-visible,
.abs-on-red button:focus-visible,
.abs-on-red [tabindex]:focus-visible {
	outline-color: var(--abs-white);
}

/* Skip link — visually hidden until focused. */
.abs-skip-link {
	position: absolute;
	top: 0;
	left: 0;
	z-index: 10000;
	padding: 0.75rem 1.25rem;
	font-family: var(--abs-ui-font);
	font-size: var(--abs-ui-size);
	font-weight: var(--abs-ui-weight);
	background: var(--abs-white);
	color: var(--abs-black);
	transform: translateY(-120%);
}

.abs-skip-link:focus {
	transform: translateY(0);
}

/* Decorative emoji and icons kept out of the accessibility tree (PRD § 17).
   Paired with aria-hidden="true" in markup; this class is the visual half. */
.abs-deco {
	display: inline-block;
	font-style: normal;
	line-height: 1;
}

/* --------------------------------------------------------------------------
   Icons
   --------------------------------------------------------------------------
   Stroke icons from assets/img/icons.svg, inlined once per page. They inherit
   currentColor, so an icon is always the same colour as the text beside it and
   the contrast rules in tools/contrast-audit.php cover it automatically. */

.abs-icon {
	display: inline-block;
	width: 1.15em;
	height: 1.15em;
	vertical-align: -0.18em;
	flex: 0 0 auto;
	/* Never scale below the stroke weight it was drawn at. */
	min-width: 16px;
	min-height: 16px;
}

/* Every interactive target clears 48px (PRD § 17). The Dispatch Bar raises its
   own to 56px in phase 2. */
:where(a, button):where([class*="abs-"]):where(:not(.abs-skip-link, .abs-deco)) {
	min-height: 48px;
}

/* --------------------------------------------------------------------------
   Motion
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* --------------------------------------------------------------------------
   Layout safety
   -------------------------------------------------------------------------- */

/* No horizontal scroll at any width (PRD § 17, 320–1920px). */
html,
body {
	overflow-x: clip;
}

/* Media never overflows its container. */
img,
video,
iframe {
	max-width: 100%;
	height: auto;
}


/* --- dispatch-bar.css --- */
/**
 * The Dispatch Bar (PRD §7.4).
 *
 * One element, two presentations:
 *   desktop  slim red strip in normal flow, above the header
 *   mobile   fixed bottom bar, two targets of at least 56px
 *
 * It is the only fixed element on the page. No entrance animation — it must be
 * there the instant the page paints, because the person reading it is standing
 * on a hard shoulder.
 */

.abs-dispatch {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	flex-wrap: wrap;
	padding: 8px max(16px, calc((100% - 1200px) / 2));
	background: var(--abs-red);
	color: var(--abs-white);
}

/* ---- the response window ------------------------------------------------ */

.abs-dispatch__window {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 0 8px;
	margin: 0;
	font-family: var(--abs-font-body);
	font-size: 14px;
	line-height: 1.4;
}

.abs-dispatch__spark {
	align-self: center;
	font-size: 15px;
}

.abs-dispatch__eyebrow {
	font-family: var(--abs-eyebrow-font);
	font-weight: var(--abs-eyebrow-weight);
	font-size: var(--abs-eyebrow-size);
	letter-spacing: var(--abs-eyebrow-ls);
	text-transform: var(--abs-eyebrow-transform);
}

/* On the red strip the window is white; amber against red is unreadable
   (2.4:1). Amber is reserved for the mobile bar, where it sits on black at
   9.40:1. See tools/contrast-audit.php. */
.abs-dispatch__eta {
	color: var(--abs-white);
}

/* ---- actions ------------------------------------------------------------ */

.abs-dispatch__actions {
	display: flex;
	align-items: stretch;
	gap: 8px;
}

.abs-dispatch__action {
	display: flex;
	flex-direction: column;
	justify-content: center;
	/* PRD §17 floor for any tap target. The mobile rule below raises it to the
	   56px the Dispatch Bar itself is held to; this is the desktop strip, where
	   40px was under the floor even though the pointer is usually a mouse. */
	min-height: 48px;
	padding: 5px 16px;
	border-radius: 3px;
	text-decoration: none;
	font-family: var(--abs-ui-font);
	line-height: 1.15;
	transition: transform 0.12s ease, filter 0.12s ease;
}

.abs-dispatch__label {
	font-size: 15px;
	font-weight: 600;
	letter-spacing: 0.2px;
}

.abs-dispatch__sub {
	font-size: 12px;
	font-weight: 500;
	opacity: 0.85;
	font-variant-numeric: tabular-nums;
}

.abs-dispatch__action--call {
	background: var(--abs-white);
	color: var(--abs-red);
}

/* WhatsApp green carries BLACK text, not white. White on #25D366 is 1.98:1 and
   fails AA outright; --abs-black on it is 9.67:1. A deliberate, documented
   departure from WhatsApp's own brand styling. */
.abs-dispatch__action--wa {
	background: var(--abs-whatsapp);
	color: var(--abs-black);
}

.abs-dispatch__action:hover {
	filter: brightness(0.94);
}

.abs-dispatch__action:focus-visible {
	outline: 3px solid var(--abs-white);
	outline-offset: 2px;
}

/* ---- mobile: fixed bottom bar ------------------------------------------- */

@media (max-width: 767px) {
	.abs-dispatch {
		position: fixed;
		inset: auto 0 0 0;
		z-index: 9990;
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		padding: 0;
		background: var(--abs-black);
		box-shadow: 0 -2px 14px rgb(0 0 0 / 28%);
		/* Clear the home indicator on iOS rather than sitting under it. */
		padding-bottom: env(safe-area-inset-bottom, 0);
	}

	.abs-dispatch__window {
		justify-content: center;
		gap: 0 6px;
		padding: 6px 12px;
		font-size: 13px;
		text-align: center;
	}

	/* Amber on black: 9.40:1. This is the one surface it is allowed on. */
	.abs-dispatch__eta {
		color: var(--abs-amber);
		font-weight: 500;
	}

	.abs-dispatch__eyebrow {
		color: var(--abs-chrome-mid);
	}

	.abs-dispatch__actions {
		gap: 2px;
		padding: 0 2px 2px;
	}

	.abs-dispatch__action {
		flex: 1 1 0;
		align-items: center;
		text-align: center;
		/* PRD §17: at least 56px in the Dispatch Bar, against 48px elsewhere. */
		min-height: 56px;
		padding: 8px 10px;
		border-radius: 4px;
	}

	.abs-dispatch__label {
		font-size: 17px;
		font-weight: 700;
	}

	.abs-dispatch__sub {
		font-size: 12px;
	}

	/* Reserve the bar's height so it never covers the end of the page. The
	   value tracks the tallest the bar gets: window line + 56px target + gaps. */
	body.abs-has-dispatch {
		padding-bottom: calc(92px + env(safe-area-inset-bottom, 0px));
	}
}

/* Very narrow phones: the two sub-labels are the first thing to sacrifice, so
   the 56px targets and their primary labels survive at 320px. */
@media (max-width: 359px) {
	.abs-dispatch__sub {
		display: none;
	}

	body.abs-has-dispatch {
		padding-bottom: calc(84px + env(safe-area-inset-bottom, 0px));
	}
}

@media (prefers-reduced-motion: reduce) {
	.abs-dispatch__action {
		transition: none;
	}
}


/* --- chrome.css --- */
/**
 * Header, navigation and footer chrome.
 *
 * Complements the generated Elementor documents in inc/designs/. Anything here
 * is behaviour the Elementor controls cannot express — sticky condensing, the
 * mobile navigation sheet, and the accessibility floors.
 */

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */

.abs-header {
	border-bottom: 1px solid var(--abs-chrome-light);
}

.abs-header__logo img {
	display: block;
	height: auto;
}

/* Desktop: condense on scroll to logo and call button (PRD §8).
 *
 * On desktop the Dispatch Bar sits in normal flow and scrolls away, so the
 * header becomes the persistent contact affordance. On mobile the reverse is
 * true — the Dispatch Bar is pinned to the bottom — so the header is NOT made
 * sticky there. That keeps PRD §7.4's "only fixed element on the page" true at
 * every breakpoint, which a sticky header plus a fixed bottom bar would not. */
@media (min-width: 768px) {
	.abs-header {
		position: sticky;
		top: 0;
		z-index: 100;
		transition: box-shadow 0.18s ease;
	}

	.admin-bar .abs-header {
		top: 32px;
	}

	.abs-header.is-condensed {
		box-shadow: 0 2px 12px rgb(14 15 17 / 12%);
	}

	.abs-header.is-condensed .abs-header__logo img {
		max-width: 132px;
		transition: max-width 0.18s ease;
	}

	.abs-header.is-condensed .abs-header__nav {
		opacity: 0;
		visibility: hidden;
		transition: opacity 0.15s ease, visibility 0.15s ease;
	}
}

@media (prefers-reduced-motion: reduce) {
	.abs-header,
	.abs-header__logo img,
	.abs-header__nav {
		transition: none !important;
	}
}

/* --------------------------------------------------------------------------
   Mobile navigation — a bottom-anchored sheet
   --------------------------------------------------------------------------
   PRD §8: "Mobile nav as a bottom-anchored sheet, not a top-right hamburger —
   thumb reach matters when one hand is holding a phone in the rain."

   Elementor's nav-menu widget drops its mobile panel down from the toggle. The
   rules below re-anchor that same panel to the bottom of the viewport, sitting
   above the Dispatch Bar rather than under it. */

@media (max-width: 767px) {
	/* The header's call button is redundant on mobile: the Dispatch Bar carries
	   Call and WhatsApp at the bottom of every screen. Removing it also stops
	   the phone number wrapping onto four lines and eating the above-the-fold
	   budget (PRD §12.1). */
	.abs-header__call {
		display: none;
	}

	/* Elementor's toggle is 33x33 by default, under the 48px floor in PRD §17. */
	.abs-header .elementor-menu-toggle {
		width: 48px;
		height: 48px;
		display: flex;
		align-items: center;
		justify-content: center;
		border-radius: 4px;
		background: var(--abs-chrome-light);
		color: var(--abs-black);
	}

	/* Two traps here.
	 *
	 * 1. `.elementor-nav-menu--dropdown` is on BOTH the mobile panel and every
	 *    `ul.sub-menu`. Only the panel also carries
	 *    `.elementor-nav-menu__container`, so without that qualifier nested
	 *    submenus get pinned to the viewport too.
	 *
	 * 2. Do not set `max-height` here. Elementor opens and closes the panel with
	 *    it, from a pair of rules at specificity 0-4-0:
	 *
	 *      .elementor-nav-menu--toggle .elementor-menu-toggle:not(.elementor-active)
	 *        + .elementor-nav-menu__container { max-height: 0 }
	 *      .elementor-nav-menu--toggle .elementor-menu-toggle.elementor-active
	 *        + .elementor-nav-menu__container { max-height: var(--menu-height) }
	 *
	 *    Declaring our own max-height either loses to those or, worse, wins and
	 *    holds the panel permanently open. Instead we cap the property Elementor
	 *    reads. `--menu-height` is set inline on the element as `1000vmax`, so
	 *    the override needs !important to beat the inline value — the one place
	 *    in this build where it is the correct tool rather than a shortcut. */
	.abs-header .elementor-nav-menu__container.elementor-nav-menu--dropdown {
		--menu-height: min(62vh, 520px) !important;

		position: fixed;
		inset: auto 0 0 0;
		top: auto;
		z-index: 9985;
		margin-top: 0;
		/* Elementor animates the panel with scaleY from `transform-origin: top`,
		   which for a bottom-anchored sheet reads as growing downwards off the
		   screen. Re-origin it so it rises from the bottom edge. */
		transform-origin: bottom;
		overflow-y: auto;
		overscroll-behavior: contain;
		border-radius: 14px 14px 0 0;
		box-shadow: 0 -6px 28px rgb(14 15 17 / 34%);
		/* Clear the Dispatch Bar so the last item is never trapped behind it. */
		padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px));
	}

	/* Assert the open state outright.
	 *
	 * Elementor gates the panel with a pair of rules that set both `max-height`
	 * and `transform: scaleY()`. Repositioning the panel to the bottom means the
	 * scaleY animation reads as unrolling off-screen, so both properties have to
	 * be taken over together — overriding only one leaves the panel measuring
	 * zero height however generous the other is.
	 *
	 * `aria-expanded` is the trigger rather than the `elementor-active` class:
	 * both are set by the same handler, but the ARIA attribute is the contract
	 * Elementor is least likely to rename between versions.
	 *
	 * !important on a third-party component's animation properties, deliberately
	 * and with the reasoning recorded, rather than escalating specificity in a
	 * fight we would have to re-fight on every Elementor update. */
	.abs-header .elementor-menu-toggle[aria-expanded="true"] + .elementor-nav-menu__container.elementor-nav-menu--dropdown {
		max-height: min(62vh, 520px) !important;
		transform: none !important;
	}

	.abs-header .elementor-nav-menu--dropdown a.elementor-item {
		min-height: 52px;
		display: flex;
		align-items: center;
	}
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.abs-footer__links a,
.abs-footer__contact a {
	text-decoration: none;
}

.abs-footer__links a:hover,
.abs-footer__contact a:hover {
	text-decoration: underline;
}

/* The footer column titles are h2 for document structure, but they should read
   as small labels rather than competing with page headings. */
.abs-footer__heading {
	margin-bottom: 4px;
}

.abs-footer__contact p {
	margin: 0 0 8px;
}

.abs-footer__legal,
.abs-footer__copyright {
	margin: 0;
}

/* A legal page held back by the publish gate keeps its label in the footer but
   loses the link. Muted, not hidden — the gap should be visible to whoever is
   reviewing the site, not quietly papered over. */
.abs-legal-pending {
	opacity: 0.55;
	text-decoration: underline dotted;
	cursor: not-allowed;
}

/* --------------------------------------------------------------------------
   Breadcrumbs
   --------------------------------------------------------------------------
   Rendered by the theme (ABS_Routes), not placed in the page documents, so a
   client editing one page in Elementor cannot delete the trail from that page
   and leave it on the other twenty. */

.abs-breadcrumbs {
	background: var(--abs-chrome-light);
	border-bottom: 1px solid rgb(0 0 0 / 7%);
}

.abs-breadcrumbs__inner {
	max-width: 1200px;
	margin-inline: auto;
	padding: 10px 20px;
}

.abs-breadcrumbs__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px 10px;
	margin: 0;
	padding: 0;
	list-style: none;
	font-family: var(--abs-ui-font);
	font-size: var(--abs-caption-size);
}

/* The separator is decorative, so it is generated rather than marked up — a
   screen reader announcing "slash" between every crumb helps nobody. */
.abs-breadcrumbs__item + .abs-breadcrumbs__item::before {
	content: "/";
	margin-inline-end: 10px;
	color: var(--abs-chrome-mid);
}

.abs-breadcrumbs__item {
	color: var(--abs-ink);
}

.abs-breadcrumbs__item a {
	color: var(--abs-ink);
	text-decoration: none;
	border-bottom: 1px solid transparent;
}

.abs-breadcrumbs__item a:hover,
.abs-breadcrumbs__item a:focus-visible {
	color: var(--abs-red);
	border-bottom-color: currentColor;
}

.abs-breadcrumbs__item--current {
	color: var(--abs-black);
	font-weight: 600;
}

@media (max-width: 600px) {
	.abs-breadcrumbs__inner {
		padding: 8px 16px;
	}
}


/* --- blocks.css --- */
/**
 * Interior page layout blocks.
 *
 * The job of every rule here is to give long-form copy edges. Nothing shortens
 * the writing; the structure lets a reader see the shape of a section before
 * committing to it, which is what the pages were missing.
 */

/* --------------------------------------------------------------------------
   Lead paragraph
   --------------------------------------------------------------------------
   The first paragraph of a section, set larger with a rule down its left edge.
   It gives the section an obvious entry point and stops the eye landing in the
   middle of a block of body text. */

.abs-block__lead {
	max-width: 62ch;
	margin: 0;
	padding-inline-start: 18px;
	border-inline-start: 3px solid var(--abs-red);
	font-family: var(--abs-font-body);
	font-size: clamp(17px, 1.35vw, 20px);
	line-height: 1.6;
	color: var(--abs-black);
}

.abs-on-dark .abs-block__lead {
	color: var(--abs-white);
}

/* --------------------------------------------------------------------------
   Supporting cards
   --------------------------------------------------------------------------
   Everything after the lead. auto-fit rather than a fixed column count, so a
   section that gains or loses a paragraph lays out correctly without anybody
   editing a template: one card fills the row, two sit side by side, three run
   across. */

.abs-block__cards {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
	gap: 20px;
	margin: 4px 0 0;
}

.abs-block__card {
	padding: 22px 24px;
	background: var(--abs-white);
	border-top: 3px solid var(--abs-chrome-light);
	box-shadow: 0 1px 0 rgb(14 15 17 / 6%), 0 6px 18px -14px rgb(14 15 17 / 45%);
}

.abs-block__card p {
	margin: 0;
	max-width: 60ch;
	font-size: var(--abs-body-size);
	line-height: 1.65;
	color: var(--abs-ink);
}

/* On a tinted panel the cards need to stay white to read as raised; on a dark
   one they invert instead, because a white card on black is a spotlight. */
.abs-on-dark .abs-block__card {
	background: rgb(255 255 255 / 5%);
	border-top-color: var(--abs-red);
	box-shadow: none;
}

.abs-on-dark .abs-block__card p {
	color: var(--abs-chrome-light);
}

/* A single card would otherwise stretch to a full 1200px line, which is the
   thing this whole file exists to prevent. */
.abs-block__cards:has(> .abs-block__card:only-child) {
	grid-template-columns: minmax(0, 68ch);
}

/* --------------------------------------------------------------------------
   Eyebrow
   -------------------------------------------------------------------------- */

/* Type comes from the Kit, set on the widget in abs_block_prose(). Only the
   spacing lives here — Elementor's per-post heading rule would win any argument
   about font-size or colour. */
.abs-block__eyebrow {
	margin-bottom: -10px;
}

/* --------------------------------------------------------------------------
   Photo beside text
   -------------------------------------------------------------------------- */

.abs-split__media img {
	display: block;
	width: 100%;
	height: auto;
	max-height: 380px;
	object-fit: cover;
	object-position: center 45%;
	filter: grayscale(25%) contrast(105%);
}

.abs-split__media figcaption,
.abs-split__media .widget-image-caption {
	margin-top: 8px;
	font-family: var(--abs-caption-font);
	font-size: var(--abs-caption-size);
	line-height: var(--abs-caption-lh);
	color: var(--abs-chrome-mid);
	font-style: italic;
}

.abs-split__copy .abs-block__lead {
	max-width: none;
}

/* --------------------------------------------------------------------------
   Numbered steps
   -------------------------------------------------------------------------- */

.abs-steps {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
	gap: 20px;
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: abs-step;
}

.abs-steps__item {
	counter-increment: abs-step;
	position: relative;
	padding: 26px 22px 22px;
	background: var(--abs-white);
	border-top: 3px solid var(--abs-red);
	box-shadow: 0 6px 18px -14px rgb(14 15 17 / 45%);
}

/* The numeral is generated, not marked up: it is a visual ordinal and the list
   is already an <ol>, so a screen reader announces the position anyway. Marking
   it up as text would have it read twice. */
.abs-steps__item::before {
	content: counter(abs-step);
	position: absolute;
	top: -3px;
	inset-inline-start: 22px;
	transform: translateY(-50%);
	display: grid;
	place-items: center;
	min-width: 34px;
	height: 34px;
	padding: 0 8px;
	background: var(--abs-red);
	color: var(--abs-white);
	font-family: var(--abs-font-display);
	font-weight: 800;
	font-size: 18px;
	line-height: 1;
}

.abs-steps__title {
	margin: 10px 0 6px;
	font-family: var(--abs-font-display);
	font-weight: 700;
	font-size: var(--abs-h3-size);
	letter-spacing: var(--abs-h3-ls);
	color: var(--abs-black);
}

.abs-steps__body {
	margin: 0;
	font-size: var(--abs-body-size);
	line-height: 1.6;
	color: var(--abs-ink);
}

/* --------------------------------------------------------------------------
   Rhythm
   --------------------------------------------------------------------------
   Interior sections were all the same height and all the same colour, which is
   most of why they read as one long document. Tightening the vertical padding
   on consecutive prose blocks and letting the panelled ones breathe gives the
   page a pulse. */

@media (max-width: 767px) {
	.abs-block__lead {
		padding-inline-start: 14px;
		font-size: 17px;
	}

	.abs-block__cards {
		gap: 14px;
	}

	.abs-block__card {
		padding: 18px 18px;
	}

	.abs-split__media img {
		max-height: 260px;
	}
}


/* --- home.css --- */
/**
 * Homepage.
 *
 * Loaded only on the front page.
 *
 * ## Visual direction
 *
 * PRD §7.1 asks for urgent, mechanical, dependable, unglamorous — and warns off
 * the slick dark-mode automotive look with glowing accents, because that reads
 * as a lead-generation aggregator.
 *
 * The first pass read "unglamorous" as "unstyled", which is a different thing
 * and produced a page of black text on white. What follows is industrial rather
 * than plain: flat fills with no gradients, no glows and no drop shadows on the
 * hero; a single hazard-stripe motif borrowed from roadside signage; and hard
 * black/white contrast doing the work that a photograph normally would.
 *
 * The hero is black. That is a deliberate accent rather than a dark theme —
 * everything below it is light, so the black returns only for the two sections
 * that carry urgency (the response zones and the closing call to action).
 */

/* --------------------------------------------------------------------------
   The hazard stripe — the page's one repeated motif
   --------------------------------------------------------------------------
   45-degree red and black bands, the pattern used on every crash barrier and
   recovery vehicle in the country. Pure CSS, so it costs nothing and scales to
   any width. */

.abs-stripe,
.abs-hero::after,
.abs-final::before {
	content: "";
	display: block;
	height: 8px;
	background-image: repeating-linear-gradient(
		45deg,
		var(--abs-red) 0 14px,
		var(--abs-black) 14px 28px
	);
}

/* --------------------------------------------------------------------------
   Hero
   --------------------------------------------------------------------------
   The fold (PRD §12.1): at 375px the first screen carries the logo, the H1, the
   response window and a call button — nothing else. The min-height pushes the
   sub-headline past the fold on a 667px viewport.

   `svh` rather than `vh`: on mobile browsers `vh` is the height with the address
   bar retracted, so a 100vh hero is taller than the screen you actually get on
   load and the fold lands in the wrong place. */

/* The photograph sits under a near-opaque black wash, so it reads as texture
   rather than as a hero image — the flat industrial direction survives, and the
   H1 keeps white-on-black contrast (19:1) rather than fighting a picture.
   Compressed at quality 52 for the same reason: detail nobody can see through
   the overlay is just bytes in the LCP path. 37.8KB at 1600x900. */
.abs-hero {
	position: relative;
	background-color: var(--abs-black);
	background-image:
		repeating-linear-gradient(
			90deg,
			rgb(255 255 255 / 3.5%) 0 2px,
			transparent 2px 26px
		),
		linear-gradient(
			100deg,
			rgb(14 15 17 / 96%) 0%,
			rgb(14 15 17 / 88%) 45%,
			rgb(14 15 17 / 72%) 100%
		),
		url("../img/stock/hero-road.webp");
	background-size: auto, cover, cover;
	background-position: center, center, center 62%;
	background-repeat: repeat, no-repeat, no-repeat;
}

/* --------------------------------------------------------------------------
   Photo band
   --------------------------------------------------------------------------
   One full-bleed image between the triage tiles and the reviews, purely to
   break the run of text blocks. Stock, and therefore deliberately anonymous —
   gloved hands and a wheel, no faces, nothing that implies whose hands they are. */

.abs-photoband {
	position: relative;
	overflow: hidden;
}

/* Qualified with the widget class: Elementor's own image rules set height:auto,
   and at equal specificity they load last and win — which left the band running
   at the image's full natural height instead of a strip. */
.abs-photoband .elementor-widget-image img {
	width: 100%;
	height: clamp(150px, 22vw, 260px);
	object-fit: cover;
	object-position: center 58%;
	display: block;
	/* Desaturated and darkened so it sits with the palette instead of shouting
	   over it — a full-colour stock photo is what makes a page look bought. */
	filter: grayscale(38%) contrast(108%) brightness(78%);
}

.abs-photoband::after {
	content: "";
	position: absolute;
	inset: auto 0 0 0;
	height: 8px;
	background-image: repeating-linear-gradient(
		45deg,
		var(--abs-red) 0 14px,
		var(--abs-black) 14px 28px
	);
}

.abs-hero::after {
	position: absolute;
	inset: auto 0 0 0;
}

@media (max-width: 767px) {
	.abs-hero {
		min-height: calc(100svh - var(--abs-header-h, 57px) - var(--abs-dispatch-h, 92px));
	}
}

/* The H1 is the LCP element. Barlow Condensed 700 is preloaded for it, and there
   is deliberately no hero image competing for that slot. */
.abs-hero__h1,
.abs-hero__h1 .elementor-heading-title {
	color: var(--abs-white);
	max-width: 17ch;
}

@media (min-width: 768px) {
	.abs-hero__h1,
	.abs-hero__h1 .elementor-heading-title {
		max-width: 19ch;
	}
}

/* On black the badge needs no fill of its own — it would be a box inside a box. */
.abs-hero .abs-eta-badge__inner {
	background: transparent;
	border-inline-start: 3px solid var(--abs-red);
	border-radius: 0;
	padding-block: 4px;
}

.abs-hero .abs-eta-badge__label {
	color: var(--abs-chrome-mid);
}

/* --------------------------------------------------------------------------
   Trust strip — the four facts, immediately under the hero
   -------------------------------------------------------------------------- */

.abs-trustbar {
	background: var(--abs-chrome-light);
}

/* Work with Elementor's flex rather than against it: the container already
   carries `display: flex`, so forcing `display: grid` here loses on load order
   and leaves four content-width columns huddled on the left. */
.abs-trustbar .abs-trustbar__grid {
	flex-wrap: wrap;
	align-items: stretch;
	column-gap: 0;
	row-gap: 0;
}

.abs-trustbar .abs-trustbar__item {
	flex: 1 1 0;
	min-width: 0;
	gap: 3px;
	padding: 18px 18px 18px 0;
	border-inline-start: 1px solid var(--abs-chrome-mid);
	padding-inline-start: 18px;
}

.abs-trustbar .abs-trustbar__item:first-child {
	border-inline-start: 0;
	padding-inline-start: 0;
}

/* The class from `_css_classes` lands on the widget wrapper, but the text lives
   in `.elementor-heading-title` inside it — and that element carries Elementor's
   own colour and type. Styling only the wrapper is why the figures came out red
   and oversized. */
/* Type comes from the Kit now, set on the widget in abs_block_stats() — see the
   note there. Elementor's per-post heading rule ties with anything this file can
   say and loads afterwards, so font-size and colour declared here would simply
   be ignored. What is left is layout, which Elementor does not touch. */
.abs-trustbar__figure .elementor-heading-title {
	line-height: 1;
	font-variant-numeric: tabular-nums;
	display: flex;
	align-items: center;
	gap: 6px;
}

/* Same again: type on the widget, only what Elementor leaves alone here. */
.abs-trustbar__label .elementor-heading-title {
	line-height: 1.35;
	text-transform: none;
}

.abs-trustbar__stars {
	display: inline-flex;
	color: var(--abs-red);
}

.abs-trustbar__stars .abs-icon {
	width: 20px;
	height: 20px;
}

@media (max-width: 767px) {
	.abs-trustbar .abs-trustbar__item {
		flex: 1 1 45%;
		padding: 14px;
		border-inline-start: 0;
		border-top: 1px solid var(--abs-chrome-mid);
	}

	.abs-trustbar .abs-trustbar__item:first-child,
	.abs-trustbar .abs-trustbar__item:nth-child(2) {
		border-top: 0;
	}

	.abs-trustbar .abs-trustbar__item:nth-child(odd) {
		border-inline-end: 1px solid var(--abs-chrome-mid);
	}

	.abs-trustbar__figure .elementor-heading-title {
		font-size: 24px;
	}
}

/* --------------------------------------------------------------------------
   Sub-headline block
   -------------------------------------------------------------------------- */

.abs-hero__sub {
	max-width: 58ch;
	font-size: calc(var(--abs-body-size) + 2px);
}

.abs-hero__badges .elementor-icon-list-item {
	white-space: normal;
}

/* --------------------------------------------------------------------------
   Cards and sections
   -------------------------------------------------------------------------- */

/* A red rule along the top edge is the whole card treatment: it reads as a
   labelled panel rather than a floating box, which suits a service that fixes
   things for a living. */
.abs-why__card {
	border-inline-start: 0;
	border-top: 3px solid var(--abs-red);
	background: var(--abs-white);
	padding: 18px 18px 20px;
	box-shadow: 0 1px 0 var(--abs-chrome-mid), 0 0 0 1px var(--abs-chrome-light);
}

.abs-why__card h3,
.abs-why__card .elementor-heading-title {
	display: flex;
	align-items: center;
	gap: 10px;
}

.abs-why__glyph {
	flex: 0 0 auto;
	color: var(--abs-red);
	width: 26px;
	height: 26px;
}

.abs-steps .abs-step {
	position: relative;
	border-top: 3px solid var(--abs-black);
	padding-top: 14px;
}

/* The step number is the graphic element — outlined, oversized, unglamorous. */
.abs-step__number,
.abs-step__number .elementor-heading-title {
	font-size: 64px;
	line-height: 0.85;
	color: transparent;
	-webkit-text-stroke: 2px var(--abs-red);
	font-variant-numeric: tabular-nums;
}

@media (max-width: 767px) {
	.abs-step__number,
	.abs-step__number .elementor-heading-title {
		font-size: 46px;
	}
}

/* Eyebrow headings in red, so a section announces itself before it is read. */
.abs-triage-section .abs-eyebrow .elementor-heading-title {
	color: var(--abs-red);
}

/* --------------------------------------------------------------------------
   Reviews block
   -------------------------------------------------------------------------- */

.abs-reviews-section .abs-reviews__stars {
	color: var(--abs-red);
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.abs-hero__call .elementor-button,
.abs-hero__wa .elementor-button {
	min-height: 56px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border-radius: 2px;
	letter-spacing: 0.3px;
}

/* Square-ish corners throughout: rounded buttons read as consumer software,
   and this is a recovery service. */
.abs-hero__call .elementor-button {
	box-shadow: inset 0 -3px 0 rgb(0 0 0 / 22%);
}

@media (max-width: 767px) {
	.abs-hero__call .elementor-button,
	.abs-hero__wa .elementor-button {
		width: 100%;
	}
}

/* --------------------------------------------------------------------------
   Closing call to action
   -------------------------------------------------------------------------- */

.abs-final {
	position: relative;
}

.abs-final::before {
	position: absolute;
	inset: 0 0 auto 0;
}


/* --- pages.css --- */
/**
 * Interior pages — about, contact, tyre types, FAQs and legal.
 *
 * Layout the Elementor controls cannot express. Everything here uses the
 * `--abs-*` tokens; no hex, no hardcoded type sizes.
 */

/* --------------------------------------------------------------------------
   Shared measure
   --------------------------------------------------------------------------
   Long-form pages need a readable line length. Elementor's container width is
   1200px, which is right for a card grid and much too wide for prose. */

/* Target the paragraphs, NOT the widget wrapper. Elementor writes
   `max-width: 100%` onto .elementor-element-<id> in its per-post stylesheet,
   which is two classes plus the post class and beats anything this file can say
   about the wrapper. It sets nothing on the `p` inside, so that is where the
   measure goes. Same trap as the FAQ panel width — see the note further down. */
.abs-about-section .elementor-widget-text-editor :where(p, li),
.abs-service-section .elementor-widget-text-editor :where(p, li),
.abs-area-section .elementor-widget-text-editor :where(p, li),
.abs-tyre-section .elementor-widget-text-editor :where(p, li),
.abs-legal .elementor-widget-text-editor :where(p, li),
.abs-faqs-hero .elementor-widget-text-editor :where(p, li) {
	max-width: 68ch;
}

.abs-about-hero__sub,
.abs-contact-hero__sub,
.abs-service-hero__intro,
.abs-area-hero__intro,
.abs-tyre-hero__intro {
	max-width: 62ch;
}

/* --------------------------------------------------------------------------
   About
   -------------------------------------------------------------------------- */

/* The photograph slot. Capped, because it is a placeholder standing in for a
   real photograph of Abu Bakar beside the van — and an oversized stock image
   claiming that space is worse than a modest one admitting it. */
.abs-about-hero__photo img {
	max-height: 340px;
	width: 100%;
	object-fit: cover;
	object-position: center 45%;
	filter: grayscale(30%) brightness(85%);
}

.abs-about-hero__photo figcaption,
.abs-about-hero__photo .widget-image-caption {
	margin-top: 8px;
	font-family: var(--abs-caption-font);
	font-size: var(--abs-caption-size);
	color: var(--abs-chrome-mid);
	font-style: italic;
}

/* The comparison table. Real tabular data, so it stays a table — and scrolls
   inside its own box rather than making the page scroll sideways. */
.abs-about__compare .elementor-widget-html {
	overflow-x: auto;
	max-width: 100%;
}

.abs-compare {
	width: 100%;
	min-width: 560px;
	border-collapse: collapse;
	font-family: var(--abs-font-body);
	font-size: var(--abs-body-size);
}

.abs-compare th,
.abs-compare td {
	padding: 13px 15px;
	text-align: start;
	border-bottom: 1px solid var(--abs-chrome-light);
	vertical-align: top;
}

.abs-compare thead th {
	font-family: var(--abs-font-display);
	font-weight: 700;
	font-size: var(--abs-h3-size);
	letter-spacing: var(--abs-h3-ls);
	color: var(--abs-black);
	border-bottom: 3px solid var(--abs-black);
}

.abs-compare tbody th {
	font-weight: 600;
	color: var(--abs-black);
	white-space: nowrap;
}

/* The ABS column carries the emphasis the client's table intends, without
   needing the emoji their markdown used. */
.abs-compare .abs-compare__us {
	background: var(--abs-chrome-light);
	color: var(--abs-black);
	font-weight: 600;
	box-shadow: inset 3px 0 0 var(--abs-red);
}

.abs-compare thead .abs-compare__us {
	border-bottom-color: var(--abs-red);
}

/* --------------------------------------------------------------------------
   Contact
   -------------------------------------------------------------------------- */

.abs-urgency {
	display: flex;
	align-items: center;
	gap: 9px;
	margin: 0;
	padding: 11px 15px;
	border-inline-start: 3px solid var(--abs-red);
	background: rgb(255 255 255 / 6%);
	color: var(--abs-white);
	font-family: var(--abs-font-body);
	font-size: var(--abs-body-size);
}

.abs-contact-methods {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
	gap: 16px;
}

.abs-contact-methods__item {
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding: 14px 16px;
	border-top: 3px solid var(--abs-red);
	background: var(--abs-chrome-light);
}

.abs-contact-methods__glyph {
	color: var(--abs-red);
}

.abs-contact-methods__caption {
	font-family: var(--abs-caption-font);
	font-size: var(--abs-caption-size);
	line-height: var(--abs-caption-lh);
	color: var(--abs-ink);
}

/* The roadside disclaimer. It sits above the form and has to be impossible to
   skim past — it is the sentence that sends an emergency to the phone instead
   of into a contact form nobody will read for hours. */
.abs-form-disclaimer {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	margin: 0;
	padding: 14px 16px;
	background: var(--abs-black);
	color: var(--abs-white);
	border-inline-start: 4px solid var(--abs-red);
	font-family: var(--abs-font-body);
	font-size: var(--abs-body-size);
}

.abs-form-disclaimer__spark {
	color: var(--abs-amber);
	flex: 0 0 auto;
}

.abs-form-privacy {
	margin: 10px 0 0;
	max-width: 62ch;
}

/* Form fields need a visible focus state and a target big enough to hit. */
.abs-enquiry-form .elementor-field-textual {
	min-height: 48px;
	border-radius: 2px;
	border: 1px solid var(--abs-chrome-mid);
}

.abs-enquiry-form .elementor-field-textual:focus-visible {
	outline: 3px solid var(--abs-black);
	outline-offset: 1px;
}

.abs-enquiry-form .elementor-field-label {
	font-family: var(--abs-ui-font);
	font-weight: 600;
	color: var(--abs-black);
}

.abs-enquiry-form .elementor-button {
	min-height: 52px;
}

/* --------------------------------------------------------------------------
   FAQs
   -------------------------------------------------------------------------- */

/* The panel width on /faqs is set by the widget's own `max_width` control in
   inc/designs/faqs.php, NOT here. Elementor writes that control into a per-post
   stylesheet at .elementor-<id> .elementor-element-<id> .abs-faq, which is three
   classes and beats anything this file can reasonably say. A CSS override here
   looks like it works and does not. The measure the control was protecting is
   kept on the answer text instead. */
.abs-faqs-section .abs-faq__a > * {
	max-width: 68ch;
}

.abs-faq__more {
	margin: 8px 0 0;
}

.abs-faq__more a {
	font-family: var(--abs-ui-font);
	font-weight: 600;
	color: var(--abs-red);
}

/* --------------------------------------------------------------------------
   Legal
   -------------------------------------------------------------------------- */

.abs-legal h2 {
	margin-top: 26px;
}

/* The draft notice. Deliberately loud: a legal page that reads as settled when
   nobody qualified has checked it is taken at face value by a visitor and by a
   regulator alike. */
.abs-legal-notice {
	margin: 0 0 8px;
	padding: 14px 16px;
	background: var(--abs-chrome-light);
	border-inline-start: 4px solid var(--abs-amber);
	color: var(--abs-black);
	font-family: var(--abs-font-body);
	font-size: var(--abs-body-size);
	max-width: 68ch;
}

/* Unresolved placeholders should be impossible to miss while proofreading. */
.abs-legal p:has(> mark),
.abs-legal mark {
	background: var(--abs-amber);
	color: var(--abs-black);
	padding: 0 3px;
}


