/* ============================================================================
   GEC — Shell: preloader, header, navigation, footer, floating WhatsApp
   ========================================================================= */

/* ------------------------------------------------------------ PRELOADER */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  background: var(--bg);
  transition: opacity .9s var(--ease), visibility .9s var(--ease);
}

.preloader.is-done { opacity: 0; visibility: hidden; }

.preloader__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2.1rem;
}

.preloader__mark {
  position: relative;
  width: clamp(132px, 34vw, 164px);
  aspect-ratio: 1;
  height: auto;
  display: grid;
  place-items: center;
}

.preloader__mark .brand__mark {
  width: 62px;
  color: var(--gold-on-bg);
  animation: markIn 1.5s var(--ease) both;
}

/* ---- The rosette ----
   Each figure is one continuous stroke, so setting stroke-dasharray to its own
   length and animating stroke-dashoffset from that length to zero traces it.
   The lengths below are the real perimeters: 110.3 squared = 441.2 for both
   squares, sixteen 32.31 edges = 517 for the star, 2(pi)40 = 251 for the inner
   circle. A wrong length does not break the draw, it just makes it run at the
   wrong speed, which is why they are written down rather than guessed. */
/* Centred by translate, NOT by insets.

   `inset: -16%` alone does not size an <svg>: it is a *replaced* element, so
   unlike a <div> it does not stretch to meet opposing offsets — it took the
   top/left offset and kept its own box, which shifted the whole figure up-left
   by exactly 26.2px on a 164px mark (16% of it), leaving the monogram sitting
   low and right of the rosette's centre.

   top/left 50% with a -50% translate is immune to however the size resolves:
   the figure is centred on the monogram whatever happens to its box. */
.rosette {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 132%;
  /* gec.css resets `img, svg, video { max-width: 100% }`, which silently
     clamped this back to 100% and drew the rosette at the monogram's own size. */
  max-width: none;
  aspect-ratio: 1;
  height: auto;
  transform: translate(-50%, -50%);
  color: var(--gold-on-bg);
  overflow: visible;
}

.rosette__ring {
  opacity: 0;
  transform-origin: 100px 100px;
  animation: rosFade 1.4s var(--ease) .1s forwards,
             spin 64s linear 1.4s infinite;
}

/* Counter-turn: the star and the ring drift against each other, which is what
   stops a symmetrical figure from looking static. 96s is deliberately below the
   threshold where the eye reads it as movement. */
.rosette__star {
  transform-origin: 100px 100px;
  animation: spinBack 96s linear 2.1s infinite;
}

.ros {
  stroke-width: 1;
  stroke-dasharray: var(--len);
  stroke-dashoffset: var(--len);
  opacity: .9;
  animation: rosDraw 1.45s cubic-bezier(.33, 0, .2, 1) var(--dly, 0s) forwards;
}

.ros--sq { --len: 441.2; --dly: .12s; }
.ros--di { --len: 441.2; --dly: .30s; }
.ros--kh { --len: 517;   --dly: .48s; stroke-width: 1.25; }
.ros--in { --len: 251.3; --dly: .78s; opacity: .55; }

@keyframes rosDraw { to { stroke-dashoffset: 0; } }
@keyframes rosFade { to { opacity: .45; } }
@keyframes spinBack { to { transform: rotate(-360deg); } }

/* Spec §6.1 — no motion means no motion. The figure simply appears, drawn. */
@media (prefers-reduced-motion: reduce) {
  .rosette__ring { animation: none; opacity: .45; }
  .rosette__star { animation: none; }
  .ros           { animation: none; stroke-dashoffset: 0; }
}

/* The full lockup, given the room the header cannot spare. Widths hold the
   artwork's 100 / 57 / 64 proportion. */
.preloader__words {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  animation: markIn 1.5s var(--ease) .18s both;
}

.preloader__words .brand__line--1 { width: clamp(210px, 46vw, 400px); color: var(--text); }
.preloader__words .brand__line--2 { width: clamp(120px, 26.2vw, 228px); color: var(--gold-on-bg); }
.preloader__words .brand__line--3 { width: clamp(134px, 29.4vw, 256px); color: var(--text-muted); }

.preloader__bar {
  position: relative;
  width: 168px; height: 1px;
  background: rgba(200,165,91,.2);
  overflow: hidden;
}

.preloader__bar span {
  position: absolute;
  inset: 0;
  background: var(--gold-grad);
  transform: scaleX(0);
  transform-origin: left;
  animation: load 2.25s var(--ease-in-out) forwards;
}

@keyframes markIn { from { opacity: 0; transform: scale(.82); } to { opacity: 1; transform: none; } }
@keyframes spin   { to { transform: rotate(360deg); } }
@keyframes load   { to { transform: scaleX(1); } }

/* --------------------------------------------------------------- HEADER */
.header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 120;
  height: var(--header-h);
  display: flex;
  align-items: center;
  transition: background-color .5s var(--ease), border-color .5s var(--ease), height .5s var(--ease);
  border-bottom: 1px solid transparent;
}

.header.is-stuck {
  height: calc(var(--header-h) - 12px);
  background: var(--header-bg);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
  border-bottom-color: var(--line-gold);
}

/* Pages that do not open with a photo hero (Contact, Journal, Privacy, Founder)
   have the header sitting straight on the page ground. It needs its own surface
   from the start, or cream-on-cream makes the nav vanish in the light theme. */
body:not(.has-hero) .header {
  background: var(--header-bg);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
  border-bottom-color: var(--line);
}

.header.is-hidden { transform: translateY(-100%); transition: transform .45s var(--ease); }

.header__in {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

/* ------------------------------------------------------------ BRAND LOCKUP
   Built from the client's own logo artwork rather than typeset again in a
   substitute face — the monogram and both wordmark lines are cropped from the
   supplied file and applied as CSS masks. Because a mask paints the element's
   own colour through the letterforms, one asset set serves gold on black, gold
   on cream and anything in between, with no second export per theme. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: .8rem;
  flex: none;
}

.brand__mark,
.brand__line {
  display: block;
  flex: none;
  /* Fallback for engines without mask support: the baked gold artwork. */
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

@supports ((-webkit-mask-image: url("")) or (mask-image: url(""))) {
  .brand__mark,
  .brand__line {
    background-image: none !important;
    background-color: currentColor;
    -webkit-mask-repeat: no-repeat;   mask-repeat: no-repeat;
    -webkit-mask-position: center;    mask-position: center;
    -webkit-mask-size: contain;       mask-size: contain;
  }
}

.brand__mark {
  width: 46px;
  aspect-ratio: 1.0922;              /* intrinsic ratio of the cropped monogram */
  color: var(--gold-on-bg);
  background-image: url("/assets/brand/monogram-gold.png");
  -webkit-mask-image: url("/assets/brand/mk-monogram.png");
  mask-image: url("/assets/brand/mk-monogram.png");
  transition: width .5s var(--ease);
}

.header.is-stuck .brand__mark { width: 39px; }

.brand__rule {
  width: 1px;
  height: 34px;
  background: linear-gradient(to bottom, transparent, var(--line-gold) 22%, var(--line-gold) 78%, transparent);
  flex: none;
  transition: height .5s var(--ease);
}

.header.is-stuck .brand__rule { height: 28px; }

/* CONCIERGE is centred beneath GLOBAL ELITE, as it is in the supplied logo —
   `align-items: center` rather than the default, which left-aligned it. The
   widths hold the artwork's own proportion: measured off the client's file,
   CONCIERGE is 57% of the GLOBAL ELITE line and the tagline 64%. */
.brand__words {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  justify-content: center;
}

.brand__line--1 {
  width: 150px;
  aspect-ratio: 14.6789;
  color: var(--text);
  background-image: url("/assets/brand/wordmark-cream.png");
  -webkit-mask-image: url("/assets/brand/mk-global.png");
  mask-image: url("/assets/brand/mk-global.png");
  transition: width .5s var(--ease);
}

.brand__line--2 {
  width: 86px;
  aspect-ratio: 14.8148;
  color: var(--gold-on-bg);
  -webkit-mask-image: url("/assets/brand/mk-concierge.png");
  mask-image: url("/assets/brand/mk-concierge.png");
  transition: width .5s var(--ease);
}

/* LUXURY · PRIVATE · EXCLUSIVE. The mask lives here, unscoped, so every lockup
   can use it; only the width is set per context.

   It is deliberately NOT in the header bar. Measured at 1440px the header has
   50px of spare width, and a legible tagline needs about 150px — at the width
   that does fit it renders 4px tall, which reads as a smudge rather than as
   three words. It carries at full size in the preloader and the footer, where
   there is room for it. */
.brand__line--3 {
  aspect-ratio: 27.2727;
  -webkit-mask-image: url("/assets/brand/mk-tagline.png");
  mask-image: url("/assets/brand/mk-tagline.png");
}

.header.is-stuck .brand__line--1 { width: 132px; }
.header.is-stuck .brand__line--2 { width: 75px; }

/* ---- Footer lockup: the full stacked mark, tagline included ----
   Centred on itself the way the supplied artwork is, so the monogram,
   CONCIERGE and the tagline all sit on the axis of GLOBAL ELITE. The block as
   a whole still starts at the column's leading edge. */
.brand-stack {
  display: flex;
  flex-direction: column;
  gap: 11px;
  align-items: center;
  /* The column is 399px wide; the lockup was using 196 of it. At this width the
     tagline renders ~7px tall and reads as three words rather than a rule. */
  width: min(290px, 100%);
}

.brand-stack .brand__mark    { width: 76px; margin-bottom: 4px; }
.brand-stack .brand__line--1 { width: 100%; }
.brand-stack .brand__line--2 { width: 57%; }
.brand-stack .brand__line--3 { width: 64%; color: var(--text-muted); }

/* Desktop nav */
.nav { display: flex; align-items: center; gap: clamp(1.3rem, 2.4vw, 2.5rem); }

/* No colour transition on the header's own text.
   These colours come from tokens that are redefined when the header switches
   between "over the hero photo" and "on the page surface". A running transition
   holds the previous computed colour through that swap and never lands on the
   new one — which left cream nav links on a cream header in the light theme.
   The header's background already cross-fades; the text stepping instantly
   underneath it is not perceptible, and it is always correct. */
.nav__link {
  position: relative;
  font-size: .715rem;
  font-weight: 400;
  letter-spacing: .19em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding-block: .55rem;
  white-space: nowrap;
}

.nav__link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .45s var(--ease);
}

.nav__link:hover,
.nav__link.is-active { color: var(--text); }

.nav__link:hover::after,
.nav__link.is-active::after { transform: scaleX(1); transform-origin: left; }

.header__actions { display: flex; align-items: center; gap: 1.15rem; flex: none; }

/* Language switch */
.lang {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-size: .7rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: .4rem .2rem;
}

.lang:hover { color: var(--gold-on-bg); }
.lang__ico { width: 13px; height: 13px; opacity: .75; }

/* Hamburger */
.burger {
  display: none;
  width: 46px; height: 46px;
  place-items: center;
  margin-right: -10px;
}

.burger__box { display: block; width: 23px; height: 13px; position: relative; }

.burger__box i {
  position: absolute;
  left: 0;
  width: 100%; height: 1px;
  background: var(--text);
  transition: transform .45s var(--ease), opacity .3s var(--ease), background-color .3s var(--ease);
}

.burger__box i:nth-child(1) { top: 0; }
.burger__box i:nth-child(2) { top: 6px; }
.burger__box i:nth-child(3) { top: 12px; }

.is-menu-open .burger__box i:nth-child(1) { transform: translateY(6px) rotate(45deg);  background: var(--gold); }
.is-menu-open .burger__box i:nth-child(2) { opacity: 0; transform: scaleX(.3); }
.is-menu-open .burger__box i:nth-child(3) { transform: translateY(-6px) rotate(-45deg); background: var(--gold); }

/* ---------------------------------------------------------- MOBILE MENU
   The full-screen overlay. It is two columns wherever there is room — the
   numbered nav on the reading side, a concierge panel carrying the six services
   and the two actions on the other — because the previous single column left
   the outer half of the screen empty on anything wider than a phone. That read
   as an unfinished mobile nav, not as the brand's front door.

   Everything is set in logical properties so the Arabic build mirrors without a
   single override, and every colour is a token so both themes follow.          */
.menu {
  position: fixed;
  inset: 0;
  z-index: 110;
  background: var(--bg-alt);
  display: flex;
  flex-direction: column;
  padding: calc(var(--header-h) + 2rem) var(--gutter) 2rem;
  overflow-y: auto;
  /* Explicit, and not optional: setting only overflow-y computes overflow-x
     from `visible` to `auto`, so the ornament bleeding past the inline edge
     produced a real horizontal scrollbar across the whole overlay. */
  overflow-x: hidden;
  overscroll-behavior: contain;
  clip-path: circle(0% at calc(100% - 44px) 44px);
  transition: clip-path .8s var(--ease);
  visibility: hidden;
}

.menu.is-open { clip-path: circle(155% at calc(100% - 44px) 44px); visibility: visible; }

/* A slow gold bloom in the outer corner, warming the ground the actions sit on.

   This started as an oversized khatam star and had to be abandoned: at the low
   opacity a watermark needs, its eight straight edges still read as a hard
   polygon crossing the panel — the eye registered a rendering artefact rather
   than an ornament. A radial gradient has no edge to give away, so it can sit
   at a strength that is actually felt instead of merely detected. */
.menu__ornament {
  position: absolute;
  inset-block-end: -18vmax;
  inset-inline-end: -14vmax;
  width: 58vmax;
  aspect-ratio: 1;
  background: radial-gradient(closest-side, var(--line-gold), transparent 72%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.8s var(--ease) .4s, transform 2s var(--ease) .4s;
  transform: scale(.9);
}

.menu.is-open .menu__ornament { opacity: .9; transform: none; }
:root[data-theme="light"] .menu.is-open .menu__ornament { opacity: .55; }

.menu__in {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2.2rem;
  margin-block-end: auto;
}

/* ---- The numbered nav ---- */
.menu__nav { display: flex; flex-direction: column; }

/* A hairline under every item, editorial-index style. The last one is dropped
   at the two-column breakpoint where the column already has an edge. */
.menu__link {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: clamp(.9rem, 2.2vw, 1.5rem);
  padding-block: clamp(.5rem, 1.1vw, .78rem);
  border-block-end: 1px solid var(--line);
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 8vw, 2.9rem);
  font-weight: 300;
  line-height: 1.24;
  color: var(--text);
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .7s var(--ease), transform .7s var(--ease), color .35s var(--ease);
  transition-delay: var(--dly, 0ms);
}

.menu.is-open .menu__link { opacity: 1; transform: none; }
.menu__link:hover,
.menu__link:focus-visible { color: var(--gold-on-bg); }

/* A gold rule that draws along the item on hover, over the static hairline. */
.menu__link::after {
  content: "";
  position: absolute;
  inset-block-end: -1px;
  inset-inline-start: 0;
  width: 0;
  height: 1px;
  background: var(--gold-grad);
  transition: width .6s var(--ease);
}

.menu__link:hover::after,
.menu__link:focus-visible::after { width: 100%; }

.menu__n {
  flex: none;
  font-family: var(--font-body);
  font-size: .6rem;
  letter-spacing: .2em;
  color: var(--gold-on-bg);
  opacity: .75;
  transform: translateY(-.35em);
}

.menu__word { min-width: 0; }

/* The arrow rides the reading edge and slides in on hover. `rotate` is set in
   rtl.css rather than here so the mirrored build points the other way. */
.menu__go {
  flex: none;
  width: 17px; height: 17px;
  margin-inline-start: auto;
  align-self: center;
  color: var(--gold-on-bg);
  opacity: 0;
  transform: translateX(-8px);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}

.menu__link:hover .menu__go,
.menu__link:focus-visible .menu__go,
.menu__svc-link:hover .menu__go,
.menu__svc-link:focus-visible .menu__go { opacity: 1; transform: none; }

/* ---- The concierge panel ---- */
.menu__panel {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  min-width: 0;
}

.menu__eyebrow {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin: 0;
  font-size: .62rem;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--gold-on-bg);
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
  transition-delay: var(--dly, 0ms);
}

.menu.is-open .menu__eyebrow { opacity: 1; transform: none; }

/* The rule runs to the end of the line, so the label reads as a section mark. */
.menu__eyebrow::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line-gold);
}

.menu__svc { display: grid; grid-template-columns: minmax(0, 1fr); }

.menu__svc-link {
  display: flex;
  align-items: center;
  gap: .8rem;
  min-width: 0;
  padding-block: .62rem;
  border-block-end: 1px solid var(--line);
  font-size: .9rem;
  letter-spacing: .015em;
  color: var(--text-muted);
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .6s var(--ease), transform .6s var(--ease), color .3s var(--ease);
  transition-delay: var(--dly, 0ms);
}

.menu.is-open .menu__svc-link { opacity: 1; transform: none; }
.menu__svc-link:hover,
.menu__svc-link:focus-visible { color: var(--gold-on-bg); }

.menu__svc-ico { flex: none; width: 19px; height: 19px; color: var(--gold-on-bg); }
.menu__svc-name { min-width: 0; overflow-wrap: anywhere; }

.menu__actions {
  display: flex;
  flex-wrap: wrap;
  gap: .7rem;
  margin-block-start: .5rem;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
  transition-delay: var(--dly, 0ms);
}

.menu.is-open .menu__actions { opacity: 1; transform: none; }
.menu__actions .btn { flex: 1 1 200px; }

/* ---- Foot ---- */
.menu__foot {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-block-start: 2rem;
  padding-block-start: 1.5rem;
  border-block-start: 1px solid var(--line);
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
  transition-delay: var(--dly, 0ms);
}

.menu.is-open .menu__foot { opacity: 1; transform: none; }

.menu__contact {
  display: flex;
  flex-wrap: wrap;
  gap: .2rem 1.5rem;
  font-size: .82rem;
  color: var(--text-dim);
}

/* `nowrap` on both axes is what keeps these intact: without it the row squeezed
   each item until the icon sat on its own line above its text, and the email
   and the phone number ran together with no gap between them. They wrap as
   whole items against each other, never inside themselves.

   padding-block takes them from a measured 23px to 29px, over WCAG 2.5.8's 24 —
   an email address is exactly the thing someone taps in a hurry. */
.menu__contact a,
.menu__contact span {
  display: inline-flex;
  align-items: center;
  flex-wrap: nowrap;
  white-space: nowrap;
  gap: .5rem;
  padding-block: 3px;
}
.menu__contact svg { width: 14px; height: 14px; color: var(--gold-on-bg); opacity: .8; flex: none; }
.menu__contact a:hover { color: var(--gold-on-bg); }

.menu__meta { display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; }

/* The third wordmark line — LUXURY · PRIVATE · EXCLUSIVE. It carries the
   .brand__line--3 class in the markup, so the mask, the aspect ratio and the
   no-mask-support fallback all come from the one place that already defines
   them; this rule only sets where it sits and how big. */
.menu__tagline {
  display: none;
  width: clamp(118px, 15vw, 162px);
  color: var(--text-dim);
  margin-inline-end: auto;
}

/* ---- Two columns, once there is room for them ----
   At 760 the nav and the panel sit side by side with a gold hairline between,
   and the panel gains its own inset. Below it they stack, which is why the
   services live in their own block rather than inside the nav list. */
@media (min-width: 760px) {
  .menu__in {
    grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr);
    gap: clamp(2rem, 4.5vw, 4.5rem);
    align-items: start;
  }

  .menu__panel {
    padding-inline-start: clamp(2rem, 4.5vw, 4.5rem);
    border-inline-start: 1px solid var(--line-gold);
    min-height: 100%;
  }

  .menu__nav .menu__link:last-child { border-block-end: 0; }
  .menu__tagline { display: block; }
  .menu__svc-link { font-size: .95rem; padding-block: .72rem; }
}

/* Calmer type on anything wider than a phone. The overlay never appears at
   1120 or above, so this range is tablets and display-scaled desktops — where
   the phone-sized display type read as shouting. */
@media (min-width: 560px) {
  .menu__link { font-size: clamp(1.7rem, 3.4vw, 2.5rem); }
}

@media (min-width: 760px) {
  .menu__link { font-size: clamp(1.8rem, 2.9vw, 2.45rem); }
}

/* A short window is the binding constraint — a 1280×720 laptop, or a desktop
   that display scaling has pushed under the nav breakpoint. Trim the overlay's
   own padding along with the type so the whole list clears the fold. */
@media (min-width: 600px) and (max-height: 800px) {
  .menu { padding-block: calc(var(--header-h) + 1.1rem) 1.3rem; }
  .menu__link { font-size: clamp(1.45rem, 2.3vw, 1.95rem); padding-block: .42rem; }
  .menu__svc-link { padding-block: .5rem; }
  .menu__foot { margin-block-start: 1.4rem; padding-block-start: 1.1rem; }
  .menu__in { gap: 1.6rem; }
}

/* Single column: the panel falls beneath the nav, which would bury the two
   actions under seven nav items and six services — measured at 970px down a
   375px-wide phone, so the primary call to action needed a scroll to reach.
   Lifting them above the services puts "Submit a Private Request" immediately
   after the navigation, where someone who came here to ask for something will
   actually meet it. The services keep their labelled section below. */
@media (max-width: 759px) {
  .menu__actions {
    order: -1;
    margin-block-start: 0;
    margin-block-end: 1.1rem;
  }
}

/* On a phone the contact block stacks; three items on one line would wrap
   mid-address. */
@media (max-width: 559px) {
  .menu__contact { flex-direction: column; gap: .45rem; }
  .menu__foot { justify-content: flex-start; }
}

/* Motion is decoration here — the overlay must still open instantly and show
   everything when the visitor has asked for less of it. */
@media (prefers-reduced-motion: reduce) {
  .menu { transition: none; }
  .menu__link,
  .menu__eyebrow,
  .menu__svc-link,
  .menu__actions,
  .menu__foot,
  .menu__ornament {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0ms !important;
  }
  .menu.is-open .menu__ornament { opacity: .05; transform: none; }
  .menu__link::after, .menu__go { transition: none; }
}


/* --------------------------------------------------- FLOATING WHATSAPP */
.wa {
  position: fixed;
  right: clamp(1rem, 3vw, 2.2rem);
  bottom: clamp(1rem, 3vw, 2.2rem);
  z-index: 100;
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-direction: row-reverse;
}

.wa__btn {
  position: relative;
  width: 58px; height: 58px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--gold-grad);
  background-size: 200% auto;
  color: var(--bg);
  box-shadow: 0 10px 34px rgba(0,0,0,.55), 0 0 0 1px rgba(200,165,91,.35);
  transition: background-position .8s var(--ease), transform .4s var(--ease);
}

.wa__btn:hover { background-position: 100% center; transform: scale(1.07); }
.wa__btn svg { width: 27px; height: 27px; }

/* Gentle attention pulse */
.wa__btn::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: 50%;
  border: 1px solid var(--gold);
  animation: waPulse 3.4s var(--ease) infinite;
}

@keyframes waPulse {
  0%   { transform: scale(1);    opacity: .7; }
  70%  { transform: scale(1.45); opacity: 0; }
  100% { transform: scale(1.45); opacity: 0; }
}

.wa__bubble {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .72rem 1rem;
  background: var(--bg-raise);
  border: 1px solid var(--line-gold);
  color: var(--text);
  font-size: .76rem;
  letter-spacing: .05em;
  white-space: nowrap;
  box-shadow: 0 8px 26px rgba(0,0,0,.28);
  opacity: 0;
  transform: translateX(14px) scale(.96);
  pointer-events: none;
  transition: opacity .6s var(--ease), transform .6s var(--ease);
}

.wa__bubble.is-shown { opacity: 1; transform: none; pointer-events: auto; }

.wa__close {
  display: grid;
  place-items: center;
  width: 19px; height: 19px;
  color: var(--text-dim);
  font-size: 1rem;
  line-height: 1;
  transition: color var(--t-fast) var(--ease);
}

.wa__close:hover { color: var(--gold-on-bg); }

/* --------------------------------------------------------------- FOOTER */
.footer {
  position: relative;
  background: var(--bg-alt);
  border-top: 1px solid var(--line-gold);
  overflow: hidden;
}

.footer__top {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(280px, 1.35fr) repeat(3, minmax(130px, .8fr));
  gap: clamp(2.2rem, 4vw, 4rem);
  padding-block: clamp(3.5rem, 7vw, 6rem);
}

.footer__brand { display: flex; flex-direction: column; gap: 1.4rem; }
.footer__brand img { width: clamp(158px, 15vw, 205px); }

.footer__tag {
  font-family: var(--font-display);
  font-size: 1.16rem;
  font-style: italic;
  color: var(--gold-on-bg);
  letter-spacing: .02em;
}

.footer__col h4 {
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--gold-on-bg);
  margin-bottom: 1.4rem;
}

.footer__col ul { list-style: none; display: flex; flex-direction: column; gap: .78rem; }

.footer__col a {
  font-size: .855rem;
  color: var(--text-muted);
  transition: color var(--t-fast) var(--ease), padding-left var(--t-fast) var(--ease);
}

.footer__col a:hover { color: var(--gold-on-bg); padding-left: 5px; }

.footer__bar {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.6rem;
  border-top: 1px solid var(--line);
  font-size: .78rem;
  color: var(--text-dim);
}

/* WCAG 2.5.8 asks for a 24x24 pointer target. This link is .78rem text with no
   box of its own, so it measured 16px tall (19px in Arabic) — fine to read,
   awkward to hit with a thumb. The padding supplies the target; the matching
   negative margin keeps the bar exactly the height it was. */
.footer__bar a {
  display: inline-block;
  padding-block: .42rem;
  margin-block: -.42rem;
}

.footer__bar a:hover { color: var(--gold-on-bg); }

.socials { display: flex; gap: .7rem; }

.social {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border: 1px solid var(--line);
  color: var(--text-muted);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}

.social:hover { color: var(--gold-on-bg); border-color: var(--line-gold); transform: translateY(-3px); }
.social svg { width: 16px; height: 16px; }

/* =============================================================== MEGA MENU
   The Services item opens a full-width panel beneath the header.

   `.hasmega` is deliberately left unpositioned: the panel then resolves against
   the fixed `.header`, which gives it the viewport's exact width without using
   `100vw` — that would be a scrollbar wider than the page and push the whole
   layout sideways — and makes it track `top: 100%` as the header shrinks on
   scroll. The panel is a DOM child of `.hasmega`, so a plain `:hover` on the
   group keeps it open while the pointer travels from the link into the panel. */
.hasmega { display: flex; align-items: center; }

.nav__link--mega { display: inline-flex; align-items: center; gap: .42rem; }

.nav__caret {
  width: 10px; height: 10px;
  flex: none;
  opacity: .7;
  transition: transform .4s var(--ease), opacity .3s var(--ease);
}

.hasmega.is-open .nav__caret { transform: rotate(180deg); opacity: 1; }

.mega {
  position: absolute;
  top: 100%; left: 0; right: 0;
  z-index: 5;
  background: var(--bg-alt);
  border-top: 1px solid var(--line-gold);
  border-bottom: 1px solid var(--line-gold);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-12px);
  transition: opacity .4s var(--ease), transform .4s var(--ease), visibility .4s;
}

.hasmega.is-open .mega { opacity: 1; visibility: visible; transform: none; }

.mega__in {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding: clamp(2rem, 3vw, 3rem) var(--gutter) clamp(2.2rem, 3.2vw, 3.2rem);
  display: grid;
  grid-template-columns: minmax(0, 250px) minmax(0, 1fr);
  gap: clamp(1.8rem, 3.5vw, 4rem);
  align-items: start;
}

.mega__title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.9vw, 2rem);
  font-weight: 300;
  line-height: 1.24;
  color: var(--text);
  margin-block: .7rem .55rem;
}

.mega__blurb {
  font-size: .86rem;
  line-height: 1.75;
  color: var(--text-dim);
  margin-bottom: 1.1rem;
}

.mega__all { font-size: .7rem; }

.mega__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
}

/* A hairline grid rather than gaps: the 1px background shows through between
   the cards, so each one reads as a cell of one table instead of six islands. */
.mega__card {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: .95rem;
  min-width: 0;
  padding: 1.15rem 1.2rem;
  background: var(--bg-alt);
  transition: background-color .35s var(--ease);
}

.mega__card:hover { background: var(--bg-raise); }

.mega__ico {
  flex: none;
  width: 42px; height: 42px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-gold);
  color: var(--gold-on-bg);
  transition: background-color .35s var(--ease), color .35s var(--ease), border-color .35s var(--ease);
}

.mega__ico svg { width: 21px; height: 21px; }

.mega__card:hover .mega__ico {
  background: var(--gold-on-bg);
  border-color: var(--gold-on-bg);
  color: var(--bg-alt);
}

.mega__txt { display: flex; flex-direction: column; gap: .18rem; min-width: 0; }

.mega__name {
  font-family: var(--font-display);
  font-size: 1.12rem;
  font-weight: 500;
  line-height: 1.25;
  color: var(--text);
}

.mega__tag {
  font-style: italic;
  font-size: .78rem;
  color: var(--gold-on-bg);
}

.mega__items {
  font-size: .72rem;
  line-height: 1.6;
  color: var(--text-dim);
  margin-top: .22rem;
}

.mega__go {
  flex: none;
  width: 15px; height: 15px;
  margin-top: .5rem;
  color: var(--gold-on-bg);
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity .35s var(--ease), transform .35s var(--ease);
}

.mega__card:hover .mega__go { opacity: 1; transform: none; }

/* With the panel open the header needs its own ground, or over a photo hero the
   transparent bar leaves the panel looking detached from nothing. */
.header.is-mega {
  background: var(--header-bg);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
}

@media (max-width: 1320px) {
  .mega__in { grid-template-columns: minmax(0, 210px) minmax(0, 1fr); }
  .mega__name { font-size: 1.04rem; }
  .mega__items { display: none; }
}

/* ------------------------------------------------------------ RESPONSIVE */
@media (max-width: 1320px) {
  .nav { gap: 1.05rem; }
  .nav__link { font-size: .67rem; letter-spacing: .14em; }
  .header__actions { gap: .85rem; }
}

/* The six-item nav plus the actions cluster has an intrinsic width of 1080px —
   brand (223) + nav (491) + actions (320) + two 24px gaps. Against a 5vw gutter
   that needs a 1200px viewport just to break even, which is why this breakpoint
   used to sit at 1240:

     1160px → 1044 available, 1080 needed — over by 36
     1200px → 1080 available — fits by 0px, too tight to trust
     1240px → 1116 available — 36px of headroom

   That was too blunt an instrument. A 1920×1080 panel at 150% display scaling
   reports 1280 CSS px, and a browser side panel takes it under 1240 — so a
   perfectly wide desktop was being handed the phone menu. GEC hit exactly that.

   The answer is to make the header narrower, not to give up sooner. Between
   1024 and 1400 the gutter, the nav gap and the header's own gap all tighten,
   which buys back about 125px and carries the inline nav down to 1024 with real
   headroom. Nothing changes above 1400, where there was never a problem. */
@media (min-width: 1024px) and (max-width: 1400px) {
  /* The gutter is the big win: 5vw is 60px a side at 1200, and this header has
     no use for it. The nav gap is deliberately NOT touched here — the ≤1320px
     block above already pulls it to 1.05rem, and anything vw-based re-loosens
     it at exactly the widths that are struggling. */
  .header__in {
    padding-inline: clamp(1.25rem, 2.1vw, 2.5rem);
    gap: 1rem;
  }
  .nav__link { letter-spacing: .1em; }
}

/* Measured after the compaction above: the intrinsic width is 1045, and the
   content box is 1073 at 1120 and 1035 at 1080. So 1120 is the last width with
   real headroom (28px) rather than the 0–9px that made 1200 untrustworthy
   before. */
@media (max-width: 1119px) {
  .nav,
  .header__actions .btn,
  .header__actions .lang { display: none; }
  .burger { display: grid; }
}

@media (max-width: 1000px) {
  .footer__top { grid-template-columns: 1fr 1fr; }
  .footer__brand { grid-column: 1 / -1; }
}

/* Scale the lockup down rather than dropping the name — a bare monogram is
   weaker branding, and there is room for the wordmark well below tablet. */
@media (max-width: 700px) {
  .brand           { gap: .62rem; }
  .brand__mark,
  .header.is-stuck .brand__mark   { width: 38px; }
  .brand__rule,
  .header.is-stuck .brand__rule   { height: 27px; }
  .brand__words    { gap: 4px; }
  .brand__line--1,
  .header.is-stuck .brand__line--1 { width: 112px; }
  .brand__line--2,
  .header.is-stuck .brand__line--2 { width: 64px; }
}

@media (max-width: 420px) {
  .brand__words { display: none; }
  .brand__rule  { display: none; }
  .brand__mark,
  .header.is-stuck .brand__mark { width: 36px; }
}

@media (max-width: 560px) {
  .footer__top  { grid-template-columns: 1fr; }
  .wa__bubble   { display: none; }
  .footer__bar  { justify-content: center; text-align: center; }
}

/* =========================================================== TOUCH TARGETS
   Every control gets at least a 44px hit area on touch widths, even where the
   visible element is smaller. This block lives at the end of the last-loaded
   sheet on purpose: the component rules it relaxes have equal specificity, so
   source order is what decides, and measuring showed the earlier attempt in
   gec.css was losing to the definitions here. */
@media (max-width: 900px) {
  .theme-btn        { width: 44px; height: 44px; }
  .social           { width: 44px; height: 44px; }
  .brand            { min-height: 44px; min-width: 44px; align-items: center; }
  .link-u           { padding-block: .82rem .64rem; }
  .includes button  { padding-block: 1rem; }
  /* .84rem measured at 40.8px tall — just under. Scoped to `.tabs .tab` for
     specificity: page.css loads AFTER layout.css on every page with a Styles
     section, and its `.tab { padding: .62rem 1.1rem }` is both later in source
     order and a shorthand, so the bare `.tab` rule here never landed. */
  .tabs .tab        { padding-block: .95rem; }
  /* The service-card "Discover" link measured 40.6px; the extra pad clears 44. */
  .svcx__go         { padding-bottom: .55rem; }

  /* Footer and menu lists: pad the links out and pull the gaps in, so the rows
     are comfortably tappable without the column growing unreasonably tall. */
  .footer__col ul     { gap: 0; }
  .footer__col a,
  .footer__col li > span { display: block; padding-block: .68rem; }
  /* These two lines were written for the old menu, where the contact block was
     a plain vertical stack of bare links. It is now an inline-flex row of
     icon+label items, so `display: block` broke each one onto two lines — the
     icon stranded above its own text — and `gap: 0` ran the email and the phone
     number together. Only the vertical padding belongs here. */
  .menu__contact a,
  .menu__contact span { padding-block: .62rem; }
  /* Short labels (notably the Arabic ones) fall under 40px wide otherwise */
  /* .72rem measured at 41.5px tall in both languages. */
  .crumb a            { display: inline-block; padding-block: .86rem; min-width: 44px; text-align: center; }
  .footer__bar a      { display: inline-block; padding-block: .72rem; }
  /* `flex: none` matters: as a flex child it was shrinking to 42.2px. */
  .wa__close          { width: 44px; height: 44px; flex: none; }
  .wa__bubble         { padding-block: .3rem; padding-inline-end: .3rem; }
}
