/* ============================================================================
 * GENERATED FILE. DO NOT EDIT.
 *
 * Assembled by scratch/rebuild_css.sh from, in order:
 *
 *   base.css                23170 bytes
 *   services.css            12764 bytes
 *   services-mobile.css     10938 bytes
 *   sections.css            15360 bytes
 *   motion.css               8026 bytes
 *   pages.css               14756 bytes
 *   media.css               31153 bytes
 *   servicepage.css         19217 bytes
 *   popup.css                4348 bytes
 *
 * Edit the source file, then run scratch/rebuild_css.sh. An edit made here
 * is lost the next time that runs, which has already happened once: three
 * type sizes raised in this file came back at 12, 14 and 15px within the
 * hour. tests/test_gravon_build.php reads every source as well as this
 * file, so the same mistake now fails a suite instead of shipping.
 *
 * Assembled 2026-09-21 08:48 UTC
 * ========================================================================= */

/* ---------- base.css ---------- */
/* ==========================================================================
   GRAVON brand layer
   --------------------------------------------------------------------------
   Every colour below was measured before it was used. The table lives in
   clients/gravon/config/contrast.md. Two rules govern the palette:

   1. The brand green #83c50f reaches only 2.11:1 on white. It therefore never
      carries text and never carries a link. It appears as decorative geometry,
      as an accent rule, and as a button fill that carries ink-coloured text.
   2. Every piece of text clears 4.5:1 and every control edge clears 3:1
      against the surface it actually sits on, not against white in general.

   This file overrides ATheme's semantic tokens. It changes no parent file.
   ========================================================================== */

:root {
	/* ---- Gravon palette, measured 2026-09-06 ---------------------------- */
	--gv-paper: #ffffff;
	--gv-band: #eef2e8;
	--gv-ink: #1c1f20;
	--gv-charcoal: #2f3233;
	--gv-muted: #565b5c;
	--gv-green: #83c50f;
	--gv-green-deep: #4a6b0a;
	--gv-sage: #7d8b6b;

	/* ---- Bridge onto the parent theme's semantic tier ------------------- */
	--color-bg: var(--gv-paper);
	--color-surface: var(--gv-band);
	--color-surface-elevated: #e4ead9;
	--color-surface-subtle: #f6f8f2;
	--color-text: var(--gv-charcoal);
	--color-text-heading: var(--gv-ink);
	--color-text-muted: var(--gv-muted);
	--color-text-inverse: var(--gv-paper);
	--color-primary: var(--gv-ink);
	--color-primary-hover: var(--gv-charcoal);
	--color-secondary: var(--gv-charcoal);
	--color-accent: var(--gv-green-deep);
	--color-border: var(--gv-sage);
	--color-border-subtle: #d7ddcc;
	--color-border-strong: var(--gv-sage);
	--input-border-color: var(--gv-sage);

	--header-bg: rgba(255, 255, 255, 0.92);
	--footer-bg: var(--gv-ink);
	--footer-text: var(--gv-paper);
	--footer-border: #33383a;

	--font-family-arabic: "IBM Plex Sans Arabic", "Tajawal", "Almarai", system-ui, sans-serif;
	--gv-wrap: 1200px;
}

/* ==========================================================================
   Section shells
   ========================================================================== */

.gv-section {
	padding-block: clamp(3.5rem, 2.4rem + 4.4vw, 6.5rem);
	padding-inline: 1.5rem;
	background-color: var(--gv-paper);
}

.gv-section--band {
	background-color: var(--gv-band);
}

.gv-section--ink {
	background-color: var(--gv-ink);
	color: var(--gv-paper);
}

.gv-wrap {
	max-width: var(--gv-wrap);
	margin-inline: auto;
	width: 100%;
}

/* ==========================================================================
   Type
   ========================================================================== */

.gv-eyebrow {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	margin: 0 0 0.9rem;
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	color: var(--gv-green-deep);       /* 6.18:1 on paper, 5.44:1 on the band */
}

/* Decorative rule. It repeats the brand green without carrying any meaning,
   so the 3:1 minimum for interface components does not apply to it. */
.gv-eyebrow::before {
	content: "";
	inline-size: 1.75rem;
	block-size: 3px;
	border-radius: 2px;
	background: var(--gv-green);
	flex: none;
}

.gv-section--ink .gv-eyebrow {
	color: var(--gv-green);            /* on ink the green reaches 7.86:1 */
}

.gv-h2 {
	margin: 0 0 1rem;
	font-size: clamp(1.75rem, 1.35rem + 1.9vw, 2.75rem);
	line-height: 1.2;
	font-weight: 700;
	color: var(--gv-ink);
}

.gv-section--ink .gv-h2 {
	color: var(--gv-paper);
}

.gv-lead {
	margin: 0;
	max-width: 62ch;
	font-size: clamp(1rem, 0.95rem + 0.25vw, 1.1875rem);
	line-height: 1.85;
	color: var(--gv-muted);
}

.gv-section--ink .gv-lead {
	color: #dfe3e2;                    /* 12.81:1 on ink */
}

.gv-head {
	margin-block-end: 2.75rem;
}

.gv-head--center {
	text-align: center;
}

.gv-head--center .gv-eyebrow {
	justify-content: center;
}

.gv-head--center .gv-lead {
	margin-inline: auto;
}

/* ==========================================================================
   Hero
   ========================================================================== */

.gv-hero {
	position: relative;
	overflow: hidden;
	padding-block: clamp(4rem, 2.6rem + 6vw, 8.5rem);
	padding-inline: 1.5rem;
	background:
		radial-gradient(120% 90% at 85% 0%, #f7faf3 0%, var(--gv-paper) 62%);
}

/*
 * Stand-in for photography. Every image on the captured site is gone, so the
 * hero backdrop is built from the geometry of the logo mark: rising bars and a
 * rounded sweep, in the brand green and a pale sage. Purely decorative and
 * marked aria-hidden in the markup.
 */
.gv-hero::before,
.gv-hero::after {
	content: "";
	position: absolute;
	pointer-events: none;
	z-index: 0;
}

.gv-hero::before {
	inline-size: 30rem;
	block-size: 30rem;
	inset-block-start: -9rem;
	inset-inline-start: -7rem;
	border-radius: 42% 58% 55% 45% / 48% 42% 58% 52%;
	background: linear-gradient(135deg, rgba(131, 197, 15, 0.16), rgba(131, 197, 15, 0.03));
}

.gv-hero::after {
	inline-size: 22rem;
	block-size: 22rem;
	inset-block-end: -8rem;
	inset-inline-start: 22%;
	border-radius: 50%;
	background: radial-gradient(circle, rgba(125, 139, 107, 0.14), transparent 68%);
}

.gv-hero > * {
	position: relative;
	z-index: 1;
}

.gv-hero-bars {
	position: absolute;
	inset-block-end: 0;
	inset-inline-end: 4%;
	display: flex;
	align-items: flex-end;
	gap: 0.75rem;
	z-index: 0;
	opacity: 0.5;
}

.gv-hero-bars span {
	display: block;
	inline-size: 2.25rem;
	border-start-start-radius: 6px;
	border-start-end-radius: 6px;
	background: linear-gradient(180deg, var(--gv-green), rgba(131, 197, 15, 0.18));
}

.gv-hero-bars span:nth-child(1) { block-size: 4rem; }
.gv-hero-bars span:nth-child(2) { block-size: 7rem; }
.gv-hero-bars span:nth-child(3) { block-size: 10rem; }
.gv-hero-bars span:nth-child(4) { block-size: 13.5rem; }

.gv-hero-eyebrow {
	margin: 0 0 1.1rem;
	font-size: 1rem;
	font-weight: 600;
	letter-spacing: 0.04em;
	color: var(--gv-green-deep);
}

.gv-h1 {
	margin: 0 0 1.25rem;
	max-width: 26ch;
	font-size: clamp(2.25rem, 1.55rem + 3.1vw, 4rem);
	line-height: 1.15;
	font-weight: 700;
	color: var(--gv-ink);
}

.gv-hero .gv-lead {
	max-width: 60ch;
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.gv-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.875rem;
	margin-block-start: 2rem;
}

.gv-btn {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	padding-block: 0.8125rem;
	padding-inline: 1.6rem;
	border-radius: 999px;
	border: 1px solid transparent;
	font-size: 1rem;
	font-weight: 600;
	line-height: 1.2;
	text-decoration: none;
	transition: background-color 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}

.gv-btn--primary {
	background: var(--gv-ink);
	color: var(--gv-paper);            /* 16.58:1 */
	border-color: var(--gv-ink);
}

.gv-btn--primary:hover,
.gv-btn--primary:focus-visible {
	background: var(--gv-charcoal);
	color: var(--gv-paper);            /* 12.92:1 */
}

.gv-btn--ghost {
	background: transparent;
	color: var(--gv-charcoal);         /* 12.92:1 */
	border-color: var(--gv-charcoal);  /* edge 12.92:1, well past the 3:1 floor */
}

.gv-btn--ghost:hover,
.gv-btn--ghost:focus-visible {
	background: var(--gv-ink);
	color: var(--gv-paper);
	border-color: var(--gv-ink);
}

/* The one place the brand green becomes a surface. Its label is ink, which
   reaches 7.86:1 on it, and the fill reaches 7.86:1 against the ink section. */
.gv-btn--green {
	background: var(--gv-green);
	color: var(--gv-ink);
	border-color: var(--gv-green);
}

.gv-btn--green:hover,
.gv-btn--green:focus-visible {
	background: #93d519;
	color: var(--gv-ink);
	border-color: #93d519;
}

.gv-section--ink .gv-btn--ghost {
	color: var(--gv-paper);
	border-color: #7c8385;
}

.gv-section--ink .gv-btn--ghost:hover,
.gv-section--ink .gv-btn--ghost:focus-visible {
	background: var(--gv-paper);
	color: var(--gv-ink);
	border-color: var(--gv-paper);
}

/* ==========================================================================
   Grids and cards
   ========================================================================== */

.gv-grid {
	display: grid;
	gap: 1.25rem;
}

.gv-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.gv-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.gv-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (max-width: 1023px) {
	.gv-grid--3,
	.gv-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 639px) {
	.gv-grid--2,
	.gv-grid--3,
	.gv-grid--4 { grid-template-columns: minmax(0, 1fr); }
}

.gv-card {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	padding: 1.6rem 1.5rem 1.7rem;
	background: var(--gv-paper);
	border: 1px solid var(--gv-sage);  /* 3.63:1 on paper, 3.20:1 on the band */
	border-radius: 14px;
	text-decoration: none;
	overflow: hidden;
	transition: border-color 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease;
}

/* Decorative edge in the brand green. The card is already identified by its
   outline and its heading, so this bar carries no information of its own. */
.gv-card::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	inline-size: 3px;
	block-size: 100%;
	background: var(--gv-green);
	opacity: 0;
	transition: opacity 0.18s ease;
}

.gv-card:hover,
.gv-card:focus-within {
	border-color: var(--gv-ink);
	transform: translateY(-2px);
	box-shadow: 0 12px 28px rgba(28, 31, 32, 0.09);
}

.gv-card:hover::before,
.gv-card:focus-within::before {
	opacity: 1;
}

.gv-card-kicker {
	margin: 0;
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.07em;
	color: var(--gv-green-deep);
}

.gv-card-title {
	margin: 0;
	font-size: 1.0625rem;
	line-height: 1.5;
	font-weight: 700;
	color: var(--gv-ink);
}

.gv-card-text {
	margin: 0;
	font-size: 1rem;
	line-height: 1.8;
	color: var(--gv-muted);            /* 6.89:1 on the white card */
}

/* A compact card used for the sector list. */
.gv-chip {
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	padding: 1.15rem 1.25rem;
	background: var(--gv-paper);
	border: 1px solid var(--gv-sage);
	border-radius: 12px;
}

.gv-chip strong {
	font-size: 1rem;
	color: var(--gv-ink);
}

.gv-chip span {
	font-size: 1rem;
	line-height: 1.7;
	color: var(--gv-muted);
}

/* The four reasons, as a plain numbered list rather than four identical cards. */
.gv-reasons {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1.5rem 2.5rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

@media (max-width: 767px) {
	.gv-reasons { grid-template-columns: minmax(0, 1fr); }
}

.gv-reasons li {
	position: relative;
	padding-inline-start: 2.75rem;
	font-size: 1.0625rem;
	line-height: 1.8;
	color: var(--gv-charcoal);
}

.gv-reasons li::before {
	content: "";
	position: absolute;
	inset-inline-start: 0;
	inset-block-start: 0.65rem;
	inline-size: 1.75rem;
	block-size: 3px;
	border-radius: 2px;
	background: var(--gv-green);
}

/* ==========================================================================
   Header and footer built in the Theme Builder
   ========================================================================== */

.gv-header {
	background: rgba(255, 255, 255, 0.94);
	backdrop-filter: blur(10px);
	-webkit-backdrop-filter: blur(10px);
	border-block-end: 1px solid #dfe4d6;
	position: sticky;
	inset-block-start: 0;
	z-index: 100;
}

.gv-header-inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	max-width: var(--gv-wrap);
	margin-inline: auto;
	padding-block: 0.85rem;
	padding-inline: 1.5rem;
}

.gv-logo {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
}

.gv-logo img {
	display: block;
	block-size: 42px;
	inline-size: auto;
}

.gv-footer {
	background: var(--gv-ink);
	color: #dfe3e2;
	padding-block: clamp(2.75rem, 2rem + 3vw, 4.5rem) 0;
	padding-inline: 1.5rem;
}

.gv-footer a {
	color: #dfe3e2;                    /* 12.81:1 on ink */
	text-decoration: none;
}

.gv-footer a:hover,
.gv-footer a:focus-visible {
	color: var(--gv-paper);
	text-decoration: underline;
}

.gv-footer-grid {
	display: grid;
	/* Five children: the brand block, three link columns and contact. */
	grid-template-columns: 1.5fr 1fr 1fr 1fr 1.1fr;
	gap: 2.5rem;
	max-width: var(--gv-wrap);
	margin-inline: auto;
}

@media (max-width: 1023px) {
	.gv-footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 639px) {
	.gv-footer-grid { grid-template-columns: minmax(0, 1fr); }
}

.gv-footer h3 {
	margin: 0 0 0.9rem;
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	color: var(--gv-green);            /* 7.86:1 on ink */
}

.gv-footer ul {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
	font-size: 1rem;
}

/* Every footer link is a 44px target. They measured 20px tall, which fails
   SC 2.5.5 Target Size (Enhanced, AAA): its inline exception covers a target
   "in a sentence or block of text", and the glossary defines a block of text
   as more than one sentence, so a column of link labels is not exempt.

   They did NOT fail SC 2.5.8 (Minimum, AA). That criterion asks for 24px but
   grants a spacing exception when a 24px circle centred on each undersized
   target misses its neighbours, which needs 24px between centres. At 20px
   tall with a 0.55rem gap the centres sat 28.8px apart, so the old footer
   conformed at AA. The fix here is the AAA bar, taken deliberately. */
.gv-footer ul a {
	display: flex;
	align-items: center;
	min-block-size: 44px;
}

.gv-footer-logo img {
	display: block;
	block-size: 40px;
	inline-size: auto;
	margin-block-end: 1rem;
	/* The placeholder logo is a crop of a printed sheet, so its dark half
	   disappears on ink. Lifting it to white keeps the mark legible until the
	   client supplies vector artwork with a reversed variant. */
	filter: brightness(0) invert(1);
}

.gv-footer-about {
	margin: 0;
	font-size: 1rem;
	line-height: 1.85;
	color: #c9cecd;                    /* 10.42:1 on ink */
	max-width: 44ch;
}

.gv-footer-bottom {
	max-width: var(--gv-wrap);
	margin: 2.75rem auto 0;
	padding-block: 1.4rem;
	border-block-start: 1px solid #33383a;
	display: flex;
	flex-wrap: wrap;
	gap: 1rem;
	justify-content: space-between;
	font-size: 0.875rem;
	color: #c9cecd;
}

/* ==========================================================================
   Focus, motion and small screens
   ========================================================================== */

.gv-btn:focus-visible,
.gv-card:focus-visible,
.gv-footer a:focus-visible,
.gv-header a:focus-visible {
	outline: 3px solid var(--gv-ink);
	outline-offset: 3px;
}

.gv-section--ink .gv-btn:focus-visible,
.gv-footer a:focus-visible {
	outline-color: var(--gv-paper);
}

@media (prefers-reduced-motion: reduce) {
	.gv-card,
	.gv-btn {
		transition: none;
	}

	.gv-card:hover,
	.gv-card:focus-within {
		transform: none;
	}
}

@media (max-width: 767px) {
	.gv-hero-bars {
		opacity: 0.28;
		inset-inline-end: -2rem;
	}

	.gv-hero-bars span {
		inline-size: 1.6rem;
	}
}

/* ==========================================================================
   Elementor plumbing
   --------------------------------------------------------------------------
   The sections are Elementor containers holding one HTML widget each. Their
   own spacing is stripped here so the brand rules above own every dimension.
   ========================================================================== */

/* Elementor's own container element. Its spacing is zeroed so the brand
   rules above own every dimension on the page. */
.elementor-location-header > .e-con,
.elementor-location-footer > .e-con,
.site-main--elementor .elementor > .e-con {
	--padding-block-start: 0;
	--padding-block-end: 0;
	--padding-inline-start: 0;
	--padding-inline-end: 0;
	max-width: none;
	width: 100%;
}

.elementor-location-header .elementor-widget-html,
.elementor-location-footer .elementor-widget-html,
.site-main--elementor .elementor-widget-html {
	width: 100%;
}

/* The canvas the Elementor content sits in. */
.site-main--elementor {
	padding: 0;
}

/* ==========================================================================
   Header navigation
   ========================================================================== */

.gv-nav ul {
	display: flex;
	align-items: center;
	gap: 1.6rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.gv-nav a {
	font-size: 1rem;
	font-weight: 600;
	color: var(--gv-charcoal);         /* 12.92:1 on the header ground */
	text-decoration: none;
	white-space: nowrap;
	padding-block: 0.35rem;
	border-block-end: 2px solid transparent;
	transition: color 0.15s ease, border-color 0.15s ease;
}

.gv-nav a:hover,
.gv-nav a:focus-visible {
	color: var(--gv-ink);
	border-block-end-color: var(--gv-green);   /* decorative underline */
}

.gv-header-cta {
	white-space: nowrap;
}

/* ---- the toggle, shown only when the row cannot hold the menu ---------- */

.gv-burger {
	display: none;
	flex-direction: column;
	justify-content: center;
	gap: 5px;
	inline-size: 44px;
	block-size: 44px;
	padding: 0 10px;
	background: transparent;
	border: 1px solid var(--gv-charcoal);      /* edge 12.92:1 */
	border-radius: 10px;
	cursor: pointer;
}

.gv-burger span {
	display: block;
	/* As flex items these have no intrinsic width, so an explicit one is
	   what makes them visible at all. */
	inline-size: 22px;
	align-self: center;
	block-size: 2px;
	background: var(--gv-ink);
	border-radius: 2px;
}

.gv-nav-panel {
	display: none;
	border-block-start: 1px solid #dfe4d6;
	background: var(--gv-paper);
	padding-block: 1rem 1.25rem;
	padding-inline: 1.5rem;
}

.gv-nav-panel[hidden] {
	display: none;
}

.gv-nav-panel ul {
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
	margin: 0 auto;
	padding: 0;
	max-width: var(--gv-wrap);
	list-style: none;
}

.gv-nav-panel a {
	display: flex;
	align-items: center;
	min-block-size: 44px;
	padding-block: 0.7rem;
	font-size: 1rem;
	font-weight: 600;
	color: var(--gv-charcoal);
	text-decoration: none;
	border-block-end: 1px solid #e7ebdf;
}

.gv-nav-panel .gv-btn {
	margin-block-start: 0.75rem;
	border-block-end: 0;
	justify-content: center;
	color: var(--gv-paper);
}

@media (max-width: 1100px) {
	.gv-nav,
	.gv-header-cta {
		display: none;
	}

	.gv-burger {
		display: flex;
	}

	.gv-nav-panel:not([hidden]) {
		display: block;
	}
}

@media (max-width: 480px) {
	.gv-logo img {
		block-size: 34px;
	}

	.gv-header-inner {
		padding-inline: 1rem;
	}
}

/* ==========================================================================
   Odds and ends
   ========================================================================== */

.gv-actions--center {
	justify-content: center;
}

.gv-head--center .gv-lead {
	margin-inline: auto;
}

/* The closing section centres its own contents. */
.gv-section--ink .gv-wrap {
	text-align: center;
}

.gv-section--ink .gv-lead {
	margin-inline: auto;
}

/* Cards are links; the whole card takes focus, so remove the inner outline. */
.gv-card:focus {
	outline: none;
}

.gv-card:focus-visible {
	outline: 3px solid var(--gv-ink);
	outline-offset: 3px;
}

/* Long Arabic service names must not spill out of a card. */
.gv-card-title,
.gv-chip strong {
	overflow-wrap: anywhere;
}

/* --------------------------------------------------------------------------
   The build credit
   --------------------------------------------------------------------------
   A quiet line under the client's own copyright, centred across the footer.

   Measured on the footer surface #1c1f20:
     the client's copyright row   #c9cecd   10.42:1
     this line                    #9aa3a1    6.42:1

   Both clear the 4.5:1 a body text needs, and the client's is the brighter of
   the two by a factor of 1.6. It is not made smaller as well: 14px is the type
   floor this build asserts, and dropping under it to look subordinate would
   trade one rule for another. Colour and position carry the subordination.

   flex-basis of 100% gives it its own row inside the flex container the
   copyright shares, so it centres across the whole footer rather than
   competing for space in the space-between row above it.
   -------------------------------------------------------------------------- */

.gv-credit {
	flex: 0 0 100%;
	margin: 0.35rem 0 0;
	text-align: center;
	font-size: 0.875rem;
	color: #9aa3a1;
}

.gv-credit a {
	/* 44px, like every other footer link. An inline-flex box is what lets a
	   single line of 14px text reach that height without padding that would
	   push the line away from the copyright it belongs under. */
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-block-size: 44px;
	padding-inline: 0.5rem;
	color: #9aa3a1;
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.gv-credit a:hover,
.gv-credit a:focus-visible {
	color: var(--gv-paper);
}

.gv-credit a:focus-visible {
	outline: 3px solid var(--gv-paper);
	outline-offset: 2px;
	border-radius: 4px;
}

/* ==========================================================================
   The second language tree.

   The font token is named --font-family-arabic by the parent theme and that
   name is not going to change, so the English tree overrides its value rather
   than introducing a second token every rule would have to learn. The value
   matters: the Arabic stack falls back to Tajawal and Almarai, which carry
   little or no Latin, so Latin text on a machine without IBM Plex would land
   on an Arabic face. The English stack falls back to Latin faces only.

   IBM Plex Sans Arabic stays first because its Latin glyphs are IBM Plex Sans,
   the same design, and the browser has already downloaded the Latin subsets of
   the three weights this site uses. Naming a separate Latin family would cost
   another set of downloads for a face the reader already has.
   ========================================================================== */

html[lang^="en"] {
	--font-family-arabic:
		"IBM Plex Sans Arabic", "IBM Plex Sans", -apple-system, BlinkMacSystemFont,
		"Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

.gv-lang {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-block-size: 44px;               /* 2.5.5 */
	min-inline-size: 44px;
	padding-inline: 0.6rem;
	font-size: 0.9375rem;
	font-weight: 600;
	text-decoration: none;
	border-radius: 8px;
	white-space: nowrap;
}

.gv-lang--header {
	color: var(--gv-charcoal);          /* 12.92:1 on the header ground */
	border: 1px solid var(--gv-sage);   /* 3.63:1, so the control has an edge */
}

.gv-lang--header:hover,
.gv-lang--header:focus-visible {
	background: var(--gv-mist);
	color: var(--gv-ink);
}

.gv-lang--footer {
	color: inherit;                     /* #c9cecd on --gv-ink = 10.42:1 */
	text-decoration: underline;
	text-underline-offset: 3px;
	padding-inline: 0;
	min-inline-size: 0;
}

.gv-lang--footer:hover,
.gv-lang--footer:focus-visible {
	color: #fff;
}

/* ---------- services.css ---------- */

/* ==========================================================================
   Services section
   --------------------------------------------------------------------------
   The visual language is taken from the client's own mark rather than applied
   over it. The mark is a staircase of rising bars pierced by an arrow; the
   arrow's shaft was measured off the artwork at 51.3 degrees from horizontal
   and the bar tops at 46.8 degrees. 51.3 is used wherever the angle is small
   enough to read as itself: the wedge that sweeps into a card, the rule beside
   the section link, the drifting mark in the background.

   A full-width edge cannot use it. At 51.3 degrees a cut across a 1200px
   section drops 1497px, which is taller than the section. The top and bottom
   edges therefore share only the direction, at a shallow angle, and that is
   a deliberate compromise rather than an oversight.

   Direction: the mark rises to the upper right in its own orientation, so on
   an Arabic page it rises to the upper left. --gv-rise carries the sign and
   every diagonal below is written in terms of it.
   ========================================================================== */

:root {
	--gv-rise: -1;            /* right-to-left: rises to the left */
	--gv-angle: 51.3deg;      /* measured off the arrow shaft */
	--gv-edge: 5vw;           /* section edge: direction only, see the note above */
}

[dir="ltr"] {
	--gv-rise: 1;
}

/* ==========================================================================
   Section shell
   ========================================================================== */

/*
 * The selector is long on purpose, and the length is the fix.
 *
 * This class sits on an Elementor container, whose own rule carries
 * `.elementor-element.e-con`. A single class loses to that, so for as long as
 * this rule read `.gv-services` the padding below did nothing at all: measured
 * on the live site, padding-inline resolved to 0px where it asks for 24px, and
 * padding-block to 0px where it asks for 80px and 64px. The clip-path on the
 * same rule DID apply, because nothing competes for it.
 *
 * That combination is what produced the client's report. The section draws a
 * diagonal across its own bottom edge and relies on padding to keep content
 * clear of it. With the padding silently gone, three things followed from one
 * cause: the heading and its eyebrow sat 2.5px from the screen edge instead of
 * 24, the service cards touched the edge, and the compact-layout button at the
 * foot of the section landed exactly on the bottom edge, where the diagonal
 * sliced up to 35px off a 52px control and left its label half outside its own
 * shape.
 *
 * The same trap is already documented forty lines below, where
 * `.gv-svc-head-cell` had to be matched at Elementor's specificity for the
 * identical reason. It was fixed for the cell and not for the section.
 *
 * Both selectors are kept: the long one wins on an Elementor container, and
 * the bare class still applies if this markup is ever used outside Elementor.
 */
.elementor .e-con.gv-services,
.gv-services {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	background: var(--gv-band);
	/* Deliberately not the same block padding as its neighbours: the vertical
	   rhythm of the page comes from sections that differ, not sections that
	   repeat. */
	padding-block: clamp(5rem, 3.2rem + 7vw, 9rem) clamp(4rem, 2.6rem + 5.5vw, 7.5rem);
	padding-inline: 1.5rem;
	margin-block: calc(var(--gv-edge) * -1);
	clip-path: polygon(0 var(--gv-edge), 100% 0, 100% calc(100% - var(--gv-edge)), 0 100%);
}

[dir="ltr"] .gv-services {
	clip-path: polygon(0 0, 100% var(--gv-edge), 100% 100%, 0 calc(100% - var(--gv-edge)));
}

/* The mark's staircase, enlarged and faded, drifting behind the cards. It is
   decoration: it carries no information and identifies no control. */
.gv-svc-drift-cell {
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	inline-size: 100%;
	block-size: 100%;
	z-index: -1;
	pointer-events: none;
}

.gv-svc-drift {
	position: absolute;
	inset-block-end: -2rem;
	inset-inline-end: 4%;
	display: flex;
	align-items: flex-end;
	gap: 1.1rem;
	opacity: 0.42;
}

.gv-svc-drift span {
	display: block;
	inline-size: 3.25rem;
	border-start-start-radius: 8px;
	border-start-end-radius: 8px;
	background: linear-gradient(180deg, rgba(131, 197, 15, 0.5), rgba(131, 197, 15, 0.06));
}

/* Four bars of rising height, the proportion taken from the mark. */
.gv-svc-drift span:nth-child(1) { block-size: 5rem; }
.gv-svc-drift span:nth-child(2) { block-size: 8.5rem; }
.gv-svc-drift span:nth-child(3) { block-size: 12.5rem; }
.gv-svc-drift span:nth-child(4) { block-size: 17rem; }

/* ==========================================================================
   Header, split 7 and 5
   ========================================================================== */

.gv-services > .e-con-inner,
.gv-services {
	--gv-inner: min(100%, var(--gv-wrap));
}

/* Elementor caps every widget inside a container with
   .elementor.elementor .e-con > .elementor-widget { max-width: 100% }
   which carries four classes. A shorter selector loses to it silently: the
   header measured 1392px inside a 1200px column until this matched it. */
.elementor .e-con > .gv-svc-head-cell.elementor-widget {
	max-inline-size: var(--gv-wrap);
	margin-inline: auto;
	inline-size: 100%;
}

.gv-services > .gv-svc-grid {
	max-inline-size: var(--gv-wrap);
	margin-inline: auto;
	inline-size: 100%;
}

.gv-svc-head {
	display: grid;
	grid-template-columns: 7fr 5fr;
	align-items: end;
	gap: 1.5rem 3rem;
	margin-block-end: clamp(2.5rem, 1.6rem + 3vw, 4.5rem);
}

.gv-svc-head-aside {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 0.9rem;
	padding-block-end: 0.4rem;
}

/* The section link carries the same rising glyph as the cards, so the angle
   sits on something that means something instead of floating beside it. */
.gv-svc-head-aside .gv-btn svg {
	flex: none;
	transform: scaleX(var(--gv-rise));
	transition: transform 0.22s ease;
}

.gv-svc-head-aside .gv-btn:hover svg,
.gv-svc-head-aside .gv-btn:focus-visible svg {
	transform: scaleX(var(--gv-rise)) translate(3px, -3px);
}

@media (max-width: 767px) {
	.gv-svc-head {
		grid-template-columns: minmax(0, 1fr);
		align-items: start;
	}

	.gv-svc-head-aside {
		justify-content: flex-start;
	}

}

/* ==========================================================================
   Type scale
   --------------------------------------------------------------------------
   The gap between the section heading and the body text is widened on purpose.
   At the previous scale the heading topped out at 2.75rem against 0.9375rem of
   body copy, a ratio of 2.9. It now reaches 3.5rem, a ratio of 3.7.
   ========================================================================== */

.gv-h2--wide {
	font-size: clamp(2rem, 1.3rem + 3vw, 3.5rem);
	line-height: 1.12;
	letter-spacing: -0.01em;
	margin-block-end: 0;
	max-inline-size: 18ch;
}

/* ==========================================================================
   The grid: 7 and 5, then 5 and 7, then 7 and 5
   ========================================================================== */

.gv-svc-grid.e-con,
.gv-svc-grid > .e-con-inner {
	display: grid;
	grid-template-columns: repeat(12, minmax(0, 1fr));
	gap: 1.25rem;
	align-items: stretch;
}

.gv-svc-cell:nth-child(1) { grid-column: span 7; }
.gv-svc-cell:nth-child(2) { grid-column: span 5; }
.gv-svc-cell:nth-child(3) { grid-column: span 5; }
.gv-svc-cell:nth-child(4) { grid-column: span 7; }
.gv-svc-cell:nth-child(5) { grid-column: span 7; }
.gv-svc-cell:nth-child(6) { grid-column: span 5; }

/* Within each row the card further along the reading direction sits higher,
   so every row carries the same rise as the mark. A transform is used rather
   than a margin so the grid rows keep their own heights. */
.gv-svc-cell:nth-child(2n) {
	transform: translateY(-2.25rem);
}

@media (max-width: 1023px) {
	.gv-svc-cell:nth-child(n) {
		grid-column: span 6;
	}

	.gv-svc-cell:nth-child(2n) {
		transform: none;
	}
}

@media (max-width: 639px) {
	.gv-svc-cell:nth-child(n) {
		grid-column: span 12;
	}
}

/* ==========================================================================
   Cards
   ========================================================================== */

.gv-svc-cell {
	display: flex;
}

.gv-svc-card {
	position: relative;
	isolation: isolate;
	display: flex;
	flex-direction: column;
	gap: 0.55rem;
	inline-size: 100%;
	padding: 1.75rem 1.6rem 1.5rem;
	background: var(--gv-paper);
	border: 1px solid var(--gv-sage);   /* 3.63:1 on paper, 3.20:1 on the band */
	border-radius: 16px;
	text-decoration: none;
	overflow: hidden;
	transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.gv-svc-card--feature {
	padding: 2.25rem 2rem 1.9rem;
	gap: 0.7rem;
}

/* The wedge is the arrow's angle at a size where the angle reads. It is
   hidden until the card is hovered or focused, so the green appears on
   interaction rather than sitting on the page permanently. */
.gv-svc-wedge {
	position: absolute;
	inset-block-end: 0;
	inset-inline-start: 0;
	inline-size: 9rem;
	block-size: 9rem;
	z-index: -1;
	background: linear-gradient(
		calc(90deg - var(--gv-angle) * var(--gv-rise)),
		rgba(131, 197, 15, 0.22) 0 42%,
		transparent 42%
	);
	opacity: 0;
	transform: translate(calc(var(--gv-rise) * 1.5rem), 1.5rem);
	transition: opacity 0.22s ease, transform 0.22s ease;
}

.gv-svc-kicker {
	margin: 0;
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.07em;
	color: var(--gv-green-deep);        /* 6.18:1 on the white card */
}

.gv-svc-title {
	margin: 0;
	font-size: 1.1875rem;
	line-height: 1.45;
	font-weight: 700;
	color: var(--gv-ink);               /* 16.58:1 */
	overflow-wrap: anywhere;
}

.gv-svc-card--feature .gv-svc-title {
	font-size: clamp(1.375rem, 1.15rem + 0.9vw, 1.75rem);
	line-height: 1.3;
}

.gv-svc-text {
	margin: 0 0 0.35rem;
	font-size: 1rem;
	line-height: 1.8;
	color: var(--gv-muted);             /* 6.89:1 */
}

.gv-svc-card--feature .gv-svc-text {
	font-size: 1rem;
	max-inline-size: 46ch;
}

.gv-svc-more {
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	margin-block-start: auto;
	padding-block-start: 0.6rem;
	font-size: 1rem;
	font-weight: 600;
	color: var(--gv-charcoal);          /* 12.92:1 */
}

.gv-svc-more svg {
	flex: none;
	/* The glyph is drawn rising to the right; in a right-to-left column it has
	   to be mirrored so it rises to the left with everything else. */
	transform: scaleX(var(--gv-rise));
	transition: transform 0.22s ease;
}

/* ---- interaction ------------------------------------------------------- */

.gv-svc-card:hover,
.gv-svc-card:focus-visible {
	transform: translateY(-4px);
	border-color: var(--gv-ink);        /* 16.58:1 */
	box-shadow: 0 16px 34px rgba(28, 31, 32, 0.10);
}

.gv-svc-card:hover .gv-svc-wedge,
.gv-svc-card:focus-visible .gv-svc-wedge {
	opacity: 1;
	transform: translate(0, 0);
}

.gv-svc-card:hover .gv-svc-more svg,
.gv-svc-card:focus-visible .gv-svc-more svg {
	transform: scaleX(var(--gv-rise)) translate(3px, -3px);
}

.gv-svc-card:focus-visible {
	outline: 3px solid var(--gv-ink);
	outline-offset: 3px;
}

/* ==========================================================================
   Motion
   --------------------------------------------------------------------------
   The cards use Elementor's own entrance animation with a staggered delay.
   Elementor hides an animated element with .elementor-invisible until its
   observer fires, which means a script failure would leave the copy hidden
   for good. The failsafe below reveals it regardless after two seconds, so
   the content never depends on an event that may not arrive.
   ========================================================================== */

.gv-services .elementor-invisible {
	/* Elementor's observer normally fires well inside 300ms. 900ms leaves a
	   clear margin while keeping the worst case, a script that never runs,
	   under a second rather than the two it was. */
	animation: gv-failsafe-reveal 1ms linear 900ms forwards;
}

@keyframes gv-failsafe-reveal {
	to {
		visibility: visible;
	}
}

@media (prefers-reduced-motion: reduce) {
	.gv-services .elementor-invisible {
		visibility: visible !important;
		animation: none !important;
	}

	.gv-services [class*="animated"],
	.gv-services .animated {
		animation: none !important;
		opacity: 1 !important;
		transform: none !important;
	}

	.gv-svc-card,
	.gv-svc-wedge,
	.gv-svc-more svg {
		transition: none !important;
	}

	.gv-svc-card:hover,
	.gv-svc-card:focus-visible {
		transform: none;
	}

	.gv-svc-drift {
		transform: none;
	}
}

/* ---------- services-mobile.css ---------- */

/* ==========================================================================
   Services: the compact layout
   --------------------------------------------------------------------------
   Written for one column first, not derived from the wide grid by collapsing
   it. The measurement that prompted this: at 375px the seven-and-five
   alternation reported span 12 on all six cards and the staircase reported
   flat on all six, so two of the section's devices were simply absent, and
   the hover layer never fires on a touch screen at all.

   What the column gets instead: a continuous vertical line threading the
   cards, the rising diagonal as a graded edge that strengthens card by card,
   an icon as the anchor for each one, and the brand green present in the
   resting state rather than waiting for a pointer that will not arrive.
   ========================================================================== */

:root {
	/* The icon tile. Deep green on this reads 5.36:1, so the mark is present
	   in the resting state and the glyph is still legible. */
	--gv-tint: #e8f3d4;
}

/* ==========================================================================
   Icons
   ========================================================================== */

.gv-svc-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 46px;
	block-size: 46px;
	border-radius: 13px;
	background: var(--gv-tint);
	color: var(--gv-green-deep);       /* 5.36:1 on the tile */
	margin-block-end: 0.9rem;
	flex: none;
	transition: background-color 0.22s ease, color 0.22s ease;
}

/* An icon that carries a direction rises the way the mark rises, which is
   towards the left once the page is right-to-left. */
.gv-svc-icon--rises svg {
	transform: scaleX(var(--gv-rise));
}

.gv-svc-card:hover .gv-svc-icon,
.gv-svc-card:focus-visible .gv-svc-icon {
	background: var(--gv-green);
	color: var(--gv-ink);              /* 7.86:1 on the brand green */
}

/* ==========================================================================
   Heavier cards, both layouts
   ========================================================================== */

.gv-svc-card {
	padding: 2rem 1.85rem 1.7rem;
	border-radius: 18px;
	box-shadow: 0 1px 2px rgba(28, 31, 32, 0.04);
}

.gv-svc-card--feature {
	padding: 2.4rem 2.2rem 2rem;
}

.gv-svc-title {
	font-size: 1.3125rem;              /* 21px, was 19 */
	line-height: 1.4;
}

.gv-svc-card--feature .gv-svc-title {
	font-size: clamp(1.5rem, 1.2rem + 1.1vw, 1.9375rem);
}

.gv-svc-card:hover,
.gv-svc-card:focus-visible {
	box-shadow: 0 18px 38px rgba(28, 31, 32, 0.12);
}

/* The button under the grid belongs to the compact layout; the wide layout
   carries the same link beside the heading. */
.gv-svc-all-cell {
	display: none;
}

/* ==========================================================================
   One column
   ========================================================================== */

@media (max-width: 767px) {

	/*
	 * Matched to Elementor's specificity for the reason spelled out in
	 * services.css: a bare .gv-services loses to .elementor-element.e-con and
	 * this padding was being discarded.
	 *
	 * The block-end is a max() rather than a plain clamp(), and that is the
	 * part that actually fixes the cut button. The section's bottom edge is a
	 * diagonal that rises var(--gv-edge) from one side to the other, so the
	 * last element in the section has to sit at least that far above the
	 * bottom or the diagonal takes a bite out of it. Before this, the compact
	 * layout put a 52px button flush against the bottom and the diagonal
	 * removed 35px of it.
	 *
	 * Leaving that to whatever the clamp happened to produce is how it broke.
	 * The floor is now stated: the edge, plus a real gap.
	 */
	.elementor .e-con.gv-services,
	.gv-services {
		padding-block:
			clamp(3.25rem, 2.4rem + 4vw, 5rem)
			max(clamp(2.75rem, 2rem + 3.5vw, 4rem), calc(var(--gv-edge) + 1.5rem));
	}

	/* The heading link is replaced by a full-width button after the cards, so
	   the reader meets it having seen what it leads to. */
	.gv-svc-head-aside {
		display: none;
	}

	.gv-svc-head {
		margin-block-end: 1.75rem;
	}

	.gv-h2--wide {
		font-size: clamp(1.75rem, 1.4rem + 2.2vw, 2.25rem);
		max-inline-size: 16ch;
	}

	.gv-svc-all-cell {
		display: block;
		max-inline-size: var(--gv-wrap);
		margin-inline: auto;
		inline-size: 100%;
		margin-block-start: 1.5rem;
	}

	.gv-svc-all {
		inline-size: 100%;
		justify-content: center;
		min-block-size: 52px;
	}

	.gv-svc-grid.e-con {
		gap: 1.4rem;
	}

	/* The three the compact layout does not keep. The child theme's script
	   detaches them below this width and puts them back above it, so a reader
	   without JavaScript sees all six rather than none. */
	.gv-svc-cell--extra {
		display: none;
	}

	.gv-svc-card,
	.gv-svc-card--feature {
		padding: 1.65rem 1.5rem 1.45rem;
	}

	/* The feature card's extra weight is dropped here. At this width it came
	   to eighty-four pixels of height for a distinction nobody could see. */
	.gv-svc-card--feature .gv-svc-title {
		font-size: 1.3125rem;
	}

	.gv-svc-card--feature .gv-svc-text {
		font-size: 1rem;
	}

	.gv-svc-title {
		font-size: 1.25rem;
	}

	/* ---- the thread ---------------------------------------------------- */

	/* A line running from one card's icon to the next, so three separate
	   boxes read as one sequence. It sits in the gap, aligned with the icon
	   centre, and is drawn in the same tint as the tile. */
	.gv-svc-cell {
		position: relative;
	}

	.gv-svc-cell:not(:last-of-type)::after {
		content: "";
		position: absolute;
		inset-block-start: 100%;
		inset-inline-start: calc(1.5rem + 22px);
		inline-size: 2px;
		block-size: 1.4rem;
		background: var(--gv-tint);
	}

	/* ---- the rise ------------------------------------------------------ */

	/* The wedge stops waiting for a pointer. In the column it becomes a fixed
	   edge on the start side, and it strengthens from the first card to the
	   third, which is the staircase read vertically. */
	.gv-svc-wedge {
		inset-block-start: 0;
		inset-block-end: auto;
		inline-size: 4px;
		block-size: 100%;
		background: var(--gv-green);
		opacity: 1;
		transform: none;
		z-index: 0;
	}

	.gv-svc-cell:nth-of-type(1) .gv-svc-wedge { opacity: 0.35; }
	.gv-svc-cell:nth-of-type(2) .gv-svc-wedge { opacity: 0.65; }
	.gv-svc-cell:nth-of-type(3) .gv-svc-wedge { opacity: 1; }

	.gv-svc-card:hover .gv-svc-wedge,
	.gv-svc-card:focus-visible .gv-svc-wedge {
		transform: none;
	}

	/* The icon leads the card rather than sitting above it. */
	.gv-svc-card {
		display: grid;
		grid-template-columns: 46px minmax(0, 1fr);
		grid-template-areas:
			"icon kicker"
			"icon title"
			"text text"
			"more more";
		column-gap: 0.9rem;
		row-gap: 0.3rem;
		align-items: center;
	}

	.gv-svc-icon  { grid-area: icon; margin-block-end: 0; align-self: start; }
	.gv-svc-kicker { grid-area: kicker; align-self: end; }
	.gv-svc-title { grid-area: title; align-self: start; }
	.gv-svc-text  { grid-area: text; margin-block-start: 0.6rem; }
	.gv-svc-more  { grid-area: more; }

	/* ---- the section edge ---------------------------------------------- */

	/* 5vw across 375px is a nineteen pixel drop, which measures 2.9 degrees
	   and reads as a printing error rather than a cut. In one column the
	   angle has less width to work with, so it takes more of it. */
	.gv-services {
		--gv-edge: 9vw;
	}

	/* ---- the hero's bars ------------------------------------------------ */

	/* Measured at left=-32, so a third of them sat outside the frame. */
	.gv-hero-bars {
		inset-inline-end: 1.25rem;
		opacity: 0.34;
	}

	.gv-hero-bars span {
		inline-size: 1.5rem;
	}
}

@media (prefers-reduced-motion: reduce) {
	.gv-svc-icon {
		transition: none !important;
	}
}

/* ==========================================================================
   Footer disclosures
   --------------------------------------------------------------------------
   The footer measured 1221px at 375, most of it link groups. Each group is a
   native <details>, which needs no script to open and is keyboard operable on
   its own. It ships open; the script closes it only in the compact layout.
   The contact block is not a disclosure, because a phone number and a
   WhatsApp link are the parts of a footer a phone user actually wants.
   ========================================================================== */

.gv-footer-group {
	min-inline-size: 0;
}

.gv-footer-group > summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.75rem;
	cursor: pointer;
	list-style: none;
	min-block-size: 44px;
}

.gv-footer-group > summary::-webkit-details-marker {
	display: none;
}

.gv-footer-group > summary h3 {
	margin: 0;
}

.gv-footer-chev {
	display: none;
	color: var(--gv-green);
	transition: transform 0.2s ease;
}

.gv-footer-group[open] .gv-footer-chev {
	transform: rotate(180deg);
}

.gv-footer-group > summary:focus-visible {
	outline: 3px solid var(--gv-paper);
	outline-offset: 3px;
	border-radius: 6px;
}

@media (max-width: 767px) {
	.gv-footer-grid {
		gap: 0.25rem;
	}

	.gv-footer-brand {
		margin-block-end: 1.25rem;
	}

	.gv-footer-group {
		border-block-start: 1px solid #33383a;
	}

	.gv-footer-group > summary {
		padding-block: 0.35rem;
	}

	.gv-footer-chev {
		display: inline-flex;
	}

	.gv-footer-contact {
		border-block-start: 1px solid #33383a;
		padding-block-start: 0.9rem;
		margin-block-start: 0.5rem;
	}

	.gv-footer-address {
		min-block-size: 44px;
		display: flex;
		align-items: center;
	}
}

@media (prefers-reduced-motion: reduce) {
	.gv-footer-chev {
		transition: none !important;
	}
}

/* ==========================================================================
   The services index
   --------------------------------------------------------------------------
   The compact homepage shows three services and sends the reader here. The
   page reuses the card the homepage uses, so the two read as one system.
   ========================================================================== */

.gv-hero--page {
	padding-block: clamp(3rem, 2.2rem + 3.5vw, 5.5rem) clamp(2.25rem, 1.8rem + 2vw, 3.5rem);
}

.gv-h1--page {
	max-inline-size: 22ch;
	font-size: clamp(2rem, 1.5rem + 2.4vw, 3.25rem);
}

.gv-sol-group-title {
	font-size: clamp(1.375rem, 1.2rem + 0.8vw, 1.75rem);
	margin-block-end: 1.5rem;
	padding-block-end: 0.75rem;
	border-block-end: 1px solid var(--gv-sage);   /* 3.63:1 on paper */
}

.gv-sol-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1.25rem;
}

@media (max-width: 767px) {
	.gv-sol-grid {
		grid-template-columns: minmax(0, 1fr);
		gap: 1rem;
	}

	.gv-sol-group {
		padding-block: 2.5rem;
	}
}

/* A service whose icon is not drawn yet keeps the tile, so the cards stay in
   rhythm instead of one of them starting higher than the rest. */
.gv-svc-icon--blank {
	opacity: 0.55;
}

/* ---------- sections.css ---------- */

/* ==========================================================================
   Section devices
   --------------------------------------------------------------------------
   Each section carries one device of its own. What they share is the rising
   diagonal measured off the client's mark at 51.3 degrees, the palette, and
   the type scale. What they do not share is the ornament: repeating the
   services section's vertical thread everywhere would turn a device into
   wallpaper.

      about        a stepped block, the lead inset by one step
      methodology  the narrow one, short measure and centred
      industries   dense tiles with a corner cut at the mark's angle
      why          oversized ghost numerals
      use cases    a pull-quote card with a cut top corner
      closing      the diagonal as a top edge
   ========================================================================== */

/* ==========================================================================
   About: the step
   ========================================================================== */

.gv-about {
	padding-block: clamp(3.5rem, 2.6rem + 3.6vw, 6rem);
	padding-inline: 1.5rem;
	background: var(--gv-paper);
}

.gv-about .gv-h2--wide {
	margin-block-end: 1.75rem;
}

/* The step: the lead starts one indent further along than the heading, and
   the rule marks the riser. It is the staircase stated once, quietly. */
.gv-about-step {
	position: relative;
	padding-inline-start: 2.25rem;
}

.gv-about-rule {
	position: absolute;
	inset-inline-start: 0;
	inset-block-start: 0.4rem;
	inline-size: 4px;
	block-size: calc(100% - 0.8rem);
	border-radius: 3px;
	background: linear-gradient(
		to bottom,
		var(--gv-green) 0%,
		rgba(131, 197, 15, 0.25) 100%
	);
}

@media (max-width: 767px) {
	.gv-about-step {
		padding-inline-start: 1.25rem;
	}

	.gv-about-rule {
		inline-size: 3px;
	}
}

/* ==========================================================================
   Methodology: the narrow one
   ========================================================================== */

.gv-method {
	padding-block: clamp(4rem, 3rem + 4.5vw, 7.5rem);
	padding-inline: 1.5rem;
	background: var(--gv-paper);
	text-align: center;
}

.gv-method-wrap {
	max-inline-size: 46rem;
	margin-inline: auto;
}

.gv-method .gv-eyebrow {
	justify-content: center;
}

.gv-method .gv-h2--wide {
	max-inline-size: none;
	margin-inline: auto;
}

.gv-method .gv-lead {
	margin-inline: auto;
	max-inline-size: 52ch;
}

/* One long stroke at the mark's own angle, sized so the angle reads. */
.gv-method-rule {
	display: block;
	inline-size: 3.5rem;
	block-size: 3px;
	margin: 1.5rem auto 1.75rem;
	border-radius: 2px;
	background: var(--gv-green);
	transform: rotate(calc(var(--gv-rise) * var(--gv-angle) * -1));
}

/* ==========================================================================
   Industries: tiles with a cut corner
   ========================================================================== */

.gv-ind-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 1rem;
}

.gv-ind-tile {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	padding: 1.5rem 1.4rem;
	background: var(--gv-paper);
	border: 1px solid var(--gv-sage);   /* 3.63:1 on paper, 3.20:1 on the band */
	border-radius: 14px;
	text-decoration: none;
	overflow: hidden;
	transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}

/* The corner cut. Small enough that the mark's 51.3 degrees reads as itself
   rather than as the shallow compromise a full-width edge has to make. */
.gv-ind-notch {
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	inline-size: 2.75rem;
	block-size: 2.75rem;
	background: var(--gv-tint);
	clip-path: polygon(0 0, 100% 0, 0 100%);
	transition: background-color 0.2s ease;
}

[dir="ltr"] .gv-ind-notch {
	clip-path: polygon(0 0, 100% 0, 100% 100%);
}

.gv-ind-tile strong {
	position: relative;
	font-size: 1.0625rem;
	color: var(--gv-ink);               /* 16.58:1 */
}

.gv-ind-tile span:not(.gv-ind-notch) {
	font-size: 1rem;
	line-height: 1.7;
	color: var(--gv-muted);             /* 6.89:1 */
}

.gv-ind-tile:hover,
.gv-ind-tile:focus-visible {
	border-color: var(--gv-ink);
	transform: translateY(-3px);
	box-shadow: 0 14px 30px rgba(28, 31, 32, 0.10);
}

.gv-ind-tile:hover .gv-ind-notch,
.gv-ind-tile:focus-visible .gv-ind-notch {
	background: var(--gv-green);
}

.gv-ind-tile:focus-visible {
	outline: 3px solid var(--gv-ink);
	outline-offset: 3px;
}

/* The named-only sectors on the index page: the capture has a label for them
   and no description, so none is invented. */
.gv-ind-more {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	margin-block-start: 1.5rem;
}

.gv-ind-name {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	min-block-size: 44px;
	padding-block: 0.5rem;
	padding-inline: 1.1rem;
	border: 1px solid var(--gv-sage);
	border-radius: 999px;
	font-size: 1rem;
	color: var(--gv-charcoal);          /* 12.92:1 */
	text-decoration: none;
	transition: border-color 0.2s ease, background-color 0.2s ease;
}

.gv-ind-name svg {
	transform: scaleX(var(--gv-rise));
	color: var(--gv-green-deep);
}

.gv-ind-name:hover,
.gv-ind-name:focus-visible {
	border-color: var(--gv-ink);
	background: var(--gv-tint);
}

/* ==========================================================================
   Why: the numerals
   ========================================================================== */

.gv-why-list {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 2rem 3rem;
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: none;
}

.gv-why-list li {
	display: flex;
	align-items: flex-start;
	gap: 1.1rem;
}

/* The anchor. Large, pale, and behind the text in reading weight rather than
   competing with it. It is an ordinal marker, not copy. */
.gv-why-num {
	flex: none;
	font-size: clamp(2.25rem, 1.7rem + 2.2vw, 3.25rem);
	font-weight: 700;
	line-height: 0.9;
	letter-spacing: -0.03em;
	color: var(--gv-tint);
	-webkit-text-stroke: 1px #cfe0ab;
}

.gv-why-text {
	font-size: 1.0625rem;
	line-height: 1.8;
	color: var(--gv-charcoal);          /* 12.92:1 */
	padding-block-start: 0.35rem;
}

@media (max-width: 767px) {
	.gv-why-list {
		grid-template-columns: minmax(0, 1fr);
		gap: 1.4rem;
	}

	.gv-why-num {
		font-size: 2.25rem;
	}
}

/* ==========================================================================
   Use cases: the pull quote
   ========================================================================== */

.gv-case-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 1.25rem;
}

.gv-case-card {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 0.7rem;
	padding: 2rem 1.85rem 1.7rem;
	background: var(--gv-paper);
	border: 1px solid var(--gv-sage);
	/* The cut corner, at the mark's angle. */
	border-radius: 16px;
	text-decoration: none;
	transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}

.gv-case-index {
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	color: var(--gv-green-deep);        /* 6.18:1 on paper */
}

.gv-case-sector {
	margin: 0;
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	color: var(--gv-green-deep);
}

.gv-case-title {
	margin: 0;
	font-size: 1.1875rem;
	line-height: 1.45;
	font-weight: 700;
	color: var(--gv-ink);               /* 16.58:1 */
}

/* The challenge reads as a quotation, because it is the client's description
   of a problem rather than a claim about GRAVON. */
.gv-case-text {
	position: relative;
	margin: 0 0 0.4rem;
	padding-inline-start: 1rem;
	border-inline-start: 3px solid var(--gv-tint);
	font-size: 1rem;
	line-height: 1.85;
	color: var(--gv-muted);             /* 6.89:1 */
}

.gv-case-card:hover,
.gv-case-card:focus-visible {
	border-color: var(--gv-ink);
	transform: translateY(-3px);
	box-shadow: 0 16px 34px rgba(28, 31, 32, 0.10);
}

.gv-case-card:hover .gv-case-text,
.gv-case-card:focus-visible .gv-case-text {
	border-inline-start-color: var(--gv-green);
}

.gv-case-card:focus-visible {
	outline: 3px solid var(--gv-ink);
	outline-offset: 3px;
}

/* ==========================================================================
   Closing: the diagonal as an edge
   ========================================================================== */

.gv-closing {
	margin-block-start: calc(var(--gv-edge) * -1);
	clip-path: polygon(0 var(--gv-edge), 100% 0, 100% 100%, 0 100%);
	padding-block-start: calc(clamp(3.5rem, 2.4rem + 4.4vw, 6.5rem) + var(--gv-edge));
}

[dir="ltr"] .gv-closing {
	clip-path: polygon(0 0, 100% var(--gv-edge), 100% 100%, 0 100%);
}

/* ==========================================================================
   The button that stands in for what the compact layout does not show
   ========================================================================== */

.gv-section-all {
	display: none;
}

/* ==========================================================================
   One column
   ========================================================================== */

@media (max-width: 1023px) {
	.gv-ind-grid,
	.gv-case-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 767px) {
	.gv-ind-grid,
	.gv-case-grid {
		grid-template-columns: minmax(0, 1fr);
		gap: 0.9rem;
	}

	/* Four sectors and two use cases, with a button for the rest. The child
	   theme's script detaches the others below this width and puts them back
	   above it, so a reader without JavaScript sees all of them. */
	.gv-ind-tile--extra,
	.gv-case-card--extra {
		display: none;
	}

	.gv-section-all {
		display: inline-flex;
		inline-size: 100%;
		justify-content: center;
		min-block-size: 52px;
		margin-block-start: 1.4rem;
	}

	.gv-case-card {
		padding: 1.6rem 1.5rem 1.4rem;
	}

	.gv-ind-tile {
		padding: 1.35rem 1.3rem;
	}

	.gv-method {
		text-align: start;
	}

	.gv-method .gv-eyebrow {
		justify-content: flex-start;
	}

	.gv-method-rule {
		margin-inline: 0;
	}

	.gv-method .gv-actions--center {
		justify-content: flex-start;
	}
}

@media (prefers-reduced-motion: reduce) {
	.gv-ind-tile,
	.gv-ind-notch,
	.gv-ind-name,
	.gv-case-card,
	.gv-case-text {
		transition: none !important;
	}

	.gv-ind-tile:hover,
	.gv-case-card:hover {
		transform: none;
	}
}

/* ==========================================================================
   The fixed contact bar
   --------------------------------------------------------------------------
   Two controls at the foot of the screen on a phone: WhatsApp and call. They
   are ordinary links and nothing scripts them, so they work with JavaScript
   off and there is no library to load.

   Measured contrast, all of it against the surface each thing actually sits
   on rather than against the page:

     bar label on the bar surface   #ffffff on #1c1f20   16.58:1
     WhatsApp label on its button   #1c1f20 on #83c50f    7.86:1
     the WhatsApp button itself     #83c50f on #1c1f20    7.86:1
     call label on its button       #ffffff on #1c1f20   16.58:1
     the call button's border       #ffffff on #1c1f20   16.58:1

   The green carries a dark label on a dark bar, which is the standing rule
   kept rather than broken: the brand green is never a text colour on a light
   surface. Here it is a surface, and what sits on it is ink.
   ========================================================================== */

/*
   The bar's height, derived rather than declared.

   Written as a flat 60px first, and measured at 65: the buttons are 48, the
   bar's own padding adds 8 above and 8 below, and the top border adds 1. The
   page then reserved 60px for a 65px bar and the last line of the footer sat
   under it by five pixels. A number that has to agree with a box it does not
   control will disagree with it eventually.

   So the parts are the source and the total is calculated from them. Change
   the button height or the padding and the reserved space follows on its own.
   tests assert the token against the bar's measured height, so if they ever
   part company a suite says so rather than a phone.

   Declared on :root because #page and html both read it, and a custom
   property on .gv-bar is invisible to its siblings.
*/
:root {
	--gv-bar-btn-h: 48px;
	--gv-bar-pad: 8px;
	--gv-bar-border: 1px;
	--gv-bar-h: calc(var(--gv-bar-btn-h) + (var(--gv-bar-pad) * 2) + var(--gv-bar-border));
}

.gv-bar {
	display: none;
	position: fixed;
	inset-inline: 0;
	inset-block-end: 0;
	z-index: 60;

	gap: 0.6rem;
	padding: var(--gv-bar-pad) 0.75rem;
	background: var(--gv-ink);
	border-block-start: var(--gv-bar-border) solid #33383a;

	/*
	   Mandatory, not decorative. On a phone with a gesture bar the bottom of
	   the viewport is under the system indicator, and without this the lower
	   part of both controls sits beneath it: reachable by the eye, not by the
	   thumb. The fallback of 0px matters as much as the env(), because a
	   browser that does not know the keyword must still get a valid value.
	*/
	padding-block-end: calc(var(--gv-bar-pad) + env(safe-area-inset-bottom, 0px));
}

@media (max-width: 767px) {
	.gv-bar {
		display: flex;
	}

	/*
	   The bar is fixed, so it is out of flow and would otherwise lie on top of
	   the last line of the footer. The page reserves exactly its height, plus
	   the same safe-area inset the bar itself adds, so the reserved space and
	   the bar are the same size on every device rather than a guess that is
	   right on one of them.
	*/
	#page.site {
		padding-block-end: calc(var(--gv-bar-h) + env(safe-area-inset-bottom, 0px));
	}

	/* An in-page anchor should not land behind the bar either. */
	html {
		scroll-padding-block-end: calc(var(--gv-bar-h) + env(safe-area-inset-bottom, 0px));
	}
}

.gv-bar-btn {
	flex: 1 1 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;

	/* 44px is the floor for a touch target and this clears it: 48px of box,
	   inside a bar whose own padding keeps it off the screen edge. */
	min-block-size: var(--gv-bar-btn-h);
	padding-inline: 0.9rem;

	border-radius: 999px;
	font-size: 1rem;
	font-weight: 600;
	line-height: 1.2;
	text-decoration: none;
	transition: background-color 0.18s ease, color 0.18s ease;
}

.gv-bar-btn--whatsapp {
	background: var(--gv-green);
	color: var(--gv-ink);
}

.gv-bar-btn--call {
	background: transparent;
	color: var(--gv-paper);
	box-shadow: inset 0 0 0 2px var(--gv-paper);
}

.gv-bar-btn--call:hover,
.gv-bar-btn--call:focus-visible {
	background: var(--gv-paper);
	color: var(--gv-ink);
}

/*
   Not --gv-green-deep, which is what this reached for first. Measured, that
   colour sits at 2.68:1 against the bar it is on: a control whose boundary
   disappears into its own background, below the 3:1 that WCAG 1.4.11 asks of
   a component. Darkening a green button on a near-black bar runs out of room
   quickly, so the hover moves only one step: 4.86:1 against the bar, with the
   ink label still at 4.86:1 on it.
*/
.gv-bar-btn--whatsapp:hover,
.gv-bar-btn--whatsapp:focus-visible {
	background: #68990b;
	color: var(--gv-ink);
}

.gv-bar-btn:focus-visible {
	outline: 3px solid var(--gv-paper);
	outline-offset: 2px;
}

.gv-bar-icon {
	flex: none;
}

@media (prefers-reduced-motion: reduce) {
	.gv-bar-btn {
		transition: none;
	}
}

/* ---------- motion.css ---------- */

/* ==========================================================================
   The mark, drawn live
   --------------------------------------------------------------------------
   Four bars grow from the base, a line is drawn rising through their tops,
   and the arrowhead completes. It is the client's own mark set in motion
   rather than ornament laid over it.

   Zero JavaScript. Bars move on transform, the line on stroke-dashoffset,
   the arrowhead on opacity, so nothing here forces layout.

   Deliberately abstract: no numerals, no axis, no labels, no units. A number
   counting up in a consulting hero reads as a claim about results.

   The resting state of every element below is its finished state. Motion is
   added only inside prefers-reduced-motion: no-preference, and the keyframes
   run backwards from an empty start. So a browser that never animates, for
   any reason, shows the completed composition rather than an empty frame.
   ========================================================================== */

.gv-mark {
	position: absolute;
	inset-block-end: 0;
	inset-inline-end: 2%;
	inline-size: min(22rem, 34%);
	z-index: 0;
	pointer-events: none;
	/*
	 * Deliberately NOT mirrored, and this is the one place the page's own
	 * direction rule is set aside.
	 *
	 * Everywhere else the rising diagonal follows the reading direction and
	 * climbs leftward in Arabic. That is right for an abstract rule, a wedge
	 * or a link glyph. It is wrong here, for two measured reasons.
	 *
	 * The client's own mark rises left to right: sampled off their artwork,
	 * the three green bars top out at y=252, 188 and 136 as x increases. And
	 * that mark is rendered unmirrored in the header, a few hundred pixels
	 * above this composition on the same screen. Mirroring the figure would
	 * put it in direct contradiction with the logo it is quoting.
	 *
	 * A chart-shaped figure also carries its own convention. Arabic numerals
	 * run left to right inside Arabic text, and a mirrored bar chart reads as
	 * a decline no matter which way the sentence beside it runs. Tested: it
	 * did read as a decline, which is the opposite of what the headline says.
	 */
}

.gv-mark svg {
	display: block;
	inline-size: 100%;
	block-size: auto;
	overflow: visible;
}

.gv-mark-bar {
	fill: url(#gv-bar-fill), var(--gv-green);
	fill: var(--gv-green);
	opacity: 0.28;
	transform-origin: center bottom;
}

.gv-mark-bar:nth-child(1) { opacity: 0.16; }
.gv-mark-bar:nth-child(2) { opacity: 0.21; }
.gv-mark-bar:nth-child(3) { opacity: 0.26; }
.gv-mark-bar:nth-child(4) { opacity: 0.32; }

.gv-mark-line,
.gv-mark-head {
	stroke: var(--gv-green-deep);
	opacity: 0.42;
}

@media (prefers-reduced-motion: no-preference) {

	.gv-mark-bar {
		animation: gv-mark-grow 0.75s cubic-bezier(0.22, 0.8, 0.24, 1) backwards;
	}

	.gv-mark-bar:nth-child(1) { animation-delay: 0.05s; }
	.gv-mark-bar:nth-child(2) { animation-delay: 0.17s; }
	.gv-mark-bar:nth-child(3) { animation-delay: 0.29s; }
	.gv-mark-bar:nth-child(4) { animation-delay: 0.41s; }

	/* The stroke runs 243 units on this geometry; 250 covers it. */
	.gv-mark-line {
		stroke-dasharray: 250;
		animation: gv-mark-draw 1.1s cubic-bezier(0.4, 0, 0.2, 1) 0.55s backwards;
	}

	.gv-mark-head {
		animation: gv-mark-tip 0.45s cubic-bezier(0.22, 0.8, 0.24, 1) 1.5s backwards;
	}
}

@keyframes gv-mark-grow {
	from {
		transform: scaleY(0);
	}
}

@keyframes gv-mark-draw {
	from {
		stroke-dashoffset: 250;
	}
}

@keyframes gv-mark-tip {
	from {
		opacity: 0;
		transform: translate(-6px, 6px);
	}
}

/* The old bar strip is replaced by the composition above. */
.gv-hero-bars {
	display: none;
}

@media (max-width: 767px) {
	.gv-mark {
		/* Fully inside the frame. The strip this replaced sat at left=-32 with a
		   third of it outside, and the same mistake is not repeated here. */
		inline-size: 58%;
		inset-inline-end: 0;
		opacity: 0.8;
	}
}

/* ==========================================================================
   The methodology sequence
   --------------------------------------------------------------------------
   Six steps, complete and visible. Nothing is behind a tap: ninety words in
   total cost nothing to show, and interaction that conceals is worse than no
   interaction at all.

   Below the breakpoint the column becomes a horizontal rail with scroll
   snapping, which makes the progression literal forward movement and uses
   the axis a phone has spare. Still zero JavaScript, still nothing hidden.
   ========================================================================== */

.gv-journey {
	background: var(--gv-paper);
}

.gv-steps {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 0;
}

.gv-step {
	position: relative;
	display: grid;
	grid-template-columns: 4.5rem minmax(0, 1fr);
	gap: 1.5rem;
	padding-block-end: 2.5rem;
}

.gv-step:last-child {
	padding-block-end: 0;
}

/* The connector. It runs from one marker to the next and rises in colour the
   way the staircase rises, so the sequence reads as a climb rather than a
   list. */
.gv-step:not(:last-child)::before {
	content: "";
	position: absolute;
	inset-block-start: 4.5rem;
	inset-block-end: 0.75rem;
	inset-inline-start: 2.2rem;
	inline-size: 2px;
	/* Strengthening downward, because the sequence gains as it advances. */
	background: linear-gradient(to bottom, var(--gv-tint), var(--gv-green));
}

.gv-step-marker {
	position: relative;
	z-index: 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 4.5rem;
	block-size: 4.5rem;
	border-radius: 50%;
	background: var(--gv-tint);
	border: 2px solid var(--gv-paper);
}

.gv-step-num {
	font-size: 1.375rem;
	font-weight: 700;
	letter-spacing: 0.02em;
	color: var(--gv-green-deep);        /* 5.36:1 on the tint */
}

.gv-step-body {
	padding-block-start: 0.65rem;
}

.gv-step-name {
	margin: 0 0 0.4rem;
	font-size: clamp(1.25rem, 1.1rem + 0.7vw, 1.625rem);
	font-weight: 700;
	color: var(--gv-ink);               /* 16.58:1 */
}

.gv-step-text {
	margin: 0;
	font-size: 1.0625rem;
	line-height: 1.85;
	color: var(--gv-muted);             /* 6.89:1 */
	max-inline-size: 60ch;
}

/* Deliberately one column at every width above the rail. Two columns were
   tried and rejected: the connector ran from 01 down to 03 while the reading
   order goes 01 then 02, so the line contradicted the numbering. A sequence
   that has to be read in order is drawn in one line. */

@media (max-width: 767px) {

	/* The rail. Snapping makes each step a stop rather than a smear, and the
	   inline padding leaves the last card room to reach the start edge. */
	.gv-steps {
		display: flex;
		gap: 0.9rem;
		overflow-x: auto;
		scroll-snap-type: x mandatory;
		scroll-padding-inline-start: 1.5rem;
		padding-block-end: 0.75rem;
		/* Reach past the wrapper so the rail runs to both edges of the screen. */
		margin-inline: -1.5rem;
		padding-inline: 1.5rem;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: thin;
	}

	.gv-step {
		flex: 0 0 78%;
		scroll-snap-align: start;
		display: block;
		padding-block-end: 0;
		padding: 1.5rem 1.4rem 1.4rem;
		background: var(--gv-paper);
		border: 1px solid var(--gv-sage);   /* 3.63:1 on paper */
		border-radius: 16px;
	}

	/* The connector becomes horizontal, running between one card and the next
	   at marker height, so the climb still reads sideways. */
	.gv-step:not(:last-child)::before {
		inset-block-start: 3.1rem;
		inset-block-end: auto;
		inset-inline-start: auto;
		inset-inline-end: -0.9rem;
		inline-size: 0.9rem;
		block-size: 2px;
		background: linear-gradient(to left, var(--gv-tint), var(--gv-green));
	}

	[dir="ltr"] .gv-step:not(:last-child)::before {
		background: linear-gradient(to right, var(--gv-tint), var(--gv-green));
	}

	.gv-step-marker {
		inline-size: 3.25rem;
		block-size: 3.25rem;
		margin-block-end: 0.9rem;
	}

	.gv-step-num {
		font-size: 1.125rem;
	}

	.gv-step-body {
		padding-block-start: 0;
	}

	.gv-step-name {
		font-size: 1.25rem;
	}

	.gv-step-text {
		font-size: 1rem;
	}
}

/* ---------- pages.css ---------- */

/* ==========================================================================
   About and contact
   --------------------------------------------------------------------------
   Two more devices, so neither page repeats one already spent:

      about    a five-stop flow rail under the stance, and a pair of framed
               cards for the vision and the mission
      contact  the details column and the form side by side, the details first
               in the compact layout because a phone number beats a form on a
               phone
   ========================================================================== */

/* ==========================================================================
   About: the flow
   ========================================================================== */

.gv-flow {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem 0;
	margin: 2.25rem 0 0;
	padding: 0;
	list-style: none;
}

.gv-flow-step {
	display: flex;
	align-items: center;
	gap: 0.65rem;
	padding-inline-end: 1.1rem;
}

/* The connector between stops, at the mark's angle rather than square, so the
   flow reads as a climb like everything else on the site. */
.gv-flow-step:not(:last-child)::after {
	content: "";
	inline-size: 1.4rem;
	block-size: 2px;
	border-radius: 2px;
	background: var(--gv-tint);
	margin-inline-start: 0.4rem;
}

.gv-flow-dot {
	inline-size: 0.7rem;
	block-size: 0.7rem;
	border-radius: 50%;
	background: var(--gv-green);
	flex: none;
}

.gv-flow-label {
	font-size: 1rem;
	font-weight: 600;
	color: var(--gv-charcoal);          /* 12.92:1 on paper */
	white-space: nowrap;
}

/* ==========================================================================
   About: vision and mission
   ========================================================================== */

.gv-vm-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1.25rem;
}

.gv-vm-card {
	position: relative;
	padding: 1.9rem 1.75rem;
	background: var(--gv-paper);
	border: 1px solid var(--gv-sage);   /* 3.20:1 on the band */
	border-radius: 16px;
	overflow: hidden;
}

/* The same corner cut the sector tiles use, held to the mark's angle. */
.gv-vm-card::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	inline-size: 3rem;
	block-size: 3rem;
	background: var(--gv-tint);
	clip-path: polygon(0 0, 100% 0, 0 100%);
}

[dir="ltr"] .gv-vm-card::before {
	clip-path: polygon(0 0, 100% 0, 100% 100%);
}

.gv-vm-label {
	position: relative;
	margin: 0 0 0.7rem;
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.07em;
	color: var(--gv-green-deep);        /* 6.18:1 on paper */
}

.gv-vm-text {
	margin: 0;
	font-size: 1.0625rem;
	line-height: 1.85;
	color: var(--gv-muted);             /* 6.89:1 */
}

/* ==========================================================================
   About: the four benefits, now titled
   ========================================================================== */

.gv-benefits {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1.75rem 3rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.gv-benefit-title {
	margin: 0 0 0.5rem;
	font-size: 1.1875rem;
	font-weight: 700;
	color: var(--gv-ink);               /* 14.61:1 on the band */
	padding-inline-start: 1rem;
	border-inline-start: 3px solid var(--gv-green);
}

.gv-benefit-text {
	margin: 0;
	padding-inline-start: 1rem;
	font-size: 1.0625rem;
	line-height: 1.8;
	color: var(--gv-muted);             /* 6.07:1 on the band */
}

/* ==========================================================================
   About: the roadmap, marked as not yet available
   ========================================================================== */

.gv-roadmap-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1.25rem;
}

.gv-roadmap-card {
	padding: 1.75rem 1.6rem;
	background: var(--gv-paper);
	border: 1px dashed var(--gv-sage);  /* dashed on purpose: not live yet */
	border-radius: 16px;
}

.gv-roadmap-note {
	margin: 0 0 0.75rem;
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	color: var(--gv-green-deep);
}

.gv-roadmap-title {
	margin: 0 0 0.5rem;
	font-size: 1.1875rem;
	font-weight: 700;
	color: var(--gv-ink);
}

.gv-roadmap-text {
	margin: 0 0 0.9rem;
	font-size: 1rem;
	line-height: 1.8;
	color: var(--gv-muted);
}

.gv-roadmap-status {
	margin: 0;
	padding-block: 0.5rem;
	padding-inline: 0.9rem;
	display: inline-block;
	border-radius: 8px;
	background: var(--gv-band);
	font-size: 1rem;
	line-height: 1.7;
	color: var(--gv-charcoal);          /* 11.39:1 on the band */
}

/* ==========================================================================
   Contact
   ========================================================================== */

.gv-contact-page .gv-contact-grid.e-con,
.gv-contact-page .gv-contact-grid > .e-con-inner {
	display: grid;
	grid-template-columns: 5fr 7fr;
	gap: 2.5rem;
	max-inline-size: var(--gv-wrap);
	margin-inline: auto;
	inline-size: 100%;
	padding-inline: 1.5rem;
	padding-block-end: clamp(3.5rem, 2.6rem + 3.6vw, 6rem);
}

.gv-contact-details {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

.gv-contact-row {
	display: flex;
	flex-direction: column;
	gap: 0.2rem;
	/* Comfortably past 44, because these are the targets most likely to be
	   used on a phone. */
	min-block-size: 64px;
	justify-content: center;
	padding: 0.75rem 1.1rem;
	background: var(--gv-paper);
	border: 1px solid var(--gv-sage);
	border-radius: 12px;
	text-decoration: none;
	transition: border-color 0.2s ease, background-color 0.2s ease;
}

.gv-contact-row--static {
	background: var(--gv-band);
}

.gv-contact-label {
	font-size: 0.875rem;
	font-weight: 700;
	letter-spacing: 0.05em;
	color: var(--gv-green-deep);        /* 6.18:1 */
}

.gv-contact-value {
	font-size: 1.0625rem;
	font-weight: 600;
	color: var(--gv-ink);               /* 16.58:1 */
}

a.gv-contact-row:hover,
a.gv-contact-row:focus-visible {
	border-color: var(--gv-ink);
	background: var(--gv-tint);
}

a.gv-contact-row:focus-visible {
	outline: 3px solid var(--gv-ink);
	outline-offset: 3px;
}

/* ==========================================================================
   The form
   --------------------------------------------------------------------------
   The theme's own markup, since the Elementor Pro Forms widget was removed.
   Field heights clear 44px, the labels stay visible rather than collapsing
   into placeholders, and the focus ring is the same one the rest of the site
   uses. The selectors changed with the markup: what were .elementor-field-*
   classes are now .gv-* ones, because naming markup after a plugin that no
   longer produces it would mislead whoever reads this next.
   ========================================================================== */

.gv-form .gv-field > label {
	font-size: 1rem;
	font-weight: 600;
	color: var(--gv-charcoal);          /* 12.92:1 */
	margin-block-end: 0.4rem;
}

.gv-form .gv-input {
	min-block-size: 48px;
	padding: 0.7rem 0.95rem;
	font-size: 1rem;
	line-height: 1.6;
	color: var(--gv-ink);
	background: var(--gv-paper);
	border: 1px solid var(--gv-sage);   /* 3.63:1 on paper */
	border-radius: 10px;
	transition: border-color 0.18s ease, box-shadow 0.18s ease;
}

.gv-form textarea.gv-input {
	min-block-size: 9rem;
	resize: vertical;
}

.gv-form .gv-input:focus {
	border-color: var(--gv-ink);
	box-shadow: 0 0 0 3px rgba(28, 31, 32, 0.12);
	outline: 3px solid var(--gv-ink);
	outline-offset: 2px;
}

.gv-form .gv-input::placeholder {
	color: var(--gv-muted);             /* 6.89:1 */
	opacity: 1;
}

.gv-form .gv-form-submit {
	min-block-size: 52px;
	border-radius: 999px;
	background: var(--gv-ink);
	color: var(--gv-paper);             /* 16.58:1 */
	font-size: 1rem;
	font-weight: 600;
	transition: background-color 0.18s ease;
}

.gv-form .gv-form-submit:hover,
.gv-form .gv-form-submit:focus-visible {
	background: var(--gv-charcoal);
}

.gv-form .gv-form-submit:focus-visible {
	outline: 3px solid var(--gv-ink);
	outline-offset: 3px;
}

.gv-form .gv-form-message {
	font-size: 1rem;
	line-height: 1.7;
}

/* --------------------------------------------------------------------------
   The field grid
   The Pro widget carried its own column classes on every field group. The
   markup no longer has them, so the two-across rows are a grid here instead:
   one column in the compact layout, two above it, and the wide fields span
   both. The half fields are the four short ones the client's own form paired.
   -------------------------------------------------------------------------- */

.gv-form-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 1.15rem;
}

@media (min-width: 640px) {
	.gv-form-grid {
		grid-template-columns: 1fr 1fr;
	}

	.gv-field--full {
		grid-column: 1 / -1;
	}
}

.gv-field {
	display: flex;
	flex-direction: column;
	min-inline-size: 0;
}

/* The asterisk is decoration: the input carries `required`, which is what a
   screen reader announces, so this is aria-hidden in the markup. */
.gv-form .gv-req {
	color: var(--gv-green-deep);        /* 6.48:1 on paper */
	font-weight: 700;
}

/*
   The honeypot. Moved out of view rather than display:none, because a bot that
   skips hidden fields is exactly the bot this is meant to catch. Taken out of
   the tab order and hidden from assistive technology in the markup, so no
   person can reach it.
*/
.gv-hp {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* Errors from a failed submission. Focusable so the browser can be sent here
   after a reload, and announced because it carries role="alert". */
.gv-form .gv-form-message--error {
	margin-block-end: 1.4rem;
	padding: 1rem 1.15rem;
	border-inline-start: 4px solid var(--gv-green-deep);
	background: var(--gv-tint);
	border-radius: 10px;
	color: var(--gv-ink);               /* 15.1:1 on the tint */
}

.gv-form .gv-form-message--error ul {
	margin: 0;
	padding-inline-start: 1.1rem;
}

.gv-form .gv-form-message--error li + li {
	margin-block-start: 0.35rem;
}

.gv-form .gv-form-submit {
	inline-size: 100%;
	border: 0;
	cursor: pointer;
	font-family: inherit;
}

.gv-form select.gv-input {
	appearance: none;
	background-image: linear-gradient(45deg, transparent 50%, var(--gv-charcoal) 50%),
	                  linear-gradient(135deg, var(--gv-charcoal) 50%, transparent 50%);
	background-position: calc(1rem) calc(50% - 2px), calc(1rem + 5px) calc(50% - 2px);
	background-size: 5px 5px, 5px 5px;
	background-repeat: no-repeat;
	padding-inline-start: 2.2rem;
}

/* ==========================================================================
   Thank you
   ========================================================================== */

.gv-thanks {
	padding-block: clamp(4.5rem, 3.4rem + 5vw, 8rem);
}

.gv-thanks-mark {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 4.5rem;
	block-size: 4.5rem;
	border-radius: 50%;
	background: var(--gv-tint);
	color: var(--gv-green-deep);        /* 5.36:1 on the tint */
	margin-block-end: 1.5rem;
}

.gv-thanks-back {
	margin-block-start: 2rem;
}

.gv-thanks-back a {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	min-block-size: 44px;
	font-size: 1rem;
	color: var(--gv-charcoal);          /* 12.92:1 */
}

.gv-thanks-back svg {
	transform: scaleX(var(--gv-rise));
}

/* ==========================================================================
   The review banner
   ========================================================================== */

.gv-review-banner {
	position: relative;
	z-index: 200;
	padding-block: 0.6rem;
	padding-inline: 1rem;
	background: var(--gv-ink);
	color: var(--gv-paper);             /* 16.58:1 */
	font-size: 0.875rem;
	font-weight: 600;
	text-align: center;
}

/* ==========================================================================
   One column
   ========================================================================== */

@media (max-width: 1023px) {
	.gv-contact-page .gv-contact-grid.e-con,
	.gv-contact-page .gv-contact-grid > .e-con-inner {
		grid-template-columns: minmax(0, 1fr);
		gap: 2rem;
	}
}

@media (max-width: 767px) {
	.gv-vm-grid,
	.gv-benefits,
	.gv-roadmap-grid {
		grid-template-columns: minmax(0, 1fr);
		gap: 1rem;
	}

	.gv-benefits {
		gap: 1.4rem;
	}

	/* The rail again, because five short stops are exactly what it suits. */
	.gv-flow {
		flex-wrap: nowrap;
		overflow-x: auto;
		scroll-snap-type: x proximity;
		margin-inline: -1.5rem;
		padding-inline: 1.5rem;
		padding-block-end: 0.6rem;
	}

	.gv-flow-step {
		scroll-snap-align: start;
		flex: none;
	}
}

@media (prefers-reduced-motion: reduce) {
	.gv-contact-row,
	.gv-form .gv-input,
	.gv-form .gv-form-submit {
		transition: none !important;
	}
}

/* ==========================================================================
   Why GRAVON, and the resources empty state
   --------------------------------------------------------------------------
   The advantages are numbered by the client: their captured page carried
   advantage-num blocks reading 01 to 06. The resources page is an empty state
   by their design too, and is transcribed as it stands rather than filled.
   ========================================================================== */

.gv-adv-note {
	margin-block-end: 2.25rem;
	max-inline-size: 56ch;
}

.gv-adv-list {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 2rem 3rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.gv-adv {
	display: flex;
	align-items: flex-start;
	gap: 1.1rem;
}

.gv-adv-num {
	flex: none;
	font-size: clamp(1.75rem, 1.4rem + 1.6vw, 2.5rem);
	font-weight: 700;
	line-height: 1;
	color: var(--gv-tint);
	-webkit-text-stroke: 1px #cfe0ab;
}

.gv-adv-title {
	margin: 0 0 0.4rem;
	font-size: 1.1875rem;
	font-weight: 700;
	color: var(--gv-ink);               /* 16.58:1 */
}

.gv-adv-text {
	margin: 0;
	font-size: 1.0625rem;
	line-height: 1.8;
	color: var(--gv-muted);             /* 6.89:1 */
}

.gv-empty {
	max-inline-size: 44rem;
	margin-inline: auto;
	padding: clamp(2.5rem, 2rem + 2vw, 4rem) 1.5rem;
	border: 1px dashed var(--gv-sage);  /* dashed: nothing here yet */
	border-radius: 18px;
	background: var(--gv-paper);
}

.gv-empty-mark {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 4rem;
	block-size: 4rem;
	border-radius: 50%;
	background: var(--gv-tint);
	color: var(--gv-green-deep);        /* 5.36:1 on the tint */
	margin-block-end: 1.25rem;
}

.gv-empty .gv-lead {
	margin-inline: auto;
	max-inline-size: 46ch;
}

@media (max-width: 767px) {
	.gv-adv-list {
		grid-template-columns: minmax(0, 1fr);
		gap: 1.5rem;
	}
}

/* ---------- media.css ---------- */
/* ==========================================================================
   Photographs

   One rule set for every photograph on the site. There are ten placements and
   one component, because a second component would be a second place for the
   radius and the spacing to drift apart.

   SPECIFICITY, and why these selectors are scoped to `.elementor`
   ---------------------------------------------------------------
   Elementor's frontend.min.css ships this, loaded after the child theme's
   stylesheet:

       .elementor img { border:none; border-radius:0; box-shadow:none;
                        height:auto; max-width:100% }

   `.elementor img` is (0,0,1,1). A bare `.gv-figure img` is also (0,0,1,1)
   and loses on source order. The first version of this file used the bare
   selector, shipped, and was verified by checking that the rule existed in
   the served stylesheet and that the class existed on the element — both
   true, and both beside the point, because neither asks whether the rule
   *won*. It did not: the radius rendered square for two days. Scoping to
   `.elementor .gv-figure img` makes it (0,0,2,1), which beats Elementor's
   without touching load order or reaching for !important.

   The pages are Elementor HTML widgets, so the scope is a description of
   where this markup lives, not a hack.
   ========================================================================== */

.gv-figure {
	margin: 0;
}


/* The frame, on every photograph on the site.

   Two things in the client's reference were measured rather than assumed,
   and both came back differently from how they look:

     the radius — its cards are rounded, but a radius cannot be read off a
       1024px JPEG to better than about three pixels, so this takes 14px from
       the site's own card language (.gv-svc-card) rather than guessing at
       the reference's. One radius across the site beats a second one that is
       nearly the same.
     the shadow — there is none. The reference separates a white card from a
       #f7f8fa ground by six levels of luminance and nothing else. A shadow
       was added here on 2026-09-12 and removed the same day: the reference
       does not carry one, nobody measured a need for one, and if six levels
       of ground contrast are enough there they are enough here. What frames
       these photographs is the radius and the photograph's own edge.

   Scoped to `.elementor` as well as bare, because Elementor ships
   `.elementor img { border-radius: 0 }` at equal specificity and loads
   later. Proven by computed value, not by presence — see HANDOVER 8a.6. */
.elementor .gv-figure img,
.gv-figure img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 14px;
	/* The ground shows while the file is in flight, so the reserved space
	   reads as a held place rather than a hole. */
	background-color: var(--gv-band);
}

/* --------------------------------------------------------------------------
   The home page's "who we are" block: photograph beside the text, not under it

   The photograph used to sit at the end of the block, immediately below the
   button — measured at a 0px gap, button bottom and figure top both at 1046.
   Whatever the intent, a full-width picture touching a call to action reads
   as the end of the section rather than as part of it.

   Beside is the better answer and it is also the reference's own: in it, the
   equivalent block runs text down one side and the photograph down the other.
   Below 900px the grid collapses and the photograph falls after the button,
   which is the other placement that does not interrupt anything.

   Grid columns in RTL run right to left, so column 1 is the text on the right
   and column 2 is the photograph on the left, matching the reference without
   any direction-specific rule.
   -------------------------------------------------------------------------- */

@media (min-width: 900px) {
	/* Only while the block still carries its photograph. The photograph was
	   removed on 2026-09-14, and this grid gives it column 2 — without it the
	   text would stay pinned to column 1, half the width, beside an empty
	   column. :has() keeps the two-column layout ready for a replacement
	   picture without a second edit. */
	.gv-about .gv-wrap:has(.gv-figure--home) {
		display: grid;
		grid-template-columns: 1fr 1.08fr;
		column-gap: clamp(2rem, 1rem + 3vw, 4rem);
		align-items: center;
	}

	/* The eyebrow and the heading introduce both columns, so they span. */
	.gv-about .gv-eyebrow,
	.gv-about .gv-h2 {
		grid-column: 1 / -1;
	}

	.gv-about .gv-about-step {
		grid-column: 1;
	}

	.gv-about .gv-figure--home {
		grid-column: 2;
		/* It is a grid item now; the stacked spacing below would fight the
		   column gap. */
		padding-block-start: 0;
	}
}

/* Stacked, under 900px: the gap the grid provided has to come back.
 *
 * Padding, not margin, and the reason is not style. Elementor ships
 *
 *     .elementor .elementor-widget:not(.elementor-widget-text-editor)
 *     :not(.elementor-widget-theme-post-content) figure { margin: 0 }
 *
 * at specificity (0,6,1). Any margin rule here would have to out-select six
 * classes to land, which means writing a selector whose only purpose is to
 * be longer than someone else's — brittle the day Elementor changes it, and
 * unreadable in the meantime. Elementor does not touch figure padding, so
 * padding gives the same visual result with no contest at all.
 *
 * The figure has no background of its own — the card is the image inside it
 * — so padding and margin are indistinguishable here in every respect except
 * which one actually applies. */
@media (max-width: 899px) {
	.gv-figure--home {
		padding-block-start: clamp(2rem, 1.4rem + 2.4vw, 3rem);
	}
}

/* --------------------------------------------------------------------------
   A photograph directly under a page's opening block (the sector pages)
   -------------------------------------------------------------------------- */

.gv-section--figure {
	padding-block-start: 0;
}

/* Below it comes the lead paragraph; without this the two sit a full section
   rhythm apart and the pairing is lost. */
.gv-section--figure + .gv-section {
	padding-block-start: clamp(2rem, 1.4rem + 2.4vw, 3.5rem);
}

/* ==========================================================================
   The opening section's photograph

   Route D, chosen after measuring four alternatives on the new image: the
   photograph behind the text at full strength, with NO scrim of any kind.

   That was impossible on the photograph this replaced. A grid over that one
   found two quiet cells out of forty, and no single text colour cleared 3:1
   against both the darkest and lightest pixel beneath a heading. The new
   pair is built for this: twenty of twenty cells on one half are quiet, mean
   luminance 27-28, spread 3-7 — half the frame is one tone, deliberately, as
   copy space.

   Two files, not one mirrored. The quiet field sits left in the English
   image and right in the Arabic one, and both were generated rather than
   flipped, so the Riyadh skyline reads correctly in both. Mirroring was
   measured and rejected on content grounds: flipping a recognisable city
   swaps its landmarks, and where the text block sits is a layout choice
   while where Kingdom Centre sits is not.

   Measured on the built page, both trees, at 1440 and 390: every text run
   between 9.77 and 17.70 against the darkest AND lightest pixel actually
   beneath it. The worst figure on the section is 7.86, which is the green
   button's own ink-on-green ratio and predates this change.
   ========================================================================== */

/* <picture> wraps the image; display:contents removes its box so the img
   behaves as if it were a direct child and the absolute positioning below
   still resolves against the section. */
.gv-hero--photo .gv-hero-pic {
	display: contents;
}

.gv-hero--photo {
	/* The ground the text is designed against, and what shows for the moment
	   before the image decodes. Without it the first paint is light text on
	   white.

	   #191b1e is not a taste choice: it is the measured mean of the artwork's
	   own quiet field, so on a phone — where the picture is a band with the
	   section's ground above it — the band's top edge meets a colour equal to
	   its own first row. The seam measures 0.00 levels. */
	background: #191b1e;
}

/* base.css draws two soft blobs on every .gv-hero — its own comment calls
   them a "stand-in for photography", built when every image on the captured
   site was gone. This section has the photograph now, so the stand-in is
   simply old scaffolding.

   It went unnoticed because on a wide screen the photograph is absolutely
   positioned over the whole section and hides it, and on a phone the band
   used to sit at the top and hide it there too. Moving the band to the
   bottom uncovered a green blob behind the English heading. The other heroes
   on the site still want theirs, so this is scoped to the one section that
   has a real picture rather than removed from base.css. */
.gv-hero--photo::before,
.gv-hero--photo::after {
	content: none;
}

/* One box for the picture, in both trees.
 *
 * The section's height was the text's to decide, and the two languages do not
 * write the same length: 830px in English against 614 in Arabic at 1440. The
 * image rule is identical in both — inset: 0, width and height 100%,
 * object-fit: cover — and the widths came out identical too, 1440 against
 * 1440. What differed was what `cover` then did with a 2.32:1 picture:
 *
 *   Arabic   1440x614 box   scale 1.00   nothing cropped, the whole frame
 *                                        visible with its own margins
 *   English  1440x830 box   scale 1.34   488px cropped off the sides, the
 *                                        composition enlarged and bleeding
 *                                        off the frame edge
 *
 * So one rule produced two treatments — a placed picture in one tree and a
 * background in the other — with nothing in the stylesheet saying so. That is
 * worse than two rules, because nothing declares the divergence and a future
 * edit lands on one of them.
 *
 * The fix takes the height out of the text's hands. A floor of 880px clears
 * the tallest English hero measured anywhere in the desktop range (858px at
 * 900px wide) with 22px to spare; above 1528px the floor gives way to 57.6vw
 * so the section keeps its proportion on a wide screen, and 940px caps it.
 * Both trees then land on the same number at every width, and the crop is the
 * same by arithmetic rather than by coincidence.
 *
 * Arabic gains empty space, which is why the content is centred rather than
 * left at the top of a box it no longer fills.
 *
 * tests/check_hero_geometry.py asserts the equality on the live pages. */
@media (min-width: 761px) {
	.gv-hero--photo {
		min-height: clamp(880px, 57.6vw, 940px);
		display: flex;
		flex-direction: column;
		justify-content: center;
	}
}

.gv-hero--photo .gv-hero-img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	z-index: 0;
	/* Not a figure, so the 14px radius above must not reach it. */
	border-radius: 0;
}

/* The text is held inside the quiet half. Without this the Arabic heading —
   one long line where the English wraps to three — runs straight across the
   composition, still legible but fighting it. */
.gv-hero--photo .gv-wrap {
	position: relative;
	z-index: 2;
	display: grid;
	grid-template-columns: minmax(0, 48%) minmax(0, 52%);
}

.gv-hero--photo .gv-wrap > * {
	grid-column: 1;
}

.gv-hero--photo .gv-h1 {
	max-width: none;
	color: #ffffff;
}

.gv-hero--photo .gv-hero-eyebrow {
	/* --gv-green-deep is a text colour for light grounds; on this one it is
	   1.3:1. This is the same hue lifted until it clears the floor: 10.4:1. */
	color: #b7dd52;
}

.gv-hero--photo .gv-lead {
	color: #e9ecec;
}

/* The primary action takes the brand green on this ground.
 *
 * It shipped for twenty minutes as --gv-ink on a #1a1d1e hero, and every
 * contrast check passed: white on ink is 16.58:1 and the label was perfectly
 * legible. What failed is a different measurement that was not being taken —
 * the button's own fill against the surface behind it, WCAG 1.4.11, which
 * wants 3:1 so a control is visibly a control. Ink on this ground is 1.02:1:
 * the most important action on the page had no edge at all.
 *
 * Green on the same ground is 8.04:1, and ink on green is 7.86:1, so both the
 * boundary and the label clear their floors. The ghost button needs no fill
 * change — its white border is 16.96:1 against the ground and that is what
 * makes it visible. */
.gv-hero--photo .gv-btn--primary {
	background: var(--gv-green);
	color: var(--gv-ink);
	border-color: var(--gv-green);
}

.gv-hero--photo .gv-btn--ghost {
	/* A transparent fill leaves the label on whatever the image happens to be
	   underneath. Its own ground is one property instead of a scrim over the
	   whole picture. */
	background: #15191b;
	color: #ffffff;
	border-color: #ffffff;
}

/* ==========================================================================
   Service-card photographs — gated on the card's own width

   The same component renders from 342px to 1200px. Measured live:

     /ar/solutions/     14 cards   590px at 1440   two columns
     home                6 cards   488 / 692       mixed-width grid
     sector pages        7 cards   1200px          ONE column, full-width rows

   At 1200 it is not a card but a row about 100px tall, and an image sized
   for a 590px card becomes a flat strip across it. So the image appears only
   where the card is card-shaped.

   A class cannot make this distinction: both contexts use .gv-svc-grid, and
   they are two different grids — one an Elementor container with 12 columns,
   one a plain div in an HTML widget. A viewport media query cannot either,
   because at 390 every context is 342px wide and every one of them wants the
   image.

   What actually distinguishes them is the card's own rendered width, so that
   is what is asked. The card becomes the container and the media element
   inside it queries the card. `inline-size` containment is safe on a grid
   item, whose width comes from the grid rather than from its contents.

   Where container queries are unsupported the media stays hidden, which is
   the correct degradation: no images, layout untouched.
   ========================================================================== */

.gv-svc-card {
	container-type: inline-size;
	container-name: svccard;
}

/* --------------------------------------------------------------------------
   The service card with a picture — four across, 3:2, badge on the seam

   Four columns, not two, and the reason is arithmetic rather than taste.
   Measured with a real element of each ratio injected into the real cards:

     columns  card    3:2 band   card height   page vs today
        2     590       393       652-681        +64%
        3     387       258       498-575        +31%
        4     285       190       478-537         +1%

   Fourteen cards in two columns is seven rows; in four it is four. The
   three rows saved pay for the pictures outright. The picture's cost is set
   by the CARD'S WIDTH, not by the picture's ratio — which is why the
   reference's near-square image is affordable in the reference's dense grid
   and ruinous in ours.

   The badge straddles the band's lower edge. It keeps the glance value the
   icons already carry, it locks the picture to the card so the picture
   cannot read as a strip pasted on top, and it costs nothing in height
   because it sits in a gap that already existed.

   The gradient under the band is not decoration. Twelve generated pictures
   will not match each other in brightness, and a fixed darkening at the
   seam means the badge always has something to sit on and the band always
   meets the card body cleanly — whatever the generator returned. One rule
   instead of twelve repairs.
   -------------------------------------------------------------------------- */

@media (min-width: 1180px) {
	.gv-sol-grid {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}

@media (min-width: 900px) and (max-width: 1179px) {
	.gv-sol-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.gv-svc-media {
	display: none;
	position: relative;
	aspect-ratio: 3 / 2;
	/* The card is a column flex container with a 0.55rem gap. A margin here
	   would stack on that gap, and the badge's pull-up is measured against
	   the gap alone. */
	margin: 0;
	/* An aspect-ratio box with no definite cross size collapsed to 46px
	   inside the flex column — it resolved its width from content that has
	   none. Stating the width makes the ratio drive the HEIGHT, which is
	   what it is here for. */
	inline-size: 100%;
	align-self: stretch;
	flex: 0 0 auto;
	overflow: hidden;
	border-radius: 12px;
	/* Shows while the file is in flight, so the reserved space reads as a
	   held place rather than a hole. */
	background: var(--gv-band);
}

/* Scoped to .elementor as well, because Elementor ships
   `.elementor img { border-radius: 0; height: auto }` at equal specificity
   and loads later. Proven by computed value, never by presence — 8a.6. */
/* The picture element is inline by default, so an img at height: 100% would
   resolve against an auto height. display: contents takes the wrapper out of
   layout and lets the img fill the 3:2 box directly. */
.gv-svc-media picture {
	display: contents;
}

.elementor .gv-svc-media img,
.gv-svc-media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
}

.gv-svc-media::after {
	content: "";
	position: absolute;
	inset-inline: 0;
	inset-block-end: 0;
	block-size: 45%;
	background: linear-gradient(to bottom,
		rgba(16, 19, 20, 0), rgba(16, 19, 20, 0.88));
	pointer-events: none;
}

/* The modifier is added by the installer alongside the picture, so a card
   without one never pulls its badge up into empty space. A :has() test
   would have covered it too, but a class the installer writes is a fact
   about the markup rather than an inference from it. */
.gv-svc-card--media .gv-svc-icon {
	position: relative;
	z-index: 2;
	/* Half the badge on the band, half on the card. The pull-up is the
	   layout's own gap plus 23px, written as arithmetic so it stays true if
	   the gap is ever retuned. Guessing gave 14px the first time. */
	margin-block-start: calc(-23px - 0.55rem);   /* flex gap */
}

/* 700, not 760, and the 60px matters. Measured on every context the card
   renders in, at five viewport widths, reporting the card's shape and not
   just its width:

     every genuine card   342 to 692 wide,  w/h 0.82 to 2.28
     every full-width row 720 to 1200 wide, w/h 4.09 to 9.38

   The first threshold was 760 and it let one context through: the sector
   pages at a 768px viewport, where the rows are 720x128 — w/h 5.62, the
   exact strip shape this gate exists to exclude. It was missed because the
   contexts were measured at 390 and 1440 and the tablet width between them
   was not looked at.

   The two populations separate cleanly — nothing sits between 2.28 and 4.09
   — but they separate on SHAPE, and a container with `inline-size`
   containment cannot be asked about its height. So the query stands in for
   shape with width, and the standing-in is only valid while 692 and 720 stay
   on their own sides of the line. That is 28px of margin, which is thin.

   tests/check_hero_geometry.py therefore asserts the real condition — the
   image shows wherever w/h <= 2.5 and hides wherever w/h >= 4 — so the day a
   padding change moves a row under 700, a check fails instead of a strip
   appearing on the sector pages. */
@container svccard (max-width: 700px) {
	.gv-svc-media {
		display: block;
	}
}

/* The sector pages need their own threshold, and width alone cannot give it.
 *
 * A sweep at eight viewport widths instead of five found the case the first
 * two thresholds both missed: at a 600px viewport the sector rows are
 * 552x132 — w/h 4.18, unambiguously a row — and 552 sits inside the range
 * every genuine card occupies (342 to 692). No single width separates them,
 * because the same element is a card at 342 and a row at 552, and a home
 * card is a card at 561.
 *
 * What does separate them is structure, and the DOM says so plainly:
 *
 *   home        .gv-svc-grid > .gv-svc-cell > .gv-svc-card   (Elementor)
 *   /solutions/ .gv-sol-grid > .gv-svc-card
 *   sector      .gv-svc-grid > .gv-svc-card                  <- only this one
 *
 * The sector card is the only one that is a direct child of .gv-svc-grid. So
 * the rule is the same everywhere — show the image while the card is
 * card-shaped — and only the width at which each context stops being
 * card-shaped differs. For the sector rows that is where their grid stops
 * stacking: 342 when it stacks, 552 when it does not, so 450 sits over 100px
 * clear of both.
 *
 * tests/check_card_gate.py asserts the shape condition itself at eight
 * widths, so neither threshold can quietly stop separating. */
@container svccard (min-width: 450px) {
	.gv-svc-grid > .gv-svc-card .gv-svc-media {
		display: none;
	}
}

/* The home grid's feature card spaces its children at 0.7rem, not 0.55rem,
   so the shared pull-up left its badge 21px on the band instead of 23 —
   measured on the live home page. Scoped above 768px: under it every card,
   the feature card included, is the named grid with its own row-gap below. */
@media (min-width: 768px) {
	.gv-svc-card--feature.gv-svc-card--media .gv-svc-icon {
		margin-block-start: calc(-23px - 0.7rem);   /* the feature card's gap */
	}
}

/* Under 768px the card is not a flex column at all: services-mobile.css
   makes it a named grid, `"icon kicker" / "icon title" / "text text" /
   "more more"`, with a 46px icon column. A prepended element with no area
   is auto-placed into the first free cell — which is that 46px column, and
   the band came back 46x31. So the band gets an area of its own, spanning
   both columns, and only on cards that actually carry one: the template is
   extended on the modifier so every other card keeps the layout it has. */
@media (max-width: 767px) {
	.gv-svc-card--media {
		grid-template-areas:
			"media  media"
			"icon   kicker"
			"icon   title"
			"text   text"
			"more   more";
	}

	.gv-svc-card--media .gv-svc-media {
		grid-area: media;
	}

	.gv-svc-card--media .gv-svc-icon {
		margin-block-start: calc(-23px - 0.3rem);   /* this layout's row-gap */
	}
}

/* --------------------------------------------------------------------------
   The opening section on a phone — the band below the text

   Designed at 390 and widened, not derived from the desktop layout.

   The band used to sit ABOVE the text, and the reasoning for that was sound
   on everything except arithmetic. The first screen on a phone is the
   viewport less two fixed costs: the sticky header at 72px and the contact
   bar at 65px. What is left has to hold the copy and the picture:

     390x844   707px of first screen   English copy 546px   leaves 161px
     414x896   759px                   English copy 525px   leaves 234px
     360x800   663px                   English copy 541px   leaves 122px

   The composition needs 304px. So a band above the text could keep its size
   or keep the buttons on the first screen, and it kept its size: both
   English buttons finished 158px under the bar at 390 and 333px under it at
   360x640. Arabic passed at 390 only because Arabic says the same thing in
   fewer lines — 316px against 546 — which is not a property of the layout.

   Below the text the band costs the first screen nothing, so it keeps its
   full size and the buttons come up by some 280px. The order changes; the
   treatment does not.

   The same two properties make it work as before. The image is fitted to the
   WIDTH, so its rendered height is a known multiple of the width — 94.8vw
   for a 1456x1380 asset — and the padding that clears it is written in vw
   rather than a percentage, because percentage padding resolves against the
   inline size (HANDOVER 8a.10). And the asset's top rows are taken to the
   flat tone of the artwork's own quiet field, #191b1e, which is what the
   section is painted, so the band's upper edge meets a colour equal to its
   own first row: the seam measures 0.00 levels. Left and right are the frame
   edges and the bottom is the section boundary, so the band has no visible
   edge anywhere. Nothing to read as a card.
   -------------------------------------------------------------------------- */

@media (max-width: 760px) {
	.gv-hero--photo {
		display: block;
		position: relative;
		padding: 0;
		overflow: hidden;
	}

	.gv-hero--photo .gv-hero-img {
		position: absolute;
		bottom: 0;
		top: auto;
		inset-inline-start: 0;
		inset-inline-end: auto;
		width: 100%;
		height: auto;
		/* Width-fitted, so `fill` scales nothing: the element's box already
		   carries the asset's own ratio. `cover` would height-fit and
		   side-crop, and the band's height would stop being knowable. */
		object-fit: fill;
		border-radius: 0;
		margin: 0;
	}

	.gv-hero--photo .gv-wrap {
		position: relative;
		z-index: 2;
		display: block;
		/* 94.8vw = the band's rendered height, 1380/1456 of the width. */
		padding: 2.5rem 1.5rem 94.8vw;
	}
}

/* ==========================================================================
   PREVIEW BLOCK — the photographic hero with a scrim. Added 2026-09-14.

   Remove this whole block to return to the silhouette treatment; nothing
   above it depends on it.

   The scrim is sized from the picture, not chosen. Measured on the live
   page, per text block, against the LIGHTEST pixel actually under it:

     ar desktop   eyebrow needs 62%   h1 51%   lead 57%
     en desktop   eyebrow needs 51%   h1 44%   lead 47%
     phone        eyebrow needs 62%   h1 46%   lead 48%

   The green eyebrow is the binding constraint everywhere, because green on
   a dark ground needs a very dark ground: its ceiling is a luminance of
   0.099 against 0.183 for white. 68% carries the worst case with margin.

   One gradient serves both trees. The text sits on the inline-start side in
   each — left in English, right in Arabic — so only the gradient's
   direction flips, and it flips through a token rather than through a
   second rule.
   ========================================================================== */

:root {
	--gv-scrim-dir: right;
}

[dir="rtl"] {
	--gv-scrim-dir: left;
}

.gv-hero--photo::after {
	content: "";
	position: absolute;
	inset: 0;
	/* base.css gives .gv-hero::after a 22rem square with border-radius 50%
	   — the decorative blob. Setting inset alone does NOT undo that: an
	   explicit size beats inset stretching, so the first version of this
	   scrim rendered as a dark CIRCLE in the corner of the hero while its
	   content, z-index, position and background all read back exactly as
	   intended. Checking the properties you set and not the ones you
	   inherited is HANDOVER 8a.6, and this is the second time. */
	inline-size: auto;
	block-size: auto;
	border-radius: 0;
	z-index: 1;
	pointer-events: none;
	/* Held at full strength across the text column, then released, so the
	   far side of the picture keeps all of its detail. */
	background: linear-gradient(to var(--gv-scrim-dir),
		rgba(0, 0, 0, 0.68) 0%,
		rgba(0, 0, 0, 0.68) 44%,
		rgba(0, 0, 0, 0.12) 76%,
		rgba(0, 0, 0, 0.12) 100%);
}

@media (max-width: 760px) {
	/* The picture becomes the section's background here too, so the two
	   breakpoints are one treatment rather than two. */
	.gv-hero--photo {
		display: flex;
		flex-direction: column;
		justify-content: center;
		position: relative;
		padding: 0;
		overflow: hidden;
		/* HANDOVER 8a.11, a second time and in a place I had not applied it.
		   The desktop got a floor so both trees render one box; this block
		   was written later for the scrim and left min-height at 0, so the
		   phone section went back to being sized by its text. Arabic carries
		   316px of copy against English's 546, and measured on the live page
		   the hero came out 427px against 657 — half a screen against three
		   quarters. The floor makes the two identical by construction.

		   svh, not vh: vh on a phone is the tallest viewport, so the hero
		   would sit under the address bar until the user scrolls.
		   4.5rem is the sticky header, measured at 72px at 360, 390 and 414.
		   vh first as the fallback for browsers without svh. */
		min-height: calc(100vh - 4.5rem);
		min-height: calc(100svh - 4.5rem);
	}

	.gv-hero--photo .gv-hero-img {
		position: absolute;
		inset: 0;
		top: 0;
		bottom: 0;
		inset-inline-start: 0;
		inset-inline-end: auto;
		width: 100%;
		height: 100%;
		object-fit: cover;
		margin: 0;
		border-radius: 0;
	}

	/* The text spans the full width on a phone, so the gradient runs down
	   instead of across and eases only at the very bottom, where the glass
	   table is and no text sits. */
	.gv-hero--photo::after {
		background: linear-gradient(to bottom,
			rgba(0, 0, 0, 0.68) 0%,
			rgba(0, 0, 0, 0.68) 72%,
			rgba(0, 0, 0, 0.30) 100%);
	}

	.gv-hero--photo .gv-wrap {
		position: relative;
		z-index: 2;
		display: block;
		padding: 3.25rem 1.5rem 3.75rem;
	}
}

/* --------------------------------------------------------------------------
   Sector tiles on the home page — a photograph edge to edge across the top

   The tile is already a clipped rounded box (overflow: hidden, radius 14px),
   so the photograph breaks out of the tile's padding with negative margins
   and the tile's own corner rounds it. The cut-corner notch stays on top of
   the photograph's corner, which makes the green corner read as part of the
   picture's frame rather than a sticker beside it.

   16:9, not the service cards' 3:2, for two measured reasons. The client's
   photographs are 1.833:1 — 16:9 keeps 97% of each frame's width where 3:2
   cut 18% off the sides. And these tiles are wide (389px at 1440) with one or
   two lines of text: 3:2 grew the section by 504px, 16:9 by 423.

   The margins mirror the tile's own padding at each breakpoint, from
   sections.css: 1.5rem / 1.4rem, and 1.35rem / 1.3rem under 768px.
   -------------------------------------------------------------------------- */

.gv-ind-media {
	position: relative;
	z-index: 0;
	display: block;
	margin: -1.5rem -1.4rem 0.7rem;
	inline-size: calc(100% + 2.8rem);
	aspect-ratio: 16 / 9;
	overflow: hidden;
	background: var(--gv-band);
}

.gv-ind-media picture {
	display: contents;
}

.elementor .gv-ind-media img,
.gv-ind-media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 0;
}

.gv-ind-tile--media .gv-ind-notch {
	z-index: 1;
}

@media (max-width: 767px) {
	.gv-ind-media {
		margin: -1.35rem -1.3rem 0.7rem;
		inline-size: calc(100% + 2.6rem);
	}
}

/* ---------- servicepage.css ---------- */

/* ==========================================================================
   Service pages after the 2026-09-15 update, and the use cases page
   --------------------------------------------------------------------------
   The client's service documents share one anatomy: an introduction, the
   scope, the value, two scenarios, what the client receives, how success is
   followed, a four-step flow, and on four of them a project demonstration.
   Each part gets one device, used the same way on all eighteen pages:

      scope          a ruled list, three columns where there is room
      scenarios      two framed cards side by side
      deliverables   two ink panels, so what the client gets is unmistakable
      flow           four numbered stops joined by arrows; a vertical rail on
                     a phone, because four stops across 360px leave each label
                     a 70px column
      demonstration  the screenshot at full wrap width with its attribution

   The flow is text, not the documents' picture of it: at phone width their
   1800x300 strip is 60px tall and its words about 6px.
   ========================================================================== */

.gv-sr {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.gv-sp-alt {
	margin: -0.35rem 0 1.1rem;
	font-size: 1rem;
	font-weight: 600;
	letter-spacing: 0.02em;
	color: var(--gv-muted);             /* 6.89:1 on paper */
}

.gv-sp .gv-lead + .gv-lead {
	margin-block-start: 1rem;
}

.gv-sp .gv-lead a,
.gv-uc-page .gv-lead a,
.gv-uc-text a {
	color: var(--gv-ink);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.22em;
}

/* --------------------------------------------------------------------------
   Scope and other lists
   -------------------------------------------------------------------------- */

.gv-sp-list {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	column-gap: 2.25rem;
	margin: 1.75rem 0 0;
	padding: 0;
	list-style: none;
}

.gv-sp-list--short {
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 1023px) {
	.gv-sp-list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 599px) {
	.gv-sp-list,
	.gv-sp-list--short {
		grid-template-columns: minmax(0, 1fr);
	}
}

.gv-sp-list li {
	position: relative;
	padding-block: 0.85rem;
	padding-inline-start: 1.6rem;
	border-block-start: 1px solid rgba(125, 139, 107, 0.35);
	font-size: 1.0625rem;
	line-height: 1.7;
	color: var(--gv-charcoal);          /* 12.92:1 on paper */
}

.gv-sp-list li::before {
	content: "";
	position: absolute;
	inset-inline-start: 0;
	inset-block-start: 1.55rem;
	inline-size: 0.8rem;
	block-size: 3px;
	border-radius: 2px;
	background: var(--gv-green);
}

.gv-sp-caveat {
	max-inline-size: 72ch;
	margin: 2rem 0 0;
	padding: 1rem 1.25rem;
	border-inline-start: 4px solid var(--gv-ink);
	background: rgba(28, 31, 32, 0.045);
	font-size: 1rem;
	line-height: 1.8;
	color: var(--gv-charcoal);
}

.gv-sp-note {
	max-inline-size: 72ch;
	margin: 0 0 2rem;
	font-size: 1rem;
	line-height: 1.8;
	color: var(--gv-muted);
}

/* --------------------------------------------------------------------------
   Scenarios and deliverables
   -------------------------------------------------------------------------- */

.gv-sp-cases,
.gv-sp-outcomes {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1.25rem;
}

.gv-sp-outcomes {
	margin-block-start: 1.25rem;
}

@media (max-width: 767px) {
	.gv-sp-cases,
	.gv-sp-outcomes {
		grid-template-columns: minmax(0, 1fr);
	}
}

.gv-sp-case {
	padding: 1.75rem 1.6rem 1.6rem;
	background: var(--gv-paper);
	border: 1px solid var(--gv-sage);   /* 3.20:1 against the band */
	border-radius: 16px;
}

.gv-sp-case-title,
.gv-sp-outcome-title {
	margin: 0 0 0.6rem;
	font-size: 1.1875rem;
	line-height: 1.45;
	font-weight: 700;
	color: var(--gv-ink);               /* 16.58:1 */
}

.gv-sp-case-text {
	margin: 0;
	font-size: 1rem;
	line-height: 1.85;
	color: var(--gv-muted);
}

.gv-sp-outcome {
	position: relative;
	padding: 1.75rem 1.6rem 1.6rem;
	background: var(--gv-ink);
	border-radius: 16px;
	overflow: hidden;
}

/* The green draws the edge; it never carries the words. */
.gv-sp-outcome::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline: 1.6rem;
	block-size: 3px;
	background: var(--gv-green);
}

.gv-sp-outcome .gv-sp-outcome-title {
	color: var(--gv-paper);             /* 16.58:1 on ink */
}

.gv-sp-outcome-text {
	margin: 0;
	font-size: 1rem;
	line-height: 1.85;
	color: #dfe3e2;                     /* 12.81:1 on ink */
}

/* --------------------------------------------------------------------------
   The flow
   -------------------------------------------------------------------------- */

/* Padding, not margin: Elementor zeroes the margin of every figure inside a
   widget at (0,4,1) — `.elementor .elementor-widget:not(…):not(…) figure` —
   which measured 0px live against this rule's 44px. */
.gv-sp-flow {
	margin: 0;
	padding-block-start: 2.75rem;
}

.gv-sp-steps {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	column-gap: 3rem;
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: none;
}

.gv-sp-step {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.45rem;
	padding-block-end: 1rem;
	border-block-end: 3px solid var(--gv-green);
	text-align: center;
}

.gv-sp-step-num {
	font-size: 1.25rem;
	line-height: 1;
	font-weight: 700;
	color: var(--gv-green-deep);        /* 6.18:1 on paper */
	font-variant-numeric: tabular-nums;
}

.gv-sp-step-label {
	font-size: 1.125rem;
	line-height: 1.45;
	font-weight: 700;
	color: var(--gv-ink);
	text-wrap: balance;
}

/* The arrow between two stops, pointing the way the page reads. */
.gv-sp-step:not(:last-child)::after {
	content: "";
	position: absolute;
	inset-block-start: calc(50% - 0.35rem);
	inset-inline-end: -1.85rem;
	inline-size: 0.7rem;
	block-size: 0.7rem;
	border-block-start: 2px solid var(--gv-sage);
	border-inline-end: 2px solid var(--gv-sage);
	transform: rotate(45deg);
}

[dir="rtl"] .gv-sp-step:not(:last-child)::after {
	transform: rotate(-45deg);
}

.gv-sp-caption {
	margin: 1rem 0 0;
	font-size: 0.9375rem;
	line-height: 1.7;
	color: var(--gv-muted);
}

.gv-sp-flow .gv-sp-caption {
	text-align: center;
}

@media (max-width: 767px) {
	.gv-sp-steps {
		grid-template-columns: minmax(0, 1fr);
		row-gap: 1.1rem;
	}

	.gv-sp-step {
		display: grid;
		grid-template-columns: 2.75rem minmax(0, 1fr);
		align-items: center;
		gap: 1rem;
		padding-block-end: 0;
		border-block-end: 0;
		text-align: start;
	}

	.gv-sp-step-num {
		display: grid;
		place-items: center;
		inline-size: 2.75rem;
		block-size: 2.75rem;
		border: 2px solid var(--gv-green);
		border-radius: 50%;
		font-size: 1.125rem;
	}

	/* A rail from one stop's ring down to the next. */
	.gv-sp-step:not(:last-child)::after {
		inset-block-start: calc(50% + 1.375rem);
		inset-inline-start: calc(1.375rem - 1px);
		inset-inline-end: auto;
		inline-size: 2px;
		block-size: 1.1rem;
		border: 0;
		background: var(--gv-sage);
		transform: none;
	}

	[dir="rtl"] .gv-sp-step:not(:last-child)::after {
		transform: none;
	}

	.gv-sp-flow .gv-sp-caption {
		text-align: start;
	}
}

/* --------------------------------------------------------------------------
   Reference projects and demonstrations
   -------------------------------------------------------------------------- */

.gv-sp-reference {
	margin-block-start: 2.25rem;
	padding-block-start: 1.5rem;
	border-block-start: 1px solid rgba(125, 139, 107, 0.4);
}

.gv-sp-reference .gv-sp-note {
	margin-block-end: 0.5rem;
}

.gv-sp-ref {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0 0.5rem;
	margin: 1rem 0 0;
	font-size: 1rem;
	line-height: 1.6;
	color: var(--gv-muted);
}

.gv-sp-ref-label {
	font-weight: 600;
}

/* What the reader is about to open, beside the link and not inside it: the
   format and the weight of a download, and the language it is written in. */
.gv-sp-ref-meta {
	font-size: 0.9375rem;
	color: var(--gv-muted);
}

.gv-sp-ref a {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
	color: var(--gv-ink);
	font-weight: 600;
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.22em;
	overflow-wrap: anywhere;
}

.gv-sp-ref a:focus-visible,
.gv-uc-related a:focus-visible {
	outline: 3px solid var(--gv-ink);
	outline-offset: 2px;
}

.gv-sp-demo {
	display: grid;
	gap: 2.5rem;
	margin-block-start: 1.5rem;
}

.gv-sp-demo-title {
	margin: 0 0 0.75rem;
	font-size: clamp(1.25rem, 1.15rem + 0.4vw, 1.5rem);
	line-height: 1.35;
	font-weight: 700;
	color: var(--gv-ink);
}

.gv-sp-shot {
	margin: 0;
	padding-block-start: 1.5rem;
}

.gv-sp-shot picture {
	display: block;
}

/* (0,0,2,1), above Elementor's `.elementor img`; see media.css. */
.elementor .gv-sp-shot img,
.gv-sp-shot img {
	display: block;
	inline-size: 100%;
	block-size: auto;
	border: 1px solid rgba(28, 31, 32, 0.14);
	border-radius: 12px;
	box-shadow: 0 18px 40px rgba(28, 31, 32, 0.12);
}

/* --------------------------------------------------------------------------
   A working product on a service page

   Two of the service pages carry a product that exists and runs: the ERP
   page carries a film of one, the platforms page a picture of another. The
   film is a 720x1280 phone recording, so it gets a column of its own rather
   than a portrait frame stretched across a 1200px wrap.

   The film is a plain <video preload="none" poster>: nothing is fetched
   until the visitor presses play, which is the same bargain the
   [gravon_video] facade strikes for a third-party embed. That shortcode is
   not used here because it cannot be: Elementor's HTML widget renders its
   setting with print_unescaped_setting() and never runs a shortcode
   (read on the server, elementor/includes/widgets/html.php:127), so the tag
   would print as text. A self-hosted file needs no facade anyway.
   -------------------------------------------------------------------------- */

.gv-sp-product {
	display: grid;
	gap: 2.25rem;
	margin-block-start: 1.5rem;
}

@media (min-width: 900px) {
	.gv-sp-product--film {
		grid-template-columns: minmax(0, 1fr) 320px;
		align-items: start;
		column-gap: 3rem;
	}
}

.gv-sp-product-intro {
	max-inline-size: 72ch;
	margin: 1.75rem 0 0.85rem;
	font-size: 1rem;
	line-height: 1.7;
	font-weight: 600;
	color: var(--gv-ink);
}

/* Padding, not margin, for the same reason as .gv-sp-flow: Elementor zeroes
   the margin of every figure inside a widget at (0,4,1). */
.gv-sp-film {
	margin: 0;
	padding: 0;
}

/* (0,0,2,1), so it clears anything Elementor declares on a bare element. */
.elementor .gv-sp-film video,
.gv-sp-film video {
	display: block;
	inline-size: 100%;
	max-inline-size: 320px;
	block-size: auto;
	aspect-ratio: 9 / 16;
	margin-inline: auto;
	border-radius: 14px;
	background: var(--gv-ink);
	box-shadow: 0 18px 40px rgba(28, 31, 32, 0.18);
}

.gv-sp-film .gv-sp-caption {
	max-inline-size: 46ch;
	margin-inline: auto;
}

/* --------------------------------------------------------------------------
   The client's own poster for the service, as one link

   4:5 artwork. Given the full 1200px wrap it would stand 1500px tall and
   bury the page, so it is held to a poster's width and centred; at phone
   width it fills the column like any other picture.

   The whole picture is the link, so the label under it is not decoration: a
   picture-only link says nothing about where it goes, and the artwork is
   Arabic on both trees. The label is inside the same <a>, which is why it
   needs no separate target height — the link's own box is far past 44px.
   -------------------------------------------------------------------------- */

.gv-sp-poster {
	display: block;
	inline-size: 100%;
	max-inline-size: 560px;
	margin-inline: auto;
	text-decoration: none;
	color: var(--gv-ink);
}

.gv-sp-poster picture {
	display: block;
}

/* (0,0,2,1), above Elementor's `.elementor img`; see media.css. */
.elementor .gv-sp-poster img,
.gv-sp-poster img {
	display: block;
	inline-size: 100%;
	block-size: auto;
	border-radius: 14px;
	box-shadow: 0 18px 40px rgba(28, 31, 32, 0.14);
}

.gv-sp-poster-cta {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.55rem;
	min-block-size: 44px;
	margin-block-start: 0.9rem;
	font-size: 1rem;
	font-weight: 600;
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.22em;
}

.gv-sp-poster-cta svg {
	flex: none;
}

.gv-sp-poster:hover .gv-sp-poster-cta {
	color: var(--gv-green-deep);        /* 6.18:1 on paper */
}

.gv-sp-poster:focus-visible {
	outline: 3px solid var(--gv-ink);
	outline-offset: 4px;
}

/* The notice the artwork carries, set again as text under it. Held to the
   poster's own width so it reads as part of the same object, and centred
   with it rather than running the full wrap. */
.gv-sp-poster-note {
	inline-size: 100%;
	max-inline-size: 560px;
	margin-inline: auto;
	margin-block-start: 1.5rem;
}

/* --------------------------------------------------------------------------
   Related services on a service page
   -------------------------------------------------------------------------- */

.gv-sp-related {
	margin-block-start: 1.75rem;
}

/* Three across, not the index's four: a group leaves two, three or six
   siblings, and three columns fill a row for all of them but the two. */
@media (min-width: 900px) {
	.gv-sp-related {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* --------------------------------------------------------------------------
   Use cases
   -------------------------------------------------------------------------- */

.gv-uc-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 1.25rem;
}

.gv-uc-grid--two {
	grid-template-columns: repeat(2, minmax(0, 1fr));
	margin-block-start: 1.75rem;
}

@media (max-width: 1023px) {
	.gv-uc-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 699px) {
	.gv-uc-grid,
	.gv-uc-grid--two {
		grid-template-columns: minmax(0, 1fr);
	}
}

.gv-uc-case {
	display: flex;
	flex-direction: column;
	gap: 0.9rem;
	padding: 1.9rem 1.75rem 1.75rem;
	background: var(--gv-paper);
	border: 1px solid var(--gv-sage);
	border-radius: 16px;
}

.gv-uc-title {
	margin: 0;
	font-size: 1.25rem;
	line-height: 1.45;
	font-weight: 700;
	color: var(--gv-ink);
}

.gv-uc-text {
	margin: 0;
	font-size: 1rem;
	line-height: 1.85;
	color: var(--gv-muted);
}

.gv-uc-deliv {
	margin: 0;
	padding-block-start: 0.9rem;
	border-block-start: 1px solid rgba(125, 139, 107, 0.35);
	font-size: 1rem;
	line-height: 1.8;
	color: var(--gv-charcoal);
}

.gv-uc-deliv strong {
	display: block;
	margin-block-end: 0.2rem;
	color: var(--gv-ink);
}

.gv-uc-related {
	margin-block-start: auto;
}

.gv-uc-related-label {
	margin: 0 0 0.5rem;
	font-size: 0.9375rem;
	font-weight: 700;
	color: var(--gv-muted);
}

.gv-uc-related ul {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.gv-uc-related a {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
	padding-inline: 0.95rem;
	border: 1px solid var(--gv-sage);
	border-radius: 999px;
	font-size: 0.9375rem;
	line-height: 1.35;
	color: var(--gv-ink);
	text-decoration: none;
	transition: border-color 0.2s ease, background-color 0.2s ease;
}

.gv-uc-related a:hover {
	border-color: var(--gv-ink);
	background: var(--gv-band);
}

@media (prefers-reduced-motion: reduce) {
	.gv-uc-related a {
		transition: none;
	}
}

/* ==========================================================================
   The page hero with the card's picture — service and sector pages
   --------------------------------------------------------------------------
   The client's request: the card carries a picture and the page behind it
   did not, so each service and sector page now opens the way the home hero
   does, with the same picture its card shows.

   The home hero's treatment under its own modifier, so the home rules (an
   880px floor, the button colours) do not travel with it:

     picture   absolutely behind the section, object-fit cover; a 2:1 crop
               above 760px and a 4:5 crop below, chosen by <source media>
     scrim     from the text's side: 70% held across the first 58% of the
               width, easing to 22%. The text column is 52% of the wrap, so
               at 1920 its far edge sits at 51% of the section — inside the
               held part at every width. On a phone the text spans the
               width, so the scrim is a flat 70%.
     ground    #191b1e before the picture decodes: the first paint is light
               text on dark, never light text on white.

   Worst case, computed rather than hoped: a pure white pixel under a 70%
   scrim reads as 77/255. White on that is 8.5:1, the lead's #e9ecec 7.1:1,
   the eyebrow's #b7dd52 5.5:1 — every run clears 4.5:1 whatever the picture
   holds beneath it.
   ========================================================================== */

.gv-hero--cover {
	display: flex;
	flex-direction: column;
	justify-content: center;
	/* One box for both trees of a page pair (HANDOVER 8a.11): the floor sits
	   above the text block, so `cover` crops the picture the same way.
	   Measured live, the tallest hero the text asks for is 642px (English
	   company qualification at 768 wide; 629 at 1024, 605 at 900, 585 at
	   1440). A 560px floor let four English pages grow past their Arabic
	   pair at 768-1024. 680 clears the tallest by 38px. */
	min-height: clamp(680px, 42vw, 720px);
	background: #191b1e;
}

.gv-hero--cover::before {
	content: none;
}

.gv-hero--cover::after {
	content: "";
	position: absolute;
	inset: 0;
	/* base.css gives .gv-hero::after a 22rem circle; inset alone does not
	   undo an explicit size. HANDOVER 8a.6. */
	inline-size: auto;
	block-size: auto;
	border-radius: 0;
	z-index: 1;
	pointer-events: none;
	background: linear-gradient(to var(--gv-scrim-dir),
		rgba(0, 0, 0, 0.70) 0%,
		rgba(0, 0, 0, 0.70) 58%,
		rgba(0, 0, 0, 0.22) 88%,
		rgba(0, 0, 0, 0.22) 100%);
}

.gv-hero--cover .gv-hero-pic {
	display: contents;
}

.elementor .gv-hero--cover .gv-hero-img,
.gv-hero--cover .gv-hero-img {
	position: absolute;
	inset: 0;
	inline-size: 100%;
	block-size: 100%;
	max-inline-size: none;
	object-fit: cover;
	z-index: 0;
	margin: 0;
	border-radius: 0;
}

.gv-hero--cover .gv-wrap {
	position: relative;
	z-index: 2;
	display: grid;
	grid-template-columns: minmax(0, 52%) minmax(0, 48%);
}

.gv-hero--cover .gv-wrap > * {
	grid-column: 1;
}

.gv-hero--cover .gv-h1 {
	color: #ffffff;
}

.gv-hero--cover .gv-eyebrow {
	color: #b7dd52;                     /* the home hero's lifted green */
}

.gv-hero--cover .gv-lead {
	color: #e9ecec;
}

.gv-hero--cover .gv-sp-alt {
	color: #d5dbda;
}

@media (max-width: 760px) {
	.gv-hero--cover {
		min-height: 640px;
	}

	.gv-hero--cover .gv-wrap {
		display: block;
	}

	.gv-hero--cover::after {
		background: rgba(0, 0, 0, 0.70);
	}
}

/* ---------- popup.css ---------- */
/* ==========================================================================
   The advertisement dialog
   --------------------------------------------------------------------------
   The client's artwork, once a visit, on the Arabic tree (inc/popup.php).

   It is a real dialog: a veil over the page, the picture centred, one close
   button, and nothing else on top of the site. Two measurements shape it:

     height   the artwork is 4:5, so at 480px wide it is 600px tall. On a
              360x640 phone that leaves nothing, so the dialog is capped at
              the visible viewport minus the header and the fixed contact
              bar, and the picture scales inside that cap (`contain`), never
              beyond it. svh, not vh, for the same reason as the hero.
     close    44px, on the corner of the picture, with its own solid ground
              — the artwork is white at the top on one edge and dark on the
              other, and a button whose contrast depends on the picture
              behind it is a button that disappears on the next artwork.
   ========================================================================== */

/* This rule is the reason the dialog could not be closed, reported from a
   phone and reproduced: `display: grid` on a class beats the browser's own
   `[hidden] { display: none }`, so setting pop.hidden did nothing. The veil
   stayed over the page — dimming it and swallowing every tap — and on the
   next page load, where the script deliberately does NOT open the dialog,
   the empty veil was shown anyway. .gv-nav-panel in base.css already carries
   the same rule for the same reason. */
.gv-pop[hidden] {
	display: none;
}

.gv-pop {
	position: fixed;
	inset: 0;
	z-index: 1000;
	display: grid;
	place-items: center;
	padding: 1rem;
	padding-block-end: calc(var(--gv-bar-h, 65px) + 1rem + env(safe-area-inset-bottom, 0px));
}

@media (min-width: 768px) {
	.gv-pop {
		padding-block-end: 1.5rem;
	}
}

.gv-pop-veil {
	position: absolute;
	inset: 0;
	background: rgba(12, 14, 15, 0.72);
}

.gv-pop-dialog {
	position: relative;
	inline-size: min(100%, 480px);
	max-block-size: calc(100svh - 4.5rem - var(--gv-bar-h, 65px) - 2rem);
	border-radius: 18px;
	background: var(--gv-paper);
	box-shadow: 0 30px 70px rgba(0, 0, 0, 0.45);
	overflow: hidden;
	animation: gv-pop-in 0.22s ease-out both;
}

@media (min-width: 768px) {
	.gv-pop-dialog {
		max-block-size: calc(100svh - 6rem);
	}
}

@keyframes gv-pop-in {
	from { opacity: 0; transform: translateY(12px); }
	to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
	.gv-pop-dialog {
		animation: none;
	}
}

.gv-pop-link {
	display: block;
	max-block-size: inherit;
}

.gv-pop-link picture {
	display: block;
}

/* (0,0,2,1), above Elementor's `.elementor img`; see media.css. */
.elementor .gv-pop-link img,
.gv-pop-link img {
	display: block;
	inline-size: 100%;
	block-size: auto;
	/* The dialog's cap is a max-height, so the picture must agree to shrink
	   inside it rather than overflow: it keeps its ratio and letterboxes on
	   the paper ground, which is the artwork's own background colour. */
	max-block-size: calc(100svh - 4.5rem - var(--gv-bar-h, 65px) - 2rem);
	object-fit: contain;
	border-radius: 0;
}

@media (min-width: 768px) {
	.elementor .gv-pop-link img,
	.gv-pop-link img {
		max-block-size: calc(100svh - 6rem);
	}
}

.gv-pop-close {
	position: absolute;
	inset-block-start: 0.6rem;
	/* `right`, not `inset-inline-end`: on the Arabic page inline-end is the
	   left, and the artwork's logo sits in its top-left corner — measured on
	   the live dialog, the button covered it. The top-right of this artwork
	   is empty. A future artwork with something in that corner wants this
	   line revisited, which is why it is physical and commented. */
	right: 0.6rem;
	z-index: 2;
	display: grid;
	place-items: center;
	inline-size: 44px;
	block-size: 44px;
	min-block-size: 44px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: var(--gv-ink);
	color: var(--gv-paper);            /* 16.58:1 on ink */
	cursor: pointer;
}

.gv-pop-close:hover {
	background: #000000;
}

.gv-pop-close:focus-visible {
	outline: 3px solid var(--gv-paper);
	outline-offset: 2px;
}

/* While the dialog is open the page behind it does not scroll. */
.gv-pop-open {
	overflow: hidden;
}
