/* ===========================================================================
   EMAAR DESIGN SYSTEM · 05 — SHARED COMPONENTS
   The controls every page family needs: buttons, links, breadcrumb, tags,
   icons, and the form system.

   WHAT IS AND IS NOT IN THIS FILE
   -------------------------------
   Here: a component used by MORE THAN ONE page family, whose appearance is
   the brand's rather than the page's.

   Not here, and deliberately so — these already have exactly one
   implementation, and moving them would be churn without a reader noticing:

     component            lives in                     documented in
     ---------------------------------------------------------------------
     Header               places.css §5                docs 02-components
     Mobile dock + sheet  mobile-nav.css               DESIGN-STANDARDS §9
     Footer               site-footer.css              docs 02-components
     Site search drawer   search.css + site-search.js  DESIGN-STANDARDS §3
     Property filter panel search.css + filters-panel.js DESIGN-STANDARDS §3
     Country / dial select ui-select.css + ui-select.js DESIGN-STANDARDS §7
     Card                 places.css §14               docs 02-components
     Modal                places.css §22               docs 02-components
     Accordion (.em-faq)  places.css §18               docs 02-components
     Segments / chips / underline tabs   about.css, launches.css
                                                      DESIGN-STANDARDS §8
     Language picker      lang.css
     Film lightbox        film-modal.css

   Figma mapping: this file plus the table above IS Figma File 02 ·
   Components Library. Naming there follows `Button / Primary`,
   `Input / Error`, `Breadcrumb / Default`, `Tag / Status`.
   =========================================================================== */


/* ###########################################################################
   1 · BUTTONS
   ---------------------------------------------------------------------------
   Six variants, and the variant is chosen by WHERE the button is and WHAT it
   asks for — never by how it should look:

     .em-btn         PRIMARY     ink fill. One per view. The thing to do next.
     .em-btn-o       SECONDARY   ink outline on paper. A real alternative.
     .em-btn-h       TERTIARY    hairline outline. A utility beside content.
     .em-btn-d       ON MEDIA    currentColor outline. Inherits the world it
                                 is dropped into, so one class works on a
                                 photograph, a night band and a light plate.
     .em-btn-inv     PRIMARY on night
     .em-btn-ghost   SECONDARY on night
     .em-cta         TEXT LINK   a tracked label with a rule and an arrow.
                                 Not a button: it goes to a page, it does not
                                 perform an action.

   Shared by all six, and not open to a page:
     · min-height 44px — the target, at every viewport. Not a mobile number.
     · radius var(--em-radius) — 2px, the brand constant. Never a pill.
     · 11px / 600 / uppercase, tracked. The tracking narrows as padding widens
       so the LABEL, not the box, stays the constant.
     · one transition: the ground, at --em-duration-base.

   THE PRIMARY ACTION IS INK, NOT GOLD. Gold marks; it never fills. Gold at
   11px behind dark text is a 1.x:1 relationship at the edges and reads as a
   different brand's button. See DESIGN-STANDARDS.md §1.

   STATES. Every variant has all seven, and none of them is colour alone:
     default   as declared
     hover     the ground moves — a fill lightens, an outline takes the wash
     focus     2px ink ring, 3px offset, from 02-base. Never removed.
     active    the hover ground; no transform (a luxury control does not bounce)
     disabled  [aria-disabled="true"] — .38 opacity + pointer-events: none.
               NEVER the [disabled] attribute: a disabled control cannot take
               focus, so a keyboard user cannot ask why it is off.
     loading   .is-busy — label to transparent, spinner in the same box, so
               the button does not change size and the layout does not jump.
     selected  aria-pressed / aria-current — ink fill + --em-text-inverse.
   ########################################################################### */

.em-btn, .em-btn-o, .em-btn-h, .em-btn-d, .em-btn-inv, .em-btn-ghost {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--em-button-gap);
  box-sizing: border-box; text-align: center; white-space: nowrap;
  min-height: var(--em-button-height);
  font-family: var(--em-font-ui);
  font-size: var(--em-text-label);
  font-weight: var(--p-weight-semi);
  letter-spacing: var(--p-ls-wide);
  text-transform: uppercase;
  border-radius: var(--em-radius);
  padding: 12px var(--em-button-padding-x);
  border: var(--em-border-width) solid transparent;
}

.em-btn {
  background: var(--em-action-primary);
  color: var(--em-action-primary-text);
  border-color: var(--em-action-primary);
  transition: background var(--em-duration-base) ease;
}
.em-btn:hover { background: var(--em-action-primary-hover); color: var(--em-action-primary-text); }

.em-btn-o {
  background: transparent;
  color: var(--em-text-primary);
  border-color: var(--em-action-secondary-border);
  letter-spacing: var(--p-ls-label);
  padding: 12px 24px;
  transition: background var(--em-duration-base) ease, color var(--em-duration-base) ease;
}
.em-btn-o:hover { background: var(--em-action-wash); }

.em-btn-h {
  background: transparent;
  color: var(--em-text-primary);
  border-color: var(--em-action-tertiary-border);
  letter-spacing: var(--p-ls-label);
  padding: 12px var(--space-16);
  transition: background var(--em-duration-base) ease, border-color var(--em-duration-base) ease;
}
.em-btn-h:hover {
  border-color: var(--em-action-secondary-border);
  background: var(--em-action-wash);
  color: var(--em-text-primary);
}

/* currentColor, so one declaration serves a photograph, a night band and a
   light plate. The wash is grey at 14% for the same reason: it darkens on
   paper and lightens on night from the same rule. */
.em-btn-d {
  background: transparent; color: currentColor; border-color: currentColor;
  letter-spacing: var(--p-ls-ui);
  padding: 9px 18px;
  transition: background var(--em-duration-base) ease;
}
.em-btn-d:hover { background: var(--em-action-wash); color: currentColor; }

.em-btn-inv {
  background: var(--em-text-on-inverse);
  color: var(--em-bg-inverse);
  border-color: var(--em-text-on-inverse);
  letter-spacing: var(--p-ls-label);
  padding: 15px 30px;
  transition: opacity var(--em-duration-base) ease;
}
.em-btn-inv:hover { opacity: .85; color: var(--em-bg-inverse); }

.em-btn-ghost {
  background: transparent;
  color: var(--em-text-on-inverse);
  border-color: var(--em-border-on-inverse-strong);
  letter-spacing: var(--p-ls-label);
  padding: 15px 30px;
  transition: background var(--em-duration-base) ease;
}
.em-btn-ghost:hover { background: var(--em-action-wash); color: var(--em-text-on-inverse); }

/* Size and width modifiers — the only two, and they apply to every variant. */
.em-btn--lg {
  padding: 16px var(--em-button-padding-x-lg);
  font-size: var(--em-text-caption);
  letter-spacing: var(--p-ls-wider);
}
.em-btn--block { width: 100%; }

/* An icon inside a button is 14px and never optical-centres itself: `flex:
   none` so a long label cannot squeeze it, `display:block` so it has no
   baseline gap under it. */
.em-btn svg, .em-btn-o svg, .em-btn-h svg, .em-btn-d svg,
.em-btn-inv svg, .em-btn-ghost svg {
  width: var(--em-icon-sm); height: var(--em-icon-sm);
  display: block; flex: none;
}

/* Loading. The label goes transparent and the spinner takes the same box, so
   the control keeps its width and nothing below it moves. */
.em-btn.is-busy, .em-btn-o.is-busy, .em-btn-inv.is-busy {
  position: relative; pointer-events: none; color: transparent;
}
.em-btn__spin {
  position: absolute; inset: 0; display: none;
  align-items: center; justify-content: center;
}
.is-busy > .em-btn__spin { display: flex; }
.em-btn__spin::before {
  content: ""; width: var(--em-icon-sm); height: var(--em-icon-sm);
  border-radius: var(--em-radius-circle);
  border: 1.5px solid currentColor; border-top-color: transparent;
  color: var(--em-action-primary-text);
  animation: emBtnSpin .7s linear infinite;
}
.em-btn-o .em-btn__spin::before,
.em-btn-h .em-btn__spin::before { color: var(--em-text-primary); }
@keyframes emBtnSpin { to { transform: rotate(360deg); } }

/* An icon-only control. Square, 44px, and it MUST carry an aria-label —
   there is no visible text to read. */
.em-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--em-icon-button-size); height: var(--em-icon-button-size);
  flex: none;
  border: var(--em-border-width) solid transparent;
  border-radius: var(--em-radius);
  color: var(--em-text-primary);
  transition: background var(--em-duration-base) ease, border-color var(--em-duration-base) ease;
}
.em-icon-btn:hover { background: var(--em-action-wash); }
.em-icon-btn--outlined { border-color: var(--em-action-tertiary-border); }
.em-icon-btn svg { width: var(--em-icon-md); height: var(--em-icon-md); display: block; }


/* ———————————————————————— 2 · The text link ————————————————————————

   A tracked label with a rule under it and an arrow after it. It NAVIGATES;
   it does not act. Inside a whole-card link it is a <span>, never a nested
   <a>. */

.em-cta {
  display: inline-flex; align-items: center; gap: var(--space-8);
  min-height: var(--em-control-min);
  font-family: var(--em-font-ui);
  font-size: var(--em-text-label);
  font-weight: var(--p-weight-semi);
  letter-spacing: .17em;
  text-transform: uppercase;
  color: inherit;
  transition: opacity var(--em-duration-base) ease;
}
.em-cta__l { border-bottom: var(--em-border-width) solid currentColor; padding-bottom: 3px; }
.em-cta__a { transition: transform var(--em-duration-base) var(--em-ease-soft); }
.em-cta:hover { opacity: .62; color: inherit; }
.em-cta:hover .em-cta__a,
a:hover > .em-cta .em-cta__a,
.em-card:hover .em-cta__a { transform: translateX(4px); }
.em-cta--micro { font-size: var(--em-text-label-xs); letter-spacing: var(--p-ls-ui); min-height: 0; }
.em-cta--dark  { color: var(--em-text-on-inverse); }


/* ———————————————————————— 3 · Breadcrumb ————————————————————————

   Every internal page opens with one. Each link is a 44px target even though
   the type is 11px — the height comes from min-height on the <a>, so the row
   still measures 11px of type and the crumb gap below it is unaffected.

   It wraps, and a wrapped crumb never starts a line with its separator: the
   "/" is drawn by the crumb it follows, not laid beside it. See below. */

.em-crumb {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--em-crumb-gap);
  font-family: var(--em-font-ui);
  font-size: var(--em-text-label);
  font-weight: var(--p-weight-semi);
  letter-spacing: var(--p-ls-wide);
  text-transform: uppercase;
  color: var(--em-text-muted);
}
.em-crumb a {
  color: var(--em-text-eyebrow);
  display: inline-flex; align-items: center;
  min-height: var(--em-control-min);
  transition: color var(--em-duration-base) ease;
}
/* The back arrow the first crumb carries. This spacing was the link's own flex
   `gap`, which since the separator moved inside the link (below) would land in
   front of that too and hold it 8px closer on one side than the other. It was
   only ever the arrow's, so it is stated on the arrow. */
.em-crumb a > [aria-hidden="true"] { margin-inline-end: var(--space-8); }
.em-crumb a:hover { color: var(--em-text-primary); }
.em-crumb [aria-current="page"] { color: var(--em-text-muted); }

/* The separator belongs to the crumb it follows, not to the row.

   It used to be its own flex item, so a wrap could break between a link and
   the "/" after it and leave a lone slash at the head of the next line — the
   longest crumb in the build did exactly that at 375. Drawn as the preceding
   item's ::after it is inside that item's box, and no break can fall between
   them. Attaching it to the FOLLOWING item would only move the problem: the
   slash would lead the new line instead of ending the old one.

   The <span class="em-crumb__sep"> stays in the markup and is hidden here.
   Five builders emit it (§16 names them) and none had to change: the fix
   lands on every page that already links this file, and the component keeps
   one definition.

   The slash is decorative — the span it replaces carried aria-hidden. The
   second `content` gives it empty alternative text so it stays out of the
   link's accessible name; the first is the fallback for a browser that does
   not take that syntax, where a spoken slash beats no separator at all.
   Its colour is stated rather than inherited so it does not follow the link
   into hover, and so it reads as the row's muted ink on either ground. */
.em-crumb__sep { display: none; }
.em-crumb > :not(.em-crumb__sep):not(:last-child)::after {
  content: "/";
  content: "/" / "";
  margin-inline-start: var(--em-crumb-gap);
  color: var(--em-text-muted);
  opacity: .5;
}

.em-crumb--dark { color: var(--em-text-on-inverse-70); }
.em-crumb--dark a { color: var(--em-text-on-inverse-80); }
.em-crumb--dark a:hover { color: var(--p-brand-white); }
.em-crumb--dark [aria-current="page"] { color: var(--em-text-on-inverse-70); }
.em-crumb--dark > :not(.em-crumb__sep):not(:last-child)::after { color: var(--em-text-on-inverse-70); }


/* ———————————————————————— 4 · Tag / status badge ————————————————————————

   On a photograph it is `.em-badge` (places.css §14) — a blurred plate,
   because a flat chip on a bright picture cannot hold its contrast.
   On paper it is `.em-tag`, below: the cream pair, never gold. */

.em-tag {
  display: inline-flex; align-items: center; gap: var(--space-6);
  padding: 6px var(--space-10);
  background: var(--em-surface-filled);
  color: var(--em-text-primary);
  border-radius: var(--em-radius);
  font-family: var(--em-font-ui);
  font-size: var(--em-text-label-sm);
  font-weight: var(--p-weight-semi);
  letter-spacing: var(--p-ls-wider);
  text-transform: uppercase;
  white-space: nowrap;
}
.em-tag--outline {
  background: transparent;
  border: var(--em-border-width) solid var(--em-border-control);
}
/* Status is carried by a mark AND a word, never by colour alone. */
.em-tag__dot { width: 6px; height: 6px; border-radius: var(--em-radius-circle); flex: none; }
.em-tag--success .em-tag__dot { background: var(--em-status-success); }
.em-tag--warning .em-tag__dot { background: var(--em-status-warning); }
.em-tag--error   .em-tag__dot { background: var(--em-status-error); }


/* ###########################################################################
   5 · FORM CONTROLS
   ---------------------------------------------------------------------------
   `.em-form` is the site's form system. It already existed — inside
   `places.css` §22, where it was filed under "Enquiry modal" and therefore
   read as the modal's private styling. It is not: it is a label, a field, an
   error line, a two-up row, a consent checkbox and a legal note, which is
   every form this site has. It is promoted here unchanged and generalised
   from `input` to `input, select, textarea`.

   The other four families each styled the same control again — `page.css`
   (18 rules), `search.css` (16), `booking.css` (its own `.bk-*` fields),
   `site-footer.css` (the newsletter field). Five heights, five borders, five
   focus treatments, for one control. Those are NOT force-migrated in this
   batch: each is inside a page that has been measured and signed off, and a
   blind sweep would move fields on pages nobody asked to change. They adopt
   this system when next touched. See docs/design-system/05-migration.md.

   THE SHAPE
     height        44px, the site's control minimum
     radius        2px, like everything else
     resting edge  --em-border-strong. This is the line that IDENTIFIES the
                   control, so it is the lightest alpha that still clears 3:1
                   on the ground, the dialog surface and the sunk well alike.
                   (It was rgba(17,17,17,.42) here and .46 in the booking
                   journey — two spellings of one line. Now one: .46.)
     label         10px/600, tracked, ABOVE the field, always. Never a
                   placeholder-as-label: a placeholder disappears the moment
                   the reader types, and takes the question with it.
     focus         the ink ring AND the edge darkening — two signals, so the
                   state never rests on colour alone.
     error         aria-invalid on the control, a message in .em-form__err
                   wired with aria-describedby, and a darker edge. The error
                   line reserves its own height so the form does not jump
                   when a message appears.
   ########################################################################### */

.em-form { display: flex; flex-direction: column; gap: var(--em-field-gap); }
/* A field group, where a label / control / error need to be addressed as a
   unit — inside a grid row, or where the form is not a <form class="em-form">. */
.em-field { display: flex; flex-direction: column; }

/* `:not(.em-form__check)` is the whole rule. A consent checkbox's label IS a
   <label>, so `.em-form label` (0,1,1) was beating `.em-form__check` (0,1,0)
   and the enquiry modal's consent line — "Keep me updated on launches and
   news" — rendered as a 10px uppercase field label in eyebrow ink, laid out
   as a block, with the checkbox above it instead of beside it. On every page
   that carries the modal. A field label and a control's own label are two
   different things and must not share a selector. */
.em-form label:not(.em-form__check):not(.em-check):not(.em-radio),
.em-label-field {
  display: block;
  font-family: var(--em-font-ui);
  font-size: var(--em-text-label-sm);
  font-weight: var(--p-weight-semi);
  letter-spacing: var(--p-ls-wider);
  text-transform: uppercase;
  color: var(--em-text-eyebrow);
  margin-bottom: var(--em-field-label-gap);
}
.em-label-field__req { color: var(--em-status-error); margin-left: 3px; }

.em-form input,
.em-form select,
.em-form textarea,
.em-input, .em-select, .em-textarea {
  width: 100%; box-sizing: border-box;
  background: transparent;
  color: var(--em-text-primary);
  border: var(--em-border-width) solid var(--em-border-strong);
  border-radius: var(--em-radius);
  padding: 13px var(--em-input-padding-x);
  font-family: var(--em-font-body);
  font-size: var(--em-text-body-md);
  line-height: var(--p-lh-body);
  min-height: var(--em-input-height);
  transition: border-color var(--em-duration-base) ease;
}
.em-form textarea, .em-textarea { min-height: 128px; resize: vertical; }

.em-form input::placeholder,
.em-form textarea::placeholder,
.em-input::placeholder, .em-textarea::placeholder { color: var(--em-text-muted); }

/* Two signals on focus: the ring, and the edge. The ring is offset 2 rather
   than the global 3 because a field's own border is already a ring. */
.em-form input:focus-visible,
.em-form select:focus-visible,
.em-form textarea:focus-visible,
.em-input:focus-visible, .em-select:focus-visible, .em-textarea:focus-visible {
  border-color: var(--em-text-primary);
  outline: var(--em-focus-ring-width) solid var(--em-focus-ring);
  outline-offset: 2px;
}

.em-form input[aria-invalid="true"],
.em-form select[aria-invalid="true"],
.em-form textarea[aria-invalid="true"],
[aria-invalid="true"].em-input,
[aria-invalid="true"].em-select,
[aria-invalid="true"].em-textarea { border-color: var(--em-status-error); }

.em-form input:disabled, .em-form select:disabled, .em-form textarea:disabled,
.em-input:disabled, .em-select:disabled, .em-textarea:disabled {
  opacity: var(--em-action-disabled-opacity);
  background: var(--em-surface-sunk);
  cursor: not-allowed;
}

/* The native chevron is drawn by the OS and is the one piece of a form that
   cannot be made to match across Safari, Chrome and Firefox. An inline
   SVG data-URI in the ink colour is the only way to get one arrow. */
.em-form select, .em-select {
  appearance: none; -webkit-appearance: none;
  padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5 6 6.5l5-5' stroke='%23111112' stroke-width='1.4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}

/* The error line RESERVES its height, so a message appearing does not push
   the rest of the form down. role="alert" on the element, aria-describedby
   on the control. */
.em-form__err, .em-error {
  display: block; min-height: 14px; margin-top: 5px;
  font-size: var(--em-text-caption);
  line-height: 1.2;
  color: var(--em-status-error);
}
.em-help {
  display: block; margin-top: 5px;
  font-size: var(--em-text-caption);
  line-height: var(--p-lh-snug);
  color: var(--em-text-muted);
}

/* A row of fields. Flex, not grid, because the country-code cell is sized by
   its own value and the field beside it takes the rest — a grid track would
   have to be given a number nobody can defend. */
.em-form__row { display: flex; gap: var(--space-10); }
.em-form__row .em-form__cc { flex: 0 0 auto; width: auto; min-width: 104px; }
.em-form__row input { flex: 1; min-width: 0; }
/* Equal columns, where the fields genuinely are peers. */
@media (min-width: 1024px) {
  .em-form__row--2 > * { flex: 1 1 0; min-width: 0; }
}

/* Country code: the shared EmaarUI.select (ui-select.css) hosted at
   .em-form__cc — DESIGN-STANDARDS.md §7. Re-skinned to this form's border and
   outline-style focus; NOT forked. */
.em-form__cc.sel .sel__btn {
  border-color: var(--em-border-strong);
  min-height: var(--em-input-height);
  padding: 13px var(--em-input-padding-x);
  font-size: var(--em-text-body-md);
}
.em-form__cc.sel .sel__btn:focus-visible,
.em-form__cc.sel.is-open .sel__btn {
  border-color: var(--em-text-primary);
  outline: var(--em-focus-ring-width) solid var(--em-focus-ring);
  outline-offset: 2px;
  box-shadow: none;
}

/* Checkbox and radio. The NATIVE control is kept and re-skinned with
   accent-color rather than replaced with a <span>: a replaced checkbox loses
   its role, its keyboard behaviour and its forced-colors rendering, and this
   site has no visual requirement that would justify any of that. */
.em-form__check, .em-check, .em-radio {
  display: flex; align-items: flex-start; gap: 11px;
  font-size: var(--em-text-body-sm);
  line-height: var(--p-lh-body);
  color: var(--em-text-body);
}
.em-form__check input, .em-check input, .em-radio input {
  width: 16px; height: 16px; min-height: 0; flex: none;
  margin-top: 2px;
  accent-color: var(--em-action-primary);
  cursor: pointer;
}

.em-form__legal { font-size: var(--em-text-meta); line-height: var(--p-lh-body); color: var(--em-text-muted); }
.em-form__legal a { color: var(--em-text-secondary); text-decoration: underline; }
.em-form__foot  { font-size: var(--em-text-caption); color: var(--em-text-muted); text-align: center; }


/* ———————————————————————— 6 · Icons ————————————————————————

   ONE icon language: line icons, drawn on a 24-unit box, stroke 1.2, round
   caps and joins, `fill: none`, `stroke: currentColor`. No filled set, no
   second library, no brand marks used as icons.

   Four sizes. An icon that needs a fifth is an illustration, and belongs in
   an <img> or a figure, not in the icon system.                            */

.em-icon {
  width: var(--em-icon-md); height: var(--em-icon-md);
  display: block; flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: var(--em-icon-stroke);
  stroke-linecap: round;
  stroke-linejoin: round;
}
.em-icon--xs { width: var(--em-icon-xs); height: var(--em-icon-xs); }
.em-icon--sm { width: var(--em-icon-sm); height: var(--em-icon-sm); }
.em-icon--lg { width: var(--em-icon-lg); height: var(--em-icon-lg); stroke-width: 1.1; }
/* A decorative icon beside a word its label already carries must be hidden
   from the reader, not read twice. Markup: aria-hidden="true" focusable="false". */
