/* ============================================================================
   The Oasis Brain — shared shell
   One token set for both tools. Light is authored on bare :root; dark redefines
   only the tokens, once for the system default and once for the explicit toggle.

   Palette rule: the chrome is greyscale and colour is spent only where it
   carries data. Anything that is navigation, panel, rule or label reads as ink
   on paper; the series colours, the up/down pair and the ochre owner markers are
   the only saturated things on a page. That is what keeps a dense analytical
   page looking calm — not fewer elements, just fewer colours competing.
   ========================================================================= */
:root{
  /* Emaar's structure — a single ramp, near-black headings, one accent — carried
     onto water. The Oasis is built around swimmable lagoons and waterways, so the
     ramp runs from shallow water at the ground to deep sea in the ink, and the one
     accent is the lagoon blue rather than the CTA navy. Warm clay and sand stay in
     the series colours: four blues would be four unreadable lines. */
  --ground:#F1F7FA; --surface:#FFFFFF; --raised:#E4EFF5; --sunk:#F6FAFC;
  --line:#D5E5EE; --line-soft:#E6F0F5;
  --ink:#07232F; --ink-2:#2C5567; --ink-3:#6F8FA0;
  --accent:#0F6D99; --accent-ink:#FFFFFF; --accent-soft:#DDEDF5;
  --grid:#E6F0F5; --context:#BFD6E2; --bench:#8AAABB;
  --vol-a:#CBE2EC; --vol-b:#2A7FA8;
  --s1:#0F6D99; --s2:#B5653C; --s3:#2E8C86; --s4:#B08A3E;
  --up:#0F6D99; --down:#A8503A;
  --ochre:#B26F16; --ochre-soft:#F6EBD9;
  /* Near-flat by design. A hairline separates a panel from the ground; the
     shadow is there to stop a floating element (menu, tooltip, lightbox) from
     dissolving into the page, and nothing else gets one. */
  --shadow:0 1px 2px rgba(14,26,32,.04);
  --shadow-lg:0 1px 3px rgba(14,26,32,.06), 0 12px 32px rgba(14,26,32,.10);
  /* Emaar sets headings in Optima and everything else in Lato. Optima ships with
     macOS, so the display face here is the developer's own with nothing to fetch.
     Lato does not, and this site has to work with no internet — Lato leads the UI
     stack anyway, so it takes over by itself if it is ever installed, and until
     then Avenir Next stands in as the nearest humanist sans on the machine.
     Figures stay monospaced: Emaar has no equivalent and a column of prices has
     to line up. */
  --font-display:Optima,"Optima nova","Gill Sans","Gill Sans MT",Candara,"Trebuchet MS",sans-serif;
  --font-ui:Lato,"Avenir Next",Avenir,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  --font-data:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --bar-h:56px;
  --radius:10px; --radius-sm:7px;
}
@media (prefers-color-scheme:dark){ :root:not([data-theme="light"]){
  --ground:#03161F; --surface:#082530; --raised:#103543; --sunk:#051C26;
  --line:#1A4152; --line-soft:#123543;
  --ink:#E6F2F7; --ink-2:#A8C6D4; --ink-3:#75A0B2;
  --accent:#4FB6DC; --accent-ink:#03161F; --accent-soft:#0C3A4C;
  --grid:#123543; --context:#2E5C70; --bench:#6D93A6;
  --vol-a:#1C4A63; --vol-b:#4FB6DC;
  --s1:#4FB6DC; --s2:#D9845C; --s3:#54B3AB; --s4:#CBA75E;
  --up:#4FB6DC; --down:#DE8A70;
  --ochre:#D9A25C; --ochre-soft:#332715;
  --shadow:0 1px 2px rgba(0,0,0,.35);
  --shadow-lg:0 1px 3px rgba(0,0,0,.4), 0 12px 32px rgba(0,0,0,.45);
}}
:root[data-theme="dark"]{
  --ground:#03161F; --surface:#082530; --raised:#103543; --sunk:#051C26;
  --line:#1A4152; --line-soft:#123543;
  --ink:#E6F2F7; --ink-2:#A8C6D4; --ink-3:#75A0B2;
  --accent:#4FB6DC; --accent-ink:#03161F; --accent-soft:#0C3A4C;
  --grid:#123543; --context:#2E5C70; --bench:#6D93A6;
  --vol-a:#1C4A63; --vol-b:#4FB6DC;
  --s1:#4FB6DC; --s2:#D9845C; --s3:#54B3AB; --s4:#CBA75E;
  --up:#4FB6DC; --down:#DE8A70;
  --ochre:#D9A25C; --ochre-soft:#332715;
  --shadow:0 1px 2px rgba(0,0,0,.35);
  --shadow-lg:0 1px 3px rgba(0,0,0,.4), 0 12px 32px rgba(0,0,0,.45);
}

*{box-sizing:border-box}
html{color-scheme:light dark}
body{margin:0;background:var(--ground);color:var(--ink);
  font-family:var(--font-ui);font-size:15px;line-height:1.55;-webkit-font-smoothing:antialiased}
body.app{height:100vh;overflow:hidden;display:flex;flex-direction:column}
.num{font-family:var(--font-data);font-variant-numeric:tabular-nums}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:6px}
a{color:var(--accent)}

/* ---------------- top bar ----------------
   Named .topbar, not .bar. A page's chart owns .bar for its rects, and a CSS rule
   beats an SVG presentation attribute — a plain .bar here silently gave every bar
   in the volume chart the height of the header. */
.topbar{position:sticky;top:0;z-index:40;display:flex;align-items:center;gap:20px;
  height:var(--bar-h);padding:0 22px;
  /* Emaar's header is not opaque — it is the page ground at .65 alpha over a 3px
     blur, so the render underneath stays faintly visible as it scrolls past. */
  background:color-mix(in srgb, var(--surface) 65%, transparent);
  backdrop-filter:blur(3px) saturate(1.4);
  -webkit-backdrop-filter:blur(3px) saturate(1.4);
  border-bottom:1px solid var(--line-soft);flex:none}
@supports not (backdrop-filter:blur(3px)){ .topbar{background:var(--surface)} }
body.app .topbar{position:relative}
.mark{display:flex;align-items:baseline;gap:8px;text-decoration:none;color:inherit;flex:none}
.mark b{font-family:var(--font-display);font-size:18px;font-weight:400;letter-spacing:.01em;text-transform:uppercase}
.mark span{font-family:var(--font-data);font-size:9px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--ink-3)}

/* Tabs carry no fill. The current page is named by ink and a hairline under the
   word itself — a tinted pill in a tray was the loudest object in the chrome and
   it was competing with the data for attention. */
nav.tabs{display:flex;gap:4px;flex:none}
nav.tabs a{font-size:13px;font-weight:500;padding:5px 2px;margin:0 7px;
  color:var(--ink-3);text-decoration:none;white-space:nowrap;
  border-bottom:1.5px solid transparent;transition:color var(--dur) var(--ease),border-color var(--dur) var(--ease)}
nav.tabs a[aria-current="page"]{color:var(--ink);border-bottom-color:var(--ink)}
nav.tabs a:hover:not([aria-current="page"]){color:var(--ink-2)}
.topbar .grow{flex:1}

/* The credit sits on every page because it lives in the shell, not in one document.
   It is the first thing to go when the bar gets tight — the tabs and the search box
   are what the page is for. */
.byline{font-family:var(--font-data);font-size:11.5px;letter-spacing:.06em;color:var(--ink-2);
  white-space:nowrap;flex:none}

/* ---------------- shell search ---------------- */
.find{position:relative;flex:none;width:280px;max-width:38vw}
.find input{width:100%;font-family:var(--font-ui);font-size:13px;padding:7px 11px 7px 30px;
  border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--sunk);color:var(--ink);
  transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease)}
.find input::placeholder{color:var(--ink-3)}
.find input:focus{background:var(--surface);border-color:var(--ink-3)}
.find svg.mag{position:absolute;left:9px;top:50%;transform:translateY(-50%);
  width:14px;height:14px;stroke:var(--ink-3);fill:none;stroke-width:1.8;pointer-events:none}
.find kbd{position:absolute;right:8px;top:50%;transform:translateY(-50%);
  font-family:var(--font-data);font-size:10px;color:var(--ink-3);border:1px solid var(--line);
  border-radius:4px;padding:1px 5px;background:var(--surface);pointer-events:none}
.find input:focus + kbd,.find input:not(:placeholder-shown) + kbd{display:none}
.hits{position:absolute;top:calc(100% + 6px);left:0;right:0;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-lg);
  max-height:min(60vh,420px);overflow-y:auto;z-index:50;padding:5px;display:none}
.hits.on{display:block}
.hits button{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
  width:100%;text-align:left;background:none;border:0;border-radius:var(--radius-sm);padding:7px 9px;
  cursor:pointer;color:var(--ink);font-family:var(--font-ui);font-size:13px}
.hits button:hover,.hits button.cursor{background:var(--sunk)}
.hits .hn{font-weight:600;font-size:13px;line-height:1.3}
.hits .hm{font-family:var(--font-data);font-size:10.5px;color:var(--ink-3);display:block;margin-top:1px}
.hits .hx{font-family:var(--font-data);font-size:10px;color:var(--ink-3);white-space:nowrap;flex:none}
.hits .grp{font-family:var(--font-data);font-size:9px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-3);padding:9px 9px 4px}
.hits .none{padding:12px 10px;color:var(--ink-3);font-size:13px}

/* ---------------- buttons ---------------- */
.ghost{font-family:var(--font-ui);font-size:12px;padding:5px 11px;border:1px solid var(--line);
  border-radius:var(--radius-sm);background:var(--surface);color:var(--ink-2);cursor:pointer;
  text-decoration:none;display:inline-flex;align-items:center;gap:5px;white-space:nowrap;
  transition:border-color var(--dur) var(--ease),color var(--dur) var(--ease)}
.ghost:hover{background:var(--surface);border-color:var(--ink-3);color:var(--ink)}
.ghost.icon{width:30px;height:30px;padding:0;justify-content:center;font-size:14px;flex:none}

/* ---------------- privacy banner ----------------
   */
.confid{background:var(--ochre);color:#fff;font-family:var(--font-data);font-size:10px;
  letter-spacing:.14em;text-transform:uppercase;padding:5px 16px;text-align:center;flex:none}

/* ---------------- document layout ---------------- */
.wrap{max-width:1140px;margin:0 auto;padding:0 24px 100px;display:flex;flex-direction:column;gap:30px}
/* A flex or grid child defaults to min-width:auto, so one wide table or chart inside a
   panel stretches the whole column and the document scrolls sideways. Let them shrink and
   let their own overflow:auto do the scrolling instead. */
.wrap > *{min-width:0}
.eyebrow{font-family:var(--font-data);font-size:10px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--ink-3)}
/* Emaar sets its page title in Optima at 46/57.5, uppercase, regular weight and
   no tracking. Optima carries that at size; bolding it or tightening it is what
   makes it look like a substitute for something else. The title is uppercase and
   the section heads are not — all-caps reads as a nameplate once on a page and as
   shouting six times down a dense one. */
h1{font-family:var(--font-display);font-weight:400;font-size:44px;line-height:1.16;margin:0;
  letter-spacing:.005em;text-transform:uppercase;text-wrap:balance}
h1 em{font-style:normal;font-weight:400;color:var(--ink-3)}
h2{font-family:var(--font-display);font-size:27px;font-weight:400;margin:0;letter-spacing:.004em}
.lede{margin:0;color:var(--ink-2);font-size:15px;max-width:62ch;line-height:1.6}
.panel{background:var(--surface);border:1px solid var(--line-soft);border-radius:var(--radius);
  box-shadow:none;overflow:hidden}
.secthead{display:flex;flex-direction:column;gap:8px;margin-top:14px}
footer{border-top:1px solid var(--line-soft);padding-top:18px;font-size:12px;
  color:var(--ink-3);line-height:1.7}
.up{color:var(--up)} .down{color:var(--down)}

/* Owner return. The sample size sits inside the figure rather than beside it, because
   a median over three villas and one over thirty-nine are not the same claim and the
   count is the only thing that says so. Under ten pairs the number is dimmed. */
.ret{display:inline-flex;align-items:baseline;gap:6px;white-space:nowrap}
.ret b{font-weight:600}
.ret .rn{font-family:var(--font-data);font-size:10px;color:var(--ink-3);letter-spacing:.02em}
.ret.thin b{opacity:.66;font-weight:530}
.ret.thin .rn{color:var(--down);opacity:.8}
.ret.none{color:var(--ink-3)}

/* ---------------- shared chart furniture ---------------- */
svg.chart{display:block;width:100%;height:auto;overflow:visible}
.grid line{stroke:var(--grid);stroke-width:1}
.axis text{font-family:var(--font-data);font-size:9.5px;fill:var(--ink-3)}
.crosshair{stroke:var(--ink-3);stroke-width:1;stroke-dasharray:3 3;opacity:.7}
.tip{position:absolute;pointer-events:none;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);box-shadow:var(--shadow-lg);padding:10px 13px;font-size:12.5px;
  min-width:150px;z-index:20}
.tip .t{font-family:var(--font-data);font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);margin-bottom:5px}
.tip .r{display:flex;align-items:center;gap:7px;justify-content:space-between;padding:1.5px 0}
.tip .r b{font-variant-numeric:tabular-nums;font-family:var(--font-data);font-size:12px}
.tip .sw{width:9px;height:9px;border-radius:2px;flex:none}

/* Below ~820px the five tabs plus the wordmark are wider than the screen, and both are
   flex:none — left alone they set a min-content width on the whole document and every page
   scrolls sideways. Give the tabs their own full-width row, scrollable if even that is tight. */
@media (max-width:1240px){ .byline{display:none} }
@media (max-width:820px){
  .topbar{flex-wrap:wrap;height:auto;padding:10px 16px;gap:10px}
  body.app .topbar{flex-wrap:wrap}
  .mark{order:1}
  .topbar > .ghost.icon{order:2;margin-left:auto}
  nav.tabs{order:3;flex:1 1 100%;overflow-x:auto;scrollbar-width:none}
  nav.tabs::-webkit-scrollbar{display:none}
  nav.tabs a{margin:0 10px 0 0}
  .find{order:4;width:100%;max-width:none;flex:1 1 100%}
  .topbar .grow{display:none}
  h1{font-size:29px}
  .wrap{padding:0 18px 76px;gap:24px}
}
/* A wide chart shrunk to phone width is unreadable — let it keep its size and scroll.
   Kept below the header breakpoint so a small laptop window still gets a fitted chart,
   and the hover tooltip goes with it: overflow-x makes overflow-y scroll too, which would
   clip the tip, and on a touch screen the pinned readout does that job anyway. */
@media (max-width:700px){
  .chartscroll{overflow-x:auto}
  .chartscroll > svg.chart{min-width:660px}
  .chartscroll .tip{display:none!important}
}

/* ---------------- motion ----------------
   Smooth scrolling for anchor jumps and the deep links, plus a reveal as sections
   come up. Every hiding rule below is gated on .motion, a class only shell.js adds
   after it has confirmed an observer exists and the machine has not asked for
   reduced motion. Nothing on a page is ever hidden unless JavaScript is running to
   put it back: a data page left blank because an observer did not fire is a broken
   page, not a subtle one. shell.js also force-reveals everything after 1.6s. */
html{scroll-behavior:smooth}

.motion .reveal{opacity:0;transform:translateY(14px);
  transition:opacity .52s cubic-bezier(.22,.61,.36,1), transform .52s cubic-bezier(.22,.61,.36,1)}
.motion .reveal.in{opacity:1;transform:none}
.motion .topbar{animation:shell-in .4s cubic-bezier(.22,.61,.36,1) both}
@keyframes shell-in{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}

/* Interactive things say so by moving a little, and only on the properties that
   are cheap to animate. */
.hits{animation:pop-in .16s ease-out both}
@keyframes pop-in{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
.tip{transition:opacity .12s ease-out}

/* ---- motion layer: grids arrive, charts draw, a progress hairline ----
   Same contract as .reveal above: every hiding rule here is put in place by
   shell.js at runtime (inline style, or a class it adds), never by the stylesheet
   alone, so a page with no JavaScript renders complete. shell.js also clears each
   pre-state on a timer in case an observer never fires. */
.m-item{opacity:0;transform:translateY(10px);
  transition:opacity .5s cubic-bezier(.22,.61,.36,1) var(--d,0ms),
             transform .5s cubic-bezier(.22,.61,.36,1) var(--d,0ms)}
.m-item.in{opacity:1;transform:none}

/* A bar grows out of its own baseline. transform-box is what makes a percentage
   transform-origin mean the rect's own box rather than the whole SVG viewport. */
rect.m-bar{transform:scaleY(0);transform-box:fill-box;transform-origin:50% 100%;
  transition:transform .5s cubic-bezier(.22,.61,.36,1) var(--d,0ms)}
rect.m-bar.in{transform:none}

/* Markers wait for the line they sit on to finish drawing. */
circle.m-mk{opacity:0;transition:opacity .35s ease-out var(--d,420ms)}
circle.m-mk.in{opacity:1}

/* A card lifts a little under the pointer. Transform and shadow only, so it stays
   on the compositor and never reflows the grid it sits in. */
.sm,.m-lift{transition:transform .22s cubic-bezier(.22,.61,.36,1),
  box-shadow .22s cubic-bezier(.22,.61,.36,1),border-color .22s ease-out}
.sm:hover,.m-lift:hover{transform:translateY(-2px)}

.scrollprog{position:fixed;left:0;top:0;height:2px;width:100%;z-index:60;
  background:var(--accent);transform:scaleX(0);transform-origin:0 50%;
  pointer-events:none;will-change:transform}
body.app .scrollprog{display:none}

/* The whole layer is off when the machine asks for it. Kept last so it wins. */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .motion .reveal{opacity:1;transform:none}
  .m-item{opacity:1;transform:none}
  rect.m-bar{transform:none}
  circle.m-mk{opacity:1}
  .scrollprog{display:none}
  *,*::before,*::after{
    animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
}

/* ---------------- hero band ----------------
   Emaar's own community pages open on a full-bleed image with the title on clean
   ground underneath, never over the picture. Same structure here: the band is a
   ::before on the existing masthead, so no page markup changes, and it fades into
   --ground at the bottom so the title never has to fight the render for contrast.

   A page opts in by setting two custom properties in its own stylesheet:
     --hero:        url(assets/hero-mirage.jpg)
   A page that sets neither gets no band and keeps its original spacing.

   The credit is not decoration. These are the developer's marketing renders of one
   specific cluster, and this site's whole habit is to say which cluster a drawing
   came from rather than let one stand in for another. */
header.hero{position:relative}
header.hero[style], header.hero{--hero-h:clamp(190px,24vw,320px)}

body:has(header.hero) { overflow-x:clip }   /* the band runs full-bleed past .wrap */

header.hero::before{
  content:"";
  display:var(--hero-display,none);
  position:absolute;top:0;left:50%;transform:translateX(-50%);
  width:100vw;height:var(--hero-h);
  background-image:
    linear-gradient(to bottom, rgba(3,22,31,.20) 0%, rgba(3,22,31,0) 42%, var(--ground) 97%),
    var(--hero, none);
  background-size:cover,cover;
  background-position:center 42%,center 42%;
  background-repeat:no-repeat;
  z-index:0;pointer-events:none;
  transform:translateX(-50%) translate3d(0,var(--hero-shift,0px),0);
  will-change:transform;
}
/* Any page that declares --hero turns both pseudo-elements on and makes room. */
header.hero{padding-block:var(--hero-pad-top,56px) 8px}

/* ---- public build: contact (added by publish.py) ---- */
.wa-fab{position:fixed;right:18px;bottom:18px;z-index:60;display:flex;align-items:center;gap:8px;
  background:#1FAF55;color:#fff;text-decoration:none;font-weight:600;font-size:14px;
  padding:12px 18px 12px 14px;border-radius:999px;box-shadow:0 6px 20px rgba(0,0,0,.22)}
.wa-fab svg{width:22px;height:22px;flex:none}
.wa-fab:hover{background:#179647;color:#fff}
.wa-fab{transition:opacity .2s, transform .2s}
.wa-fab.away{opacity:0;transform:translateY(12px);pointer-events:none}
@media (max-width:640px){
  .wa-fab{padding:14px;right:14px;bottom:14px}
  .wa-fab span{display:none}
}
.contact{margin:48px 0 24px;border:1px solid var(--line-soft);border-radius:14px;
  background:var(--surface);padding:26px 28px}
.contact-in{display:grid;grid-template-columns:minmax(180px,240px) 1fr;gap:10px 28px;align-items:start}
.contact .who{display:flex;flex-direction:column;gap:3px}
.contact .who b{font-size:18px;color:var(--ink)}
.contact .who span{color:var(--ink-2);font-size:13.5px}
.contact .who .brn{color:var(--ink-3);font-family:var(--font-data);font-size:11px;letter-spacing:.08em}
.contact p{margin:0;color:var(--ink-2);line-height:1.55;max-width:62ch}
.contact .acts{grid-column:2;display:flex;flex-wrap:wrap;gap:10px;margin-top:8px}
.contact .btn{display:inline-flex;align-items:center;gap:7px;padding:10px 16px;border-radius:999px;
  text-decoration:none;font-weight:600;font-size:14px;background:var(--accent);color:var(--accent-ink)}
.contact .btn.wa{background:#1FAF55;color:#fff}
.contact .btn.wa svg{width:18px;height:18px}
.contact .btn.ghostline{background:transparent;color:var(--ink);border:1px solid var(--line-soft)}
@media (max-width:720px){
  .contact{padding:22px 18px}
  .contact-in{grid-template-columns:1fr}
  .contact .acts{grid-column:1}
  .contact .btn{flex:1 1 100%;justify-content:center}
}
/* keep the floating button clear of the last line of content */
body{padding-bottom:72px}
