/* ==========================================================================
   ESNAD — Animated logo component (isolated & reusable)
   Uses the REAL logo artwork, split into two layers so the rings can spin
   while the "E" stays upright:
     assets/images/logo/esnad-layer-rings.png  (+ -white for dark bg)
     assets/images/logo/esnad-layer-e.png      (+ -white for dark bg)

   Markup:
     <span class="esnad-logo esnad-logo--spin" style="--logo-size:160px;">
       <img class="esnad-logo__rings" src=".../esnad-layer-rings.png" alt="">
       <img class="esnad-logo__e"     src=".../esnad-layer-e.png" alt="ESNAD">
     </span>
   For dark backgrounds add class `esnad-logo--on-dark` and use the -white images.
   ========================================================================== */

.esnad-logo {
  position: relative;
  display: inline-block;
  width: var(--logo-size, 120px);
  aspect-ratio: 759 / 751;   /* native ratio of the source art */
  line-height: 0;
}
.esnad-logo__rings,
.esnad-logo__e {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
.esnad-logo__rings { transform-origin: 50% 50%; }

/* ---- Spin: rings rotate as one assembly; offset gaps create the spiral ---- */
.esnad-logo--spin .esnad-logo__rings {
  animation: esnad-spin 16s linear infinite;
}
/* ---- Counter option: uncomment to also rotate the E slowly the other way ----
.esnad-logo--spin .esnad-logo__e { animation: esnad-spin-rev 22s linear infinite; }
*/

/* ---- Zoom-in on load (whole mark) ---- */
.esnad-logo--intro .esnad-logo__rings,
.esnad-logo--intro .esnad-logo__e {
  animation-name: esnad-pop;
  animation-duration: 900ms;
  animation-timing-function: cubic-bezier(.22, 1, .36, 1);
}
/* When both spin + intro are on, rings get a one-off pop then the infinite spin */
.esnad-logo--spin.esnad-logo--intro .esnad-logo__rings {
  animation: esnad-pop 900ms cubic-bezier(.22,1,.36,1), esnad-spin 16s linear 900ms infinite;
}

@keyframes esnad-spin      { to { transform: rotate(360deg); } }
@keyframes esnad-spin-rev  { to { transform: rotate(-360deg); } }
@keyframes esnad-pop       { from { opacity: 0; transform: scale(.8); } to { opacity: 1; transform: scale(1); } }

/* ---- Accessibility ---- */
@media (prefers-reduced-motion: reduce) {
  .esnad-logo__rings,
  .esnad-logo__e { animation: none !important; }
}

/* ==========================================================================
   ESNAD — FINAL LOGO LOCKUP (decided)
   Drawn-ring emblem + rounded "E" that reads with SNAD as ESNAD, plus the
   WE PROTECT slogan beneath. On load the ring draws itself in from the
   edges, then the E, wordmark and slogan fade in — no rotation.

   Markup:
     <span class="esnad-lockup esnad-lockup--on-dark"
           style="--lk-emblem:150px;--lk-word:3.4rem;--lk-slogan:.9rem;"
           role="img" aria-label="ESNAD — We Protect">
       <svg class="esnad-lockup__emblem" viewBox="0 0 200 200" aria-hidden="true"> … </svg>
       <span class="esnad-lockup__wm">
         <span class="esnad-lockup__snad">SNAD</span>
         <span class="esnad-lockup__slogan">WE&nbsp;PROTECT</span>
       </span>
     </span>
   Use --on-dark with the -white ring art; --on-light with the navy ring art.
   ========================================================================== */
.esnad-lockup {
  display: inline-flex;
  align-items: center;
  gap: 0;
  direction: ltr;                 /* Latin brand lockup — keep E→SNAD order in RTL pages */
  color: var(--lk-fg, #0E3A5F);
  --lk-emblem: 130px;
}
.esnad-lockup--on-dark  { --lk-fg: #ffffff; --lk-accent: #8fbaf0; }
.esnad-lockup--on-light { --lk-fg: #0E3A5F; --lk-accent: #4A90D9; }

.esnad-lockup__emblem {
  width: var(--lk-emblem);
  height: var(--lk-emblem);
  display: block;
  flex: 0 0 auto;
  transform: translateY(-6px);
}
.esnad-lockup__wm {
  position: relative;
  line-height: 1;
  margin-inline-start: 4px;
  transform: scaleX(1.14);
  transform-origin: left center;
}

.esnad-lockup__snad {
  display: block;
  font-family: Arial, "Segoe UI", system-ui, sans-serif;
  font-size: var(--lk-word, 2.9rem);
  font-weight: 500;
  letter-spacing: 0.07em;
  color: var(--lk-fg);
  opacity: 0;
  animation: esnad-show .5s ease 2.05s forwards;
}
.esnad-lockup__slogan {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-top: 0.42em;
  white-space: nowrap;
  font-size: var(--lk-slogan, 0.82rem);
  font-weight: 600;
  letter-spacing: 0.42em;
  padding-inline-start: 0.42em;
  color: var(--lk-accent);
  opacity: 0;
  animation: esnad-show .5s ease 2.4s forwards;
}

/* self-drawing ring (revealed through a luminance mask) + reveal of the E */
.esnad-lockup__emblem .draw {
  fill: none;
  stroke: #fff;
  stroke-linecap: round;
  stroke-dasharray: 100 100;
  stroke-dashoffset: 100;
  animation: esnad-draw 1.5s cubic-bezier(.45, 0, .25, 1) forwards;
}
.esnad-lockup__emblem .eRound {
  fill: none;
  stroke: currentColor;
  stroke-width: 13;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
  animation: esnad-show .55s ease 1.6s forwards;
}
@keyframes esnad-draw { to { stroke-dashoffset: 0; } }
@keyframes esnad-show { to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .esnad-lockup__emblem .draw { animation: none; stroke-dashoffset: 0; }
  .esnad-lockup__emblem .eRound,
  .esnad-lockup__snad,
  .esnad-lockup__slogan { animation: none; opacity: 1; }
}

/* Static emblem-only mark (header): ring art + rounded E, no animation */
.esnad-mark { display: block; }
.esnad-mark .eRound {
  fill: none;
  stroke: currentColor;
  stroke-width: 13;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ==========================================================================
   FINAL brand build — real artwork emblem (rings + E layers) + exact wordmark
   image, used in the site header and homepage hero.
   ========================================================================== */

/* header emblem (exact artwork, static) */
.brand-emblem { position: relative; display: inline-block; height: 42px; width: 42px; flex: 0 0 auto; line-height: 0; }
.brand-emblem img { position: absolute; inset: 0; width: 100%; height: 100%; }

/* homepage hero logo: emblem fades in, then the wordmark image fades in */
.site-logo { --lem: clamp(120px, 22vw, 178px); display: inline-flex; flex-direction: column; align-items: center; }
.site-logo__em { position: relative; width: var(--lem); aspect-ratio: 759/751; display: block; opacity: 1; }
.site-logo__em img { position: absolute; inset: 0; width: 100%; height: 100%; }
.site-logo__wm { width: calc(var(--lem) * 1.95); height: auto; margin-top: calc(var(--lem) * 0.16); display: block; opacity: 1; }
/* The whole lockup appears at once — emblem and wordmark fade in together,
   one single movement, timed to land with the single thud at 0.03s. */
.site-logo.go { animation: esnadFade 1s ease-out both; }
@keyframes esnadFade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .site-logo.go { animation: none; }
}

/* homepage hero: turbine backdrop + tiled floor glow behind the logo */
.hero { position: relative; overflow: hidden; }
.hero__bg { position: absolute; inset: 0; z-index: 0; overflow: hidden;
  background: #0a2c49 url(../images/turbine.jpg) center/cover no-repeat; }
.hero__bg video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* heavy overlay so the white hero text stays clearly legible over the video */
.hero__bg::after { content: ""; position: absolute; inset: 0;
  /* neutral (not blue) light scrim — kept light so the turbine's real colours show */
  background: linear-gradient(100deg, rgba(0,0,0,0.48) 24%, rgba(0,0,0,0.28) 64%, rgba(0,0,0,0.18) 100%); }
.hero .hero__content { text-shadow: 0 2px 16px rgba(0,0,0,0.6); }

/* MOBILE HERO: no panel, the glyphs carry their own legibility.
   DO NOT MOVE THIS TO style.css. The rule above and this one are both
   `.hero .hero__content` -- specificity (0,2,0) each, and a media query adds
   none. style.css loads FIRST, so an override written there loses on source
   order and silently does nothing. (It already did: a mobile text-shadow sat
   dead in style.css for exactly this reason.) It has to live here, after the
   rule it overrides.

   Three layers rather than one: a tight near-opaque shadow that keeps the
   letter edges defined against a bright frame, a mid blur for body weight,
   and a wide soft halo that separates the block from busy footage without
   reading as a box. */
@media (max-width: 860px) {
  .hero .hero__content {
    text-shadow:
      0 0 2px rgba(0, 0, 0, 1),
      0 0 4px rgba(0, 0, 0, 0.99),
      0 1px 3px rgba(0, 0, 0, 0.98),
      0 2px 8px rgba(0, 0, 0, 0.95),
      0 0 18px rgba(0, 0, 0, 0.90),
      0 0 38px rgba(0, 0, 0, 0.70);
  }
  /* the buttons carry their own fill and shadow -- keep the glyph halo off
     them or the labels smudge */
  .hero .hero__cta .btn { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45); }
}

/* PHASE 3: the alternating grey/white banding made the page read as stacked
   boxes. Every section is now the same near-white surface; separation comes
   from the soft centred rule defined in style.css instead. The class is kept
   so existing markup needs no change. */
/* B6 PREVIEW — applied to this one alternating band only, pending sign-off
   before rolling out site-wide. */
.section--soft { background: var(--color-section-tint, #E3EEF9); }

/* RETIRED — the old standalone DUNS panel that sat at the end of the homepage.
   That section no longer exists in any page's markup (checked across en/ ar/
   nothing references .duns__text). A10 reuses the .duns/.duns__qr/
   .duns__num names for the header utility bar and the footer mark, and these
   rules were still winning because logo.css loads after style.css -- the
   150px QR burst out of the 34px bar. Kept here, commented, rather than
   deleted, in case the homepage panel is ever wanted back.

.duns { display: flex; align-items: center; justify-content: center; gap: 34px; flex-wrap: wrap; }
.duns__qr { width: 150px; height: 150px; background: #fff; border: 1px solid var(--color-line, #e3e8ef);
  border-radius: 14px; padding: 12px; box-shadow: 0 8px 30px rgba(14,58,95,0.08); flex: 0 0 auto; }
.duns__text { max-width: 420px; }
.duns__num { font-size: 1.4rem; font-weight: 800; color: var(--color-dark-blue, #0E3A5F); letter-spacing: 0.04em; margin: 4px 0 8px; }
.duns__num small { display: block; font-size: 0.68rem; font-weight: 500; color: var(--color-muted, #6b7688); letter-spacing: 0.02em; margin-top: 2px; }
[dir="rtl"] .duns { text-align: right; }
*/

/* Mission / Vision / Values / Goals — connected step-flow with arrows */
.mvvg { display: flex; flex-wrap: wrap; align-items: stretch; justify-content: center; gap: 12px; }
.mvvg__item { flex: 1 1 220px; max-width: 300px; position: relative; background: #fff;
  border: 1px solid var(--color-line, #e3e8ef); border-top: 4px solid var(--color-light-blue, #4A90D9);
  border-radius: 16px; padding: 26px 22px; box-shadow: 0 10px 30px rgba(14,58,95,0.07); transition: transform .18s, box-shadow .18s; }
.mvvg__item:hover { transform: translateY(-5px); box-shadow: 0 18px 44px rgba(14,58,95,0.14); }
.mvvg__icon { width: 48px; height: 48px; border-radius: 12px; background: var(--color-light-blue-100, #eaf2fb);
  display: grid; place-items: center; color: var(--color-dark-blue, #0E3A5F); margin-bottom: 14px; }
.mvvg__icon svg { width: 26px; height: 26px; }
.mvvg__item h3 { margin: 0 0 8px; color: var(--color-dark-blue, #0E3A5F); font-size: 1.12rem; }
.mvvg__item p { margin: 0; font-size: 0.92rem; line-height: 1.65; color: var(--color-body, #2C5577); }
.mvvg__arrow { display: flex; align-items: center; justify-content: center; color: var(--color-light-blue, #4A90D9);
  font-size: 1.6rem; flex: 0 0 auto; }
.mvvg__arrow svg { width: 26px; height: 26px; }
@media (max-width: 900px) {
  .mvvg { flex-direction: column; align-items: center; }
  .mvvg__item { max-width: 460px; width: 100%; }
  .mvvg__arrow { transform: rotate(90deg); }
}
[dir="rtl"] .mvvg__arrow svg { transform: scaleX(-1); }
@media (max-width: 900px) { [dir="rtl"] .mvvg__arrow svg { transform: none; } }

/* scroll-reveal (fade + rise as elements enter view) */
[data-reveal] { opacity: 0; transform: translateY(26px); transition: opacity .7s ease, transform .7s ease; }
[data-reveal].is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { [data-reveal] { opacity: 1; transform: none; transition: none; } }

/* ============================ WHAT'S NEW band ============================ */
.whatsnew { position: relative; overflow: hidden; background: linear-gradient(135deg, #0E3A5F, #0a2c49); color: #fff; }
.whatsnew .container { position: relative; z-index: 1; text-align: center; }
.whatsnew__badge { display: inline-flex; align-items: center; gap: 8px; background: rgba(74,144,217,0.18);
  border: 1px solid rgba(140,195,255,0.4); color: #bcd8f6; font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; padding: 7px 15px; border-radius: 20px; animation: wnPulse 2.6s ease-in-out infinite; }
@keyframes wnPulse { 0%,100% { box-shadow: 0 0 0 0 rgba(140,195,255,0.35); } 50% { box-shadow: 0 0 0 8px rgba(140,195,255,0); } }
.whatsnew h2 { color: #fff; margin: 16px 0 8px; }
.whatsnew__lead { color: rgba(255,255,255,0.82); max-width: 620px; margin: 0 auto 34px; }
.whatsnew__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; text-align: left; }
@media (max-width: 760px) { .whatsnew__grid { grid-template-columns: 1fr; } }
.wn-card { background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.14); border-radius: 16px; padding: 24px; }
.wn-card__icon { width: 46px; height: 46px; border-radius: 12px; background: rgba(74,144,217,0.25); display: grid; place-items: center; color: #bcd8f6; margin-bottom: 14px; }
.wn-card__icon svg { width: 24px; height: 24px; }
.wn-card__tag { display: inline-block; font-size: 0.6rem; font-weight: 800; letter-spacing: 0.12em; color: #0a2c49; background: #8fbaf0; border-radius: 5px; padding: 3px 8px; margin-bottom: 10px; }
.wn-card h3 { color: #fff; margin: 0 0 6px; font-size: 1.05rem; }
.wn-card p { color: rgba(255,255,255,0.78); font-size: 0.9rem; margin: 0; line-height: 1.6; }

/* WHAT'S NEW — single highlighted image (ad-style: shine sweep + glow pulse) */
.wn-figure { position: relative; max-width: 980px; margin: 26px auto 0; border-radius: 18px; overflow: hidden;
  box-shadow: 0 22px 60px rgba(0,0,0,0.4); animation: wnGlow 3.4s ease-in-out infinite; }
.wn-figure img { display: block; width: 100%; height: auto; }
.wn-figure::before { content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(105deg, transparent 38%, rgba(255,255,255,0.4) 48%, transparent 58%);
  background-size: 260% 100%; background-position: 180% 0; animation: wnShine 4.8s ease-in-out infinite; }
@keyframes wnShine { 0% { background-position: 180% 0; } 55%, 100% { background-position: -90% 0; } }
@keyframes wnGlow { 0%, 100% { box-shadow: 0 22px 60px rgba(0,0,0,0.4), 0 0 0 0 rgba(140,195,255,0); }
  50% { box-shadow: 0 22px 60px rgba(0,0,0,0.4), 0 0 48px 3px rgba(140,195,255,0.5); } }
@media (prefers-reduced-motion: reduce) { .wn-figure, .wn-figure::before { animation: none; } }

/* NB: the "key stats" counter block (.stats / .stat__num) was removed in the
   2026-08 content update — the client confirmed there are no figures to show.
   The narrative .milestones block below replaces both it and the old timeline. */

/* client / partner logo strip (placeholders) */
.logos { display: grid; grid-template-columns: repeat(6, 1fr); gap: 14px; align-items: center; }
@media (max-width: 720px) { .logos { grid-template-columns: repeat(3, 1fr); } }
.logo-box { aspect-ratio: 3/2; background: #f0f3f7; border: 1px dashed #cfd8e6; border-radius: 10px;
  display: grid; place-items: center; color: #9aa7b6; font-size: 0.72rem; letter-spacing: 0.05em; }

/* ---------------------------------------------------------------------------
   Named logo tiles — partners & clients
   Each tile already points at its final file under /client-images/. Until that
   file exists the tile shows a labelled placeholder instead of a broken image
   (see the .is-missing handling in main.js), so the section is reviewable now
   and becomes real simply by dropping the artwork in.
   --------------------------------------------------------------------------- */
.logo-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 16px; }
@media (max-width: 980px) { .logo-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 560px) { .logo-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* space-between pinned every logo to the top of its tile, so a short mark
   floated with a gap beneath it while a tall one sat flush — the client asked
   for them centred. The artwork now gets a flexible centred row of its own and
   the caption stays on the baseline. */
.logo-tile { margin: 0; background: #fff; border: 1px solid var(--color-line, #e3e8ef); border-radius: 12px;
  padding: 16px 12px 12px; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; min-height: 168px; transition: transform .18s, box-shadow .18s, border-color .18s; }
.logo-tile img { flex: 1 1 auto; min-height: 0; }
.logo-tile:hover { transform: translateY(-3px); border-color: var(--color-light-blue, #4A90D9);
  box-shadow: 0 10px 26px rgba(14,58,95,0.10); }
/* Logos always render in full brand colour. Hover is a gentle lift only —
   a small scale-up plus a touch of brightness, no colour change. */
/* PHASE 12: every mark is pre-scaled to roughly equal ink area (see
   _work/phase12.py), so the tile just gives them all the same box to sit in.
   Height alone is the wrong normaliser — a wide wordmark and a compact roundel
   at equal height read as very different sizes. */
.logo-tile img { max-width: min(176px, 100%); max-height: 92px; width: auto; height: auto; object-fit: contain;
  filter: none; opacity: 1; transition: transform .22s ease, filter .22s ease; }
.logo-tile:hover img { transform: scale(1.05); filter: brightness(1.07); }
@media (prefers-reduced-motion: reduce) { .logo-tile:hover img { transform: none; } }
.logo-tile--tall img { max-height: 120px; }
.logo-tile figcaption { font-size: 0.78rem; font-weight: 600; color: var(--color-dark-blue, #0E3A5F);
  text-align: center; line-height: 1.35; }
/* Three marks are supplied as white or near-white artwork and are invisible
   on a light tile. Measured against the card background at the WCAG 3:1
   threshold for graphical objects, each renders 0% of its ink readable:
       red-sea-global   0%    aispeco   0%    ampacimon   0%
   The navy plate sits behind THOSE IMAGES ONLY — the tile, its border and its
   caption stay identical to every other tile, so it reads as a deliberate
   treatment rather than a styling glitch. Temporary, pending colour files.
   NB: the card background itself is deliberately NOT blue — tested at
   #A1C5EB, 17 of 29 logos dropped below 3:1, and the three above stayed
   invisible, so it degraded the set without fixing the problem. */
.logo-tile--plate img { background: var(--color-dark-blue, #0E3A5F);
  padding: 10px 14px; border-radius: 8px; box-sizing: border-box; }
.logo-tile--plate:hover img { filter: brightness(1.12); }

/* placeholder state — no artwork supplied yet */
.logo-tile.is-missing::before { content: "Logo pending"; display: grid; place-items: center;
  width: 100%; min-height: 62px; background: #f0f3f7; border: 1px dashed #cfd8e6; border-radius: 8px;
  color: #9aa7b6; font-size: 0.68rem; letter-spacing: 0.06em; text-transform: uppercase; }
[lang="ar"] .logo-tile.is-missing::before { content: "شعار قيد الإضافة"; text-transform: none; letter-spacing: 0; }

/* ---------------------------------------------------------------------------
   Product / solution cards with a real image slot
   --------------------------------------------------------------------------- */
.media-ph { position: relative; border-radius: 12px; overflow: hidden; background: #eef2f7;
  /* fixed height keeps every card in a row the same height regardless of the
     source image's aspect ratio */
  height: 190px; display: grid; place-items: center; margin-bottom: 16px; }
.media-ph { background: #fff; }
/* product shots are studio cut-outs on white, so contain (not cover) keeps the
   whole unit visible instead of cropping into it */
.media-ph img { width: 100%; height: 100%; object-fit: contain; display: block; padding: 10px; }
.media-ph.is-missing { border: 1px dashed #cfd8e6; }
.media-ph.is-missing { background: #eef2f7; }
.media-ph.is-missing::before { content: attr(data-label); color: #9aa7b6; font-size: 0.78rem;
  text-align: center; padding: 14px; line-height: 1.5; }
.media-ph--photo { height: 200px; background: #eef2f7; }
/* photographs fill the frame, unlike the product cut-outs which use contain */
.media-ph--photo img { width: 100%; height: 100%; object-fit: cover; padding: 0; max-height: none; }
.card__source { margin-top: 10px; font-size: 0.76rem; color: var(--color-muted, #6b7688); }
.card__source strong { color: var(--color-light-blue-600, #2b6cb8); font-weight: 600; }

/* ---------------------------------------------------------------------------
   Projects list — extensible; add another .proj-card and nothing else changes
   --------------------------------------------------------------------------- */
.proj-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
@media (max-width: 860px) { .proj-grid { grid-template-columns: 1fr; } }
.proj-card { background: #fff; border: 1px solid var(--color-line, #e3e8ef); border-radius: 14px;
  padding: 22px 24px; transition: transform .18s, box-shadow .18s; }
.proj-card:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(14,58,95,0.12); }
.proj-card h3 { margin: 0 0 12px; font-size: 1.05rem; color: var(--color-dark-blue, #0E3A5F); line-height: 1.4; }
.proj-meta { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.proj-meta span { font-size: 0.74rem; font-weight: 600; padding: 4px 10px; border-radius: 999px;
  background: rgba(74,144,217,0.10); color: var(--color-light-blue-600, #2b6cb8); }
.proj-meta .proj-date { background: rgba(14,58,95,0.08); color: var(--color-dark-blue, #0E3A5F); }
.proj-card p { margin: 0; color: var(--color-body, #2C5577); font-size: 0.92rem; line-height: 1.65; }

/* ---------------------------------------------------------------------------
   Values / Goals — heading + description lists
   --------------------------------------------------------------------------- */
/* B8: the value/goal cards are genuinely three-dimensional, not a flat panel
   with a drop shadow. The grid supplies the perspective; each card keeps a
   preserve-3d context so its face, its extruded side and its icon sit at
   different real depths on the Z axis. Tilting the card therefore moves those
   layers by different amounts -- which is what makes it read as a solid
   object rather than a picture of one. */
.vg-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;
  perspective: 1200px; perspective-origin: 50% 40%; }
@media (max-width: 900px) { .vg-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .vg-grid { grid-template-columns: 1fr; } }
.vg-item { background: #fff; border: 1px solid var(--color-line, #e3e8ef); border-radius: 14px; padding: 22px 22px 20px;
  border-top: 3px solid var(--color-light-blue, #4A90D9);
  position: relative; transform-style: preserve-3d;
  transition: transform .38s cubic-bezier(.2,.7,.3,1), box-shadow .38s ease;
  box-shadow: 0 1px 0 rgba(14,58,95,0.05), 0 10px 22px -14px rgba(14,58,95,0.30); }

/* The extruded side. A solid slab sitting 16px BEHIND the face in real 3D
   space, so when the card tilts it is revealed along one edge like the side
   of a block -- a shadow cannot do this because a shadow does not have a
   position in space. */
.vg-item::after {
  content: ""; position: absolute; inset: 0; border-radius: 14px;
  background: linear-gradient(160deg, #cfe0f2, #aec9e6);
  transform: translateZ(-16px);
  z-index: -1;
}
/* The icon and heading float above the card face, so the parallax between
   them and the face is visible as the card moves. */
.vg-item .vg-icon { transform: translateZ(26px); transition: transform .38s cubic-bezier(.2,.7,.3,1); }
.vg-item h3 { transform: translateZ(14px); }

@media (hover: hover) {
  /* The 3D tilt is replaced with a modest, contained grow, per the client.
     The card's built depth (the extruded slab and the lifted icon) is kept --
     only the hover BEHAVIOUR changed. 1.03 is deliberately small: the cards
     sit in a tight 3-column grid with a 20px gap, so anything larger would
     overlap its neighbours. Pointer devices only, or :hover sticks after a
     tap on a touch screen. */
  .vg-item:hover {
    transform: scale(1.03);
    box-shadow: 0 1px 0 rgba(14,58,95,0.05), 0 22px 40px -20px rgba(14,58,95,0.34);
    z-index: 1;
  }
}
.vg-item:focus-within { transform: scale(1.03); z-index: 1; }
@media (prefers-reduced-motion: reduce) {
  .vg-item, .vg-item .vg-icon { transition: none; }
  .vg-item:hover, .vg-item:focus-within { transform: none; }
}
.vg-icon { width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;
  background: rgba(74,144,217,0.10); color: var(--color-light-blue-600, #3a7bc0);
  margin-bottom: 14px; }
.vg-icon svg { display: block; }
.vg-item h3 { margin: 0 0 8px; font-size: 1rem; color: var(--color-dark-blue, #0E3A5F); }
.vg-item p { margin: 0; color: var(--color-body, #2C5577); font-size: 0.9rem; line-height: 1.65; }

/* Mission / Vision statement panels */
.mv-panel { background: #fff; border: 1px solid var(--color-line, #e3e8ef); border-radius: 16px;
  padding: 30px 32px; box-shadow: 0 10px 30px rgba(14,58,95,0.06); }
.mv-panel + .mv-panel { margin-top: 20px; }
.mv-panel h3 { margin: 0 0 12px; font-size: 1.25rem; color: var(--color-dark-blue, #0E3A5F); }
.mv-panel p { margin: 0; color: var(--color-body, #2C5577); line-height: 1.8; }

/* Goals tagline */
.goals-tagline { max-width: 820px; margin: 0 auto 30px; text-align: center; font-size: 1.1rem; line-height: 1.7;
  color: var(--color-dark-blue, #0E3A5F); font-weight: 600; }

/* ---------------------------------------------------------------------------
   Company milestones — narrative replacement for the removed stats/timeline
   --------------------------------------------------------------------------- */
.milestones { max-width: 860px; margin: 0 auto; }
.milestones p { color: var(--color-body, #2C5577); line-height: 1.85; margin: 0 0 18px; }
.milestones p:last-child { margin-bottom: 0; }
.milestones p:first-child { font-size: 1.05rem; color: var(--color-ink, #0E3A5F); }

/* testimonial */
.testi { max-width: 680px; margin: 34px auto 0; text-align: center; font-size: 1.15rem; line-height: 1.6; color: var(--color-ink, #0E3A5F); font-style: italic; }
.testi cite { display: block; margin-top: 12px; font-style: normal; font-weight: 700; color: var(--color-dark-blue, #0E3A5F); font-size: 0.9rem; }

/* generic image placeholder area */
.img-ph { background: #eef2f7; border: 1px dashed #cfd8e6; border-radius: 12px; display: grid; place-items: center;
  color: #9aa7b6; font-size: 0.8rem; letter-spacing: 0.03em; min-height: 160px; text-align: center; padding: 12px; }

/* team grid */
.team { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
@media (max-width: 820px) { .team { grid-template-columns: 1fr 1fr; } }
.team__card { text-align: center; }
.team__photo { aspect-ratio: 1/1; border-radius: 14px; background: #eef2f7; border: 1px dashed #cfd8e6;
  display: grid; place-items: center; color: #9aa7b6; font-size: 0.75rem; margin-bottom: 12px; }
.team__card h3 { margin: 0; font-size: 1rem; color: var(--color-dark-blue, #0E3A5F); }
.team__role { color: var(--color-light-blue, #4A90D9); font-size: 0.85rem; font-weight: 600; margin: 2px 0 6px; }
.team__bio { color: var(--color-muted, #6b7688); font-size: 0.85rem; line-height: 1.55; margin: 0; }

/* NB: the visual milestones timeline (.timeline) was removed in the 2026-08
   content update at the client's request — the growth story is now told as
   narrative prose in the .milestones block above, with no dates or figures. */
.hero .hero__inner { position: relative; z-index: 2; }
.hero .hero__visual { position: relative; }
.hero__floor { position: absolute; inset: -14% -8%; z-index: 0; overflow: hidden; pointer-events: none;
  --tbase: rgba(74,144,217,0.05); --tpeak: rgba(140,195,255,0.24); }
.hero__floor .plane { position: absolute; left: 50%; top: 56%; width: 200%; height: 200%;
  transform: translate(-50%, -50%) perspective(680px) rotateX(52deg); transform-origin: center;
  display: grid; gap: 4px;
  -webkit-mask-image: radial-gradient(ellipse at center, #000 28%, transparent 70%);
          mask-image: radial-gradient(ellipse at center, #000 28%, transparent 70%); }
.hero__floor .tile { background: var(--tbase); border-radius: 2px; animation: esnadTile 4.2s ease-in-out infinite; }
@keyframes esnadTile { 0% { background: var(--tbase); } 10% { background: var(--tpeak); } 30%, 100% { background: var(--tbase); } }
.hero .site-logo { position: relative; z-index: 2; }
@media (prefers-reduced-motion: reduce) { .hero__floor .tile { animation: none; } }

/* full-width tiled-floor background spanning the header and footer bars.
   NB: header keeps its sticky position from style.css — only clip overflow here. */
/* NB: never put overflow:hidden on .site-header. It has backdrop-filter,
   which makes it the containing block for position:fixed descendants — the
   clip then swallows the whole mobile nav panel and the burger appears dead.
   .esnad-floor below already clips itself (inset:0 + overflow:hidden), which
   is all this ever needed to do. */
.site-footer { position: relative; overflow: hidden; }
.site-header > .container { position: relative; z-index: 1; }
.site-footer > .container { position: relative; z-index: 1; }
.esnad-floor { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
  --tbase: rgba(74,144,217,0.05); --tpeak: rgba(140,195,255,0.24); }
.esnad-floor .plane { position: absolute; left: 50%; top: 56%; width: 200%; height: 220%;
  transform: translate(-50%, -50%) perspective(720px) rotateX(54deg); transform-origin: center;
  display: grid; gap: 4px;
  -webkit-mask-image: radial-gradient(130% 100% at 50% 55%, #000 42%, transparent 88%);
          mask-image: radial-gradient(130% 100% at 50% 55%, #000 42%, transparent 88%); }
.esnad-floor .tile { background: var(--tbase); border-radius: 2px; animation: esnadTile 4.2s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .esnad-floor .tile { animation: none; } }

/* B2 — HEADER ONLY: static, no flow, rendered in the bright highlight colour.
   That colour is the animation's own peak: --tpeak is rgba(74,144,217,0.52),
   which over the header's white bar composites to exactly #A1C5EB (sampled
   from a render, 25,410px of it, not estimated). It is published as
   --color-tile-blue so B6 and B13 can reuse the identical value.
   The footer keeps its animation — this change is header-only. */

/* Below 1024px the builder lays a finer grid, so only every third tile carries
   the animation — the wave still crosses the strip, but the animated-node count
   stays in the same range as desktop's. */
@media (max-width: 1024px) {
  .esnad-floor .tile { animation: none; }
  .esnad-floor .tile--lit { animation: esnadTile 4.2s ease-in-out infinite; }
}
@media (prefers-reduced-motion: reduce) { .esnad-floor .tile--lit { animation: none; } }
/* ===== hover states =====
   NB: the nav's old solid-blue hover block lived here and, because logo.css
   loads after style.css, it was overriding the thin-underline hover defined
   there. Nav hover is now underline-only — see .main-nav a::after in
   style.css. Do not reintroduce a background here. */
a:not(.btn):hover { color: var(--color-dark-blue, #0E3A5F); text-decoration: none; }

/* ---- NAV HOVER — THE ONE DEFINITION. DO NOT MOVE THIS TO style.css -----
   This lived in style.css for three rounds and was silently beaten every time
   by the `a:not(.btn):hover` rule directly above.

   Why: `a:not(.btn):hover` has specificity (0,2,1) -- :not() counts the class
   inside it -- which is EXACTLY the same as `.main-nav a:hover`. Equal
   specificity is settled by source order, and logo.css loads after style.css,
   so the blanket rule repainted the text navy on a navy pill.

   The active item was never affected because `.main-nav a.is-active:hover` is
   (0,3,1), one class higher, so it outranked the blanket rule. That is the
   whole reason "Home" worked and nothing else did.

   Defining it here, after the blanket rule, means the plain selector wins on
   source order and the active selector wins on specificity -- so both land on
   identical declarations. Verified over the DevTools Protocol with :hover
   forced on all 8 links: every one reports white on navy, 11.74:1. */
.main-nav a:hover,
.main-nav a:focus-visible,
.main-nav a.is-active:hover,
.main-nav a.is-active:focus-visible {
  background: var(--color-dark-blue, #0E3A5F);
  color: #fff;
  transform: scale(1.06);
  text-decoration: none;
}
/* logo.css loads after style.css, so these once cancelled the nav hover. The
   hover treatment is now a navy pill defined in style.css — do not reintroduce
   a `background: none` here or it will silently kill it again. */
.main-nav a:hover { text-decoration: none; }
.lang-flags a:hover { background: rgba(74,144,217,0.30); color: var(--color-dark-blue, #0E3A5F); text-decoration: none; }
.site-footer a:hover { color: #fff; text-decoration: none; }
.btn:hover { box-shadow: 0 6px 18px rgba(14,58,95,0.28); filter: brightness(0.94); }

/* header variant — flatter & shorter so the perspective floor fits the thin header bar cleanly */
.esnad-floor--header { --tbase: rgba(74,144,217,0.12); --tpeak: rgba(74,144,217,0.52); }
/* shifted DOWN so a full tile row ends flush with the header's bottom edge
   (no ~5% partial sliver at the bottom; top row now ~75-80% visible). Tunable via `top`. */
.esnad-floor--header .plane { top: 61%; height: 460%; transform: translate(-50%, -50%) perspective(440px) rotateX(62deg); gap: 3px; }
/* footer variant — fill the whole footer bar, including the area above the text */
/* Desktop geometry, unchanged: the plane is 320% of a 473px footer = 1513px,
   centred 46% down, which reaches the footer's top edge comfortably. The
   mobile case needs different numbers and is handled in the media query
   below — see the note there for why. */
.esnad-floor--footer .plane { top: 46%; height: 320%;
  -webkit-mask-image: radial-gradient(165% 170% at 50% 42%, #000 64%, transparent 97%);
          mask-image: radial-gradient(165% 170% at 50% 42%, #000 64%, transparent 97%); }
/* ---- mobile / tablet floor -------------------------------------------
   Desktop above is the reference and must not be altered. These rules only
   change how MUCH plane there is, never its angle, gradient or tile shape —
   the transform and mask are deliberately inherited so the flow reads
   identically at every width.

   The footer grows from 473px on desktop to ~1073px on a 390px phone, so a
   plane sized at 320% of it becomes enormous and its 12 fixed rows stretch
   into slivers. Bringing the height down keeps the plane in proportion; the
   row and column counts are then derived per width in logo-reveal.js so the
   tile SHAPE stays the same as desktop's. */
@media (max-width: 1024px) {
  /* MOBILE FOOTER GEOMETRY — why these numbers.
     A plane under perspective(720px) rotateX(54deg) has a horizon at
     720/tan(54) = 523px above its own centre. It can never draw above that,
     and it only approaches it asymptotically: a half-height of 950px reaches
     270px, 6000px still only reaches 456px.
     The mobile footer is ~1000px tall, so top:46% puts the centre 460px below
     its top edge — more than a sane plane can reach upward. That is why the
     previous 1900px cap left a ~210px bare band: not a wrong number, a limit
     of the projection. Raising the cap would need a ~13000px plane, which is
     exactly the runaway that caused the mono-colour compression.
     Downward reach has no such limit (a half-height of 850px covers 11000px
     down), so the fix is to move the plane's CENTRE close to the footer's top
     and let the near field cover everything below it. top:20% keeps the
     upward requirement at ~200-220px across 375-430px widths, well inside the
     ~256px a 1700px plane delivers, while the depth stays near desktop's so
     the compression cannot return. */
  .esnad-floor--footer .plane {
    top: 20%;
    height: min(320%, 1700px);
    -webkit-mask-image: radial-gradient(210% 210% at 50% 34%, #000 84%, transparent 100%);
            mask-image: radial-gradient(210% 210% at 50% 34%, #000 84%, transparent 100%); }
}
/* footer lockup: block sits left in the column, but the emblem stays centred
   over the wordmark below it (same as the original logo — do not left-align the em). */
.footer__brand .site-logo { --lem: 104px; align-items: center; }
/* the full-size lockup dominates a phone footer — scale it back */
@media (max-width: 620px) { .footer__brand .site-logo { --lem: 62px; } }
@media (max-width: 380px) { .footer__brand .site-logo { --lem: 54px; } }

/* flag language switcher (English / Arabic only) */
.lang-flags { display: inline-flex; align-items: center; gap: 6px; }
/* D5: the flag was rendering greyed out. Cause was `opacity: 0.62` on the
   LINK -- it dimmed the whole thing, flag included, so a full-colour national
   flag was washed out. The de-emphasis belongs on the label text only, so the
   opacity is gone and the muted look is carried by the text colour instead.
   The flag itself is now pinned to full opacity so nothing can dim it again. */
.lang-flags a {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 9px; border-radius: 8px;
  text-decoration: none; font-size: 0.8rem; font-weight: 700; letter-spacing: 0.03em;
  color: var(--color-muted, #6b7688); opacity: 1; transition: 0.15s;
}
.lang-flags .flag { opacity: 1; filter: none; }
.lang-flags a:hover { color: var(--color-dark-blue, #0E3A5F); background: rgba(14, 58, 95, 0.06); }
.lang-flags a.is-current { opacity: 1; color: var(--color-navy, #0E3A5F); }
/* B4: real flags now, so their true ratios are respected rather than both
   being squashed into one 22x15 box. Saudi Arabia is 2:3 and the United States
   is 10:19 -- forcing a shared width distorted the US flag noticeably. Height
   is fixed so the two still line up on the same baseline. */
.lang-flags .flag { height: 15px; width: auto; border-radius: 2px; box-shadow: 0 0 0 1px rgba(0,0,0,0.14); flex: 0 0 auto; display: block; }

/* ---------------------------------------------------------------------------
   Full-width hero slideshow (replaces the old boxed "What's New" card)
   Sits directly under the hero, edge to edge: no container, no card, no
   background of its own — the photography fills the full width itself.
   Crossfade only; nothing slides or bounces.
   --------------------------------------------------------------------------- */
.hero-slides { position: relative; width: 100%; margin: 0; padding: 0;
  overflow: hidden; background: none; line-height: 0;
  aspect-ratio: 12 / 5; max-height: 660px; }
@media (max-width: 760px) { .hero-slides { aspect-ratio: 3 / 2; max-height: none; } }

.hero-slides__slide { position: absolute; inset: 0; margin: 0;
  opacity: 0; transition: opacity .8s ease-in-out; }
.hero-slides__slide.is-on { opacity: 1; }
.hero-slides__slide img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* B11: the first Projects slide was cropping from the centre, which cut the
   bottom of the frame. object-position pins the image to the BOTTOM of the
   box, so any crop is taken off the TOP only and the bottom edge is always
   fully visible -- which is what was asked for. Only the first slide: the
   others were not flagged and centre-cropping suits them. */
/* SUPERSEDED (kept for history): B11 anchored the first slide to the bottom
   so the frame trimmed only its top. With the band now at the images' own
   16:9 there is no trim to steer, and the Round 10 rule further down sets
   every slide to centre. */
/* .hero-slides__slide:first-of-type img { object-position: 50% 100%; } */

/* caption scrim — keeps the text legible over any photograph */
.hero-slides__cap { position: absolute; left: 0; right: 0; bottom: 0;
  padding: 54px 34px 20px;
  background: linear-gradient(to top, rgba(10,44,73,0.72), rgba(10,44,73,0));
  color: #fff; font-size: 0.92rem; line-height: 1.5; font-weight: 500;
  text-shadow: 0 1px 10px rgba(0,0,0,0.45); }
@media (max-width: 760px) { .hero-slides__cap { font-size: 0.82rem; padding: 40px 18px 16px; } }

/* dots */
.hero-slides__dots { position: absolute; inset-inline-end: 22px; bottom: 20px; z-index: 3;
  display: flex; gap: 8px; }
.hero-slides__dots button { width: 9px; height: 9px; padding: 0; border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.85); background: transparent; cursor: pointer;
  transition: background .2s, transform .2s; }
.hero-slides__dots button[aria-selected="true"] { background: #fff; transform: scale(1.25); }

/* explicit play/pause — replaces the old pause-on-hover, which could hold the
   slideshow stopped indefinitely whenever the cursor rested over the band */
/* The control used to hold a ⏸ / ▶ text glyph, which sits on the text
   baseline and is optically off-centre in a round button — and renders at a
   different size on every platform. An inline SVG centres exactly. */
.hero-slides__toggle { position: absolute; inset-inline-end: 22px; bottom: 42px; z-index: 3;
  width: 34px; height: 34px; border-radius: 50%; cursor: pointer; padding: 0;
  border: 1px solid rgba(255,255,255,0.85); background: rgba(10,44,73,0.45);
  color: #fff; display: flex; align-items: center; justify-content: center;
  transition: background .2s; }
.hero-slides__toggle svg { width: 13px; height: 13px; display: block; fill: currentColor; }
.hero-slides__toggle:hover { background: rgba(10,44,73,0.75); }
.hero-slides__dots button:hover { background: rgba(255,255,255,0.6); }
[dir="rtl"] .hero-slides__cap { text-align: right; }

@media (prefers-reduced-motion: reduce) {
  /* drop the crossfade but let the slides keep advancing — the explicit
     play/pause control satisfies the pause requirement */
  .hero-slides__slide { transition: none; }
}

/* ---------------------------------------------------------------------------
   PHASE 8 — product card: image carousel, original copy, contact link
   --------------------------------------------------------------------------- */
.prod { display: flex; flex-direction: column; }
.prod__desc { color: var(--color-body, #2C5577); font-size: 0.92rem; line-height: 1.7; margin: 0 0 14px; flex: 1 1 auto; }
.prod__cta { align-self: flex-start; font-size: 0.85rem; font-weight: 600;
  color: var(--color-light-blue-600, #2b6cb8); text-decoration: none; }
.prod__cta:hover { text-decoration: underline; }
.prod__cta span { transition: transform .18s ease; display: inline-block; }
.prod__cta:hover span { transform: translateX(3px); }
[dir="rtl"] .prod__cta span { transform: scaleX(-1); }
[dir="rtl"] .prod__cta:hover span { transform: scaleX(-1) translateX(3px); }

/* carousel — one image visible, arrows step through that product's set */
.pcar {
  position: relative;
  /* The shared .media-ph frame is a fixed 190px strip, which squeezed product
     shots into a thin letterbox and read as cropping. A 4:3 frame is closer to
     the natural shape of these images, so contain has room to show the whole
     unit at a sensible size. Nothing is cropped — object-fit stays contain. */
  height: auto;
  aspect-ratio: 4 / 3;
  max-height: 300px;
  background: #fff;
}
.pcar__track { position: relative; width: 100%; height: 100%; }
.pcar__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain;
  padding: 14px; box-sizing: border-box; opacity: 0; transition: opacity .35s ease; }
.pcar__img.is-on { opacity: 1; }
.pcar__nav { position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 28px; height: 28px; border-radius: 50%; cursor: pointer; padding: 0;
  border: 1px solid var(--color-line, #e3e8ef); background: rgba(255,255,255,0.92);
  color: var(--color-dark-blue, #0E3A5F); font-size: 17px; line-height: 1;
  display: grid; place-items: center; transition: opacity .18s, background .18s;
  /* Visible at rest on every device, not hover-only: the brief asks for arrow
     controls on desktop as well as mobile, and a control you have to discover
     by hovering is not really there. Softened so it does not fight the photo. */
  opacity: 0.72; }
.pcar:hover .pcar__nav, .pcar__nav:focus-visible { opacity: 1; }
.pcar__nav:hover { background: #fff; border-color: var(--color-light-blue, #4A90D9); }
.pcar__nav--prev { left: 8px; }
.pcar__nav--next { right: 8px; }
.pcar__dots { position: absolute; left: 0; right: 0; bottom: 6px; z-index: 2;
  display: flex; gap: 5px; justify-content: center; }

/* ---- touch: swipe the carousel instead of hunting for the arrows ----
   Must come after the base .pcar rules above, and the scroller has to be
   .pcar__track — that is the element the images are actually children of.
   Desktop keeps the crossfade. */
@media (hover: none), (max-width: 760px) {
  .pcar__track { display: flex; overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* the arrows set scrollLeft directly; this is what animates that move */
    scroll-behavior: smooth; }
  .pcar__track::-webkit-scrollbar { width: 0; height: 0; display: none; }
  .pcar__track .pcar__img { position: relative; inset: auto;
    flex: 0 0 100%; width: 100%; height: 100%;
    opacity: 1; transition: none; scroll-snap-align: center; }
  .pcar__nav { display: none; }
}
.pcar__dots span { width: 5px; height: 5px; border-radius: 50%; background: #c3ccd8; }
.pcar__dots span.is-on { background: var(--color-light-blue, #4A90D9); }

/* ---------------------------------------------------------------------------
   PHASES 9-10 — shared form styling (contact enquiry + career application)
   Replaces the inline styles the original contact form carried.
   --------------------------------------------------------------------------- */
.frm { display: grid; gap: 14px; max-width: 560px; margin-top: 16px; position: relative; }
.frm label { display: grid; gap: 6px; font-size: 0.88rem; font-weight: 600;
  color: var(--color-dark-blue, #0E3A5F); }
.frm input, .frm select, .frm textarea {
  padding: 12px 14px; border: 1px solid #cfd8e6; border-radius: 8px;
  font: inherit; color: var(--color-ink, #1a2230); background: #fff; width: 100%;
  box-sizing: border-box; transition: border-color .16s, box-shadow .16s; }
.frm input:focus, .frm select:focus, .frm textarea:focus {
  outline: none; border-color: var(--color-light-blue, #4A90D9);
  box-shadow: 0 0 0 3px rgba(74,144,217,0.16); }
.frm textarea { resize: vertical; min-height: 120px; }
.frm .frm__row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 620px) { .frm .frm__row { grid-template-columns: 1fr; } }
.frm .frm__hint { font-size: 0.78rem; font-weight: 400; color: var(--color-muted, #6b7688); }
.frm button { justify-self: start; }
.frm__note { font-size: 0.8rem; color: var(--color-muted, #6b7688); margin: 0; }

/* ---------------------------------------------------------------------------
   PHASE 11 — Projects timeline (CV style)
   Date on one side, project on the other, joined by a rule with a marker per
   entry. Entries carry data-reveal, so they fade in as the page scrolls.
   --------------------------------------------------------------------------- */
/* Projects / About band.
   Both slide sets are generated at exactly this ratio (1920x960), so `cover`
   fills the frame edge to edge with nothing trimmed at display time. The only
   crop is the deliberate, per-image one applied when the files are built —
   which keeps the subject framed instead of slicing it. No mat is needed. */
.hero-slides--page { aspect-ratio: 2 / 1; max-height: 620px; }
@media (max-width: 760px) {
  .hero-slides--page { aspect-ratio: 4 / 3; max-height: none; }
}

.tl { list-style: none; margin: 0; padding: 0; position: relative; }
/* The gap goes on .tl__body, NOT on the item. Padding on the grid container
   sits outside the rows, so the stretched marker stopped short of the next dot
   and the rule came out dashed. Padding the body keeps the row (and the line)
   running the full distance between markers. */
.tl__item { display: grid; grid-template-columns: 168px 44px 1fr; align-items: stretch; }
.tl__body { padding-bottom: 38px; }
.tl__item:last-child .tl__body { padding-bottom: 0; }
.tl__date { text-align: right; padding-top: 2px; font-weight: 700; font-size: 0.9rem;
  color: var(--color-light-blue-600, #2b6cb8); white-space: nowrap; }

/* the middle column draws the connecting rule and its marker */
.tl__marker { position: relative; align-self: stretch; justify-self: center; width: 2px;
  background: var(--color-line, #e3e8ef); }
.tl__item:first-child .tl__marker {
  background: linear-gradient(to bottom, transparent 9px, var(--color-line, #e3e8ef) 9px); }
.tl__item:last-child .tl__marker {
  background: linear-gradient(to bottom, var(--color-line, #e3e8ef) 24px, transparent 24px); }
.tl__marker::before { content: ""; position: absolute; top: 4px; left: 50%;
  transform: translateX(-50%); width: 11px; height: 11px; border-radius: 50%;
  background: var(--color-light-blue, #4A90D9); border: 2px solid #fff;
  box-shadow: 0 0 0 3px rgba(74,144,217,0.18); }

.tl__body h3 { margin: 0 0 10px; font-size: 1.04rem; line-height: 1.4;
  color: var(--color-dark-blue, #0E3A5F); }
.tl__body p { margin: 0; color: var(--color-body, #2C5577); font-size: 0.92rem; line-height: 1.7; }
.tl__body .proj-meta { margin-bottom: 10px; }

[dir="rtl"] .tl__date { text-align: left; }

@media (max-width: 760px) {
  .tl__item { grid-template-columns: 26px 1fr; column-gap: 14px; }
  .tl__date { grid-column: 2; text-align: left; margin-bottom: 6px; }
  [dir="rtl"] .tl__date { text-align: right; }
  .tl__marker { grid-column: 1; grid-row: 1 / span 2; }
  .tl__body { grid-column: 2; }
}

/* ---------------------------------------------------------------------------
   Career page — no-vacancy notice and how-to-apply block
   --------------------------------------------------------------------------- */
.notice { max-width: 760px; margin: 0 auto; background: rgba(74,144,217,0.06);
  border: 1px solid rgba(74,144,217,0.22); border-radius: 14px; padding: 22px 26px; }
.notice p { margin: 0 0 10px; color: var(--color-body, #2C5577); line-height: 1.7; }
.notice p:last-child { margin-bottom: 0; }
.notice strong { color: var(--color-dark-blue, #0E3A5F); }

.howto { max-width: 760px; margin: 26px auto 0; }
.howto h3 { margin: 0 0 12px; font-size: 1.02rem; color: var(--color-dark-blue, #0E3A5F); }
.howto ol { margin: 0 0 12px; padding-inline-start: 22px; list-style: decimal; }
.howto li { color: var(--color-body, #2C5577); font-size: 0.94rem; line-height: 1.75; margin-bottom: 6px; }
.howto__note { margin: 0; font-size: 0.88rem; color: var(--color-muted, #6b7688); line-height: 1.7; }

/* ---------------------------------------------------------------------------
   Contact map embed + form submission states
   --------------------------------------------------------------------------- */
.map-embed { position: relative; border-radius: 12px; overflow: hidden;
  border: 1px solid var(--color-line, #e3e8ef); aspect-ratio: 4 / 3; margin-top: 18px; }
.map-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.map-note { margin: 8px 0 0; font-size: 0.86rem; }
.map-note a { color: var(--color-light-blue-600, #2b6cb8); text-decoration: none; font-weight: 600; }
.map-note a:hover { text-decoration: underline; }

/* honeypot — never focusable, invisible to real visitors.
   NB: do not hide this with left:-9999px. The Arabic pages are dir="rtl",
   where leftward overflow is *forward* overflow, so that trick added ~9950px
   of horizontal scroll to career.html and contact.html. Clipping in place
   hides it just as well and takes up no space in either direction. */
.frm__bot { position: absolute !important; top: 0; left: 0; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  opacity: 0; pointer-events: none; }

.frm__note { font-size: 0.82rem; line-height: 1.6; margin: 0; }
.frm__note[hidden] { display: none; }
.frm__note--warn { color: #8a5a00; }
.frm__note--ok { color: #1c7a45; font-weight: 600; }
.frm__note--err { color: #b3261e; }
.frm button[disabled] { opacity: .6; cursor: default; }

/* row holding a "view all" button under a grid */
.more-row { display: flex; justify-content: center; margin-top: 34px; }

/* ---- B2: slideshow overlay spacing -------------------------------------
   The caption strip and the controls share the same bottom-right corner. Keep
   the text clear of them at every width; on phones give the controls a band of
   their own beneath the caption text. */
.hero-slides__cap { padding-inline-end: 92px; }        /* never run under the controls */
@media (max-width: 760px) {
  .hero-slides__cap {
    padding: 34px 14px 46px;                            /* 46px band for the controls */
    padding-inline-end: 14px;
    font-size: 0.8rem; line-height: 1.45;
  }
  /* controls sit in that band, one at each end, well clear of the text */
  .hero-slides__toggle { inset-inline-start: 14px; inset-inline-end: auto;
    bottom: 10px; width: 32px; height: 32px; }
  .hero-slides__dots { inset-inline-start: auto; inset-inline-end: 14px;
    bottom: 20px; gap: 7px; }
  .hero-slides__dots button { width: 8px; height: 8px; }
}

/* ---- A13: full-bleed slideshow sits on the same rhythm as a section ----
   .hero-slides sets `margin: 0` above, so this has to live after it. The band
   carries no padding of its own; without a margin it sat hard against the page
   title with a large gap underneath. Exception: when it leads the page
   (Projects) it should still run straight up under the header. */
/* Item 5b: the bottom margin is gone. Margin sits OUTSIDE the band, so an
   88px white strip of body background showed between the slideshow and the
   tinted section below it. The following section already carries its own
   padding-top (`.hero-slides + .section`), so removing the margin loses no
   breathing room -- it just moves that space INSIDE the tint, and the colour
   now starts exactly where the slideshow ends. */
.hero-slides--page { margin-block: clamp(56px, 7vw, 96px) 0; }
main > .hero-slides--page:first-child { margin-top: 0; }

/* ---- item 3: slideshow arrows -----------------------------------------
   Shown at every width, including touch, alongside swipe. */
.hero-slides__nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 40px; height: 40px; border-radius: 50%; padding: 0; cursor: pointer;
  border: 1px solid rgba(255,255,255,0.85); background: rgba(10,44,73,0.45);
  color: #fff; display: flex; align-items: center; justify-content: center;
  transition: background .2s;
}
.hero-slides__nav svg { width: 18px; height: 18px; display: block; }
.hero-slides__nav:hover { background: rgba(10,44,73,0.78); }
.hero-slides__nav--prev { inset-inline-start: 14px; }
.hero-slides__nav--next { inset-inline-end: 14px; }
/* mirrored automatically in RTL by the logical insets above, but the glyphs
   themselves must also flip so "next" still points the way reading travels */
[dir="rtl"] .hero-slides__nav svg { transform: scaleX(-1); }
@media (max-width: 760px) {
  .hero-slides__nav { width: 34px; height: 34px; }
  .hero-slides__nav svg { width: 15px; height: 15px; }
  .hero-slides__nav--prev { inset-inline-start: 8px; }
  .hero-slides__nav--next { inset-inline-end: 8px; }
}
/* the per-product carousels keep their arrows on touch too — they were hidden
   there when swipe was added, which left no visible control on a phone */
@media (hover: none), (max-width: 760px) {
  .pcar__nav { display: grid; opacity: 1; }
}

/* ---- About page prose: use the container width (client width fix) ------
   These two are capped above; the override has to be after those rules. The
   Values and Goals card grids are untouched — they are columns, not capped
   prose, and already fill their row. */
.goals-tagline { max-width: none; }
.milestones { max-width: none; }

@media (prefers-reduced-motion: reduce) {
  .pcar__track { scroll-behavior: auto; }
}

/* B2 — HEADER ONLY: static field in the bright highlight colour.
   Placed at the end of the file, and matching .tile--lit explicitly, so it
   also beats the max-width:1024px rule above that re-enables the flow on lit
   tiles. Without that the animation's keyframes overwrote this background on
   every third header tile, which read as a patchy, half-coloured header.
   The footer keeps its animation — this is header-only. */
.esnad-floor--header .tile,
.esnad-floor--header .tile.tile--lit {
  animation: none;
  background: var(--color-tile-blue, #A1C5EB);
}

/* B15: the contact details sitting above the embedded map read bold. */
.contact-details li,
.contact-details li a { font-weight: 700; }

/* ---- Form validation: visible, persistent field errors -------------------
   Replaces the browser's native bubble, which showed one field at a time and
   vanished after a few seconds. Red is paired with an icon glyph and a text
   message so the state is never carried by colour alone. */
.frm__err {
  display: block;
  margin-top: 6px;
  font-size: 0.85rem;
  font-weight: 600;
  color: #B3261E;                 /* 5.9:1 on white — AA for small text */
  line-height: 1.35;
}
.frm__err::before { content: "\26A0\FE0E"; margin-inline-end: 6px; }
.frm input.is-invalid,
.frm textarea.is-invalid,
.frm select.is-invalid {
  border-color: #B3261E;
  box-shadow: 0 0 0 3px rgba(179, 38, 30, 0.12);
}
.frm input.is-invalid:focus,
.frm textarea.is-invalid:focus {
  outline-color: #B3261E;
}

/* ---- logo tiles link to the company's own site --------------------------
   The <a> wraps the mark and its caption, so the whole tile is the hit area.
   .logo-tile is a flex column and the link is now its only child, so the link
   has to carry that same layout or the mark and caption lose their alignment.
   Appearance is unchanged: no underline, no colour shift -- the existing tile
   hover still does the work, and :focus-within extends it to keyboard users. */
.logo-tile__link {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; flex: 1 1 auto; width: 100%; min-height: 0;
  text-decoration: none; color: inherit;
}
.logo-tile__link:hover,
.logo-tile__link:focus { text-decoration: none; color: inherit; }
.logo-tile:focus-within {
  border-color: var(--color-light-blue, #4A90D9);
  box-shadow: 0 10px 26px rgba(14,58,95,0.10);
}
.logo-tile__link:focus-visible {
  outline: 3px solid var(--color-dark-blue, #0E3A5F);
  outline-offset: 4px;
  border-radius: 8px;
}

/* ======================================================================
   ROUND 4 — Mission & Vision cards, Projects by year, Career figure
   ====================================================================== */

/* ---- Item 5: Mission and Vision -----------------------------------------
   Stacked VERTICALLY -- Mission above Vision -- and inside each card the text
   and image sit side by side: image RIGHT of Mission, LEFT of Vision.

   The image is shown WHOLE. It was previously forced into a 4/5 portrait box
   while both source files are 3:2 landscape, so it was cover-cropped to a
   narrow vertical slice. At 3/2 the box matches the source exactly, which
   means cover and contain are identical: nothing is cropped and there is no
   letterboxing.

   Column widths are deliberately unequal per card. Mission's text runs 871
   characters and Vision's 346, so each gives its text the share it needs. */
.mv-wrap { display: flex; flex-direction: column; gap: 22px; }

.mv-panel {
  --mv-gap: clamp(18px, 2.4vw, 32px);
  display: grid;
  align-items: center;
  gap: 0;
  padding: clamp(20px, 2.6vw, 30px);
  overflow: hidden;
  transition: transform .18s ease, box-shadow .18s ease;
}
.mv-panel + .mv-panel { margin-top: 0; }
.mv-panel--mission {
  grid-template-columns: minmax(0, 1.35fr) auto minmax(0, 1fr);
  grid-template-areas: "text link media";
}
.mv-panel--vision {
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1.2fr);
  grid-template-areas: "media link text";
}
.mv-panel__text  { grid-area: text; padding: 0; }
.mv-panel__media { grid-area: media; margin: 0; }
.mv-panel__link  { grid-area: link; }
.mv-panel__text > :first-child { margin-top: 0; }
.mv-panel__text > :last-child  { margin-bottom: 0; }
.mv-panel h3 { margin: 0 0 12px; }
.mv-panel p  { margin: 0; }

.mv-panel__media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;      /* the source ratio -- so nothing is cropped */
  object-fit: cover;
  object-position: center;
  border-radius: 12px;
}

/* The connector: a dotted rule down the gutter with a dot at each end, so the
   two halves read as one unit instead of two boxes side by side. */
.mv-panel__link {
  align-self: stretch;
  position: relative;
  width: 3px;
  margin: 14% var(--mv-gap);
  background-image: radial-gradient(circle,
      var(--color-light-blue, #4A90D9) 1.2px, transparent 1.6px);
  background-size: 3px 10px;
  background-repeat: repeat-y;
  opacity: 0.5;
}
.mv-panel__link::before,
.mv-panel__link::after {
  content: "";
  position: absolute;
  inset-inline-start: 50%;
  translate: -50% 0;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--color-light-blue, #4A90D9);
}
.mv-panel__link::before { top: -8px; }
.mv-panel__link::after  { bottom: -8px; }

@media (max-width: 820px) {
  /* One column. The connector turns horizontal and the text is forced above
     the image in BOTH cards so the reading order stays sane. */
  .mv-panel--mission,
  .mv-panel--vision {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "text" "link" "media";
  }
  .mv-panel__link {
    width: auto; height: 3px;
    margin: 18px 22%;
    background-size: 10px 3px;
    background-repeat: repeat-x;
  }
  .mv-panel__link::before { top: 50%; inset-inline-start: -8px; translate: 0 -50%; }
  .mv-panel__link::after  { top: 50%; bottom: auto; inset-inline-start: auto;
                            inset-inline-end: -8px; translate: 0 -50%; }
}

/* ---- A9: Projects grouped by year -------------------------------------
   Replaces the per-project timeline. The year is the structural device here
   because the content genuinely is a chronology, not a ranked list. */
.pyears { display: flex; flex-direction: column; gap: 40px; }
.pyear { position: relative; padding-inline-start: 26px; }
.pyear::before {
  content: "";
  position: absolute;
  inset-block: 6px 6px;
  inset-inline-start: 0;
  width: 3px;
  border-radius: 2px;
  background: var(--color-light-blue, #4A90D9);
}
.pyear__year {
  margin: 0 0 14px;
  font-size: clamp(1.6rem, 3vw, 2.1rem);
  font-weight: 800;
  color: var(--color-light-blue-600, #3a7bc0);
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
}
.pyear__list { margin: 0; padding-inline-start: 20px; display: flex; flex-direction: column; gap: 12px; }
.pyear__list li { color: var(--color-body, #2C5577); line-height: 1.75; max-width: var(--measure, 72ch); }
.pyear__list li::marker { color: var(--color-dark-blue, #0E3A5F); }
.pyears__closer { margin: 4px 0 0; font-weight: 600; color: var(--color-dark-blue, #0E3A5F); }

/* ---- Career page figure ----------------------------------------------- */
.page-figure { margin: 0 auto; max-width: 1140px; padding-inline: clamp(18px, 4vw, 32px); }
.page-figure img {
  display: block;
  width: 100%;
  max-height: 420px;
  object-fit: cover;
  object-position: 50% 100%;     /* trim from the top, per the brief */
  border-radius: 16px;
}

/* ---- C1: arrival glow on a deep-linked product -------------------------
   Arriving from the homepage's "View More Info", the target card pulses once
   so it is obvious which product you landed on. Driven by a class rather than
   :target so it can be removed when it finishes -- a :target style would stay
   applied for as long as the hash is in the URL. */
.prod.is-arrived {
  animation: prodGlow 2.2s cubic-bezier(.22,.7,.3,1) 1;
}
@keyframes prodGlow {
  0%   { box-shadow: 0 0 0 0 rgba(74,144,217,0.00); border-color: var(--color-line, #e3e8ef); }
  12%  { box-shadow: 0 0 0 6px rgba(74,144,217,0.35), 0 14px 40px rgba(14,58,95,0.18);
         border-color: var(--color-light-blue, #4A90D9); }
  55%  { box-shadow: 0 0 0 6px rgba(74,144,217,0.22), 0 14px 40px rgba(14,58,95,0.12);
         border-color: var(--color-light-blue, #4A90D9); }
  100% { box-shadow: 0 0 0 0 rgba(74,144,217,0.00); border-color: var(--color-line, #e3e8ef); }
}
@media (prefers-reduced-motion: reduce) {
  /* No pulse, but the visitor still needs to see which card they arrived at,
     so it gets a steady outline instead of an animated one. */
  .prod.is-arrived { animation: none; box-shadow: 0 0 0 3px rgba(74,144,217,0.45); }
}

/* A3: the homepage product cards are now image + name + button, so the card
   needs to push its button to the bottom or the grid rows look ragged. */
.prod__more { margin-top: auto; align-self: flex-start; }
.grid--3 > .card:has(.prod__more) { display: flex; flex-direction: column; gap: 10px; }

/* ---- Phone field: country code + number -------------------------------- */
.telgrp { display: flex; gap: 8px; align-items: stretch; }
/* The country control is a flag graphic plus the code, held to roughly 30% of
   the row so the number field gets the remaining ~70%. */
.telgrp { position: relative; }
.telgrp__cc {
  flex: 0 0 30%;
  width: 30%;
  min-width: 0;
  max-width: none;
  /* Room for the flag chip. The whole control is ~81px at the form's column
     width, so the flag, the code and the native dropdown arrow all have to fit
     inside that -- hence the tighter padding and slightly smaller text. */
  text-align: start;
  font: inherit;
  color: var(--color-ink, #0E3A5F);
  background: #fff;
  border: 1px solid var(--color-line, #e3e8ef);
  border-radius: var(--radius-sm, 8px);
  padding: 12px 10px;
}
.telgrp__num { flex: 1 1 70%; width: 70%; min-width: 0; }
.telgrp__cc:focus-visible, .telgrp__num:focus-visible { outline-offset: 1px; }
/* The error message belongs under the whole group, not under one half. */
.telgrp + .frm__err, .telgrp ~ .frm__err { display: block; }
@media (max-width: 480px) {
  .telgrp { flex-direction: column; }
  .telgrp__cc { max-width: none; }
}

/* ---- Item 6: service cards size to their own content -------------------
   The grid stretched every card to the tallest one in the row, which left the
   short Partial Discharge card (203 characters against 588 for the longest)
   with a large empty area under its text. align-items:start lets each card end
   where its content ends. Width and styling are untouched, so the row still
   reads as one set. */
.services-grid { align-items: start; }

/* ======================================================================
   ROUND 9 — items 7, 8, 9
   ====================================================================== */

/* ---- Item 7: Projects timeline ----------------------------------------
   A continuous rule down the page with a large marker per YEAR and a small
   dot per bullet, so the structure of the list is visible again. The dots are
   drawn on the list items themselves, so a year with three entries gets three
   dots without anything being hand-placed.
   Offsets use logical properties throughout, so the whole thing mirrors on the
   Arabic pages without a second set of rules. */
.pyears {
  position: relative;
  padding-inline-start: 42px;
  display: flex;
  flex-direction: column;
  gap: 38px;
}
/* the rule itself */
.pyears::before {
  content: "";
  position: absolute;
  /* Unbroken from the first marker to the last. The markers paint over it
     (z-index 2), so it reads as one continuous line passing behind them. */
  inset-block: 14px 14px;
  inset-inline-start: 9px;
  z-index: 0;
  width: 2px;
  /* Sampled from the header and footer: the nav links and brand wordmark both
     compute to #0E3A5F (--color-dark-blue). The timeline was on the lighter
     #4A90D9 / #3A7BC0 pair, which is why it read as a different blue. */
  background: linear-gradient(180deg,
      var(--color-dark-blue, #0E3A5F),
      color-mix(in srgb, var(--color-dark-blue, #0E3A5F) 30%, transparent));
  border-radius: 2px;
}
.pyear { position: relative; padding-inline-start: 0; }
.pyear::before { content: none; }           /* the old single bar is gone */

.pyear__year {
  position: relative;
  margin: 0 0 16px;
  font-size: clamp(1.5rem, 2.6vw, 1.95rem);
  font-weight: 800;
  color: var(--color-dark-blue, #0E3A5F);
  font-variant-numeric: tabular-nums;
}
/* the year marker: a filled disc with a white ring, sitting on the rule */
/* The rule runs down x=9..11, so its centre is x=10 measured from .pyears.
   Content starts at x=42 (the padding), so an offset of -42 puts a marker's
   LEFT EDGE on x=0. Centring a 20px marker on the line therefore needs
   -42 + (10 - 20/2) = -42px exactly, with NO extra margin. The previous rule
   also carried margin-inline-start:-9px on top of that, which is precisely why
   every dot sat 9px clear of the line. */
.pyear__year::before {
  content: "";
  position: absolute;
  inset-inline-start: -42px;      /* 20px dot -> centre lands on x=10 */
  top: 50%;
  translate: 0 -50%;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--color-dark-blue, #0E3A5F);
  box-shadow: 0 0 0 4px var(--color-bg, #fff);
  z-index: 2;
}

.pyear__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.pyear__list li {
  position: relative;
  color: var(--color-body, #2C5577);
  line-height: 1.75;
}
/* one dot per bullet, on the same rule */
.pyear__list li::before {
  content: "";
  position: absolute;
  /* 10px dot incl. its 2px border: -42 + (10 - 10/2) = -37px puts the centre
     on x=10, the same line the year markers sit on. */
  inset-inline-start: -37px;
  top: 0.55em;
  width: 10px; height: 10px;
  box-sizing: border-box;
  border-radius: 50%;
  background: var(--color-bg, #fff);
  border: 2px solid var(--color-dark-blue, #0E3A5F);
  z-index: 2;
}
.pyears__closer { margin: 0; font-weight: 600; color: var(--color-dark-blue, #0E3A5F); }

@media (max-width: 620px) {
  /* Mobile refinements. On a 375px screen the desktop gutter was taking 42px
     of an already narrow column, the year marker was large next to a smaller
     heading, and the year groups ran together. Everything is scaled to the
     column rather than inherited from desktop.

     Offsets re-derived for the narrower gutter: content starts at 26px and the
     rule's centre is x=8, so a 14px year marker sits at -26+(8-7) = -25, and a
     9px bullet at -26+(8-4.5) = -22. */
  .pyears { padding-inline-start: 26px; gap: 30px; }
  .pyears::before { inset-inline-start: 7px; inset-block: 11px 11px; }

  .pyear__year {
    font-size: 1.35rem;
    margin-bottom: 12px;
    letter-spacing: 0.02em;
  }
  .pyear__year::before {
    inset-inline-start: -25px;
    width: 14px; height: 14px;
    box-shadow: 0 0 0 3px var(--color-bg, #fff);
  }

  .pyear__list { gap: 12px; }
  .pyear__list li {
    font-size: 0.94rem;
    line-height: 1.7;
  }
  .pyear__list li::before {
    inset-inline-start: -22px;
    top: 0.52em;
    width: 9px; height: 9px;
    border-width: 2px;
  }
  .pyears__closer { margin-top: 2px; }
}

/* ---- Item 8: Career page image needs room ------------------------------
   The figure was overlapping the section below it by 26px. */
.page-figure {
  margin-block: clamp(16px, 2.4vw, 26px) clamp(36px, 5vw, 60px);
  position: relative;
  z-index: 1;
}

/* ---- Item 9: justified body text ---------------------------------------
   Standard justification -- the browser distributes small amounts of extra
   space between words so every line but the last reaches the same right edge.
   text-align-last:start keeps the final line ragged, which is what makes it
   read as justified prose rather than stretched-out text.

   Applied to standalone body copy and to the Career cards, which were called
   out specifically. NOT applied where the column is too narrow for it to look
   like anything but gaps: the product cards, the hero, captions and form text.
   In a 38-character column justification produces rivers of white space. */
main p,
.pyear__list li,
.mv-panel p,
.card p,
.intro p,
.lead {
  text-align: justify;
  text-align-last: start;
}
[dir="rtl"] main p,
[dir="rtl"] .pyear__list li,
[dir="rtl"] .card p { text-align: justify; text-align-last: start; }

/* Kept ragged on purpose. The hero paragraph is NO LONGER here -- it now gets
   the same justified treatment as the rest of the body copy. */
/* .card p (0,1,1) outranks a bare .prod__desc (0,1,0), so the product
   descriptions were being justified despite being listed here. Qualified to
   (0,2,1) so the exclusion actually wins. They sit in ~38-character columns,
   where justification produces rivers of white space rather than tidy edges.
   The Career cards are wider and stay justified, as asked. */
.card p.prod__desc,
.prod__desc,
figcaption,
.frm p,
.frm__note,
.frm__err,
.duns,
.site-footer p,
.pyears__closer,
.page-head p,
.section__head--center p,
.section__head--center .lead {
  text-align: start;
  text-align-last: auto;
}

/* ======================================================================
   ROUND 10 — slideshow framing (items 2 and 3)
   ======================================================================
   The band was aspect-ratio 12/5 (2.40) while almost every supplied image is
   3:2 (1.50). Covering a 1.50 image into a 2.40 box throws away 37% of its
   height -- the "too tightly zoomed in" the client is seeing.

   Fully avoiding a crop is not possible for a FULL-BLEED band: at 3/2 a
   1920px-wide viewport would need a 1280px-tall banner. So the ratio is opened
   as far as is sensible and the retained part is anchored per image.
   Measured: crop drops from ~37% of image height to ~18%.                  */
/* The 700px height cap is GONE. It was what made the band wider than 16:9 on
   large screens (1920 / 700 = 2.74:1), which forced a further crop on top of
   whatever the source already was. The images are now cropped to 16:9 by hand,
   so the frame is held to exactly 16:9 at every width -- cover and contain are
   then identical and nothing is re-cropped or letterboxed. */
/* Slideshow band sizing -- a balance, not a maximum of either constraint.
   The history, because four attempts got here:

     1. 16:9 + fixed 700px cap  -> full width, but ~35% of the image cropped.
     2. Pure 16:9, no cap       -> nothing cropped, but 1067px tall: scrolling.
     3. WIDTH capped to fit     -> fitted and uncropped, but white space at the
                                   sides. Regression.
     4. Full width + height cap -> no gaps, no scroll, but up to 34% cropped.

   These images are hand-cropped and are the MINIMUM safe crop, so taking 34%
   off them cuts into the subject. The rule now bounds the CROP first and lets
   a little scrolling reappear on short windows instead:

     - the band is always full width (no side gaps -- that part stays);
     - its height is 16:9 of that width, so on a tall window nothing is cropped;
     - the height may be clamped to fit the window, BUT never below the height
       at which the crop would exceed ~10%.

   The 10% floor works out as a box no wider than 16:9 / 0.90 = 1.976 : 1, i.e.
   a height of at least 100vw / 1.976 = 50.6vw. Where that is taller than the
   window, the visitor scrolls a little to see the last slice rather than
   losing it. 100vw slightly overstates the band's real width (it counts the
   scrollbar), which errs toward less cropping -- the right direction. */
.hero-slides--page {
  width: 100%;
  max-width: none;
  margin-inline: 0;
  aspect-ratio: 16 / 9;
  --band-floor: 50.6vw;                                   /* crop never > ~10% */
  --band-fit: calc(100vh - var(--header-h) - 22px);       /* fits the window   */
  max-height: max(var(--band-floor), var(--band-fit));
}
@supports (height: 1svh) {
  .hero-slides--page { --band-fit: calc(100svh - var(--header-h) - 22px); }
}
.hero-slides--page .hero-slides__slide img { object-fit: cover; object-position: 50% 50%; }

@media (max-width: 760px) {
  /* On a portrait phone the 16:9 box is far shorter than the window, so
     neither bound is reached -- it stays full-bleed and uncropped. */
  .hero-slides--page { --band-fit: calc(100svh - var(--header-h) - 12px); }
}
}
}
}

/* The per-image anchoring rules that used to live here are retired. They
   existed to steer where the frame cut each photograph; the photographs are
   pre-cropped to the frame's exact ratio now, so there is nothing to steer --
   every image fills the frame completely. */
.about-slides .hero-slides__slide img,
.projects-slides .hero-slides__slide img { object-position: 50% 50%; }

/* ---- Item 4: service-card carousels ------------------------------------
   The product carousel letterboxes its images (object-fit: contain) because a
   product shot needs its whole outline visible. A service card is a
   photograph and should fill its frame, so this variant covers instead. */
.pcar--photo .pcar__img { object-fit: cover; }

/* The real flag, overlaid on the left of the select. Kept out of the flow so
   the select stays a single native control -- keyboard, screen reader and the
   mobile OS picker all keep working. */
.telgrp__flag {
  position: absolute;
  inset-inline-start: 7px;
  top: 50%;
  translate: 0 -50%;
  width: 16px;
  height: 12px;
  pointer-events: none;
  border-radius: 2px;
  overflow: hidden;
  box-shadow: 0 0 0 1px rgba(14, 58, 95, 0.18);
  line-height: 0;
  z-index: 1;
}
.telgrp__flag img { display: block; width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 480px) {
  /* stacked at this width, so the percentages no longer apply */
  .telgrp__cc, .telgrp__num { flex: 1 1 auto; width: 100%; }
}

/* Padding for the flag chip. Written as `.frm .telgrp__cc` (0,2,1) because the
   generic `.frm select` rule (0,1,1) sets `padding: 12px 14px` and was
   overriding a bare `.telgrp__cc`, leaving the code sitting under the flag. */
.frm .telgrp__cc {
  /* The native dropdown arrow reserves ~18px of the 81px control, which was
     clipping "+966" to "+96". appearance:none drops it and a small chevron is
     drawn instead, which costs 12px and leaves the code room to render whole. */
  -webkit-appearance: none;
  appearance: none;
  padding-inline-start: 28px;
  padding-inline-end: 14px;
  font-size: 0.88rem;
  letter-spacing: -0.01em;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%232C5577'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 5px center;
}
[dir="rtl"] .frm .telgrp__cc { background-position: left 5px center; }

/* ---- Country combobox: flag images in BOTH states ----------------------
   A native <select> cannot put an image in an option, which is why this is a
   button + listbox. Everything the native control did for free is
   reimplemented in JS -- see main.js -- including type-ahead. */
.telcc { position: relative; flex: 0 0 30%; width: 30%; min-width: 0; }
.telcc__btn {
  /* The caret was being pushed 4px past the button's right border: the flow
     content (flag + code + caret + padding) needed 84px inside an 81px box.
     The caret is taken out of flow and pinned to the button's own inline-end,
     so it can never be displaced into the number field again, and the space it
     used to occupy is reserved as padding instead. */
  position: relative;
  display: flex; align-items: center; gap: 4px;
  width: 100%; height: 100%;
  padding-block: 12px;
  padding-inline: 7px 13px;
  overflow: hidden;
  font: inherit; font-size: 0.85rem;
  color: var(--color-ink, #0E3A5F);
  background: #fff;
  border: 1px solid #cfd8e6; border-radius: 8px;
  cursor: pointer; text-align: start;
}
.telcc__btn:hover { border-color: #a9bcd4; }
.telcc__btn:focus-visible { outline: 2px solid var(--color-light-blue, #4A90D9); outline-offset: 1px; }
.telcc__flag { flex: 0 0 auto; width: 18px; height: 13px; border-radius: 2px; box-shadow: 0 0 0 1px rgba(14,58,95,0.18); display: block; }
.telcc__code { font-variant-numeric: tabular-nums; white-space: nowrap; min-width: 0; }
.telcc__caret {
  position: absolute;
  inset-inline-end: 4px;
  top: 50%;
  margin-top: -2px;
  width: 0; height: 0;
  border-inline: 4px solid transparent;
  border-top: 5px solid var(--color-body, #2C5577);
}
.telcc[data-open] .telcc__caret { transform: rotate(180deg); }

.telcc__list {
  position: absolute;
  z-index: 60;
  inset-inline-start: 0;
  top: calc(100% + 4px);
  min-width: 260px;
  max-height: 280px;
  overflow-y: auto;
  margin: 0; padding: 4px;
  list-style: none;
  background: #fff;
  border: 1px solid #cfd8e6;
  border-radius: 10px;
  box-shadow: 0 18px 40px -18px rgba(14, 58, 95, 0.45);
}
.telcc__list li {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--color-ink, #0E3A5F);
}
.telcc__list li img { flex: 0 0 auto; border-radius: 2px; box-shadow: 0 0 0 1px rgba(14,58,95,0.18); display: block; }
.telcc__name { flex: 1 1 auto; }
.telcc__dial { color: var(--color-muted, #476E90); font-variant-numeric: tabular-nums; }
.telcc__list li[aria-selected="true"] { background: rgba(74,144,217,0.14); font-weight: 600; }
.telcc__list li.is-active { background: var(--color-dark-blue, #0E3A5F); color: #fff; }
.telcc__list li.is-active .telcc__dial { color: rgba(255,255,255,0.85); }

@media (max-width: 480px) {
  .telcc { flex: 1 1 auto; width: 100%; }
  .telcc__list { min-width: 0; width: 100%; }
}

/* ---- HEADER: flat colour, no tile grid --------------------------------
   Client asked for the header pattern gone and a single flat colour in its
   place -- specifically the colour the header already uses, not a new one.

   Sampled off the rendered header rather than picked from the palette: the
   band is 84% #A1C5EB (the tiles) and 6.9% #FFFFFF (the grout showing the
   header's own white background through the gaps). So #A1C5EB is the colour
   the header READS as, and it is what goes on the bar. Taking the literal
   layer underneath the tiles would mean white, which would turn the header
   white -- the opposite of keeping the colour it has.
   --color-tile-blue is the same token the tiles were drawing with, so the
   flat bar and the old tiles are the identical value by construction.

   HEADER ONLY. .esnad-floor--header is the header's own floor element; the
   footer floor (.esnad-floor--footer) and the page watermark are untouched.

   This lives in logo.css, after style.css, because `.site-header` is (0,1,0)
   in both files -- an override written in style.css would lose on source
   order, and the mobile `.site-header { background:#fff }` at style.css:547
   would beat it at phone widths. Only `background` is set here, so that
   rule's deliberate `backdrop-filter: none` on mobile still applies. */
.esnad-floor--header { display: none; }
.site-header { background: var(--color-tile-blue, #A1C5EB); }

/* ---- Footer D-U-N-S block: centre the caption under the QR ---------------
   The label sat right-aligned and the number inherited a different alignment,
   so the two lines disagreed with each other and with the code above them.
   .footer__duns is now a column whose items centre on the QR's own width --
   the text centres on the CODE, not on the footer column, because the
   wrapper shrinks to the QR rather than filling the grid cell.
   text-align covers the inline text; align-items covers the boxes. */
.footer__duns {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: max-content;
  gap: 8px;
}
.footer__duns .duns-qr { display: block; margin: 0; }
.footer__duns-txt {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin: 0;
  width: 100%;
}
.footer__duns-txt .duns__label,
.footer__duns-txt .duns__num {
  display: block;
  text-align: center;
  width: 100%;
}
[dir="rtl"] .footer__duns-txt,
[dir="rtl"] .footer__duns-txt .duns__label,
[dir="rtl"] .footer__duns-txt .duns__num { text-align: center; }

/* ---- Footer D-U-N-S on mobile: flush left with the rest of the footer ----
   The centring above is a DESKTOP treatment -- there the QR is its own column,
   so centring the caption under the code reads as deliberate. Below 1024px the
   footer collapses to one left-aligned column and every other block starts at
   the container's edge, so a centred QR sat 29px inboard of the address, the
   email and the phone number and looked accidental.
   Note this rule has to live here rather than in style.css: style.css already
   had `.footer__duns { align-items: flex-start }` at this same breakpoint, and
   the centring block above -- being later in the cascade and unconditional --
   was overriding it. That is what pushed the QR off the left edge.
   text-align: start, not left, so the Arabic footer mirrors to the right along
   with everything else in it. */
@media (max-width: 1024px) {
  .footer__duns { align-items: flex-start; width: auto; }
  /* .footer__duns-txt is itself a flex column that was centring its two spans.
     text-align alone does not move a flex item -- the spans shrink to their own
     content, so the shorter number floated inboard of the longer label (24px vs
     37px). align-items has to come off too. */
  .footer__duns-txt { align-items: flex-start; }
  .footer__duns-txt,
  .footer__duns-txt .duns__label,
  .footer__duns-txt .duns__num,
  [dir="rtl"] .footer__duns-txt,
  [dir="rtl"] .footer__duns-txt .duns__label,
  [dir="rtl"] .footer__duns-txt .duns__num {
    text-align: start;
    width: auto;
  }
}

/* ---- Item 1: header wordmark is the ARTWORK, not re-typeset text ---------
   The loader (.pt__wm) draws esnad-wm.png. The header used to set ESNAD and
   WE PROTECT as live text and approximate the artwork with letter-spacing plus
   a size ratio, which is why the two never matched. The English header now
   draws the same file, so the spacing between the two words and the tracking
   within each are identical by construction.
   Layout is deliberately unchanged -- .brand is still a horizontal flex row
   with the emblem on the left; only the text rendering moved to the artwork.
   Width is set to sit in the footprint the live text occupied (65px measured),
   nudged to 70px because the artwork's tighter leading makes the same width
   read smaller. The image is 1076x359, so height follows at ~1/3 the width. */
.brand__wm {
  display: block;
  --wm-w: 70px;
  width: var(--wm-w);
  height: auto;
  flex-shrink: 0;
  /* ESNAD SITS ON THE EMBLEM'S CENTRE LINE, not the wordmark's.
     The artwork is 1076x359: ESNAD occupies rows 0-242 (centre 121) and
     WE PROTECT rows 289-358. Centring the whole image puts its midpoint (179.5)
     on the emblem's centre, which leaves ESNAD 58.5 image-px HIGH of it.
     Nudging the image down by that 58.5 -- 0.054368 of the image WIDTH, since
     width is the dimension we set -- lands ESNAD's own centre on the emblem's.
     position/top rather than margin: with align-items:center a margin would be
     halved by the centring, and it would also change the flex line's height. */
  position: relative;
  top: calc(var(--wm-w) * 0.054368);
}
@media (max-width: 520px) {
  .brand__wm { --wm-w: 62px; }
}

/* ---- Item 2: WE PROTECT was hidden outright below 520px -----------------
   style.css had `.brand__name small { display: none }` in its 520px query, so
   the strip did not render at all on a phone. It is restored here (this file
   loads after style.css, so this wins) and scaled instead of hidden.
   Only Arabic and Urdu still use live text for the header name; English now
   draws the artwork above and is unaffected by these rules. */
@media (max-width: 520px) {
  .brand__name small {
    display: block;
    font-size: 0.40rem;
    letter-spacing: 0.20em;
  }
}

/* ---- Item 3: About Us image shows whole, not cropped --------------------
   .split__media was `align-self: stretch` with `object-fit: cover`, so the box
   took its height from the text column beside it and the photo was cropped to
   whatever that height happened to be.

   The fix has to avoid the trap documented in style.css: an aspect-ratio on a
   STRETCHED item computes the WIDTH from the row height, which once made the
   figure 677px wide inside a 522px column and hung it off the side of the
   screen -- the "stretched to one side" the client called out before. The
   escape is the same one the stacked layout already uses: align-self: start,
   so width stays governed by the grid column and the ratio derives the HEIGHT
   from it.
   3 / 2 is the source's own ratio (about-preview.jpg is 1200x800), so the
   frame matches the picture exactly and nothing is cut. object-fit: contain is
   belt and braces -- if a future image has a different ratio it will letterbox
   rather than silently crop again. min-height is released for the same reason:
   a 300px floor would override the ratio on a narrow column. */
.split__media {
  align-self: start;
  aspect-ratio: 3 / 2;
  min-height: 0;
}
.split__media img {
  object-fit: contain;
  object-position: center;
}

/* ---- Item 9: centre the About button on mobile --------------------------
   Every other button that stands alone on a phone is centred (the .more-row
   ones by text-align). This one sits directly in .split__text, which is
   left-aligned prose, so it inherited the left edge.
   margin-inline: auto only works on a block-level box, and .btn is inline-flex
   -- hence display: flex plus width: max-content, which keeps the button its
   own width while letting the auto margins centre it.
   Scoped to the mobile query, so the desktop left alignment is untouched. */
@media (max-width: 860px) {
  .split__text > .btn {
    display: flex;
    width: max-content;
    margin-inline: auto;
  }
}

/* ======================================================================
   STANDING RULE - card background is always the opposite of its section
   ----------------------------------------------------------------------
   White section  -> cards are the light blue band tint
   Light blue section -> cards are white
   Keyed off the section class so it applies to any card added later, and
   uses --color-section-tint so cards and bands are the identical approved
   blue rather than two values that drift apart.
   Placed at the end of logo.css, after every component's own background, so
   it wins without needing !important.
   ====================================================================== */
.section:not(.section--soft) .card,
.section:not(.section--soft) .vg-item,
.section:not(.section--soft) .logo-tile {
  background: var(--color-section-tint, rgba(161, 197, 235, 0.298));
}
.section--soft .card,
.section--soft .vg-item,
.section--soft .logo-tile {
  background: #fff;
}
/* The navy plate behind certain partner logos is a contrast device on the
   IMAGE, not the tile, so it survives both rules -- restated here so a future
   edit to the block above cannot quietly take it out. */
.logo-tile--plate img { background: var(--color-dark-blue, #0E3A5F); }

/* ---- Item 4b: no blue top rule on the About cards -----------------------
   .vg-item carried `border-top: 3px solid` in the accent blue, which no other
   card on the site has. Replaced with the same 1px line as the other three
   edges so Values and Goals match the standard card. */
.vg-item {
  border-top: 1px solid var(--color-line, #e3e8ef);
}

/* ---- Item 1: the blue (Our Goals) cards go flat -------------------------
   .vg-item carries a 3D treatment: an extruded slab behind the face
   (::after, translateZ(-16px)) plus the icon and heading floating forward.
   On the WHITE Values cards that reads as depth. On the BLUE Goals cards the
   slab is a blue-on-blue gradient sitting right behind blue, which muddies the
   card and fights the text.
   Targeted by section, not by a new class: the blue cards are exactly the ones
   on a non-soft section, which is the same selector the card-colour rule uses.
   Values, on .section--soft, keep their 3D untouched. */
.section:not(.section--soft) .vg-item {
  transform-style: flat;
  box-shadow: 0 1px 2px rgba(14, 58, 95, 0.06);
}
.section:not(.section--soft) .vg-item::after { content: none; }
.section:not(.section--soft) .vg-item .vg-icon,
.section:not(.section--soft) .vg-item h3 { transform: none; }
.section:not(.section--soft) .vg-item:hover,
.section:not(.section--soft) .vg-item:focus-within { transform: none; }

/* ---- Item 4: icon chip on the Careers cards -----------------------------
   Same chip the About sections use, so the two read as one family. .card has
   no icon slot of its own, hence a small block rather than reusing .vg-icon's
   layout wholesale. */
.card__icon {
  width: 38px; height: 38px;
  border-radius: 10px;
  display: grid; place-items: center;
  margin-bottom: 14px;
  color: var(--color-light-blue-600, #3a7bc0);
  background: rgba(74, 144, 217, 0.12);
}
.card__icon svg { display: block; }

/* ---- Item 5: cards in a grid are all the same height --------------------
   Two things were making them ragged:
     * .services-grid set `align-items: start`, so each card shrank to its own
       text (measured 650 / 650 / 701 / 676 / 701 / 498 on the services page --
       a 203px spread in one grid);
     * even stretched, each ROW sizes to its own tallest card, so a short
       bottom row still differed from a tall top row.
   align-items: stretch fixes the first, grid-auto-rows: 1fr the second, so
   every card in the grid matches regardless of how much text it holds.
   Width was already equal -- the columns are repeat(N, 1fr). */
.grid--2, .grid--3, .grid--4, .services-grid {
  align-items: stretch;
  grid-auto-rows: 1fr;
}
.grid--2 > .card, .grid--3 > .card, .grid--4 > .card,
.grid--2 > .vg-item, .grid--3 > .vg-item, .grid--4 > .vg-item,
.vg-grid > .vg-item {
  height: 100%;
}
.vg-grid { align-items: stretch; grid-auto-rows: 1fr; }

/* radius matched to the homepage card (10px) as well, so the two are the same
   object in every respect. */
.vg-item { border-radius: var(--radius, 10px); }

/* ---- Values and Goals become ordinary cards -----------------------------
   Both now match the homepage .card exactly: flat, 1px border, no extruded
   slab, no drop shadow. The 3D treatment (an ::after slab sitting 16px behind
   the face, plus the icon and heading pushed forward in Z) is switched off for
   BOTH sections now, not just the blue one -- the client asked for the plain
   card style used elsewhere on the site.
   These override the earlier Goals-only rule above, which is left in place
   because it is narrower and harmless. */
.vg-item {
  transform-style: flat;
  box-shadow: none;
}
.vg-item::after { content: none; }
.vg-item .vg-icon,
.vg-item h3 { transform: none; }
.vg-item:hover,
.vg-item:focus-within { transform: none; box-shadow: none; }
.section:not(.section--soft) .vg-item,
.section--soft .vg-item { box-shadow: none; }

/* (the header rule that lived here is superseded by the slide-away
   behaviour further down this file) */

/* ---- Item 2: nav slides away going down, returns on any upward scroll ----
   Back to sticky, so the bar can travel with the viewport, plus a transform
   that lifts it out of sight. The earlier `position: static` experiment is
   replaced here rather than left to fight this.
   z-index is restated because a sticky element needs it to stay above the
   hero's positioned content -- that was the bug when the header went static. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  transition: transform .26s cubic-bezier(.2, .7, .3, 1);
  will-change: transform;
}
.site-header.is-tucked { transform: translateY(-100%); }
@media (prefers-reduced-motion: reduce) {
  .site-header { transition: none; }
}

/* ---- Item 3: the About image sits inside its frame, never against it ------
   The frame already matches the source's 3:2 and uses object-fit: contain, so
   nothing is being cut by the CSS -- but the SOURCE FILE is itself cropped
   (the turbine blades run off its right edge, the monitor off its bottom), so
   the picture reads as clipped wherever it meets the frame edge.
   Padding the frame pulls the whole picture inward, so it is surrounded by the
   panel's own light ground rather than butting against the border. It cannot
   restore pixels the file does not contain -- that still needs the original
   artwork -- but nothing touches an edge any more. */
/* The client supplied the uncropped artwork (1536x1024, the same 3:2 the frame
   uses, and measuring clear on the top, left and right edges where the old file
   had content against 11.9% of its right edge).

   The inset is KEPT even though the crop is fixed. It began as a workaround --
   pushing a clipped picture away from the frame edge -- but the client preferred
   how it looked, so it stays as a deliberate choice: the illustration sits in
   its frame rather than butting against it. The background stays matched to the
   illustration's own ground (#F4F5F9, sampled off the file) so the inset reads
   as part of the picture rather than as a white border around it. */
.split__media {
  padding: clamp(10px, 1.6vw, 20px);
  background: #F4F5F9;
}
.split__media img { border-radius: 0; }

/* ---- Item 6: Mission and Vision take the blue card treatment -------------
   .mv-panel is a card in every sense but was not in the card-colour rule, so
   it stayed white on a white section. Added here, following the same rule:
   white section -> blue card.

   The connector between the halves is a dotted rule in --color-light-blue at
   50% opacity. That is close enough to the new card tint to disappear, so it
   is recoloured -- to the brand NAVY, not white. The client suggested white,
   which is right for a dark card, but this card tint is LIGHT (#E3EEF9): white
   on it measures about 1.1:1 and would vanish just as thoroughly. Navy reads
   strongly on the tint and matches the headings already on the card. */
.section:not(.section--soft) .mv-panel {
  background: var(--color-section-tint, rgba(161, 197, 235, 0.298));
}
.section--soft .mv-panel { background: #fff; }

.section:not(.section--soft) .mv-panel .mv-panel__link {
  opacity: 1;
  background-image: radial-gradient(circle,
      var(--color-dark-blue, #0E3A5F) 1.2px, transparent 1.6px);
}
.section:not(.section--soft) .mv-panel .mv-panel__link::before,
.section:not(.section--soft) .mv-panel .mv-panel__link::after {
  background: var(--color-dark-blue, #0E3A5F);
}

/* ---- Item 8b: required marker -------------------------------------------
   An <abbr> rather than a bare asterisk, so assistive tech announces
   "required" instead of reading out a star. aria-hidden on the glyph itself
   keeps it from being read twice, since the input already carries `required`. */
.frm .req {
  color: #B3261E;
  margin-inline-start: 4px;
  font-weight: 700;
  text-decoration: none;
  border: 0;
}
.frm label > .lbl { display: block; }

/* ---- Item 8c: an error must not move the field it belongs to -------------
   The error span is appended INSIDE the <label>, so showing one grew that
   label and pushed its input down -- while the field beside it in the same row
   stayed put, breaking the alignment the client reported.
   Every field now reserves the error's height whether or not it has one, and
   the message is absolutely positioned into that reserved strip. The row
   therefore has identical geometry in both states, so nothing can shift.
   align-items: start on the row stops a tall field stretching its neighbour. */
.frm__row { align-items: start; }
.frm label {
  position: relative;
  padding-bottom: 22px;
}
.frm__err {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* the phone message is the long one; let it use the full row width */
.frm label:has(.telgrp) .frm__err { white-space: normal; }

/* the file input on the careers form sits in the same system */
.frm label.frm__file { padding-bottom: 22px; }

/* ---- Item 1: Arabic/Urdu header keeps the English arrangement ------------
   dir="rtl" makes every flex row lay its children out right-to-left, so the
   header put the logo on the right and the language switcher on the left --
   a mirror image of the English header rather than the same header with
   translated links.

   The client wants the logo left and the switcher right in BOTH languages,
   with only the NAV LINKS reading right-to-left. So the header row is pinned
   back to ltr, and direction is handed to the nav on its own: the links then
   read right-to-left among themselves (الرئيسية first, on the right of the
   group) while the row around them keeps its English arrangement.

   Scoped to the header. The rest of the RTL pages are untouched. */
[dir="rtl"] .site-header__inner { direction: ltr; }
[dir="rtl"] .site-header__inner .main-nav { direction: rtl; }
/* The switcher deliberately does NOT get direction back: it should read
   flag-then-label in both languages, the same way the English one does. */

/* The burger panel is a column, so it needs the same treatment: the panel
   itself follows the page, but it hangs off a row that is now ltr. */
@media (max-width: 900px) {
  [dir="rtl"] .site-header__inner .main-nav.is-open { direction: rtl; text-align: right; }
}

/* ---- First-arrival cover -------------------------------------------------
   The branded cover now also plays on a cold arrival (see the inline <head>
   script). The component itself is unchanged.

   There is deliberately NO CSS failsafe here. The first attempt animated the
   cover's opacity to 0 after six seconds, which left visibility:visible and
   pointer-events intact: the panel went invisible but still swallowed every
   click, so the site looked fine and was entirely dead. The guard lives in the
   inline <head> script instead, in the same block that raises the cover -- if
   that block cannot run, no cover is raised and nothing needs clearing. */

/* ==== Round: Arabic parity items ========================================= */

/* ---- Item 1: footer links need a hover you can actually see --------------
   The effect existed -- rgba(255,255,255,.75) to #fff -- but a 25% opacity
   step on small white text is close to invisible, which is why it was read as
   "no effect at all" on the Arabic pages. It was equally invisible in English.
   Colour alone is not enough at this size, so the hover also underlines.
   NB the underline has to be stated here: the rule a few hundred lines up in
   this same file sets `text-decoration: none` on .site-footer a:hover, and
   this later rule is what overrides it. */
.site-footer a {
  transition: color .18s ease, text-decoration-color .18s ease;
}
.site-footer a:hover,
.site-footer a:focus-visible {
  color: #fff;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* ---- Item 2: the current page, unmistakably ------------------------------
   Bold is kept -- it is what English already had -- and an underline accent is
   added beneath the active item. Weight is a weak signal in Arabic script, so
   the accent is what makes the state legible there; applying it to both
   languages keeps them identical, which is what was asked for.
   Nav links carry no other pseudo-element, so ::after is free to use. */
.main-nav a.is-active { position: relative; }
.main-nav a.is-active::after {
  content: "";
  position: absolute;
  left: 12%;
  right: 12%;
  bottom: -5px;
  height: 2px;
  border-radius: 2px;
  background: var(--color-dark-blue, #0E3A5F);
}
/* Hovering an item already gives it a solid navy pill; the accent underneath
   it would then read as a stray mark, so it steps aside. */
.main-nav a.is-active:hover::after,
.main-nav a.is-active:focus-visible::after { opacity: 0; }

/* ---- Item 3: the Partners page title band -------------------------------
   The client marked this band as too tall and wanting the light blue. It is
   the header's own blue, so the band reads as a continuation of the header
   rather than a second, competing colour. .page-head is used by no other page,
   so nothing else moves.
   The hairline rule underneath is dropped: it existed to separate a white band
   from a white section, and a coloured band separates itself. */
.page-head {
  /* The same tint the alternating page sections use, NOT the header's solid
     #A1C5EB -- the band should read as one of the site's blue sections, not as
     a second header. --color-section-tint is that single token. */
  background: var(--color-section-tint, rgba(161, 197, 235, 0.298));
  padding-block: clamp(26px, 3.2vw, 42px);
}
.page-head::after { display: none; }
/* The band and the section below it are both page content now, so the generous
   title-to-content gap reads as a hole. Closed up to roughly half. */
.page-head + .section { padding-top: clamp(28px, 3.4vw, 48px); }

/* ---- Item 4: both flags, one box ----------------------------------------
   Saudi is 3:2 and the US flag is 1.9:1, so equal heights gave unequal widths
   -- 23x15 against 29x15. They now share a single box and are cropped to fill
   it, which is how icon sets normally reconcile flags of different ratios.
   Both files are SVG, so the artwork itself is vector and stays sharp; the
   box is a little larger than before and carries a hairline edge and a 2px
   radius so it reads as a deliberate icon rather than a floating shape. */
.lang-flags img,
.lang-flags .flag {
  width: 26px;
  height: 17px;
  object-fit: cover;
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(14, 58, 95, 0.18);
  display: block;
  flex: none;
}

/* ==== Mobile round ======================================================= */

/* ---- The About frame: even inset on every side --------------------------
   The frame carried aspect-ratio 3/2 and the picture was fitted inside its
   PADDED box with object-fit: contain. Padding shrinks the content box but not
   its ratio, so at 390px the content box came out 322x208 -- 1.548 against the
   picture's 1.500. contain then fits by height, so the picture filled the box
   top to bottom and was letterboxed at the sides: 10px of frame above and
   below the artwork, 15px either side. On a phone that reads as no padding at
   all at the bottom edge, which is what was reported.

   Fixed by letting the PICTURE set the height instead of the frame: the ratio
   moves onto the image, the frame height becomes image + padding, and the
   inset is then genuinely equal on all four sides. The source is 3:2, so
   nothing is letterboxed or cropped either way. */
.split__media {
  aspect-ratio: auto;
  padding: clamp(12px, 3.4vw, 20px);
}
.split__media img {
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: contain;
  display: block;
}

/* ---- The active-page underline is desktop only --------------------------
   In the burger panel each link is full width, so the accent stretched to
   ~278px and read as a divider rule between menu items rather than a marker on
   the current one. The panel does not need it: the items are stacked and the
   bold weight alone is unambiguous there. Desktop keeps it, where the links
   sit in a row and weight alone is weak. */
/* 1024px, not 900: that is where style.css collapses the nav into the burger
   (.nav-toggle { display: flex }). Hiding the accent at 900 would have left
   901-1024px showing it inside the stacked panel -- the same fault, just at
   tablet widths. */
@media (max-width: 1024px) {
  .main-nav a.is-active::after { display: none; }
}

/* ---- Stop the footer floor extending the scrollable page ----------------
   The decorative floor plane is drawn with perspective(720px) rotateX(54deg).
   Its LAYOUT height is capped at 1700px, but a 3D projection makes its visual
   bounding box roughly 11,400px -- about 10,000px of it below the footer.
   .esnad-floor already sets overflow: hidden, which Chrome honours (the
   document ends exactly at the footer there). Safari on iOS is far more
   willing to count transformed overflow towards the scrollable area, which is
   the reported "keeps scrolling into white past the footer".

   contain: paint states the clip as containment rather than as overflow, which
   is the form Safari applies reliably to transformed descendants. It changes
   nothing visually -- the parent was already clipping. */
.esnad-floor { contain: paint; }

/* ==== Arabic active-page indicator + footer hover ======================== */

/* ---- Item 1: the active page, marked in a way Arabic can show ------------
   MEASURED: rendering the same Arabic string at font-weight 500 and 700 in
   this font stack ("Segoe UI", Tahoma, system-ui) produces byte-identical
   output -- 89.72px wide either way. The declaration is real, the pixels are
   not. So on Arabic the bold marker has never been visible, and once the
   long underline was removed from the burger panel there was no marker there
   at all. The client's report is exactly right.

   Colour cannot carry it either: every nav link is #0E3A5F on a #A1C5EB
   header, which is 6.54:1. Lightening the inactive links to make the active
   one stand out drops them to 3.6-4.3:1, under AA. Legibility is not worth
   trading for an indicator.

   So the marker is structural, and differs by layout:
     desktop  -- the links sit in a row, so an underline beneath the active one
                 reads correctly (already in place, unchanged);
     burger   -- the links are stacked full-width, where an underline read as a
                 divider. A short bar at the inline-start is the conventional
                 selected-row marker and cannot be mistaken for a rule.
   Both are drawn shapes, so they are identical in Arabic and English. */
@media (max-width: 1024px) {
  .main-nav a.is-active {
    position: relative;
    background: rgba(14, 58, 95, 0.06);
    border-radius: 6px;
  }
  /* inset-inline-start, not left: this puts the bar on the correct side in
     both directions without a separate RTL rule */
  .main-nav a.is-active::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 1.15em;
    border-radius: 2px;
    background: var(--color-dark-blue, #0E3A5F);
  }
  /* the pill already carries the state while hovered */
  .main-nav a.is-active:hover::before,
  .main-nav a.is-active:focus-visible::before { opacity: 0; }
}

/* ---- Item 2: footer links grow slightly on hover ------------------------
   scale, not font-size: changing the size would reflow the column and nudge
   every link below it. A transform is painted, so nothing around it moves.
   1.06 is the figure the nav hover already uses, so the two feel like the same
   site rather than two different effects.
   The origin is pinned to the inline start so the text grows away from its own
   left edge in English and its right edge in Arabic, instead of drifting
   sideways from the centre. */
.site-footer a {
  display: inline-block;
  transform-origin: left center;
  transition: color .18s ease, transform .18s cubic-bezier(.2, .7, .3, 1);
}
[dir="rtl"] .site-footer a { transform-origin: right center; }
.site-footer a:hover,
.site-footer a:focus-visible { transform: scale(1.06); }

@media (prefers-reduced-motion: reduce) {
  .site-footer a { transition: color .18s ease; }
  .site-footer a:hover,
  .site-footer a:focus-visible { transform: none; }
}

/* ---- Arabic: make the current page genuinely THICKER --------------------
   Correcting an earlier conclusion of my own. Comparing ADVANCE WIDTHS at
   different weights showed no change, so I reported that the Arabic face was
   flat. Width was the wrong measure: this font keeps the same advance and
   varies stroke instead. Measuring ink coverage tells the real story --

       weight   ink vs 400
       300      0.51x
       400      1.00x
       500      1.30x   <- what the inactive links were using
       600      1.30x
       700      1.45x   <- what the active link was using
       800      1.94x
       900      1.94x

   500 and 700 are only 1.11x apart, which is why every item looked the same
   weight. 500 already sits on a semibold face, so the "bold" active item was
   barely heavier than its neighbours.

   800 against 500 is 1.49x -- a clear step. Only the active item changes, so
   the rest of the bar keeps the weight it has today rather than being thinned
   to manufacture contrast. 900 is the same face as 800, so there is nothing
   above this to reach for.

   RTL only: the Latin stack has real 500 and 700 faces and already reads
   correctly, so English is left alone. */
[dir="rtl"] .main-nav a.is-active { font-weight: 800; }

/* ==== Nav states + button hover ========================================== */

/* The three colours this round uses, named once so the intent is readable:
     navy    #0E3A5F  --color-dark-blue     : the current page
     light   #E3EEF9                        : hover. This is the alternating
              section blue -- --color-section-tint is rgba(161,197,235,.298),
              which is that value flattened over white. It has to be SOLID
              here: as a translucent tint it would blend with whatever sits
              behind it, so the same rule would paint a pale pill in the header
              and a dark one on the navy footer.
     accent  #3a7bc0  --color-light-blue-600: button hover. This is the exact
              value behind the "Our Clients" / "Our Partners" headings
              (.heading--label in style.css), not an approximation. */

/* ---- PART A: header nav -------------------------------------------------
   The current page now wears the navy pill permanently, so the underline it
   used to carry is gone -- and so is the bar that marked it in the burger
   panel, which the pill replaces there too. */
.main-nav a.is-active::after,
.main-nav a.is-active::before { display: none; }

.main-nav a.is-active,
.main-nav a.is-active:hover,
.main-nav a.is-active:focus-visible {
  background: var(--color-dark-blue, #0E3A5F);
  color: #fff;
}

/* Hover applies to the OTHER items only; the current page keeps its navy. */
.main-nav a:not(.is-active):hover,
.main-nav a:not(.is-active):focus-visible {
  background: #E3EEF9;
  /* NOT white: white on #E3EEF9 is 1.18:1, which is invisible. Navy on it is
     9.98:1. The background is exactly the colour asked for; only the text
     colour had to change for the label to still be readable. */
  color: var(--color-dark-blue, #0E3A5F);
}

/* ---- PART B: the footer's page-name links -------------------------------
   Scoped to .footer__links, which is the two page-name lists (Company and
   Services). .footer__contact -- the address, email, phone and LinkedIn --
   is deliberately untouched.

   The footer sits on --color-dark-blue-800 (#0a2c49), so the header's navy
   pill measures 1.00:1 against it: literally the same colour, an invisible
   marker. The current page therefore takes a WHITE pill here, which is the
   strongest thing available on a dark ground, and hover keeps the light blue
   exactly as specified. Active stays brighter than hover, so the hierarchy
   reads the same way it does in the header. */
.footer__links a {
  display: inline-block;
  padding: 4px 10px;
  margin: -4px -10px;
  border-radius: var(--radius-sm, 8px);
  transition: background-color .18s ease, color .18s ease, transform .18s ease;
}
.footer__links a.is-active,
.footer__links a.is-active:hover,
.footer__links a.is-active:focus-visible {
  background: #fff;
  color: var(--color-dark-blue, #0E3A5F);
  text-decoration: none;
}
.footer__links a:not(.is-active):hover,
.footer__links a:not(.is-active):focus-visible {
  background: #E3EEF9;
  color: var(--color-dark-blue, #0E3A5F);
  text-decoration: none;
}

/* ---- PART C: every button hovers to the heading accent ------------------
   One colour for all of them, on white sections and on blue ones alike, as
   asked. #3a7bc0 is distinct from both grounds so it stays legible either
   way. Stated for each variant because .btn--primary, .btn--dark and
   .btn--ghost each set their own hover in style.css. */
.btn:hover,
.btn:focus-visible,
.btn--primary:hover,
.btn--primary:focus-visible,
.btn--dark:hover,
.btn--dark:focus-visible,
.btn--ghost:hover,
.btn--ghost:focus-visible {
  background: var(--color-light-blue-600, #3a7bc0);
  color: #fff;
  border-color: transparent;
}

/* ==== Button hover: colour AND size; slideshow crop direction ============ */

/* ---- Buttons ------------------------------------------------------------
   Two things were working against the accent-colour hover added last round:

     .btn:hover { box-shadow: 0 6px 18px rgba(14,58,95,.28);
                  filter: brightness(0.94); }

   earlier in this file. The box-shadow is the "unrelated shadow" being
   reported, and brightness(0.94) darkens whatever colour the button ends up
   with -- so even once the background became #3a7bc0 it was being rendered
   6% darker than the heading it is supposed to match.

   Both are neutralised here, and the size increase is added. The transform is
   written out in full because .btn--primary and .btn--dark already set
   translateY(-2px); a bare scale() would replace that and lose the lift. */
.btn { transition: background-color .18s ease, color .18s ease,
                   transform .18s cubic-bezier(.2, .7, .3, 1), box-shadow .18s ease; }

.btn:hover,
.btn:focus-visible,
.btn--primary:hover,
.btn--primary:focus-visible,
.btn--dark:hover,
.btn--dark:focus-visible,
.btn--ghost:hover,
.btn--ghost:focus-visible {
  background: var(--color-light-blue-600, #3a7bc0);
  color: #fff;
  border-color: transparent;
  filter: none;                       /* let the accent render at full value */
  box-shadow: 0 4px 14px rgba(14, 58, 95, 0.18);
  transform: translateY(-2px) scale(1.04);
}

@media (prefers-reduced-motion: reduce) {
  .btn:hover, .btn:focus-visible,
  .btn--primary:hover, .btn--dark:hover, .btn--ghost:hover { transform: none; }
}

/* ---- About slideshow: never crop the bottom -----------------------------
   The band is aspect-ratio 2/1 and the photographs are 16:9, so object-fit:
   cover has to lose 11% of their height. It was taking that off both ends
   (object-position 50% 50%), which cut into the bottom of every frame.

   Anchoring to the bottom keeps the full bottom edge visible and takes the
   whole 11% off the top instead, which is the instruction for the case where
   cropping cannot be avoided.

   It cannot be avoided at this band ratio: fitting the whole 16:9 frame inside
   a 2/1 box leaves bars down each side worth 5.5% of the width (about 78px at
   desktop), and removing the crop properly means letting the band grow from
   620px to roughly 800px tall. Both are design changes rather than fixes, so
   they are offered rather than assumed. */
.about-slides .hero-slides__slide img,
.hero-slides--page .hero-slides__slide img { object-position: 50% 100%; }

/* ==== Footer back to underline; header gains bold + a teal hover ========= */

/* ---- Item 1: the footer's page links go back to an underline ------------
   The pill treatment is withdrawn from the footer only -- the header keeps
   it. Hover is now three things at once: underline, bold, and a little
   larger.

   Bold is the reason the size change is a transform rather than a font-size
   change. Bolding a link widens it, and widening it inside a list would
   nudge its neighbours; scaling is painted, so the column stays still.

   NOTE: with the pill gone the footer no longer marks which page you are on.
   That follows the instruction as written -- only a hover was specified -- so
   .is-active is left in the markup, unstyled, ready if a marker is wanted
   back later. */
.footer__links a,
.footer__links a.is-active,
.footer__links a:not(.is-active):hover,
.footer__links a:not(.is-active):focus-visible,
.footer__links a.is-active:hover,
.footer__links a.is-active:focus-visible {
  background: none;
  color: rgba(255, 255, 255, 0.75);
  padding: 0;
  margin: 0;
  border-radius: 0;
  font-weight: 400;
  text-decoration: none;
}
.footer__links a {
  display: inline-block;
  transform-origin: left center;
  transition: color .18s ease, transform .18s cubic-bezier(.2, .7, .3, 1);
}
[dir="rtl"] .footer__links a { transform-origin: right center; }

/* The :not(.is-active) selectors are here on purpose. The previous round's
   pill rule is written as `.footer__links a:not(.is-active):hover`, which is
   (0,3,1); a plain `.footer__links a:hover` is only (0,2,1) and loses to it
   however late it appears in the file. Matching its shape is what lets this
   rule win -- the first attempt applied the bold but kept the old rule's navy
   text and lost the underline entirely. */
.footer__links a:hover,
.footer__links a:focus-visible,
.footer__links a:not(.is-active):hover,
.footer__links a:not(.is-active):focus-visible,
.footer__links a.is-active:hover,
.footer__links a.is-active:focus-visible {
  color: #fff;
  font-weight: 700;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transform: scale(1.06);
  background: none;
}
/* Arabic has no usable step between 500 and 700 -- 800 is the first weight
   that reads as heavier. Same reason as the nav. */
[dir="rtl"] .footer__links a:hover,
[dir="rtl"] .footer__links a:focus-visible { font-weight: 800; }

@media (prefers-reduced-motion: reduce) {
  .footer__links a:hover, .footer__links a:focus-visible { transform: none; }
}

/* ---- Item 2: header nav, bold in both states ----------------------------
   Colours are unchanged for the active item: navy ground, white text. Hover
   moves to the teal set in the block below. Both states now also bold.
   700 for Latin; 800 for Arabic, where 700 is indistinguishable from the
   500 the other items use. */
.main-nav a.is-active,
.main-nav a.is-active:hover,
.main-nav a.is-active:focus-visible,
.main-nav a:not(.is-active):hover,
.main-nav a:not(.is-active):focus-visible { font-weight: 700; }

[dir="rtl"] .main-nav a.is-active,
[dir="rtl"] .main-nav a.is-active:hover,
[dir="rtl"] .main-nav a.is-active:focus-visible,
[dir="rtl"] .main-nav a:not(.is-active):hover,
[dir="rtl"] .main-nav a:not(.is-active):focus-visible { font-weight: 800; }

/* ---- Item 3: the teal hover accent --------------------------------------
   Three shades were shortlisted; all clear 4.5:1 with white bold text on top.
   A fourth, a brighter #0D949C, was dropped for failing at 3.66:1.

     A  #0D5E63  hue 183deg  sat 77%  light 22%   white 7.50:1
     B  #117A80  hue 183deg  sat 77%  light 28%   white 5.10:1
     C  #266A76  hue 189deg  sat 51%  light 31%   white 6.17:1

   A is set here because it is the closest relative of the navy already in the
   palette: --color-dark-blue is hue 207deg, sat 74%, light 21%, so A is very
   nearly the same colour rotated into teal. It reads as a sibling of the
   brand rather than a new colour introduced next to it. B is the same hue
   lifted six points lighter if a more obvious accent is wanted; C drops the
   saturation for something quieter.

   To switch, change this one value -- nothing else references the shade. */
:root { --color-teal: #0D5E63; }

.main-nav a:not(.is-active):hover,
.main-nav a:not(.is-active):focus-visible {
  background: var(--color-teal, #0D5E63);
  color: #fff;
}

/* ---- FINAL: the client's chosen nav hover -------------------------------
   "colour #57F4FF, effect: Fill + lift + bold" -- confirmed by the client
   from the comparison page.

   The label is navy, not white: white on #57F4FF is 1.33:1, which cannot be
   read. Navy on it is 8.83:1. The background is exactly the chosen colour.

   This supersedes the teal trialled earlier; --color-teal is left defined but
   unused so reverting is a one-line change if the client changes their mind. */
:root { --color-nav-hover: #57F4FF; }

.main-nav a:not(.is-active):hover,
.main-nav a:not(.is-active):focus-visible {
  background: var(--color-nav-hover, #57F4FF);
  color: var(--color-dark-blue, #0E3A5F);
  font-weight: 700;
  transform: translateY(-2px);
  box-shadow: 0 5px 14px rgba(14, 58, 95, 0.26);
}
[dir="rtl"] .main-nav a:not(.is-active):hover,
[dir="rtl"] .main-nav a:not(.is-active):focus-visible { font-weight: 800; }

@media (prefers-reduced-motion: reduce) {
  .main-nav a:not(.is-active):hover,
  .main-nav a:not(.is-active):focus-visible { transform: none; }
}

/* ======================================================================
   ROUND 12 - chosen hover colour #57F4FF
   ====================================================================== */

/* The hero Get in Touch button fills with the nav hover colour ------------
   Asked for as "the same colour fill inside its button outline", so unlike
   every other button the outline is kept rather than dissolved -- the colour
   appears within it.

   Three things have to be undone from the generic .btn--ghost:hover rule
   earlier in this file, which was written for the shared #3a7bc0 accent:
     - border-color: transparent      -> the outline must survive
     - color: #fff                    -> white on #57F4FF is 1.33:1, illegible
     - the mobile translucent ground  -> an opaque fill replaces it

   Only one element matches this on the whole site: the hero button on the two
   home pages. Every other button keeps the shared blue accent. */
.hero__cta .btn--ghost:hover,
.hero__cta .btn--ghost:focus-visible {
  background: var(--color-nav-hover, #57F4FF);
  color: var(--color-dark-blue, #0E3A5F);
  border-color: rgba(255, 255, 255, 0.85);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
