/* ===========================================================================
   EMAAR — Communities / Community / Project
   places.css — the complete stylesheet for the three new templates.

   This file is SELF-CONTAINED. It links nothing and inherits nothing: not
   page.css, not styles.css, not search.css, not a Tailwind build. Three
   reasons —
     1. page.css / app.js / index.html are owned by another concurrent session.
     2. page.css turns every direct child of <main class="page"> into a sticky
        shutter panel, which these pages must not inherit.
     3. A borrowed stylesheet's token carrier is a trap: off its own selector
        every class silently loses its values.

   Everything here is the visual language of emaar-search-results.html — the
   declared source of truth for this redesign — expressed as classes instead
   of inline style attributes. Where a value departs from that file it is
   because the file's value fails a measured accessibility floor, and the
   departure is annotated at the token.

   Namespace: .em-*  and  --em-*
   =========================================================================== */

@font-face {
  font-family: 'Source Sans 3';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(./fonts/source-sans-3.woff2) format('woff2');
}

/* ————————————————————————————— 1 · Tokens —————————————————————————————

   MOVED — assets/ds/01-tokens.css.

   The token block used to live here, in a stylesheet named after ONE page
   family. Forty-five pages linked this file and got the system; six did not,
   and each of those had rewritten the same palette under its own prefix.
   Every --em-* name still resolves exactly as it did; it is simply declared
   somewhere every page can reach.                                          */


/* ——————————————————————— 2–3 · Reset, skip link ———————————————————————

   MOVED — assets/ds/02-base.css.                                           */

/* ———————————————————————— 4 · Brand lockup ———————————————————————— */

.em-brand {
  position: fixed; left: var(--em-gut-wide); top: 24px; z-index: var(--z-brand);
  display: flex; align-items: flex-start; line-height: 0;
  /* the lockup is 19px tall; padding plus an equal negative margin grows the
     hit box to 44px and leaves the glyphs exactly where they were */
  padding: 14px 12px; margin: -14px -12px;
  font-size: 19px; color: var(--em-ink);
  transition: color var(--em-t-slow) ease, opacity var(--em-t) ease;
}
.em-brand:hover { opacity: .65; color: var(--em-ink); }
.em-brand:focus-visible { outline: 2px solid currentColor; outline-offset: 6px; }
.em-brand svg { height: 1em; width: auto; display: block; fill: currentColor; }
.em-brand svg + svg { margin-left: .0184em; }
.em-brand svg:nth-child(2) { margin-left: .0497em; }
.em-brand svg:nth-child(4) { margin-left: .0156em; }
.em-brand svg:nth-child(5) { margin-left: .0288em; }
.em-brand.is-inverted { color: var(--em-on-night); }

/* ———————————————————————— 5 · Header ———————————————————————— */

.em-hdr {
  position: fixed; top: 0; left: 0; right: 0; z-index: var(--z-header);
  height: var(--em-hdr);
  display: flex; align-items: center; gap: clamp(20px,3vw,44px);
  padding: 0 var(--em-gut-wide);
  color: var(--em-ink);
  background: var(--em-header-bg);
  -webkit-backdrop-filter: var(--em-header-bf);
  backdrop-filter: var(--em-header-bf);
  border-bottom: 1px solid var(--em-header-line);
  transition: color var(--em-t-slow) ease, background var(--em-t-slow) ease,
              border-color var(--em-t-slow) ease;
}
.em-hdr__spacer { width: 118px; height: 24px; flex: none; }
@media (max-width: 519px) {
  /* the lockup shrinks with the bar, so the box it reserves shrinks too */
  .em-brand { font-size: 16px; }
  .em-hdr__spacer { width: 88px; }
  .em-hdr { gap: 8px; padding: 0 var(--em-gut); }
  .em-hdr__util .em-hdr__util-l { display: none; }
}
.em-hdr__nav { display: none; align-items: center; gap: clamp(12px,1.7vw,28px); }
.em-hdr__link {
  position: relative; white-space: nowrap;
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: 11.5px; font-weight: 600; letter-spacing: .13em; text-transform: uppercase;
  padding: 0 1px; color: inherit;
}
/* anchored to the middle of the box, not its floor: the box is 44px for the
   thumb, the rule belongs to the 11.5px word */
.em-hdr__link::after {
  content: ''; position: absolute; left: 0; right: 0; top: calc(50% + 9px); height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: left;
  transition: transform .45s var(--em-e-soft);
}
.em-hdr__link:hover, .em-hdr__link:focus-visible { color: inherit; }
.em-hdr__link:hover::after,
.em-hdr__link:focus-visible::after,
.em-hdr__link[aria-current="page"]::after { transform: scaleX(1); }
.em-hdr__acts { margin-left: auto; display: flex; align-items: center; gap: clamp(10px,1.5vw,22px); }
.em-hdr__util {
  display: flex; align-items: center; gap: 9px; min-height: 44px;
  font-size: 11px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  padding: 9px 6px; color: inherit; transition: opacity var(--em-t) ease;
}
.em-hdr__util:hover { opacity: .65; color: inherit; }
.em-hdr__util svg { width: 13px; height: 13px; display: block; flex: none; }
.em-hdr__div { width: 1px; height: 18px; background: currentColor; opacity: .25; flex: none; }
 /* Superseded. lang.js replaces this <span> with the shared .lang-pick control
    on every page, so these rules style nothing at runtime; they are kept only
    as the no-JS resting appearance of the label the markup still ships. The
    old note here — "this build ships one language" — stopped being true when
    the picker landed: it lists three, and names the two still in translation. */
.em-hdr__lang {
  min-height: 44px; display: flex; align-items: center;
  font-size: 11px; font-weight: 600; letter-spacing: .16em; padding: 9px 4px;
  color: inherit; opacity: .72;
}
.em-hdr__menu {
  display: flex; align-items: center; gap: 9px; min-height: 44px; padding: 9px 4px;
  font-size: 11px; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: inherit; transition: opacity var(--em-t) ease;
}
.em-hdr__menu:hover { opacity: .65; color: inherit; }
.em-hdr__burger { display: block; width: 16px; height: 9px; position: relative; flex: none; }
.em-hdr__burger::before, .em-hdr__burger::after {
  content: ''; position: absolute; left: 0; right: 0; height: 1px; background: currentColor;
  transition: transform var(--em-t) var(--em-e-panel);
}
.em-hdr__burger::before { top: 0; }
.em-hdr__burger::after  { bottom: 0; }
 /* The bar goes light only when the picture is under it — and then it must
    carry its own ground. Relying on the hero's veil was wrong twice: below
    1024 that veil is a bottom-only wash with nothing behind the bar at all,
    and at 1440 its top band has fallen to .10 by 200px while the bar's
    right-hand utilities sit where the left band contributes nothing.

    So `is-over` brings a gradient of its own, full width, strong at the bar
    and gone by its lower edge. Measured against the brightest frame in the
    set: #f5f2ec over rgba(6,6,5,.62) on rgb(249,246,240) is 4.71:1. */
.em-hdr.is-over, .em-hdr.is-over.is-inverted {
  color: var(--em-on-night);
  background: linear-gradient(180deg, rgba(var(--em-rgb-veil), .66) 0%, rgba(var(--em-rgb-veil), .58) 72%, rgba(var(--em-rgb-veil), .42) 100%);
  -webkit-backdrop-filter: none; backdrop-filter: none; border-bottom-color: transparent;
}
/* the fixed lockup sits outside the bar, so it needs its own. Generated
   unconditionally (never gated by content) so opacity can transition it —
   content itself can't animate, so toggling the glow on and off via
   content:none popped it instantly while the ink colour above it was still
   fading, which is the flash that showed as a stray dark patch behind the
   logo once the bar had already cleared. */
.em-brand::before {
  content: ''; position: absolute; left: -22px; right: -22px; top: -26px; bottom: -22px;
  z-index: -1; border-radius: 2px;
  background: radial-gradient(ellipse at 34% 50%, rgba(var(--em-rgb-veil), .64) 0%, rgba(var(--em-rgb-veil), .34) 58%, rgba(var(--em-rgb-veil), 0) 100%);
  opacity: 0;
  transition: opacity var(--em-t-slow) ease;
}
.em-brand.is-over::before {
  opacity: 1;
}
.em-brand { position: fixed; }
.em-brand.is-over { color: var(--em-on-night); }
.em-hdr.is-inverted { color: var(--em-on-night); background: transparent;
  -webkit-backdrop-filter: none; backdrop-filter: none; border-bottom-color: transparent; }

/* ———————————————————————— 6 · Mobile menu ———————————————————————— */

.em-menu { position: fixed; inset: 0; z-index: var(--z-menu); display: flex; flex-direction: column;
  background: var(--em-night); color: var(--em-on-night);
  padding: calc(var(--em-hdr) + 18px) var(--em-gut-wide) calc(28px + env(safe-area-inset-bottom,0px));
  overflow: auto; overscroll-behavior: contain; }
.em-menu[hidden] { display: none; }
.em-menu__list { display: flex; flex-direction: column; gap: 4px; }
.em-menu__link {
  display: block; padding: 14px 0; min-height: 44px;
  font-family: var(--em-display); font-size: 30px; line-height: 1.15;
  color: var(--em-on-night); border-bottom: 1px solid var(--em-line-dark);
  transition: opacity var(--em-t) ease;
}
.em-menu__link:hover { opacity: .65; color: var(--em-on-night); }
.em-menu__acts { margin-top: auto; padding-top: 34px; display: flex; flex-direction: column; gap: 12px; }

/* ———————————————————————— 7 · Page shell ————————————————————————

   MOVED — assets/ds/04-layout.css.
   .em-main · .em-wrap · .em-top and the masthead rhythm · .em-band* ·
   .em-bleed · section[id] scroll margin · [data-em-reveal="media"].        */


/* ———————————————————————— 8 · Breadcrumb ————————————————————————

   MOVED — assets/ds/05-components.css.                                     */


/* ———————————————————— 9–10 · Eyebrow and type ————————————————————

   MOVED — assets/ds/03-typography.css.
   .em-eyebrow* · .em-h1 · .em-h2 · .em-lead · .em-prose · .em-note, plus the
   display / heading / body / label scale the rest of the site now shares.   */


/* ———————————————————————— 11 · Controls ————————————————————————

   MOVED — assets/ds/05-components.css.
   .em-btn* · .em-cta* · [aria-disabled] · the loading and icon-button states. */


/* ———————————————————————— 12 · Photograph ————————————————————————

   MOVED — assets/ds/04-layout.css §5, with two ratios added (3x2, 1x1) and
   --2x1 kept as an alias of --banner for the markup that carries it.       */

/* ————————————————————————— The hero —————————————————————————

   Measured, then redesigned. The first build put the breadcrumb (11px) and an
   eyebrow (11px) over the media behind a three-gradient veil. Rendering all
   fourteen heroes at 1440 and 390, hiding the type and sampling the ground
   beneath each run, 35 of 100 runs failed 4.5:1 — the worst, Grand Polo's
   eyebrow at 390px, measured 1.41:1.

   The cause is not the veil. It is that 11px type cannot be guaranteed over a
   crop nobody controls: at 390px `object-fit:cover` on a 1600x822 render pulls
   a noon sky straight into the lockup, and the veil needed to fix that would
   be dark enough to destroy the photograph — which is the one thing the brief
   says must lead.

   So the type comes off the picture — and as of 2026-09-21, ALL of it, at
   every width. The finding above was that 11px could not be guaranteed over a
   crop nobody controls; the direction now is that nothing needs to be, because
   nothing sits there.

     · The breadcrumb sits ABOVE the hero, on the page ground, at 16.9:1.
     · The lockup sits BELOW the media, on the page ground, at every width.
       Below 1024 that was already true. From 1024 it is true as well: the
       media keeps its own box in flow and the eyebrow, the h1, the sub-line
       and the actions follow it on cream, in ink, at the contrast the page
       ground gives them by construction.
     · The veil is a whisper at every width — the photograph settling into
       the page, not a scrim holding type up.
     · The picture's height is the REMAINDER of the fold, so the heading is
       in view on a 1024x768 laptop as well as on a 27-inch display. The
       arithmetic is in the 1024 block below.

   The component now has no text slot over the media at all, which is the
   enforcement: a future page cannot put a heading on the photograph, because
   there is nowhere for one to go. Markup order was already media-then-lockup,
   so this batch changed no DOM and no page file.

   The measurement paragraph above is kept because it is why. Re-measure if a
   hero image is replaced; the harness that did it is scratchpad/harness/veil.js. */

 /* The night ground belongs to the PICTURE, not to the hero.
    Below 1024 the lockup is a sibling of the media, so a background on the
    hero itself put ink type on a near-black band: the h1 measured 1.05:1, the
    sub 2.62:1 and the eyebrow 3.45:1, identically on all ten pages — and a
    number that does not vary with the photograph is never the photograph. */
.em-hero { position: relative; overflow: hidden; background: transparent;
  /* The fold budget. Declared here so it holds at every width; the 1024
     block below only restates the two numbers that change. See the long
     note there for what each one is and why the reserve holds two lines. */
  --em-hero-above:   calc(104px + 74px + clamp(20px, 3vh, 30px));
  --em-hero-reserve: clamp(132px, 120px + 6vw, 170px);
  /* Below 1024 the fold does not end at the viewport: the mobile dock owns
     the foot of the screen (DESIGN-STANDARDS §9) and a heading behind it is
     a heading below the fold. It comes out of the budget like everything
     else. Zero from 1024, where the dock is gone. */
  --em-hero-dock:    calc(var(--em-dock-height) + env(safe-area-inset-bottom, 0px));
  --em-hero-cap:     560px;
  --em-hero-floor:   170px;
}
/* 4/5 is the portrait art direction, and it stays — but it is a RATIO, not a
   height, and on a small screen a ratio is how a picture eats the fold: at
   768 it made the band 960px tall and put the page's own name a screenful
   below the photograph, and at 375 and 320 the heading was off the fold too.
   So the ratio is capped by the same budget the desktop band uses. The crop
   deepens, `object-fit: cover` keeps it undistorted, and the heading is in
   view on every phone in the ladder. */
.em-hero__media { position: relative; width: 100%; aspect-ratio: 4/5;
  max-height: clamp(var(--em-hero-floor),
                    calc(100svh - var(--em-hero-above) - var(--em-hero-reserve)
                                - var(--em-hero-dock)),
                    var(--em-hero-cap));
  background: var(--em-night); overflow: hidden; }
.em-hero__media > img, .em-hero__media > video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block;
  object-position: var(--em-focal, 50% 50%);
}
/* The hero is where one asset is asked to do the most work, and below 1024 it
   is asked to do the impossible: a 1.949:1 community master covering the 4:5
   box keeps 45% of its width, a 2.7:1 businesses band keeps 32%. The file is
   the same file — only the anchor changes. Set --em-focal-sm on the section
   for the phone and tablet-portrait crop; see assets/ds/04-layout.css, §5. */
@media (max-width: 1023px) {
  .em-hero__media > img, .em-hero__media > video {
    object-position: var(--em-focal-sm, var(--em-focal, 50% 50%));
  }
}
.em-hero__veil { position: absolute; inset: 0; pointer-events: none; }
.em-hero__in { position: relative; z-index: 2; }
.em-hero__foot { padding: clamp(26px,4vw,34px) var(--em-gut) clamp(30px,5vw,40px); }
.em-hero__eyebrow { font-size: 11px; font-weight: 600; letter-spacing: .26em;
  text-transform: uppercase; color: var(--em-text-eyebrow-neutral); }
.em-hero__h1 { font-family: var(--em-display); color: var(--em-ink); margin-top: 13px;
  font-size: clamp(32px,8.5vw,46px); line-height: 1.04; max-width: 11em; text-wrap: balance; }
.em-hero__sub { margin-top: 12px; font-size: 15px; line-height: 1.5; letter-spacing: .01em;
  color: var(--em-ink-body); max-width: 30em; text-wrap: pretty; }
.em-hero__cta { margin-top: 24px; display: flex; gap: 10px; flex-wrap: wrap; }
.em-hero__cta > * { flex: 1 1 auto; }

/* The veil carries no type at any width now, so it is only there to settle
   the picture into the page — a whisper, not a scrim. */
.em-hero__veil {
  background: linear-gradient(0deg, rgba(var(--em-rgb-veil), .14) 0, rgba(var(--em-rgb-veil), 0) 26%);
}

@media (min-width: 1024px) {
  /* ——— THE FOLD IS BUDGETED, NOT STYLED ———

     An interior page answers two questions in its first screen — *where am
     I* and *what is this* — so the picture takes what is LEFT of the fold
     rather than a height of its own. A fixed band is fine at 1920x1080 and
     pushes the heading off a 1024x768 laptop entirely; this cannot, because
     both of the things that must stay visible are subtracted BEFORE the
     media gets its share:

       --em-hero-above    what the row above has already spent: .em-top's
                          104px header clearance, the breadcrumb's own 44px
                          line box, and .em-hero's margin-top. Measured at
                          rest, not assumed: 175px at 1440x900.
       --em-hero-reserve  what must stay in the fold BELOW the picture: the
                          lockup's top padding, the eyebrow, and TWO lines of
                          the h1, plus ~10px so the heading does not sit on
                          the fold's edge.

     Two lines, not one, and that is the whole of the second draft. A
     one-line reserve held on thirteen of the fourteen hero pages and lost
     the second line of "Dubai Polo & Equestrian Club" at 1366, 1280 and
     1024 — a reserve is a guess about the longest string, so it is sized
     for the longest string this build actually has. The sub-line and the
     actions may fall below the fold; the reference pattern lets them, and
     the brief asks for the media, the eyebrow and the heading, not for the
     whole lockup.

     Floored so the band never becomes a stripe, capped so a tall window does
     not hand the photograph the whole screen. */
  .em-hero {
    /* one line of breadcrumb from here; below 1024 it wraps to two, which is
       why the base value above budgets 74px for it and this one 44px. Both
       measured at rest: 175px at 1440x900, 195px at 320x568. */
    --em-hero-above:   calc(104px + 44px + clamp(20px, 3vh, 30px));
    --em-hero-reserve: clamp(174px, 58px + 11.3vw, 226px);
    --em-hero-dock:    0px;
    --em-hero-cap:     620px;
    --em-hero-floor:   300px;
  }
  /* The short variant is the same budget under a lower ceiling: the
     businesses and Delivered pages open on a band, not on a screen. */
  .em-hero--short { --em-hero-cap: 500px; }

  /* From 1024 the ratio goes entirely: the band is the budget, full stop.
     max-height above resolves to the same expression, so it never bites. */
  .em-hero__media {
    position: relative; inset: auto; aspect-ratio: auto;
    height: clamp(var(--em-hero-floor),
                  calc(100svh - var(--em-hero-above) - var(--em-hero-reserve)
                              - var(--em-hero-dock)),
                  var(--em-hero-cap));
  }
  /* The media is full-bleed; the lockup is in the content column, on the
     same left edge as everything that follows it down the page. */
  .em-hero__in { max-width: var(--em-max); margin: 0 auto;
    padding-inline: var(--em-gut); }
  .em-hero__foot { padding: clamp(30px,3.2vw,42px) 0 clamp(34px,4vw,52px);
    max-width: min(760px, 76%); }
  /* Ink, not white: the lockup is on cream from here, and the colours it
     inherits from the base rules above are already the right ones. Only the
     display sizes step up. */
  .em-hero__h1 { margin-top: 15px; font-size: clamp(38px,4.4vw,64px); }
  .em-hero__sub { margin-top: 14px; }
  .em-hero__cta { margin-top: 26px; gap: 12px; }
  .em-hero__cta > * { flex: 0 0 auto; }
}

/* ———————————————————————— 13 · Film band ———————————————————————— */

.em-film { position: relative; overflow: hidden; background: var(--em-well);
  border-radius: var(--em-r); aspect-ratio: 16/9; }
.em-film > video, .em-film > img { position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block; }
/* Never upscale a 480-line master across a 1440px page. */
.em-film--sd { max-width: 1000px; margin-inline: auto; }
.em-film--296 { aspect-ratio: 1422/480; }
.em-film__play {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
  width: 76px; height: 76px; border-radius: 50%; display: grid; place-items: center;
  /* .70, measured. Sampled behind every film poster in the set, the brightest
     ground under this control is Emaar South's at rgb(244,240,237); a white
     glyph needs the plate at .70 to clear 4.5:1 there. blur(8px) spreads
     bright pixels without darkening them — the plate is the whole defence. */
  background: rgba(var(--em-rgb-night), .70); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border: 1px solid rgba(var(--em-rgb-on-inverse), .7); color: var(--p-brand-white);
  transition: background var(--em-t) ease, transform var(--em-t) var(--em-e-panel);
}
.em-film__play:hover { background: rgba(var(--em-rgb-night), .64); color: var(--p-brand-white);
  transform: translate(-50%,-50%) scale(1.06); }
.em-film__play:focus-visible { outline: 2px solid var(--p-brand-white); outline-offset: 3px; }
.em-film__play svg { width: 20px; height: 20px; display: block; }
.em-film.is-playing .em-film__play { opacity: 0; }
.em-film.is-playing:hover .em-film__play,
.em-film.is-playing .em-film__play:focus-visible { opacity: 1; }

/* ———————————————————————— 14 · Card ———————————————————————— */

.em-grid { display: grid; gap: clamp(20px,2.4vw,30px); }
.em-grid--cards { grid-template-columns: repeat(auto-fill, minmax(min(330px,100%),1fr)); }
.em-grid--wide  { grid-template-columns: repeat(auto-fill, minmax(min(420px,100%),1fr)); }
.em-grid--three { grid-template-columns: repeat(auto-fill, minmax(min(300px,100%),1fr)); }

.em-card {
  position: relative; background: var(--em-surface); border: 1px solid var(--em-line);
  border-radius: var(--em-r); overflow: hidden; display: flex; flex-direction: column;
  color: var(--em-ink);
  transition: box-shadow var(--em-t-slow) ease, border-color var(--em-t-slow) ease,
              transform var(--em-t-slow) ease;
}
.em-card:hover { box-shadow: var(--em-sh-card); border-color: var(--em-line-hover);
  transform: translateY(-3px); color: var(--em-ink); }
.em-card__body { padding: clamp(20px,2.2vw,26px); display: flex; flex-direction: column; flex: 1; }
.em-card__kicker { font-size: 10.5px; font-weight: 600; letter-spacing: .24em;
  line-height: 1.2; text-transform: uppercase; color: var(--em-text-eyebrow-neutral); }
.em-card__name { font-family: var(--em-display); font-size: clamp(22px,2.2vw,27px);
  line-height: 1.1; margin-top: 7px; }
/* A 30px heading link is not a 44px target. An inset pseudo-element grows the
   hit box to 44px and changes no layout at all, so the card's vertical rhythm
   is untouched. */
.em-card__name a { position: relative; display: inline-block; }
.em-card__name a::after { content: ''; position: absolute; inset: -10px -6px; }
/* A grid row stretches every card to the tallest in it, but the words inside
   stop where they stop — so three cards whose summaries run to three, three
   and two lines put their price and their buttons on three different lines.
   The summary takes the slack: it is the one elastic thing in the card, and
   growing it bottom-aligns the price row and the action row together, each
   keeping its own spacing. Where a card carries no summary there is nothing
   to stretch, so the foot takes the slack instead — as padding, not margin,
   because an auto margin resolves to zero once the card is full and would
   take the gap with it. */
.em-card__meta { font-size: 14px; line-height: 1.45; color: var(--em-ink-body); margin-top: 6px;
  flex: 1 1 auto; }
.em-card__body > .em-card__acts:last-child,
.em-card__body > .em-card__foot:last-child { margin-top: auto; padding-top: 18px; }
.em-card__row { display: flex; align-items: baseline; justify-content: space-between;
  gap: 14px; margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--em-line); }
.em-card__price { font-size: 15.5px; font-weight: 600; white-space: nowrap; }
.em-card__cap { font-size: 12px; color: var(--em-ink-mute); white-space: nowrap; }
.em-card__acts { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.em-card__acts > * { flex: 1 1 128px; }
.em-card__acts > .em-plans-btn { flex: 1 1 100%; }
.em-card__foot { margin-top: 18px; }

/* The image zoom lives on the <img>, so it fires only over the picture. */
.em-card .em-shot > img,
.em-figure .em-shot > img { transition: transform var(--em-t-image) var(--em-e-image),
                                        filter var(--em-t-image) ease; }
.em-card:hover .em-shot > img { transform: scale(1.05); filter: brightness(1.06); }

/* A whole-card link. The CTA inside it is a <span>, never a nested <a>. */
a.em-card { display: flex; }
a.em-card:hover .em-card__name { color: var(--em-ink); }

.em-badge {
  position: absolute; left: 14px; top: 14px; z-index: 2;
  display: flex; align-items: center; gap: 8px;
  /* --em-badge is rgba(10,10,10,.55). Verified, not assumed: sampled behind
     every card image in the set the brightest ground is rgb(249,230,205), and
     #f8f8f8 over the plate on that ground is 4.78:1. Do not thin it. */
  background: var(--em-badge); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  color: var(--em-text-inverse); font-size: 10px; font-weight: 600; letter-spacing: .20em;
  text-transform: uppercase; white-space: nowrap; padding: 7px 12px; border-radius: var(--em-r);
}
.em-badge__dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }
.em-badge__dot--soon    { background: transparent; border: 1px solid var(--em-sand); }
.em-badge__dot--new     { background: var(--em-accent-dark); }
.em-badge__dot--selling { background: var(--em-sand); }

/* ———————————————————————— 15 · Editorial figure ———————————————————————— */

/* The alternating image / text composition. The picture is one column, the
   words the other; the words never sit on the picture. */
/* start, not center: a 180px paragraph centred against a 745px portrait
   opens ~280px of dead ground above and below it. */
.em-figure { display: grid; gap: clamp(24px,3vw,48px); align-items: start;
  grid-template-columns: 1fr; }
.em-figure__body { display: flex; flex-direction: column; align-items: flex-start; }
.em-figure__body > * + * { margin-top: 16px; }
.em-figure__body > .em-h2 { margin-top: 12px; }

/* The words inside a control that are worth their width at desktop and not at
   375. A button is not a paragraph, so `.em-btn` and its siblings are
   `white-space: nowrap` by design (assets/ds/05-components.css) — which means
   a long label does not wrap: it pushes the page sideways, or the band around
   it clips the label's tail. The longest community this build names, "The
   Heights Country Club and Wellness", makes "Explore …" 389px and "Search in
   …" 384px in a 335px column. The heading directly above each of those buttons
   has already said the name and the button's own aria-label still carries it in
   full, so what stands down below 600 is repetition, never information.

   It goes INSIDE the button's own label span, never beside it: `.em-btn` is a
   flex box with a 10px gap for its icon, so a second child would be spaced off
   the verb like an icon rather than read as the rest of the sentence. */
.em-wide { display: none; }
@media (min-width: 600px) { .em-wide { display: inline; } }

/* ———————————————————————— 16 · Ledgers ———————————————————————— */

.em-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(210px,100%),1fr));
  gap: clamp(20px,2.4vw,32px);
  padding-top: 26px; border-top: 1px solid var(--em-line-rule);
}
/* A cell is mark, figure, label — ranged left, so the mark sets the left edge
   the two lines already sit on rather than floating over them. */
.em-stat { display: flex; flex-direction: column; align-items: flex-start; }
/* The metal is allowed on an icon (never on the figure above it, which is the
   heading here). 26px at 1.1 keeps the line hairline-thin at the size the
   eyebrow rules are drawn, so the marks read as engraving, not as UI. */
.em-stat__m { display: block; width: 26px; height: 26px; margin-bottom: 14px;
  color: var(--em-accent); overflow: visible; }
.em-stat__v { font-family: var(--em-display); font-size: clamp(24px,2.5vw,32px);
  line-height: 1.05; text-wrap: balance; }
.em-stat__k { font-size: 12.5px; line-height: 1.45; color: var(--em-ink-mute); margin-top: 8px; }

@media (max-width: 640px) {
  /* auto-fit's 210px minimum only ever seats one column at phone widths, so
     the sole track stretches full-bleed and strands the ranged-left cell at
     its own edge — the rest of the row reads as a stray margin. Two fixed
     tracks, the width the poi grid already uses at this size, fill it instead. */
  .em-stats { grid-template-columns: repeat(2, 1fr); gap: 28px 20px; }
}

.em-poi { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(168px,100%),1fr));
  gap: clamp(20px,2.4vw,30px); padding-top: 26px; border-top: 1px solid var(--em-line-rule); }
/* A cell is mark, figure, label — the ledger's own arrangement, ranged left,
   so the mark sets the left edge the two lines already sit on. Before it, every
   row here was a bare number over a bare line of tracking, and five of them in
   a row read as a table of contents rather than a map of the place. */
.em-poi li { display: flex; flex-direction: column; align-items: flex-start; }
/* The metal is allowed on an icon. 24px at stroke 1.1 keeps the line as fine as
   the eyebrow rules, so the marks read as engraving and not as UI. */
.em-poi__m { display: block; width: 24px; height: 24px; margin-bottom: 13px;
  color: var(--em-accent); overflow: visible; }
.em-poi__v { font-family: var(--em-display); font-size: clamp(24px,2.2vw,30px);
  line-height: 1; color: var(--em-accent); }
.em-poi__k { font-size: 11px; font-weight: 600; letter-spacing: .12em; line-height: 1.45;
  text-transform: uppercase; color: var(--em-ink-eyebrow); margin-top: 10px; max-width: 16em; }

@media (max-width: 640px) {
  /* The same trap the ledger above had, and for the same reason: auto-fit's
     168px minimum plus the gap cannot seat two tracks in a 350px content box,
     so the sole track stretches to 350px while the label's own 16em measure
     stops at 176px — half of every row is dead ground. Two fixed tracks put
     the cell and its content back on the same width. */
  .em-poi { grid-template-columns: repeat(2, 1fr); gap: 26px 18px; }
  .em-poi__k { max-width: none; }
}

.em-amen { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(200px,100%),1fr));
  gap: 0 clamp(20px,2.4vw,30px); padding-top: 8px; }
.em-amen li { display: flex; align-items: baseline; gap: 12px; padding: 13px 0;
  border-bottom: 1px solid var(--em-line-faint); font-size: 14.5px; color: var(--em-ink-body); }
.em-amen li::before { content: ''; width: 5px; height: 5px; flex: none; border-radius: 50%;
  background: var(--em-accent); transform: translateY(-3px); }

/* A marked row. The mark REPLACES the dot rather than joining it — two markers
   on one row is two answers to the same question — and it is the only thing
   that decides the swap, so the dot survives wherever amenItem() could not
   place a label and on the two deliberately denser lists (the atlas card's
   facts and the release page's texture row) that carry no marks at all.
   20px against a 14.5px label: smaller than the ledger's 26px, because here
   the mark sits BESIDE the words at their own size rather than above them.
   The row's baseline alignment has to go with it — an svg baselines on its
   bottom edge, which would hang a 20px mark below a one-line label — so a
   marked row ranges its mark and its first line from the top instead. */
.em-amen li:has(> .em-amen__m) { align-items: flex-start; }
.em-amen li:has(> .em-amen__m)::before { content: none; }
.em-amen__m { display: block; width: 20px; height: 20px; flex: none; margin-top: 1px;
  color: var(--em-accent); overflow: visible; }

/* The specification ladder. A <dl>, not a table: these are label/value pairs,
   not tabular data, and no cell is a heading. */
.em-specs { }
.em-specs__row { display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; padding: 13px 2px; border-bottom: 1px solid var(--em-line-faint); }
.em-specs__row:last-child { border-bottom: 0; }
.em-specs dt { display: inline-flex; align-items: center; gap: 8px;
  font-size: 9.5px; font-weight: 600; letter-spacing: .20em; line-height: 1.3;
  text-transform: uppercase; color: var(--em-ink-mute); }
.em-specs dd { font-size: 13.5px; line-height: 1.4; text-align: right; color: var(--em-ink); }
.em-specs dd.is-price { font-size: 15px; font-weight: 600; }
.em-specs dd.is-empty { color: var(--em-ink-mute); }
/* The ladder's own mark: the same engraved metal as the ledger and the poi
   grid, at a scale that sits inline with a 9.5px eyebrow rather than stacked
   above a display figure — see .em-stat__m and .em-poi__m for the pattern. */
.em-specs__m { display: block; width: 15px; height: 15px; flex: none;
  color: var(--em-accent); overflow: visible; }

/* ———————————————————————— 17 · Locator map ———————————————————————— */

.em-map { background: var(--em-white); border: 1px solid var(--em-line);
  border-radius: var(--em-r); padding: clamp(14px,2vw,22px); }
.em-map img { display: block; width: 100%; height: auto; }

/* ———————————————————————— 18 · FAQ ———————————————————————— */

.em-faq { border-top: 1px solid var(--em-line-bar); }
.em-faq__item { border-bottom: 1px solid var(--em-line-bar); }
.em-faq__q {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  min-height: 56px; padding: 17px 2px; cursor: pointer; list-style: none;
  font-size: 14px; font-weight: 600; letter-spacing: .02em; line-height: 1.45;
  color: var(--em-ink);
}
.em-faq__q::-webkit-details-marker { display: none; }
.em-faq__q::after {
  content: ''; width: 9px; height: 9px; flex: none; margin-right: 3px;
  border-right: 1px solid var(--em-ink-2); border-bottom: 1px solid var(--em-ink-2);
  transform: rotate(45deg) translateY(-2px);
  transition: transform var(--em-t) var(--em-e-panel);
}
.em-faq__item[open] > .em-faq__q::after { transform: rotate(-135deg) translateY(-2px); }
.em-faq__q:focus-visible { outline: 2px solid var(--em-ink); outline-offset: -2px; }
.em-faq__a { padding: 0 2px 22px; max-width: var(--em-measure); }
.em-faq__a p { font-size: 14.5px; line-height: 1.62; color: var(--em-ink-body); }
.em-faq__a p + p { margin-top: 12px; }

/* ———————————————————————— 19 · Placeholder ———————————————————————— */

/* Everything EMAAR has not supplied is drawn as a slot awaiting content, and
   labelled as such. Nothing is ever invented to fill a composition. */
.em-ph {
  display: grid; place-items: center; text-align: center;
  background: var(--em-sunk); border: 1px dashed var(--em-line-ctl);
  border-radius: var(--em-r); padding: clamp(24px,4vw,40px); color: var(--em-ink-eyebrow);
}
.em-ph__t { font-size: 10px; font-weight: 600; letter-spacing: .26em; text-transform: uppercase; }
.em-ph__b { margin-top: 10px; font-size: 13.5px; line-height: 1.55;
  color: var(--em-ink-body); max-width: 34em; }
.em-ph--16x10 { aspect-ratio: 16/10; }
.em-ph--16x9  { aspect-ratio: 16/9; }
.em-ph--4x3   { aspect-ratio: 4/3; }

.em-flag {
  display: inline-flex; align-items: center; gap: 9px; padding: 9px 14px;
  background: var(--em-sunk); border: 1px dashed var(--em-line-ctl); border-radius: var(--em-r);
  font-size: 10px; font-weight: 600; letter-spacing: .20em; text-transform: uppercase;
  color: var(--em-ink-eyebrow);
}

/* ———————————————————— 20 · Floor plans — trigger ———————————————————— */

.em-plans-btn { position: relative; }

/* ———————— 21 · Floor plans — drawer (>=1024) / sheet (<1024) ————————
   ONE component, two presentations. The markup is identical at both widths;
   only the plate's geometry and its entrance change, so there is no second
   implementation to drift. */

.em-plans { position: fixed; inset: 0; z-index: var(--z-dock); display: flex; }
.em-plans[hidden] { display: none; }
.em-plans__scrim { position: absolute; inset: 0; background: var(--em-scrim);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
.em-plans__panel {
  position: relative; margin-left: auto; display: flex; flex-direction: column;
  width: 100%; max-height: 100%;
  background: var(--em-surface-warm); color: var(--em-ink);
  box-shadow: var(--em-sh-panel);
}
.em-plans__head {
  flex: none; display: flex; align-items: flex-start; gap: 18px;
  padding: clamp(22px,3vw,30px) clamp(20px,3vw,34px) 20px;
  border-bottom: 1px solid var(--em-line-bar);
}
.em-plans__eyebrow { font-size: 10px; font-weight: 600; letter-spacing: .26em;
  text-transform: uppercase; color: var(--em-text-eyebrow-neutral); }
.em-plans__title { font-family: var(--em-display); font-size: clamp(24px,2.6vw,30px);
  line-height: 1.1; margin-top: 9px; }
.em-plans__sub { font-size: 13.5px; color: var(--em-ink-body); margin-top: 8px; max-width: 34em; }
.em-plans__close {
  margin-left: auto; flex: none; width: 44px; height: 44px; display: grid; place-items: center;
  border: 1px solid rgba(var(--em-rgb-ink), .20); border-radius: 50%;
  transition: border-color var(--em-t-mid) ease, background var(--em-t-mid) ease;
}
.em-plans__close:hover { border-color: var(--em-ink); background: rgba(var(--em-rgb-ink), .06); }
.em-plans__close svg { width: 13px; height: 13px; display: block; }
.em-plans__body { flex: 1 1 auto; overflow: auto; overscroll-behavior: contain;
  padding: clamp(20px,3vw,28px) clamp(20px,3vw,34px) clamp(24px,4vw,36px); }
.em-plans__list { display: grid; gap: 14px; }
.em-plans__foot { flex: none; padding: 18px clamp(20px,3vw,34px)
  calc(18px + env(safe-area-inset-bottom,0px));
  border-top: 1px solid var(--em-line-bar); display: flex; gap: 12px; flex-wrap: wrap; }
.em-plans__foot > * { flex: 1 1 160px; }

.em-plan {
  display: grid; gap: 16px; align-items: start;
  grid-template-columns: 96px 1fr;
  padding: 16px; border: 1px solid var(--em-line); border-radius: var(--em-r);
  background: var(--em-surface); transition: border-color var(--em-t) ease;
}
.em-plan:hover { border-color: var(--em-line-hover); }
.em-plan__thumb { grid-row: span 2; }
.em-plan__ph { aspect-ratio: 3/4; display: grid; place-items: center;
  background: var(--em-sunk); border: 1px dashed var(--em-line-ctl); border-radius: var(--em-r); }
.em-plan__ph svg { width: 30px; height: 30px; color: var(--em-ink-mute); }
.em-plan__t { font-family: var(--em-display); font-size: 21px; line-height: 1.15; }
.em-plan__k { font-size: 9.5px; font-weight: 600; letter-spacing: .20em;
  text-transform: uppercase; color: var(--em-ink-mute); }
.em-plan__meta { font-size: 13px; line-height: 1.5; color: var(--em-ink-body); margin-top: 8px; }
.em-plan__acts { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
.em-plan__acts > * { flex: 1 1 128px; }
.em-plan__doc { display: flex; align-items: center; gap: 9px; margin-top: 12px;
  font-size: 12px; color: var(--em-ink-mute); }
.em-plan__doc svg { width: 13px; height: 15px; flex: none; }

/* The project page carries the same plan rows inline, in its own section. */
.em-plans-inline .em-plan { background: var(--em-surface); }

/* ———————————————————————— 22 · Enquiry modal ———————————————————————— */

.em-modal { position: fixed; inset: 0; z-index: var(--z-modal); display: flex;
  align-items: center; justify-content: center; padding: 18px; }
.em-modal[hidden] { display: none; }
.em-modal__scrim { position: absolute; inset: 0; background: var(--em-scrim);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px); }
.em-modal__card { position: relative; width: min(540px,100%);
  max-height: calc(100vh - 36px); overflow: auto;
  background: var(--em-surface-warm); border-radius: var(--em-r);
  padding: clamp(28px,4vw,46px); box-shadow: var(--em-sh-modal); }
.em-modal__top { display: flex; align-items: flex-start; gap: 18px; }
.em-modal__title { font-family: var(--em-display); font-size: clamp(26px,3vw,34px); line-height: 1.05; }
.em-modal__sub { font-size: 14.5px; line-height: 1.55; color: var(--em-ink-body);
  margin-top: 10px; max-width: 36em; }
.em-modal__close { margin-left: auto; flex: none; width: 44px; height: 44px;
  display: grid; place-items: center; border: 1px solid rgba(var(--em-rgb-ink), .20); border-radius: 50%;
  transition: border-color var(--em-t-mid) ease, background var(--em-t-mid) ease; }
.em-modal__close:hover { border-color: var(--em-ink); background: rgba(var(--em-rgb-ink), .06); }
.em-modal__close svg { width: 13px; height: 13px; display: block; }
/* --- The form: MOVED to assets/ds/05-components.css §5, where it is the
       site's one form system rather than this modal's private styling. The
       modal keeps only the air above it, which is a modal decision. --- */
.em-form { margin-top: 26px; }

.em-form__legal { font-size: 12.5px; line-height: 1.5; color: var(--em-ink-mute); }
.em-form__legal a { color: var(--em-ink-2); text-decoration: underline; }
.em-form__foot { font-size: 12px; color: var(--em-ink-mute); text-align: center; }
.em-sent__mark { width: 52px; height: 52px; display: grid; place-items: center;
  border: 1px solid var(--em-accent); border-radius: 50%; color: var(--em-accent); }
.em-sent__mark svg { width: 18px; height: 18px; display: block; }
.em-sent__t { font-family: var(--em-display); font-size: 26px; line-height: 1.1; margin-top: 20px; }
.em-sent__lead { font-size: 14.5px; line-height: 1.55; color: var(--em-ink-body);
  margin-top: 10px; max-width: 40em; }
.em-sent__steps { margin-top: 24px; display: flex; flex-direction: column; gap: 14px; }
.em-sent__step { display: flex; gap: 16px; align-items: baseline; }
.em-sent__n { font-size: 11px; font-weight: 600; letter-spacing: .20em;
  color: var(--em-accent); flex: none; }
.em-sent__s { font-size: 14.5px; line-height: 1.5; }

/* ———————————————————————— 23 · Action ledge ———————————————————————— */

/* A bottom-sticky bar is pulled up over the content behind it, so it must
   draw its own ground: the plate plus the top hairline IS that ground. */
.em-ledge {
  position: sticky; bottom: 0; z-index: var(--z-ledge); display: flex; gap: 10px;
  padding: 13px var(--em-gut) calc(13px + env(safe-area-inset-bottom,0px));
  background: var(--em-ledge);
  -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px);
  border-top: 1px solid var(--em-line-dark);
  box-shadow: 0 -22px 60px rgba(0,0,0,.28);
}
.em-ledge > * { flex: 1 1 0; min-width: 0; }
/* AN AUTHOR display DEFEATS [hidden]. The ledge is display:flex above, so the
   `hidden` attribute the three shells ship it with does nothing: on every page
   whose renderer does not fill it, the empty bar still lays out — 27px of the
   night plate stuck across the foot of the viewport. Found on
   emaar-iconic-creations.html and emaar-communities-v2.html, where the ledge is
   raised at load because those pages have no hero for initHeroHeader to wait
   for. Matches the [hidden] rules this file already carries for the menu, the
   plans drawer, the modal and the lightbox. */
.em-ledge[hidden] { display: none; }
.em-ledge .em-btn { background: var(--em-on-night); color: var(--em-bg-inverse); border-color: var(--em-on-night); }
.em-ledge .em-btn:hover { background: var(--p-brand-white); color: var(--em-bg-inverse); }
.em-ledge .em-btn-h { color: var(--em-on-night); border-color: var(--em-line-dark-2); }
.em-ledge .em-btn-h:hover { border-color: var(--em-on-night); background: rgba(128,128,128,.14);
  color: var(--em-on-night); }

/* ———————————————————————— 24 · Closing band + footer ———————————————— */

/* The closing band is the page's LAST LAYER BEFORE THE FOOTER, and for most
   of this build it was --em-night (#0a0a0a) sitting directly on the footer's
   own #050505. Those two measure 1.03:1 against each other: not a transition
   at all, but one continuous black slab about five hundred pixels tall that
   swallowed the footer into the page and ended the experience on a void.

   The fix is the ground, not the darkness. Sand is the house's own "change
   of paper" band — already carrying "Explore more" on all twenty-eight
   destination pages — so the tail now steps cream (#f6f2ea) → sand
   (#e7dcca) → footer (#050505): 1.21:1 into the band, 15.03:1 out of it.
   The reader crosses one soft edge and one decisive one, in that order, and
   the footer arrives as a deliberate final layer instead of as more of the
   same dark.

   The bottom padding is the LARGER of the two on purpose. The band's job at
   its foot is to hand over, and a hand-over needs room on the near side of
   the edge. */
.em-close { background: var(--em-sand-band); color: var(--em-ink);
  border-top: 1px solid rgba(var(--em-rgb-ink), .12); }
.em-close__in { max-width: var(--em-max-wide); margin: 0 auto;
  padding: clamp(64px,7vw,96px) var(--em-gut-wide) clamp(78px,8.5vw,116px); }
.em-close__acts { margin-top: 36px; display: flex; gap: 16px; flex-wrap: wrap; }
.em-foot { border-top: 1px solid var(--em-line-dark); }
.em-foot__in { max-width: var(--em-max-wide); margin: 0 auto;
  padding: 34px var(--em-gut-wide) calc(34px + env(safe-area-inset-bottom,0px));
  display: flex; align-items: center; gap: 18px 34px; flex-wrap: wrap; }
.em-foot__mark { display: flex; align-items: flex-start; font-size: 17px;
  color: var(--em-on-night); line-height: 0; }
.em-foot__mark svg { height: 1em; width: auto; display: block; fill: currentColor; }
.em-foot__mark svg + svg { margin-left: .0184em; }
.em-foot__mark svg:nth-child(2) { margin-left: .0497em; }
.em-foot__mark svg:nth-child(4) { margin-left: .0156em; }
.em-foot__mark svg:nth-child(5) { margin-left: .0288em; }
.em-foot__c { font-size: 12.5px; color: var(--em-ink-caption); }
.em-foot__links { margin-left: auto; display: flex; align-items: center;
  gap: 10px 26px; flex-wrap: wrap; }
.em-foot__links a { font-size: 12.5px; color: var(--em-on-night-2); min-height: 44px;
  display: inline-flex; align-items: center; transition: color var(--em-t) ease; }
.em-foot__links a:hover { color: var(--em-on-night); }
.em-foot__links a.is-caps { font-size: 11px; font-weight: 600; letter-spacing: .16em;
  text-transform: uppercase; color: var(--em-ink-caption); gap: 8px; }
.em-foot__links a.is-caps:hover { color: var(--em-on-night); }

/* ===========================================================================
   25 · Motion

   ONE rule governs this whole section: the motion is DECLARED INSIDE the
   negative query. A `@media (prefers-reduced-motion: reduce) { animation:none }`
   block is specificity (0,1,0) and a media query adds no specificity — an
   override written to cancel motion loses to any base rule of equal or higher
   weight, and the animation keeps running. Declaring the motion only where it
   is wanted means that under `reduce` there is nothing to override.

   `not all and (…: reduce)` rather than `(…: no-preference)` so a browser that
   has never heard of the feature still gets the motion instead of losing it.
   =========================================================================== */

@media not all and (prefers-reduced-motion: reduce) {

  /* --- the scroll reveal ---------------------------------------------------
     MOVED. [data-em-reveal], [data-em-stagger], .em-armed, .is-in and the
     .em-in-* masthead cascade are declared in motion.css and driven by
     motion.js — one stylesheet and one script for the whole site, rather than
     one declaration here and two copies of the same observer in places-ui.js
     and about.js. Nothing about the markup changed: the hooks are the same
     hooks, so a band written before that move reveals like a band written
     after it.

     A page that links places.css also links motion.css, immediately after.
     If it does not, nothing is ever armed and every band renders plainly
     visible — which is the fail-safe this system has always had. */

  /* --- the shared keyframes ----------------------------------------------- */
  @keyframes emItem { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
  @keyframes emFade { from { opacity: 0; } to { opacity: 1; } }
  @keyframes emMenuIn { from { opacity: 0; transform: translateY(-10px); filter: blur(5px); }
                        to { opacity: 1; transform: none; filter: none; } }
  @keyframes emSheet { from { transform: translateY(100%); } to { transform: none; } }
  @keyframes emDrawer { from { opacity: .3; transform: translateX(100%); } to { opacity: 1; transform: none; } }

  .em-modal__scrim, .em-plans__scrim { animation: emFade var(--em-t-mid) ease both; }
  /* `backwards`, not `both`: emMenuIn ends on a filter, and a filling
     animation keeps that filter applied for ever. An element with a filter is
     a stacking context AND the containing block for every fixed descendant
     under it — which is how a dropdown ends up trapped inside the card that
     opened it. `backwards` holds the from-state through the delay and then
     hands the element back to its own styles, which is all this needed. */
  .em-modal__card  { animation: emMenuIn .45s var(--em-e-panel) backwards; }
  .em-menu         { animation: emFade var(--em-t) ease both; }
  .em-plans__panel { animation: emSheet .42s var(--em-e-panel) both; }
  .em-menu__link   { animation: emItem .5s var(--em-e-soft) both;
                     animation-delay: calc(80ms + var(--i,0) * 60ms); }

  /* the card image zoom is motion too, and must stop under `reduce` */
  .em-card .em-shot > img, .em-figure .em-shot > img {
    transition: transform var(--em-t-image) var(--em-e-image), filter var(--em-t-image) ease;
  }
}

@media (min-width: 1024px) {
  @media not all and (prefers-reduced-motion: reduce) {
    .em-plans__panel { animation: emDrawer .5s var(--em-e-panel) both; }
  }
}

/* Under `reduce` the image transition must not merely be short — it must not
   exist. Declared here so it cancels the shorthand above by source order. */
@media (prefers-reduced-motion: reduce) {
  .em-card .em-shot > img, .em-figure .em-shot > img { transition: none; }
  .em-card:hover .em-shot > img { transform: none; filter: none; }
  html { scroll-behavior: auto; }
}

/* ===========================================================================
   26 · Breakpoints

   Three, all min-width, each doing one job. Every block below sits AFTER the
   rules it modifies — a media query adds no specificity, so an override
   written above its base rule loses.

   Card grids need no breakpoint at all: repeat(auto-fill, minmax(min(N,100%),1fr))
   handles every width, and the min() floor is what stops a 330px track
   overflowing a 320px screen.
   =========================================================================== */

/* --- the floor-plan surface: a bottom sheet by default --------------------- */
.em-plans__panel {
  margin-left: 0; margin-top: auto;
  max-height: min(86vh, 100%); border-radius: 10px 10px 0 0;
}
.em-plans__head { border-top-left-radius: 10px; border-top-right-radius: 10px; }
/* the grab rail, a sheet affordance and nothing else */
.em-plans__panel::before {
  content: ''; position: absolute; left: 50%; top: 9px; width: 42px; height: 4px;
  transform: translateX(-50%); border-radius: 2px; background: rgba(var(--em-rgb-ink), .18);
}

@media (min-width: 768px) {
  .em-figure--split { grid-template-columns: 1fr 1fr; }
  .em-plan { grid-template-columns: 120px 1fr; }
}

@media (min-width: 1024px) {
  .em-hdr__nav { display: flex; }
  .em-hdr__menu { display: none; }
  .em-ledge { display: none; }

  /* the sheet becomes a right-hand drawer, hung off the header's lower edge */
  .em-plans__panel {
    margin-left: auto; margin-top: 0;
    width: clamp(430px, 38vw, 580px);
    height: 100%; max-height: 100%; border-radius: 0;
  }
  .em-plans__head { border-radius: 0; }
  .em-plans__panel::before { content: none; }

  .em-figure--split { grid-template-columns: 1.08fr 1fr; gap: clamp(32px,4vw,68px); }
  .em-figure--split.is-flipped .em-figure__media { order: 2; }
  .em-hero__in { padding-left: var(--em-gut); padding-right: var(--em-gut); }
}

@media (max-width: 1199px) {
  .em-hdr__cta, .em-hdr__wa, .em-hdr__lang { display: none; }
}

@media (max-width: 1023px) {
  .em-hdr__acts { gap: 8px; }
}
@media (max-width: 519px) {
  /* at the narrowest header content (spacer + search icon + divider + lang
     picker + menu) the row's intrinsic width sat 0.336px over the space
     available inside .em-hdr's own padding — a fit so tight that ordinary
     cross-engine text-metric variance (not just a longer label) was enough
     to tip it into real horizontal overflow. Trimmed here rather than in
     lang.css, which seats three different headers and must stay untouched. */
  .em-hdr__acts { gap: 6px; }
}

/* Short viewports: the flex column above already trims the band on its own —
   at 1280x720 it hands the picture what the lockup does not need. What it
   cannot do is go below the media's floor, and under ~640px of height that
   floor is what would push the heading off the screen. So the FLOOR comes
   down here: the picture is allowed to become a band rather than the heading
   being allowed to leave. Scoped to 1024+ because below it the hero is not a
   flex column and the property is not declared. */
@media (min-width: 1024px) and (max-height: 720px) {
  .em-hero { --em-hero-floor: 210px; }
}

/* Print: the ledge, the header and every interactive surface come off. */
@media print {
  .em-hdr, .em-ledge, .em-skip, .em-menu, .em-plans, .em-modal, .em-brand { display: none !important; }
  .em-close { background: var(--p-brand-white); color: var(--p-brand-black); }
  .em-hero__media { height: auto; max-height: none; aspect-ratio: 16/9; }
}

/* ———————————————————————— 27 · Gallery lightbox ———————————————————————— */

.em-lb { position: fixed; inset: 0; z-index: var(--z-lightbox); display: grid; place-items: center;
  padding: clamp(14px,4vw,56px); }
.em-lb[hidden] { display: none; }
.em-lb__scrim { position: absolute; inset: 0; background: rgba(6,6,6,.92); }
.em-lb__fig { position: relative; margin: 0; max-width: min(1280px, 100%); max-height: 100%;
  display: flex; flex-direction: column; gap: 14px; }
.em-lb__fig img { display: block; max-width: 100%; max-height: calc(100vh - 170px);
  width: auto; height: auto; object-fit: contain; border-radius: var(--em-r); background: var(--em-night); }
.em-lb__cap { font-size: 12.5px; line-height: 1.5; color: var(--em-on-night-2); text-align: center; }
.em-lb__nav, .em-lb__close {
  position: absolute; z-index: 2; width: 52px; height: 52px; display: grid; place-items: center;
  border-radius: 50%; color: var(--p-brand-white); background: rgba(var(--em-rgb-white), .08);
  border: 1px solid rgba(var(--em-rgb-on-inverse), .34);
  transition: background var(--em-t) ease, border-color var(--em-t) ease;
}
.em-lb__nav:hover, .em-lb__close:hover { background: rgba(var(--em-rgb-white), .18); border-color: var(--p-brand-white); color: var(--p-brand-white); }
.em-lb__nav:focus-visible, .em-lb__close:focus-visible { outline: 2px solid var(--p-brand-white); outline-offset: 3px; }
.em-lb__nav svg, .em-lb__close svg { width: 15px; height: 15px; display: block; }
.em-lb__nav--prev { left: clamp(10px,2vw,28px); top: 50%; transform: translateY(-50%); }
.em-lb__nav--next { right: clamp(10px,2vw,28px); top: 50%; transform: translateY(-50%); }
.em-lb__close { right: clamp(10px,2vw,28px); top: clamp(10px,2vw,28px); }
.em-lb__count { position: absolute; left: 50%; bottom: clamp(10px,2vw,22px); transform: translateX(-50%);
  font-size: 11px; font-weight: 600; letter-spacing: .20em; color: var(--em-on-night-2); }

/* a button that exists only to make a picture operable — it must add nothing */
.em-lightbox-open { display: block; width: 100%; padding: 0; border: 0; background: none;
  cursor: zoom-in; border-radius: var(--em-r); }
.em-lightbox-open:focus-visible { outline: 2px solid var(--em-ink); outline-offset: 3px; }
.em-lightbox-open .em-shot > img { transition: transform var(--em-t-image) var(--em-e-image),
  filter var(--em-t-image) ease; }
.em-lightbox-open:hover .em-shot > img { transform: scale(1.03); filter: brightness(1.04); }

/* a film that sits inside a card shares the card's top corners and nothing else */
.em-film--in-card { border-radius: var(--em-r) var(--em-r) 0 0; max-width: none; margin-inline: 0; }

@media (prefers-reduced-motion: reduce) {
  .em-lightbox-open .em-shot > img { transition: none; }
  .em-lightbox-open:hover .em-shot > img { transform: none; filter: none; }
}

/* ———————————————————————— 28 · Published highlights ———————————————————— */

/* The live page's own three-up highlight row. A hairline box each, because
   these are quotations from another surface and must read as such — not as
   this page's own claims. */
.em-facts { display: grid; gap: clamp(12px,1.6vw,18px);
  grid-template-columns: repeat(auto-fit, minmax(min(260px,100%),1fr));
  margin-top: clamp(26px,4vh,40px); }
.em-fact { display: flex; align-items: center; gap: 14px; min-height: 84px;
  padding: 20px clamp(18px,2vw,26px);
  border: 1px solid var(--em-line-rule); border-radius: var(--em-r);
  background: var(--em-surface);
  font-family: var(--em-display); font-size: clamp(17px,1.5vw,21px); line-height: 1.2;
  color: var(--em-ink); }
.em-fact::before { content: ''; width: 6px; height: 6px; flex: none; border-radius: 50%;
  background: var(--em-accent); }

/* The hero's own CTAs. They are ordinary ink controls at every width now:
   the lockup is on the page ground from 320 to 1440+, so the inversion that
   used to run from 1024 (white on night, for buttons sitting on the
   photograph) has gone with the overlay it existed for. .em-hero-cta and
   .em-hero-cta2 are kept as hooks — launches-pages.js and places-pages.js
   both name them — and simply add nothing over .em-btn / .em-btn-h. */
/* The crumb row sits above the hero and carries the page's top clearance, so
   the hero itself starts flush under it. */
.em-top { padding-top: 104px; }
.em-hero { margin-top: clamp(20px,3vh,30px); }

/* The ledge waits for the hero to pass. It is `sticky`, so it is in flow and
   its own box still reserves space at the end of the document — it is only
   the PAINT that is withheld, which is why translating it is right and
   display:none would be wrong. */
.em-ledge { transform: translateY(102%); transition: transform .42s var(--em-e-panel); will-change: transform; }
.em-ledge.is-up { transform: none; }
@media (prefers-reduced-motion: reduce) { .em-ledge { transition: none; } }

/* ———————————————————————— Header · the mega menu ————————————————————————
   The Communities popover that used to live here has been replaced by the
   home page's own two-panel mega menu, so that a reader meets one dropdown
   on the site rather than two. It is shared from site-nav.css, which every
   page carrying a header nav links after this file. */

/* ———————————— 29 · Enquiry modal — the phone presentation ————————————

   ONE component, two presentations, exactly as the floor-plan drawer is. The
   markup and the script are untouched; only the plate's geometry changes.

   Why it is needed. The card is centred and capped at `calc(100vh - 36px)`.
   `vh` does not shrink when the software keyboard opens, so on a 390x844
   phone the card keeps its full height, the keyboard covers its lower third,
   and Submit — the last element in the form — sits under it with no way to
   scroll to it, because the card's own scrollport is also the part that has
   been covered. Below 640 the card therefore becomes a bottom sheet measured
   in `dvh`, which tracks the visual viewport: the sheet shortens as the
   keyboard opens and its scroll reaches the button. `vh` is declared first as
   the fallback for engines without dynamic units. */

@media (max-width: 640px) {
  .em-modal { align-items: flex-end; padding: 0; }
  .em-modal__card {
    width: 100%;
    max-height: calc(100vh - 44px);
    max-height: calc(100dvh - 44px);
    border-radius: 0;
    padding: 26px var(--em-gut) calc(26px + env(safe-area-inset-bottom, 0px));
    /* -webkit-overflow-scrolling keeps the momentum scroll the page has */
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
  }
  /* The close control is the one thing that must stay reachable while the
     form is scrolled, so it rides the top of the sheet on its own ground. */
  .em-modal__top {
    position: sticky; top: -26px; z-index: 2;
    margin: -26px calc(var(--em-gut) * -1) 0;
    padding: 22px var(--em-gut) 14px;
    background: var(--em-surface-warm);
  }
  .em-modal__title { font-size: 25px; }
  .em-form { margin-top: 20px; gap: 16px; }
}

@media (prefers-reduced-motion: no-preference) {
  /* A sheet rises; it does not fall in from above. emMenuIn is the desktop
     card's entrance and reads backwards against a bottom-anchored plate. */
  @media (max-width: 640px) {
    .em-modal__card { animation: emSheet .4s var(--em-e-panel) both; }
  }
}

/* ————————————————— 25 · The community property finder —————————————————

   One band renders a community's COMPLETE portfolio — 41 cards at Dubai Creek
   Harbour, 42 at Dubai Hills Estate — so it has to stay elegant at 3 projects
   and at 43. Three levers do that: a short card (picture, name, one meta line,
   one facts line, the actions), a fixed three-track grid that never leaves a
   short last row stranded, and a 9-card opening with one control that opens
   the rest. Nothing is ever removed from the page to make it fit.            */

.em-pf__bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 16px;
  margin-top: clamp(26px,3.5vh,36px); padding-bottom: 20px;
  border-bottom: 1px solid var(--em-line-rule);
}

/* The field is the widest thing in the row and the first thing a reader
   reaches for, so it takes the remainder rather than a fixed measure. */
.em-pf__search {
  display: flex; align-items: center; gap: 10px; flex: 1 1 240px; min-width: 0;
  padding: 11px 14px; background: var(--em-surface);
  border: 1px solid var(--em-line-ctl); border-radius: var(--em-r);
  transition: border-color var(--em-t) ease, box-shadow var(--em-t) ease;
}
.em-pf__search:focus-within { border-color: var(--em-ink); box-shadow: 0 0 0 3px rgba(77,77,79,.18); }
.em-pf__search svg { width: 14px; height: 14px; flex: none; color: var(--em-ink-mute); }
.em-pf__search input {
  flex: 1; min-width: 0; border: 0; background: none; outline: none; padding: 0;
  font: inherit; font-size: 14px; color: var(--em-ink);
}
.em-pf__search input::placeholder { color: var(--em-ink-mute); }
.em-pf__search input::-webkit-search-cancel-button { cursor: pointer; }

/* A segmented control, not chips: the three states are mutually exclusive and
   one of them is always on, which is what a segment says and a chip does not. */
.em-pf__segs {
  display: flex; flex: none; border: 1px solid var(--em-line-ctl);
  border-radius: var(--em-r); overflow: hidden; background: var(--em-surface);
}
.em-pf__seg {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  padding: 11px 16px; min-height: 44px; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 11px; font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--em-ink-body);
  transition: background var(--em-t) ease, color var(--em-t) ease;
}
.em-pf__seg + .em-pf__seg { border-left: 1px solid var(--em-line-ctl); }
.em-pf__seg:hover { background: rgba(var(--em-rgb-ink), .04); color: var(--em-ink); }
.em-pf__seg.is-on { background: var(--em-ink); color: var(--em-on-ink); }
/* The count rides the segment, so the reader knows the size of a set before
   choosing it. On the selected segment it borrows the plate's own ink. */
.em-pf__n { font-size: 11px; font-weight: 600; letter-spacing: .04em;
  font-variant-numeric: tabular-nums; color: var(--em-ink-mute); }
.em-pf__seg.is-on .em-pf__n { color: rgba(248,248,248,.72); }

.em-pf__beds { display: flex; align-items: center; gap: 10px; flex: none; }
.em-pf__lab { font-size: 11px; font-weight: 600; letter-spacing: .18em;
  text-transform: uppercase; color: var(--em-ink-eyebrow); }
.em-pf__beds > div { min-width: 168px; }

.em-pf__count { font-size: 12px; letter-spacing: .06em; color: var(--em-ink-mute);
  margin-top: 16px; font-variant-numeric: tabular-nums; }
.em-pf__none { font-size: 15px; color: var(--em-ink-body); margin-top: 28px; }
.em-pf__more { margin-top: clamp(32px,4.5vh,48px); text-align: center; }

/* Same busy pattern as the press page's Load more: a hairline sweeping the
   button's own floor, label fading rather than swapping so nothing resizes. */
[data-em-pf-all] { position: relative; overflow: hidden; }
.em-pf__more-l { transition: opacity var(--em-t) ease; }
[data-em-pf-all][aria-busy="true"] .em-pf__more-l { opacity: .45; }
[data-em-pf-all]::after {
  content: ''; position: absolute; left: 0; bottom: 0; height: 2px; width: 45%;
  background: var(--em-ink); opacity: 0; transform: translateX(-100%);
}
[data-em-pf-all][aria-busy="true"]::after {
  opacity: 1; animation: em-pf-more-sweep .7s var(--em-e-soft) infinite;
}
@keyframes em-pf-more-sweep {
  from { transform: translateX(-100%); }
  to   { transform: translateX(222%); }
}
@media (prefers-reduced-motion: reduce) {
  [data-em-pf-all][aria-busy="true"]::after {
    animation: none; transform: none; width: 100%; opacity: .22;
  }
}

.em-pf__grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(22px,2.4vw,32px) clamp(18px,2vw,28px);
  margin-top: 18px;
}
/* An author `display` on the element beats the UA's [hidden]{display:none} with
   no specificity contest, so every display-carrying member of this band states
   the rule itself. Filtering is what hides a card; without this it hides none. */
.em-pf__grid[hidden], .em-pc[hidden], .em-pf__more[hidden], .em-pf__none[hidden] {
  display: none !important;
}

/* ——— one project ——— */

.em-pc {
  display: flex; flex-direction: column; min-width: 0;
  color: var(--em-ink);
}
.em-pc__pic { position: relative; border-radius: var(--em-r); overflow: hidden; }
.em-pc__pic .em-shot { border-radius: 0; }
/* The card is a picture with words BELOW it — the plate over the frame is the
   badge alone, on the measured --em-badge ground the house already verified. */
.em-pc .em-shot > img { transition: transform var(--em-t-image) var(--em-e-image); }
.em-pc:hover .em-shot > img { transform: scale(1.04); }

.em-pc__body { display: flex; flex-direction: column; flex: 1; padding-top: 16px; }
.em-pc__name { font-family: var(--em-display); font-size: clamp(19px,1.5vw,22px);
  line-height: 1.14; text-wrap: pretty; }
.em-pc__name a { color: inherit; text-decoration: none; position: relative; display: inline-block; }
/* A 22px heading link is not a 44px target; the inset pseudo-element grows the
   hit box and changes no layout at all. */
.em-pc__name a::after { content: ''; position: absolute; inset: -11px -6px; }
.em-pc__name a:hover { color: var(--em-accent); }
.em-pc__ext { width: 10px; height: 10px; margin-left: 7px; flex: none; opacity: .75;
  vertical-align: -1px; }

.em-pc__meta { font-size: 13px; line-height: 1.45; color: var(--em-ink-mute); margin-top: 7px; }
/* Same rule as .em-card__row: the price row belongs to the bottom-pinned
   block, not the top one, so two cards whose names wrap to a different
   number of lines still show "From AED …" on the same line as each other.
   It carries the auto margin itself; .em-pc__acts keeps its own only as the
   fallback for a card with no price to show. */
.em-pc__facts { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 14px;
  margin-top: auto; padding-top: 12px; border-top: 1px solid var(--em-line); }
.em-pc__price { font-size: 15px; font-weight: 600; white-space: nowrap; }
.em-pc__units { font-size: 12px; color: var(--em-ink-mute); white-space: nowrap; }

/* The actions sit on the card's bottom edge so a row of cards of unequal text
   length still lines its buttons up — margin-top:auto, and the card is the
   flex column that gives it something to push against. */
.em-pc__acts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: auto; padding-top: 16px; }
.em-pc__facts + .em-pc__acts { margin-top: 0; }
.em-pc__acts > * { flex: 1 1 auto; }
.em-pc__acts .em-plans-btn { flex: 1 1 100%; }
.em-pc__acts .em-btn, .em-pc__acts .em-btn-o, .em-pc__acts .em-btn-h {
  padding: 11px 16px; font-size: 10.5px; justify-content: center;
}

@media (max-width: 1100px) { .em-pf__grid { grid-template-columns: repeat(2, 1fr); } }

@media (max-width: 720px) {
  /* One column, and the bar stacks: a segmented control at three segments is
     already wider than a 360px screen once the counts are on it. */
  .em-pf__grid { grid-template-columns: 1fr; gap: 30px; }
  .em-pf__bar { gap: 12px; }
  .em-pf__search, .em-pf__segs, .em-pf__beds { flex: 1 1 100%; }
  .em-pf__segs { display: grid; grid-template-columns: repeat(3, 1fr); }
  .em-pf__seg { justify-content: center; padding: 12px 8px; font-size: 10px;
    letter-spacing: .10em; gap: 5px; }
  .em-pf__beds > div { flex: 1; min-width: 0; }
  .em-pc__name { font-size: 21px; }
  .em-pc__acts > * { flex: 1 1 100%; }
}

/* ————————————————————— the four-action listing card —————————————————————
   Every property card in a master community carries the same four actions in
   the same two rows — Book Now and Explore above, Enquire and Floor Plans
   below — so a reader scanning forty-one of them learns the layout once.

   Grid, not flex: the slots must hold still. A wrapping flex row reflows
   every button after the missing one, so on a card with no Book Now the
   floor-plans button would slide up into Enquire's place and the grid would
   read as noise. Here Explore simply spans the top row instead, and Enquire
   and Floor Plans stay exactly where they are on every other card.

   These rules come last on purpose: they override the flex display that
   .em-pc__acts and .em-card__acts set for the older card shapes.           */
.em-acts--quad { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.em-acts--quad > * { min-width: 0; }
/* no booking to do — Explore leads the card and takes the row alone */
.em-acts--quad.em-acts--nobook > .em-pc__explore { grid-column: 1 / -1; }

/* The pair holds on phones too. Stacking the set turned a four-action card
   into four identical full-width bars — a menu, not two choices — and cost
   an extra ~110px of card height on every one of forty-one listings.

   It only ever stacked because the buttons carried desktop padding into a
   136px column: at 320px, the narrowest phone in the ladder, the card is
   280px and each slot is 136px, while FLOOR PLANS — the widest label, and
   the only one with an icon — asked for 139px. Below 600px the button
   spends less on air either side and the label, its tracking and its icon
   are untouched; the widest one then measures 121px and clears the slot.

   The font-size is the listing card's own 10.5px, stated here so the
   collection card's quad (.em-card__acts) matches it on a phone instead of
   sitting at the 11px base and overflowing the same slot. */
@media (max-width: 599px) {
  .em-acts--quad > .em-btn,
  .em-acts--quad > .em-btn-o,
  .em-acts--quad > .em-btn-h {
    padding-left: 8px; padding-right: 8px;
    font-size: 10.5px;
    gap: 8px;
  }
}
