/* MONTROYAL — Holiday Homes & Interiors (demo). Warm editorial hospitality. */
:root{
  /* Palette taken from the MONTROYAL logo: #681009 maroon plate,
     off-white -> silver lettering. Neutrals warmed to sit with the maroon
     (the previous set was keyed to a green-black). */
  --bg:#FBF8F2; --surface:#FFFFFF; --sand:#F1E8DC; --sand-2:#E5D8C9;
  --ink:#1C1411; --muted:#6F635B; --line:#E8DCCD;
  --brand:#681009; --brand-d:#4A0B06; --brass:#8A827B; --brass-d:#6E6660;
  --danger:#B23B2E;
  /* 1320, not 1600. At 1600 the content ran almost edge to edge on a large
     monitor, which reads as a web app rather than a considered brand page, and
     pushed line lengths past comfortable reading. Narrower leaves visible margin
     on both sides and lets the photography carry the width instead.
     Two comments elsewhere in this file still reason about the old 1600 —
     they describe why those rules exist, not a value to restore. */
  --wrap:1320px; --r:16px; --r-s:11px;
  --sh:0 1px 2px rgba(28,20,17,.05),0 12px 34px -18px rgba(28,20,17,.28);
  --sh-lg:0 30px 70px -32px rgba(104,16,9,.38);
  /* Arabic faces sit AFTER the Latin ones: neither Fraunces nor Inter covers
     Arabic, so the browser falls back per-glyph. Latin stays Fraunces/Inter in
     every language, Arabic picks up Naskh/Plex, and Google's unicode-range
     subsetting means EN/RU visitors never download the Arabic files. */
  /* Futura. "Futura" and "Futura PT" are listed first so anyone who has the real
     typeface installed (most Macs ship Futura) gets it; everyone else gets Jost,
     which is the geometric Futura companion on Google Fonts — same circular bowls,
     high ascenders and single-storey a. Jost is used rather than local Futura alone
     because macOS's Futura has no Light weight, and because Futura is a licensed
     face we cannot serve as a webfont without buying a licence.
     Arabic follows: neither Futura nor Jost covers Arabic, so those glyphs fall
     through to Naskh/Plex per-glyph, exactly as before. */
  --f-disp:"Futura","Futura PT","Jost","Noto Naskh Arabic","Trebuchet MS",sans-serif;
  --f-body:"Futura","Futura PT","Jost","IBM Plex Sans Arabic",system-ui,-apple-system,"Segoe UI",sans-serif;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--bg);color:var(--ink);
  /* Futura Light for body and subtext, per the brand direction. 300 is genuinely
     light, so line-height is a touch more generous than it was — thin geometric
     letterforms need the extra air to stay readable at 16px. */
  font-family:var(--f-body);font-weight:300;font-size:16px;line-height:1.7;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;overflow-wrap:break-word;
}
h1,h2,h3,h4,p,a,span,li,label,button{overflow-wrap:break-word}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
/* Futura Bold for every heading. Letter-spacing eased from -.015em to -.005em:
   Fraunces was a serif that took tight tracking well, but geometric capitals set
   too tight start colliding — Futura is drawn wide and wants the room. */
h1,h2,h3,h4{font-family:var(--f-disp);font-weight:700;line-height:1.08;letter-spacing:-.005em;margin:0}
.wrap{max-width:var(--wrap);margin:0 auto;padding:0 22px}
.eyebrow{font-family:var(--f-body);font-weight:600;font-size:.72rem;letter-spacing:.22em;text-transform:uppercase;color:var(--brand)}
.eyebrow.brass{color:var(--brass-d)}
.lede{font-size:clamp(1.02rem,1.4vw,1.18rem);color:var(--muted);max-width:60ch}
.serif-i{font-style:italic;font-variation-settings:"opsz" 32}

/* buttons */
.btn{display:inline-flex;align-items:center;gap:.55rem;min-height:48px;padding:0 1.35rem;border-radius:999px;
  font-weight:600;font-size:.95rem;cursor:pointer;border:1px solid transparent;transition:transform .15s ease,background .2s,box-shadow .2s,color .2s;white-space:nowrap}
.btn:active{transform:translateY(1px)}
.btn-primary{background:var(--brand);color:#fff}
.btn-primary:hover{background:var(--brand-d)}
.btn-ghost{background:transparent;color:var(--ink);border-color:var(--line)}
.btn-ghost:hover{border-color:var(--ink)}
.btn-brass{background:var(--brand);color:#fff}
/* sits on the dark maroon bands — darkening on hover made it sink into the
   background, so the colour holds and the lift + sweep carry the hover. */
.btn-brass:hover{background:var(--brand);color:#fff;box-shadow:0 12px 26px -12px rgba(0,0,0,.55)}
.btn-wa{background:#25D366;color:#fff}
.btn-wa:hover{background:#1EBE5D}
.btn-block{width:100%;justify-content:center}

/* Contact page, phones only: the WhatsApp and email buttons share one row.
   They are .btn-block inside a grid, so the columns do the work — but the
   defaults have to come down with them: "info@montroyal.ae" is 17 characters
   and .btn is white-space:nowrap, so at full size it would overflow a half
   width column. min-width:0 lets the grid items actually shrink, and 44px
   keeps them at the minimum comfortable tap size. */
/* Unconditional, not inside a max-width:560px query — the container is capped
   at 420px on every screen, so the two buttons share a row at all widths. The
   old breakpoint meant anything wider than a small phone still stacked them.
   minmax(0,1fr), not 1fr: a plain 1fr has an automatic minimum of the content
   size, so a nowrap label pushes the column wider and breaks the row. */
.contact-actions{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px}
.contact-actions .btn{min-width:0;min-height:46px;padding:0 .6rem;
  font-size:clamp(.78rem,2.5vw,.9rem);gap:.35rem}

/* Address and opening hours: was an unstyled paragraph pressed against the
   buttons above it. */
.contact-meta{margin-top:20px;color:var(--muted);font-size:.92rem;line-height:1.9}
.contact-meta b{display:block;color:var(--ink);font-weight:600;font-size:.72rem;
  letter-spacing:.18em;text-transform:uppercase;margin-bottom:.3rem}

/* hover motion. The .btn transition already lists transform/box-shadow but
   nothing ever moved on hover — only :active. Lift + a light sweep across the
   filled buttons; ghost buttons get a tint instead (a white sheen is invisible
   on cream). All of it is neutralised by the prefers-reduced-motion block at
   the end of this file. */
.btn{position:relative;overflow:hidden}
.btn:hover{transform:translateY(-2px);box-shadow:0 12px 24px -12px rgba(104,16,9,.5)}
.btn:active{transform:translateY(0);box-shadow:none}
.btn:focus-visible{transform:translateY(-2px)}

.btn-primary::after,.btn-brass::after,.btn-wa::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(105deg,transparent 30%,rgba(255,255,255,.30) 48%,transparent 66%);
  transform:translateX(-130%);transition:transform .6s cubic-bezier(.22,.61,.36,1)}
.btn-primary:hover::after,.btn-brass:hover::after,.btn-wa:hover::after{transform:translateX(130%)}

.btn-ghost:hover{border-color:var(--ink);background:rgba(104,16,9,.05)}
.btn-wa:hover{box-shadow:0 12px 24px -12px rgba(37,211,102,.6)}

/* trailing arrow slides with the lift */
.btn svg:last-child{transition:transform .25s ease}
.btn:hover svg:last-child{transform:translateX(3px)}

/* round WhatsApp button on each listing card */
.card-fav{transition:transform .2s cubic-bezier(.34,1.56,.64,1),background .2s,color .2s,box-shadow .2s}
.card-fav:hover{transform:scale(1.09)}
.card-fav:active{transform:scale(.94)}
@keyframes favpop{0%{transform:scale(1)}45%{transform:scale(1.28)}100%{transform:scale(1)}}
.card-fav.pop{animation:favpop .34s cubic-bezier(.34,1.56,.64,1)}

/* header */
.hdr{position:sticky;top:0;z-index:60;background:rgba(251,248,242,.82);backdrop-filter:saturate(1.3) blur(12px);border-bottom:1px solid var(--line)}
.hdr-in{display:flex;align-items:center;justify-content:space-between;height:70px}
.brand{display:flex;align-items:baseline;gap:.5rem;font-family:var(--f-disp);font-size:1.5rem;font-weight:600;letter-spacing:.02em}
.brand{flex:0 0 auto}
.brand-logo{height:16px;width:auto;display:block;flex:none}
.brand-logo-foot{height:26px}
.foot-brand{display:inline-flex;transition:opacity .2s}
.foot-brand:hover{opacity:.8}
.foot-brand:focus-visible{outline:2px solid #fff;outline-offset:4px;border-radius:4px}
@media(min-width:420px){.brand-logo{height:18px}}
@media(min-width:900px){.brand-logo{height:20px}}
@media(min-width:1200px){.brand-logo{height:22px}.brand-logo-foot{height:28px}}
.brand small{font-family:var(--f-body);font-size:.6rem;letter-spacing:.24em;text-transform:uppercase;color:var(--muted);font-weight:600}
/* Size and spacing scale with the viewport rather than being fixed. Six items
   plus the logo, language switcher and CTA have to fit a 1080px header — that
   is where the nav first appears — so the floor of each clamp is what keeps the
   row from wrapping there, while wide screens get the fuller spacing. */
.nav{display:none;align-items:center;gap:clamp(1.15rem,1.7vw,2.1rem)}
.nav a{font-size:clamp(.95rem,1.05vw,1.06rem);font-weight:500;color:var(--ink);opacity:.82;padding:.4rem 0;position:relative;white-space:nowrap}
.nav a:hover,.nav a.on{opacity:1}
.nav a.on::after{content:"";position:absolute;left:0;right:0;bottom:-2px;height:2px;background:var(--brand);border-radius:2px}
.hdr .cta{display:none}
.hdr-r{display:flex;align-items:center;gap:10px}
.langtoggle{min-width:46px;min-height:40px;padding:0 13px;border:1px solid var(--line);border-radius:999px;background:transparent;color:var(--ink);font-weight:700;font-size:.82rem;letter-spacing:.05em;cursor:pointer;transition:border-color .15s,background .15s}
.langtoggle:hover{border-color:var(--ink)}
.langseg{display:inline-flex;border:1px solid var(--line);border-radius:999px;overflow:hidden;direction:ltr;background:transparent}
.langseg button{min-width:32px;min-height:40px;padding:0 9px;border:0;border-inline-start:1px solid var(--line);background:transparent;color:var(--muted);font-weight:700;font-size:.78rem;letter-spacing:.03em;cursor:pointer;transition:background .15s,color .15s}
.langseg button:first-child{border-inline-start:0}
.langseg button.on{background:var(--ink);color:#fff}
.langseg button:not(.on):hover{color:var(--ink)}
/* 3 language pills + burger overflow a 360px header — tighten them below the nav breakpoint */
@media(max-width:899px){.langseg button{min-width:26px;padding:0 6px;font-size:.72rem}.hdr-r{gap:6px}}
.burger{display:inline-flex;flex-direction:column;gap:5px;background:none;border:0;padding:12px;cursor:pointer}
.burger span{width:24px;height:2px;background:var(--ink);border-radius:2px;transition:.25s}
.burger.x span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.burger.x span:nth-child(2){opacity:0}
.burger.x span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
/* mobile drawer */
.drawer{position:fixed;inset:70px 0 0;background:var(--bg);z-index:55;transform:translateY(-6%);opacity:0;pointer-events:none;transition:.28s ease;padding:18px 22px calc(28px + env(safe-area-inset-bottom));display:flex;flex-direction:column;gap:.2rem}
.drawer.open{transform:none;opacity:1;pointer-events:auto}
.drawer a{padding:15px 4px;font-size:1.3rem;font-family:var(--f-disp);font-weight:500;border-bottom:1px solid var(--line)}
.drawer .btn{margin-top:18px}

/* hero */
.hero{position:relative;min-height:calc(100svh - 70px);display:flex;align-items:flex-end;color:#fff;overflow:hidden}
.hero::before{content:"";position:absolute;inset:0;background:url(../img/montroyal_rental_marina.jpg) center/cover;transform:scale(1.04)}
.hero::after{content:"";position:absolute;inset:0;z-index:1;background:linear-gradient(180deg,rgba(10,30,27,.34) 0%,rgba(10,30,27,.2) 40%,rgba(8,26,23,.84) 100%)}
.hero-in{position:relative;z-index:2;width:100%;padding-bottom:clamp(28px,5vw,60px)}
/* Eased down from clamp(2.6rem,8.5vw,5.6rem). The ceiling drops most: at 5.6rem
   the headline dominated a 1320px page after the wrap narrowed. */
/* Two steps down from clamp(2.4rem,7.4vw,4.6rem): 73.6px was sized for a
   video background where the type had to hold its own against motion. Over a
   still photograph it can sit back and let the room carry the frame. */
.hero h1{font-size:clamp(1.8rem,5.6vw,3.4rem);font-weight:540;color:#fff;max-width:16ch}
.hero .lede{color:rgba(255,255,255,.9);margin-top:1rem}
.hero .eyebrow{color:#DFD6CB}
/* The video starts invisible and is revealed only once it is actually playing.
   Doing it this way round means a paused video — and the browser's play-button
   overlay — can never be on screen: the .hero::before still image simply stays.
   Opacity rather than display:none, because a display:none video is not decoded
   in some browsers, so it would never reach "playing" and never appear at all. */
.hero-video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0}
/* Visible by default so that if the script never runs the hero still plays via
   the autoplay attribute. Only once JS is confirmed (html.js, set in the head)
   do we take over and hold it back until it has frames to show. */
html.js .hero-video{opacity:0;transition:opacity .8s ease}
html.js .hero-video.is-playing{opacity:1}
/* Safari/iOS draw a start-playback button over any video that is not running,
   independently of the controls attribute. This is the element itself — with
   the JS above it should never be reachable, but suppressing it directly means
   the button cannot appear even for the instant before the script runs. */
.hero-video::-webkit-media-controls,
.hero-video::-webkit-media-controls-panel,
.hero-video::-webkit-media-controls-play-button,
.hero-video::-webkit-media-controls-start-playback-button{
  display:none!important;-webkit-appearance:none;appearance:none;opacity:0!important}
.hero-video{pointer-events:none}
/* the hero still drifts as you scroll; --py is set from JS and capped there */
.hero{--py:0px}
.hero::before{transform:scale(1.06) translate3d(-1.5%,var(--py,0px),0);
  animation:heroDrift 20s ease-in-out infinite;will-change:transform}
/* A slow, continuous zoom on the hero still. This is what guarantees the hero
   is always moving: if the browser refuses to autoplay the video — a per-site
   Auto-Play setting, Low Power Mode — the video stays hidden (so no play button
   can ever be drawn) and this carries the motion instead. When the video does
   play it fades in over the top and both are in motion.
   var(--py) is re-read every frame, so the scroll parallax still applies. */
/* 20s and a 14% zoom with a slow pan — the previous 34s / 7% version was
   deployed and correct but too subtle to read as movement, which is why the
   hero looked frozen until the video was clicked into life. The pan stays well
   inside the overscan the scale provides, so no edge is ever exposed. */
@keyframes heroDrift{
  0%   {transform:scale(1.06) translate3d(-1.5%,var(--py,0px),0)}
  50%  {transform:scale(1.20) translate3d(1.5%,var(--py,0px),0)}
  100% {transform:scale(1.06) translate3d(-1.5%,var(--py,0px),0)}
}
@media(prefers-reduced-motion:reduce){.hero-video{display:none}}

/* three paths */
.paths{display:grid;gap:14px;grid-template-columns:1fr;margin-top:26px}
/* taller cards: at the 1600px wrap a 190px card cropped to ~2.6:1 and gutted the photos */
.path{position:relative;border-radius:var(--r);overflow:hidden;min-height:300px;display:flex;align-items:flex-end;padding:24px;color:#fff;box-shadow:var(--sh);transition:transform .35s ease,box-shadow .35s ease}
@media(min-width:760px){.path{min-height:360px}}
/* two stops: a soft top veil plus a deep, taller foot so the copy is legible on ANY photo
   the client swaps in later — the old scrim only covered the bottom sliver */
.path::after{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(180deg,rgba(6,20,18,.30) 0%,rgba(6,20,18,.05) 30%,rgba(6,20,18,.62) 62%,rgba(4,14,12,.95) 100%)}
.path img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;transition:transform .7s cubic-bezier(.22,.61,.36,1)}
.path:hover{transform:translateY(-4px);box-shadow:0 26px 50px -26px rgba(4,14,12,.6)}
.path:hover img{transform:scale(1.07)}
.path .pc{position:relative;z-index:2;text-shadow:0 1px 14px rgba(0,0,0,.5)}
.path .pnum{display:block;font-family:var(--f-body);font-size:.7rem;font-weight:700;letter-spacing:.22em;
  color:rgba(255,255,255,.92);margin-bottom:.55rem;font-size:.74rem}
.path h3{color:#fff;font-size:1.55rem;line-height:1.2}
.path p{margin:.4rem 0 .9rem;font-size:.92rem;color:rgba(255,255,255,.88);max-width:34ch}
/* reads as a control, not a sentence: underline grows out from the left on hover */
.path .lnk{font-weight:600;font-size:.9rem;color:#fff;display:inline-flex;gap:.45rem;align-items:center;
  position:relative;padding-bottom:5px}
.path .lnk::after{content:"";position:absolute;left:0;bottom:0;height:1.5px;width:100%;background:rgba(255,255,255,.42);
  transform:scaleX(1);transform-origin:left;transition:transform .35s ease,background .35s ease}
.path:hover .lnk::after{background:#fff}
.path:focus-visible{outline:2px solid var(--brand);outline-offset:3px}

/* sections */
section{padding:clamp(56px,8vw,104px) 0}
.sec-head{max-width:64ch}
/* Base size for any h2 that is not inside a component with its own. Added
   14 Aug: six headings carried inline font-sizes purely because nothing else
   sized them, which is how a stylesheet quietly stops being the source of truth.
   The component rules below (.band, .quotecard, .feature, .philosophy, .why)
   are deliberate and still win on specificity. */
h2{font-size:clamp(1.8rem,4vw,2.7rem)}
.sec-head h2{font-size:clamp(2rem,4.6vw,3.1rem);margin:.5rem 0 .6rem}
.grid{display:grid;gap:18px}
@media(min-width:640px){.g2{grid-template-columns:1fr 1fr}.g3{grid-template-columns:1fr 1fr}}
@media(min-width:980px){.g3{grid-template-columns:repeat(3,1fr)}.g4{grid-template-columns:repeat(4,1fr)}}

/* apartment card */
.card{position:relative;background:var(--surface);border:1px solid var(--line);border-radius:var(--r);overflow:hidden;box-shadow:var(--sh);display:flex;flex-direction:column;transition:transform .2s,box-shadow .2s}
.card:hover{transform:translateY(-4px);box-shadow:var(--sh-lg)}
.card-body{display:flex;flex-direction:column;flex:1;color:inherit}
.card-fav{position:absolute;top:11px;right:11px;z-index:4;width:42px;height:42px;border-radius:50%;
  background:rgba(255,255,255,.92);color:var(--brand);border:0;cursor:pointer;padding:0;
  display:grid;place-items:center;backdrop-filter:blur(6px);
  box-shadow:0 4px 14px -4px rgba(0,0,0,.28),0 1px 3px rgba(0,0,0,.16)}
.card-fav svg{width:21px;height:21px;fill:none;transition:fill .18s ease}
.card-fav:hover{background:#fff}
.card-fav.on{background:var(--brand);color:#fff}
.card-fav.on svg{fill:currentColor}
.card-fav:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.card .ph{position:relative;aspect-ratio:4/3;background:var(--sand)}
.card .ph img{width:100%;height:100%;object-fit:cover}
/* ── Quotation card ───────────────────────────────────────────────────────
   Was a plain white box on a cream page — correct but colourless. A brand bar
   across the top and a warm fade behind the heading give it some identity
   without tinting the fields themselves, which have to stay white to read as
   inputs. */
.quotecard{position:relative;max-width:760px;margin:0 auto;overflow:hidden;
  border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--sh-lg);
  padding:clamp(28px,4vw,44px);
  background:linear-gradient(180deg,#F6ECDE 0%,#FCF7F0 34%,var(--surface) 62%)}
.quotecard::before{content:"";position:absolute;left:0;right:0;top:0;height:5px;
  background:linear-gradient(90deg,var(--brand) 0%,#9E3318 55%,#C0863A 100%)}
.quotecard .eyebrow{color:var(--brand)}
.quotecard h2{font-size:clamp(1.7rem,3.4vw,2.4rem);margin:.4rem 0 .3rem}
.quotecard .note{margin-bottom:18px}

/* Slow attention pulse — a ring that expands out of the button roughly every
   five seconds. Long gap on purpose: fast enough to catch the eye, rare enough
   not to nag. Pauses on hover, and the reduced-motion block stops it entirely. */
@keyframes btnRing{
  0%, 68%, 100% {box-shadow:0 0 0 0 rgba(104,16,9,0)}
  72%           {box-shadow:0 0 0 0 rgba(104,16,9,.38)}
  90%           {box-shadow:0 0 0 16px rgba(104,16,9,0)}
}
.btn-ring{animation:btnRing 5s ease-out infinite}
.btn-ring:hover,.btn-ring:focus-visible{animation-play-state:paused}

/* ── Project gallery tile ─────────────────────────────────────────────────
   One holder, several photographs cycling inside it, no thumbnail strip — the
   images fade between themselves on the shared .shots timer. A burgundy scrim
   rises from the bottom so the project name sits on the photo and stays legible
   whatever the image underneath is doing. */
.shotcard{position:relative;margin:0;border-radius:var(--r);overflow:hidden;
  aspect-ratio:4/3;box-shadow:var(--sh);transition:transform .35s ease,box-shadow .35s ease}
.shotcard:hover{transform:translateY(-4px);box-shadow:var(--sh-lg)}
.shotcard .shots{position:absolute;inset:0}
.shotcard .shots img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .9s ease}
.shotcard .shots img.on{opacity:1}
/* Ken Burns drift on whichever photo is showing. The tile keeps moving between
   changes instead of sitting still for four seconds, and because the drift runs
   through the crossfade the swap reads as one continuous motion rather than a
   cut. Starts at 1.02 rather than 1 so no edge gap can appear mid-animation.
   Skipped entirely for visitors who have asked for reduced motion. */
@media (prefers-reduced-motion:no-preference){
  .shotcard .shots img.on{animation:shotDrift 9s ease-out both}
}
@keyframes shotDrift{from{transform:scale(1.02)}to{transform:scale(1.09)}}
/* A tile holding a video instead of photographs. Same frame, same scrim, same
   hover lift — only the content differs, so a mixed grid still reads as one set.

   `contain`, not `cover`. A photograph cropped to 4:3 is still the photograph,
   but a video is composed — crop it and you lose the edges of the shot. The
   whole frame is shown and any leftover space is filled with the deep burgundy
   below, which reads as a deliberate mat rather than a mistake.

   Tiles whose video is close to 4:3 will show no border at all; a 16:9 clip
   shows a band top and bottom. */
.shotcard-v .shotvid{position:absolute;inset:0;width:100%;height:100%;
  object-fit:contain;display:block;background:#2A0703}
/* The burgundy scrim exists only to keep the project name readable, so it starts
   low (62% down) rather than washing over the middle of the photograph. Below
   that it ramps quickly, which gives the text its contrast in the bottom eighth
   while leaving most of the interior clear. */
.shotcard::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,rgba(74,11,6,0) 54%,rgba(74,11,6,.3) 74%,rgba(74,11,6,.72) 88%,rgba(74,11,6,.9) 100%);
  transition:opacity .35s ease}
.shotcard:hover::after{opacity:.92}
.shotcap{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:16px 18px 18px;color:#fff}
.shotname{font-family:var(--f-disp);font-weight:700;font-size:clamp(.98rem,1.5vw,1.15rem);
  letter-spacing:-.01em;text-shadow:0 1px 12px rgba(38,8,4,.45);
  /* A long project name wrapped to a third line and pushed itself off the
     bottom of the tile. Two lines, then an ellipsis — the tile is a label, not
     a place to read a paragraph. */
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;line-height:1.25}

/* ── Stepping through a tile's photographs ────────────────────────────────
   The photographs used to change by themselves as the page scrolled past. The
   client asked for them to be stepped through deliberately instead, with the
   controls on show — a control a visitor cannot see is a control they will not
   use, so these do not appear only on hover.

   Sat at z-index 3, above the burgundy scrim (1) and the caption (2), because
   the scrim sets `pointer-events:none` and would otherwise swallow the clicks.
   40px targets clear the 44px-with-padding minimum for a thumb. */
.shotnav{position:absolute;top:50%;z-index:3;transform:translateY(-50%);
  width:40px;height:40px;display:grid;place-items:center;padding:0;border:0;
  cursor:pointer;border-radius:50%;color:#fff;background:rgba(38,8,4,.44);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  box-shadow:0 6px 18px -8px rgba(38,8,4,.6);
  transition:background .25s ease,transform .25s ease}
.shotnav:hover{background:var(--brand);transform:translateY(-50%) scale(1.08)}
.shotnav:active{transform:translateY(-50%) scale(.96)}
.shotnav:focus-visible{outline:2px solid var(--brass);outline-offset:2px}
.shotnav.prev{left:10px}
.shotnav.next{right:10px}
.shotnav svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:2.4;
  stroke-linecap:round;stroke-linejoin:round}
/* Nudged in on a phone, where the tile is narrower and the arrows would
   otherwise sit over the middle of the photograph. */
@media(max-width:560px){
  .shotnav{width:36px;height:36px}
  .shotnav.prev{left:7px}.shotnav.next{right:7px}
}

/* Which photograph of how many. Sits opposite the project name in the caption,
   so the tile always says where the visitor is in the set. */
.shotcap{display:flex;align-items:flex-end;justify-content:space-between;gap:14px}
.shotcount{flex:none;font-size:.78rem;font-weight:400;letter-spacing:.05em;
  color:rgba(255,255,255,.84);white-space:nowrap;font-variant-numeric:tabular-nums;
  text-shadow:0 1px 10px rgba(38,8,4,.5)}

/* Position markers, above the caption. Only drawn for short sets — a row of
   twelve dots reads as noise, and the counter already carries the information. */
.shotdots{position:absolute;left:52px;right:52px;bottom:54px;
  z-index:2;display:flex;gap:6px;justify-content:center;pointer-events:none}
.shotdot{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.45);
  box-shadow:0 1px 4px rgba(38,8,4,.4);transition:background .25s ease,transform .25s ease}
.shotdot[aria-current="true"]{background:var(--brass);transform:scale(1.4)}

/* Manual stepping means a photograph can sit still for as long as the visitor
   leaves it, so the slow Ken Burns push would run to its end and stop. Held at
   the start instead: the drift now belongs to the change itself. */
.shotcard[data-manual] .shots img.on{animation-duration:5.5s}

.card .shots{position:absolute;inset:0}
.card .shots img{position:absolute;inset:0;opacity:0;transition:opacity .9s ease}
.card .shots img.on{opacity:1}
.card .dots{position:absolute;left:0;right:0;bottom:10px;z-index:3;display:flex;gap:5px;justify-content:center;pointer-events:none}
.card .dots i{width:5px;height:5px;border-radius:50%;background:rgba(255,255,255,.55);box-shadow:0 1px 2px rgba(0,0,0,.35);transition:background .3s,width .3s}
.card .dots i.on{background:#fff;width:14px;border-radius:3px}
.card:hover .shots img.on{transform:scale(1.02);transition:opacity .9s ease,transform 6s ease}
.badge{position:absolute;top:12px;left:12px;z-index:2;background:rgba(38,92,64,.94);color:#fff;font-size:.68rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;padding:.34rem .6rem;border-radius:999px}
.badge.booked{background:rgba(110,102,96,.94)}
.badge.soon{background:rgba(104,16,9,.94);color:#fff}
.card .bd{padding:16px 17px 18px;display:flex;flex-direction:column;gap:.35rem;flex:1}
.card .loc{font-size:.78rem;color:var(--brand);font-weight:600;letter-spacing:.04em;text-transform:uppercase}
/* Reduced twice, and for the same reason both times: 1.24rem -> 1.08rem on
   13 Aug, then -> 0.97rem. The listing names are raw marketing titles
   ("Luxurious Studio | Amazing Canal View | Balcony") and at the larger sizes
   they wrapped to two and three lines, pushing the price and the meta row out
   of alignment across the grid.

   Now 0.93rem, which is genuinely the floor: the description under it is
   0.88rem and the meta row 0.86rem, so the name is only a hair larger than the
   text it has to head. What keeps the hierarchy readable at this size is weight
   and colour, not scale - the name is semibold in full ink, everything under it
   is regular and muted. Going smaller inverts that and the card loses its title.
   If the titles are ever rewritten to the shorter house style used by the
   drafted listings ("1 Bedroom - Terraces Marasi Drive"), this can go back up. */
.card h3{font-size:.93rem;line-height:1.34}
.card .meta{display:flex;flex-wrap:wrap;gap:.5rem .9rem;color:var(--muted);font-size:.86rem;margin-top:.15rem}
.card .meta span{display:inline-flex;align-items:center;gap:.35rem}
.card .price{margin-top:auto;padding-top:12px;display:flex;align-items:baseline;justify-content:space-between;border-top:1px solid var(--line)}
.card .price b{font-family:var(--f-disp);font-size:1.28rem;font-weight:600}
.card .price small{color:var(--muted);font-size:.8rem}

/* filters */
.filters{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--sh);padding:16px;position:static;margin-bottom:22px}
.filters-body{display:grid;gap:12px;grid-template-columns:1fr}
@media(min-width:760px){.filters-body{grid-template-columns:repeat(4,1fr) auto;align-items:end}}
/* the toggle exists on mobile only — on desktop the filters are always open */
.filters-toggle{display:none}
@media(max-width:759px){
  .filters-toggle{display:flex;width:100%;align-items:center;justify-content:space-between;gap:.6rem;
    background:none;border:0;padding:0;cursor:pointer;font:inherit;font-weight:600;color:var(--ink);min-height:32px}
  .filters-toggle svg{transition:transform .25s ease;color:var(--brand)}
  .filters-toggle:focus-visible{outline:2px solid var(--brand);outline-offset:3px;border-radius:6px}
  .filters-body{display:none}
  .filters.open .filters-body{display:grid;margin-top:14px}
  .filters.open .filters-toggle svg{transform:rotate(180deg)}
}
.field{display:flex;flex-direction:column;gap:.35rem}
.field label{font-size:.72rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.field select,.field input,.form input,.form select,.form textarea{
  width:100%;min-height:48px;padding:.6rem .8rem;border:1px solid var(--line);border-radius:var(--r-s);background:#fff;color:var(--ink);font:inherit}
.field select:focus,.form :focus-visible{outline:2px solid var(--brand);outline-offset:1px;border-color:var(--brand)}
.count{color:var(--muted);font-size:.9rem;margin:14px 0 2px}

/* single property */
/* gallery: one uniform stage + a thumbnail rail. The old mosaic gave each photo a
   different crop, so portrait shots came out letterboxed against landscape ones. */
.gal{display:grid;gap:10px;grid-template-columns:1fr}
@media(min-width:760px){.gal{grid-template-columns:1fr 96px;align-items:start}}
.gal-stage{position:relative;aspect-ratio:16/10;border-radius:12px;overflow:hidden;background:var(--sand)}
.gal-stage .gal-media{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .35s ease;border:0;display:block}
/* The video slide is contained rather than cropped — a composed shot loses its
   edges under object-fit:cover — and sits on burgundy where the shapes differ.
   pointer-events only while it is the active slide, or its controls would be
   clickable through the photograph on top of it. */
.gal-stage video.gal-media,.gal-stage iframe.gal-media{object-fit:contain;background:#2A0703;pointer-events:none}
.gal-stage .gal-media.on{pointer-events:auto}
/* play badge on the video's thumbnail — it reuses the first photo, so without
   this there is nothing to say which thumbnail opens the tour */
.gal-thumb-v{position:relative}
.gal-thumb-v .playbadge{position:absolute;inset:0;display:grid;place-items:center;
  background:rgba(74,11,6,.45);color:#fff;font-size:.8rem;border-radius:inherit;
  text-shadow:0 1px 3px rgba(0,0,0,.5)}
/* .gal-media, not img — the video slide has to be able to become visible too. */
.gal-stage .gal-media.on{opacity:1}
.gal-nav{position:absolute;top:50%;transform:translateY(-50%);z-index:3;width:40px;height:40px;border:0;border-radius:50%;
  background:rgba(255,255,255,.92);color:var(--ink);display:grid;place-items:center;cursor:pointer;padding:0;
  box-shadow:0 4px 14px -4px rgba(0,0,0,.35);transition:background .2s,transform .2s}
.gal-nav.prev{left:12px}.gal-nav.next{right:12px}
.gal-nav:hover{background:#fff;transform:translateY(-50%) scale(1.08)}
.gal-nav:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.gal-count{position:absolute;right:12px;bottom:12px;z-index:3;background:rgba(4,14,12,.62);color:#fff;
  font-size:.76rem;font-weight:600;padding:.28rem .6rem;border-radius:999px;backdrop-filter:blur(4px)}
/* every thumb identical: square, cropped, never stretched */
.gal-thumbs{display:flex;gap:8px;overflow-x:auto;padding-bottom:2px;scrollbar-width:thin}
@media(min-width:760px){.gal-thumbs{flex-direction:column;overflow-x:visible;overflow-y:auto;max-height:calc((100vw - 44px) * 0.625);padding-right:2px}}
.gal-thumb{flex:0 0 auto;width:88px;height:88px;padding:0;border:0;border-radius:9px;overflow:hidden;cursor:pointer;
  background:var(--sand);position:relative;opacity:.62;transition:opacity .2s,box-shadow .2s,transform .2s}
.gal-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.gal-thumb:hover{opacity:.9;transform:translateY(-1px)}
.gal-thumb.on{opacity:1;box-shadow:0 0 0 2px var(--brand)}
.gal-thumb:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.spec{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin:18px 0}
@media(min-width:640px){.spec{grid-template-columns:repeat(4,1fr)}}
.spec div{background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:14px}
.spec small{color:var(--muted);font-size:.74rem;text-transform:uppercase;letter-spacing:.08em}
.spec b{display:block;font-family:var(--f-disp);font-weight:700;font-size:1.3rem;margin-top:2px}
.amen{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.6rem}
.amen span{background:var(--sand);border-radius:999px;padding:.4rem .8rem;font-size:.85rem;color:var(--ink)}
.aside{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--sh);padding:20px;position:sticky;top:86px}
.mapbox{border:0;width:100%;height:260px;border-radius:12px;filter:saturate(1.05)}
/* Click-to-load placeholder — same footprint as the map it replaces, so the
   page does not jump when the visitor loads it. */
.mapask{width:100%;height:260px;border-radius:12px;border:1px dashed var(--sand-2);
  background:var(--sand);display:grid;place-items:center;padding:18px;text-align:center}
.mapask-in{max-width:46ch;display:flex;flex-direction:column;align-items:center;gap:.5rem}
.mapask b{font-family:var(--f-disp);font-weight:700;font-size:1.05rem;color:var(--ink)}
.mapask p{margin:0;font-size:.85rem;line-height:1.6;color:var(--muted)}
.mapask .maplink{font-size:.82rem;color:var(--brand);font-weight:600;text-decoration:underline;text-underline-offset:2px}

/* feature list */
.feat{display:flex;gap:.8rem;align-items:flex-start;padding:16px 0;border-bottom:1px solid var(--line);
  transition:border-color .3s ease}
/* Hover: the icon tile fills with brand maroon and lifts, and the rule beneath
   the row darkens — enough to show the row is a distinct service without
   turning nine of them into nine moving cards. */
.feat:hover{border-color:var(--sand-2)}
.feat .ic{transition:background .3s ease,color .3s ease,transform .3s cubic-bezier(.34,1.4,.64,1)}
.feat:hover .ic{background:var(--brand);color:#fff;transform:translateY(-3px)}
.feat h4{transition:color .3s ease}
.feat:hover h4{color:var(--brand)}
.feat .ic{flex:0 0 42px;height:42px;border-radius:11px;background:var(--sand);display:grid;place-items:center;color:var(--brand)}
.feat h4{font-size:1.08rem;font-family:var(--f-body);font-weight:650}
.feat p{margin:.15rem 0 0;color:var(--muted);font-size:.92rem}

/* before/after */
/* The walkthrough and the finished still sit in the same row as the
   before/after slider, so all three tiles share its 4:3 and line up exactly.
   The film is 16:9 inside a 4:3 tile: contain, never cover — cover would slice
   a quarter off each side of the footage. The letterbox is the brand near-black
   so it reads as intentional rather than as a gap. */
/* This section's lede is 117 characters and is meant to read as one line, so it
   escapes the 64ch/60ch measures that .sec-head and .lede normally impose.
   Scoped to #work — every other lede on the site keeps its reading measure. */
#work .sec-head{max-width:none}
#work .sec-head .lede{max-width:min(1050px,100%)}

.projvid{display:block;width:100%;aspect-ratio:4/3;object-fit:contain;background:#1C1411;
  border-radius:var(--r);box-shadow:var(--sh)}
.projstill{display:block;width:100%;height:auto;aspect-ratio:4/3;object-fit:cover;
  border-radius:var(--r);box-shadow:var(--sh)}

.ba{position:relative;border-radius:var(--r);overflow:hidden;aspect-ratio:4/3;user-select:none;touch-action:pan-y}
.ba img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.ba .after{clip-path:inset(0 0 0 50%)}
.ba .tag{position:absolute;bottom:12px;z-index:3;font-size:.7rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;background:rgba(23,32,30,.7);color:#fff;padding:.3rem .6rem;border-radius:6px}
.ba .tag.l{left:12px}.ba .tag.r{right:12px}
.ba .handle{position:absolute;top:0;bottom:0;left:50%;width:3px;background:#fff;z-index:4;transform:translateX(-50%)}
.ba .handle::after{content:"⇆";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:40px;height:40px;background:#fff;color:var(--brand);border-radius:50%;display:grid;place-items:center;font-size:1.1rem;box-shadow:var(--sh)}
.ba input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:ew-resize;z-index:5;margin:0}

/* forms */
.form{display:grid;gap:14px}
.form .row{display:grid;gap:14px}
@media(min-width:640px){.form .row2{grid-template-columns:1fr 1fr}}
.form label.fl{font-size:.8rem;font-weight:600;color:var(--ink);display:block;margin-bottom:.5rem}
.form label.fl .req{color:var(--danger)}
.form textarea{min-height:120px;resize:vertical}
.filebox{border:1.5px dashed var(--sand-2);border-radius:var(--r-s);padding:16px;text-align:center;color:var(--muted);font-size:.9rem;cursor:pointer}
/* the WhatsApp variant of the drop area — same shape, but it opens a chat */
.filebox-wa{display:block;text-decoration:none;transition:border-color .2s,background .2s}
.filebox-wa:hover{border-color:#25D366;background:rgba(37,211,102,.06)}
.filebox-wa .fbt{display:flex;flex-direction:column;gap:.2rem}
.filebox-wa b{color:var(--ink);font-size:.95rem}
.filebox-wa small{color:var(--muted);font-size:.82rem;line-height:1.5}
.note{font-size:.82rem;color:var(--muted)}
.ok{background:#EAF3EA;border:1px solid #BFDCC0;color:#1d5a2a;padding:14px 16px;border-radius:12px;display:none}
.ok.show{display:block}

/* panels / cta band */
.band{background:var(--brand);color:#fff;border-radius:var(--r);padding:clamp(28px,5vw,52px);position:relative;overflow:hidden}
.band h2{color:#fff;font-size:clamp(1.7rem,3.6vw,2.6rem)}

/* ── How it works: a connected sequence ──────────────────────────────────────
   Four numbered medallions joined by a brass thread, so the eye follows a path
   instead of reading four unrelated boxes. The thread is drawn per step rather
   than once across the row, which means it lands correctly whatever the column
   width and simply rotates to vertical when the steps stack. */

@media(min-width:820px){}






/* the thread — vertical while stacked, horizontal once side by side */

@media(min-width:820px){
  
}
/* the medallion lifts as its step reveals, so the sequence assembles on scroll */
.step.reveal 
.step.reveal:not(.in) 
@media(prefers-reduced-motion:reduce){.step.reveal:not(.in) }
.band p{color:rgba(255,255,255,.86);max-width:52ch}
.split{display:grid;gap:26px}
@media(min-width:900px){.split{grid-template-columns:1.1fr .9fr;align-items:center}.split.wide{grid-template-columns:1.4fr 1fr}}
/* height:auto is load-bearing: these images carry width/height attributes (for
   layout stability), which the browser treats as a definite height. With both
   dimensions definite, aspect-ratio is ignored and the box renders at the
   intrinsic height — portrait — with object-fit:cover cropping to fill it. */
.rounded{border-radius:var(--r);box-shadow:var(--sh);width:100%;height:auto;aspect-ratio:4/3;object-fit:cover}

/* faq */
.acc{border-bottom:1px solid var(--line)}
.acc button{width:100%;text-align:left;background:none;border:0;padding:18px 2px;font-size:1.08rem;font-family:var(--f-disp);font-weight:500;color:var(--ink);display:flex;justify-content:space-between;gap:1rem;cursor:pointer;align-items:center}
.acc .a{max-height:0;overflow:hidden;transition:max-height .3s ease;color:var(--muted)}
.acc .a p{margin:0 0 18px}
.acc.open .a{max-height:320px}
.acc .pl{transition:transform .3s;color:var(--brand)}
.acc.open .pl{transform:rotate(45deg)}

/* footer */
.foot{background:var(--ink);color:#CFC9BE;padding:56px 0 calc(30px + env(safe-area-inset-bottom))}
.foot a{color:#CFC9BE;opacity:.8}.foot a:hover{opacity:1;color:#fff}
/* "Cookie settings" is a button, not a link: it reopens the consent panel and
   goes nowhere, and an <a href="#"> would push a history entry the visitor then
   has to press Back through. This strips the button chrome so it sits in the
   legal row indistinguishably from its neighbours, while staying a real button
   for a keyboard and a screen reader. */
.foot .legal-links .linklike{
  background:none;border:0;padding:0;margin:0;font:inherit;color:#CFC9BE;
  opacity:.8;cursor:pointer;text-decoration:none;line-height:inherit}
.foot .legal-links .linklike:hover{opacity:1;color:#fff}
.foot .legal-links .linklike:focus-visible{outline:2px solid #fff;outline-offset:2px;border-radius:3px}
.foot .cols{display:grid;gap:28px;grid-template-columns:1fr}
@media(min-width:760px){.foot .cols{grid-template-columns:1.4fr 1fr 1fr 1fr}}
.foot .brand{color:#fff}.foot h5{color:#fff;font-family:var(--f-body);letter-spacing:.1em;text-transform:uppercase;font-size:.72rem;margin:0 0 .8rem}
.foot ul{list-style:none;margin:0;padding:0;display:grid;gap:.5rem;font-size:.92rem}
.foot .socials a{width:42px;height:42px;border-radius:50%;background:rgba(255,255,255,.08);display:grid;place-items:center;color:#fff;opacity:1;transition:background .15s,color .15s}
/* brand maroon on hover rather than plain white — the footer is near-black, so
   the maroon reads clearly and the icon stays white on top of it */
.foot .socials a:hover{background:var(--brand);color:#fff;transform:translateY(-2px)}
/* Placeholder social marks: same circle as the real links, but deliberately
   inert — no pointer cursor, no hover lift, and slightly dimmed, so they read as
   present-but-not-yet-live rather than as a link that fails to do anything. */
.foot .socials .soc-static{
  width:42px;height:42px;border-radius:50%;background:rgba(255,255,255,.05);
  display:grid;place-items:center;color:#CFC9BE;opacity:.55;cursor:default}
.foot .bottom{border-top:1px solid rgba(255,255,255,.12);margin-top:34px;padding-top:18px;font-size:.82rem;opacity:.7;display:flex;flex-wrap:wrap;gap:.6rem 1.4rem;justify-content:space-between}
/* Phones: the bottom bar is a space-between row built for desktop, and with six
   legal links it ran off the side — "Cookie settings" was cut in half. Stack the
   three parts instead, and reserve room at the foot of the page for the floating
   WhatsApp button (60px + its 18px offset), which was sitting on top of the
   credit line. */
@media(max-width:640px){
  .foot{padding-bottom:calc(96px + env(safe-area-inset-bottom))}
  .foot .bottom{flex-direction:column;align-items:flex-start;gap:.85rem;font-size:.78rem}
  .foot .legal-links{gap:.3rem .8rem;min-width:0}
  .foot .legal-links a{white-space:normal}
}
/* the whole bottom bar sits at .7 opacity, so the Velare link needs an underline
   to read as a link at all rather than as slightly paler text */
.foot .credit a{text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:1px}
.foot .credit a:hover{color:#fff;text-decoration-color:#fff}

/* floating whatsapp */
/* Page-transition veil. Sits above everything including the sticky header and
   the WhatsApp button, but starts fully transparent and pointer-events:none, so
   if the script that raises it never runs the page is entirely unaffected. */
#pageveil{position:fixed;inset:0;z-index:200;background:var(--bg);
  display:grid;place-items:center;opacity:0;pointer-events:none;
  transition:opacity .32s ease}
#pageveil.on{opacity:1;pointer-events:auto}
#pageveil img{width:min(240px,54vw);height:auto;animation:veilBreathe 1.6s ease-in-out infinite}
@keyframes veilBreathe{
  0%,100%{opacity:.5;transform:scale(.985)}
  50%    {opacity:1;transform:scale(1.015)}
}

.wa-float{position:fixed;right:18px;bottom:calc(18px + env(safe-area-inset-bottom));z-index:70;width:60px;height:60px;border-radius:50%;background:#25D366;color:#fff;display:grid;place-items:center;box-shadow:0 10px 26px -6px rgba(37,211,102,.6),0 4px 10px rgba(0,0,0,.2);transition:transform .18s ease,box-shadow .18s ease}
.wa-float svg{width:32px;height:32px}
.wa-float:hover{transform:translateY(-2px) scale(1.04);box-shadow:0 16px 34px -8px rgba(37,211,102,.72),0 6px 14px rgba(0,0,0,.24)}
.wa-float::after{content:"";position:absolute;inset:0;border-radius:50%;animation:waPulse 2.6s ease-out infinite;pointer-events:none}
@keyframes waPulse{0%{box-shadow:0 0 0 0 rgba(37,211,102,.5)}70%{box-shadow:0 0 0 15px rgba(37,211,102,0)}100%{box-shadow:0 0 0 0 rgba(37,211,102,0)}}
.demo-tag{position:fixed;left:12px;bottom:calc(12px + env(safe-area-inset-bottom));z-index:70;background:var(--ink);color:#fff;font-size:.68rem;letter-spacing:.06em;padding:.4rem .7rem;border-radius:999px;opacity:.85;pointer-events:none;transition:opacity .25s}
.demo-tag.hide{opacity:0}

/* cookie consent banner */
.cookie-bar{position:fixed;left:0;right:0;bottom:0;z-index:80;transform:translateY(115%);transition:transform .3s ease;background:var(--ink);color:#fff;padding:11px 18px calc(11px + env(safe-area-inset-bottom));display:flex;flex-wrap:wrap;align-items:center;gap:10px 18px;justify-content:center;box-shadow:0 -8px 30px -12px rgba(0,0,0,.5)}
.cookie-bar.show{transform:translateY(0)}
.cookie-bar p{margin:0;font-size:.9rem;max-width:60ch;color:#eee}
.cookie-bar a{color:#fff;text-decoration:underline}
.cookie-bar .ck-acts{display:flex;gap:10px;flex-wrap:wrap}
/* three actions + an expandable preferences panel, so the bar needs to stack */
.cookie-bar{flex-direction:column;align-items:stretch}
.cookie-bar .ck-main{display:flex;gap:16px;align-items:center;justify-content:space-between;flex-wrap:wrap}
/* THE BUG: this display:flex overrode the hidden attribute. The panel is built
   with `hidden` and was always meant to start collapsed, but an explicit display
   beats the browser's own [hidden]{display:none}, so every visitor met the fully
   expanded banner — a third of a desktop screen and over half of a phone. The
   guard below has to stay next to the rule that needs it. */
.cookie-bar .ck-prefs{margin-top:12px;padding-top:12px;border-top:1px solid rgba(255,255,255,.18);
  display:flex;flex-direction:column;gap:10px}
.cookie-bar .ck-prefs[hidden]{display:none}
.cookie-bar .ck-row{display:flex;gap:10px;align-items:flex-start;font-size:.86rem;color:#eee;line-height:1.55;max-width:78ch}
.cookie-bar .ck-row input{margin-top:.25rem;flex:0 0 auto;width:16px;height:16px;accent-color:#fff}
.cookie-bar .ck-row b{color:#fff;font-weight:600}
@media(max-width:640px){.cookie-bar .ck-acts .btn{flex:1 1 auto;justify-content:center}}

/* the notice under every enquiry form */
.form-privacy{font-size:.82rem;line-height:1.6;color:var(--muted);margin:.4rem 0 0}
.form-privacy a{color:var(--brand);font-weight:600;text-decoration:underline;text-underline-offset:2px}
/* Narrower buttons: the horizontal padding is what made them long, so that is
   what comes off. Height stays at 40px — below that they stop being comfortable
   touch targets on a phone, which is the screen this banner hurts most. */
.cookie-bar .btn-sm{min-height:40px;padding:.42rem .78rem;font-size:.83rem;white-space:nowrap}
.cookie-bar .btn-ghost{color:#fff;border-color:rgba(255,255,255,.45)}
.foot .legal-links a{color:#CFC9BE}
/* these are five separate pages — a bare flex gap made the row read as one
   run-on line, so each link gets a divider. The dot rides with the preceding
   link, so a wrapped line never starts with a stray separator. */
.foot .legal-links a:not(:last-child)::after{content:"·";margin-inline-start:.9rem;color:rgba(255,255,255,.34);pointer-events:none}
.foot .legal-links a{white-space:nowrap}

/* RTL (Arabic) */
html[dir=rtl] body{direction:rtl}
html[dir=rtl] .lede,html[dir=rtl] .wrap>p,html[dir=rtl] .fl,html[dir=rtl] label,html[dir=rtl] h1,html[dir=rtl] h2,html[dir=rtl] h3,html[dir=rtl] .sec-head,html[dir=rtl] .feat,html[dir=rtl] .acc{text-align:right}
html[dir=rtl] ul{padding-right:0}
html[dir=rtl] .foot ul{padding:0}
html[dir=rtl] .langtoggle,html[dir=rtl] .price,html[dir=rtl] .spec div{direction:ltr}
html[dir=rtl] .spec div{text-align:right}
html[dir=rtl] input,html[dir=rtl] select,html[dir=rtl] textarea{text-align:right}

@media(min-width:900px){
  .paths{grid-template-columns:repeat(3,1fr)}
}
@media(min-width:1080px){
  .nav{display:flex}.hdr .cta{display:inline-flex}.burger{display:none}
  .drawer{display:none}
}
@media(prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}.hero::before{transform:none}}
/* Scroll reveal. Expo-out easing (.16,1,.3,1) — fast at the start, settling
   slowly — which is what makes the movement read as considered rather than
   springy. The slight scale gives it depth without any blur: blur on
   full-width imagery is expensive to composite and janks on phones. */
.reveal{opacity:0;transform:translateY(24px) scale(.985);
  transition:opacity .85s cubic-bezier(.16,1,.3,1),transform .85s cubic-bezier(.16,1,.3,1);
  transition-delay:var(--rd,0ms)}
/* scrolling back up, content arrives from above instead of rising from below,
   so the page reads as moving with you rather than replaying one fixed cue */
.reveal.up{transform:translateY(-24px) scale(.985)}
.reveal.in{opacity:1;transform:none}

/* Scroll-linked drift, driven from initParallax(). The feature image is given
   an overscan so it can move vertically without exposing an edge of the panel. */
.feature img{top:-26px;bottom:auto;height:calc(100% + 52px);will-change:transform}
.eco-num{will-change:transform}
/* page-open: one gentle fade-up of the whole page body */
@keyframes pageIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
body.page-in > section,body.page-in > .wrap,body.page-in > #site-foot{animation:pageIn .5s cubic-bezier(.22,.61,.36,1) both}
@media(prefers-reduced-motion:reduce){body.page-in > section,body.page-in > .wrap,body.page-in > #site-foot{animation:none}}

/* ---------- long-form legal documents (terms, privacy, …) ---------- */
.legal{max-width:820px}
.legal .meta{display:flex;flex-wrap:wrap;gap:.5rem .9rem;align-items:center;margin:.7rem 0 0;font-size:.84rem;color:var(--muted)}
.legal .meta .dot{width:4px;height:4px;border-radius:50%;background:var(--sand-2)}
.legal .entity{margin:22px 0 0;padding:18px 20px;background:var(--sand);border:1px solid var(--line);border-radius:var(--r-s);font-size:.92rem;line-height:1.7}
.legal .entity strong{display:block;font-size:1rem;color:var(--ink);letter-spacing:.01em}
.legal .entity a{color:var(--brand);font-weight:600}
.legal .toc{margin:30px 0 0;padding:20px 22px;border:1px solid var(--line);border-radius:var(--r-s);background:var(--surface)}
.legal .toc h2{font-family:var(--f-body);font-size:.72rem;font-weight:700;letter-spacing:.2em;text-transform:uppercase;color:var(--muted);margin:0 0 .7rem}
.legal .toc ol{margin:0;padding:0;list-style:none;columns:2;column-gap:28px;font-size:.9rem}
.legal .toc li{margin:0 0 .32rem;break-inside:avoid}
.legal .toc a{color:var(--muted);text-decoration:none;transition:color .15s}
.legal .toc a:hover{color:var(--brand)}
.legal .toc .num{display:inline-block;min-width:1.7em;color:var(--sand-2);font-variant-numeric:tabular-nums}
@media(max-width:640px){.legal .toc ol{columns:1}}
.legal .part{margin:46px 0 0;padding:0 0 .5rem;border-bottom:1px solid var(--line);
  font-family:var(--f-body);font-size:.72rem;font-weight:700;letter-spacing:.2em;text-transform:uppercase;color:var(--brand)}
.legal .clause{margin:30px 0 0;scroll-margin-top:90px}
.legal .clause h3{font-size:1.12rem;color:var(--ink);margin:0 0 .5rem;display:flex;gap:.6rem;align-items:baseline}
.legal .clause h3 .num{font-family:var(--f-body);font-size:.8rem;font-weight:700;color:var(--brand);
  flex:0 0 auto;min-width:1.8em;padding-top:.15rem;font-variant-numeric:tabular-nums}
.legal .clause h4{font-family:var(--f-body);font-size:.78rem;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink);margin:24px 0 .1rem}
.legal .clause > p,.legal .clause > ul{color:var(--muted);line-height:1.75;margin:.55rem 0 0}
.legal .clause p{font-size:.95rem}
.legal .clause ul{padding-left:1.15rem;font-size:.95rem}
.legal .clause li{margin:.22rem 0}
.legal .clause ul.tight{margin-top:.35rem}
.legal .clause a{color:var(--brand);font-weight:600}
.legal .clause strong{color:var(--ink);font-weight:600}
.legal .callout{margin:.7rem 0 0;padding:14px 16px;border-left:3px solid var(--brand);background:var(--sand);
  border-radius:0 var(--r-s) var(--r-s) 0;font-size:.92rem;line-height:1.7;color:var(--ink)}
.legal .backtop{display:inline-block;margin-top:40px;font-size:.84rem;color:var(--muted)}
.legal .backtop:hover{color:var(--brand)}

/* ---------- Arabic typography ----------
   Arabic is a connected script: letter-spacing pulls the joins apart and makes
   words look broken, so every tracked-out Latin style is reset here. Arabic
   also needs more leading than Inter's 1.65, and the negative heading tracking
   is a Latin-only refinement. Scoped to lang=ar, which i18n.apply() sets. */
html[lang=ar] .eyebrow,
html[lang=ar] .brand small,
html[lang=ar] .badge,
html[lang=ar] .path .pnum,
html[lang=ar] .foot h5,
html[lang=ar] .legal .part,
html[lang=ar] .legal .toc h2,
html[lang=ar] .legal .clause h4,
html[lang=ar] .pill,
html[lang=ar] .btn{letter-spacing:normal}
html[lang=ar] body{line-height:1.85}
html[lang=ar] h1,html[lang=ar] h2,html[lang=ar] h3,html[lang=ar] h4{letter-spacing:normal;line-height:1.35}
html[lang=ar] .legal .clause > p,html[lang=ar] .legal .clause ul,html[lang=ar] .legal .entity{line-height:1.95}
html[lang=ar] .legal .clause h3{align-items:flex-start}
/* the clause number stays a Latin numeral — keep it upright and to the right */
html[lang=ar] .legal .clause h3 .num,html[lang=ar] .legal .toc .num{direction:ltr;unicode-bidi:isolate}

/* ---------- About Montroyal ---------- */
/* the philosophy / manifesto lines the client asked to emphasise */
.statement{font-family:var(--f-disp);font-weight:700;font-size:clamp(1.4rem,3.1vw,2.15rem);line-height:1.22;
  color:var(--brand);margin:1.2rem 0 0;max-width:26ch;letter-spacing:-.015em}
.statement.on-dark{color:#fff}
/* Single-line variant. .statement caps the measure at 26ch and this line is 43
   characters, so it always broke in two. The cap is lifted and the type scaled
   to fit the hero column at every width. Deliberately no white-space:nowrap —
   if a font substitution renders it slightly wider it wraps, which is far
   better than pushing the whole page sideways. */
.statement.oneline{max-width:none;font-size:clamp(.95rem,2.7vw,2.15rem)}
/* Three stepped lines, each led by a rule that lengthens as the thought grows
   from home to asset to investment. Each line carries its own gradient rather
   than one across the block, so the sweep completes within every line instead
   of the short first line getting only the dark end of it. */
/* line-height 1.28, not 1.12: with background-clip:text the glyphs are painted
   only where the element's background box reaches, so a line box shorter than
   the type left descenders (the g in "Long") unpainted and looking sliced off.
   The padding on .ln below buys the same margin at the bottom edge. */
.bigline{font-family:var(--f-disp);font-weight:700;font-size:clamp(1.55rem,4.2vw,2.9rem);
  line-height:1.28;letter-spacing:-.02em;margin:1.5rem 0 0;color:var(--ink);
  display:flex;flex-direction:column;gap:.06em}
/* align-self:flex-start so each row shrinks to its own content. As a stretched
   flex child the row would span the whole column, and the gradient — painted
   across the row's box — would run out long after the text ended, so no line
   would ever reach the maroon at the far end of the sweep. */
.bigline .ln{display:flex;align-items:center;gap:.5em;white-space:nowrap;align-self:flex-start;
  padding-block:.04em .1em}
/* the lead rule grows 1 -> 2 -> 3 steps down the stack */
.bigline .ln::before{content:"";flex:0 0 auto;height:3px;border-radius:3px;
  background:linear-gradient(90deg,var(--brand) 0%,#C0863A 100%);
  width:.7em;opacity:.95}
.bigline .ln:nth-child(2)::before{width:1.5em}
.bigline .ln:nth-child(3)::before{width:2.3em}
.bigline em{font-style:normal;color:var(--brand)}
/* Gradient runs ink -> deep maroon -> brand maroon, all from the palette, so
   each line resolves into the brand colour. Guarded by @supports because the
   transparent text-fill would leave it invisible without background-clip. */
@supports (background-clip:text) or (-webkit-background-clip:text){
  .bigline .ln{background-image:linear-gradient(96deg,var(--ink) 0%,var(--brand-d) 52%,var(--brand) 100%);
    -webkit-background-clip:text;background-clip:text;
    color:transparent;-webkit-text-fill-color:transparent}
  html[dir=rtl] .bigline .ln{background-image:linear-gradient(-96deg,var(--ink) 0%,var(--brand-d) 52%,var(--brand) 100%)}
  .bigline em{-webkit-text-fill-color:currentColor}
}
/* the longest line is 23 characters; below this it would clip, so let it wrap */
@media(max-width:420px){
  .bigline{font-size:1.35rem}
  .bigline .ln{white-space:normal}
}
/* brand pull-quote */
.quote{margin:0;padding:clamp(30px,5vw,56px) 0 0;border-top:1px solid var(--line)}
.quote p{font-family:var(--f-disp);font-weight:700;font-size:clamp(1.45rem,3.4vw,2.4rem);line-height:1.25;letter-spacing:-.018em;
  color:var(--ink);max-width:none;margin:0}
.quote .mark{display:block;font-family:var(--f-disp);font-size:3.2rem;line-height:.6;color:var(--sand-2);margin-bottom:.3rem}
/* closing mark balances the opening one, sitting at the end of the quote */
.quote .mark.close{margin:.55rem 0 0;text-align:right}
html[dir=rtl] .quote .mark.close{text-align:left}

/* three divisions — distinct cards, visually tied by a shared connector rule */
/* Intro copy runs as one continuous block across the full section width —
   no column split and no measure cap, so it spreads to the same width as the
   card row beneath it. */
.story-cols{display:grid;gap:14px;margin-top:20px}
.story-cols p{margin:0;color:var(--muted);max-width:none}
.story-cols .lede{max-width:none}
.divisions{display:grid;gap:16px;grid-template-columns:1fr;margin-top:28px;position:relative}
@media(min-width:900px){.divisions{grid-template-columns:repeat(3,1fr)}}

/* ── Division connector ───────────────────────────────────────────────────
   The brief asks for the three divisions to be distinct but clearly one
   Montroyal ecosystem. One unbroken gradient line threads all three — maroon
   at Rentals through to brass at Renovation — with a node above each card.
   The cards keep their own borders and hover lift, so they stay distinct.
   It is decorative only (aria-hidden), and it is drawn on its own element
   rather than on .divcard because the cards are overflow:hidden and would
   clip anything reaching outside them. */
.divspine{display:none}
@media(min-width:900px){
  .divspine{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;
    position:relative;margin-top:28px;height:14px}
  /* the line runs the full width, straight through the grid gaps */
  .divspine::before{content:"";position:absolute;left:0;right:0;top:50%;height:2px;
    transform:translateY(-50%);border-radius:2px;
    background:linear-gradient(90deg,var(--brand) 0%,#9E3318 52%,#C0863A 100%)}
  .divspine span{position:relative}
  /* node sits centred over each card; the ring of page colour punches the
     line out behind it so the dot reads as a stop on the line */
  .divspine span::after{content:"";position:absolute;left:50%;top:50%;width:11px;height:11px;
    transform:translate(-50%,-50%);border-radius:50%;
    background:var(--bg);border:2px solid var(--brand);box-shadow:0 0 0 4px var(--bg)}
  .divspine span:nth-child(2)::after{border-color:#9E3318}
  .divspine span:nth-child(3)::after{border-color:#C0863A}
  .divisions{margin-top:12px}
}
/* Stacked: the spine turns vertical and runs down the left of the column,
   continuous through the gaps between cards. */
@media(max-width:899px){
  .divisions{padding-inline-start:26px}
  .divisions::before{content:"";position:absolute;inset-inline-start:8px;top:6px;bottom:6px;
    width:2px;border-radius:2px;
    background:linear-gradient(180deg,var(--brand) 0%,#9E3318 52%,#C0863A 100%)}
}
.divcard{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);overflow:hidden;
  display:flex;flex-direction:column;box-shadow:var(--sh);transition:transform .25s ease,box-shadow .25s ease}
.divcard:hover{transform:translateY(-4px);box-shadow:var(--sh-lg)}
.divcard img{width:100%;height:auto;aspect-ratio:16/10;object-fit:cover}
.divcard .dc{padding:20px 20px 24px;display:flex;flex-direction:column;gap:.4rem;flex:1}
.divcard .dnum{font-family:var(--f-body);font-size:.68rem;font-weight:700;letter-spacing:.2em;
  text-transform:uppercase;color:var(--brand)}
.divcard h3{font-size:1.28rem}
.divcard p{margin:0;color:var(--muted);font-size:.94rem}

/* statistics band */
.statband{background:var(--brand);color:#fff;border-radius:var(--r);padding:clamp(30px,5vw,56px);overflow:hidden}
.statband .eyebrow{color:rgba(255,255,255,.72)}
.statband h2{color:#fff}
.stats{display:grid;gap:22px;grid-template-columns:1fr;margin-top:30px}
@media(min-width:600px){.stats{grid-template-columns:1fr 1fr}}
/* four figures: 4-up on desktop and 2×2 on tablet, so no row is left with a
   single orphan stat. Was 3-up when there were six.
   4-up only from 1240px: at 1040 each column is ~206px, and the longest label
   ("Renovation, Furnishing & Property Transformations Completed") stacks into
   eight lines. iPad landscape therefore gets a comfortable 2x2. */
@media(min-width:1240px){.stats{grid-template-columns:repeat(4,1fr)}}
.stat{padding-top:18px;border-top:1px solid rgba(255,255,255,.22)}
/* Eased down from clamp(2rem,4.4vw,3.1rem) on 14 Aug. Four figures sit in one
   row, and the longest — "AED 75M+" — was filling its column edge to edge
   after the page width came in to 1320. The ceiling drops most; on a phone,
   where they stack two-up, the change is barely visible. */
.stat b{display:block;font-family:var(--f-disp);font-weight:700;font-size:clamp(1.7rem,3.4vw,2.4rem);
  line-height:1;letter-spacing:-.02em;color:#fff;font-variant-numeric:tabular-nums}
.stat span{display:block;margin-top:.55rem;font-size:.9rem;line-height:1.5;color:rgba(255,255,255,.82);max-width:26ch}

/* area chips */
.chips{display:flex;flex-wrap:wrap;gap:10px;margin-top:22px}
/* Outlined in brand maroon. Was sand on a sand page, which left the chips
   almost invisible. Outline rather than a solid fill on purpose: .core below
   is solid maroon, and that contrast is what separates our strongest markets
   from the rest — the client is explicit that the others are not excluded. */
.chip{display:inline-flex;align-items:center;padding:.5rem 1rem;border-radius:999px;background:transparent;
  border:1px solid var(--brand);font-size:.92rem;font-weight:600;color:var(--brand)}
.chip.core{background:var(--brand);border-color:var(--brand);color:#fff}
.chips-note{margin:.9rem 0 0;font-size:.86rem;color:var(--muted)}
/* Core markets / Also serving — two labelled groups instead of one wrapping row */
.areagroup{margin-top:20px}
.areagroup .chips{margin-top:9px}
.arealabel{display:block;font-family:var(--f-body);font-weight:700;font-size:.68rem;
  letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}

/* why-different cards */
.whycards{display:grid;gap:16px;grid-template-columns:1fr;margin-top:30px}
@media(min-width:700px){.whycards{grid-template-columns:1fr 1fr}}
.whycard{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:24px;
  display:flex;flex-direction:column;gap:.35rem}
.whycard .wnum{font-family:var(--f-body);font-size:.68rem;font-weight:700;letter-spacing:.2em;
  text-transform:uppercase;color:var(--brand)}
.whycard h3{font-size:1.18rem;margin-top:.15rem}
.whycard .wlead{font-family:var(--f-disp);font-weight:500;font-size:1.02rem;color:var(--brand);margin:0}
.whycard p{margin:.3rem 0 0;color:var(--muted);font-size:.94rem}

/* ── Ecosystem band (Our Story) ───────────────────────────────────────────
   Recreated from the supplied concept. Its palette is scoped to this block as
   local custom properties rather than added to :root — these darks belong to
   this one band and must not leak into the site tokens. */
.eco{
  --eco-bg:#2A1416; --eco-panel:#3A1D1F; --eco-head:#4A2A2A;
  --eco-gold:#C89A5B; --eco-cream:#F7F2EA; --eco-muted:#BFAFA6;
  background:var(--eco-bg);border-radius:var(--r);overflow:hidden;
  padding:clamp(26px,4vw,52px)}
.eco-eyebrow{color:var(--eco-gold)}
.eco-h{font-family:var(--f-disp);font-weight:700;color:var(--eco-cream);line-height:1.12;
  font-size:clamp(1.8rem,4vw,3rem);margin:.5rem 0 1rem;max-width:24ch}
.eco-lede{font-family:var(--f-body);color:var(--eco-cream);font-size:clamp(1.02rem,1.3vw,1.2rem);
  line-height:1.6;margin:0 0 .85rem;max-width:60ch}
.eco-p{font-family:var(--f-body);color:var(--eco-muted);font-size:.98rem;line-height:1.72;
  margin:0 0 .85rem;max-width:68ch}

/* 1px gaps let the gold backing show through as hairline dividers, which is
   what fuses the three panels into a single object */
.eco-grid{display:grid;grid-template-columns:1fr;gap:1px;
  background:rgba(200,154,91,.35);border-radius:10px;overflow:hidden;margin-top:28px}
@media(min-width:820px){.eco-grid{grid-template-columns:repeat(3,minmax(0,1fr))}}
.eco-card{background:var(--eco-panel);display:flex;flex-direction:column}
.eco-top{height:120px;background:var(--eco-head);position:relative;overflow:hidden;
  display:flex;align-items:center;justify-content:center}
.eco-num{position:absolute;left:14px;top:2px;font-family:var(--f-disp);font-weight:700;line-height:1;
  font-size:clamp(2.4rem,3.6vw,2.9rem);color:rgba(247,242,234,.22)}
/* Stage labels: the site body face, noticeably larger and bold. Cream rather
   than muted, because at this weight the low-contrast grey read as murky. */
.eco-stage{font-family:var(--f-body);display:inline-flex;align-items:center;gap:8px;
  font-size:clamp(.84rem,1.05vw,1rem);font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--eco-cream);text-align:center;
  padding:0 12px;position:relative;z-index:1;transition:color .3s ease}
.eco-stage svg{width:1.15em;height:1.15em;flex:0 0 auto;color:var(--eco-gold)}
/* Same sheen the primary buttons use — a diagonal highlight sweeping across on
   hover, identical gradient, timing and easing (see .btn-primary::after). */
.eco-top::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,transparent 30%,rgba(255,255,255,.30) 48%,transparent 66%);
  transform:translateX(-130%);transition:transform .6s cubic-bezier(.22,.61,.36,1)}
.eco-card:hover .eco-top::after,.eco-top:hover::after{transform:translateX(130%)}
.eco-card:hover .eco-stage{color:#fff}
/* Stacked, the numeral was pinned to the top-left corner while the stage label
   sat centred, so they read as two unrelated things on different rows. Dropping
   the absolute positioning puts the numeral into the same flex row as the label,
   vertically aligned with it. */
@media(max-width:819px){
  .eco-top{gap:14px;height:96px}
  .eco-num{position:static;font-size:2.2rem}
}
.eco-body{padding:20px 18px 24px;text-align:center}
.eco-body h3{font-family:var(--f-disp);font-weight:700;font-size:1.08rem;color:var(--eco-cream);margin:0 0 .35rem}
.eco-body p{font-family:var(--f-body);margin:0;font-size:.9rem;line-height:1.65;color:var(--eco-muted)}

/* the loop marker: the line that closes the lifecycle */
.eco-loop{display:flex;align-items:center;gap:12px;margin-top:24px}
.eco-rule{height:1px;flex:1;background:rgba(200,154,91,.4)}
.eco-loop-label{font-family:var(--f-body);display:inline-flex;align-items:center;gap:7px;
  font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--eco-gold);white-space:nowrap}
@media(max-width:520px){
  .eco-loop-label{white-space:normal;text-align:center}
}
.eco-close{font-family:var(--f-body);margin:18px 0 0;color:var(--eco-muted);font-size:.98rem;line-height:1.72;max-width:70ch}

/* ── Gradient text utility ────────────────────────────────────────────────
   Same warm sweep as the brand statement. The solid colour underneath is what
   shows if background-clip:text is unsupported — without it the text-fill is
   transparent and the words disappear entirely. */
.grad-text{
  color:var(--brand);
  background-image:linear-gradient(102deg,#4B0A05 0%,#681009 24%,#9E3318 56%,#C0863A 100%);
  -webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;
}
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .grad-text{background-image:none;-webkit-text-fill-color:currentColor;color:var(--brand)}
}
@media(prefers-contrast:more){
  .grad-text{background-image:none;-webkit-text-fill-color:currentColor;color:var(--brand)}
}

/* ── "Why Montroyal is different" — the page's selling section ────────────
   Centred and given the full width of the wrap: the copy was capped at 72ch
   and left-aligned, which left the right half of a 1600px page empty and made
   the argument look like a footnote. */
.why .sec-head{max-width:none;text-align:center;margin-inline:auto}
.why .sec-head h2{font-weight:700;font-size:clamp(2.1rem,5vw,3.9rem);
  max-width:22ch;margin-inline:auto;text-wrap:balance;line-height:1.05}
/* Widened from 86ch so each sentence sits on a single line on desktop — the
   two long ones are 139 and 152 characters, which needs roughly 1300px of
   measure at this size. Below that they wrap normally. */
.why-intro{max-width:min(1300px,100%);margin:1.5rem auto 0;text-align:center}
/* The three sentences run as one continuous block — no paragraph gap between
   them, so they read as a single thought rather than three statements. */
.why-intro p{color:var(--muted);margin:0;font-size:clamp(1rem,1.1vw,1.14rem);line-height:1.72}
.why-intro p:first-of-type{margin-top:.95rem}
.why-intro .chips{justify-content:center;margin-top:26px}

/* four pillars read as one row on a wide screen rather than a 2x2 block.
   1280px, not 1100: card 02 carries ~40 words, and at 1100 the columns are
   ~250px wide, which turns it into a narrow ribbon of text. iPad landscape
   (1024) and small laptops keep the roomier 2x2. */
.why .whycards{margin-top:clamp(36px,4.5vw,60px);gap:18px}
@media(min-width:1280px){.why .whycards{grid-template-columns:repeat(4,1fr)}}
.why .whycard{padding:30px 26px;border-color:var(--sand-2);box-shadow:var(--sh);
  transition:transform .3s ease,box-shadow .3s ease,border-color .3s ease}
.why .whycard:hover{transform:translateY(-4px);box-shadow:var(--sh-lg);border-color:var(--brand)}
/* the index becomes a display numeral — the loudest thing in the card */
.why .whycard .wnum{font-family:var(--f-disp);font-size:2.1rem;font-weight:700;
  letter-spacing:0;text-transform:none;line-height:1;color:var(--brand);margin-bottom:.35rem}
.why .whycard h3{font-size:1.32rem;font-weight:700}
.why .whycard .wlead{font-size:1.06rem}

/* full-bleed image feature */
.feature{position:relative;border-radius:var(--r);overflow:hidden;min-height:min(74vh,560px);
  display:flex;align-items:flex-end;padding:clamp(24px,4vw,48px);color:#fff}
.feature img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0}
.feature::after{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(180deg,rgba(20,6,4,.15) 0%,rgba(20,6,4,.42) 45%,rgba(38,8,4,.88) 100%)}
.feature .fc{position:relative;z-index:2;max-width:58ch}

/* Phones: stop overlaying and stack instead. The copy here is a heading, three
   paragraphs and a button — on a narrow screen that fills the whole panel, so
   every line sat on the photo and the gradient (light at the top by design)
   could not carry it. Darkening the scrim enough to fix it would have buried
   the photograph. Image on top, text on solid maroon beneath: both readable.
   The parallax transform is cancelled here too — it only makes sense while the
   image is the absolutely-positioned background of the panel. */
@media(max-width:760px){
  .feature{display:block;min-height:0;padding:0;background:var(--brand-d);border-radius:var(--r);overflow:hidden}
  .feature::after{display:none}
  .feature img{position:static;top:auto;bottom:auto;width:100%;height:auto;
    aspect-ratio:4/3;object-fit:cover;transform:none!important}
  .feature .fc{max-width:none;padding:22px 20px 26px}
  .feature h2{font-size:clamp(1.6rem,6.4vw,2.1rem)}
}
.feature h2{color:#fff;font-size:clamp(1.8rem,4.2vw,3rem)}
.feature p{color:rgba(255,255,255,.88);margin:.7rem 0 0}

/* philosophy — quiet and centred */
/* Philosophy — the quiet close. Brief kept it short and elegant, so this is
   scaled up rather than rebuilt: wider measure, gradient heading matching the
   "Why Montroyal" section, and the closing line promoted to the payoff.
   It was 62ch with the statement capped at 34ch, which broke that line across
   three and left the section reading as cramped. */
/* Widened so the intro sentence (170 characters) sits on one line on a large
   screen. The heading and the closing statement keep their own narrow measures
   below, so only that sentence uses the extra width. */
.philosophy{max-width:min(1420px,100%);margin:0 auto;text-align:center}
/* a small brand rule to open the section — the only ornament it needs */
.philosophy::before{content:"";display:block;width:58px;height:2px;border-radius:2px;
  margin:0 auto 24px;background:linear-gradient(90deg,var(--brand) 0%,#C0863A 100%)}
.philosophy h2{font-weight:700;font-size:clamp(1.95rem,4.4vw,3.3rem);line-height:1.07;
  max-width:21ch;margin-inline:auto;text-wrap:balance}
.philosophy p{color:var(--muted);margin:1.1rem auto 0;max-width:100%;
  font-size:clamp(1rem,1.1vw,1.14rem);line-height:1.72}
/* Two lines. The line is 85 characters, so each carries ~43 — measure and type
   scale are a pair, as with .brandstate. The 1.02rem floor is what holds it to
   two lines on a 375px phone; raise it and it breaks to three. */
.philosophy .statement{margin:1.6rem auto 0;max-width:min(42ch,100%);
  font-size:clamp(1.02rem,2.85vw,2.4rem);line-height:1.24;text-wrap:balance}
html[dir=rtl] .philosophy{text-align:center}

/* Releases the ratio for photographs that aren't 4:3, so they show whole
   instead of being cropped to fit the standard box. */
.rounded.shot-wide{aspect-ratio:auto}

/* Image column matches the text column's height exactly. .split centres its two
   columns and .rounded is locked to 4:3, so the photo sets its own height and
   almost never agrees with the copy beside it. Here the row stretches and the
   photo fills whatever height the text needs, cropping via object-fit rather
   than leaving the two sides ragged. Only on two-column widths — stacked, the
   photo keeps its natural 4:3. */
@media(min-width:900px){
  /* align-items:stretch alone is enough: both grid items already grow to the
     row height, so the photo can simply fill its own column with height:100%.
     Do NOT add display:flex to these columns — it lays the text column's
     heading, copy and buttons out in a row and squashes the buttons into
     circles. */
  .split-match{align-items:stretch}
  .split-match img.rounded{aspect-ratio:auto;height:100%;width:100%;object-fit:cover}
}

/* ── English-only pages inside an RTL shell ───────────────────────────────
   The About page stays in English whichever language is chosen (client
   decision, 10 Aug 2026), so when the chrome switches to Arabic its content
   must keep LTR typography. Without this the English copy would be
   right-aligned and read as broken. Header, footer and the language switcher
   are outside <section> and still translate and flip normally. */
html[dir=rtl] body[data-en-only] section{direction:ltr;text-align:left}
html[dir=rtl] body[data-en-only] section .lede,
html[dir=rtl] body[data-en-only] section .wrap>p,
html[dir=rtl] body[data-en-only] section h1,
html[dir=rtl] body[data-en-only] section h2,
html[dir=rtl] body[data-en-only] section h3,
html[dir=rtl] body[data-en-only] section .sec-head{text-align:left}
/* these three are centred in LTR too, so they must stay centred here — the
   generic left-align above would otherwise catch them via .wrap>p and h2 */
html[dir=rtl] body[data-en-only] section .philosophy,
html[dir=rtl] body[data-en-only] section .philosophy h2,
html[dir=rtl] body[data-en-only] section .brandstate,
html[dir=rtl] body[data-en-only] section.why .sec-head,
html[dir=rtl] body[data-en-only] section.why .sec-head h2,
html[dir=rtl] body[data-en-only] section.why .why-intro{text-align:center}
html[dir=rtl] body[data-en-only] section ul{padding-right:revert}
@supports (background-clip:text) or (-webkit-background-clip:text){
  /* targets .ln, not .bigline — the gradient moved onto the individual lines */
  html[dir=rtl] body[data-en-only] .bigline .ln{
    background-image:linear-gradient(96deg,var(--ink) 0%,var(--brand-d) 52%,var(--brand) 100%)}
}

/* ── Brand statement ──────────────────────────────────────────────────────
   The line Montroyal leads with. Bold display type, gradient across the whole
   sentence, warm maroon into brass. Sits between the hero and Our Story so it
   is the first thing read after the introduction. */
.brandstate-sec{padding:clamp(46px,7vw,86px) 0 clamp(10px,2vw,24px)}
/* The philosophy line in the About hero. Sits directly under the sentence that
   introduces it ("...one simple philosophy:"), so it follows that column's
   alignment rather than being centred. Sized at .72rem to match the eyebrow
   labels, in the brand maroon it has always had. */
/* Inline, not a block: it continues the sentence that introduces it, sitting
   next to the colon and wrapping with the rest of the paragraph. Colour, weight
   and size are unchanged from the standalone version. */
.philo-line{display:inline;font-family:var(--f-body);font-weight:600;font-size:.95rem;
  letter-spacing:.02em;color:var(--brand);margin:0}
.brandstate{
  font-family:var(--f-disp);
  font-weight:700;
  /* Two lines. The sentence is 99 characters, so each line carries ~50 — that
     needs a wide measure, hence 48ch. Measure and type scale are a pair: widen
     one without easing the other and it wraps to three.
     Phones are the exception: 2 lines at 375px would need ~14px type, which is
     body-copy size and would stop this reading as a statement. It settles at
     three lines below roughly 600px, by choice. */
  font-size:clamp(1.25rem,3.2vw,2.7rem);
  line-height:1.18;
  letter-spacing:-.015em;
  text-align:center;
  max-width:min(48ch,100%);
  margin:0 auto;
  text-wrap:balance;                 /* keeps the three lines evenly weighted */
  color:var(--brand);                /* the colour used if the clip below fails */
  background-image:linear-gradient(102deg,#4B0A05 0%,#681009 24%,#9E3318 56%,#C0863A 100%);
  -webkit-background-clip:text;
  background-clip:text;
  -webkit-text-fill-color:transparent;
}
/* Without background-clip:text the fill would be transparent and the sentence
   would vanish, so put the solid brand colour back. */
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .brandstate{background-image:none;-webkit-text-fill-color:currentColor;color:var(--brand)}
}
@media(prefers-contrast:more){
  .brandstate{background-image:none;-webkit-text-fill-color:currentColor;color:var(--brand)}
}

/* Buttons sitting on the maroon band.
   .btn-brass was the old brass gold; the rebrand repointed it to var(--brand),
   which is the band's own background — so every button inside a band rendered
   as bare white text. On the band they take a light fill instead. */
.band .btn-brass{background:var(--sand);color:var(--brand)}
.band .btn-brass:hover{background:#fff;color:var(--brand);box-shadow:0 14px 30px -14px rgba(0,0,0,.6)}
/* secondary actions: outlined, so a row of three doesn't read as three primaries */
.band .btn-line{background:transparent;color:#fff;box-shadow:inset 0 0 0 1px rgba(255,255,255,.5)}
.band .btn-line:hover{background:rgba(255,255,255,.13);color:#fff;box-shadow:inset 0 0 0 1px rgba(255,255,255,.8)}

/* three-way closing CTA */
.ctarow{display:flex;flex-wrap:wrap;gap:12px;margin-top:22px}
@media(max-width:560px){.ctarow .btn{width:100%;justify-content:center}}

/* Closing CTA band: on wide screens the copy sat in a narrow column with the
   whole right-hand half of the panel empty. Two columns puts the actions there. */
@media(min-width:900px){
  .band-cta{display:grid;grid-template-columns:minmax(0,1fr) auto;
    gap:clamp(30px,4.5vw,64px);align-items:center}
  .band-cta .ctarow{margin-top:0;flex-direction:column;align-items:stretch;min-width:250px}
  .band-cta .ctarow .btn{justify-content:center}
}

/* ── Booking request card ─────────────────────────────────────────────────
   Lives in the apartment aside, under the WhatsApp button. Deliberately plain:
   it is a request form, not a checkout, and nothing here takes payment. */
.bookcard{margin-top:18px;padding-top:18px;border-top:1px solid var(--line)}
.bookcard h3{font-family:var(--f-disp);font-weight:700;font-size:1.25rem;margin:0 0 .15rem}
.bookcard form{margin-top:12px;display:flex;flex-direction:column;gap:10px}
.bk2{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.fl2{display:block;font-size:.72rem;font-weight:600;letter-spacing:.04em;
  text-transform:uppercase;color:var(--muted)}
.fl2 input,.fl2 textarea{display:block;width:100%;margin-top:.25rem;min-height:44px;
  padding:.5rem .65rem;border:1px solid var(--line);border-radius:10px;background:#fff;
  color:var(--ink);font:inherit;text-transform:none;letter-spacing:normal;font-weight:400}
.fl2 textarea{min-height:60px;resize:vertical}
.nightsout{display:block;margin-top:.25rem;min-height:44px;padding:.6rem .65rem;
  border:1px solid var(--line);border-radius:10px;background:var(--sand);
  color:var(--ink);font-weight:600;text-transform:none;letter-spacing:normal}
.bkerr{color:var(--brand);font-size:.85rem;font-weight:600}
.bkerr:empty{display:none}

/* availability — two months, read-only. Confirmed stays only. */
.bkcal{margin-top:16px}
.callegend{display:flex;align-items:center;gap:6px;font-size:.75rem;color:var(--muted);margin-bottom:10px}
.callegend .k{width:12px;height:12px;border-radius:4px;display:inline-block}
.callegend .k.free{background:var(--sand)}
.callegend .k.off{background:var(--brand);opacity:.85}
.cal{margin-bottom:14px}
.cal>b{display:block;font-size:.8rem;font-weight:600;margin-bottom:6px}
.calgrid{display:grid;grid-template-columns:repeat(7,1fr);gap:3px;text-align:center}
.calgrid i{font-style:normal;font-size:.65rem;color:var(--muted);padding-bottom:2px}
.calgrid span{font-size:.75rem;padding:.34rem 0;border-radius:6px;background:var(--sand)}
.calgrid span:empty{background:none}
.calgrid span.past{background:none;color:var(--sand-2)}
.calgrid span.off{background:var(--brand);color:#fff;opacity:.85}

/* "Good to know" — rates, fees and house rules. Deliberately plainer than the
   amenity chips: these are terms a guest is agreeing to, not selling points. */
/* No gap between items: these are typed one per line in the admin with no blank
   lines, so they should read as a tight list rather than spaced paragraphs.
   The .15rem margin that used to sit on each li was the space showing up on the
   site that never existed in the admin field. */
.notelist{margin:.2rem 0 0;padding-inline-start:1.15rem;max-width:64ch;color:var(--muted);line-height:1.6}
.notelist li{margin:0}

/* Short description — the one-line summary. On the apartment page it sits under
   the status badge as a lede; on a card it is clamped to two lines so a long
   one cannot push the price out of alignment across a row of cards. */
.shortlede{margin:1rem 0 0;max-width:60ch;color:var(--muted);font-size:1.05rem;line-height:1.6}
.cardlede{margin:.35rem 0 0;color:var(--muted);font-size:.88rem;line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}

/* A listing's video tour, under its photo gallery. Contained rather than cropped
   for the same reason as the gallery tiles: a video is composed, and cutting its
   edges loses part of the shot. */
.listvid{display:block;width:100%;margin:14px 0 0;border-radius:var(--r);
  background:#2A0703;aspect-ratio:16/9;object-fit:contain}

/* ── Before/after inset ──────────────────────────────────────────────────────
   A small "before" photograph hung over the lower corner of the finished shot.
   The section is about transformation, so showing both states says it faster
   than the copy does.

   Bottom padding on the wrapper reserves the space the inset hangs into —
   without it the overhang would collide with whatever follows. The inset is
   sized in % so it keeps its proportion to the main image at every width, with
   a max so it cannot dominate on a large screen. */
.beforeinset{position:relative;padding-bottom:clamp(26px,4vw,44px)}
.beforeinset .bi-after{display:block;width:100%;height:auto}
.bi-before{position:absolute;left:7%;bottom:0;width:38%;max-width:250px;margin:0;
  border-radius:var(--r-s);overflow:hidden;box-shadow:var(--sh-lg);
  /* the border is the page colour, so the inset reads as lifted off the photo
     rather than as a hole cut into it */
  border:4px solid var(--bg);background:var(--bg)}
.bi-before img{display:block;width:100%;height:auto;aspect-ratio:4/3;object-fit:cover}
.bi-before figcaption{position:absolute;top:9px;left:9px;background:var(--brand);color:#fff;
  font-size:.6rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  padding:.2rem .5rem;border-radius:999px;line-height:1.5}
@media(max-width:560px){.bi-before{left:5%;width:44%;border-width:3px}}

/* ── Case study figures ──────────────────────────────────────────────────────
   Three numbers that have to be read as a sequence: what the market was doing,
   what was spent, what came back. The third is highlighted because it is the
   result; the other two are the context that makes it mean anything. */
.casebox{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:22px 20px;display:flex;flex-direction:column;gap:2px}
.casebox b{font-family:var(--f-disp);font-weight:700;font-size:clamp(1.5rem,3vw,2.05rem);
  line-height:1.1;letter-spacing:-.02em;color:var(--ink);font-variant-numeric:tabular-nums}
.caselabel{font-size:.66rem;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--muted);margin-bottom:6px}
.casenote{font-size:.84rem;color:var(--muted)}
.casebox-hi{background:linear-gradient(135deg,#7A1410 0%,var(--brand) 55%,var(--brand-d) 100%);
  border-color:transparent;box-shadow:var(--sh-lg)}
.casebox-hi b,.casebox-hi .caselabel{color:#fff}
.casebox-hi .caselabel{color:#F1D9AE}
.casebox-hi .casenote{color:rgba(255,255,255,.84)}
/* The qualifier must be legible, not buried — it is the sentence that keeps a
   real result from reading as a promise. */
.casedisc{max-width:78ch;margin-top:16px;padding-left:12px;border-left:2px solid var(--line)}

/* ── Lead kicker ─────────────────────────────────────────────────────────────
   A section label promoted to be the headline. Used where the plain-English
   label ("Rent your apartment") says more to a visitor than the crafted line
   beneath it does.

   A separate class on purpose: .eyebrow appears on every section of every page,
   so changing it there would resize the whole site. This opts one in.

   Still uppercase and still letter-spaced, so it reads as a confident label
   rather than as a second headline competing with the one below it — but in the
   display face and at headline size, so it carries the section. */
/* Ink rather than burgundy, 14 Aug. At 0.72rem a burgundy eyebrow is a small
   accent; at headline size it competes with the gradient headline beneath it and
   the page ends up with two burgundy statements arguing. Ink lets the kicker
   carry the size while the colour stays with the headline. --ink, not pure
   black — the site has no #000 anywhere and it would sit oddly against the warm
   sand background. */
.eyebrow-lead{display:block;font-family:var(--f-disp);font-weight:700;
  font-size:clamp(1.75rem,3.9vw,2.7rem);line-height:1.08;letter-spacing:.03em;
  color:var(--ink);margin-bottom:.15rem}
/* Two classes, to outrank .eyebrow.brass. Renovation and Projects carry `brass`
   on the same element, and a single-class rule loses to it — so those two stayed
   brass while the other four went black. Specificity, not the cascade order. */
.eyebrow.eyebrow-lead{color:var(--ink)}

/* ── Before / after rows ─────────────────────────────────────────────────────
   The showcase on this page, so the slider gets the full column and the caption
   sits above it rather than stealing half the width.

   Capped at 1080px: at 4:3 that is about 810px tall, which fills a laptop screen
   without three of them turning the page into a mile of scrolling. Wider would
   be taller still, not more impressive.

   The earlier version put the caption beside the image and held the slider to
   640px, on the reasoning that a long handle drag is hard to read. That was
   overcautious — the control is an <input type="range">, so a click anywhere
   jumps the handle straight to that point and nobody has to drag at all. */
.barows{display:grid;gap:clamp(38px,5vw,64px);margin-top:26px}
.barow{display:block}
/* Full column width, flush left. Capping at 1080 and centring left the slider
   inset about 120px from "Before & after." above it — every other section on the
   site starts at the same left edge, and one that does not reads as a mistake
   rather than as emphasis. Alignment wins over the extra height this costs. */
/* A brass hairline and a soft burgundy shadow — the pairing used on the brand
   statement and the tab underline, so the frame reads as part of the identity
   rather than a generic photo border. Inset, so it does not add width and
   break the alignment with the heading. */
/* A real border, not an inset shadow. The before and after images are absolutely
   positioned over the whole frame, and an inset shadow paints below child
   content — so the first attempt was there but completely covered.

   box-sizing is border-box globally, so this sits inside the existing width and
   the frames stay aligned with the section heading. */
.barow .ba{width:100%;margin:0;
  /* the brand burgundy itself, taken from the variable so it follows the palette
     rather than being a copy of it that drifts */
  border:4px solid var(--brand);
  /* Raised rather than flat: a catch light along the top edge, a tight contact
     shadow directly beneath, then a deep soft one further down. Light from above
     is what makes the frame read as standing off the page instead of printed on
     it — reversing these two would sink it. */
  box-shadow:
    0 -1px 0 rgba(255,255,255,.30),
    0 2px 3px rgba(0,0,0,.18),
    0 30px 60px -30px rgba(74,11,6,.62)}
/* The bevel INSIDE the frame has to be its own overlay. .ba is overflow:hidden
   and its two images are position:absolute inset:0, so an inset shadow on .ba
   is painted underneath them and never seen — the same trap noted above, which
   already cost one attempt. ::after is taken by the light sweep, so this is
   ::before, sitting above it at z-index 7 so the frame edge stays crisp, and
   pointer-events:none so it never intercepts a drag.
   inset:0 places it against the padding box, i.e. inside the 4px border, so the
   radius is the outer one less that border. */
.barow .ba::before{
  content:"";position:absolute;inset:0;z-index:7;pointer-events:none;
  border-radius:calc(var(--r) - 4px);
  box-shadow:
    inset 0 3px 4px -1px rgba(255,255,255,.34),
    inset 0 -3px 4px -1px rgba(0,0,0,.34),
    inset 3px 0 4px -2px rgba(255,255,255,.14),
    inset -3px 0 4px -2px rgba(0,0,0,.22);
}
/* The caption leads. A visitor should know which apartment they are looking at
   before they start dragging — on the Sky View row the address is part of the
   proof, not a footnote. A thin brass rule ties the name to the frame below it
   without adding another heading colour to the page. */
.bacap{margin:0 0 14px;position:relative;padding-left:14px}
.bacap::before{content:"";position:absolute;left:0;top:.28em;bottom:.35em;width:2px;
  border-radius:2px;background:linear-gradient(180deg,#C0863A,rgba(192,134,58,.15))}
.bacap h3{font-size:clamp(1.25rem,2.6vw,1.75rem);margin:0 0 .2rem;line-height:1.15}
.bacap p{color:var(--muted);margin:0;max-width:62ch}
/* Bigger frame, bigger controls — the handle and the Before/After tags were
   sized for a 4:3 tile a third of this width and get lost at this scale. */
.barow .ba .handle{width:3px}
.barow .ba .tag{font-size:.74rem;padding:.34rem .7rem}

/* ── Glass treatment on the before/after showcase ────────────────────────────
   Scoped to .barow, so the smaller sliders on the Projects page keep the plain
   styling — this is for the section that is meant to be the showcase.

   Three parts, all restrained on purpose. A property photograph is the thing
   being sold; an effect that competes with it is worse than none.

   1. The labels and the grip become frosted glass, blurring the photograph
      behind them rather than sitting on a flat grey block.
   2. The divider becomes a soft band of light instead of a hard white line, so
      the two states meet rather than being cut apart.
   3. A single slow sweep of light crosses each row the first time it scrolls
      into view — the look of light moving across glass. It runs once and stops. */
.barow .ba{isolation:isolate}

/* 1 · frosted labels */
.barow .ba .tag{
  background:rgba(20,12,10,.34);
  -webkit-backdrop-filter:blur(14px) saturate(140%);
  backdrop-filter:blur(14px) saturate(140%);
  border:1px solid rgba(255,255,255,.22);
  box-shadow:0 4px 18px -6px rgba(0,0,0,.45), inset 0 1px 0 rgba(255,255,255,.18);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  /* no blur support: keep it legible with a solid tint rather than a pale ghost */
  .barow .ba .tag{background:rgba(20,12,10,.72)}
}

/* 2 · the divider as light rather than a line, with a glass grip on it */
.barow .ba .handle{
  width:2px;
  background:linear-gradient(180deg,rgba(255,255,255,.35),rgba(255,255,255,.95) 22%,
                             rgba(255,255,255,.95) 78%,rgba(255,255,255,.35));
  box-shadow:0 0 0 1px rgba(255,255,255,.18), 0 0 26px 3px rgba(255,255,255,.32);
}
.barow .ba .handle::after{
  content:"";position:absolute;top:50%;left:50%;translate:-50% -50%;
  width:46px;height:46px;border-radius:50%;
  background:rgba(255,255,255,.14);
  -webkit-backdrop-filter:blur(10px) saturate(130%);
  backdrop-filter:blur(10px) saturate(130%);
  border:1px solid rgba(255,255,255,.5);
  box-shadow:0 8px 26px -8px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.55);
  pointer-events:none;
}
/* the two arrows, drawn rather than added as markup */
.barow .ba .handle::before{
  content:"";position:absolute;top:50%;left:50%;translate:-50% -50%;z-index:1;
  width:16px;height:8px;pointer-events:none;
  background:
    linear-gradient(45deg,transparent 46%,#fff 46%,#fff 60%,transparent 60%) left center/8px 8px no-repeat,
    linear-gradient(-45deg,transparent 46%,#fff 46%,#fff 60%,transparent 60%) right center/8px 8px no-repeat;
  opacity:.92;
}

/* 3 · one slow sweep of light as the row arrives */
.barow .ba::after{
  content:"";position:absolute;inset:0;z-index:6;pointer-events:none;opacity:0;
  background:linear-gradient(105deg,transparent 32%,rgba(255,255,255,.10) 46%,
             rgba(255,255,255,.34) 50%,rgba(255,255,255,.10) 54%,transparent 68%);
  background-size:260% 100%;background-position:130% 0;
}
@media(prefers-reduced-motion:no-preference){
  .barow.in .ba::after{animation:glassSweep 1.5s cubic-bezier(.25,.6,.3,1) .18s both}
}
@keyframes glassSweep{
  from{opacity:0;background-position:130% 0}
  25%{opacity:1}
  to{opacity:0;background-position:-40% 0}
}

/* ── How it works: a vertical sequence ───────────────────────────────────────
   Five steps read down the page rather than across.

   Four in a row worked. The fifth broke it: at the 1320px wrap five columns give
   each about 225px, and "3-Year Workmanship Warranty" wraps to three lines in
   that — the row stops being scannable and one step looks like an afterthought.

   Down the page each step has the full width for its text, the thread reads as
   one unbroken line instead of gaps between columns, it is identical on a phone
   so there is a single layout to reason about, and a sixth step could be added
   without redesigning anything. */
.steps{list-style:none;margin:26px 0 0;padding:0;display:grid;gap:0}
.step{position:relative;margin:0;padding:0 0 26px 84px;min-height:64px}
.step:last-child{padding-bottom:0}
.step-mark{position:absolute;left:0;top:0;z-index:1;display:grid;place-items:center;
  width:60px;height:60px;border-radius:50%;
  background:rgba(255,255,255,.07);border:1px solid rgba(241,217,174,.45)}
.step-mark svg{width:24px;height:24px;stroke:#F1D9AE;fill:none;stroke-width:1.6}
.step-n{position:absolute;top:-5px;right:-5px;min-width:23px;height:23px;padding:0 6px;
  border-radius:999px;background:#F1D9AE;color:#4A0B06;font-family:var(--f-disp);
  font-weight:700;font-size:.74rem;line-height:23px;text-align:center;letter-spacing:.02em}
.step h4{color:#fff;font-family:var(--f-body);font-size:1.12rem;margin:.35rem 0 .3rem}
.step p{color:rgba(255,255,255,.82);margin:0;max-width:56ch;font-size:.97rem}
.step:not(:last-child)::after{content:"";position:absolute;left:30px;top:66px;bottom:6px;width:1px;
  background:linear-gradient(180deg,rgba(241,217,174,.55),rgba(241,217,174,.12))}
.step.reveal .step-mark{transition:transform .5s cubic-bezier(.2,.7,.3,1) .1s}
.step.reveal:not(.in) .step-mark{transform:scale(.86)}
@media(prefers-reduced-motion:reduce){.step.reveal:not(.in) .step-mark{transform:none}}
@media(min-width:760px){.step{padding-left:96px;padding-bottom:30px}.step h4{font-size:1.2rem}}

/* ── Who we renovate for ─────────────────────────────────────────────────────
   Two equal cards. The page argues commercially throughout, so a homeowner needs
   telling in the first screenful that it applies to them too — making one card
   dominant would undo that. */
.audcard{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:clamp(20px,3vw,28px)}
.audtag{display:inline-block;font-size:.66rem;font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;color:var(--brand);background:#FBF1EF;
  padding:.28rem .6rem;border-radius:999px;margin-bottom:.7rem}
.audcard h3{font-size:clamp(1.1rem,2.2vw,1.35rem);margin:0 0 .45rem}
.audcard p{color:var(--muted);margin:0;max-width:46ch}

/* ── Branded video cover ─────────────────────────────────────────────────────
   The wordmark on burgundy, standing in front of a video until it is played.
   Pressing play turns the mark away and fades it out, then the film starts.

   A <button> rather than an overlay div, so it is focusable and announced. It
   covers the video completely, so the video's own controls are unreachable until
   it has gone — which is what makes the sequence feel deliberate rather than
   like two things fighting. */
.vidwrap{position:relative;isolation:isolate}
.vidwrap video{display:block;width:100%}
.vidcover{position:absolute;inset:0;z-index:2;border:0;cursor:pointer;padding:0;
  display:grid;place-content:center;justify-items:center;gap:14px;
  border-radius:var(--r);overflow:hidden;font:inherit;
  background:linear-gradient(140deg,#4A0B06 0%,var(--brand) 52%,#2A0703 100%)}
/* a faint sheen so the panel reads as a surface rather than a flat fill */
.vidcover::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 90% at 30% 20%,rgba(255,255,255,.10),transparent 60%)}
.vidcover-logo{width:min(320px,54%);height:auto;position:relative;
  transition:transform .42s cubic-bezier(.4,0,.2,1),opacity .42s ease}
.vidcover-play{position:relative;display:grid;place-items:center;width:62px;height:62px;
  border-radius:50%;color:#4A0B06;background:#F1D9AE;
  box-shadow:0 10px 30px -10px rgba(0,0,0,.6);
  transition:transform .3s cubic-bezier(.34,1.56,.64,1),background .25s ease}
.vidcover-play svg{width:26px;height:26px;margin-left:3px}
.vidcover-hint{position:relative;font-size:.7rem;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:rgba(255,255,255,.8)}
.vidcover:hover .vidcover-play,.vidcover:focus-visible .vidcover-play{transform:scale(1.09);background:#fff}
.vidcover:focus-visible{outline:2px solid #F1D9AE;outline-offset:-4px}

/* the exit: the mark turns on its own axis and lifts away, the panel fades
   behind it, and only then does the video appear */
.vidwrap.playing .vidcover{animation:coverOut .62s cubic-bezier(.4,0,.2,1) .18s forwards;pointer-events:none}
.vidwrap.playing .vidcover-logo{animation:markTurn .6s cubic-bezier(.4,0,.2,1) forwards}
.vidwrap.playing .vidcover-play{animation:playGo .3s ease forwards}
@keyframes markTurn{
  0%{transform:perspective(700px) rotateY(0) scale(1);opacity:1}
  55%{transform:perspective(700px) rotateY(38deg) scale(1.06);opacity:.85}
  100%{transform:perspective(700px) rotateY(90deg) scale(1.14);opacity:0}
}
@keyframes playGo{to{transform:scale(.6);opacity:0}}
@keyframes coverOut{to{opacity:0;visibility:hidden}}
@media(prefers-reduced-motion:reduce){
  .vidwrap.playing .vidcover{animation:none;opacity:0;visibility:hidden;pointer-events:none}
  .vidwrap.playing .vidcover-logo,.vidwrap.playing .vidcover-play{animation:none}
}
