/* ===========================================================================
   EMAAR — Latest Launches / New Launch detail / Recently Completed
   launches.css

   This file adds ONLY what places.css does not already carry. It is loaded
   AFTER places.css and inherits every --em-* token from it; it declares no
   token of its own and no colour that is not a token. If a component here
   duplicates one in places.css, that is a defect — delete it here and use the
   original. The house rule is one implementation per component.

   Reused unchanged from places.css: .em-hero, .em-card, .em-grid, .em-figure,
   .em-shot, .em-amen, .em-stats, .em-specs, .em-badge, .em-faq, .em-btn*,
   .em-cta, .em-crumb, .em-eyebrow, .em-modal, the reveal system and the four
   motion curves.

   Namespace: .ll-*
   =========================================================================== */

/* ————————————————————————— 1 · Masthead —————————————————————————

   The two listing pages open on the page ground, not over a photograph.
   EMAAR's own introduction runs to three paragraphs; a hero image behind it
   would either bury the words or crop to nothing at 390px, and no photograph
   in the set depicts "the latest launches" as a set — it depicts one project.
   So the picture comes AFTER the words, captioned and attributed, and the
   opening is typographic. (places.css's .em-hero is used on the detail
   template, where the photograph genuinely IS the subject.) */

/* This overrode .em-top's 104px header clearance with 26–44px, which put the
   breadcrumb at y=36 beneath a 72px FIXED header: elementFromPoint over the
   Home / Latest Launches crumb returned the header's own brand link, so the
   crumb was both half-hidden and unclickable. The clearance is not this
   component's to spend — it adds to the header, it does not replace it.
   Same expression as .ab-mast so every masthead on the site opens level. */
.ll-mast { padding-top: calc(var(--em-hdr) + clamp(22px, 3.4vw, 40px)); }
.ll-mast__grid {
  display: grid; gap: clamp(20px, 3vw, 56px);
  grid-template-columns: 1fr;
  align-items: start;
  margin-top: clamp(18px, 2.6vh, 26px);
}
.ll-mast__lede p { font-size: 16px; line-height: 1.62; color: var(--em-ink-body); text-wrap: pretty; }
.ll-mast__lede p + p { margin-top: 14px; }
/* Two classes, because `.ll-mast__lede p` above out-ranks a single-class
   .em-note and would print a footnote at the size of the copy it annotates. */
.ll-mast__lede .ll-mast__note {
  margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--em-line-faint);
  font-size: 12.5px; line-height: 1.5; color: var(--em-ink-mute);
}

/* ——— The lede is a disclosure, not a wall ———————————————————————————

   EMAAR's own introduction runs to three paragraphs — about 250 words. Set
   whole it is ~9 lines at 1440 and ~20 at 390, which on a phone is the entire
   first screen and most of the second: the reader arrives at a page called
   Latest Launches and cannot see a launch without scrolling past an essay.
   The introduction is not cut — it is folded. The first paragraph opens, the
   rest is one control away, and the listing starts within the first screen at
   every width.

   The crop is -webkit-line-clamp on the FIRST PARAGRAPH, not a max-height on
   the group. A pixel budget over three paragraphs has no idea where the 14px
   paragraph gaps fall, so at 900+ a five-line budget lands three pixels into
   the first line of the second paragraph and prints half a row of type. A
   line clamp cannot: it counts line boxes inside one block, so the cut is
   always ON a baseline, and the ellipsis it sets is the house's own way of
   saying there is more — the same one .press-latest__card-head and the press
   rows already use.

   Four lines below 900, five above, where the column is 38em and the first
   paragraph is four lines anyway: on desktop nothing is cut at all and the
   control reveals the two paragraphs beneath it. No gradient over the fold.
   The button sits directly under the crop and says what is behind it; a fade
   would be a second, softer way of saying the same thing, and this build does
   not decorate an edge it can name. */

/* max-height is never set here — the collapsed height IS the clamped first
   paragraph. The script writes an inline max-height for the length of the
   fold and clears it again, so nothing but the transition depends on a
   number this stylesheet would have to guess. */
.ll-lede__body { overflow: hidden; transition: max-height var(--em-t-mid) var(--em-e-soft); }

/* Hidden rather than clipped, so the collapsed lede costs the exact height of
   its first paragraph and nothing is left below the fold to be scrolled to by
   Find-in-page or read out by a screen reader as if it were on screen. */
.ll-lede__body > p { display: none; }
.ll-lede__body > p:first-child {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
}
.ll-lede.is-open .ll-lede__body > p {
  display: block;
  -webkit-line-clamp: none;
  line-clamp: none;
  overflow: visible;
}

/* A caret, never an arrow. The arrow in .em-cta means the reader leaves for
   somewhere else — §2 of the standards: the text link NAVIGATES, it does not
   act. This one opens what is already here, so it carries the same downward
   caret the chip row's "+N more" carries, and turns over the same way. The
   rule under the label is on the label alone, so the caret is not underlined
   with it. */
.ll-lede__more {
  display: inline-flex; align-items: center; gap: 9px;
  /* §12: a touch target is never expressed in rem. The label is small and the
     target is not — 44px of button around 11px of type. */
  min-height: var(--em-control-min);
  margin-top: 2px;
  padding: 0; border: 0; background: none;
  font-family: var(--em-font-ui);
  font-size: 11px; font-weight: 600; letter-spacing: .18em; line-height: 1;
  text-transform: uppercase;
  color: var(--em-ink-body);
  cursor: pointer;
  transition: opacity var(--em-t) ease;
}
.ll-lede__more:hover { opacity: .62; }
.ll-lede__more-l { border-bottom: 1px solid currentColor; padding-bottom: 3px; }
.ll-lede__cav { width: 8px; height: 5px; flex: none; transition: transform var(--em-t) ease; }
.ll-lede__more[aria-expanded="true"] .ll-lede__cav { transform: rotate(180deg); }

@media (prefers-reduced-motion: reduce) {
  .ll-lede__body { transition: none; }
  .ll-lede__cav, .ll-lede__more { transition: none; }
}

/* The ledger is derived, never typed: every number is counted from the data
   at render time, so it cannot contradict the list underneath it. */
.ll-ledger {
  /* 240, not 150. At 1440 the masthead's right column is ~570px wide, which
     at 150 fits three tracks and leaves the fourth metric alone on a second
     row — a ragged 3+1. At 240 it is two clean rows of two. */
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: clamp(18px, 2.2vw, 28px);
  padding-top: 24px; margin-top: 4px;
  border-top: 1px solid var(--em-line-rule);
}
.ll-ledger__v { font-family: var(--em-display); font-size: clamp(26px, 2.6vw, 34px); line-height: 1.04; }
.ll-ledger__k {
  margin-top: 8px; font-size: 10.5px; font-weight: 600; letter-spacing: .18em;
  line-height: 1.45; text-transform: uppercase; color: var(--em-ink-eyebrow);
}

@media (min-width: 900px) {
  .ll-mast__grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); }
  .ll-mast__lede { max-width: 38em; }
  /* Repeated at the specificity of the rule it replaces — a media query adds
     none of its own. At 38em the first paragraph sets four lines, so five is
     the budget that shows it whole and cuts nothing; what the control opens
     here is the second and third paragraphs, not the end of a sentence. */
  .ll-lede__body > p:first-child { -webkit-line-clamp: 5; line-clamp: 5; }
}

/* ————————————————————————— 2 · View switch —————————————————————————

   EMAAR's own page divides the same content three ways — Communities, Newly
   Launched, Now Available — and that division is the page's information
   architecture, not a decoration. It is a real tablist: arrow keys move
   between the tabs, only the selected panel is in the accessibility tree.
   Square, because nothing in this build has a radius beyond 2px. */

.ll-views { margin-top: clamp(28px, 4vh, 44px); }
.ll-seg {
  display: flex; flex-wrap: wrap; gap: 0;
  border: 1px solid var(--em-line-ctl); border-radius: var(--em-r);
  width: fit-content; max-width: 100%;
  background: var(--em-surface);
}
.ll-seg__b {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 46px; padding: 12px clamp(14px, 2vw, 26px);
  font-size: 10.5px; font-weight: 600; letter-spacing: .18em; text-transform: uppercase;
  color: var(--em-ink-eyebrow); white-space: nowrap;
  border-right: 1px solid var(--em-line);
  transition: background var(--em-t) ease, color var(--em-t) ease;
}
.ll-seg__b:last-child { border-right: 0; }
.ll-seg__b:hover { background: rgba(var(--em-rgb-ink), .04); color: var(--em-ink); }
.ll-seg__b[aria-selected="true"] { background: var(--em-ink); color: var(--em-on-ink); }
.ll-seg__b[aria-selected="true"]:hover { background: var(--em-ink-hover); color: var(--em-on-ink); }
.ll-seg__n {
  font-size: 10px; letter-spacing: .08em; opacity: .7;
  font-variant-numeric: tabular-nums;
}

/* Below 700 the three views do not fit on one line at any tracking this build
   would accept — measured, they want 485px inside a 350px column and wrap to
   a ragged three rows. So the control becomes what it already is at that
   width: an index. One full-width row each, the count ranged right, the
   divider moving from the right edge to the bottom. EMAAR's own three labels
   are kept whole; shrinking them to fit would be a content change. */
@media (max-width: 699px) {
  .ll-seg { display: grid; width: 100%; }
  .ll-seg__b {
    justify-content: space-between; text-align: left;
    padding-left: 16px; padding-right: 16px;
    border-right: 0; border-bottom: 1px solid var(--em-line);
  }
  .ll-seg__b:last-child { border-bottom: 0; }
}

/* ————————————————————————— 3 · Filter bar —————————————————————————

   Desktop. Not a dashboard: hairline controls on the page ground, an active
   state that fills rather than outlines, a live result count, and a reset
   that only exists while there is something to reset.

   Two rows, not one flex-wrap line. The community row (.ll-bar__desk) wraps
   freely on its own; .ll-bar__meta — count, reset, sort — keeps its own
   baseline underneath instead of being vertically centred against however
   tall the wrapped chips happen to be, which is what read as "not aligned." */

.ll-bar {
  display: flex; flex-direction: column; gap: 14px;
  margin-top: clamp(20px, 2.6vh, 28px);
  padding-bottom: 18px; border-bottom: 1px solid var(--em-line-rule);
}
.ll-bar__label {
  font-size: 10px; font-weight: 600; letter-spacing: .22em; text-transform: uppercase;
  color: var(--em-ink-eyebrow); margin-right: 2px;
}
.ll-bar__meta { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; }
.ll-bar__spacer { flex: 1 1 24px; }
.ll-bar__count {
  font-size: 12.5px; color: var(--em-ink-mute); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.ll-bar__count b { font-weight: 600; color: var(--em-ink); }

.ll-chips { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; min-width: 0; }
.ll-chip {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 10px 16px;
  font-size: 11px; font-weight: 600; letter-spacing: .10em;
  color: var(--em-ink-body);
  /* 3.1:1 — the floor this build set for a control's own edge. A .16 hairline
     measured 1.55:1 and is not a border a keyboard user can find. */
  border: 1px solid var(--em-line-ctl); border-radius: var(--em-r);
  background: transparent; white-space: nowrap;
  transition: background var(--em-t) ease, border-color var(--em-t) ease, color var(--em-t) ease;
}
.ll-chip:hover { border-color: var(--em-ink); color: var(--em-ink); background: rgba(var(--em-rgb-ink), .04); }
.ll-chip[aria-pressed="true"] {
  background: var(--em-ink); border-color: var(--em-ink); color: var(--em-on-ink);
}
.ll-chip[aria-pressed="true"]:hover { background: var(--em-ink-hover); color: var(--em-on-ink); }
.ll-chip__n { font-size: 10.5px; opacity: .62; font-variant-numeric: tabular-nums; }

/* "+N more" reads as an action on the row, not a thirteenth community:
   dashed, muted, no count badge. */
.ll-chip--more { border-style: dashed; color: var(--em-ink-mute); }
.ll-chip--more:hover { border-style: solid; }
.ll-chip__cav { width: 8px; height: 5px; flex: none; transition: transform var(--em-t) ease; }
.ll-chip--more[aria-expanded="true"] .ll-chip__cav { transform: rotate(180deg); }

.ll-reset {
  display: inline-flex; align-items: center; gap: 7px; min-height: 44px; padding: 10px 2px;
  font-size: 10.5px; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: var(--em-ink-eyebrow); border-bottom: 1px solid var(--em-line-ctl);
  transition: color var(--em-t) ease, border-color var(--em-t) ease;
}
.ll-reset:hover { color: var(--em-ink); border-color: var(--em-ink); }
/* An author display beats the UA [hidden] rule at equal specificity — same
   defect this build already guards on .ll-sheet. Without this, JS's
   reset.hidden = true never actually hides the button. */
.ll-reset[hidden] { display: none; }

/* Sort — a button that opens a small owned listbox, styled to the site's own
   language. A native <select>'s open popup is the platform's own chrome and
   no CSS reaches it, which is what read as un-styled against everything
   around it. */
.ll-sort { position: relative; }
.ll-sort__btn {
  display: inline-flex; align-items: center; gap: 10px; min-height: 44px;
  padding: 10px 14px;
  font-size: 11px; font-weight: 600; letter-spacing: .08em; color: var(--em-ink);
  background: transparent; border: 1px solid var(--em-line-ctl); border-radius: var(--em-r);
  transition: border-color var(--em-t) ease;
}
.ll-sort__btn:hover { border-color: var(--em-ink); }
.ll-sort.is-open .ll-sort__btn { border-color: var(--em-ink); }
.ll-sort__cav { width: 9px; height: 6px; flex: none; color: var(--em-ink-2); transition: transform var(--em-t) ease; }
.ll-sort.is-open .ll-sort__cav { transform: rotate(180deg); }

.ll-sort__list {
  position: absolute; z-index: var(--z-sticky); left: 0; top: calc(100% + 6px);
  min-width: 100%; width: max-content; max-width: min(280px, 90vw);
  margin: 0; padding: 6px; list-style: none;
  background: var(--em-surface); border: 1px solid var(--em-line-ctl); border-radius: var(--em-r);
  box-shadow: 0 12px 28px rgba(var(--em-rgb-ink), .16), 0 2px 8px rgba(var(--em-rgb-ink), .08);
  animation: llSortPop .16s var(--em-e-soft) both;
}
@keyframes llSortPop { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.ll-sort__opt {
  display: flex; align-items: center; gap: 14px;
  padding: 10px 12px; border-radius: var(--em-r);
  font-size: 12.5px; color: var(--em-ink-body); white-space: nowrap; cursor: pointer;
  transition: background var(--em-t) ease;
}
.ll-sort__opt:hover, .ll-sort__opt:focus { background: rgba(var(--em-rgb-ink), .04); outline: none; }
.ll-sort__opt[aria-selected="true"] { color: var(--em-ink); font-weight: 600; }
.ll-sort__tick { margin-left: auto; width: 13px; height: 13px; flex: none; color: var(--em-ink); opacity: 0; }
.ll-sort__opt[aria-selected="true"] .ll-sort__tick { opacity: 1; }

/* The mobile trigger. Below 900 the chip row is replaced outright — not
   wrapped, not scrolled sideways — by one control that opens a sheet. */
.ll-bar__trigger { display: inline-flex; }
.ll-bar__desk { display: none; }
@media (min-width: 900px) {
  .ll-bar__trigger { display: none; }
  .ll-bar__desk { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; }
}
.ll-trig__n {
  display: inline-grid; place-items: center; min-width: 19px; height: 19px; padding: 0 5px;
  background: var(--em-ink); color: var(--em-on-ink); border-radius: var(--em-r);
  font-size: 10px; font-weight: 600; font-variant-numeric: tabular-nums;
}
.ll-trig__n[hidden] { display: none; }

/* ————————————————————————— 4 · Filter sheet —————————————————————————

   Mobile. The same geometry language as the floor-plan sheet in places.css —
   a bottom-anchored plate on a blurred scrim, its own scroll, and a fixed
   foot carrying Reset and Apply so the primary action never scrolls away. */

.ll-sheet { position: fixed; inset: 0; z-index: var(--z-modal); display: flex; align-items: flex-end; }
.ll-sheet[hidden] { display: none; }
.ll-sheet__scrim {
  position: absolute; inset: 0; background: var(--em-scrim);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
}
.ll-sheet__panel {
  position: relative; display: flex; flex-direction: column;
  width: 100%; max-height: 88vh;
  background: var(--em-surface-warm); color: var(--em-ink);
  box-shadow: var(--em-sh-panel);
}
.ll-sheet__head {
  flex: none; display: flex; align-items: flex-start; justify-content: space-between; gap: 18px;
  padding: 22px var(--em-gut) 16px; border-bottom: 1px solid var(--em-line);
}
.ll-sheet__eyebrow {
  font-size: 10px; font-weight: 600; letter-spacing: .24em; text-transform: uppercase;
  color: var(--em-text-eyebrow-neutral);
}
.ll-sheet__title { font-family: var(--em-display); font-size: 26px; line-height: 1.1; margin-top: 8px; }
.ll-sheet__close {
  flex: none; display: grid; place-items: center; width: 44px; height: 44px; margin: -6px -8px 0 0;
  border: 1px solid var(--em-line-ctl); border-radius: var(--em-r);
  transition: border-color var(--em-t) ease;
}
.ll-sheet__close:hover { border-color: var(--em-ink); }
.ll-sheet__close svg { width: 13px; height: 13px; display: block; }
.ll-sheet__body { flex: 1 1 auto; overflow-y: auto; -webkit-overflow-scrolling: touch;
  padding: 20px var(--em-gut) 24px; }
.ll-sheet__group + .ll-sheet__group { margin-top: 26px; }
.ll-sheet__legend {
  font-size: 10px; font-weight: 600; letter-spacing: .22em; text-transform: uppercase;
  color: var(--em-ink-eyebrow); margin-bottom: 12px;
}
/* One option per row at 320px: a wrapped chip grid puts two 44px targets a
   few pixels apart, which is the classic mis-tap. */
.ll-sheet__opts { display: grid; gap: 8px; }
.ll-sheet__opt {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  min-height: 52px; padding: 13px 16px;
  border: 1px solid var(--em-line-ctl); border-radius: var(--em-r);
  font-size: 14px; color: var(--em-ink-body);
  transition: background var(--em-t) ease, border-color var(--em-t) ease, color var(--em-t) ease;
}
.ll-sheet__opt[aria-pressed="true"] {
  background: var(--em-ink); border-color: var(--em-ink); color: var(--em-on-ink);
}
.ll-sheet__opt-n { font-size: 11.5px; opacity: .62; font-variant-numeric: tabular-nums; }
.ll-sheet__foot {
  flex: none; display: flex; gap: 10px;
  padding: 16px var(--em-gut) calc(16px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--em-line); background: var(--em-surface-warm);
}
.ll-sheet__foot > * { flex: 1 1 0; }
@media (min-width: 900px) { .ll-sheet { display: none !important; } }

/* ————————————————————————— 5 · Result grids —————————————————————————

   The card itself is places.css's .em-card. What is added here is the
   availability read-out, which is the one fact EMAAR's own Now Available list
   leads with, and the empty and load-more states. */

.ll-results { margin-top: clamp(26px, 3.4vh, 38px); }

/* The bottom-alignment of the price row and the action row is places.css's,
   on .em-card itself — it was scoped here while only these grids needed it,
   and the same card is used on the release and community pages. One rule,
   one component. See places.css §14. */

.ll-avail {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--em-line);
}
.ll-avail__v { font-size: 15.5px; font-weight: 600; font-variant-numeric: tabular-nums; }
.ll-avail__k { font-size: 11px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--em-ink-mute); }
/* Scarcity as a rule, not a red bar: the track is the largest count in the
   set, so the mark is comparative and carries no invented threshold. */
.ll-avail__track { position: relative; height: 2px; background: var(--em-line); margin-top: 12px; }
.ll-avail__fill { position: absolute; inset: 0 auto 0 0; background: var(--em-accent); }

.ll-empty {
  padding: clamp(40px, 7vw, 76px) clamp(20px, 4vw, 40px); text-align: center;
  border: 1px dashed var(--em-line-ctl); border-radius: var(--em-r); background: var(--em-sunk);
}
.ll-empty__t { font-family: var(--em-display); font-size: clamp(22px, 2.4vw, 28px); line-height: 1.12; }
.ll-empty__b { margin-top: 12px; font-size: 14.5px; line-height: 1.6; color: var(--em-ink-body);
  max-width: 34em; margin-inline: auto; }
.ll-empty__a { margin-top: 22px; }

.ll-more { display: flex; flex-direction: column; align-items: center; gap: 12px;
  margin-top: clamp(30px, 4vw, 46px); }
.ll-more__n { font-size: 11.5px; letter-spacing: .06em; color: var(--em-ink-mute);
  font-variant-numeric: tabular-nums; }

/* 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-ll-more] { position: relative; overflow: hidden; }
.ll-more-l { transition: opacity var(--em-t) ease; }
[data-ll-more][aria-busy="true"] .ll-more-l { opacity: .45; }
[data-ll-more]::after {
  content: ''; position: absolute; left: 0; bottom: 0; height: 2px; width: 45%;
  background: var(--em-ink); opacity: 0; transform: translateX(-100%);
}
[data-ll-more][aria-busy="true"]::after {
  opacity: 1; animation: ll-more-sweep .7s var(--em-e-soft) infinite;
}
@keyframes ll-more-sweep {
  from { transform: translateX(-100%); }
  to   { transform: translateX(222%); }
}
@media (prefers-reduced-motion: reduce) {
  [data-ll-more][aria-busy="true"]::after {
    animation: none; transform: none; width: 100%; opacity: .22;
  }
}

/* ————————————————————————— 6 · Community tiles —————————————————————————

   Taller than a project card and carrying two actions, because a community is
   a place to enter rather than a unit to buy. */

.ll-comm__body { display: flex; flex-direction: column; flex: 1; }
.ll-comm__acts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: auto; padding-top: 20px; }
.ll-comm__acts > * { flex: 1 1 140px; }
.ll-comm__note { margin-top: 12px; font-size: 11.5px; line-height: 1.5; color: var(--em-ink-mute); }

/* ————————————————————————— 7 · Editorial band —————————————————————————

   The completed-projects index. One project per band, the picture alternating
   side, the words always on the page ground beside it and never on it. */

.ll-band { display: grid; gap: clamp(22px, 3vw, 54px); align-items: center;
  grid-template-columns: 1fr; }
.ll-band + .ll-band { margin-top: clamp(48px, 7vw, 96px); }
.ll-band__body > * + * { margin-top: 16px; }
.ll-band__n {
  font-family: var(--em-display); font-size: 13px; letter-spacing: .12em;
  color: var(--em-ink-mute); font-variant-numeric: tabular-nums;
}
.ll-band__area {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 10.5px; font-weight: 600; letter-spacing: .20em; text-transform: uppercase;
  color: var(--em-text-eyebrow-neutral);
}
.ll-band__area::before { content: ''; width: 18px; height: 1px; background: var(--em-line-rule); }
.ll-band__acts { display: flex; flex-wrap: wrap; gap: 10px; padding-top: 6px; }

@media (min-width: 900px) {
  .ll-band { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); }
  .ll-band__media { grid-column: 1; grid-row: 1; }
  .ll-band__body  { grid-column: 2; grid-row: 1; }
  .ll-band--flip .ll-band__media { grid-column: 2; }
  .ll-band--flip .ll-band__body  { grid-column: 1; }
  /* The tracks swap with the picture. Without this the wide track stayed on
     the left and a flipped band's photograph was rendered into the narrow one
     — 516px against 700px — so alternating the side also alternated the size,
     and every second project read as the lesser of the pair. The picture
     keeps its weight; only the side changes. */
  .ll-band--flip { grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr); }
}

/* The hero's photo credit. The page hero is one of the four projects rather
   than a generic skyline, so the lockup has to name it — and, naming it,
   may as well carry the reader to it. Sits in the lockup, on the measured
   veil, so it is printed for a dark ground exactly like the sub above it. */
.ll-done__credit {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px;
  margin-top: 20px; font-size: 12.5px; line-height: 1.4;
}
.ll-done__credit-k {
  font-size: 10px; font-weight: 600; letter-spacing: .20em; text-transform: uppercase;
  color: var(--em-ink-eyebrow);
}
/* Padded out to a 44px hit area and pulled back by the same amount, so the
   target is comfortable on a phone without the lockup growing a line of air
   around it. Measured as a hit area, not as a bounding box: at its natural
   21px this was the smallest target on the page. */
.ll-done__credit a {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; margin-block: -12px; padding-block: 12px;
  color: var(--em-ink-body);
  /* text-decoration, not a border: the box is now 44px tall and a bottom
     border would draw the rule 12px under the words it belongs to. */
  text-decoration: underline; text-decoration-color: transparent;
  text-underline-offset: 4px; text-decoration-thickness: 1px;
  transition: color var(--em-t) ease, text-decoration-color var(--em-t) ease;
}
.ll-done__credit a span { transition: transform var(--em-t) var(--em-e-soft); }
.ll-done__credit a:hover { color: var(--em-ink); text-decoration-color: currentColor; }
.ll-done__credit a:hover span { transform: translateX(4px); }

/* The white flip that stood here went with the overlay. The lockup is below
   the media, on cream, at every width now — see places.css, The hero — so the
   ink rules above hold from 320 to 1440+ and .em-hero__eyebrow / __h1 / __sub
   no longer flip either. */

/* The area rail: EMAAR's own two-column index, Areas against Properties, kept
   as an index rather than turned into a chip row or a card grid — four areas,
   four delivered projects, and a one-to-one map between them. What it gained
   is the photograph: on a page about how places look now they are built, a
   reader should be able to see the four before scrolling to them. */
.ll-rail { display: grid; gap: 0; }
/* Emaar's pair of column labels is the truth only where the row really has
   two columns. Below 1024 the row stacks area over name in a single column,
   and a head reading "Areas … Properties" over it would label nothing — so it
   is not drawn there, and the rail's aria-label carries the same sense. */
.ll-rail__head {
  display: none;
  padding-bottom: 10px; border-bottom: 1px solid var(--em-line-rule);
  font-size: 10px; font-weight: 600; letter-spacing: .20em; text-transform: uppercase;
  color: var(--em-ink-eyebrow);
}
.ll-rail__b {
  display: grid; gap: 2px 14px;
  grid-template-columns: 56px minmax(0, 1fr) 16px;
  align-items: center;
  min-height: 64px; padding: 12px 0;
  border-bottom: 1px solid var(--em-line-faint);
  color: var(--em-ink-body);
  transition: color var(--em-t) ease;
}
.ll-rail__th {
  grid-row: 1 / span 2; align-self: stretch;
  position: relative; overflow: hidden; background: var(--em-well);
  border-radius: var(--em-r); aspect-ratio: 1/1;
}
.ll-rail__th > img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform var(--em-t-image) var(--em-e-image);
}
.ll-rail__area {
  grid-column: 2; grid-row: 1;
  font-size: 10px; font-weight: 600; letter-spacing: .18em; text-transform: uppercase;
  color: var(--em-text-eyebrow-neutral);
}
.ll-rail__name { grid-column: 2; grid-row: 2; font-size: 16px; line-height: 1.3; }
.ll-rail__a {
  grid-column: 3; grid-row: 1 / span 2; justify-self: end;
  color: var(--em-ink-mute);
  transition: transform var(--em-t) var(--em-e-soft), color var(--em-t) ease;
}
.ll-rail__a svg { display: block; }
.ll-rail__b:hover { color: var(--em-ink); }
.ll-rail__b:hover .ll-rail__th > img { transform: scale(1.06); }
.ll-rail__b:hover .ll-rail__a { transform: translateX(4px); color: var(--em-ink); }

@media (min-width: 1024px) {
  /* Now the row holds Emaar's own two columns side by side, so the head can
     be drawn — on the same track grid as the rows, so each label sits over
     the column it names rather than at the far edges of the rail. */
  .ll-rail__b { grid-template-columns: 56px minmax(0, 1fr) minmax(0, 1fr) 16px; }
  .ll-rail__area { grid-column: 2; grid-row: 1 / span 2; font-size: 10.5px; }
  .ll-rail__name { grid-column: 3; grid-row: 1 / span 2; text-align: right; font-size: 15px; }
  .ll-rail__a { grid-column: 4; }
  .ll-rail__head {
    display: grid; gap: 14px;
    grid-template-columns: 56px minmax(0, 1fr) minmax(0, 1fr) 16px;
  }
  .ll-rail__head span:first-child { grid-column: 2; }
  .ll-rail__head span:last-child { grid-column: 3; text-align: right; }
}

/* ——————————————— 7b · One delivered project, one chapter ———————————————

   One frame and the words beside it (.ll-band above). The frame is the film
   — .em-reel-th in film-modal.css — and it is the chapter's only media, so
   all four chapters are the same shape. The detail strip that used to follow
   it is gone: it drew one frame for a project that published one image block
   and two for a project that published two, which on an index of four read
   as three pictures, two, three, two. */

.ll-done + .ll-done { margin-top: clamp(56px, 8vw, 110px); }

.ll-done__of { color: var(--em-ink-mute); }

/* The amenity row. Not .em-amen: that is the release page's two-column
   bulleted grid, and six bulleted rows per project, four times over, was the
   densest thing on this page. Here they are a texture — what kind of place
   this is — set as a wrapped run with a hairline between items. */
/* A MARKER, not a separator. A divider between items — leading or trailing —
   is a thing that belongs between two items on one line, and this row wraps:
   a leading rule hangs at the start of every wrapped line, a trailing one
   hangs at the end of every wrapped line. Neither is fixable in CSS, because
   nothing in CSS knows where a line broke. So every item carries its own dot,
   the first included, and there is nothing left to dangle. It is also the
   marker .em-amen already uses on the release page, so the two lists read as
   the same list in two densities rather than two different ideas. */
.ll-done__amen {
  display: flex; flex-wrap: wrap; gap: 4px 20px;
  margin-top: 2px; padding-top: 14px; border-top: 1px solid var(--em-line-faint);
  font-size: 12.5px; line-height: 1.5; color: var(--em-ink-mute);
}
.ll-done__amen li { display: flex; align-items: baseline; gap: 8px; }
.ll-done__amen li::before {
  content: ''; width: 3px; height: 3px; flex: none; border-radius: 50%;
  background: var(--em-accent); transform: translateY(-3px);
}

@media (prefers-reduced-motion: reduce) {
  .ll-rail__th > img, .ll-rail__a, .ll-done__credit a span { transition: none; }
  .ll-rail__b:hover .ll-rail__th > img { transform: none; }
}

/* ————————————————————————— 8 · Detail template —————————————————————————

   Everything below belongs to emaar-launch.html. */

/* The key-facts ladder under the hero. EMAAR publishes these as an icon list
   ("3-5 Bedroom Villas", "Starting Price AED 6.2 Mn"); the icons are a web
   font this bundle does not ship, so the list is set as a ladder of values. */
.ll-facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  gap: clamp(18px, 2.2vw, 30px);
  padding-top: 24px; border-top: 1px solid var(--em-line-rule);
}
.ll-fact__v { font-family: var(--em-display); font-size: clamp(19px, 1.8vw, 23px); line-height: 1.2;
  text-wrap: pretty; }
.ll-fact__k { margin-top: 8px; font-size: 10px; font-weight: 600; letter-spacing: .20em;
  text-transform: uppercase; color: var(--em-ink-eyebrow); }

/* The gallery band. Not a uniform grid: the first frame takes the width and
   the rest fall into a two-up beneath it, so the composition has a subject
   rather than a wallpaper. */
.ll-gal { display: grid; gap: clamp(12px, 1.6vw, 20px); grid-template-columns: 1fr; }
.ll-gal__f { position: relative; display: block; width: 100%; background: var(--em-well);
  border-radius: var(--em-r); overflow: hidden; cursor: zoom-in; }
.ll-gal__f img { display: block; width: 100%; height: 100%; object-fit: cover; }
@media (min-width: 760px) {
  .ll-gal { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ll-gal__f--lead { grid-column: 1 / -1; }
}
@media (min-width: 1100px) {
  .ll-gal { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .ll-gal__f { grid-column: span 2; }
  .ll-gal__f--lead { grid-column: span 6; }
  .ll-gal--3 .ll-gal__f:not(.ll-gal__f--lead) { grid-column: span 3; }
}

/* The availability ladder. Every number here is COUNTED from the published
   unit list on the page it was captured from — never typed, never rounded. */
.ll-units {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  gap: clamp(18px, 2.2vw, 30px);
  padding: clamp(22px, 3vw, 30px);
  background: var(--em-surface); border: 1px solid var(--em-line); border-radius: var(--em-r);
}
.ll-units__v { font-family: var(--em-display); font-size: clamp(22px, 2.2vw, 28px); line-height: 1.06;
  font-variant-numeric: tabular-nums; }
.ll-units__k { margin-top: 8px; font-size: 10px; font-weight: 600; letter-spacing: .20em;
  text-transform: uppercase; color: var(--em-ink-eyebrow); }

/* The closing register band.

   It used to be a night ground, and that was one dark block too many: the
   site footer is also black, so the page ended black — cream — black, with
   the page's tail padding showing as a sliver of ground between the two. The
   footer masthead is ALSO a display line with two buttons on a dark ground,
   so the band was not only a second dark block, it was the same gesture
   twice.

   The band is now the page's last PAPER moment. SAND is the brand's own
   Highlight Colour, and one step down from it gives a band that is plainly a
   plate and not a wash of the ground it sits on. The page then descends
   once — ground, sand, night — and the single drop into black is the footer,
   which is the thing that should end the page.

   The band's own bottom edge meets the footer with nothing between them:
   .em-band--tail in places.css stands down below a full-bleed last child. */
.ll-reg {
  margin-top: clamp(60px, 7.5vw, 104px);
  background: var(--em-sand-band); color: var(--em-ink);
  padding: clamp(56px, 7.5vw, 96px) 0 clamp(60px, 8vw, 104px);
}
.ll-reg__in { display: grid; gap: clamp(26px, 3vw, 44px); grid-template-columns: 1fr;
  align-items: end; }
.ll-reg__h { font-family: var(--em-display); font-size: clamp(30px, 4vw, 54px);
  line-height: 1.06; max-width: 15em; text-wrap: pretty; color: var(--em-ink); }
.ll-reg__in .em-prose { margin-top: 16px; }
.ll-reg__in .em-prose p { color: var(--em-ink-body); }
.ll-reg__acts { display: flex; flex-wrap: wrap; gap: 12px; }

/* On a phone the pair stacks, and two buttons sized to their own labels stack
   ragged — 289px over 202px. Stretched they are one block, which is also how
   the mobile menu sets its own pair. */
@media (max-width: 559px) {
  .ll-reg__acts { flex-direction: column; align-items: stretch; }
}

/* The two-column form waits for 1080px, not 900. The actions column is sized
   to the buttons (auto), not to a fraction, because at 900px a 1fr column is
   narrower than the two buttons and they wrapped into a ragged right-hand
   stack with a hole between them and the words they belong to. */
@media (min-width: 1080px) {
  .ll-reg__in { grid-template-columns: minmax(0, 1fr) auto; column-gap: clamp(40px, 5vw, 80px); }
  .ll-reg__acts { justify-content: flex-end; flex-wrap: nowrap; }
}

/* ————————————————————————— 9 · Motion —————————————————————————

   One addition only, inside the same reduced-motion guard places.css uses.
   The panel itself no longer fades in — on load or on a tab change — since
   content across the site is painted as it is (Brand Growth, 2026-10-01;
   see motion.css). */

@media (prefers-reduced-motion: no-preference) {
  /* Cards appended by Load more animate in from where the button was, so the
     eye is already there. Capped at eight so a long append does not become a
     queue the reader has to wait out. */
  .ll-appear { animation: emItem .55s var(--em-e-card) both;
               animation-delay: calc(min(var(--i, 0), 7) * 55ms); }
}
