@charset "UTF-8";
/* ==========================================================================
   M Amin Property Advisor — theme "amin"

   One stylesheet, no build step. The design leans on three things rather than
   decoration: a strict spacing rhythm, a serif/sans pairing that gives the
   headings some authority, and photography treated as the main event.

   Everything is driven by the tokens in :root, so a rebrand is an edit to the
   first forty lines.
   ========================================================================== */

:root {
  /* ---- brand ------------------------------------------------------------ */
  --brand-900: #102a25;
  --brand-800: #163f37;
  --brand-700: #1e5a4f;
  --brand-600: #2f7567;
  --brand:     #3d9484;
  --brand-500: #65b7a8;
  --brand-200: #b9ded5;
  --brand-100: #d9eee8;
  --brand-50:  #f2f8f5;

  /* Brass is reserved for reassurance, key numbers and premium emphasis. */
  --gold-700:  #6e4d1f;
  --gold:      #b98235;
  --gold-200:  #e6c78d;
  --gold-100:  #f3dfba;
  --gold-50:   #fcf7ed;

  /* ---- neutrals: warm stone surfaces and forest-black typography ------- */
  --ink:       #17231f;
  --ink-soft:  #2b3a34;
  --body:      #45554e;
  --muted:     #6e7d75;
  --faint:     #9aa69f;
  --line:      #d9e3dc;
  --line-soft: #ecf1ed;
  --surface:   #fffefd;
  --surface-2: #f5f3ee;
  --white:     #fffefd;

  --ok:     #146c43;  --ok-bg:  #e7f4ec;
  --bad:    #a32b2b;  --bad-bg: #fbeaea;

  /* ---- type -------------------------------------------------------------
     Fraunces carries the display sizes; Inter does everything functional.
     Both fall back to the platform stack, so a blocked font request degrades
     to something deliberate rather than to Times. */
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --font-display: "Fraunces", "Iowan Old Style", "Palatino Linotype", Palatino,
                  Georgia, "Times New Roman", serif;
  --font-ur: "Noto Nastaliq Urdu", "Jameel Noori Nastaleeq", var(--font-sans);

  /* Fluid scale, 1.2 ratio at mobile opening to 1.25 at desktop.

     The ratio holds through the middle, where text is read, and is abandoned
     at both ends, where text is looked at. A page whose every step is 1.25
     from the last has no loud and no quiet in it - everything arrives at the
     same volume, which reads as even rather than as designed.

     t--2 is for labels only: uppercase, tracked, a word or two, where the
     reader is identifying a thing rather than reading it. Anything carrying
     real information stays at t--1 or above, because this audience is not
     uniformly young and an address set at 11px is a wall. */
  --t--2: clamp(0.72rem, 0.70rem + 0.09vw, 0.78rem);
  --t--1: clamp(0.78rem, 0.76rem + 0.10vw, 0.84rem);
  --t-0:  clamp(0.95rem, 0.93rem + 0.12vw, 1.02rem);
  --t-1:  clamp(1.08rem, 1.03rem + 0.24vw, 1.22rem);
  --t-2:  clamp(1.28rem, 1.17rem + 0.50vw, 1.60rem);
  --t-3:  clamp(1.55rem, 1.33rem + 1.00vw, 2.20rem);
  --t-4:  clamp(1.90rem, 1.40rem + 2.30vw, 3.40rem);
  --t-5:  clamp(2.30rem, 1.50rem + 3.80vw, 4.70rem);
  /* One step above the page's own headline, for the statement lines that carry
     a section on their own. Deliberately outside the 1.25 ratio: it is a
     different job from a heading, and sizing it politely wastes it. */
  --t-6:  clamp(2.85rem, 1.20rem + 7.20vw, 7.40rem);

  /* Wide tracking for the small capitals that sit above a display line. Latin
     only - it is applied through .eyebrow, which drops it for Urdu, because
     Nastaliq is a connected script and tracking pulls the joins apart. */
  --track-wide: .18em;

  /* ---- space ------------------------------------------------------------ */
  --s1: 4px;   --s2: 8px;   --s3: 12px;  --s4: 16px;
  --s5: 24px;  --s6: 32px;  --s7: 48px;  --s8: 72px;  --s9: 104px;

  --wrap: 1200px;
  --gap: var(--s5);

  /* ---- surface treatment ------------------------------------------------ */
  --r-sm: 8px;  --r: 12px;  --r-lg: 18px;  --r-xl: 26px;  --r-full: 999px;

  /* Green-tinted shadows. Neutral black shadows read as grey haze on a warm
     page; tinting them to the brand keeps the whole thing coherent. */
  --sh-1: 0 1px 2px rgba(9, 42, 30, .05), 0 1px 3px rgba(9, 42, 30, .04);
  --sh-2: 0 2px 4px rgba(9, 42, 30, .04), 0 6px 16px rgba(9, 42, 30, .07);
  --sh-3: 0 4px 8px rgba(9, 42, 30, .05), 0 14px 32px rgba(9, 42, 30, .10);
  --sh-4: 0 8px 20px rgba(9, 42, 30, .10), 0 28px 60px rgba(9, 42, 30, .16);

  --ease: cubic-bezier(.22, .61, .36, 1);
  /* Slower to leave, quicker to arrive. Entrances travel further than a hover
     does, and the standard ease makes that distance read as a drift. */
  --ease-in-out: cubic-bezier(.65, .05, .36, 1);

  color-scheme: light;
}

/* ------------------------------------------------------------------ reset -- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: 84px;
}

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--t-0);
  line-height: 1.65;
  color: var(--body);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: "kern" 1, "liga" 1, "cv11" 1;
}

h1, h2, h3, h4 {
  margin: 0 0 .5em;
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.14;
  letter-spacing: -.015em;
  /* Fraunces is a variable font; this keeps the display cut at large sizes. */
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 40;
  text-wrap: balance;
}
h1 { font-size: var(--t-4); }
h2 { font-size: var(--t-3); }
h3 { font-size: var(--t-1); font-family: var(--font-sans); font-weight: 650; letter-spacing: -.01em; line-height: 1.3; }
h4 { font-size: var(--t-0); font-family: var(--font-sans); font-weight: 650; }

p { margin: 0 0 1em; text-wrap: pretty; }
img, svg, video { max-width: 100%; height: auto; display: block; }

a { color: var(--brand-600); text-decoration: none; transition: color .16s var(--ease); }
a:hover { color: var(--brand-500); }

/* Underline links inside prose only — nav and cards get their own treatment. */
.prose a { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }

:focus-visible {
  outline: 2.5px solid var(--brand-500);
  outline-offset: 3px;
  border-radius: 4px;
}

::selection { background: var(--brand-100); color: var(--brand-800); }

.muted { color: var(--muted); }
.visually-hidden, .hp {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--brand-800); color: #fff; padding: 14px 22px;
  border-radius: 0 0 var(--r) 0; font-weight: 600;
}
.skip:focus { left: 0; color: #fff; }

/* ----------------------------------------------------------------- layout -- */

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--s5); }
.wrap--narrow { max-width: 760px; }

.section { padding-block: clamp(48px, 6vw, 96px); }
.section--tint {
  background: var(--surface);
  border-block: 1px solid var(--line-soft);
}

.section__head {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  justify-content: space-between; gap: var(--s3) var(--s5);
  margin-bottom: var(--s7);
}
.section__title { margin: 0; }

/* Sections are not equally important, and setting them all at one size says
   that they are. The two that carry the business - what is for sale, and where
   - take the display size and the tighter tracking that goes with it. The
   supporting ones sit back deliberately, so the eye has somewhere to rest
   between the loud ones. */
.section__title--lead {
  font-size: var(--t-4); line-height: 1.04; letter-spacing: -.03em;
  font-variation-settings: "SOFT" 0, "WONK" 1, "opsz" 96;
}
.section__title--quiet { font-size: var(--t-2); letter-spacing: -.015em; }

/* Nastaliq needs the height back and wants none of the tracking. */
.is-rtl .section__title--lead,
.is-rtl .section__title--quiet { line-height: 1.6; letter-spacing: 0; }
.section__lead { flex-basis: 100%; max-width: 60ch; margin: var(--s2) 0 0; color: var(--muted); font-size: var(--t-1); }
.section__more {
  font-weight: 600; font-size: var(--t--1); white-space: nowrap;
  display: inline-flex; align-items: center; gap: 6px;
  padding-bottom: 2px; border-bottom: 1.5px solid var(--brand-200);
  transition: border-color .16s var(--ease), gap .16s var(--ease);
}
.section__more::after { content: "\2192"; transition: transform .16s var(--ease); }
.section__more:hover { border-color: var(--brand); }
.section__more:hover::after { transform: translateX(3px); }

/* A small caps label above a heading. Cheap, and it instantly makes a section
   read as designed rather than as a stack of text. */
.eyebrow {
  display: inline-flex; align-items: center; gap: var(--s2);
  margin: 0 0 var(--s3);
  font-family: var(--font-sans);
  font-size: var(--t--2); font-weight: 650;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--brand-600);
}
.eyebrow::before {
  content: ""; width: 22px; height: 1.5px; background: var(--brand-200); flex: 0 0 auto;
}
.eyebrow--light { color: var(--brand-200); }
.eyebrow--light::before { background: rgba(255,255,255,.35); }

/* Wider still, for the label above a statement line. The .is-rtl rule further
   down already zeroes tracking on every .eyebrow and outranks this one, so
   Urdu never receives it. */
.eyebrow--wide { letter-spacing: var(--track-wide); font-weight: 600; }

/* -------------------------------------------------------------- statement -- */

/* One idea, set large enough that it is the only thing on the screen. Used for
   the section that explains how the office works, which was previously a
   heading over a list and read as filler at the size a heading gets. */
.statement { padding-block: clamp(72px, 11vw, 168px); }
.statement__line {
  margin: 0; max-width: 15ch;
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(2rem, 2rem + 4.4vw, 5.8rem); line-height: 1.08; letter-spacing: -.035em;
  color: var(--ink);
  font-variation-settings: "SOFT" 0, "WONK" 1, "opsz" 144;
  text-wrap: balance;
}
.statement__line em {
  font-style: italic; color: var(--brand);
  font-variation-settings: "SOFT" 60, "WONK" 1, "opsz" 144;
}
.statement__foot {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s3) var(--s6);
  margin-top: clamp(32px, 5vw, 64px);
  padding-top: var(--s5); border-top: 1px solid var(--line);
}
.statement__note { margin: 0; max-width: 46ch; color: var(--muted); font-size: var(--t-1); }

/* --------------------------------------------------- typography journey -- */

.typography-journey { position: relative; overflow: hidden; padding-block: clamp(64px, 9vw, 128px); }
.typography-journey::before, .typography-journey::after { content: ""; position: absolute; pointer-events: none; }
.typography-journey::before { inset: -35%; background: radial-gradient(circle at 22% 46%, rgba(61,148,132,.26), transparent 25%), radial-gradient(circle at 76% 55%, rgba(230,199,141,.14), transparent 19%); animation: journey-light 18s ease-in-out infinite alternate; }
.typography-journey::after { inset: 0; opacity: .26; background-image: linear-gradient(rgba(255,255,255,.08) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.08) 1px, transparent 1px); background-size: 52px 52px; mask-image: radial-gradient(ellipse at center, #000, transparent 72%); }
.typography-journey .wrap { position: relative; z-index: 1; }
.typography-journey__intro { display: flex; justify-content: space-between; align-items: end; gap: var(--s6); margin-bottom: var(--s6); }
.typography-journey__intro .eyebrow, .typography-journey__intro > p:last-child { margin: 0; }
.typography-journey__intro > p:last-child { max-width: 38ch; color: rgba(255,255,255,.62); font-size: var(--t-1); text-align: end; }
.typography-journey__stage { position: relative; min-height: clamp(410px, 48vw, 600px); perspective: 1100px; perspective-origin: 50% 48%; transform-style: preserve-3d; }
.typography-journey__track { position: absolute; inset: 0; margin: 0; padding: 0; list-style: none; transform-style: preserve-3d; }
.journey-title { position: absolute; top: 50%; left: 50%; width: min(100%, 850px); padding: var(--s7); border: 1px solid rgba(255,255,255,.16); border-radius: var(--r-lg); background: linear-gradient(135deg, rgba(16,42,37,.82), rgba(30,90,79,.46)); box-shadow: 0 26px 90px rgba(0,0,0,.28); opacity: 0; transform-style: preserve-3d; will-change: transform, opacity, filter; animation: typography-journey 20s cubic-bezier(.65, 0, .35, 1) infinite; }
.journey-title::before { content: ""; position: absolute; inset: 0; border-radius: inherit; background: linear-gradient(115deg, rgba(255,255,255,.12), transparent 35%); pointer-events: none; }
.journey-title--1 { --in-x: -12vw; --in-y: 8vh; --out-x: 8vw; --out-y: -5vh; animation-delay: 0s; }
.journey-title--2 { --in-x: 14vw; --in-y: -7vh; --out-x: -10vw; --out-y: 5vh; animation-delay: -15s; }
.journey-title--3 { --in-x: -8vw; --in-y: -10vh; --out-x: 11vw; --out-y: 6vh; animation-delay: -10s; }
.journey-title--4 { --in-x: 11vw; --in-y: 7vh; --out-x: -7vw; --out-y: -8vh; animation-delay: -5s; }
.journey-title__number { display: inline-block; margin-bottom: var(--s5); color: var(--gold-200); font-size: var(--t--1); font-weight: 750; letter-spacing: .18em; }
.journey-title h2 { position: relative; max-width: 17ch; margin: 0 0 var(--s4); color: #fff; font-size: var(--t-4); line-height: 1.04; letter-spacing: -.035em; }
.journey-title p { position: relative; max-width: 49ch; margin: 0; color: rgba(255,255,255,.74); font-size: var(--t-1); }
.typography-journey__caption { position: absolute; inset-inline: 0; bottom: 0; margin: 0; color: rgba(255,255,255,.46); font-size: var(--t--1); text-align: center; }

@keyframes journey-light { from { transform: translate3d(-3%, -2%, 0) scale(1); } to { transform: translate3d(4%, 3%, 0) scale(1.12); } }
@keyframes typography-journey {
  0% { opacity: .94; filter: blur(.4px); transform: translate3d(-50%, -50%, 130px) translate(var(--out-x), var(--out-y)) rotateZ(1.2deg) scale(1.14); }
  18% { opacity: .30; filter: blur(3px); transform: translate3d(-50%, -50%, -180px) translate(var(--out-x), var(--out-y)) rotateZ(-1.5deg) scale(.72); }
  30%, 67% { opacity: 0; filter: blur(9px); transform: translate3d(-50%, -50%, -420px) translate(var(--out-x), var(--out-y)) rotateZ(-3deg) scale(.42); }
  78% { opacity: .08; filter: blur(11px); transform: translate3d(-50%, -50%, -500px) translate(var(--in-x), var(--in-y)) rotateZ(3deg) scale(.36); }
  91% { opacity: .78; filter: blur(1.4px); transform: translate3d(-50%, -50%, -70px) translate(calc(var(--in-x) * .18), calc(var(--in-y) * .18)) rotateZ(-.6deg) scale(.88); }
  100% { opacity: .94; filter: blur(.4px); transform: translate3d(-50%, -50%, 130px) translate(var(--out-x), var(--out-y)) rotateZ(1.2deg) scale(1.14); }
}

/* Nastaliq needs the room, and it does not want the tight Latin tracking. */
.is-rtl .statement__line { line-height: 1.75; letter-spacing: 0; }

/* ------------------------------------------------------------------- rail -- */

/* A horizontal run of cards that snaps, for the featured listings. On a phone
   this is how people expect to move through a short set - a vertical grid of
   three makes them scroll past the rest of the page to reach it. Above the
   fold of a laptop it falls back to the ordinary grid, because there the whole
   set fits and hiding two thirds of it off the edge would be worse. */
.rail {
  display: grid; grid-auto-flow: column;
  grid-auto-columns: minmax(268px, 82%);
  gap: var(--gap);
  overflow-x: auto; overscroll-behavior-inline: contain;
  scroll-snap-type: x mandatory;
  /* The inline padding is what lets the first and last card sit clear of the
     edge while still snapping to it. */
  padding-inline: var(--s4); margin-inline: calc(var(--s4) * -1);
  padding-block-end: var(--s3);
  scrollbar-width: none;
}
.rail::-webkit-scrollbar { display: none; }
.rail > * { scroll-snap-align: start; }

.rail-bar {
  height: 2px; margin-top: var(--s4);
  background: var(--line); border-radius: var(--r-full);
  overflow: hidden;
}
.rail-bar__fill {
  display: block; height: 100%; width: 0;
  background: var(--brand); border-radius: inherit;
  transform-origin: left center;
}
.is-rtl .rail-bar__fill { transform-origin: right center; }

@media (min-width: 780px) {
  .rail {
    grid-auto-flow: row;
    grid-auto-columns: auto;
    grid-template-columns: repeat(auto-fill, minmax(288px, 1fr));
    overflow: visible; scroll-snap-type: none;
    padding-inline: 0; margin-inline: 0;
  }
  .rail-bar { display: none; }
}

/* ---------------------------------------------------------------- marquee -- */

/* The areas, moving slowly across the page. Each one is a real link to a real
   area page, so this is navigation that happens to move rather than decoration
   that happens to be clickable. It stops on hover and on focus, because a
   moving target that cannot be clicked is a nuisance rather than a flourish. */
.marquee {
  position: relative; overflow: hidden;
  padding-block: var(--s5);
  border-block: 1px solid var(--line-soft);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  /* Allow vertical page scrolling while the marquee scrolls horizontally. */
  touch-action: pan-y;
}
.marquee__track { display: flex; align-items: center; gap: var(--s6); width: max-content; will-change: transform; }
.marquee__row   { display: flex; align-items: center; gap: var(--s6); }
/* The animation waits for is-looping, which main.js only adds once it has
   unhidden the second copy of the list. Starting it on .js alone would slide a
   single list off the screen and leave an empty strip behind it. */
.marquee__track.is-looping { animation: marquee var(--marquee-time, 48s) linear infinite; }
.marquee:hover .marquee__track,
.marquee:focus-within .marquee__track { animation-play-state: paused; }

.marquee__item {
  display: inline-flex; align-items: baseline; gap: var(--s2);
  font-family: var(--font-display); font-size: var(--t-2); font-weight: 600;
  color: var(--ink-soft); white-space: nowrap;
  transition: color .18s var(--ease);
}
.marquee__item:hover { color: var(--brand); }
.marquee__item span { font-family: var(--font-sans); font-size: var(--t--2); font-weight: 600; color: var(--faint); }
.marquee__dot { width: 5px; height: 5px; border-radius: 50%; background: var(--brand-200); flex: 0 0 auto; }

/* The track is written out twice, so translating exactly half of it lands on
   an identical frame and the loop has no seam. */
@keyframes marquee { to { transform: translate3d(-50%, 0, 0); } }
.is-rtl .marquee__track { animation-direction: reverse; }

/* ------------------------------------------------------ horizontal gallery -- */

/* A row of photographs that travels left to right while the page scrolls down.
   The section is tall, the stage inside it sticks, and the track is moved by
   main.js from the shared scroll pass.

   It is opt-in from script: without .is-pinned this is an ordinary swipeable
   rail, which is what a phone, a reduced-motion visitor and a page with no
   JavaScript all get. Pinning is the enhancement, never the mechanism - a
   sticky section whose driver never ran would be a screen the reader cannot
   scroll past, which is the worst failure this page could have. */
.hgal { position: relative; background: var(--brand-900); color: #fff; }

.hgal__stage {
  display: flex; flex-direction: column; justify-content: center;
  gap: var(--s5);
  padding-block: clamp(48px, 7vw, 96px);
  overflow: hidden;
}
.hgal.is-pinned { height: var(--hgal-h, 300vh); }
.hgal.is-pinned .hgal__stage {
  position: sticky; inset-block-start: 0; height: 100vh;
  padding-block: 0;
}

.hgal__head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: var(--s3) var(--s5);
  max-width: var(--wrap); margin-inline: auto; width: 100%;
  padding-inline: var(--s5);
}
.hgal__title {
  margin: 0; color: #fff; font-size: var(--t-3);
  font-variation-settings: "SOFT" 0, "WONK" 1, "opsz" 96;
}
/* The slide counter. Tabular figures so the number does not jitter as it
   counts - the one place on this page where digits change in situ. */
.hgal__count {
  font-family: var(--font-display); font-size: var(--t-1); color: var(--brand-200);
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
}

.hgal__track {
  display: flex; gap: var(--s5); padding-inline: var(--s5);
  will-change: transform;
}
/* Un-pinned it is a rail you swipe; pinned, script owns the transform and the
   native scrolling has to be off or the two fight each other. */
.hgal:not(.is-pinned) .hgal__track {
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; padding-block-end: var(--s3);
}
.hgal:not(.is-pinned) .hgal__track::-webkit-scrollbar { display: none; }
.hgal:not(.is-pinned) .hgal__figure { scroll-snap-align: center; }
.hgal.is-pinned .hgal__track { width: max-content; }

.hgal__figure {
  position: relative; flex: 0 0 auto;
  width: clamp(240px, 62vw, 460px); aspect-ratio: 3 / 4;
  border-radius: var(--r-lg); overflow: hidden;
  background: var(--brand-800);
}
/* On phones the 3/4 portrait ratio makes the gallery taller than the screen.
   4/5 at the narrow end gives a better fill without dominating the viewport. */
@media (max-width: 600px) {
  .hgal__figure { aspect-ratio: 4 / 5; width: clamp(200px, 72vw, 340px); }
}
.hgal__figure img { width: 100%; height: 100%; object-fit: cover; }
.hgal__cap {
  position: absolute; inset-inline: 0; inset-block-end: 0;
  padding: var(--s6) var(--s4) var(--s4);
  background: linear-gradient(to top, rgba(4,37,27,.86), rgba(4,37,27,0));
  font-family: var(--font-sans);
}
.hgal__cap b { display: block; font-size: var(--t-0); font-weight: 650; color: #fff; }
.hgal__cap span { font-size: var(--t--2); color: rgba(255,255,255,.72); }

/* ----------------------------------------------------------------- story --- */

/* Chapters that hold the screen while the page scrolls through them, the
   background changing under each one.

   Read without script this is an ordinary stack: heading, paragraph, heading,
   paragraph, one photograph behind the lot. .is-playing is what turns it into
   the pinned version, and main.js only adds it once it can drive it - the same
   rule as the sideways gallery, and for the same reason. A pinned section
   nobody is moving is a screen the reader cannot get past. */
.story { position: relative; background: var(--brand-900); color: rgba(255,255,255,.78); }
.story__stage { position: relative; padding-block: clamp(56px, 8vw, 104px); overflow: hidden; }

.story.is-playing { height: var(--story-h, 400vh); }
.story.is-playing .story__stage {
  position: sticky; inset-block-start: 0; height: 100vh;
  padding-block: 0; display: grid; place-items: center;
}

.story__bg { position: absolute; inset: 0; z-index: 0; }

/* The corners fall off, the way they do through a lens. One static gradient
   over the whole stage rather than anything per-frame - it costs a paint on
   the first frame and nothing on any of the ones after. */
.story__stage::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  pointer-events: none;
  background: radial-gradient(118% 88% at 50% 46%,
              rgba(4, 37, 27, 0) 44%, rgba(4, 37, 27, .34) 78%, rgba(4, 37, 27, .58) 100%);
}
.story__layer {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  /* Held slightly over-size so the slow push never shows an edge. */
  transform: scale(var(--layer-zoom, 1.06));
}
.story__layer::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(4,37,27,.72) 0%, rgba(4,37,27,.82) 100%);
}
/* Only the pinned version cross-fades; unpinned, the first layer is simply the
   photograph behind the text and the rest are not drawn at all. */
.story.is-playing .story__layer {
  opacity: 0; transition: opacity 1s var(--ease), transform 1.6s var(--ease);
}
.story.is-playing .story__layer.is-on { opacity: 1; }
.story:not(.is-playing) .story__layer + .story__layer { display: none; }

/* Above the vignette, which is a pseudo-element and therefore paints after
   everything else at its own level. The copy has to sit over it, not under. */
.story__chapters { position: relative; z-index: 2; width: 100%; }
.story__chapter {
  max-width: var(--wrap); margin-inline: auto; padding-inline: var(--s5);
  max-width: 46ch;
}
.story:not(.is-playing) .story__chapter + .story__chapter { margin-block-start: clamp(48px, 7vw, 88px); }

.story.is-playing .story__chapters { display: grid; }
.story.is-playing .story__chapter {
  grid-area: 1 / 1;
  opacity: 0; transform: translateY(28px) scale(.98);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
  pointer-events: none;
}
.story.is-playing .story__chapter.is-on {
  opacity: 1; transform: none; pointer-events: auto;
}

.story__n {
  display: block; margin-bottom: var(--s3);
  font-family: var(--font-display); font-size: var(--t-1); color: var(--gold-200);
  font-variant-numeric: tabular-nums;
}
.story__h {
  margin: 0 0 var(--s4); color: #fff; font-size: var(--t-4);
  letter-spacing: -.03em; line-height: 1.06;
  font-variation-settings: "SOFT" 0, "WONK" 1, "opsz" 144;
}
.story__p { margin: 0; font-size: var(--t-1); color: rgba(255,255,255,.76); }
.is-rtl .story__h { line-height: 1.6; letter-spacing: 0; }

/* --------------------------------------------------------- 3D town ring --- */

/* The areas on a slowly turning carousel, each one facing the reader in turn.
   Without script it is the plain list of links it has always been, which is
   also what a phone gets: a 3D ring on a 360px screen is three overlapping
   cards and a scroll trap. */
.ring { --ring-r: 300px; }
.ring__list { display: flex; flex-wrap: wrap; gap: var(--s4); list-style: none; margin: 0; padding: 0; }
.ring__item { flex: 1 1 200px; min-width: 0; }
.ring__item .area-tile { height: 100%; }

.ring.is-turning { perspective: 1100px; perspective-origin: 50% 50%; }
.ring.is-turning .ring__list {
  position: relative; height: 260px; display: block;
  transform-style: preserve-3d;
  transform: translateZ(calc(var(--ring-r) * -1)) rotateY(var(--ring-a, 0deg));
  transition: transform .9s var(--ease-in-out);
}
.ring.is-turning .ring__item {
  position: absolute; inset-block-start: 0; inset-inline-start: 50%;
  width: 230px; margin-inline-start: -115px;
  transform: rotateY(calc(var(--i) * var(--ring-step, 45deg))) translateZ(var(--ring-r));
  backface-visibility: hidden;
}
.ring.is-turning .area-tile {
  transition: opacity .5s var(--ease), border-color .3s var(--ease);
  opacity: .38;
}
.ring.is-turning .ring__item.is-front .area-tile {
  opacity: 1; border-color: var(--brand-200); box-shadow: var(--sh-3);
}

.ring__nav { display: flex; justify-content: center; gap: var(--s2); margin-top: var(--s5); }
.ring__dot {
  width: 7px; height: 7px; padding: 0; border-radius: 50%;
  border: 0; background: var(--line); cursor: pointer;
  transition: background .2s var(--ease), transform .2s var(--ease);
}
.ring__dot[aria-current="true"] { background: var(--brand); transform: scale(1.5); }
.ring__dot:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

/* --------------------------------------------------------------- figures --- */

/* A photograph that opens as it arrives and drifts inside its own frame as it
   crosses the screen. The frame clips; the picture is slightly taller than the
   frame so there is something to move without an edge appearing. */
.figure { position: relative; overflow: hidden; border-radius: var(--r-lg); background: var(--surface-2); }
.figure img { width: 100%; height: 100%; object-fit: cover; }
.js .figure[data-parallax] img { height: 118%; will-change: transform; }
.js .figure[data-parallax] img { transform: translate3d(0, var(--fig-shift, 0px), 0); }

/* ------------------------------------------------------------- dark band --- */

/* Contrast is structural here, not decoration: the page alternates ground so
   that a section reads as a new subject before a word of it is read. */
.section--dark {
  background: var(--brand-900); color: rgba(255,255,255,.74);
  border-block: 0;
}
.section--dark h2, .section--dark h3, .section--dark .section__title { color: #fff; }
.section--dark .eyebrow { color: var(--brand-200); }
.section--dark .eyebrow::before { background: rgba(255,255,255,.35); }
.section--dark .section__lead { color: rgba(255,255,255,.66); }
.section--dark .section__more { color: #fff; border-bottom-color: rgba(255,255,255,.4); }
.section--dark .section__more:hover { border-bottom-color: #fff; }
.section--dark .statement__line { color: #fff; }
.section--dark .statement__line em { color: var(--gold-200); }
.section--dark .statement__foot { border-top-color: rgba(255,255,255,.16); }
.section--dark .statement__note { color: rgba(255,255,255,.66); }

/* ---------------------------------------------------------------- utility -- */

.utility {
  background: var(--brand-900); color: #b7cdc3;
  font-size: var(--t--1);
}
.utility__inner {
  display: flex; align-items: center; gap: var(--s5);
  min-height: 38px; flex-wrap: wrap;
}
.utility__inner--full { max-width: none; }
.utility a { color: #e2eee8; }
.utility a:hover { color: #fff; }
.utility__item { display: inline-flex; align-items: center; gap: 7px; }
.utility__item svg { opacity: .7; flex: 0 0 auto; }
.utility__spacer { margin-inline-start: auto; }
.utility__social { display: inline-flex; gap: var(--s4); }

.announce {
  background: var(--gold-100); color: var(--gold-700);
  font-size: var(--t--1); font-weight: 550; text-align: center;
  padding: 9px var(--s5);
}

/* ----------------------------------------------------------------- header -- */

.site-head {
  position: sticky; top: 0; z-index: 60;
  background: rgba(255, 254, 253, .90);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--line);
  transition: box-shadow .2s var(--ease), border-color .2s var(--ease);
}
.site-head.is-stuck { box-shadow: var(--sh-2); border-color: transparent; }
.site-head--static { position: relative; }

.site-head__inner { display: flex; align-items: center; gap: var(--s4); min-height: 74px; }
.site-head__inner--full { max-width: none; }

.brand { display: inline-flex; align-items: center; gap: 11px; color: var(--ink); flex: 0 0 auto; }
.brand:hover { color: var(--ink); }
.brand__mark {
  display: grid; place-items: center; width: 42px; height: 42px; flex: 0 0 auto;
  border-radius: 11px; color: #fff;
  background: linear-gradient(145deg, var(--brand-500), var(--brand-700));
  box-shadow: 0 2px 8px rgba(30, 90, 79, .28);
}
.brand__text { display: flex; flex-direction: column; line-height: 1.18; }
.brand__text strong {
  font-family: var(--font-display); font-size: 1.06rem; font-weight: 600;
  letter-spacing: -.015em; font-variation-settings: "opsz" 20;
}
.brand__text small { font-size: .72rem; color: var(--muted); letter-spacing: .005em; }
.brand__logo { max-height: 44px; width: auto; }

.site-nav { margin-inline-start: auto; }
.site-nav ul { display: flex; gap: 2px; list-style: none; margin: 0; padding: 0; }
.site-nav a {
  position: relative; z-index: 0; isolation: isolate; display: block; overflow: hidden;
  min-height: 40px; padding: 10px 13px; border-radius: 999px;
  color: var(--body); font-size: var(--t--1); font-weight: 550; white-space: nowrap;
  transition: color .22s ease .73s, transform .24s cubic-bezier(.34,1.4,.64,1),
              box-shadow .25s ease, background-color .25s ease;
}
/* Pseudo-element used by pill-fill modes */
.site-nav a::after {
  content: ""; position: absolute; z-index: -1; left: 50%; bottom: 7px; width: 0; height: 2px;
  border: 1px solid transparent; border-radius: 999px;
  background: linear-gradient(var(--brand), var(--brand)) bottom / 100% 0 no-repeat;
  transform: translateX(-50%);
  transition:
    background-size .32s cubic-bezier(.2, .8, .2, 1),
    height .26s cubic-bezier(.22, 1, .36, 1) .32s,
    bottom .26s cubic-bezier(.22, 1, .36, 1) .32s,
    border-color .18s ease .32s,
    width .28s cubic-bezier(.22, 1, .36, 1) .58s;
}
/* Liquid-fill blob layer (hidden by default) */
.site-nav a::before {
  content: ""; position: absolute; z-index: -1; left: -20%; bottom: -160%;
  width: 140%; height: 240%;
  background: radial-gradient(circle at 50% 0%, var(--brand, #075985), var(--brand-800, #073b5c));
  border-radius: 40% 45% 42% 44%;
  transform: rotate(0deg);
  /* EXIT speed: fast sink so color can return immediately without overlap */
  transition: bottom .28s cubic-bezier(.4,0,1,1), transform .3s ease;
  pointer-events: none; opacity: 0;
}

/* Active-page indicator underline */
.site-nav a[aria-current="page"] { color: var(--brand-700); font-weight: 650; }
.site-nav a[aria-current="page"]::after {
  left: 13px; bottom: 4px; width: calc(100% - 26px); height: 2px;
  border: 0; border-radius: 2px; background: var(--brand); transform: none;
}

/* =============================================================================
 * Nav Link Hover Effects — scoped to .header-effect-{mode}
 * The fallback (no mode class) keeps the original pill-fill animation.
 * ============================================================================= */

/* — Fallback / default pill-fill hover (applies when no effect class set) — */
.site-nav a:hover, .site-nav a:focus-visible { color: #fff; }
.site-nav a:hover::after, .site-nav a:focus-visible::after {
  bottom: 3px; width: calc(100% - 4px); height: calc(100% - 6px);
  border-color: var(--brand); background-size: 100% 100%;
  transition:
    width .28s cubic-bezier(.22, 1, .36, 1),
    height .26s cubic-bezier(.22, 1, .36, 1) .28s,
    bottom .26s cubic-bezier(.22, 1, .36, 1) .28s,
    border-color .18s ease .28s,
    background-size .52s cubic-bezier(.2, .8, .2, 1) .59s;
}
.site-nav a[aria-current="page"]:hover::after,
.site-nav a[aria-current="page"]:focus-visible::after {
  left: 50%; bottom: 3px; width: calc(100% - 4px); height: calc(100% - 6px);
  border: 1px solid var(--brand); border-radius: 999px;
  background: linear-gradient(var(--brand), var(--brand)) bottom / 100% 100% no-repeat;
  transform: translateX(-50%);
}

/* Quick color return for all non-pill modes — no delay */
.header-effect-liquid  .site-nav a,
.header-effect-glow    .site-nav a,
.header-effect-magnetic .site-nav a,
.header-effect-glass   .site-nav a,
.header-effect-minimal .site-nav a {
  transition: color .15s ease, transform .24s cubic-bezier(.34,1.4,.64,1),
              box-shadow .25s ease, background-color .18s ease,
              backdrop-filter .22s ease;
}

/* --- MODE 1: Liquid Fill --- */
/* Suppress ::after pill on liquid mode */
.header-effect-liquid .site-nav a::after { display: none; }
/* Activate ::before liquid blob */
.header-effect-liquid .site-nav a::before { opacity: 1; }
/* ENTER: override blob transition so it rises slowly (organic liquid feel) */
.header-effect-liquid .site-nav a:hover::before,
.header-effect-liquid .site-nav a:focus-visible::before {
  bottom: -10%; transform: rotate(360deg);
  transition: bottom .65s cubic-bezier(.2,.8,.2,1), transform .75s ease;
}
.header-effect-liquid .site-nav a:hover,
.header-effect-liquid .site-nav a:focus-visible {
  color: #fff; transform: translateY(-2px);
  box-shadow: 0 6px 18px -4px rgba(7, 89, 133, 0.35);
}

/* --- MODE 2: Pulse (keeps original pill-fill, adds lift) --- */
/* ::after pill-fill already works by default; just add a lift */
.header-effect-pulse .site-nav a:hover,
.header-effect-pulse .site-nav a:focus-visible {
  color: #fff; transform: translateY(-2px);
}

/* --- MODE 3: Neon Glow --- */
/* Suppress ::after pill; use ::before conic beam */
.header-effect-glow .site-nav a::after { display: none; }
.header-effect-glow .site-nav a::before {
  opacity: 0; left: -50%; bottom: unset; top: -50%;
  width: 200%; height: 200%;
  background: conic-gradient(transparent, var(--brand-500, #0ea5e9), transparent 30%);
  border-radius: 0; transform: rotate(0deg);
  transition: opacity .3s ease;
}
.header-effect-glow .site-nav a:hover::before,
.header-effect-glow .site-nav a:focus-visible::before {
  opacity: 1; animation: header-radar-spin 2.2s linear infinite;
}
.header-effect-glow .site-nav a:hover,
.header-effect-glow .site-nav a:focus-visible {
  color: #fff; transform: translateY(-2px);
  box-shadow: 0 0 14px rgba(14, 165, 233, 0.5), inset 0 0 8px rgba(14, 165, 233, 0.2);
  border: 1px solid rgba(14, 165, 233, 0.6);
}

/* --- MODE 4: Magnetic Float --- */
/* Suppress ::after pill; pure transform spring */
.header-effect-magnetic .site-nav a::after { display: none; }
.header-effect-magnetic .site-nav a::before { opacity: 0; }
.header-effect-magnetic .site-nav a {
  transition: transform .28s cubic-bezier(.34, 1.56, .64, 1),
              box-shadow .28s ease, color .2s ease, background-color .2s ease;
}
.header-effect-magnetic .site-nav a:hover,
.header-effect-magnetic .site-nav a:focus-visible {
  color: #fff; transform: translateY(-4px) scale(1.06);
  background: var(--brand); box-shadow: 0 12px 28px -6px rgba(7, 89, 133, 0.35);
}
.header-effect-magnetic .site-nav a:active { transform: translateY(-1px) scale(0.98); }

/* --- MODE 5: Frosted Glass --- */
/* Suppress ::after pill; use ::before lens flare */
.header-effect-glass .site-nav a::after { display: none; }
.header-effect-glass .site-nav a::before {
  opacity: 0; left: 0; bottom: 0; top: 0; right: 0;
  width: 100%; height: 100%;
  background: radial-gradient(circle at 50% 50%, rgba(255,255,255,0.45) 0%, transparent 65%);
  border-radius: 0; transform: none;
  transition: opacity .3s ease;
}
.header-effect-glass .site-nav a:hover::before,
.header-effect-glass .site-nav a:focus-visible::before { opacity: 1; }
.header-effect-glass .site-nav a:hover,
.header-effect-glass .site-nav a:focus-visible {
  color: #fff; transform: translateY(-2px);
  background: rgba(7, 89, 133, 0.65);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 8px 24px -4px rgba(0,0,0,0.12), inset 0 1px 1px rgba(255,255,255,0.6);
}

/* --- MODE 6: Minimal --- */
.header-effect-minimal .site-nav a::after { display: none; }
.header-effect-minimal .site-nav a::before { opacity: 0; }
.header-effect-minimal .site-nav a:hover,
.header-effect-minimal .site-nav a:focus-visible {
  color: var(--brand-700); transform: translateY(-1.5px);
  box-shadow: 0 3px 10px -2px rgba(0,0,0,0.08);
  background: var(--brand-50);
}

/* Header actions are deliberately small and self-contained. This is a new
   control system, not a compressed version of the old search field. */
.site-actions { display: flex; align-items: center; gap: 8px; margin-inline-start: 0; }
.header-action {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 42px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: #fff; color: var(--ink); padding: 0 12px; cursor: pointer;
  font: inherit; font-size: var(--t--1); font-weight: 700; white-space: nowrap;
  transition: background-color .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.header-action:hover { background: var(--brand-50); border-color: var(--brand-200); color: var(--brand-800); }
/* =============================================================================
 * Header Action Buttons Hover Effects Architecture
 * ========================================================================== */

/* Common base for all action buttons */
.header-action {
  position: relative;
  isolation: isolate;
  transition: transform 0.24s cubic-bezier(0.34, 1.4, 0.64, 1),
              box-shadow 0.25s ease,
              border-color 0.25s ease,
              background-color 0.25s ease,
              color 0.25s ease;
}

/* -----------------------------------------------------------------------------
 * EFFECT MODE 1: Liquid Fill (Wave Fill with Dynamic Swell) [Default]
 * -------------------------------------------------------------------------- */
.header-effect-liquid .header-action,
.header-effect-liquid .saved-toggle {
  overflow: hidden;
}

.header-effect-liquid .header-action::before,
.header-effect-liquid .saved-toggle::before {
  content: "";
  position: absolute;
  left: -20%;
  bottom: -160%;
  width: 140%;
  height: 240%;
  background: radial-gradient(circle at 50% 0%, var(--brand, #075985), var(--brand-800, #073b5c));
  border-radius: 40% 45% 42% 44%;
  transform: rotate(0deg);
  transition: bottom 0.65s cubic-bezier(0.2, 0.8, 0.2, 1), transform 0.75s ease;
  z-index: -1;
  pointer-events: none;
}

.header-effect-liquid .header-action:hover::before,
.header-effect-liquid .saved-toggle:hover::before {
  bottom: -10%;
  transform: rotate(360deg);
}

.header-effect-liquid .header-action:hover,
.header-effect-liquid .saved-toggle:hover {
  transform: translateY(-2.5px);
  color: #fff !important;
  border-color: var(--brand-400, #38bdf8);
  box-shadow: 0 8px 24px -4px rgba(7, 89, 133, 0.4);
}

.header-effect-liquid .header-action:hover svg,
.header-effect-liquid .saved-toggle:hover svg {
  color: #fff !important;
  transform: scale(1.12);
  transition: transform 0.3s cubic-bezier(0.34, 1.5, 0.64, 1);
}

/* -----------------------------------------------------------------------------
 * EFFECT MODE 2: Pulse & Radar (Magnetic pulse + radar sweep)
 * -------------------------------------------------------------------------- */
.header-effect-pulse .header-call {
  overflow: visible;
  background: var(--brand-700);
  border-color: var(--brand-700);
  color: #fff;
}
.header-effect-pulse .header-call::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: inherit;
  border: 2px solid var(--brand-400, #38bdf8);
  opacity: 0;
  transform: scale(0.95);
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.header-effect-pulse .header-call:hover {
  background: var(--brand-800);
  border-color: var(--brand-800);
  transform: translateY(-2px) scale(1.02);
  box-shadow: 0 6px 20px -3px rgba(7, 89, 133, 0.45);
}
.header-effect-pulse .header-call:hover::after {
  opacity: 1;
  transform: scale(1.08);
  animation: header-call-pulse 1.6s cubic-bezier(0.24, 0, 0.38, 1) infinite;
}
.header-effect-pulse .header-call:hover svg {
  animation: header-phone-wiggle 0.7s ease infinite alternate;
}

.header-effect-pulse .header-search-toggle {
  overflow: hidden;
  width: 42px;
  padding: 0;
}
.header-effect-pulse .header-search-toggle::before {
  content: "";
  position: absolute;
  inset: -50%;
  background: conic-gradient(from 0deg, transparent 0deg, rgba(7, 89, 133, 0.35) 60deg, transparent 120deg);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}
.header-effect-pulse .header-search-toggle:hover {
  transform: translateY(-2px) scale(1.06);
  border-color: var(--brand-300);
  box-shadow: 0 4px 16px -2px rgba(7, 89, 133, 0.3);
}
.header-effect-pulse .header-search-toggle:hover::before {
  opacity: 1;
  animation: header-radar-spin 2s linear infinite;
}
.header-effect-pulse .header-search-toggle:hover svg {
  transform: rotate(90deg) scale(1.18);
  color: var(--brand-700);
}

.header-effect-pulse .header-search__submit,
.header-effect-pulse .saved-toggle {
  overflow: hidden;
}
.header-effect-pulse .header-search__submit::before,
.header-effect-pulse .saved-toggle::before {
  content: "";
  position: absolute;
  top: 0;
  left: -120%;
  width: 80%;
  height: 100%;
  background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.5) 50%, transparent 100%);
  transform: skewX(-24deg);
  pointer-events: none;
  transition: left 0s ease;
}
.header-effect-pulse .header-search__submit:hover,
.header-effect-pulse .saved-toggle:hover {
  transform: translateY(-2px) scale(1.03);
  box-shadow: 0 6px 18px -4px rgba(7, 89, 133, 0.3);
}
.header-effect-pulse .header-search__submit:hover::before,
.header-effect-pulse .saved-toggle:hover::before {
  left: 180%;
  transition: left 0.75s cubic-bezier(0.4, 0, 0.2, 1);
}

/* -----------------------------------------------------------------------------
 * EFFECT MODE 3: Neon Glow & Border Beam
 * -------------------------------------------------------------------------- */
.header-effect-glow .header-action,
.header-effect-glow .saved-toggle {
  position: relative;
  overflow: hidden;
  border-color: var(--line);
}

.header-effect-glow .header-action:hover,
.header-effect-glow .saved-toggle:hover {
  transform: translateY(-2px);
  border-color: var(--brand-500, #0ea5e9);
  box-shadow: 0 0 16px rgba(14, 165, 233, 0.45), inset 0 0 8px rgba(14, 165, 233, 0.2);
}

.header-effect-glow .header-action::before,
.header-effect-glow .saved-toggle::before {
  content: "";
  position: absolute;
  top: -50%;
  left: -50%;
  width: 200%;
  height: 200%;
  background: conic-gradient(transparent, var(--brand-500, #0ea5e9), transparent 30%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.header-effect-glow .header-action:hover::before,
.header-effect-glow .saved-toggle:hover::before {
  opacity: 1;
  animation: header-radar-spin 2.2s linear infinite;
}

/* -----------------------------------------------------------------------------
 * EFFECT MODE 4: Magnetic Float & Ripple Shimmer
 * -------------------------------------------------------------------------- */
.header-effect-magnetic .header-action,
.header-effect-magnetic .saved-toggle {
  overflow: visible;
  transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1),
              box-shadow 0.28s ease,
              border-color 0.2s ease;
}

.header-effect-magnetic .header-action:hover,
.header-effect-magnetic .saved-toggle:hover {
  transform: translateY(-4px) scale(1.05);
  box-shadow: 0 12px 28px -6px rgba(7, 89, 133, 0.35);
  border-color: var(--brand-500, #0ea5e9);
}

.header-effect-magnetic .header-action:active,
.header-effect-magnetic .saved-toggle:active {
  transform: translateY(-1px) scale(0.98);
}

/* -----------------------------------------------------------------------------
 * EFFECT MODE 5: Frosted Glass & Ambient Flare
 * -------------------------------------------------------------------------- */
.header-effect-glass .header-action,
.header-effect-glass .saved-toggle {
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  position: relative;
  overflow: hidden;
}

.header-effect-glass .header-action::before,
.header-effect-glass .saved-toggle::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.45) 0%, transparent 65%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.header-effect-glass .header-action:hover::before,
.header-effect-glass .saved-toggle:hover::before {
  opacity: 1;
}

.header-effect-glass .header-action:hover,
.header-effect-glass .saved-toggle:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px -4px rgba(0, 0, 0, 0.12), inset 0 1px 1px rgba(255, 255, 255, 0.6);
}

/* -----------------------------------------------------------------------------
 * EFFECT MODE 6: Minimal Subtle Lift
 * -------------------------------------------------------------------------- */
.header-effect-minimal .header-action:hover,
.header-effect-minimal .saved-toggle:hover {
  transform: translateY(-1.5px);
  box-shadow: 0 4px 12px -2px rgba(0, 0, 0, 0.08);
}

@keyframes header-call-pulse {
  0% { transform: scale(1); opacity: 0.8; }
  50% { transform: scale(1.14); opacity: 0.2; }
  100% { transform: scale(1.22); opacity: 0; }
}

@keyframes header-phone-wiggle {
  0% { transform: rotate(0deg) scale(1.1); }
  25% { transform: rotate(-12deg) scale(1.12); }
  75% { transform: rotate(12deg) scale(1.12); }
  100% { transform: rotate(0deg) scale(1.1); }
}

@keyframes header-radar-spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.header-call--icon-only { width: 42px; padding: 0; }
.header-search {
  position: absolute; z-index: 75; inset-inline-end: max(var(--s5), calc((100vw - var(--wrap)) / 2 + var(--s5)));
  top: calc(100% + 10px); display: flex; align-items: center; gap: 10px;
  width: min(480px, calc(100vw - 32px)); padding: 10px 10px 10px 14px;
  background: #fff; border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: var(--sh-3); color: var(--muted);
}
.header-search[hidden] { display: none; }
.header-search input { min-width: 0; flex: 1; border: 0; padding: 8px 0; font-size: var(--t-0); }
.header-search input:focus { outline: 0; }
.header-search__submit { border: 0; border-radius: var(--r-sm); background: var(--brand-700); color: #fff; padding: 10px 14px; font: inherit; font-size: var(--t--1); font-weight: 700; cursor: pointer; }
.header-search .quicksearch__results { inset-inline: 0; top: calc(100% + 8px); }

.nav-toggle {
  display: none; width: 44px; height: 44px; margin-inline-start: auto;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: #fff;
  cursor: pointer; padding: 12px 11px;
  transition: background .16s var(--ease);
}
.nav-toggle:hover { background: var(--surface); }
.nav-toggle span {
  display: block; height: 2px; background: var(--ink); border-radius: 2px;
  transition: transform .22s var(--ease), opacity .16s var(--ease);
}
.nav-toggle span + span { margin-top: 5px; }
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ---------------------------------------------------------------- buttons -- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 12px 22px; border-radius: var(--r-full); border: 1.5px solid transparent;
  font: inherit; font-size: var(--t--1); font-weight: 650; line-height: 1.2;
  letter-spacing: .005em; cursor: pointer; text-align: center;
  transition: background-color .18s var(--ease), border-color .18s var(--ease),
              color .18s var(--ease), transform .18s var(--ease), box-shadow .18s var(--ease);
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn--primary {
  background: var(--brand); color: #fff;
  box-shadow: 0 2px 6px rgba(30, 90, 79, .22);
}
.btn--primary:hover { background: var(--brand-600); color: #fff; box-shadow: 0 6px 18px rgba(30, 90, 79, .30); }

.btn--ghost { background: #fff; color: var(--brand-700); border-color: var(--line); }
.btn--ghost:hover { background: var(--brand-50); border-color: var(--brand-200); color: var(--brand-700); }

.btn--wa { background: #1faa54; color: #fff; box-shadow: 0 2px 6px rgba(31, 170, 84, .25); }
.btn--wa:hover { background: #17954a; color: #fff; box-shadow: 0 6px 18px rgba(31, 170, 84, .32); }

.btn--light { background: rgba(255,255,255,.14); color: #fff; border-color: rgba(255,255,255,.3); backdrop-filter: blur(6px); }
.btn--light:hover { background: rgba(255,255,255,.24); color: #fff; }

.btn--block { width: 100%; }
.btn--lg { padding: 15px 30px; font-size: var(--t-0); }

/* ----------------------------------------------------- buyer requirements -- */

.buyer-board {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s4); margin-block: var(--s6);
}
.buyer-board__card {
  display: flex; flex-direction: column; min-height: 100%; padding: var(--s5);
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--white);
  box-shadow: var(--sh-1);
}
.buyer-board__card h2 { margin: 6px 0 var(--s4); font-size: var(--t-2); line-height: 1.15; }
.buyer-board__card dl { display: grid; gap: 10px; margin: 0; }
.buyer-board__card dl div { display: grid; grid-template-columns: 74px 1fr; gap: 10px; }
.buyer-board__card dt { color: var(--muted); font-size: var(--t--1); }
.buyer-board__card dd { margin: 0; font-weight: 650; }
.buyer-board__summary { margin: var(--s4) 0; color: var(--body); line-height: 1.65; }
.buyer-board__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: auto; padding-top: var(--s3); }
.buyer-board__actions .btn { font-size: var(--t--1); }

@media (max-width: 900px) { .buyer-board { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 580px) { .buyer-board { grid-template-columns: 1fr; } }

.btn--call {
  flex: 0 0 auto; background: var(--brand-50); color: var(--brand-700);
  border-color: var(--brand-100); white-space: nowrap; padding: 11px 18px;
}
.btn--call:hover { background: var(--brand-100); color: var(--brand-800); }

/* ------------------------------------------------------------------- hero -- */

.hero {
  position: relative; isolation: isolate;
  /* Minimum height prevents collapse on landscape phones and short viewports. */
  min-height: clamp(520px, 80vh, 900px);
  padding-block: clamp(56px, 8vw, 116px) clamp(40px, 5vw, 72px);
  background:
    radial-gradient(ellipse 90% 110% at 6% 0%, rgba(255,255,255,.58) 0%, rgba(255,255,255,0) 56%),
    radial-gradient(ellipse 80% 95% at 100% 95%, rgba(30, 144, 255, .34) 0%, rgba(30, 144, 255, 0) 68%),
    linear-gradient(128deg, #0b79d0 0%, #36a9f3 42%, #8bd9ff 100%);
  background-size: 150% 150%;
  color: #fff;
  overflow: hidden;
}

/* Sky gradient animation — off for reduced-motion visitors. */
@media (prefers-reduced-motion: no-preference) {
  .hero { animation: hero-sky 16s ease-in-out infinite alternate; }
}

/* The photograph, when one is set in Settings.

   --hero-shift is written by main.js on each scroll pass. The photograph
   travels at about a third of the page's speed, which reads as depth rather
   than as an effect.

   Scale 1.14 (up from 1.08) gives 14% overscan — enough headroom for the
   parallax to travel at its maximum without showing an edge, even on tall
   viewports where the shift is largest.

   will-change is added only when JS is active (via .js class on <html>), so
   a no-JS visitor does not pay for a composite layer they will never use. */
.hero__media {
  position: absolute; inset: 0; z-index: -2;
  transform: translate3d(0, var(--hero-shift, 0px), 0) scale(1.14);
  background-size: cover; background-position: center;
  /* Isolation promotes ::after to its own stacking context inside this layer,
     decoupling overlay repaints from the parallax transform compositing. */
  isolation: isolate;
}
.js .hero__media { will-change: transform; }

/* The dark wash over the photograph. Isolated inside .hero__media so its
   repaints do not invalidate the parent's composited transform layer. */
.hero__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(168deg, rgba(4, 37, 27, .92) 0%, rgba(6, 52, 34, .80) 45%, rgba(10, 90, 59, .70) 100%);
  /* Pointer events off — this is decoration, and taps on the hero should
     reach the real content behind it. */
  pointer-events: none;
}

/* A drifting light source keeps the sky gradient from feeling static. */
.hero::before {
  content: ""; position: absolute; z-index: -1;
  top: -30%; right: -12%; width: 62vw; height: 62vw; max-width: 780px; max-height: 780px;
  background: radial-gradient(circle, rgba(255,255,255,.36) 0%, rgba(255,255,255,0) 68%);
  pointer-events: none;
  opacity: var(--hero-effect-opacity, 1);
}

@media (prefers-reduced-motion: no-preference) {
  .hero::before { animation: hero-sky-glow 12s ease-in-out infinite alternate; }
}


@keyframes hero-sky {
  from { background-position: 0% 20%; }
  to { background-position: 100% 80%; }
}

@keyframes hero-sky-glow {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to { transform: translate3d(-11%, 12%, 0) scale(1.16); }
}

/* ---- alternate hero styles --------------------------------------------- */
.hero--light { background: var(--white); color: var(--body); }
.hero--light::before { display: none; }

/* Near-black editorial treatment for the alternate hero style. */
.hero--film { background: linear-gradient(168deg, #04120c 0%, var(--brand-900) 55%, var(--brand-800) 100%); }
.hero--film .hero__media { display: none; }
.hero--film .hero__wordmark { color: #fff; }

/* The writing moves off the picture rather than sitting on top of it. Used
   when the subject occupies one side of the frame - this clip has its flowers
   in the top-left corner, so the column goes right and they stay clear. */
@media (min-width: 900px) {
  .hero--right .hero__inner { padding-inline-start: 46%; }
}
.hero--light .hero__media::after { display: none; }

.hero--light .hero__title,
.hero--light .hero__wordmark { color: var(--ink); }
.hero--light .hero__sub { color: var(--body); }
.hero--light .eyebrow--light { color: var(--brand-600); }
.hero--light .eyebrow--light::before { background: var(--brand-200); }
.hero--light .trust { border-block-start-color: var(--line); }
.hero--light .trust__n { color: var(--ink); }
.hero--light .trust__l { color: var(--muted); }

/* =============================================================================
 * HERO STYLE VARIANTS — 7 new professional themes
 * Each variant fully self-contained: background, animation, text colour, overlay.
 * ============================================================================= */

/* Hide photo darkening overlay on all new styles (it's baked into their bg) */
.hero--sunset .hero__media::after,
.hero--midnight .hero__media::after,
.hero--emerald .hero__media::after,
.hero--aurora .hero__media::after,
.hero--rose .hero__media::after,
.hero--charcoal .hero__media::after,
.hero--crystal .hero__media::after { display: none; }

/* ---- Golden Sunset ----------------------------------------- */
.hero--sunset {
  background:
    radial-gradient(ellipse 90% 110% at 0% 0%, rgba(255,255,255,.22) 0%, transparent 55%),
    linear-gradient(135deg, #92400e 0%, #b45309 20%, #d97706 45%, #f59e0b 65%, #ef4444 85%, #dc2626 100%);
  background-size: 220% 220%;
  color: #fff;
}
@media (prefers-reduced-motion: no-preference) {
  .hero--sunset { animation: hero-sunset 14s ease-in-out infinite alternate; }
  .hero--sunset::before { animation: hero-sky-glow 10s ease-in-out infinite alternate; }
}
.hero--sunset::before {
  background: radial-gradient(circle, rgba(255,200,50,.4) 0%, transparent 65%);
}
@keyframes hero-sunset {
  from { background-position: 0% 0%; }
  to   { background-position: 100% 100%; }
}

/* ---- Midnight Navy ----------------------------------------- */
.hero--midnight {
  background:
    radial-gradient(ellipse 70% 80% at 20% 10%, rgba(99,102,241,.5) 0%, transparent 60%),
    radial-gradient(ellipse 60% 60% at 80% 90%, rgba(139,92,246,.4) 0%, transparent 55%),
    linear-gradient(165deg, #0f0c29 0%, #1e1b4b 45%, #312e81 100%);
  background-size: 220% 220%;
  color: #fff;
}
.hero--midnight::before {
  background: radial-gradient(circle, rgba(167,139,250,.3) 0%, transparent 65%);
}
@media (prefers-reduced-motion: no-preference) {
  .hero--midnight { animation: hero-midnight 18s ease-in-out infinite alternate; }
  .hero--midnight::before { animation: hero-sky-glow 14s ease-in-out infinite alternate; }
}
/* Twinkling stars overlay — static by default, animating only when motion is ok. */
.hero--midnight::after {
  content: "";
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image:
    radial-gradient(1.5px 1.5px at 10% 15%, #fff 0%, transparent 100%),
    radial-gradient(1px 1px   at 30% 50%, rgba(255,255,255,.8) 0%, transparent 100%),
    radial-gradient(2px 2px   at 55% 12%, #fff 0%, transparent 100%),
    radial-gradient(1px 1px   at 75% 38%, rgba(255,255,255,.7) 0%, transparent 100%),
    radial-gradient(1.5px 1.5px at 88% 65%, #fff 0%, transparent 100%),
    radial-gradient(1px 1px   at 45% 78%, rgba(255,255,255,.6) 0%, transparent 100%),
    radial-gradient(2px 2px   at 20% 88%, rgba(255,255,255,.9) 0%, transparent 100%),
    radial-gradient(1px 1px   at 65% 4%,  #fff 0%, transparent 100%);
  opacity: calc(0.65 * var(--hero-effect-opacity, 1));
}
@media (prefers-reduced-motion: no-preference) {
  .hero--midnight::after { animation: hero-twinkle 3.5s ease-in-out infinite alternate; }
}
@keyframes hero-midnight {
  from { background-position: 0% 30%; }
  to   { background-position: 100% 70%; }
}
@keyframes hero-twinkle {
  from { opacity: calc(0.5 * var(--hero-effect-opacity, 1)); }
  to   { opacity: var(--hero-effect-opacity, 1); }
}

/* ---- Emerald Forest ---------------------------------------- */
.hero--emerald {
  background:
    radial-gradient(ellipse 80% 100% at 5% 0%, rgba(255,255,255,.18) 0%, transparent 50%),
    radial-gradient(ellipse 70% 80% at 95% 100%, rgba(52,211,153,.4) 0%, transparent 60%),
    linear-gradient(135deg, #022c22 0%, #064e3b 30%, #065f46 60%, #047857 85%, #059669 100%);
  background-size: 200% 200%;
  color: #fff;
}
.hero--emerald::before {
  background: radial-gradient(circle, rgba(52,211,153,.35) 0%, transparent 65%);
}
@media (prefers-reduced-motion: no-preference) {
  .hero--emerald { animation: hero-emerald 16s ease-in-out infinite alternate; }
  .hero--emerald::before { animation: hero-sky-glow 12s ease-in-out infinite alternate; }
}
@keyframes hero-emerald {
  from { background-position: 10% 20%; }
  to   { background-position: 90% 80%; }
}

/* ---- Aurora Borealis --------------------------------------- */
.hero--aurora {
  background:
    radial-gradient(ellipse 100% 55% at 0% 45%, rgba(16,185,129,.6) 0%, transparent 55%),
    radial-gradient(ellipse 80% 65% at 60% 10%, rgba(139,92,246,.55) 0%, transparent 55%),
    radial-gradient(ellipse 60% 75% at 100% 65%, rgba(6,182,212,.5) 0%, transparent 55%),
    linear-gradient(160deg, #0a0f1e 0%, #111827 50%, #0a0f1e 100%);
  background-size: 260% 220%;
  color: #fff;
}
.hero--aurora::before {
  background: radial-gradient(ellipse 80% 50% at 50% 0%, rgba(52,211,153,.35) 0%, transparent 70%);
}
@media (prefers-reduced-motion: no-preference) {
  .hero--aurora { animation: hero-aurora 20s ease-in-out infinite alternate; }
  .hero--aurora::before { animation: hero-aurora-glow 8s ease-in-out infinite alternate; }
}
@keyframes hero-aurora {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 50% 0%; }
}
@keyframes hero-aurora-glow {
  from { transform: translate3d(-10%, 0, 0) scaleX(1);   opacity: .65; }
  to   { transform: translate3d(10%, 15%, 0) scaleX(1.3); opacity: 1; }
}

/* ---- Rose Gold --------------------------------------------- */
.hero--rose {
  background:
    radial-gradient(ellipse 90% 100% at 0% 0%, rgba(255,255,255,.28) 0%, transparent 50%),
    radial-gradient(ellipse 70% 90% at 100% 100%, rgba(251,113,133,.45) 0%, transparent 55%),
    linear-gradient(135deg, #4c0519 0%, #881337 25%, #be123c 50%, #f43f5e 72%, #fb7185 88%, #fecdd3 100%);
  background-size: 220% 220%;
  color: #fff;
}
.hero--rose::before {
  background: radial-gradient(circle, rgba(253,164,175,.4) 0%, transparent 65%);
}
@media (prefers-reduced-motion: no-preference) {
  .hero--rose { animation: hero-rose 15s ease-in-out infinite alternate; }
  .hero--rose::before { animation: hero-sky-glow 11s ease-in-out infinite alternate; }
}
@keyframes hero-rose {
  from { background-position: 0% 0%; }
  to   { background-position: 100% 100%; }
}

/* ---- Charcoal Noir ----------------------------------------- */
.hero--charcoal {
  background:
    radial-gradient(ellipse 70% 80% at 100% 0%, rgba(99,102,241,.25) 0%, transparent 55%),
    radial-gradient(ellipse 60% 70% at 0% 100%, rgba(14,165,233,.2) 0%, transparent 50%),
    linear-gradient(160deg, #030712 0%, #111827 45%, #1f2937 80%, #374151 100%);
  background-size: 200% 200%;
  color: #fff;
}
.hero--charcoal::before {
  background: radial-gradient(circle, rgba(99,102,241,.22) 0%, transparent 65%);
}
@media (prefers-reduced-motion: no-preference) {
  .hero--charcoal { animation: hero-charcoal 18s ease-in-out infinite alternate; }
  .hero--charcoal::before { animation: hero-sky-glow 13s ease-in-out infinite alternate; }
}
@keyframes hero-charcoal {
  from { background-position: 0% 20%; }
  to   { background-position: 100% 80%; }
}

/* ---- Crystal Clear ----------------------------------------- */
/* Uses a bright frosted-glass sky. Text is dark to stay readable. */
.hero--crystal {
  background:
    radial-gradient(ellipse 100% 70% at 50% -5%, rgba(255,255,255,.98) 0%, rgba(255,255,255,0) 55%),
    radial-gradient(ellipse 80% 60% at 0% 100%, rgba(186,230,253,.8) 0%, transparent 55%),
    radial-gradient(ellipse 70% 60% at 100% 100%, rgba(216,180,254,.6) 0%, transparent 55%),
    linear-gradient(180deg, #f0f9ff 0%, #e0f2fe 35%, #bae6fd 65%, #c4b5fd 100%);
  background-size: 220% 220%;
  /* Override shared white — crystal is a light bg with dark text */
  color: #1e3a5f !important;
}
.hero--crystal::before {
  background: radial-gradient(circle, rgba(255,255,255,.65) 0%, transparent 60%);
}
@media (prefers-reduced-motion: no-preference) {
  .hero--crystal { animation: hero-crystal 16s ease-in-out infinite alternate; }
  .hero--crystal::before { animation: hero-sky-glow 10s ease-in-out infinite alternate; }
}
/* Moving light-refraction shimmer band — only animates when motion is welcome. */
.hero--crystal::after {
  content: "";
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(110deg,
    transparent 20%,
    rgba(255,255,255,.55) 35%,
    rgba(200,230,255,.35) 50%,
    rgba(255,255,255,.55) 65%,
    transparent 80%);
  background-size: 250% 100%;
}
@media (prefers-reduced-motion: no-preference) {
  .hero--crystal::after { animation: hero-crystal-shimmer 6s ease-in-out infinite; }
}
.hero--crystal .hero__title,
.hero--crystal .hero__wordmark { color: #0c3460 !important; }
.hero--crystal .hero__sub      { color: #1e4d7b !important; }
.hero--crystal .eyebrow--light { color: #0369a1 !important; }
.hero--crystal .eyebrow--light::before { background: rgba(3,105,161,.25); }
/* Trust strip reads well on light background */
.hero--crystal .trust { border-block-start-color: rgba(3,105,161,.2); }
.hero--crystal .trust__n { color: #0c3460; }
.hero--crystal .trust__l { color: #0369a1; }
@keyframes hero-crystal {
  from { background-position: 0% 0%; }
  to   { background-position: 100% 100%; }
}
@keyframes hero-crystal-shimmer {
  0%   { background-position: 200% 0; opacity: calc(0.6 * var(--hero-effect-opacity, 1)); }
  50%  { opacity: var(--hero-effect-opacity, 1); }
  100% { background-position: -50% 0; opacity: calc(0.6 * var(--hero-effect-opacity, 1)); }
}


/* The name, set as big as the page will take. This is a wordmark rather than a
   heading: it says who the office is before it says anything about property,
   which is the whole point of putting it at this size. */
.hero__wordmark {
  margin: 0 0 var(--s4);
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(2.2rem, 0.6rem + 7.4vw, 7.4rem);
  line-height: .94; letter-spacing: -.045em;
  color: var(--ink); text-wrap: balance;
  font-variation-settings: "SOFT" 0, "WONK" 1, "opsz" 144;
}
.is-rtl .hero__wordmark { letter-spacing: 0; line-height: 1.6; }

.hero__inner {
  position: relative;
  /* Give the content a bit more breathing room on narrow phones. */
  padding-inline: 0;
}
.hero__title {
  color: #fff; font-size: var(--t-5); max-width: 15ch;
  margin-bottom: var(--s4); letter-spacing: -.025em;
  font-variation-settings: "SOFT" 0, "WONK" 1, "opsz" 144;
  /* Prevent the title from overflowing on very narrow viewports. */
  overflow-wrap: break-word;
}
.hero__sub {
  max-width: 54ch; font-size: var(--t-1); color: rgba(255,255,255,.82);
  margin-bottom: var(--s7);
}

.hero__search {
  background: rgba(255, 255, 255, .97);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-4);
  overflow: hidden;
}

.purpose-tabs {
  display: flex; gap: 2px; padding: var(--s2) var(--s2) 0;
  border-bottom: 1px solid var(--line-soft); background: var(--surface);
}
.purpose-tabs__tab {
  padding: 12px 24px; border-radius: var(--r) var(--r) 0 0;
  font-weight: 600; font-size: var(--t--1); color: var(--muted);
  transition: background .16s var(--ease), color .16s var(--ease);
}
.purpose-tabs__tab:hover { background: rgba(255,255,255,.7); color: var(--ink); }
.purpose-tabs__tab.is-active { color: var(--brand-700); background: #fff; font-weight: 700; }
/* Keyboard focus indicator — tabs lacked any visible outline. */
.purpose-tabs__tab:focus-visible {
  outline: 2.5px solid var(--brand-500);
  outline-offset: -2px;
}

/* ------------------------------------------------------------ trust band --- */

.trust {
  display: grid; gap: var(--s4);
  /* 120px min allows 4 columns at 480px+ without clipping on 360px phones. */
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  margin-top: var(--s7); padding-top: var(--s6);
  border-top: 1px solid rgba(255,255,255,.16);
}
.trust__item { text-align: left; }
.trust__n {
  display: block;
  font-family: var(--font-display); font-size: var(--t-3); font-weight: 600;
  color: #fff; line-height: 1; letter-spacing: -.02em;
  font-variation-settings: "opsz" 40;
}
.trust__l { display: block; margin-top: 6px; font-size: var(--t--1); color: rgba(255,255,255,.66); }

/* Below 480px, collapse trust to a 2-column layout so numbers breathe. */
@media (max-width: 480px) {
  .trust { grid-template-columns: repeat(2, 1fr); gap: var(--s4) var(--s5); }
  .trust__n { font-size: var(--t-2); }
}

/* ---------------------------------------------------------------- filters -- */

.filters { padding: var(--s5); }

/* Grid rather than wrapped flex. Six controls on a flex row do not divide into
   the space - the last one to fit stretches to fill whatever is left and the
   row reads as a mistake. auto-fit gives every control the same width and
   breaks to an even number per line at any width, which is the whole job of a
   filter bar. */
.filters__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  gap: var(--s3);
  align-items: end;
}
/* Only once there are two columns to span. Below that the span would create a
   second column that is not there and push the row off the side. */
@media (min-width: 560px) {
  .filters__row > .field--grow { grid-column: span 2; }
}
.filters__row + .filters__row { margin-top: var(--s3); }
.filters__clear { margin: var(--s3) 0 0; font-size: var(--t--1); }

/* ---- the hero's search bar ---------------------------------------------- */

/* Four controls on one line, sized so the whole thing reads as a single bar
   rather than as a form. The heights are pinned to one value: a select and an
   input and a button each compute their own from padding and line-height, and
   left alone they land two or three pixels apart, which is exactly the sort of
   thing that makes a bar look wrong without anybody being able to say why. */
.filters--compact { padding: var(--s3); }
.filters--compact .filters__row {
  grid-template-columns: minmax(0, 2.4fr) minmax(0, 1fr) minmax(0, 1fr) auto;
  gap: var(--s2);
  align-items: center;
}
.filters--compact .filters__row > .field--grow { grid-column: auto; }

.filters--compact .field input,
.filters--compact .field select,
.filters--compact .field--action .btn {
  height: 52px;
  margin: 0;
}
.filters--compact .field--action .btn { padding-inline: var(--s6); white-space: nowrap; }

/* The bar folds in two steps rather than one. In between - a tablet, and the
   narrowed column the right-hand hero treatment creates - the search keeps the
   full width and the two menus share the line under it. */
@media (max-width: 780px) {
  .filters--compact .filters__row { grid-template-columns: 1fr 1fr; }
  .filters--compact .filters__row > .field--grow,
  .filters--compact .filters__row > .field--action { grid-column: 1 / -1; }
  .filters--compact .field--action .btn { width: 100%; }
}
/* 380–500px: the 2-column layout is still viable but the inputs need to shrink
   slightly to avoid overflow on the narrowest common Android widths. */
@media (max-width: 500px) {
  .filters--compact .field input,
  .filters--compact .field select { height: 48px; font-size: var(--t--1); }
  .filters--compact .field--action .btn { height: 48px; }
}
@media (max-width: 430px) {
  .filters--compact .filters__row { grid-template-columns: 1fr; }
  /* Also shrink the search box corners so it doesn't feel over-rounded on
     a narrow phone where the box nearly fills the width. */
  .hero__search { border-radius: var(--r-lg); }
}

.field { display: flex; flex-direction: column; gap: 6px; flex: 1 1 170px; min-width: 0; }
.field--grow { flex: 2 1 260px; }
.field--action { flex: 0 0 auto; justify-content: flex-end; }
.field label {
  font-size: var(--t--1); font-weight: 600; color: var(--ink-soft);
  letter-spacing: .01em;
}
.req { color: var(--bad); }

input[type="text"], input[type="search"], input[type="tel"], input[type="email"],
input[type="password"], input[type="number"], input[type="url"], input[type="date"],
select, textarea {
  width: 100%; padding: 12px 14px;
  border: 1.5px solid var(--line); border-radius: var(--r);
  font: inherit; font-size: var(--t-0); color: var(--ink); background: #fff;
  transition: border-color .16s var(--ease), box-shadow .16s var(--ease);
}
select {
  appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%2374857d' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round' d='m1 1.5 5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; background-size: 11px;
  padding-right: 38px;
}
textarea { resize: vertical; min-height: 104px; line-height: 1.6; }

input:hover, select:hover, textarea:hover { border-color: var(--brand-200); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 4px var(--brand-50);
}
::placeholder { color: var(--faint); }

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

.grid { display: grid; gap: var(--gap); }
.grid--cards { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.grid--posts { grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); }
.grid--areas { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--s4); }

.card {
  position: relative;
  display: flex; flex-direction: column;
  background: #fff; border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden; box-shadow: var(--sh-1);
  transition: box-shadow .26s var(--ease), transform .26s var(--ease), border-color .26s var(--ease);
}
.card:hover { box-shadow: var(--sh-3); transform: translateY(-4px); --rv-lift: -4px; border-color: transparent; }
.card--sold { opacity: .88; }

.card__media {
  position: relative; display: block; overflow: hidden;
  background: var(--surface-2); aspect-ratio: 4 / 3;
}
.card__media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .5s var(--ease);
}
.card:hover .card__media img { transform: scale(1.045); }

/* Keeps white badge text legible over a bright sky in the top of a photo. */
.card__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(4, 37, 27, .28) 0%, rgba(4, 37, 27, 0) 34%);
  pointer-events: none;
}

.card__tags {
  position: absolute; z-index: 1; top: var(--s3); left: var(--s3);
  display: flex; gap: 6px; flex-wrap: wrap; max-width: calc(100% - var(--s5));
}
.tag {
  display: inline-block; padding: 5px 11px; border-radius: var(--r-full);
  font-size: .68rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  backdrop-filter: blur(6px);
}
.tag--purpose { background: rgba(255,255,255,.94); color: var(--brand-800); }
.tag--sold { background: rgba(15, 31, 25, .82); color: #fff; }
.tag--verified {
  background: rgba(253, 248, 238, .94); color: var(--gold-700);
  display: inline-flex; align-items: center; gap: 4px;
}

.card__body { padding: var(--s5); display: flex; flex-direction: column; gap: var(--s2); flex: 1; }

.card__price {
  margin: 0; font-family: var(--font-display); font-size: var(--t-2);
  font-weight: 600; color: var(--ink); letter-spacing: -.02em; line-height: 1.1;
  font-variation-settings: "opsz" 30;
}
.card__period { font-family: var(--font-sans); font-size: .78rem; font-weight: 500; color: var(--muted); }

.card__title { margin: 0; font-size: var(--t-0); line-height: 1.4; font-weight: 600; }
.card__title a { color: var(--ink); }
/* The whole card is clickable, but only the title is a real link — this keeps
   the tab order sane while giving a big hit area. */
.card__title a::before { content: ""; position: absolute; inset: 0; z-index: 2; }
.card:hover .card__title a { color: var(--brand-600); }

.card__where {
  display: flex; align-items: center; gap: 6px; margin: 0;
  font-size: var(--t--1); color: var(--muted);
}
.card__where svg { flex: 0 0 auto; opacity: .8; }

.card__specs {
  display: flex; flex-wrap: wrap; gap: 6px var(--s4);
  margin: auto 0 0; padding: var(--s3) 0 0;
  list-style: none; border-top: 1px solid var(--line-soft);
  font-size: var(--t--1); color: var(--body);
}
.card__specs li { display: inline-flex; align-items: center; gap: 5px; }
.card__specs li + li::before {
  content: ""; width: 3px; height: 3px; border-radius: 50%;
  background: var(--line); margin-inline-end: 5px;
}
.card__specs abbr { text-decoration: none; border: 0; font-weight: 600; color: var(--ink-soft); }

.card__ref {
  margin: 0; font-size: .68rem; color: var(--faint);
  letter-spacing: .08em; font-weight: 500;
}

/* ------------------------------------------------------------- area tiles -- */

.area-tile {
  position: relative; display: flex; flex-direction: column; gap: 3px;
  padding: var(--s4) var(--s5); background: #fff;
  border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden;
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease), transform .2s var(--ease);
}
.area-tile::after {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--brand); transform: scaleY(0); transform-origin: top;
  transition: transform .24s var(--ease);
}
.area-tile:hover {
  border-color: var(--brand-100); box-shadow: var(--sh-2); transform: translateY(-2px); --rv-lift: -2px;
}
.area-tile:hover::after { transform: scaleY(1); }
.area-tile__name { font-weight: 650; color: var(--ink); font-size: var(--t-0); }
.area-tile__count { font-size: var(--t--2); color: var(--muted); }

.chips { display: flex; flex-wrap: wrap; gap: var(--s2); }
.chips--sub { margin-bottom: var(--s6); }
.chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 17px; border-radius: var(--r-full);
  background: #fff; border: 1.5px solid var(--line);
  font-size: var(--t--1); font-weight: 550; color: var(--body);
  transition: background .16s var(--ease), border-color .16s var(--ease), color .16s var(--ease);
}
.chip:hover { background: var(--brand-50); border-color: var(--brand-200); color: var(--brand-700); }
.chip__n { font-size: .72rem; color: var(--muted); }

/* ------------------------------------------------------------- page heads -- */

.crumbs { padding: var(--s5) 0 0; font-size: var(--t--1); }
.crumbs ol { display: flex; flex-wrap: wrap; gap: 7px; list-style: none; margin: 0; padding: 0; }
.crumbs li { display: inline-flex; align-items: center; gap: 7px; }
.crumbs li + li::before { content: "\203A"; color: var(--faint); }
.crumbs a { color: var(--muted); }
.crumbs a:hover { color: var(--brand-600); }
.crumbs span { color: var(--ink-soft); font-weight: 550; }

.page-head { padding: var(--s6) 0 var(--s5); }
.page-head__title { margin-bottom: .18em; }
.page-head__count { margin: 0; color: var(--muted); font-size: var(--t-1); }
.page-head__ur { font-family: var(--font-ur); font-size: var(--t-2); margin: 0 0 .3em; line-height: 2; }

.toolbar {
  display: flex; justify-content: flex-end; align-items: center;
  margin: var(--s6) 0 var(--s5);
}
.toolbar__sort { display: inline-flex; align-items: center; gap: var(--s3); font-size: var(--t--1); color: var(--muted); }
.toolbar__sort select { width: auto; padding-block: 9px; font-size: var(--t--1); }

/* -------------------------------------------------------------- property --- */

.banner {
  padding: var(--s4) var(--s5); border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--line);
  font-size: var(--t-0); margin: var(--s5) 0;
}
.banner--sold { background: var(--gold-50); border-color: var(--gold-200); color: var(--gold-700); }

.property__head {
  display: flex; flex-wrap: wrap; gap: var(--s5) var(--s8);
  align-items: flex-start; justify-content: space-between;
  padding: var(--s4) 0 var(--s6);
}
.property__title { margin-bottom: .18em; max-width: 20ch; }
.property__title-ur { font-family: var(--font-ur); font-size: var(--t-2); margin: 0 0 .35em; color: var(--ink); line-height: 2.1; }
.property__where {
  margin: 0; color: var(--muted); font-size: var(--t-1);
  display: flex; align-items: center; gap: 7px;
}

.property__price { text-align: right; flex: 0 0 auto; }
.property__price-main {
  margin: 0; font-family: var(--font-display); font-size: var(--t-4);
  font-weight: 600; color: var(--brand-700); letter-spacing: -.03em; line-height: 1;
  font-variation-settings: "opsz" 60;
}
.property__period { display: block; font-family: var(--font-sans); font-size: var(--t--1); font-weight: 500; color: var(--muted); margin-top: 6px; }
.property__price-exact { margin: 7px 0 0; font-size: var(--t--1); color: var(--muted); }
.property__negotiable {
  display: inline-flex; align-items: center; gap: 6px;
  margin: var(--s3) 0 0; padding: 5px 12px; border-radius: var(--r-full);
  background: var(--gold-50); border: 1px solid var(--gold-200);
  font-size: var(--t--1); color: var(--gold-700); font-weight: 600;
}

/* ---- gallery ---- */

.gallery { margin-bottom: var(--s7); }
.gallery__main {
  position: relative; margin: 0; border-radius: var(--r-lg);
  overflow: hidden; background: var(--surface-2);
}
.gallery__zoom {
  display: block; width: 100%; padding: 0; margin: 0;
  border: 0; background: none; cursor: zoom-in;
}
.gallery__main img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.gallery__zoom:focus-visible { outline-offset: -4px; }
.gallery__count {
  position: absolute; right: var(--s4); bottom: var(--s4);
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 14px; border-radius: var(--r-full);
  background: rgba(15, 31, 25, .72); backdrop-filter: blur(8px);
  color: #fff; font-size: var(--t--1); font-weight: 600;
}

.gallery__thumbs {
  display: flex; gap: var(--s3); margin-top: var(--s3);
  overflow-x: auto; padding-bottom: var(--s1);
  scrollbar-width: thin; scroll-snap-type: x proximity;
}
.gallery__thumb {
  flex: 0 0 auto; width: 118px; padding: 0; cursor: pointer;
  border: 2px solid transparent; border-radius: var(--r); overflow: hidden;
  background: none; scroll-snap-align: start;
  transition: border-color .18s var(--ease), opacity .18s var(--ease);
  opacity: .68;
}
.gallery__thumb img { width: 118px; height: 82px; object-fit: cover; }
/* The <picture> only exists to carry the WebP twin. display:contents takes it
   out of the layout so the image is still the direct child it was before. */
.gallery__thumb picture, .mini-list picture { display: contents; }
.gallery__thumb:hover { opacity: 1; }
.gallery__thumb.is-active { border-color: var(--brand); opacity: 1; }

/* ---- body ---- */

.property__body {
  display: grid; gap: var(--s8);
  grid-template-columns: minmax(0, 1fr) 360px;
  align-items: start; padding-bottom: var(--s8);
}
.property__aside { position: sticky; top: 96px; display: flex; flex-direction: column; gap: var(--s5); }

.spec-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1px; background: var(--line-soft);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden; margin-bottom: var(--s7);
}
.spec { background: #fff; padding: var(--s4) var(--s5); }
.spec dt {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .09em;
  color: var(--muted); margin-bottom: 5px; font-weight: 650;
}
.spec dd { margin: 0; font-weight: 650; color: var(--ink); font-size: var(--t-0); }

.feature-list {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--s3) var(--s5); list-style: none; padding: 0; margin: 0;
}
.feature-list li { display: flex; align-items: center; gap: var(--s2); font-size: var(--t-0); }
.feature-list svg {
  color: var(--brand); flex: 0 0 auto;
  background: var(--brand-50); border-radius: 50%; padding: 4px; box-sizing: content-box;
}

.cta-card {
  background: linear-gradient(160deg, var(--brand-800), var(--brand-600));
  border-radius: var(--r-lg); padding: var(--s5);
  display: flex; flex-direction: column; gap: var(--s3);
  box-shadow: var(--sh-2); color: #fff;
}
.cta-card__ref {
  margin: 0 0 var(--s1); font-size: var(--t--1); color: rgba(255,255,255,.7);
  letter-spacing: .04em;
}
.cta-card__ref strong { color: #fff; letter-spacing: .08em; }
.cta-card__hours { margin: var(--s1) 0 0; font-size: var(--t--1); color: rgba(255,255,255,.62); text-align: center; }

/* Phone-only fixed call/WhatsApp bar. On a property page this is the single
   highest-value control on the screen, so it never scrolls away. */
.sticky-cta {
  position: fixed; z-index: 55; inset-inline: 0; bottom: 0;
  display: none; gap: var(--s2); padding: var(--s2) var(--s3);
  padding-bottom: calc(var(--s2) + env(safe-area-inset-bottom, 0px));
  background: rgba(255,255,255,.94); backdrop-filter: blur(14px);
  border-top: 1px solid var(--line); box-shadow: 0 -4px 20px rgba(9,42,30,.10);
}
.sticky-cta .btn { flex: 1; padding-block: 13px; }

/* ------------------------------------------------------------------ lead --- */

.lead {
  background: #fff; border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--s6); box-shadow: var(--sh-1);
}
.lead__h { font-size: var(--t-1); margin-bottom: .3em; font-family: var(--font-sans); font-weight: 650; }
.lead__intro { font-size: var(--t--1); color: var(--muted); margin-bottom: var(--s5); }
.lead__form { display: flex; flex-direction: column; gap: var(--s4); }
.lead__note { margin: 0; font-size: .74rem; color: var(--muted); text-align: center; line-height: 1.5; }

.notice {
  padding: var(--s4) var(--s5); border-radius: var(--r);
  font-size: var(--t-0); margin-bottom: var(--s5);
  display: flex; gap: var(--s3); align-items: flex-start;
}
.notice--ok  { background: var(--ok-bg); color: var(--ok); border: 1px solid #bfe0cd; }
.notice--bad { background: var(--bad-bg); color: var(--bad); border: 1px solid #efc8c8; }

/* ------------------------------------------------------------------ prose -- */

.prose { max-width: 68ch; margin-bottom: var(--s7); font-size: var(--t-0); line-height: 1.75; }
.prose h2 { margin-top: 1.7em; font-size: var(--t-2); }
.prose h2:first-child { margin-top: 0; }
.prose h3 { margin-top: 1.5em; }
.prose ul, .prose ol { padding-inline-start: 1.35em; margin: 0 0 1.1em; }
.prose li { margin-bottom: .45em; }
.prose li::marker { color: var(--brand-200); }
.prose blockquote {
  margin: 1.6em 0; padding: var(--s2) 0 var(--s2) var(--s5);
  border-inline-start: 3px solid var(--brand-200);
  color: var(--ink-soft); font-family: var(--font-display); font-size: var(--t-1);
  font-style: italic; line-height: 1.5;
}
.prose blockquote p:last-child { margin-bottom: 0; }
.prose code { background: var(--surface-2); padding: 2px 6px; border-radius: 5px; font-size: .9em; }
.prose--intro { max-width: 72ch; margin-bottom: var(--s6); font-size: var(--t-1); color: var(--body); }
.prose--fineprint {
  font-size: var(--t--1); color: var(--muted);
  border-top: 1px solid var(--line-soft); padding-top: var(--s5);
}

.ticks { list-style: none; padding: 0; margin: 0 0 var(--s6); }
.ticks li { position: relative; padding-inline-start: 34px; margin-bottom: var(--s4); }
.ticks li::before {
  content: ""; position: absolute; inset-inline-start: 0; top: 1px;
  width: 22px; height: 22px; border-radius: 50%; background: var(--brand-50);
}
.ticks li::after {
  content: ""; position: absolute; inset-inline-start: 7px; top: 8px;
  width: 8px; height: 4px;
  border-inline-start: 2px solid var(--brand); border-bottom: 2px solid var(--brand);
  transform: rotate(-45deg);
}
.ticks strong { color: var(--ink); }

.steps { counter-reset: step; list-style: none; padding: 0; margin: 0 0 var(--s6); }
.steps li { position: relative; padding-inline-start: 46px; margin-bottom: var(--s5); }
.steps li::before {
  counter-increment: step; content: counter(step);
  position: absolute; inset-inline-start: 0; top: -1px;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--brand-50); color: var(--brand-700);
  display: grid; place-items: center;
  font-size: var(--t--1); font-weight: 700;
}
.steps strong { color: var(--ink); }

/* ------------------------------------------------------------------ split -- */

.split { display: grid; gap: var(--s8); grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); align-items: start; }
.split__cta { display: flex; flex-wrap: wrap; gap: var(--s3); }
.split__aside {
  background: #fff; border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--s5); box-shadow: var(--sh-1);
}
.split__h { font-size: var(--t-0); margin-bottom: var(--s4); font-family: var(--font-sans); font-weight: 650; }
.split__more { font-size: var(--t--1); font-weight: 650; }

.mini-list { list-style: none; padding: 0; margin: 0 0 var(--s4); }
.mini-list li + li { border-top: 1px solid var(--line-soft); }
.mini-list a { display: flex; gap: var(--s3); align-items: center; padding: var(--s3) 0; color: var(--ink); }
.mini-list a:hover strong { color: var(--brand-600); }
.mini-list img { width: 76px; height: 58px; object-fit: cover; border-radius: var(--r-sm); flex: 0 0 auto; }
.mini-list strong { display: block; font-size: var(--t--1); font-weight: 600; line-height: 1.4; }
.mini-list em {
  font-style: normal; font-size: var(--t--1); color: var(--brand-600);
  font-weight: 650; font-family: var(--font-display); font-variation-settings: "opsz" 14;
}

/* ------------------------------------------------------------------ posts -- */

.post-card {
  background: #fff; border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden; display: flex; flex-direction: column; position: relative;
  box-shadow: var(--sh-1);
  transition: box-shadow .26s var(--ease), transform .26s var(--ease);
}
.post-card:hover { box-shadow: var(--sh-3); transform: translateY(-4px); --rv-lift: -4px; }
.post-card__media { overflow: hidden; }
.post-card__media img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; transition: transform .5s var(--ease); }
.post-card:hover .post-card__media img { transform: scale(1.045); }
.post-card__body { padding: var(--s5); }
.post-card__date {
  margin: 0 0 var(--s2); font-size: .7rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: .09em; font-weight: 650;
}
.post-card h2, .post-card h3 { font-size: var(--t-1); margin-bottom: .35em; font-family: var(--font-display); }
.post-card h2 a, .post-card h3 a { color: var(--ink); }
.post-card h2 a::before, .post-card h3 a::before { content: ""; position: absolute; inset: 0; }
.post-card:hover h2 a, .post-card:hover h3 a { color: var(--brand-600); }

.article { padding: var(--s4) 0 var(--s8); }
.article__head { margin-bottom: var(--s6); }
.article__title { margin-bottom: .2em; }
.article__meta { margin: 0; font-size: var(--t--1); color: var(--muted); }
.article__cover { margin: 0 0 var(--s7); border-radius: var(--r-lg); overflow: hidden; }

/* ---------------------------------------------------------------- contact -- */

.contact-grid {
  display: grid; gap: var(--s8);
  grid-template-columns: minmax(0, 1fr) minmax(0, 430px);
  align-items: start; padding-bottom: var(--s8);
}
.contact-cards {
  list-style: none; padding: 0; margin: 0; display: grid; gap: var(--s4);
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}
.contact-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); padding: var(--s5);
}
.contact-card h2 {
  font-family: var(--font-sans); font-size: .7rem; text-transform: uppercase;
  letter-spacing: .1em; color: var(--muted); margin-bottom: .7em; font-weight: 700;
}
.contact-card p:last-child { margin-bottom: 0; }
.contact-card__big {
  font-family: var(--font-display); font-size: var(--t-2);
  font-weight: 600; color: var(--ink); letter-spacing: -.02em;
}

/* ----------------------------------------------------------------- footer -- */

.site-foot {
  background: var(--brand-900); color: #9fbfb0;
  padding: var(--s9) 0 0; margin-top: var(--s8);
  font-size: var(--t--1);
}
.site-foot a { color: #cfe3d8; }
.site-foot a:hover { color: #fff; }
.site-foot__grid {
  display: grid; gap: var(--s7) var(--s5);
  grid-template-columns: 1.6fr repeat(3, 1fr);
  padding-bottom: var(--s8);
}
.site-foot__name {
  color: #fff; font-family: var(--font-display); font-size: var(--t-1);
  font-weight: 600; margin-bottom: .3em; letter-spacing: -.01em;
}
.site-foot__col--brand .muted { color: #86a898; max-width: 34ch; }
.site-foot__h {
  color: #fff; font-family: var(--font-sans); font-size: .7rem;
  text-transform: uppercase; letter-spacing: .12em; margin-bottom: 1.4em; font-weight: 700;
}

.link-list { list-style: none; padding: 0; margin: 0; }
.link-list li { margin-bottom: var(--s3); }
.link-list--lg li { margin-bottom: var(--s4); font-size: var(--t-0); }

.contact-list { list-style: none; padding: 0; margin: var(--s5) 0 0; }
.contact-list li { margin-bottom: var(--s3); color: #bcd6c8; }
.contact-list__k {
  display: block; font-size: .66rem; text-transform: uppercase;
  letter-spacing: .11em; color: #6f9384; margin-bottom: 2px; font-weight: 650;
}

.social { display: flex; gap: var(--s3); margin-top: var(--s5); }
.social a {
  display: grid; place-items: center; width: 38px; height: 38px;
  border: 1px solid rgba(255,255,255,.16); border-radius: 50%;
  transition: background .16s var(--ease), border-color .16s var(--ease);
}
.social a:hover { background: rgba(255,255,255,.1); border-color: rgba(255,255,255,.3); }

.site-foot__legal {
  border-top: 1px solid rgba(255,255,255,.1);
  padding: var(--s5) 0 var(--s7);
  display: flex; flex-wrap: wrap; gap: var(--s3) var(--s7); align-items: baseline;
}
.site-foot__legal p { margin: 0; }
.site-foot__legal .muted { color: #7e9e90; max-width: 74ch; font-size: .74rem; line-height: 1.6; }

/* ------------------------------------------------------------------ pager -- */

.pager { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; padding: var(--s8) 0 var(--s2); }
.pager__link {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; height: 44px; padding: 0 var(--s4);
  border: 1.5px solid var(--line); border-radius: var(--r);
  font-size: var(--t--1); font-weight: 600; color: var(--body); background: #fff;
  transition: border-color .16s var(--ease), background .16s var(--ease), color .16s var(--ease);
}
.pager__link:hover { border-color: var(--brand-200); background: var(--brand-50); color: var(--brand-700); }
.pager__link.is-current { background: var(--brand); border-color: var(--brand); color: #fff; }
.pager__gap { display: inline-flex; align-items: center; padding: 0 var(--s1); color: var(--faint); }

/* ------------------------------------------------------------------ empty -- */

.empty { text-align: center; padding: var(--s9) var(--s5); }
.empty h1, .empty h2 { margin-bottom: .35em; }
.empty p { max-width: 52ch; margin-inline: auto; color: var(--muted); font-size: var(--t-1); }
.empty__code {
  font-family: var(--font-display); font-size: clamp(4rem, 12vw, 7rem);
  font-weight: 600; color: var(--brand-100); margin: 0; line-height: .9;
  letter-spacing: -.04em;
}
.empty__actions { display: flex; flex-wrap: wrap; gap: var(--s3); justify-content: center; margin-top: var(--s6); }
.empty__search { max-width: 460px; margin: var(--s7) auto 0; text-align: left; }
.empty__search label { display: block; font-size: var(--t--1); font-weight: 600; color: var(--ink-soft); margin-bottom: 6px; }
.empty__search-row { display: flex; gap: var(--s2); }

/* --------------------------------------------------------------- lightbox -- */

.lightbox {
  position: fixed; inset: 0; z-index: 200;
  display: none; align-items: center; justify-content: center;
  background: rgba(4, 20, 15, .94);
  padding: var(--s5);
  opacity: 0; transition: opacity .2s var(--ease);
}
.lightbox.is-open { display: flex; opacity: 1; }
.lightbox img {
  max-width: min(1200px, 94vw); max-height: 86vh;
  width: auto; border-radius: var(--r); box-shadow: var(--sh-4);
}
.lightbox__bar {
  position: absolute; top: 0; inset-inline: 0;
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--s4) var(--s5); color: #fff;
}
.lightbox__count { font-size: var(--t--1); color: rgba(255,255,255,.7); letter-spacing: .04em; }
.lightbox__btn {
  display: grid; place-items: center; width: 46px; height: 46px;
  border: 1px solid rgba(255,255,255,.2); border-radius: 50%;
  background: rgba(255,255,255,.08); color: #fff; cursor: pointer;
  transition: background .16s var(--ease);
}
.lightbox__btn:hover { background: rgba(255,255,255,.18); }
.lightbox__nav { position: absolute; top: 50%; transform: translateY(-50%); }
.lightbox__nav--prev { inset-inline-start: var(--s5); }
.lightbox__nav--next { inset-inline-end: var(--s5); }

/* --------------------------------------------------------------- floating -- */

.wa-float {
  position: fixed; inset-block-end: var(--s5); inset-inline-end: var(--s5); z-index: 50;
  display: grid; place-items: center; width: 58px; height: 58px;
  background: #1faa54; color: #fff; border-radius: 50%;
  box-shadow: 0 6px 22px rgba(31, 170, 84, .42);
  transition: transform .2s var(--ease), box-shadow .2s var(--ease);
}
.wa-float:hover { transform: scale(1.06); color: #fff; box-shadow: 0 10px 30px rgba(31, 170, 84, .52); }

/* ------------------------------------------------------------- policies --- */

/* Terms of dealing. Set at normal reading size on a tinted panel, not as
   small print — a term the buyer cannot comfortably read protects nobody. */
.policies {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s6);
  margin-bottom: var(--s7);
  max-width: 72ch;
}
.policies__h {
  font-size: var(--t-1);
  font-family: var(--font-sans);
  font-weight: 650;
  margin-bottom: var(--s5);
}
.policies__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s5);
  counter-reset: policy;
}

.policy { display: flex; gap: var(--s4); align-items: flex-start; }
.policy__icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--brand-50);
  color: var(--brand-600);
  border: 1px solid var(--brand-100);
}
.policy__body { flex: 1; min-width: 0; }
.policy__title {
  margin: 0 0 4px;
  font-size: var(--t-0);
  font-family: var(--font-sans);
  font-weight: 650;
}
.policy__text { margin: 0; font-size: var(--t-0); color: var(--body); }

/* The other language, quieter but still legible. */
.policy__alt {
  margin: var(--s2) 0 0;
  padding-top: var(--s2);
  border-top: 1px dashed var(--line);
  font-size: var(--t--1);
  color: var(--muted);
}
.policy__alt[lang="ur"] { font-family: var(--font-ur); line-height: 2; font-size: .9rem; }
.policy__alt[lang="en"] { line-height: 1.6; }

@media (max-width: 620px) {
  .policies { padding: var(--s5); }
  .policy { gap: var(--s3); }
  .policy__icon { width: 30px; height: 30px; }
}

/* ---------------------------------------------------------- credentials --- */

/* Compact row in the footer. Quiet on purpose: a business that is genuinely
   registered states it once and moves on. */
.trustbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3) var(--s5);
  max-width: var(--wrap); margin-inline: auto;
  padding: var(--s5) var(--s5) 0;
  border-top: 1px solid rgba(255, 255, 255, .1);
}
.trustbar__label {
  font-size: .66rem; text-transform: uppercase; letter-spacing: .11em;
  color: #6f9384; font-weight: 650;
}
.trustbar__list { display: flex; flex-wrap: wrap; gap: var(--s3) var(--s5); list-style: none; margin: 0; padding: 0; }
.trustbar__item {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: var(--t--1); color: #bcd6c8;
}
.trustbar__item svg { color: var(--brand-200); flex: 0 0 auto; }
.trustbar__ref {
  font-variant-numeric: tabular-nums; color: #86a898;
  padding-inline-start: 6px; border-inline-start: 1px solid rgba(255,255,255,.16);
  margin-inline-start: 2px;
}

/* The full block, on the homepage. */
.creds { display: grid; gap: var(--gap); grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }

.cred {
  display: flex; gap: var(--s5); align-items: flex-start;
  background: #fff; border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: var(--s5); box-shadow: var(--sh-1);
}
.cred__scan {
  flex: 0 0 auto; width: 108px; border-radius: var(--r-sm);
  overflow: hidden; border: 1px solid var(--line); background: var(--surface);
  transition: box-shadow .2s var(--ease), transform .2s var(--ease);
}
.cred__scan:hover { box-shadow: var(--sh-2); transform: translateY(-2px); }
.cred__scan img { width: 100%; height: auto; display: block; }

.cred__body { flex: 1; min-width: 0; }
.cred__title { margin: 0 0 3px; font-size: var(--t-0); font-family: var(--font-sans); font-weight: 650; }
.cred__issuer { margin: 0 0 var(--s3); font-size: var(--t--1); color: var(--muted); }

.cred__ref { display: flex; align-items: baseline; gap: var(--s2); margin: 0 0 var(--s2); }
.cred__ref-k { font-size: .68rem; text-transform: uppercase; letter-spacing: .09em; color: var(--muted); font-weight: 650; }
.cred__ref-v {
  font-size: var(--t-0); font-weight: 650; color: var(--ink);
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
}

.cred__note { margin: 0 0 var(--s3); font-size: var(--t--1); color: var(--body); }

.cred__verify {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--t--1); font-weight: 650; color: var(--brand-600);
  padding-bottom: 1px; border-bottom: 1.5px solid var(--brand-200);
}
.cred__verify:hover { border-color: var(--brand); }

@media (max-width: 620px) {
  .cred { gap: var(--s4); }
  .cred__scan { width: 84px; }
  .trustbar { padding-inline: var(--s4); }
}

/* ------------------------------------------------------------------- faq --- */

.faq { margin-bottom: var(--s7); max-width: 68ch; }
.faq__h { font-size: var(--t-2); margin-bottom: var(--s5); }
.faq__list { margin: 0; display: flex; flex-direction: column; gap: var(--s4); }
.faq__item {
  border: 1px solid var(--line); border-radius: var(--r);
  padding: var(--s4) var(--s5); background: var(--surface);
}
.faq__item dt {
  font-weight: 650; color: var(--ink); font-size: var(--t-0);
  margin-bottom: var(--s2);
}
.faq__item dd { margin: 0; color: var(--body); font-size: var(--t-0); }

/* -------------------------------------------------------- quick search ----- */

.quicksearch {
  position: relative; flex: 0 1 260px; min-width: 0;
  margin-inline-start: var(--s4);
}
.quicksearch__icon {
  position: absolute; inset-inline-start: 12px; top: 50%; transform: translateY(-50%);
  color: var(--muted); pointer-events: none;
}
.quicksearch input {
  padding-block: 9px; padding-inline: 36px 12px;
  border-radius: var(--r-full); font-size: var(--t--1);
  background: var(--surface); border-color: transparent;
}
.quicksearch input:focus { background: #fff; border-color: var(--brand); }

.quicksearch__results {
  position: absolute; z-index: 70; inset-inline: 0; top: calc(100% + 8px);
  background: #fff; border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: var(--sh-3); overflow: hidden; max-height: 380px; overflow-y: auto;
}
.qs-item {
  display: flex; align-items: baseline; gap: var(--s3);
  padding: 10px 14px; color: var(--ink); font-size: var(--t--1);
  border-bottom: 1px solid var(--line-soft);
}
.qs-item:last-child { border-bottom: 0; }
.qs-item:hover, .qs-item.is-active { background: var(--brand-50); color: var(--brand-700); }
.qs-item__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qs-item__meta { flex: 0 0 auto; font-size: .78rem; color: var(--muted); font-weight: 600; }
.qs-empty { padding: 14px; font-size: var(--t--1); color: var(--muted); text-align: center; }

/* ------------------------------------------------------ language switch ---- */

.langswitch {
  display: inline-flex; align-items: center; gap: 2px;
  border: 1px solid rgba(255, 255, 255, .18); border-radius: var(--r-full);
  padding: 2px; flex: 0 0 auto;
}
.langswitch__opt {
  display: inline-block; padding: 3px 11px; border-radius: var(--r-full);
  font-size: .78rem; font-weight: 600; line-height: 1.5; color: inherit;
  transition: background-color .16s var(--ease), color .16s var(--ease);
}
.langswitch__opt:hover { background: rgba(255, 255, 255, .12); color: #fff; }
.langswitch__opt.is-on { background: #fff; color: var(--brand-800); }
/* Nastaliq needs vertical room even at this size or the descenders clip. */
.langswitch__opt[lang="ur"] { font-family: var(--font-ur); font-size: .9rem; line-height: 1.9; padding-block: 0; }

.site-nav__lang { display: none; padding: var(--s3) var(--s3) 0; border-top: 1px solid var(--line-soft); margin-top: var(--s2); }
.site-nav__lang .langswitch { border-color: var(--line); }
.site-nav__lang .langswitch__opt { color: var(--body); }
.site-nav__lang .langswitch__opt:hover { background: var(--brand-50); color: var(--brand-700); }
.site-nav__lang .langswitch__opt.is-on { background: var(--brand); color: #fff; }

/* --------------------------------------------------------------- urdu ------
   Nastaliq is a sloping script: glyphs need far more line height than Latin,
   and it is set with the whole block right-aligned. These rules apply whenever
   Urdu is the page language, and to individual Urdu strings inside an English
   page (a listing's Urdu title, the switcher). */

[lang="ur"], .is-rtl { font-family: var(--font-ur); }

.is-rtl body, .is-rtl { line-height: 2.05; }
.is-rtl h1, .is-rtl h2, .is-rtl h3, .is-rtl h4 {
  font-family: var(--font-ur);
  line-height: 1.85;
  letter-spacing: 0;          /* tracking is meaningless in a connected script */
  font-variation-settings: normal;
}
.is-rtl .hero__title { line-height: 1.75; }
.is-rtl p { line-height: 2.05; }

/* Latin numerals and references stay LTR inside Urdu text. */
.is-rtl .card__ref,
.is-rtl .cta-card__ref strong,
.is-rtl .path { direction: ltr; unicode-bidi: embed; display: inline-block; }

.is-rtl .eyebrow { letter-spacing: 0; }
.is-rtl .eyebrow::before { display: none; }

/* Physical properties that logical ones could not cover. */
.is-rtl .property__price { text-align: left; }
.is-rtl .ticks li::after { transform: rotate(-45deg) scaleX(-1); }
.is-rtl .section__more::after { content: "\2190"; }
.is-rtl .section__more:hover::after { transform: translateX(-3px); }
.is-rtl .split__more, .is-rtl .empty__search { text-align: right; }
.is-rtl .crumbs li + li::before { content: "\2039"; }

/* The select arrow is painted from the right edge; flip it for RTL. */
.is-rtl select {
  background-position: left 14px center;
  padding-right: 14px; padding-left: 38px;
}

.is-rtl .lightbox__nav--prev svg,
.is-rtl .lightbox__nav--next svg { transform: scaleX(-1); }

.is-rtl .area-tile::after { left: auto; right: 0; }
.is-rtl .site-nav a::after { transform-origin: right; }

/* Nastaliq at small sizes is unreadable, so the smallest labels step up. */
.is-rtl .card__specs, .is-rtl .spec dt, .is-rtl .post-card__date,
.is-rtl .site-foot__h, .is-rtl .contact-list__k, .is-rtl .lead__note {
  font-size: .84rem; line-height: 1.9; letter-spacing: 0;
}

/* ------------------------------------------------------------- blur-up ----- */

/* The 16px placeholder is painted as the element's own background, so it fills
   the frame from the first paint. main.js removes .is-blurred once the real
   file has decoded; if the script never runs, the photo simply covers it and
   nothing looks wrong. */
img.is-blurred {
  filter: blur(12px);
  transform: scale(1.03);   /* hides the soft edge the blur leaves */
  transition: filter .45s var(--ease), transform .45s var(--ease);
}
img.is-loaded {
  filter: none;
  transform: none;
  background-image: none !important;
}

/* ------------------------------------------------------ view transitions --- */

/* Chrome and Edge cross-fade between pages when this is present. Everything
   else ignores it completely, so it costs nothing to offer. */
@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: .22s;
  animation-timing-function: var(--ease);
}

/* The header must not fade with the rest, or it appears to flicker on every
   navigation. Naming it keeps it as one continuous element across pages. */
.site-head { view-transition-name: site-head; }

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

/* Sections lift in as they enter the viewport.
   The hidden starting state is scoped to .js, which a one-line inline script in
   <head> sets. If that script or main.js never runs, the rule never applies and
   the content is simply visible — an animation must never be able to hide copy. */
.js .reveal { opacity: 0; transform: translateY(18px); }
.js .reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity .6s var(--ease), transform .6s var(--ease);
}
.js .reveal:nth-child(2).is-in { transition-delay: .06s; }
.js .reveal:nth-child(3).is-in { transition-delay: .12s; }
.js .reveal:nth-child(4).is-in { transition-delay: .18s; }

/* The directional variant. [data-rv] says which way a thing travels in from,
   and --rv-i is its place in a stagger, set on the element in the template
   rather than counted in CSS - a run of nth-child delays breaks the moment one
   of the siblings turns out to be conditional, which on this page most of them
   are.

   Everything moves on transform and opacity and nothing else. Those are the
   two properties a browser can animate without laying the page out again,
   which is the whole difference between smooth and juddering on the mid-range
   Android most of these visitors are holding. */
.js [data-rv] {
  opacity: 0;

  /* --rv-lift is what a hover adds on top of the entrance. It is folded into
     the same transform rather than written as a second one, because a finished
     entrance used to resolve to transform:none - and that rule, carrying an
     attribute and two classes, outranked every .thing:hover on the site. Any
     element given an entrance quietly lost its lift on hover, which is how the
     homepage area tiles and article cards came to stand still. Composing the
     two here means one transform, and neither can silence the other. */
  transform: translate3d(var(--rv-x, 0px),
                         calc(var(--rv-y, 24px) + var(--rv-lift, 0px)), 0)
             scale(var(--rv-s, 1));
  transition: opacity .55s var(--ease), transform .55s var(--ease);

  /* The stagger is capped here rather than in the template. A section is free
     to number twenty cards, and without the min() the twentieth would wait a
     second and a half - which on a fast scroll is a reader arriving at an
     empty screen. Whatever the template counts to, nothing waits longer than
     six steps. */
  transition-delay: calc(min(var(--rv-i, 0), 6) * 55ms);
}
.js [data-rv].is-in { opacity: 1; --rv-x: 0px; --rv-y: 0px; --rv-s: 1; }

.js [data-rv="down"]  { --rv-y: -24px; }
.js [data-rv="start"] { --rv-x: -32px; --rv-y: 0px; }
.js [data-rv="end"]   { --rv-x: 32px;  --rv-y: 0px; }
.js [data-rv="in"]    { --rv-y: 0px; --rv-s: .93; }
.js [data-rv="out"]   { --rv-y: 0px; --rv-s: 1.07; }

/* Three that open rather than travel. A photograph looks wrong sliding in and
   right being uncovered, so these animate the clip and leave the picture still
   - the frame moves off it, which is how a print is revealed on a table. */
.js [data-rv="clip"], .js [data-rv="wipe"] {
  opacity: 1; --rv-y: 0px;
  clip-path: inset(var(--rv-t, 100%) var(--rv-r, 0%) var(--rv-b, 0%) var(--rv-l, 0%));

  /* The stagger is written into the clip-path transition rather than declared
     for the whole rule, so that a hover lift on one of these - the area tiles
     are both wiped and liftable - answers at once instead of waiting out the
     entrance delay it happens to have been given. */
  transition: clip-path .95s var(--ease-in-out) calc(min(var(--rv-i, 0), 6) * 55ms),
              transform .2s var(--ease);
}
/* Left to right. The inset closes from the end of the line, so in Urdu it
   uncovers from the right, which is the direction that reads as forward. */
.js [data-rv="wipe"] { --rv-t: 0%; --rv-r: 100%; }
.is-rtl.js [data-rv="wipe"] { --rv-r: 0%; --rv-l: 100%; }

.js [data-rv="clip"].is-in, .js [data-rv="wipe"].is-in {
  clip-path: inset(0% 0% 0% 0%);
}

/* The two zooms, stronger than "in" and "out" above, for the moments the page
   is meant to feel like a cut rather than a scroll. */
.js [data-rv="zoom-in"]  { --rv-y: 0px; --rv-s: .80; }
.js [data-rv="zoom-out"] { --rv-y: 0px; --rv-s: 1.22; }

/* Scroll-linked scale, written continuously rather than switched once. main.js
   sets --zoom from how far the element has crossed the screen, so the movement
   belongs to the reader's thumb instead of to a timer. Unset, it resolves to 1
   and the element simply sits there. */
.js [data-zoom] { transform: scale(var(--zoom, 1)); transform-origin: var(--zoom-from, 50% 50%); will-change: transform; }

/* Softens in rather than moves. Kept for the small print that sits under a
   statement, where any travel at all competes with the line above it. */
.js [data-rv="soften"] {
  --rv-y: 8px;
  filter: blur(6px);
  transition: opacity .7s var(--ease), transform .7s var(--ease), filter .7s var(--ease);
}
.js [data-rv="soften"].is-in { filter: none; }

/* Named for the line rather than the compass, and flipped with it. A panel
   that enters from the start of the line has to keep doing that in Urdu, where
   the start of the line is the right-hand side. */
.is-rtl.js [data-rv="start"] { --rv-x: 32px; }
.is-rtl.js [data-rv="end"]   { --rv-x: -32px; }

/* Word-by-word mask, for the two or three display lines that carry a section.
   main.js wraps each word of a [data-words] heading in .rvw > span: the outer
   span is the window, the inner one rides up into it. The wrapping is done in
   script, so a heading whose script never arrived is ordinary text with no
   starting state it could get stuck in.

   The padding and the matching negative margin are what stop the window
   clipping the descenders of a Fraunces g or y without changing where the line
   sits. */
.rvw {
  display: inline-block; overflow: hidden; vertical-align: top;
  padding: .12em .04em; margin: -.12em -.04em;
}
.rvw > span {
  display: inline-block;
  transform: translateY(112%);
  transition: transform .7s var(--ease-in-out);
  /* Capped for the same reason as the entrance stagger: a long headline must
     not take longer to finish arriving than a reader will wait for it. */
  transition-delay: calc(min(var(--rvw-i, 0), 8) * 45ms);
}
.js .is-in .rvw > span { transform: none; }

/* ------------------------------------------------------------- people ----- */
/* The agent card on a listing, the team page, and the strip on the homepage.
   All three share .agent so a change to how a person is presented happens in
   one place rather than three. */

.agent-panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s5);
}

.agent-panel__eyebrow {
  margin: 0 0 var(--s3);
  font-size: var(--t--1);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}

.agent { display: flex; flex-direction: column; gap: var(--s3); }

.agent__who { display: flex; align-items: center; gap: var(--s3); }

.agent__photo {
  width: 56px; height: 56px;
  flex: none;
  border-radius: var(--r-full);
  object-fit: cover;
  background: var(--surface-2);
}

/* An initial rather than a stock silhouette. A grey outline of a person reads
   as a picture that failed to load; a letter reads as a choice. */
.agent__photo--initials {
  display: grid; place-items: center;
  background: var(--brand-50);
  color: var(--brand);
  font-family: var(--font-display);
  font-size: var(--t-1);
  font-weight: 600;
  line-height: 1;
}

.agent__lines { min-width: 0; }
.agent__name { margin: 0; font-weight: 600; color: var(--ink); line-height: 1.3; }
.agent__title { margin: 2px 0 0; font-size: var(--t--1); color: var(--muted); }
.agent__bio { margin: 0; font-size: var(--t--1); line-height: 1.6; }

.agent__actions { display: flex; flex-wrap: wrap; gap: var(--s2); }
.agent__actions .btn { flex: 1 1 auto; justify-content: center; }
.agent--compact .agent__actions .btn { flex: 0 1 auto; }

/* Homepage strip. auto-fit rather than a fixed count, so an office of two and
   an office of five both look deliberate. */
.team-strip {
  display: grid;
  gap: var(--s4);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.team-strip .agent {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: var(--s4);
}

/* ---- the team page ---- */

.team {
  list-style: none;
  margin: 0 0 var(--s7);
  padding: 0;
  display: grid;
  gap: var(--s5);
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

.team__member {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--s4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s6) var(--s4);
  box-shadow: 0 4px 20px rgba(0,0,0,0.03);
  transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.3s cubic-bezier(0.2, 0.8, 0.2, 1), border-color 0.3s ease;
  position: relative;
  overflow: hidden;
  z-index: 1;
}

.team__member::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 80px;
  background: linear-gradient(180deg, var(--brand-50) 0%, rgba(255,255,255,0) 100%);
  z-index: -1;
  opacity: 0;
  transition: opacity 0.4s ease;
}

.team__member:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 30px rgba(0,0,0,0.08);
  border-color: var(--brand-200);
}

.team__member:hover::before {
  opacity: 1;
}

.team__photo {
  width: 110px; height: 110px;
  border-radius: var(--r-full);
  object-fit: cover;
  background: var(--surface-2);
  border: 4px solid var(--white);
  box-shadow: 0 6px 16px rgba(0,0,0,0.06);
  transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.team__member:hover .team__photo {
  transform: scale(1.05) rotate(3deg);
}

.team__photo--initials {
  display: grid; place-items: center;
  background: var(--brand-50);
  color: var(--brand);
  font-family: var(--font-display);
  font-size: var(--t-3);
  font-weight: 600;
  line-height: 1;
  border: 4px solid var(--white);
  box-shadow: 0 6px 16px rgba(0,0,0,0.06);
  transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.team__member:hover .team__photo--initials {
  transform: scale(1.05) rotate(-3deg);
}

.team__text { 
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
  width: 100%;
}
.team__name { margin: 0 0 4px; font-size: var(--t-2); font-weight: 700; color: var(--brand-900); }
.team__role { margin: 0 0 var(--s3); font-size: var(--t--1); color: var(--brand); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; }
.team__bio { margin: 0 0 var(--s4); font-size: var(--t--1); line-height: 1.65; color: var(--muted); }
.team__count { 
  margin: auto 0 var(--s4); 
  font-size: var(--t--1); 
  color: var(--brand-700); 
  font-weight: 500; 
  background: var(--brand-50); 
  padding: 4px 12px; 
  border-radius: 20px; 
}
.team__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s3); width: 100%; margin-top: var(--s2); }
.team__actions .btn { flex: 1; min-width: 120px; border-radius: var(--r-full); }
.btn--icon-text { display: inline-flex; align-items: center; justify-content: center; gap: 8px; font-weight: 600; }
.btn--icon-text svg { flex-shrink: 0; }
.btn--edit-member { flex: 100% !important; border: 1px dashed var(--line) !important; background: transparent; }
.btn--edit-member:hover { border-style: solid !important; background: var(--surface-2); }
.team__hours { margin: 0 0 var(--s7); color: var(--muted); font-size: var(--t--1); text-align: center; }

/* ------------------------------------------------------------ reviews ----- */
/* Deliberately quiet. A review section that shouts is the one people discount,
   and these are competing with the licence numbers directly above them - which
   are the stronger claim and should stay the louder one. */

.reviews {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s4);
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

.review {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s5);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.review__stars {
  margin: 0;
  display: flex;
  gap: 2px;
  color: var(--gold);
  line-height: 0;
}
.review__stars svg { opacity: .32; }
.review__stars svg.is-on { opacity: 1; }

.review__body {
  margin: 0;
  font-size: var(--t-0);
  line-height: 1.7;
  color: var(--ink-soft);
  /* Not italic: Nastaliq has no italic and a synthesised slant on a connected
     script is unreadable, so the quote is set upright in both languages. */
}

.review__who {
  margin: auto 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s1) var(--s2);
  font-size: var(--t--1);
}
.review__name { font-weight: 600; color: var(--ink); }
.review__area { color: var(--muted); }
.review__area::before { content: "—"; margin-inline-end: var(--s1); }

@media (max-width: 620px) {
  .team__photo { width: 72px; height: 72px; }
  .team__photo--initials { font-size: var(--t-2); }
}

/* ==========================================================================
   Comfort layer

   Everything here belongs to a control main.js switches on. The markup for all
   of it ships `hidden`, so these rules only ever describe something the script
   has already taken responsibility for — there is no state in which a visitor
   is shown a styled control that cannot do anything.
   ========================================================================== */

/* The rule the whole layer rests on. Several controls below need a display of
   their own — grid for a round button, flex for a row — and any such rule
   silently outranks the browser's own `[hidden] { display: none }`, because an
   author stylesheet always beats the user agent one. Without this, `hidden` in
   the markup would stop meaning hidden, and every drawer, toast and heart on
   the site would be on screen from the first paint. */
[hidden] { display: none !important; }

/* ------------------------------------------------------------- progress ---- */

.progress {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 240;
  height: 3px; pointer-events: none;
}
.progress__bar {
  display: block; height: 100%;
  background: linear-gradient(90deg, var(--brand), var(--brand-500));
  transform: scaleX(0);
  /* Filled from the edge the language starts at, so the bar grows the way the
     page reads rather than the way the stylesheet was written. */
  transform-origin: left center;
}
.is-rtl .progress__bar { transform-origin: right center; }

/* --------------------------------------------------------------- toasts ---- */

.toasts {
  position: fixed; z-index: 250;
  inset-block-end: var(--s5); inset-inline-start: 50%;
  transform: translateX(-50%);
  display: flex; flex-direction: column; gap: var(--s2);
  align-items: center; pointer-events: none;
  width: max-content; max-width: min(92vw, 420px);
}
.toast {
  margin: 0; padding: 11px 20px;
  background: var(--ink); color: #fff;
  border-radius: var(--r-full);
  font-size: var(--t--1); font-weight: 550; text-align: center;
  box-shadow: var(--sh-3);
  opacity: 0; transform: translateY(10px);
  transition: opacity .22s var(--ease), transform .22s var(--ease);
}
.toast.is-in { opacity: 1; transform: none; }

/* ----------------------------------------------------------- connection ---- */

.netbar {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 245;
  padding: 9px var(--s5);
  background: var(--ink); color: #fff;
  font-size: var(--t--1); font-weight: 550; text-align: center;
}
.netbar.is-ok { background: var(--ok); }

/* ---------------------------------------------------------- back to top ---- */

/* Clears the WhatsApp button rather than landing on top of it. The two
   exceptions below are the phone sizes where that button changes or gives way
   to the fixed call bar. */
.to-top {
  position: fixed; z-index: 56;
  inset-block-end: calc(var(--s5) + 70px);
  inset-inline-end: var(--s5);
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: rgba(255,255,255,.92);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  color: var(--brand-700); cursor: pointer;
  box-shadow: var(--sh-2);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease);
}
/* Smooth scrolling — forced here as a hard guarantee regardless of browser defaults */
html { scroll-behavior: smooth; scroll-padding-top: 84px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

.to-top:hover { transform: translateY(-2px); box-shadow: var(--sh-3); }

/* =============================================================================
 * Back-to-top Button Style System
 * Scoped to .to-top--{style}. Base .to-top remains unchanged.
 * ============================================================================= */

/* ---- 1: Classic (default) — already styled by base .to-top above ---------- */
.to-top--classic:hover {
  background: var(--brand-50);
  border-color: var(--brand-200);
  color: var(--brand-800);
  transform: translateY(-3px);
  box-shadow: 0 8px 24px -4px rgba(7, 89, 133, 0.25);
}

/* ---- 2: Liquid Fill -------------------------------------------------------- */
.to-top--liquid {
  overflow: hidden;
  position: relative;
  transition: transform 0.24s cubic-bezier(.34,1.4,.64,1),
              box-shadow 0.25s ease, color 0.15s ease, border-color 0.25s ease;
}
.to-top--liquid::before {
  content: "";
  position: absolute; z-index: -1;
  left: -20%; bottom: -160%;
  width: 140%; height: 240%;
  background: radial-gradient(circle at 50% 0%, var(--brand, #075985), var(--brand-800, #073b5c));
  border-radius: 40% 45% 42% 44%;
  transform: rotate(0deg);
  transition: bottom 0.6s cubic-bezier(.2,.8,.2,1), transform 0.7s ease;
  pointer-events: none;
}
.to-top--liquid:hover::before {
  bottom: -10%; transform: rotate(360deg);
}
.to-top--liquid:hover {
  color: #fff !important;
  border-color: var(--brand-400);
  transform: translateY(-3px);
  box-shadow: 0 10px 28px -4px rgba(7, 89, 133, 0.4);
}

/* ---- 3: Pulse Ring --------------------------------------------------------- */
.to-top--pulse {
  overflow: visible;
  transition: transform 0.24s cubic-bezier(.34,1.4,.64,1), box-shadow 0.25s ease;
}
.to-top--pulse::after {
  content: "";
  position: absolute; inset: -4px;
  border-radius: 50%;
  border: 2px solid var(--brand-400);
  opacity: 0; transform: scale(0.9);
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.35s cubic-bezier(.16,1,.3,1);
}
.to-top--pulse:hover {
  background: var(--brand-700);
  border-color: var(--brand-700);
  color: #fff;
  transform: translateY(-3px) scale(1.05);
  box-shadow: 0 8px 24px -4px rgba(7, 89, 133, 0.45);
}
.to-top--pulse:hover::after {
  opacity: 1; transform: scale(1);
  animation: to-top-pulse-ring 1.4s cubic-bezier(.24,0,.38,1) infinite;
}
@keyframes to-top-pulse-ring {
  0%   { transform: scale(1);    opacity: 0.8; }
  50%  { transform: scale(1.18); opacity: 0.25; }
  100% { transform: scale(1.3);  opacity: 0; }
}

/* ---- 4: Neon Glow ---------------------------------------------------------- */
.to-top--glow {
  overflow: hidden;
  transition: transform 0.22s ease, box-shadow 0.25s ease, border-color 0.25s ease;
}
.to-top--glow::before {
  content: "";
  position: absolute; top: -50%; left: -50%;
  width: 200%; height: 200%;
  background: conic-gradient(transparent, var(--brand-500, #0ea5e9), transparent 30%);
  opacity: 0; pointer-events: none;
  transition: opacity 0.3s ease;
}
.to-top--glow:hover {
  transform: translateY(-3px);
  border-color: var(--brand-500);
  box-shadow: 0 0 20px rgba(14,165,233,.55), inset 0 0 10px rgba(14,165,233,.2);
  color: var(--brand-700);
}
.to-top--glow:hover::before {
  opacity: 1;
  animation: to-top-beam 2s linear infinite;
}
@keyframes to-top-beam {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* ---- 5: Gradient Spin ------------------------------------------------------ */
.to-top--gradient {
  background: conic-gradient(from 0deg, var(--brand, #075985), #38bdf8, #818cf8, #f43f5e, var(--brand, #075985));
  border: none;
  color: #fff;
  transition: transform 0.24s cubic-bezier(.34,1.4,.64,1), box-shadow 0.25s ease;
  animation: to-top-spin 5s linear infinite;
}
.to-top--gradient:hover {
  transform: translateY(-3px) scale(1.08);
  box-shadow: 0 10px 28px -4px rgba(7,89,133,.45);
  animation-duration: 1.5s;
}
@keyframes to-top-spin {
  from { filter: hue-rotate(0deg); }
  to   { filter: hue-rotate(360deg); }
}

/* ---- 6: Frosted Glass ------------------------------------------------------ */
.to-top--glass {
  background: rgba(255,255,255,.55);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255,255,255,.7);
  overflow: hidden;
  transition: transform 0.24s cubic-bezier(.34,1.4,.64,1), box-shadow 0.25s ease,
              background 0.25s ease;
}
.to-top--glass::before {
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(circle at 50% 50%, rgba(255,255,255,.6) 0%, transparent 65%);
  opacity: 0; pointer-events: none;
  transition: opacity 0.3s ease;
}
.to-top--glass:hover {
  transform: translateY(-3px);
  background: rgba(255,255,255,.75);
  box-shadow: 0 8px 32px -4px rgba(0,0,0,.14), inset 0 1px 1px rgba(255,255,255,.8);
  color: var(--brand-800);
}
.to-top--glass:hover::before { opacity: 1; }

/* ---- 7: Magnetic Float ----------------------------------------------------- */
.to-top--magnetic {
  overflow: visible;
  transition: transform 0.28s cubic-bezier(.34,1.56,.64,1),
              box-shadow 0.28s ease, border-color 0.2s ease, background 0.2s ease;
}
.to-top--magnetic:hover {
  transform: translateY(-6px) scale(1.1);
  background: var(--brand-700);
  border-color: var(--brand-700);
  color: #fff;
  box-shadow: 0 16px 36px -6px rgba(7,89,133,.45);
}
.to-top--magnetic:active {
  transform: translateY(-2px) scale(0.96);
  box-shadow: 0 4px 12px -2px rgba(7,89,133,.3);
}

/* ---- 8: Rocket Launch ------------------------------------------------------ */
.to-top--rocket {
  font-size: 1.25rem;
  line-height: 1;
  overflow: visible;
  border-style: none;
  background: linear-gradient(135deg, #f97316, #ef4444);
  color: #fff;
  transition: transform 0.28s cubic-bezier(.34,1.56,.64,1), box-shadow 0.25s ease;
}
.to-top--rocket .to-top__rocket {
  display: inline-block;
  transition: transform 0.3s cubic-bezier(.34,1.56,.64,1);
}
.to-top--rocket:hover {
  box-shadow: 0 12px 32px -4px rgba(239,68,68,.45);
}
.to-top--rocket:hover .to-top__rocket {
  transform: translateY(-6px) scale(1.2);
  animation: rocket-launch 0.6s cubic-bezier(.34,1.56,.64,1) infinite alternate;
}
/* Flame trail */
.to-top--rocket::after {
  content: "🔥";
  position: absolute; bottom: -14px; left: 50%; transform: translateX(-50%);
  font-size: 0.85rem; opacity: 0;
  transition: opacity 0.2s ease;
  pointer-events: none;
}
.to-top--rocket:hover::after { opacity: 1; }
@keyframes rocket-launch {
  from { transform: translateY(-4px) scale(1.18); }
  to   { transform: translateY(-8px) scale(1.25) rotate(-5deg); }
}

@media (max-width: 780px) {
  /* On a listing the WhatsApp button is replaced by the fixed call bar, which
     is taller and runs the full width. */
  .page-property .to-top { inset-block-end: calc(74px + var(--s3)); }
}
@media (max-width: 620px) {
  .to-top { inset-inline-end: var(--s4); inset-block-end: calc(var(--s4) + 64px); }
  .page-property .to-top { inset-block-end: calc(74px + var(--s3)); }
}

/* --------------------------------------------------------------- drawer ---- */

/* One dialog shell, shared by the shortlist and the keyboard help. */
.drawer { position: fixed; inset: 0; z-index: 150; }

.drawer__scrim {
  position: absolute; inset: 0;
  background: rgba(4, 20, 15, .5);
  opacity: 0; transition: opacity .22s var(--ease);
}
.drawer.is-open .drawer__scrim { opacity: 1; }

.drawer__panel {
  position: absolute; inset-block: 0; inset-inline-end: 0;
  width: min(420px, 92vw);
  display: flex; flex-direction: column;
  background: var(--white);
  box-shadow: var(--sh-4);
  /* Off the edge it is anchored to, whichever edge the language makes that. */
  transform: translateX(100%);
  transition: transform .24s var(--ease);
}
.is-rtl .drawer__panel { transform: translateX(-100%); }
.drawer.is-open .drawer__panel { transform: none; }

/* The keyboard help is a card in the middle instead: it is read once and
   dismissed, not worked through like a list. */
.drawer--center { display: grid; place-items: center; padding: var(--s5); }
.drawer--center .drawer__panel {
  position: relative; inset: auto;
  max-height: 86vh; border-radius: var(--r-lg);
  transform: scale(.96); opacity: 0;
  transition: transform .22s var(--ease), opacity .22s var(--ease);
}
.drawer--center.is-open .drawer__panel { transform: none; opacity: 1; }

.drawer__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s4); padding: var(--s5) var(--s5) var(--s3);
  border-bottom: 1px solid var(--line-soft);
}
.drawer__title { margin: 0; font-size: var(--t-1); font-family: var(--font-sans); font-weight: 650; }
.drawer__x {
  display: grid; place-items: center; flex: none;
  width: 38px; height: 38px; border: 0; border-radius: 50%;
  background: var(--surface-2); color: var(--ink-soft); cursor: pointer;
}
.drawer__x:hover { background: var(--line); }

.drawer__note { margin: 0; padding: var(--s3) var(--s5) 0; font-size: .74rem; color: var(--muted); line-height: 1.55; }
.drawer__list {
  flex: 1 1 auto; overflow-y: auto;
  padding: var(--s4) var(--s5);
  display: grid; gap: var(--s2); align-content: start;
}
.drawer__empty { margin: 0; padding: var(--s6) var(--s5); color: var(--muted); font-size: var(--t--1); text-align: center; }
.drawer__foot {
  padding: var(--s4) var(--s5) calc(var(--s5) + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--line-soft);
}

/* A saved or recently seen listing, small enough that six fit on a phone. */
.srow { display: flex; align-items: stretch; gap: var(--s2); }
.srow__link {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s2); border-radius: var(--r);
  color: var(--ink); transition: background .16s var(--ease);
}
.srow__link:hover { background: var(--surface); color: var(--ink); }
.srow__img {
  width: 84px; height: 60px; flex: none;
  object-fit: cover; border-radius: var(--r-sm); background: var(--surface-2);
}
.srow__text { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.srow__text strong { color: var(--brand-700); font-size: var(--t-0); }
.srow__title {
  font-size: var(--t--1); color: var(--ink-soft); line-height: 1.4;
  /* Two lines, then an ellipsis. A long title must not push the price and the
     area out of a row this size. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.srow__text small { font-size: .72rem; color: var(--muted); }
.srow__x {
  flex: none; align-self: center;
  display: grid; place-items: center; width: 34px; height: 34px;
  border: 0; border-radius: 50%; background: transparent;
  color: var(--faint); cursor: pointer;
}
.srow__x:hover { background: var(--bad-bg); color: var(--bad); }

/* ---- keyboard help ---- */

.keys { margin: 0; padding: var(--s4) var(--s5) var(--s6); display: grid; gap: var(--s3); }
.keys__row { display: flex; align-items: center; gap: var(--s4); }
.keys__row dt { flex: 0 0 88px; display: flex; gap: 4px; }
.keys__row dd { margin: 0; font-size: var(--t--1); color: var(--body); }
.keys kbd {
  display: inline-block; min-width: 26px; padding: 3px 7px;
  border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 6px;
  background: var(--surface); color: var(--ink-soft);
  font-family: var(--font-sans); font-size: .74rem; font-weight: 600; text-align: center;
}

/* ------------------------------------------------------------ shortlist ---- */

.saved-toggle {
  position: relative; flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 9px 12px; border: 1px solid var(--line); border-radius: var(--r-full);
  background: #fff; color: var(--brand-700); cursor: pointer;
  transition: border-color .16s var(--ease), background .16s var(--ease);
}
.saved-toggle:hover { background: var(--brand-50); border-color: var(--brand-200); }
.saved-toggle svg { fill: var(--brand-100); }
.saved-toggle__count { font-size: var(--t--1); font-weight: 700; font-variant-numeric: tabular-nums; }

/* The heart on a card. It sits over a photograph, so it carries its own
   backdrop rather than trusting whatever happens to be behind it.
   Positioned physically, not logically: the tag strip opposite it is pinned to
   the left in both languages, and a heart that moved would land on top of it. */
.heart {
  position: absolute; top: var(--s3); right: var(--s3); z-index: 2;
  display: grid; place-items: center; width: 36px; height: 36px;
  border: 0; border-radius: 50%;
  background: rgba(255,255,255,.88);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  color: var(--ink-soft); cursor: pointer;
  box-shadow: 0 2px 8px rgba(9,42,30,.18);
  transition: transform .16s var(--ease), color .16s var(--ease);
}
.heart:hover { transform: scale(1.08); color: var(--bad); }
.heart.is-on { color: var(--bad); }
.heart.is-on svg { fill: currentColor; }

.tag--new { background: var(--brand); color: #fff; }

/* -------------------------------------------------------------- actions ---- */

/* Save, share, copy, print. Quiet on purpose: they sit directly under a price,
   which is the one thing on that screen that should be loud. */
.actions { display: flex; flex-wrap: wrap; gap: var(--s2); margin-bottom: var(--s5); }
.action {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 15px;
  border: 1px solid var(--line); border-radius: var(--r-full);
  background: #fff; color: var(--body);
  font-family: inherit; font-size: var(--t--1); font-weight: 550;
  cursor: pointer;
  transition: border-color .16s var(--ease), color .16s var(--ease), background .16s var(--ease);
}
.action:hover { border-color: var(--brand-200); background: var(--brand-50); color: var(--brand-700); }
.action[aria-pressed="true"] { border-color: var(--bad); color: var(--bad); background: var(--bad-bg); }
.action[aria-pressed="true"] svg { fill: currentColor; }

/* ------------------------------------------------------------- page nav ---- */

.pagenav { margin-bottom: var(--s5); border-bottom: 1px solid var(--line-soft); }
.pagenav ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; gap: var(--s5);
  overflow-x: auto; scrollbar-width: none;
}
.pagenav ul::-webkit-scrollbar { display: none; }
.pagenav a {
  display: block; padding: 11px 0;
  border-bottom: 2px solid transparent;
  color: var(--muted); font-size: var(--t--1); font-weight: 600; white-space: nowrap;
  transition: color .16s var(--ease), border-color .16s var(--ease);
}
.pagenav a:hover { color: var(--brand-700); }
.pagenav a.is-on { color: var(--brand-700); border-color: var(--brand); }

/* Sticky only where the header is a single row. Below that it wraps to carry
   the search field, and a second sticky strip under a header that tall eats
   the screen the listing is meant to be shown on. */
@media (min-width: 1025px) {
  .pagenav {
    position: sticky; top: 74px; z-index: 40;
    background: rgba(255,255,255,.94);
    -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  }
}

/* Enough clearance that a jump link does not land the heading under the
   header that is sitting on top of it. */
.property [id] { scroll-margin-top: 130px; }

/* ------------------------------------------------------------------ toc ---- */

.toc {
  margin: 0 0 var(--s6); padding: var(--s5);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
}
.toc__h {
  margin: 0 0 var(--s3); font-size: var(--t--1); font-weight: 650;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
}
.is-rtl .toc__h { letter-spacing: 0; }
.toc__list { margin: 0; padding-inline-start: 1.2em; display: grid; gap: 6px; }
.toc__list a { color: var(--body); font-size: var(--t--1); }
.toc__list a:hover, .toc__list a.is-on { color: var(--brand-700); font-weight: 600; }
.article .prose h2 { scroll-margin-top: 110px; }

/* ------------------------------------------------------------- backlink ---- */

.backlink { margin: var(--s3) 0 0; font-size: var(--t--1); }
.backlink__a { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-weight: 550; }
.backlink__a::before { content: "\2190"; }
.is-rtl .backlink__a::before { content: "\2192"; }
.backlink__a:hover { color: var(--brand-700); }

/* ------------------------------------------------------- recently viewed --- */

.section--slim { padding-block: var(--s7); }
.section__head--tight { margin-bottom: var(--s5); align-items: center; }
.section__title--sm { font-size: var(--t-2); }

.recent__rail {
  display: grid; gap: var(--s3);
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.recent .srow__link { background: #fff; border: 1px solid var(--line); }

/* A button doing a link-sized job, and reading like one. */
.linkish {
  border: 0; background: none; padding: 0; cursor: pointer;
  color: var(--muted); font-family: inherit; font-size: var(--t--1); font-weight: 550;
  text-decoration: underline; text-underline-offset: 3px;
}
.linkish:hover { color: var(--brand-700); }

/* --------------------------------------------------------------- fields ---- */

.field__err { margin: 0; font-size: var(--t--1); color: var(--bad); line-height: 1.45; }
.field__err:empty { display: none; }
input.is-bad, textarea.is-bad { border-color: var(--bad); background: var(--bad-bg); }

.field__count { margin: 0; font-size: .74rem; color: var(--muted); text-align: end; }
.field__count.is-tight { color: var(--bad); font-weight: 600; }

/* A button that has already been pressed. Disabled so it cannot be pressed
   again, and visibly busy so that reads as deliberate rather than as dead. */
.btn.is-busy { opacity: .72; cursor: progress; }
.btn.is-busy::after {
  content: ""; width: 13px; height: 13px; margin-inline-start: 8px;
  border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* -------------------------------------------------------- active filters --- */

.activef {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s3);
  margin: var(--s4) 0 0;
}
.activef__k {
  font-size: var(--t--1); font-weight: 600; color: var(--muted);
  letter-spacing: .06em; text-transform: uppercase;
}
.is-rtl .activef__k { letter-spacing: 0; text-transform: none; }
.activef__list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--s2); }
.activef__chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px;
  background: var(--brand-50); border: 1px solid var(--brand-100); border-radius: var(--r-full);
  color: var(--brand-800); font-size: var(--t--1); font-weight: 550;
  transition: background .16s var(--ease), border-color .16s var(--ease), color .16s var(--ease);
}
.activef__chip:hover { background: var(--bad-bg); border-color: #efc8c8; color: var(--bad); }
.activef__chip svg { opacity: .55; }
.activef__chip:hover svg { opacity: 1; }
.activef__all { font-size: var(--t--1); color: var(--muted); text-decoration: underline; text-underline-offset: 3px; }
.activef__all:hover { color: var(--brand-700); }

/* ----------------------------------------------------------------- rate ---- */

/* The price per marla, sitting under the asking price it comes from. */
.property__rate { margin: 2px 0 0; font-size: var(--t--1); color: var(--muted); font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------- scroll lock ---- */

/* Holds the page still behind an open drawer. Without it a phone scrolls the
   listing underneath while the visitor believes they are scrolling the panel. */
body.is-locked { overflow: hidden; }

/* ------------------------------------------------- price flags on a listing */

.property__drop {
  display: inline-flex; align-items: center; gap: var(--s1);
  margin: var(--s2) 0 0;
  font-size: var(--t--1); font-weight: 600;
  color: var(--ok);
}
.property__drop-was { text-decoration: line-through; color: var(--muted); font-weight: 400; }
.property__drop-when { color: var(--muted); font-weight: 400; }

.property__plan-flag {
  margin: var(--s2) 0 0;
  font-size: var(--t--1);
  color: var(--body);
}
.property__plan-flag strong { color: var(--ink); }

/* ------------------------------------------------------------ documentation */
/* Deliberately plain. This is the section a nervous buyer reads hardest, and
   anything that looks like marketing here reads as a sales pitch about the one
   subject where they want a straight answer. */

.docs {
  margin: 0 0 var(--s6);
  padding: var(--s5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.docs__h { font-size: var(--t-1); margin-bottom: var(--s3); }

.docs__list {
  list-style: none; margin: 0 0 var(--s3); padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--s2);
}

.doc {
  font-size: var(--t--1); font-weight: 600;
  padding: 6px 12px;
  border-radius: var(--r-full);
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--ink-soft);
}
.doc--good { border-color: var(--brand-200); background: var(--brand-50); color: var(--brand-700); }
.doc--warn { border-color: var(--gold-200); background: var(--gold-50); color: var(--gold-700); }

.docs__note { margin: 0; font-size: var(--t--1); color: var(--muted); line-height: 1.6; }

/* ------------------------------------------------------------ payment plan */

.plan {
  margin: 0 0 var(--s6);
  padding: var(--s5);
  border: 1px solid var(--brand-200);
  border-radius: var(--r-lg);
  background: var(--brand-50);
}
.plan__h { font-size: var(--t-2); margin-bottom: var(--s4); }

.plan__grid { margin: 0; display: grid; gap: 0; }

.plan__row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s4);
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--brand-200);
}
.plan__row:last-child { border-bottom: 0; }
.plan__row dt { color: var(--body); font-size: var(--t--1); margin: 0; }
.plan__row dd {
  margin: 0; font-weight: 600; color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.plan__row--lead dd { font-size: var(--t-2); font-family: var(--font-display); color: var(--brand-700); }
.plan__row--total { border-top: 2px solid var(--brand-200); margin-top: var(--s2); }
.plan__row--total dt { font-weight: 600; color: var(--ink-soft); }

.plan__note {
  margin: var(--s4) 0 0; font-size: var(--t--1); color: var(--body);
  padding-top: var(--s3); border-top: 1px dashed var(--brand-200);
}

/* ---- the calculator ---- */

.calc { margin-top: var(--s4); padding-top: var(--s4); border-top: 1px solid var(--brand-200); }
.calc__label { display: block; font-size: var(--t--1); color: var(--body); margin-bottom: var(--s2); }
.calc__range { width: 100%; accent-color: var(--brand); }
.calc__out {
  margin: var(--s3) 0 0;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s2);
  font-variant-numeric: tabular-nums;
}
.calc__out strong { font-size: var(--t-2); font-family: var(--font-display); color: var(--brand-700); }
.calc__sep, .calc__per { color: var(--muted); font-size: var(--t--1); }
.calc__note { margin: var(--s2) 0 0; font-size: var(--t--1); color: var(--muted); }

/* ------------------------------------------------------------- floor plans */
/* On a white ground with a border rather than cropped into a tile: a plan is
   read, not admired, and cropping one loses the corner with the dimensions. */

.planshots {
  display: grid; gap: var(--s4);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.planshot { margin: 0; }
.planshot img {
  width: 100%; height: auto; display: block;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.planshot figcaption { margin-top: var(--s2); font-size: var(--t--1); color: var(--muted); }

/* --------------------------------------------------- video and map facades */
/* Both load nothing until pressed. A visitor who never opens them pays no
   bytes and gets no third-party cookies for the privilege. */

.videobox, .mapbox {
  position: relative;
  border-radius: var(--r);
  overflow: hidden;
  background: var(--surface-2);
  border: 1px solid var(--line);
  aspect-ratio: 16 / 9;
}
.mapbox { aspect-ratio: 16 / 10; }

.videobox__play, .mapbox__open {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s2);
  border: 0; cursor: pointer;
  background: transparent;
  color: var(--ink-soft);
  font: inherit; font-weight: 600;
}
.videobox__play:hover, .mapbox__open:hover { background: var(--surface); color: var(--brand-700); }

.videobox__icon {
  display: grid; place-items: center;
  width: 58px; height: 58px;
  border-radius: var(--r-full);
  background: var(--brand); color: #fff;
  box-shadow: var(--sh-2);
}
.videobox__play:hover .videobox__icon { background: var(--brand-700); }
.videobox__text { font-size: var(--t--1); }

.videobox__frame, .mapbox__frame {
  width: 100%; height: 100%; border: 0; display: block;
}

/* ------------------------------------------------------------------ nearby */

.nearby {
  list-style: none; margin: 0 0 var(--s4); padding: 0;
  display: grid; gap: 0;
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
}
.nearby__item {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s4);
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--line-soft);
  font-size: var(--t--1);
}
.nearby__item:last-child { border-bottom: 0; }
.nearby__name { color: var(--ink-soft); }
.nearby__far { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------------------------------------------- listing card, extra flags -- */

.card__flags {
  display: flex; flex-wrap: wrap; gap: var(--s1);
  margin-top: var(--s2);
}
.card__flag {
  font-size: 11.5px; font-weight: 600; line-height: 1.3;
  padding: 3px 8px;
  border-radius: var(--r-full);
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--muted);
}
.card__flag--drop { border-color: var(--brand-200); background: var(--brand-50); color: var(--ok); }
.card__flag--plan { border-color: var(--gold-200); background: var(--gold-50); color: var(--gold-700); }
.card__flag--doc  { border-color: var(--line); background: var(--surface); color: var(--ink-soft); }

/* --------------------------------------------------------- more filters --- */
/* A <details>, so it works with no script and holds its state in the markup.
   Fourteen controls on one row is how a filter bar stops being used at all. */

.filters__more { margin-top: var(--s3); }

.filters__more > summary {
  cursor: pointer;
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--brand-700);
  padding: var(--s2) 0;
  list-style: none;
  display: inline-flex; align-items: center; gap: var(--s1);
}
.filters__more > summary::-webkit-details-marker { display: none; }
.filters__more > summary::after {
  content: "";
  width: 7px; height: 7px;
  border-inline-end: 2px solid currentColor;
  border-block-end: 2px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
  transition: transform .18s var(--ease);
}
.filters__more[open] > summary::after { transform: rotate(-135deg) translateY(-2px); }

.field--check { display: flex; flex-direction: column; gap: var(--s2); justify-content: flex-end; }

.check {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-size: var(--t--1);
  color: var(--ink-soft);
  cursor: pointer;
  line-height: 1.4;
}
.check input { accent-color: var(--brand); flex: none; }

.filters__features {
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: var(--s3) var(--s4) var(--s4);
  margin: var(--s3) 0 0;
}
.filters__features legend {
  font-size: var(--t--1); font-weight: 600; color: var(--muted);
  padding-inline: var(--s2);
}
.filters__checks {
  display: grid; gap: var(--s2) var(--s4);
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
}

/* ------------------------------------------------------------- compare ----- */
/* Scrolls sideways inside its own box on a phone rather than making the whole
   page scroll: the label column stays put, which is what makes a wide table
   readable on a small screen at all. */

.cmp-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--white);
  margin-bottom: var(--s4);
  -webkit-overflow-scrolling: touch;
}

.cmp {
  border-collapse: collapse;
  width: 100%;
  min-width: 560px;
  font-size: var(--t-0);
}

.cmp th, .cmp td {
  padding: var(--s3) var(--s4);
  text-align: start;
  vertical-align: top;
  border-bottom: 1px solid var(--line-soft);
}

.cmp thead th { border-bottom: 1px solid var(--line); vertical-align: bottom; }

.cmp tbody th {
  font-weight: 600;
  color: var(--muted);
  font-size: var(--t--1);
  white-space: nowrap;
  background: var(--surface);
  width: 1%;
}

.cmp td { color: var(--ink-soft); font-variant-numeric: tabular-nums; }

.cmp__head { display: block; text-decoration: none; color: inherit; }
.cmp__img {
  width: 100%; max-width: 220px; height: auto;
  border-radius: var(--r-sm);
  display: block;
  margin-bottom: var(--s2);
}
.cmp__title {
  display: block;
  font-weight: 600;
  color: var(--ink);
  font-size: var(--t--1);
  line-height: 1.4;
}
.cmp__head:hover .cmp__title { color: var(--brand-700); }

/* Same in every column: still shown, because knowing two plots are both five
   marla is part of the comparison — just not the part worth looking at. */
.cmp__row--same td { color: var(--muted); }

.cmp__blank { color: var(--faint); font-style: normal; }

.cmp tfoot td { border-bottom: 0; padding-top: var(--s4); }

.cmp__note {
  font-size: var(--t--1);
  color: var(--muted);
  margin: 0 0 var(--s7);
  max-width: 60ch;
}

/* --------------------------------------------------------- area guides ---- */
/* The rate table is the most valuable thing on an area page and the thing the
   owner revises most often, so it is given the weight of a real table rather
   than being folded into the prose. */

.rates { margin: 0 0 var(--s6); }
.rates__h { font-size: var(--t-2); margin-bottom: var(--s3); }

.rates__wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--white);
}

.rates__table { border-collapse: collapse; width: 100%; min-width: 380px; }

.rates__table th, .rates__table td {
  text-align: start;
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--line-soft);
  font-variant-numeric: tabular-nums;
}
.rates__table thead th {
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--muted);
  background: var(--surface);
  white-space: nowrap;
}
.rates__table tbody th { font-weight: 600; color: var(--ink); white-space: nowrap; }
.rates__table tbody tr:last-child th,
.rates__table tbody tr:last-child td { border-bottom: 0; }
.rates__trend { color: var(--muted); font-size: var(--t--1); }

.rates__note {
  margin: var(--s3) 0 0;
  font-size: var(--t--1);
  color: var(--muted);
  display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3);
}
.rates__when { color: var(--faint); }

.prose--guide { margin-bottom: var(--s7); }

/* ------------------------------------------------------------- byline ------ */
/* An article about handing over a crore of somebody's money is worth more
   signed than unsigned, and the signature links to a person with a phone. */

.byline {
  margin-top: var(--s7);
  padding-top: var(--s5);
  border-top: 1px solid var(--line);
}
.byline__eyebrow {
  margin: 0 0 var(--s3);
  font-size: var(--t--1);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}

.chip--cat { font-size: var(--t--1); }
.chip.is-on { background: var(--brand); color: #fff; border-color: var(--brand); }

/* --------------------------------------------------------- cookie bar ------ */
/* A notice, not a consent gate — the analytics tag fires either way, and a box
   claiming to ask permission it does not enforce would be a lie. */

.cookiebar {
  position: fixed;
  z-index: 60;
  inset-inline: var(--s4);
  inset-block-end: var(--s4);
  max-width: 560px;
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s3);
  padding: var(--s4);
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-3);
}
.cookiebar__text { margin: 0; flex: 1 1 240px; font-size: var(--t--1); line-height: 1.55; }

/* ------------------------------------------------- viewing request form ---- */

.field--visit {
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: var(--s3) var(--s4) var(--s4);
  margin: 0;
}
.field--visit legend { font-size: var(--t--1); font-weight: 600; padding-inline: var(--s2); }
.visit__row { display: grid; gap: var(--s3); grid-template-columns: 1fr 1fr; }
.visit__cell { min-width: 0; }
.visit__cell label { display: block; font-size: var(--t--1); margin-bottom: var(--s1); color: var(--body); }
.visit__cell input, .visit__cell select { width: 100%; }

@media (max-width: 480px) {
  .visit__row { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------- preview -------- */

.banner--preview {
  background: var(--gold-50);
  border-color: var(--gold-200);
  color: var(--gold-700);
}

/* ------------------------------------------------------- accessibility ----- */
/* One visible focus treatment for everything that takes focus. :focus-visible
   so it appears for the keyboard and not for a mouse click, with a plain
   :focus fallback for browsers that do not know the newer selector — losing
   the ring entirely is much worse than showing it slightly too often. */

:where(a, button, input, select, textarea, summary, [tabindex]):focus {
  outline: 3px solid var(--brand-500);
  outline-offset: 2px;
  border-radius: 3px;
}
:where(a, button, input, select, textarea, summary, [tabindex]):focus:not(:focus-visible) {
  outline: none;
}
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--brand-500);
  outline-offset: 2px;
  border-radius: 3px;
}

/* On the dark call-to-action card the brand green has almost no contrast
   against the background it would be drawn on, so the ring goes light there. */
.cta-card :where(a, button):focus-visible,
.sticky-cta :where(a, button):focus-visible {
  outline-color: #fff;
}

/* ------------------------------------------------- micro-interactions ------ */

/* The small answers a page gives back when it is touched: a press that gives
   under the finger, a row that lights as the cursor crosses it, an arrow that
   leans towards where it is about to take you.

   Three rules hold throughout:

   - Nothing here animates anything but transform, opacity, colour and shadow.
     The first two are free; the last two cost a repaint and no layout. Nothing
     touches width, height, margin or top, because a page full of those is what
     turns a mid-range Android into a slideshow.
   - Every duration is shorter than an entrance. An entrance is the page
     arriving and can afford .55s; a hover is an answer to the reader's hand,
     and much above .2s reads as lag rather than as polish.
   - Direction is written with logical properties, so the leaning arrows turn
     around in Urdu without a second rule.

   The reduced-motion block further down flattens every duration here to
   nothing, which leaves a visitor who asked their phone to stop moving with all
   of the colour changes and none of the travel. */

/* ---- the press ----------------------------------------------------------- */

/* One shared answer to being pushed, and deliberately a scale rather than a
   drop: on a phone the finger is already covering the control, and a thing that
   shrinks under the thumb still reads as pressed when it cannot be seen. */
.chip:active,
.heart:active,
.action:active,
.pager__link:active,
.purpose-tabs__tab:active,
.area-tile:active { transform: scale(.96); }

.btn:active { transform: translateY(0) scale(.98); }

/* The blue flash Android paints over a tapped control undoes all of the above.
   Removed only where this file provides a press of its own. */
.chip, .action, .heart, .pager__link, .area-tile, .cred__scan,
.contact-card, .team__member, .review, .spec, .faq__item {
  -webkit-tap-highlight-color: transparent;
}

/* ---- arrows lean --------------------------------------------------------- */

/* An icon sitting after its label is pointing at where the link goes, so on
   hover it sets off that way. Flipped for Urdu, where after the label is to
   the left and an arrow travelling right would be leaving backwards. */
.cred__verify svg { transition: transform .18s var(--ease); }
.cred__verify:hover svg { transform: translate3d(.18em, -.18em, 0); }
.is-rtl .cred__verify:hover svg { transform: translate3d(-.18em, -.18em, 0); }

/* ---- links that draw their own underline --------------------------------- */

/* The footer links carry no underline at rest, so theirs is drawn on: a
   gradient grown across the word rather than a border switched on, because a
   border changes the line box and shifts the column as the cursor moves down
   it. The start edge is written for both directions, so in Urdu the rule grows
   from the right, which is the direction the line is read in.

   This is deliberately the only place on the site that does it. Every other
   link sits inside something that already answers on hover, and two answers to
   one gesture is noise rather than richness. */
.site-foot a {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1.5px;
  transition: background-size .28s var(--ease), color .18s var(--ease);
}
.is-rtl .site-foot a { background-position: 100% 100%; }
.site-foot a:hover { background-size: 100% 1.5px; }

/* Prose links are underlined already, so there is no line to draw. Theirs
   thickens and drops a little clear of the text, which reads as the link
   coming forward - where a second rule grown underneath the first would just
   read as a rendering fault. */
.prose a {
  transition: color .18s var(--ease),
              text-decoration-thickness .18s var(--ease),
              text-underline-offset .18s var(--ease);
}
.prose a:hover { text-decoration-thickness: 2px; text-underline-offset: 3px; }

/* Nastaliq descends a long way below its baseline and a rule set close to it
   cuts through the script, so Urdu keeps the colour change and leaves the
   underline where the base rule put it. */
[lang="ur"] .prose a:hover { text-decoration-thickness: 1px; text-underline-offset: 2px; }

/* ---- panels that lift ---------------------------------------------------- */

/* The gesture the listing cards already make, extended to the other panels a
   reader can act on, so that "this is a thing rather than a paragraph" is said
   the same way everywhere. The border tint carries it on touch, where the
   hover never fires and the shadow never arrives. */
.contact-card,
.team__member,
.review,
.cred,
.faq__item {
  transition: transform .22s var(--ease), box-shadow .22s var(--ease),
              border-color .22s var(--ease);
}
.contact-card:hover,
.team__member:hover,
.review:hover,
.cred:hover,
.faq__item:hover {
  /* Both spellings of the same move: the transform for a panel with no
     entrance on it, the variable for one that has. */
  transform: translateY(-3px);
  --rv-lift: -3px;
  box-shadow: var(--sh-2);
  border-color: var(--brand-200);
}

/* The specification tiles are a grid of small facts separated by hairlines, so
   one of them lifting would tear the grid open. They warm instead. */
.spec { transition: background-color .18s var(--ease), color .18s var(--ease); }
.spec:hover { background: var(--brand-50); }
.spec:hover dd { color: var(--brand-800); }

/* ---- rows in a table ----------------------------------------------------- */

/* Both tables on this site are read across a row - what does this size cost,
   what does this listing say - so lighting the row under the cursor is the
   whole of the job. */
.rates__table tbody tr,
.cmp tbody tr { transition: background-color .16s var(--ease); }
.rates__table tbody tr:hover,
.cmp tbody tr:hover { background: var(--brand-50); }

.cmp__head { display: block; transition: transform .22s var(--ease); }
.cmp__head:hover { transform: translateY(-3px); }
.cmp__img { transition: box-shadow .22s var(--ease); }
.cmp__head:hover .cmp__img { box-shadow: var(--sh-2); }

/* ---- the shortlist heart ------------------------------------------------- */

/* Saving is the one moment on a card where the reader has committed to
   something, and it has earned more than a change of colour. The keyframe
   overshoots once and settles: a heart that only grows reads as a hover that
   got stuck rather than as a thing that happened. */
@keyframes heart-pop {
  0%   { transform: scale(1); }
  38%  { transform: scale(1.34); }
  100% { transform: scale(1); }
}
.heart.is-on { animation: heart-pop .34s var(--ease); }

/* ---- fields -------------------------------------------------------------- */

/* The focused field is lifted a hair clear of the form. On a long enquiry form
   on a small screen that is what says which line you are on once the keyboard
   has covered the other half of it. */
input, select, textarea {
  transition: border-color .16s var(--ease), box-shadow .18s var(--ease),
              transform .18s var(--ease);
}
.lead__form input:focus,
.lead__form select:focus,
.lead__form textarea:focus { transform: translateY(-1px); }

/* ---- the gallery strip --------------------------------------------------- */

/* The thumbnails already come up to full opacity on hover. The scale is what
   makes the strip read as a row of photographs rather than a row of buttons. */
.gallery__thumb { transition: opacity .18s var(--ease), transform .18s var(--ease); }
.gallery__thumb:hover { transform: scale(1.05); }

/* ---- the pager ----------------------------------------------------------- */

.pager__link {
  transition: border-color .16s var(--ease), background .16s var(--ease),
              color .16s var(--ease), transform .16s var(--ease);
}
.pager__link:hover { transform: translateY(-2px); }

/* ---- trust marks --------------------------------------------------------- */

/* The registration row is not a link, so it gets the smallest acknowledgement
   there is - the shield warms as the cursor passes. Anything more would promise
   an action that is not on offer. */
.trustbar__item { transition: color .18s var(--ease); }
.trustbar__item:hover { color: var(--brand-700); }

/* ------------------------------------------------------------- liquid ----- */

/* Pointer polish. Every rule here is scoped to .is-liquid, which the body only
   carries when the owner has left the switch on, so turning it off removes the
   layer rather than leaving a quieter version of it.

   main.js writes the custom properties and nothing else - no classes toggled
   per frame, no styles set directly on elements. That keeps the whole layer
   readable from this file alone, and means a script that never arrives leaves
   every default in place: --mx and --my unset means no sheen, --mag-x unset
   means no lean, --flow unset means the grid sits still. */

/* ---- the sheen ----------------------------------------------------------- */

/* A soft light following the cursor across a card. Painted on a pseudo-element
   rather than as a background on the card itself, because the card's own
   background is white and a gradient over it would have to be re-declared
   every time the theme changes.

   It is held at zero opacity until the pointer is actually inside, so a card
   the mouse has merely passed over on its way somewhere else does not light
   up behind it. */
/* The area tiles are deliberately not in this list. Their ::after is already
   the brand bar that wipes down their leading edge, and a second rule for the
   same pseudo-element does not sit alongside the first - it merges with it, and
   the tile loses its accent to a gradient. They have their own hover language
   and do not need this one. */
.is-liquid .card,
.is-liquid .post-card,
.is-liquid .cred,
.is-liquid .contact-card { position: relative; }

.is-liquid :where(.card, .post-card, .cred, .contact-card)::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity .3s var(--ease);
  background: radial-gradient(
    22rem circle at var(--mx, 50%) var(--my, 50%),
    rgba(255, 255, 255, .55),
    rgba(255, 255, 255, .16) 38%,
    transparent 68%
  );
  /* Screened rather than laid over: on a photograph a flat white wash reads as
     fog, while screen only lifts what is already light. */
  mix-blend-mode: soft-light;
}

.is-liquid :where(.card, .post-card, .cred, .contact-card):hover::after {
  opacity: 1;
}

/* ---- the magnet ---------------------------------------------------------- */

/* The button leans a few pixels towards the cursor. The lean, the hover rise
   and the press are three separate variables folded into one transform, for
   the reason written against the entrances: a second transform rule on the
   same element does not compose with the first, it replaces it, and whichever
   loses is a gesture that silently stops working. */
.is-liquid .btn {
  transform: translate3d(var(--mag-x, 0px),
                         calc(var(--mag-y, 0px) + var(--btn-y, 0px)), 0)
             scale(var(--btn-s, 1));
}
.is-liquid .btn:hover  { --btn-y: -1px; }
.is-liquid .btn:active { --btn-y: 0px; --btn-s: .98; }

/* ---- the ripple ---------------------------------------------------------- */

/* Spreads from where the press landed. Clipped to the control, so on a pill
   button it is a pill and on a square one it is a square, with no second rule
   saying so. */
.is-liquid .btn,
.is-liquid .chip,
.is-liquid .pager__link { position: relative; overflow: hidden; }

.ripple {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  background: currentColor;
  opacity: .22;
  transform: scale(0);
  animation: ripple-out .55s var(--ease) forwards;
}

@keyframes ripple-out {
  to { transform: scale(1); opacity: 0; }
}

/* ---- the give ------------------------------------------------------------ */

/* The grid lags a few pixels behind a fast scroll and settles when the thumb
   stops. One transform on one container: the same effect written per card is
   thirty style recalculations a frame, which is exactly the wrong trade on the
   mid-range phones most of these visitors are holding.

   Capped at six pixels. Past that it stops reading as weight and starts
   reading as a page that cannot keep up. */
.is-liquid .grid--cards,
.is-liquid .grid--posts {
  transform: translate3d(0, calc(var(--flow, 0) * 6px), 0);
}

/* ------------------------------------------------------- the unit switch --- */

/* Sits at the start of the toolbar and pushes the sort control to the far end,
   which works whether or not the sort is there - space-between would move the
   sort to the left on any page that has no switch. */
.unitsw {
  display: flex; align-items: center; gap: var(--s3);
  margin-inline-end: auto;
  font-size: var(--t--1);
}
.unitsw__label { color: var(--muted); }

.unitsw__opts {
  display: inline-flex;
  border: 1.5px solid var(--line);
  border-radius: var(--r-full);
  background: #fff;
  padding: 2px;
}

.unitsw__opt {
  border: 0; background: none; cursor: pointer;
  font: inherit; font-size: var(--t--2); font-weight: 600;
  color: var(--body);
  padding: 7px 13px;
  border-radius: var(--r-full);
  transition: background-color .18s var(--ease), color .18s var(--ease);
}
.unitsw__opt:hover { color: var(--brand-700); }
.unitsw__opt.is-on { background: var(--brand); color: #fff; }

/* The switch stands alone above the specification grid on a listing, where
   there is no toolbar to sit in. */
.property__main .unitsw { margin: 0 0 var(--s4); }

/* --------------------------------------------------------- saved searches -- */

.ssearch { margin: 0 0 var(--s5); }

.ssearch__bar { display: flex; flex-wrap: wrap; gap: var(--s2) var(--s3); align-items: center; }

.ssearch__save,
.ssearch__toggle {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 15px;
  border: 1.5px solid var(--line); border-radius: var(--r-full);
  background: #fff; color: var(--body);
  font: inherit; font-size: var(--t--1); font-weight: 600;
  cursor: pointer;
  transition: border-color .18s var(--ease), background-color .18s var(--ease),
              color .18s var(--ease);
}
.ssearch__save:hover,
.ssearch__toggle:hover { border-color: var(--brand-200); background: var(--brand-50); color: var(--brand-700); }

/* Saved reads as a state rather than as an offer, so it takes the brand colour
   the way a ticked filter chip does. */
.ssearch__save.is-on {
  background: var(--brand-50); border-color: var(--brand-200); color: var(--brand-700);
}
.ssearch__save.is-on svg { fill: currentColor; }

.ssearch__list {
  list-style: none; margin: var(--s3) 0 0; padding: var(--s2);
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface);
  max-width: 46rem;
}
.ssearch__list li {
  display: flex; align-items: center; gap: var(--s2);
  border-radius: var(--r-sm);
}
.ssearch__list li + li { margin-top: 2px; }
.ssearch__list li:hover { background: #fff; }

.ssearch__link {
  flex: 1 1 auto; min-width: 0;
  padding: 10px var(--s3);
  font-size: var(--t--1); color: var(--ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ssearch__link:hover { color: var(--brand-700); }

.ssearch__drop {
  flex: 0 0 auto;
  width: 30px; height: 30px; margin-inline-end: 4px;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: none; color: var(--muted);
  font-size: 1.1rem; line-height: 1; cursor: pointer;
  transition: background-color .16s var(--ease), color .16s var(--ease);
}
.ssearch__drop:hover { background: var(--bad-bg); color: var(--bad); }

/* ------------------------------------------------------------ responsive --- */

@media (max-width: 1180px) {
  .brand__text small { display: none; }
  .site-head__inner { gap: var(--s3); }
}

@media (max-width: 1080px) {
  .property__body { grid-template-columns: minmax(0, 1fr) 320px; gap: var(--s6); }
  .contact-grid, .split { grid-template-columns: 1fr; gap: var(--s7); }
  .site-foot__grid { grid-template-columns: 1.4fr 1fr 1fr; }
}

@media (max-width: 1024px) {
  .nav-toggle { display: block; order: 3; }
  /* A phone number is useful reassurance on a property site. Keep it visible
     by default; owners who want a compact icon can choose that in Settings. */
  .btn--call { order: 2; padding: 10px 13px; gap: 7px; font-size: .78rem; }
  .btn--call--icon-only { padding: 11px 14px; }

  .site-head__inner { flex-wrap: wrap; }
  .site-actions { order: 2; margin-inline-start: auto; }
  .header-call { padding: 0 10px; font-size: .78rem; }
  .header-search { inset-inline-end: var(--s4); }
  .site-nav {
    order: 4; flex-basis: 100%; margin: 0;
    display: none; padding-bottom: var(--s3);
  }
  .site-nav.is-open { display: block; }
  .site-nav ul { flex-direction: column; gap: 1px; }
  .site-nav a { padding: 13px var(--s3); border-radius: var(--r-sm); }
  .site-nav a::after { display: none; }
  .site-nav a:hover, .site-nav a:focus-visible, .site-nav a[aria-current="page"] {
    background: var(--brand-50); color: var(--brand-700);
  }
  .site-nav__lang { display: block; }

  .property__body { grid-template-columns: 1fr; }
  .property__aside { position: static; }
  .property__head { flex-direction: column; gap: var(--s4); }
  .property__price { text-align: left; }
  .utility__item--hours { display: none; }

  .typography-journey__stage { min-height: 520px; }
}

@media (max-width: 780px) {
  .utility { display: none; }
  /* The desktop CTA card duplicates the fixed bar, so only one shows. */
  .page-property .cta-card { display: none; }
  .page-property .sticky-cta { display: flex; }
  .page-property .wa-float { display: none; }
  .page-property { padding-bottom: 74px; }
}

@media (max-width: 620px) {
  :root { --gap: var(--s4); }
  .wrap { padding-inline: var(--s4); }
  /* A phone has room for one toolbar, not a brand row plus a controls row.
     The brand yields its extra words first; the three actions remain large
     enough to tap and the navigation drawer is the only thing that may add a
     second row when it is actually opened. */
  .site-head__inner { position: relative; min-height: 64px; flex-wrap: nowrap; gap: 6px; }
  .brand { min-width: 0; flex: 1 1 auto; gap: 8px; }
  .brand__mark { width: 40px; height: 40px; border-radius: 10px; }
  .brand__text { min-width: 0; }
  .brand__text strong {
    display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: .98rem;
  }
  .saved-toggle { display: none !important; }
  .site-actions { order: 2; flex: 0 0 auto; gap: 6px; margin-inline-start: 0; }
  .nav-toggle { order: 3; flex: 0 0 auto; width: 42px; height: 42px; margin-inline-start: 0; }
  .header-action, .header-search-toggle, .header-call { width: 42px; min-height: 42px; padding: 0; }
  .header-call span { display: none; }
  .header-search { inset-inline: var(--s3); width: auto; }
  .site-nav.is-open {
    position: absolute; z-index: 5; inset: 100% 0 auto;
    padding: 8px var(--s4) var(--s4); border-bottom: 1px solid var(--line);
    background: rgba(255, 254, 253, .98); box-shadow: var(--sh-3);
  }
  .hero { padding-block: 46px 38px; }
  .hero__sub { margin-bottom: var(--s6); }
  .hero__search { border-radius: 22px; }
  .grid--cards, .grid--posts { grid-template-columns: 1fr; }
  .site-foot__grid { grid-template-columns: 1fr; gap: var(--s6); }
  .site-foot { padding-top: var(--s8); }
  .filters { padding: var(--s4); }
  .field { flex-basis: 100%; }
  .field--action .btn { width: 100%; }
  .spec-grid { grid-template-columns: 1fr 1fr; }
  .trust { grid-template-columns: 1fr 1fr; gap: var(--s4); }
  .lead { padding: var(--s5); }
  .purpose-tabs__tab { padding: 11px 16px; }
  .wa-float { width: 52px; height: 52px; inset-block-end: var(--s4); inset-inline-end: var(--s4); }
  .lightbox__nav--prev { inset-inline-start: var(--s2); }
  .lightbox__nav--next { inset-inline-end: var(--s2); }

  .statement { padding-block: 64px; }
  .statement__line { max-width: 100%; font-size: clamp(2.35rem, 12vw, 3.7rem); }
  .typography-journey__intro { display: block; margin-bottom: var(--s5); }
  .typography-journey__intro > p:last-child { margin-top: var(--s3); text-align: start; }
  .typography-journey__stage { min-height: 475px; }
  .journey-title { width: 100%; padding: var(--s5); }
  .journey-title h2 { font-size: var(--t-3); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
  .typography-journey::before { animation: none; }
  .typography-journey__stage { min-height: 0; perspective: none; }
  .typography-journey__track { position: static; display: grid; gap: var(--s3); }
  .journey-title { position: static; width: auto; padding: var(--s5); opacity: 1; filter: none; transform: none; animation: none; }
  .typography-journey__caption { position: static; margin-top: var(--s5); }
  .js .reveal, .js .reveal.is-in { opacity: 1; transform: none; }

  /* Every entrance resolves to its finished state rather than to a fast
     version of itself. The word masks matter most: .rvw clips, so a word left
     at its starting transform would be a heading with nothing in it. */
  /* Zeroing the offsets rather than blanking the transform, for the same
     reason the finished state does: transform:none here would outrank every
     hover on the site and take the lift with it. A 3px lift under the cursor
     is not what somebody asking for less movement is asking to be spared, and
     the blanket rule above has already made it instant. */
  .js [data-rv], .js [data-rv].is-in {
    opacity: 1; --rv-x: 0px; --rv-y: 0px; --rv-s: 1;
  }
  .rvw { overflow: visible; }
  .rvw > span, .js .is-in .rvw > span { transform: none; }

  /* The clipping pair have to be opened explicitly. They do not carry their
     starting state in opacity, so the rule above does not reach them, and a
     photograph left at inset(100%) is a hole in the page. */
  .js [data-rv="clip"], .js [data-rv="wipe"],
  .js [data-rv="clip"].is-in, .js [data-rv="wipe"].is-in { clip-path: none; }
  .js [data-rv="soften"], .js [data-rv="soften"].is-in { filter: none; }

  /* Pinning is scroll-linked movement by definition. Without it the gallery
     falls back to the rail it already is when script has not touched it. */
  .hgal.is-pinned { height: auto; }
  .hgal.is-pinned .hgal__stage { position: static; height: auto; padding-block: clamp(48px, 7vw, 96px); }
  .hgal.is-pinned .hgal__track { width: auto; overflow-x: auto; }
  .js .figure[data-parallax] img { height: 100%; transform: none; }

  /* The scroll-linked scale resolves to no scale at all. */
  .js [data-zoom] { transform: none; }

  /* The story unpins and becomes the stack of chapters it is underneath. Every
     chapter has to be put back to full opacity by hand: they carry their
     hidden state on .is-playing rather than on .js, so the general rule above
     does not reach them, and a chapter left at 0 is a paragraph nobody can
     read. */
  .story.is-playing { height: auto; }
  .story.is-playing .story__stage { position: static; height: auto; display: block; padding-block: clamp(56px, 8vw, 104px); }
  .story.is-playing .story__chapters { display: block; }
  .story.is-playing .story__chapter {
    opacity: 1; transform: none; pointer-events: auto;
  }
  .story.is-playing .story__chapter + .story__chapter { margin-block-start: clamp(48px, 7vw, 88px); }
  .story.is-playing .story__layer { opacity: 0; transition: none; }
  .story.is-playing .story__layer:first-child { opacity: 1; }

  /* The ring stops turning and goes back to being a list of links. */
  .ring.is-turning { perspective: none; }
  .ring.is-turning .ring__list {
    position: static; height: auto; display: flex; flex-wrap: wrap;
    transform: none; transition: none;
  }
  .ring.is-turning .ring__item {
    position: static; width: auto; margin-inline-start: 0; transform: none;
  }
  .ring.is-turning .area-tile,
  .ring.is-turning .ring__item.is-front .area-tile { opacity: 1; }
  .ring__nav { display: none; }

  /* The film is movement the visitor did not ask for, and the photograph
     underneath is already the whole picture. main.js does not start it either;
     this is the belt to that braces. */
  .hero__media { transform: scale(1.08); }

  .marquee__track.is-looping { animation: none; }
  /* Without the animation the doubled track is just an over-long line, so the
     copy that only existed to make the loop seamless is dropped. */
  .marquee__row[data-marquee-twin] { display: none; }
  .btn:hover, .card:hover, .post-card:hover, .area-tile:hover,
  .heart:hover, .to-top:hover { transform: none; }
  img.is-blurred { filter: none; transform: none; }

  /* The drawer and the help card appear rather than slide. They still need to
     end up where they belong, so the resting transform is cleared, not the
     opening one - otherwise the panel stays parked off the side of the screen. */
  .drawer__panel, .is-rtl .drawer__panel { transform: none; }
  .drawer--center .drawer__panel { opacity: 1; }
  @view-transition { navigation: none; }
}

/* ------------------------------------------------------------------ print -- */

@media print {
  .site-head, .site-foot, .wa-float, .lead, .filters, .toolbar, .pager,
  .skip, .utility, .sticky-cta, .lightbox, .gallery__thumbs,
  /* The comfort layer is all screen furniture. A printed listing is something
     somebody carries to a viewing, and none of it survives the journey. */
  .progress, .toasts, .netbar, .to-top, .drawer, .saved-toggle, .heart,
  .actions, .pagenav, .backlink, .recent, .activef { display: none !important; }
  body { color: #000; font-size: 11pt; }
  .property__body, .split, .contact-grid { grid-template-columns: 1fr; }
  .card, .panel { break-inside: avoid; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .8em; word-break: break-all; }
}

/* ==========================================================================
   Advertising

   Drawn from the same tokens as everything else, on purpose. An advert that
   looks bolted on makes the whole page look bolted together, and a reader who
   decides a site is cheap stops believing its listings too. What separates an
   advert from the content here is the label above it and the tint behind it,
   not a different typeface and a border in somebody else's blue.

   Three things this section is careful about:

   - Nothing is hidden that a blocked script would have to reveal. The only
     exception is the bar along the bottom, which ships `hidden` like every
     other pinned control, for the reason written in the comfort layer above.
     Every other slot is visible from the first paint; a script that never
     arrives costs the advertiser an animation, not their booking.

   - Height is held open before anything lands in it. --ad-reserve is written
     onto the slot by the template for network adverts, whose size is not known
     until the network answers. Without it, an advert arriving after the text
     has been read moves the page under somebody's thumb, which is how an
     advert earns a click it did not deserve and a visitor who does not come
     back.

   - The label is never letter-spaced in Urdu. Nastaliq is a connected script
     and tracking breaks the joins.
   ========================================================================== */

.ad {
  --ad-y: 12px;
  position: relative;
  margin-block: var(--s6);
}

/* The entrance. Scoped to .js so that a page whose script is blocked has no
   starting state to be stranded in, and written as a variable rather than a
   `transform: none` finish, so that a hover added to this element later
   composes with it instead of replacing it. */
.js .ad {
  opacity: 0;
  /* Two movements, one transform. The entrance sets --ad-y and the drift sets
     --ad-drift, and they are added inside a single translate rather than
     written as two rules — a second transform rule on the same element does
     not compose with the first, it replaces it, and whichever loses is a
     movement that silently stops working. */
  transform: translate3d(0, calc(var(--ad-y) + var(--ad-drift, 0px)), 0);
  transition: opacity .5s var(--ease), transform .5s var(--ease);
}
.js .ad.is-in { opacity: 1; --ad-y: 0px; }

/* Once the entrance is over, the drift has to answer the scroll rather than
   ease behind it by half a second. The transition is dropped from transform
   and kept on opacity, so the advert still fades in and then tracks the page
   exactly. */
.js .ad--fx-drift.is-in { transition: opacity .5s var(--ease); }

/* The room the drift moves in. 22 pixels each way is exactly what main.js
   writes, so the advert travels inside its own slot and never rides over the
   paragraph above or the one below — and is never clipped, which is the whole
   point of bounding it. */
.ad--fx-drift { padding-block: 22px; }

/* No entrance at all on this one. The markup still ships, so a placement set
   to "sit still" is visible from the first paint whether or not the script
   arrives. */
.js .ad--fx-none { opacity: 1; --ad-y: 0px; transition: none; }

.ad__label {
  margin: 0 0 var(--s2);
  font-size: var(--t--2);
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--faint);
}

/* Nastaliq is a connected script: tracking pulls the joins apart. */
.is-rtl .ad__label { letter-spacing: normal; text-transform: none; }

.ad__box { position: relative; }

/* Only a network slot needs the space held open. A house advert is already in
   the markup and sizes itself, and reserving height for something that is
   present just leaves a gap underneath it. */
.ad--reserve .ad__box { min-height: var(--ad-reserve, 120px); }

.ad__item {
  display: block;
  position: relative;
  color: inherit;
  border-radius: var(--r-lg);
  overflow: hidden;
  transition: box-shadow .26s var(--ease), transform .26s var(--ease),
              border-color .26s var(--ease);
}

.ad__media { display: block; }
.ad__media img {
  display: block; width: 100%; height: auto;
  background: var(--surface-2);
}

.ad__text {
  display: flex; flex-direction: column; gap: var(--s1);
  padding: var(--s4) var(--s5);
}
.ad__by {
  font-size: var(--t--2); font-weight: 600; color: var(--muted);
}
.ad__head {
  font-family: var(--font-display);
  font-size: var(--t-1); line-height: 1.25; color: var(--ink);
}
.ad__body { font-size: var(--t--1); color: var(--body); }
.ad__cta {
  margin-block-start: var(--s2);
  align-self: flex-start;
  padding: 7px 16px;
  border-radius: var(--r-full);
  background: var(--brand); color: #fff;
  font-size: var(--t--1); font-weight: 600;
  transition: background-color .18s var(--ease);
}
a.ad__item:hover .ad__cta { background: var(--brand-600); }

/* The mid-article slot sits inside .prose, where every link is underlined so
   that it reads as a link in a sentence. This one is a card, and an underline
   running the width of its headline and its body text reads as a fault in the
   page rather than as an invitation. The class is what wins here: `.prose a`
   is two selectors and would otherwise outrank a bare `.ad__item`. */
.prose a.ad__item,
.prose a.ad__item:hover { text-decoration: none; }

/* Whatever the advertiser supplies, it stays inside the column. A network unit
   wider than the page is the fastest way to give every phone a horizontal
   scroll bar it cannot get rid of. */
.ad__net { max-width: 100%; overflow: hidden; }
.ad__net img, .ad__net iframe { max-width: 100%; }

/* The sealed frame. Everything that matters about it is in the sandbox
   attribute rather than here — this only has to make a frame look like part of
   the page instead of like a frame. */
.ad__frame {
  display: block;
  width: 100%;
  border: 0;
  /* The height comes from the zone's reserved height, written inline, so the
     space is held before the frame has loaded anything into it. */
  background: transparent;
  color-scheme: light;
}

/* ---- tone ---------------------------------------------------------------- */

/* The owner's choice of whether a placement sits on the page plainly or in a
   panel of its own. Tinted reads as more clearly separate from the content,
   which is worth having where an advert sits close to something it could be
   mistaken for. */
.ad--tinted {
  padding: var(--s4);
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-lg);
}
.ad--tinted.ad--fx-drift { padding-block: calc(var(--s4) + 22px); }
.ad--tinted .ad__label { margin-inline-start: 2px; }

/* Already a card, already a bar: a panel around either is a box in a box. */
.ad--native.ad--tinted, .ad--anchor.ad--tinted, .ad--strip.ad--tinted {
  padding: 0; background: none; border: 0; border-radius: 0;
}

/* ---- a banner across the column ------------------------------------------ */

.ad--banner .ad__item,
.ad--rect .ad__item {
  border: 1px solid var(--line);
  background: var(--surface);
}
.ad--banner a.ad__item:hover,
.ad--rect a.ad__item:hover {
  box-shadow: var(--sh-2);
  border-color: transparent;
  transform: translateY(-2px);
}

@media (min-width: 720px) {
  /* Picture beside the words rather than above them, so a banner reads as a
     band across the page instead of a second hero. */
  .ad--banner .ad__item {
    display: grid;
    grid-template-columns: minmax(0, 260px) minmax(0, 1fr);
    align-items: center;
  }
  .ad--banner .ad__media img { height: 100%; object-fit: cover; }
}

.ad--rect { max-width: 420px; margin-inline: auto; }

/* ---- a card in a grid of cards ------------------------------------------- */

/* Sits in .grid--cards and .grid--posts as one more child, so it inherits the
   column it lands in and needs no width of its own.

   The slot itself is the card, not the box inside it. The label is a sibling
   of the box rather than a child — it is written before it in every format —
   so drawing the card on the box would leave the word "Advertisement" floating
   above the grid row, which throws out the alignment of every card beside it. */
.ad--native {
  margin-block: 0;
  height: 100%;
  display: flex; flex-direction: column;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--sh-1);
  transition: box-shadow .26s var(--ease), border-color .26s var(--ease);
}

.ad--native .ad__label {
  margin: 0;
  padding: var(--s3) var(--s4) 0;
}
.ad--native .ad__box { flex: 1; display: flex; flex-direction: column; }
.ad--native .ad__item { border-radius: 0; flex: 1; }
.ad--native .ad__media img { aspect-ratio: 4 / 3; object-fit: cover; }
.ad--native:hover { box-shadow: var(--sh-3); border-color: transparent; }

/* ---- the column beside a listing ----------------------------------------- */

/* Follows the reader down the page while they scroll the description. Sticky
   rather than fixed: it stops at the end of its own column instead of sitting
   over the footer, and it costs nothing per frame because the browser does it
   rather than a scroll handler. */
.ad--rail {
  margin-block-start: var(--s5);
  position: sticky;
  /* Clear of the sticky header, whatever the header is doing. */
  inset-block-start: calc(var(--s5) + 64px);
}
.ad--rail .ad__item {
  border: 1px solid var(--line);
  background: var(--surface);
}
.ad--rail .ad__text { padding: var(--s4); }

@media (max-width: 1024px) {
  /* The aside stacks under the description on a narrow screen, where sticking
     would park an advert over the enquiry form somebody is filling in. */
  .ad--rail { position: static; }
}

/* ---- the bar along the bottom -------------------------------------------- */

.ad--anchor {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 54;
  margin: 0;
  display: flex; align-items: center; gap: var(--s3);
  /* Room at the top for the label, which is lifted out of the row below so
     that it cannot set the height of the bar. */
  padding: 17px var(--s4) var(--s2);
  padding-bottom: calc(var(--s2) + env(safe-area-inset-bottom, 0px));
  background: rgba(255, 255, 255, .94);
  backdrop-filter: blur(10px);
  border-block-start: 1px solid var(--line);
  box-shadow: 0 -6px 24px rgba(9, 42, 30, .08);
  transform: translate3d(0, 100%, 0);
  transition: transform .42s var(--ease), opacity .42s var(--ease);
}

/* Both selectors carry .js on purpose. The shared entrance above is written as
   `.js .ad`, which outranks a bare `.ad--anchor` — so an anchor rule without
   the same weight loses its transform to the entrance and the bar never
   slides, it just appears in place. Matching the weight is what keeps the two
   from arguing. */
.js .ad--anchor { opacity: 1; transform: translate3d(0, 100%, 0); }
.js .ad--anchor.is-in { transform: translate3d(0, 0, 0); }

/* Along the top of the bar rather than turned on its side down the edge.
   Rotated, it was 81 pixels of the word "Advertisement" setting the height of
   the whole bar — 12% of a phone screen for a strip whose entire justification
   is that it does not take much. Lifted out of the row, the picture sets the
   height instead and the bar comes in around seventy. */
.ad--anchor .ad__label {
  position: absolute;
  inset-block-start: 4px;
  inset-inline-start: var(--s4);
  margin: 0;
  font-size: 9px;
  line-height: 1;
  opacity: .65;
}

.ad--anchor .ad__box { flex: 1; min-width: 0; }
.ad--anchor .ad__item { display: flex; align-items: center; gap: var(--s3); }
.ad--anchor .ad__media { flex: 0 0 auto; }
.ad--anchor .ad__media img { width: 46px; height: 46px; object-fit: cover; border-radius: var(--r-sm); }
/* min-width: 0 is what makes the ellipsis below possible. A flex child will
   not shrink past the width of its own content by default, so a long headline
   pushes the whole row wider than the bar and takes the button off the side of
   the screen with it — which on a phone means an advert nobody can act on and
   a close button somebody has to hunt for. */
.ad--anchor .ad__text { padding: 0; gap: 0; flex: 1 1 auto; min-width: 0; }
.ad--anchor .ad__head {
  font-size: var(--t--1); font-family: var(--font-sans); font-weight: 650;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ad--anchor .ad__body {
  font-size: var(--t--2);
  /* One line. A bar that grows to two has taken a third of a phone screen. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ad--anchor .ad__cta { margin: 0; padding: 5px 12px; font-size: var(--t--2); flex: 0 0 auto; }

.ad__close {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 32px; height: 32px;
  border: 1px solid var(--line); border-radius: var(--r-full);
  background: #fff; color: var(--muted);
  cursor: pointer;
  transition: color .16s var(--ease), border-color .16s var(--ease);
}
.ad__close:hover { color: var(--ink); border-color: var(--faint); }

/* The other things pinned to that corner move up out of the way. Written here
   rather than as a change to their own rules, so that deleting this section
   removes every trace of advertising from the stylesheet. */
.has-anchor-ad .wa-float { inset-block-end: calc(var(--s5) + var(--anchor-h, 68px)); }
.has-anchor-ad .to-top   { inset-block-end: calc(var(--s5) + 70px + var(--anchor-h, 68px)); }
.has-anchor-ad .toasts   { inset-block-end: calc(var(--s5) + var(--anchor-h, 68px)); }

/* ---- the pointer polish -------------------------------------------------- */

/* Joins the liquid layer on the same terms as everything else in it: a soft
   light following the cursor, painted on a pseudo-element of its own. Checked
   before it was written, as that section says to - .ad__item carries no other
   ::after, so there is nothing here for this rule to merge with and silently
   replace. */
.is-liquid .ad__item { position: relative; }
.is-liquid a.ad__item::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity .3s var(--ease);
  background: radial-gradient(
    22rem circle at var(--mx, 50%) var(--my, 50%),
    rgba(255, 255, 255, .55),
    rgba(255, 255, 255, .16) 38%,
    transparent 68%
  );
  mix-blend-mode: soft-light;
}
.is-liquid a.ad__item:hover::after { opacity: 1; }

/* ---- rotation ------------------------------------------------------------ */

/* Two advertisers booked into one place, crossfading rather than flicking. The
   outgoing advert keeps its space until the fade is over, so the box never
   collapses mid-change, and it stops taking clicks the moment it starts to
   leave - a tap landing on an advert halfway out is a click nobody meant. */
.ad__box--rotating .ad__item { transition: opacity .45s var(--ease); }
.ad__item.is-fading { opacity: 0; pointer-events: none; }

/* ---- the partner strip --------------------------------------------------- */

/* A row of local business logos above the footer. Quiet on purpose: this is
   the placement an office can sell for a year to a builder who will actually
   renew, and the reason it renews is that it never got in anybody's way.

   Nothing here rotates. Every partner is shown at once, which is what makes it
   worth buying — a partner who cannot point their own customer at it is a
   partner who does not pay again. */
.ad--strip {
  margin-block: var(--s7) var(--s5);
  padding-block-start: var(--s5);
  border-block-start: 1px solid var(--line-soft);
}

.ad--strip .ad__label { text-align: center; }

.ad--strip .ad__box {
  display: flex; flex-wrap: wrap;
  align-items: center; justify-content: center;
  gap: var(--s4) var(--s6);
}

.ad--strip .ad__item {
  border-radius: var(--r-sm);
  /* The logos come from a dozen different businesses and no two arrive the
     same size or the same weight of colour. Held to one height and lifted to
     full strength on hover, they read as one row rather than as a scrapbook. */
  opacity: .72;
  filter: grayscale(1);
  transition: opacity .22s var(--ease), filter .22s var(--ease), transform .22s var(--ease);
}
.ad--strip a.ad__item:hover {
  opacity: 1;
  filter: none;
  transform: translateY(-2px);
}

.ad--strip .ad__media img {
  width: auto; height: 34px;
  max-width: 150px;
  object-fit: contain;
  background: none;
}

/* A partner with no logo falls back to their name, at the size the logos are,
   so the row keeps its rhythm rather than growing a paragraph in the middle. */
.ad--strip .ad__text { padding: 0; gap: 0; }
.ad--strip .ad__head {
  font-family: var(--font-sans);
  font-size: var(--t--1); font-weight: 650; color: var(--body);
}
.ad--strip .ad__by, .ad--strip .ad__body, .ad--strip .ad__cta { display: none; }

@media (max-width: 620px) {
  .ad--strip .ad__box { gap: var(--s4); }
  .ad--strip .ad__media img { height: 26px; max-width: 110px; }
}

/* ---- promoted listings --------------------------------------------------- */

/* Said out loud on the card, for the same reason an advert is labelled. A
   listing at the top because somebody paid is not the same as a listing at the
   top because it matched, and a reader who works that out for themselves later
   stops believing the rest of the page.

   Deliberately not the brand colour: "Verified" and "New" are the site
   vouching for something, and this one is not. */
.tag--promoted {
  background: rgba(253, 248, 238, .94);
  color: var(--gold-700);
  box-shadow: inset 0 0 0 1px var(--gold-200);
}


/* ---- how it arrives ------------------------------------------------------ */

/* Each of these replaces the shared rise above rather than adding to it, so
   every one of them has to clear the starting state the rise set — opacity 0
   and a --ad-y offset — or the advert arrives twice, from two places at once.
   That is why each block below says `opacity: 1; --ad-y: 0px` before doing
   anything of its own. */

/* Curtain. Uncovered from the side the language reads from, with nothing
   fading, so the advert is legible the whole way through rather than
   half-there. clip-path has no logical form, so the RTL case is a rule of its
   own — this is exactly the kind of thing the .is-rtl block exists for. */
.js .ad--fx-curtain {
  opacity: 1; --ad-y: 0px;
  clip-path: inset(0 100% 0 0);
  transition: clip-path .85s var(--ease);
}
.js .ad--fx-curtain.is-in { clip-path: inset(0 0 0 0); }

/* `.js` is on <html> and `.is-rtl` on <body>, so the Urdu pair has to be
   written in that order — `.is-rtl .js` describes an ancestry that does not
   exist and would never match at all.
   The open state below also has to carry both classes. Written as
   `.js .ad--fx-curtain.is-in` it ties on specificity with the closed rule
   above it and loses on source order, which leaves every advert on an Urdu
   page shut. */
.js .is-rtl .ad--fx-curtain { clip-path: inset(0 0 0 100%); }
.js .is-rtl .ad--fx-curtain.is-in { clip-path: inset(0 0 0 0); }

/* Tilt. Leans away and straightens as it lands, once. The rotation is on the
   box rather than the slot so that it cannot collide with the shared translate
   on .ad — two transform rules on one element do not compose, and the one that
   loses is a movement that silently stops. */
.js .ad--fx-tilt { opacity: 1; --ad-y: 0px; perspective: 900px; }
.js .ad--fx-tilt .ad__box {
  transform: rotateX(var(--ad-tilt, 7deg));
  transform-origin: center bottom;
  opacity: var(--ad-tilt-o, 0);
  transition: transform .75s var(--ease), opacity .5s var(--ease);
}
.js .ad--fx-tilt.is-in .ad__box { --ad-tilt: 0deg; --ad-tilt-o: 1; }

/* Depth. The advert holds still and its photograph shifts behind it, which
   reads as depth rather than as something moving. The picture is held 12%
   oversized so a 14px shift can never expose an edge, and the frame clips it. */
.ad--fx-depth .ad__media { overflow: hidden; }
.ad--fx-depth .ad__media img {
  transform: translate3d(0, var(--ad-depth, 0px), 0) scale(1.12);
}

/* Pin. The advert stops in the middle of the screen and holds while the page
   scrolls past the room below it.

   It never covers anything: the space it holds in is space the slot itself
   reserved, so the page is exactly as long as it looks. That reserved room is
   also why this is wrong in a sidebar or a grid cell — there the space is not
   the advert's to take — and the rules underneath switch it off in both. */
.ad--fx-pin { padding-block-end: 44vh; }
.ad--fx-pin .ad__box { position: sticky; inset-block-start: 22vh; }

.ad--rail.ad--fx-pin,
.ad--native.ad--fx-pin,
.ad--strip.ad--fx-pin,
.ad--anchor.ad--fx-pin { padding-block-end: 0; }
.ad--rail.ad--fx-pin .ad__box,
.ad--native.ad--fx-pin .ad__box,
.ad--strip.ad--fx-pin .ad__box,
.ad--anchor.ad--fx-pin .ad__box { position: static; }

/* A short screen has no room to give away. Half a screen of hold on a phone in
   landscape is most of the page, so it simply does not hold there. */
@media (max-height: 560px) {
  .ad--fx-pin { padding-block-end: 0; }
  .ad--fx-pin .ad__box { position: static; }
}

/* Waiting for the reader to stop moving. The advert is held at its starting
   state — whatever that state is for the effect chosen — and main.js adds
   is-in once the page has come to rest. Nothing here is a second starting
   state; it is the same one, held for longer. */
.js .ad[data-ad-settle]:not(.is-in) { transition-delay: 0s; }


/* ---- less movement ------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  /* The entrance becomes an appearance. The starting state is cleared rather
     than the finish, so nothing is left parked below where it belongs.

     --ad-drift is zeroed here as well as being left unwritten by main.js,
     which does not start the drift job at all under reduced motion. Two
     answers to the same question on purpose: the movement this rule is
     undoing is one that follows the reader's own scrolling, and somebody who
     has asked their phone for less of that should not be relying on a script
     having read the setting correctly. */
  .js .ad { opacity: 1; --ad-y: 0px; --ad-drift: 0px; transition: none; }

  /* Every arrival becomes an arrival that has already happened. Each one
     clears its own starting state rather than its finishing one, so nothing is
     left part-drawn: the curtain opens rather than staying shut, the tilt
     stands up rather than lying back, and the picture sits where it belongs. */
  .js .ad--fx-curtain { clip-path: none; transition: none; }
  .js .is-rtl .ad--fx-curtain { clip-path: none; }
  .js .ad--fx-tilt .ad__box { --ad-tilt: 0deg; --ad-tilt-o: 1; transition: none; }
  .ad--fx-depth .ad__media img { --ad-depth: 0px; }

  /* The pin is left alone on purpose. Sticky positioning is layout rather than
     animation - the sidebar advert has always used it, for everybody - and
     switching it off here would leave the room it reserved sitting empty. */
  .ad--anchor { transition: none; }
  .ad__item, .ad__box--rotating .ad__item { transition: none; }
  .ad--banner a.ad__item:hover, .ad--rect a.ad__item:hover { transform: none; }

  /* Named with the same weight as the rule it is undoing. `.ad--strip
     .ad__item` is two classes and would otherwise outrank the bare
     `.ad__item` above it, leaving the one element on the page still
     animating for somebody who asked their phone for less of it. */
  .ad--strip .ad__item { transition: none; }
  .ad--strip a.ad__item:hover { transform: none; }
}

/* ---- printing ------------------------------------------------------------ */

@media print {
  /* A printed listing is something somebody carries to a viewing. */
  .ad { display: none !important; }
}
