/*
 * Shared design tokens for every Andjenie code component.
 *
 * Code components render in a shadow root, so Webflow's class styles don't
 * reach them, but custom properties and inherited values (font-family,
 * lang, dir) do. Each token resolves in this order:
 *   1. --ajb-*            component-specific override (a Webflow variable or
 *                         a custom property on a parent class)
 *   2. --font-display /   site-wide Webflow variables, if the site defines them
 *      --font-body
 *   3. safe fallback      body text inherits the page font; display text falls
 *                         back to a serif stack of locally installed fonts.
 * No font files are loaded here.
 */

.ajb-featured,
.ajb-property-card,
.ajb-about,
.ajb-footer,
.ajb-consult,
.ajb-project,
.ajb-ap,
.ajb-po,
.ajb-ev,
.ajb-nav {
  /* Palette. Site-wide overrides via --ajb-color-* Webflow variables. */
  --_brown: var(--ajb-color-brown, #1c1410);
  --_cream: var(--ajb-color-cream, #f4ede2);
  --_gold: var(--ajb-color-gold, #b99a68);
  --_gold-text: var(--ajb-color-gold-text, #8f7247);

  /* Semantic colours. FeaturedProjectsSection sets --featured-* and --card-*
     from its Webflow colour props on its own root; they inherit into its
     cards. The same properties can be set on any parent class in Webflow
     (e.g. around a standalone PropertyCard). Unset, they fall back to the
     palette above. */
  --_bg: var(--featured-bg, var(--_cream));
  --_heading: var(--featured-heading, var(--_brown));
  --_subtitle: var(--featured-subtitle, var(--ajb-color-muted, #75665a));
  --_eyebrow: var(--featured-eyebrow, var(--_gold-text));
  --_accent: var(--featured-accent, var(--_gold));
  --_divider: var(--featured-divider, var(--_accent));

  --_card-overlay: var(--card-overlay, #140e0b);
  --_card-title: var(--card-title, var(--_cream));
  --_card-location: var(
    --card-location,
    color-mix(in srgb, var(--_cream) 72%, transparent)
  );
  --_card-price: var(--card-price, var(--_accent));
  --_card-cta: var(--card-cta, var(--_cream));
  --_card-border: var(
    --card-border,
    color-mix(in srgb, var(--_cream) 14%, transparent)
  );
  --_card-shadow: var(--card-shadow, #251812);

  /* Type. --_font-body has no final fallback on purpose: when neither
     variable is set, `font-family: var(--_font-body)` is invalid at computed
     time and falls back to inherit, i.e. the Webflow page's body font. */
  /* Display serif: explicit variables first, then the site's own h2 font
     (detected by the section components as --_site-display), then an
     editorial stack that avoids Georgia/Times wherever a better serif is
     installed (Didot/Bodoni on Apple, Sitka on Windows, Noto on Android). */
  --_font-display: var(
    --ajb-font-display,
    var(
      --font-display,
      var(
        --_site-display,
        "Cormorant Garamond",
        "Cormorant",
        "Playfair Display",
        "Bodoni Moda",
        "Bodoni 72",
        Didot,
        "Sitka Heading",
        "Noto Serif Display",
        Georgia,
        serif
      )
    )
  );
  --_font-body: var(--ajb-font-body, var(--font-body));

  /* Eyebrows, locations and CTAs share one small-caps voice. */
  --_label-size: 0.6875rem;
  --_label-weight: 500;
  --_label-tracking: 0.2em;

  /* Motion: calm expo-out, never springy. */
  --_ease: cubic-bezier(0.22, 1, 0.36, 1);
  --_ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --_dur: 700ms;
  --_dur-slow: 800ms;

  font-family: var(--_font-body);
}

/* Arabic-script locales: letter-spacing breaks the joins between letters
   and there is no uppercase, so labels drop both. */
:is(
  .ajb-featured,
  .ajb-property-card,
  .ajb-about,
  .ajb-footer,
  .ajb-consult,
  .ajb-project,
  .ajb-ap,
  .ajb-po,
  .ajb-ev,
  .ajb-nav
):is(:lang(ar), :lang(fa), :lang(ur)) {
  --_label-tracking: 0;
}

:is(
    .ajb-featured,
    .ajb-property-card,
    .ajb-about,
    .ajb-footer,
    .ajb-consult,
    .ajb-project,
    .ajb-ap,
    .ajb-po,
    .ajb-ev,
    .ajb-nav
  ):is(:lang(ar), :lang(fa), :lang(ur))
  * {
  letter-spacing: 0;
}

/*
 * FeaturedProjectsSection
 * Colours, fonts and motion come from ./tokens.css, shared with
 * PropertyCard, so one set of Webflow variables themes both. Breakpoints are
 * container queries on the section. The section itself is full-bleed, so
 * in practice they track the viewport.
 */

.ajb-featured {
  /* Content width on large screens, excluding the side padding. */
  --_max: var(--ajb-container-max, 90rem);
  --_pad-x: clamp(1.5rem, 4cqi, 4.5rem);
  --_ease-reveal: cubic-bezier(0.16, 1, 0.3, 1);

  container-type: inline-size;
  position: relative;
  isolation: isolate;
  display: block;
  /* Full-bleed: break out of whatever Webflow container holds the component
     so the background runs edge to edge. The CSS fallback assumes a
     centred parent; the component then sets --_bleed-left/right to the exact
     offsets (scrollbar excluded) so there is never horizontal overflow. With
     width auto, the two negative margins alone decide the width, in LTR and
     RTL alike. */
  width: auto;
  max-width: none;
  margin-left: var(--_bleed-left, calc(50% - 50vw));
  margin-right: var(--_bleed-right, calc(50% - 50vw));
  align-self: stretch;
  /* No overflow clipping here: it would cut off the card shadows. The
     full-bleed margins already prevent horizontal overflow. */
  box-sizing: border-box;
  background: var(--_bg);
  color: var(--_heading);
  color-scheme: light;
}

.ajb-featured *,
.ajb-featured *::before,
.ajb-featured *::after {
  box-sizing: border-box;
}

/* Centred content container: the background is full-bleed, the content
   is not. */
.ajb-featured__inner {
  --_gap: clamp(1.25rem, 2.6cqi, 2.5rem);

  position: relative;
  z-index: 1;
  max-width: calc(var(--_max) + 2 * var(--_pad-x));
  margin-inline: auto;
  /* Top is tighter than the bottom so the section opens with the intro
     rather than empty space (~81px at 1440px, ~52px on phones). */
  padding: clamp(3.25rem, 5.6cqi, 5.75rem) var(--_pad-x)
    clamp(5rem, 11cqi, 10rem);
}

/* ---------- Intro ---------- */

.ajb-featured__intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 0 auto clamp(2.75rem, 5cqi, 4.75rem);
  text-align: center;
}

.ajb-featured__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 1.125rem;
  margin: 0 0 clamp(0.625rem, 1cqi, 0.875rem);
  font-size: clamp(var(--_label-size), 0.9cqi, 0.75rem);
  font-weight: var(--_label-weight);
  letter-spacing: calc(var(--_label-tracking) * 1.4);
  line-height: 1;
  text-transform: uppercase;
  color: var(--_eyebrow);
}

/* Hairlines either side of the eyebrow. The trailing margin offsets the
   letter-spacing so the text sits optically centered. */
.ajb-featured__eyebrow::before,
.ajb-featured__eyebrow::after {
  content: "";
  width: clamp(1.5rem, 4cqi, 2.75rem);
  height: 1px;
  background: var(--_divider);
  opacity: 0.7;
}

.ajb-featured__eyebrow::after {
  margin-inline-start: calc(var(--_label-tracking) * -1.4);
}

/* Magazine-style headline: a light, high-contrast display serif, set tight,
   with a narrow measure so longer translations break into a balanced
   shape rather than one long line. */
.ajb-featured__heading {
  max-width: 16ch;
  margin: 0;
  font-family: var(--_font-display);
  font-size: clamp(2.75rem, 5.6cqi, 4.5rem);
  /* Light where the face has it; falls back to regular without faking. */
  font-weight: 300;
  font-synthesis: none;
  font-optical-sizing: auto;
  letter-spacing: -0.028em;
  line-height: 1.02;
  color: var(--_heading);
  text-wrap: balance;
  font-kerning: normal;
  font-feature-settings:
    "kern" 1,
    "liga" 1;
  transition:
    opacity 700ms var(--_ease-reveal),
    transform 700ms var(--_ease-reveal);
}

/* *Word* in the heading: the face's true italic, a touch warmer. If the
   font has no italic it stays upright (font-synthesis: none) rather than
   being slanted artificially. */
.ajb-featured__heading-em {
  font-style: italic;
  letter-spacing: -0.012em;
  color: color-mix(in srgb, var(--_heading) 78%, var(--_accent));
  /* Room for the italic overhang at the end of the word. */
  padding-inline-end: 0.04em;
}

:is(:lang(ar), :lang(fa), :lang(ur), :lang(he)) .ajb-featured__heading-em {
  font-style: normal;
}

/* The single accent: a short, thin gold line that draws out from the
   centre on reveal. */
.ajb-featured__ornament {
  display: block;
  width: clamp(2.625rem, 3.6cqi, 3.75rem);
  height: 1px;
  margin: clamp(1rem, 1.5cqi, 1.25rem) auto clamp(1.125rem, 1.7cqi, 1.5rem);
  background: var(--_divider);
  opacity: 0.7;
  transition:
    transform 800ms var(--_ease-in-out) 250ms,
    opacity 800ms var(--_ease) 250ms;
}

.ajb-featured__subtitle {
  max-width: 35rem;
  margin: 0;
  font-size: clamp(0.90625rem, 1cqi, 0.9375rem);
  font-weight: 300;
  letter-spacing: 0.015em;
  line-height: 1.85;
  color: var(--_subtitle);
  text-wrap: balance;
  transition:
    opacity 700ms var(--_ease-reveal) 280ms,
    transform 700ms var(--_ease-reveal) 280ms;
}

/* Reveal: hidden only after JS confirms the intro is below the fold. The
   heading rises first, the gold line draws, then the subtitle follows. */
.ajb-featured__intro[data-reveal="pending"] .ajb-featured__heading,
.ajb-featured__intro[data-reveal="pending"] .ajb-featured__subtitle {
  opacity: 0;
  transform: translate3d(0, 12px, 0);
}

.ajb-featured__intro[data-reveal="pending"] .ajb-featured__ornament {
  opacity: 0;
  transform: scaleX(0);
}

@media (prefers-reduced-motion: reduce) {
  .ajb-featured__heading,
  .ajb-featured__subtitle {
    transition: opacity 400ms linear;
  }

  .ajb-featured__subtitle {
    transition-delay: 150ms;
  }

  .ajb-featured__intro[data-reveal="pending"] .ajb-featured__heading,
  .ajb-featured__intro[data-reveal="pending"] .ajb-featured__subtitle {
    transform: none;
  }

  .ajb-featured__ornament {
    transition: opacity 400ms linear 150ms;
  }

  .ajb-featured__intro[data-reveal="pending"] .ajb-featured__ornament {
    transform: none;
  }
}

/* ---------- Grid ---------- */

/* Flex rather than grid so a lone last card (tablet) centers instead of
   stretching into a landscape crop. */
.ajb-featured__grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--_gap);
}

.ajb-featured__cell {
  display: flex;
  flex: 0 1 100%;
  max-width: 28rem;
}

@container (min-width: 700px) {
  .ajb-featured__cell {
    flex-basis: calc((100% - var(--_gap)) / 2);
    max-width: none;
  }
}

@container (min-width: 1100px) {
  .ajb-featured__cell {
    flex-basis: calc((100% - 2 * var(--_gap)) / 3);
  }
}

/*
 * PropertyCard
 * Colours, fonts and motion come from ./tokens.css; every token can be
 * overridden from Webflow (site variables or a parent class) because custom
 * properties inherit into the component's shadow root.
 */

.ajb-property-card {
  --_radius: var(--ajb-card-radius, 1.25rem);
  --_aspect: var(--ajb-card-aspect, 5 / 6);
  /* Lift and shadow share one calm curve. */
  --_dur-card: 650ms;
  --_ease-card: cubic-bezier(0.25, 0.8, 0.25, 1);

  container-type: inline-size;
  position: relative;
  display: block;
  width: 100%;
  border-radius: var(--_radius);
  color: var(--_card-title);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  /* This outer element is the dedicated shadow wrapper: two layered
     warm-brown shadows (a tighter one for definition, a wide one for lift)
     and the hover lift. It never clips; only the inner shell uses
     overflow: hidden, so the image is cropped but the shadow is not. */
  overflow: visible;
  box-shadow:
    0 12px 28px color-mix(in srgb, var(--_card-shadow) 12%, transparent),
    0 30px 70px color-mix(in srgb, var(--_card-shadow) 18%, transparent);
  transform: translate3d(0, 0, 0);
  transition:
    transform var(--_dur-card) var(--_ease-card),
    box-shadow var(--_dur-card) var(--_ease-card);
}

.ajb-property-card:focus-visible {
  outline: 1px solid var(--_accent);
  outline-offset: 6px;
}

/* ---------- Shell ----------
   The only element in the card that clips: it rounds and crops the image
   and overlay. The outer card (the shadow wrapper) stays overflow: visible
   so its shadow is never cut off. */

.ajb-property-card__shell {
  position: relative;
  aspect-ratio: var(--_aspect);
  overflow: hidden;
  border-radius: inherit;
  background-color: var(--_card-overlay);
  /* Keeps rounded corners clipped while the image transforms (Safari). */
  isolation: isolate;
  transform: translateZ(0);
}

/* Crop to the card's own width, not the viewport, so it looks right in any
   Webflow grid column. */
@container (min-width: 560px) {
  .ajb-property-card__shell {
    aspect-ratio: 5 / 4;
  }
}

@container (min-width: 860px) {
  .ajb-property-card__shell {
    aspect-ratio: 16 / 9;
  }
}

.ajb-property-card__image,
.ajb-property-card__placeholder {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.ajb-property-card__image {
  display: block;
  max-width: none;
  object-fit: cover;
  object-position: 50% 45%;
  transform: scale(1.04) translate3d(0, 0, 0);
  transform-origin: 50% 60%;
  transition:
    transform var(--_dur-slow) var(--_ease),
    filter var(--_dur-slow) var(--_ease);
  will-change: transform;
}

.ajb-property-card__placeholder {
  background:
    radial-gradient(
      120% 80% at 70% 20%,
      color-mix(in srgb, var(--_accent) 18%, transparent),
      transparent 60%
    ),
    var(--_card-overlay);
}

.ajb-property-card__overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    to top,
    color-mix(in srgb, var(--_card-overlay) 86%, transparent) 0%,
    color-mix(in srgb, var(--_card-overlay) 50%, transparent) 32%,
    color-mix(in srgb, var(--_card-overlay) 8%, transparent) 62%,
    transparent 100%
  );
  transition: opacity var(--_dur) var(--_ease);
}

/* Faint inset hairline that settles in on hover. */
.ajb-property-card__frame {
  position: absolute;
  inset: 0.75rem;
  border: 1px solid var(--_card-border);
  border-radius: calc(var(--_radius) - 0.5rem);
  pointer-events: none;
  opacity: 0;
  transform: scale(1.015);
  transition:
    opacity var(--_dur) var(--_ease),
    transform var(--_dur) var(--_ease);
}

/* ---------- Content ---------- */

.ajb-property-card__content {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 1;
  padding: clamp(1.25rem, 7cqi, 2.5rem);
  transform: translate3d(0, 0, 0);
  transition: transform var(--_dur) var(--_ease);
}

.ajb-property-card__location {
  margin: 0 0 0.75rem;
  font-size: clamp(var(--_label-size), 2.6cqi, 0.8125rem);
  font-weight: 400;
  letter-spacing: calc(var(--_label-tracking) * 1.1);
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--_card-location);
  transition:
    color var(--_dur) var(--_ease),
    transform var(--_dur) var(--_ease);
}

.ajb-property-card__title {
  margin: 0;
  max-width: 18ch;
  font-family: var(--_font-display);
  font-size: clamp(1.625rem, 8cqi, 2.75rem);
  font-weight: 400;
  letter-spacing: -0.01em;
  line-height: 1.04;
  color: var(--_card-title);
  text-wrap: balance;
}

.ajb-property-card__rule {
  display: block;
  width: 3.5rem;
  height: 1px;
  margin: clamp(1rem, 4.5cqi, 1.5rem) 0;
  background-color: var(--_divider);
  transform: scaleX(0.3);
  transform-origin: left center;
  opacity: 0.55;
  transition:
    transform var(--_dur-slow) var(--_ease-in-out) 60ms,
    opacity var(--_dur-slow) var(--_ease) 60ms;
}

.ajb-property-card__rule:dir(rtl) {
  transform-origin: right center;
}

/* Footer row: price at the start, CTA at the end, on every card. It never
   wraps, so title or price length can't push the CTA onto its own line; an
   unusually long price wraps inside its own column instead.
   The content block is anchored to the bottom of the card, so the footer
   always sits at the same distance from the bottom edge. In RTL locales the
   row mirrors automatically. */
.ajb-property-card__footer {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: clamp(0.75rem, 4cqi, 1rem);
}

.ajb-property-card__price {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--_font-display);
  font-size: clamp(0.9375rem, 4.6cqi, 1.375rem);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.2;
  color: var(--_card-price);
  font-variant-numeric: lining-nums;
  text-wrap: balance;
}

/* The CTA is always in the layout; only its inner line is masked, so the
   reveal never shifts anything around it. */
.ajb-property-card__cta {
  display: block;
  flex: none;
  /* Stays at the end of the row even when a card has no price. */
  margin-inline-start: auto;
  overflow: hidden;
  white-space: nowrap;
  /* Tightens slightly on the narrowest 3-column cards so the row fits. */
  font-size: clamp(0.625rem, 3.1cqi, var(--_label-size));
  font-weight: var(--_label-weight);
  letter-spacing: var(--_label-tracking);
  line-height: 1.6;
  text-transform: uppercase;
  color: var(--_card-cta);
}

.ajb-property-card__cta-inner {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  transform: translate3d(0, 110%, 0);
  opacity: 0;
  transition:
    transform var(--_dur) var(--_ease) 120ms,
    opacity var(--_dur) var(--_ease) 120ms;
}

.ajb-property-card__arrow {
  flex: none;
  width: 1.125rem;
  height: 0.5625rem;
  fill: none;
  stroke: var(--_accent);
  stroke-width: 1;
  transform: translate3d(-4px, 0, 0);
  transition: transform var(--_dur) var(--_ease) 180ms;
}

/* Point the arrow the reading direction. `scale` composes after
   `transform`, so the hover nudge mirrors too. */
.ajb-property-card__arrow:dir(rtl) {
  scale: -1 1;
}

/* ---------- Hover / focus ---------- */

@media (hover: hover) and (pointer: fine) {
  .ajb-property-card:hover,
  .ajb-property-card:focus-visible {
    transform: translate3d(0, -6px, 0);
    box-shadow:
      0 18px 38px color-mix(in srgb, var(--_card-shadow) 16%, transparent),
      0 38px 90px color-mix(in srgb, var(--_card-shadow) 24%, transparent);
  }

  .ajb-property-card:hover .ajb-property-card__image,
  .ajb-property-card:focus-visible .ajb-property-card__image {
    transform: scale(1.09) translate3d(0, -1.25%, 0);
    filter: brightness(0.9);
  }

  .ajb-property-card:hover .ajb-property-card__frame,
  .ajb-property-card:focus-visible .ajb-property-card__frame {
    opacity: 1;
    transform: scale(1);
  }

  .ajb-property-card:hover .ajb-property-card__content,
  .ajb-property-card:focus-visible .ajb-property-card__content {
    transform: translate3d(0, -0.375rem, 0);
  }

  .ajb-property-card:hover .ajb-property-card__location,
  .ajb-property-card:focus-visible .ajb-property-card__location {
    /* Brighten toward the title colour, whatever the chosen colours are. */
    color: color-mix(in srgb, var(--_card-location) 50%, var(--_card-title));
  }

  .ajb-property-card:hover .ajb-property-card__rule,
  .ajb-property-card:focus-visible .ajb-property-card__rule {
    transform: scaleX(1);
    opacity: 1;
  }

  .ajb-property-card:hover .ajb-property-card__cta-inner,
  .ajb-property-card:focus-visible .ajb-property-card__cta-inner {
    transform: translate3d(0, 0, 0);
    opacity: 1;
  }

  .ajb-property-card:hover .ajb-property-card__arrow,
  .ajb-property-card:focus-visible .ajb-property-card__arrow {
    transform: translate3d(0, 0, 0);
  }
}

/* Touch devices have no hover: show the finished state. */
@media (hover: none), (pointer: coarse) {
  .ajb-property-card__rule {
    transform: scaleX(1);
    opacity: 1;
  }

  .ajb-property-card__cta-inner {
    transform: none;
    opacity: 1;
  }

  .ajb-property-card__arrow {
    transform: none;
  }
}

/* ---------- Small cards ---------- */

@container (max-width: 359px) {
  .ajb-property-card__frame {
    inset: 0.5rem;
  }
}

/* Narrow cards (smallest 3-column desktop, phones): trim the side padding
   and CTA tracking a touch so price and CTA still share one row. */
@container (max-width: 379px) {
  .ajb-property-card__content {
    padding-inline: 1.125rem;
  }

  .ajb-property-card__footer {
    gap: 0.625rem;
  }

  .ajb-property-card__cta {
    letter-spacing: calc(var(--_label-tracking) * 0.8);
  }

  .ajb-property-card__cta-inner {
    gap: 0.5rem;
  }
}

/* Only genuinely tiny cards stack the footer; the CTA then drops below the
   price, aligned under it. */
@container (max-width: 279px) {
  .ajb-property-card__footer {
    flex-wrap: wrap;
    gap: 0.5rem 1.5rem;
  }

  .ajb-property-card__cta {
    margin-inline-start: 0;
  }
}

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .ajb-property-card,
  .ajb-property-card__image,
  .ajb-property-card__frame,
  .ajb-property-card__content,
  .ajb-property-card__rule,
  .ajb-property-card__cta-inner,
  .ajb-property-card__arrow {
    transition-duration: 200ms;
    transition-delay: 0ms;
    transition-property: opacity, filter, color, box-shadow;
  }

  .ajb-property-card:hover,
  .ajb-property-card:focus-visible,
  .ajb-property-card .ajb-property-card__image,
  .ajb-property-card:hover .ajb-property-card__image,
  .ajb-property-card:focus-visible .ajb-property-card__image,
  .ajb-property-card:hover .ajb-property-card__content,
  .ajb-property-card:focus-visible .ajb-property-card__content,
  .ajb-property-card .ajb-property-card__frame,
  .ajb-property-card .ajb-property-card__arrow {
    transform: none;
  }

  .ajb-property-card .ajb-property-card__rule {
    transform: scaleX(1);
  }

  .ajb-property-card .ajb-property-card__cta-inner {
    transform: none;
    opacity: 1;
  }
}

