{"id":36404,"date":"2026-04-07T11:58:14","date_gmt":"2026-04-07T07:58:14","guid":{"rendered":"https:\/\/truhauz.com\/?page_id=36404"},"modified":"2026-04-07T17:57:46","modified_gmt":"2026-04-07T13:57:46","slug":"new-projects","status":"publish","type":"page","link":"https:\/\/truhauz.com\/fa\/new-projects\/","title":{"rendered":"\u067e\u0631\u0648\u0698\u0647\u200c\u0647\u0627\u06cc \u062c\u062f\u06cc\u062f"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"36404\" class=\"elementor elementor-36404\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-061e8c0 e-flex e-con-boxed e-con e-parent\" data-id=\"061e8c0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-cef770a elementor-widget elementor-widget-html\" data-id=\"cef770a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- ============================================================\n     TruHauz \u00d7 Reelly.ai \u2014 Projects Grid\n     Paste into a WordPress Custom HTML block.\n     Requires: truhauz-reelly-plugin.php to be installed & active.\n     ============================================================ -->\n\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Playfair+Display:wght@600;700&family=Inter:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">\n\n<style>\n.trly-wrap *, .trly-wrap *::before, .trly-wrap *::after { box-sizing: border-box; margin: 0; padding: 0; }\n.trly-wrap a { text-decoration: none; color: inherit; }\n\n\/* Full-width stretch *\/\n.trly-wrap {\n  width: 100vw;\n  position: relative;\n  left: 50%;\n  transform: translateX(-50%);\n  margin-left: 0 !important;\n  margin-right: 0 !important;\n  max-width: none !important;\n  font-family: 'Inter', sans-serif;\n  background: #fff;\n  overflow-x: hidden;\n}\n\n\/* \u2500\u2500 Header \u2500\u2500 *\/\n.trly-header {\n  background: linear-gradient(135deg, #660033 0%, #3a0020 100%);\n  padding: 60px 24px 50px;\n  text-align: center;\n}\n.trly-badge {\n  display: inline-block;\n  background: rgba(255,255,255,0.15);\n  border: 1px solid rgba(255,255,255,0.35);\n  color: #fff;\n  font-size: 0.7rem;\n  font-weight: 700;\n  letter-spacing: 2px;\n  text-transform: uppercase;\n  padding: 5px 16px;\n  border-radius: 20px;\n  margin-bottom: 16px;\n}\n.trly-header h1 {\n  font-family: 'Playfair Display', serif;\n  font-size: clamp(1.8rem, 4.5vw, 2.8rem);\n  color: #fff;\n  margin-bottom: 12px;\n  line-height: 1.2;\n}\n.trly-header p {\n  color: rgba(255,255,255,0.75);\n  font-size: 1rem;\n  max-width: 600px;\n  margin: 0 auto;\n  line-height: 1.6;\n}\n\n\/* \u2500\u2500 Filters \u2500\u2500 *\/\n.trly-filters {\n  background: #f9f4f6;\n  padding: 24px 24px;\n  border-bottom: 1px solid #f0e0e8;\n}\n.trly-filters-inner {\n  max-width: 1200px;\n  margin: 0 auto;\n  display: flex;\n  flex-wrap: wrap;\n  gap: 12px;\n  justify-content: center;\n}\n.trly-filters input, .trly-filters select {\n  font-family: 'Inter', sans-serif;\n  font-size: 0.88rem;\n  padding: 11px 14px;\n  border: 1px solid #e0d0d8;\n  border-radius: 8px;\n  background: #fff;\n  color: #333;\n  min-width: 170px;\n  outline: none;\n  transition: border-color 0.2s;\n}\n.trly-filters input:focus, .trly-filters select:focus { border-color: #660033; }\n.trly-filters button {\n  font-family: 'Inter', sans-serif;\n  font-size: 0.88rem;\n  font-weight: 700;\n  padding: 11px 24px;\n  background: #660033;\n  color: #fff !important;\n  border: none;\n  border-radius: 8px;\n  cursor: pointer;\n  transition: background 0.2s;\n}\n.trly-filters button:hover { background: #3a0020; }\n.trly-filters button.trly-clear { background: #fff; color: #660033 !important; border: 1px solid #660033; }\n.trly-filters button.trly-clear:hover { background: #f0e0e8; }\n\n\/* \u2500\u2500 Grid \u2500\u2500 *\/\n.trly-grid-section { background: #fff; padding: 50px 24px; }\n.trly-grid-inner   { max-width: 1200px; margin: 0 auto; }\n.trly-meta-bar {\n  display: flex; justify-content: space-between; align-items: center;\n  margin-bottom: 24px; flex-wrap: wrap; gap: 10px;\n}\n.trly-count { color: #660033; font-weight: 600; font-size: 0.9rem; }\n.trly-grid {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));\n  gap: 26px;\n}\n\n\/* \u2500\u2500 Card \u2500\u2500 *\/\n.trly-card {\n  background: #fff;\n  border-radius: 14px;\n  overflow: hidden;\n  border: 1px solid #f0e0e8;\n  box-shadow: 0 4px 18px rgba(102,0,51,0.06);\n  transition: transform 0.25s, box-shadow 0.25s;\n  display: flex; flex-direction: column;\n  text-decoration: none !important;\n  color: inherit !important;\n  cursor: pointer;\n}\n.trly-card:hover, .trly-card:focus, .trly-card:visited { color: inherit !important; text-decoration: none !important; }\n.trly-card:hover {\n  transform: translateY(-4px);\n  box-shadow: 0 12px 36px rgba(102,0,51,0.16);\n}\n.trly-card-img {\n  width: 100%; height: 220px;\n  background: linear-gradient(135deg, #660033 0%, #3a0020 100%);\n  background-size: cover; background-position: center;\n  position: relative;\n}\n.trly-card-tag {\n  position: absolute; top: 14px; left: 14px;\n  background: rgba(255,255,255,0.95);\n  color: #660033;\n  font-size: 0.7rem;\n  font-weight: 700;\n  padding: 5px 12px;\n  border-radius: 20px;\n  text-transform: uppercase;\n  letter-spacing: 0.5px;\n}\n.trly-card-body { padding: 22px; flex: 1; display: flex; flex-direction: column; }\n.trly-card-dev { color: #aa6688; font-size: 0.72rem; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 6px; }\n.trly-card h3 {\n  font-family: 'Playfair Display', serif;\n  font-size: 1.3rem;\n  color: #660033;\n  margin-bottom: 8px;\n  line-height: 1.25;\n}\n.trly-card-loc { color: #888; font-size: 0.85rem; margin-bottom: 14px; display: flex; align-items: center; gap: 6px; }\n.trly-card-specs {\n  display: flex; gap: 14px; flex-wrap: wrap;\n  padding: 12px 0;\n  border-top: 1px solid #f0e0e8;\n  border-bottom: 1px solid #f0e0e8;\n  margin-bottom: 14px;\n  font-size: 0.78rem;\n  color: #666;\n}\n.trly-card-specs span { display: flex; align-items: center; gap: 4px; }\n.trly-card-price { color: #660033; font-weight: 700; font-size: 1.1rem; margin-bottom: 16px; }\n.trly-card-price small { color: #888; font-weight: 500; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.5px; display: block; }\n.trly-card-btn {\n  margin-top: auto;\n  display: block;\n  text-align: center;\n  padding: 11px;\n  background: #660033;\n  color: #fff !important;\n  border-radius: 8px;\n  font-weight: 700;\n  font-size: 0.85rem;\n  transition: background 0.2s;\n  text-transform: uppercase;\n  letter-spacing: 0.5px;\n}\n.trly-card-btn:hover { background: #3a0020; }\n\n\/* \u2500\u2500 States \u2500\u2500 *\/\n.trly-loading, .trly-empty, .trly-error {\n  text-align: center;\n  padding: 70px 24px;\n  color: #999;\n  font-size: 0.95rem;\n}\n.trly-spinner {\n  width: 38px; height: 38px;\n  border: 3px solid #f0e0e8;\n  border-top-color: #660033;\n  border-radius: 50%;\n  margin: 0 auto 18px;\n  animation: trly-spin 0.9s linear infinite;\n}\n@keyframes trly-spin { to { transform: rotate(360deg); } }\n.trly-error { color: #b00; }\n\n\/* \u2500\u2500 Modal \u2500\u2500 *\/\n.trly-modal-overlay {\n  position: fixed; inset: 0;\n  background: rgba(20, 0, 10, 0.78);\n  z-index: 99999;\n  display: none !important;\n  align-items: flex-start;\n  justify-content: center;\n  padding: 40px 20px;\n  overflow-y: auto;\n  -webkit-overflow-scrolling: touch;\n}\n.trly-modal-overlay.open { display: flex; }\n.trly-modal {\n  background: #fff;\n  border-radius: 16px;\n  max-width: 900px;\n  width: 100%;\n  position: relative;\n  box-shadow: 0 30px 80px rgba(0,0,0,0.45);\n  overflow: hidden;\n  animation: trly-pop 0.25s ease;\n}\n@keyframes trly-pop { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }\n.trly-modal-close {\n  position: absolute; top: 14px; right: 14px;\n  width: 38px; height: 38px;\n  border-radius: 50%;\n  background: rgba(255,255,255,0.95);\n  border: none;\n  font-size: 22px;\n  cursor: pointer;\n  z-index: 5;\n  color: #660033;\n  font-weight: 700;\n  box-shadow: 0 2px 10px rgba(0,0,0,0.2);\n}\n.trly-modal-hero {\n  width: 100%; height: 320px;\n  background: linear-gradient(135deg,#660033,#3a0020);\n  background-size: cover; background-position: center;\n}\n.trly-modal-body { padding: 30px 36px 36px; }\n.trly-modal-dev { color: #aa6688; font-size: 0.78rem; font-weight: 600; text-transform: uppercase; letter-spacing: 1.5px; margin-bottom: 8px; }\n.trly-modal-body h2 {\n  font-family: 'Playfair Display', serif;\n  font-size: clamp(1.6rem, 3vw, 2.2rem);\n  color: #660033;\n  margin-bottom: 8px;\n  line-height: 1.2;\n}\n.trly-modal-loc { color: #888; font-size: 0.95rem; margin-bottom: 22px; }\n.trly-modal-stats {\n  display: grid;\n  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n  gap: 14px;\n  padding: 18px;\n  background: #f9f4f6;\n  border-radius: 12px;\n  margin-bottom: 24px;\n}\n.trly-modal-stat { text-align: center; }\n.trly-modal-stat strong {\n  display: block;\n  font-family: 'Playfair Display', serif;\n  font-size: 1.25rem;\n  color: #660033;\n  margin-bottom: 2px;\n}\n.trly-modal-stat span { font-size: 0.7rem; color: #888; text-transform: uppercase; letter-spacing: 1px; }\n.trly-modal-section { margin-bottom: 22px; }\n.trly-modal-section h4 {\n  font-family: 'Playfair Display', serif;\n  color: #660033;\n  font-size: 1.05rem;\n  margin-bottom: 8px;\n  padding-bottom: 6px;\n  border-bottom: 1px solid #f0e0e8;\n}\n.trly-modal-section p, .trly-modal-section li { color: #555; font-size: 0.9rem; line-height: 1.65; }\n.trly-modal-section ul { list-style: none; }\n.trly-modal-section li { padding: 4px 0; }\n.trly-modal-section li::before { content: '\u2713'; color: #660033; font-weight: 700; margin-right: 8px; }\n.trly-modal-gallery {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\n  gap: 8px;\n  margin-top: 12px;\n}\n.trly-modal-gallery img {\n  width: 100%; height: 100px;\n  object-fit: cover;\n  border-radius: 8px;\n  cursor: pointer;\n  transition: transform 0.2s;\n}\n.trly-modal-gallery img:hover { transform: scale(1.04); }\n.trly-modal-actions {\n  display: flex; gap: 12px; flex-wrap: wrap;\n  margin-top: 22px;\n}\n.trly-modal-actions a {\n  flex: 1; min-width: 180px;\n  padding: 14px;\n  text-align: center;\n  background: #660033;\n  color: #fff !important;\n  font-weight: 700;\n  font-size: 0.85rem;\n  text-transform: uppercase;\n  letter-spacing: 0.5px;\n  border-radius: 8px;\n  transition: background 0.2s;\n}\n.trly-modal-actions a.secondary { background: #fff; color: #660033 !important; border: 2px solid #660033; }\n.trly-modal-actions a:hover { background: #3a0020; }\n.trly-modal-actions a.secondary:hover { background: #f0e0e8; }\n.trly-modal-loading { padding: 80px 20px; text-align: center; color: #999; }\n\n\/* Card click affordance *\/\n.trly-card { cursor: pointer; }\n\n\/* \u2500\u2500 Pagination \u2500\u2500 *\/\n.trly-pagination {\n  text-align: center;\n  margin-top: 40px;\n}\n.trly-pagination button {\n  font-family: 'Inter', sans-serif;\n  padding: 13px 32px;\n  background: #660033;\n  color: #fff !important;\n  border: none;\n  border-radius: 8px;\n  font-weight: 700;\n  font-size: 0.88rem;\n  cursor: pointer;\n  text-transform: uppercase;\n  letter-spacing: 0.5px;\n  transition: background 0.2s;\n}\n.trly-pagination button:hover { background: #3a0020; }\n.trly-pagination button:disabled { background: #ccc; cursor: not-allowed; }\n\n\/* \u2500\u2500 CTA \u2500\u2500 *\/\n.trly-cta {\n  background: linear-gradient(135deg, #660033 0%, #3a0020 100%);\n  padding: 60px 24px;\n  text-align: center;\n}\n.trly-cta h3 {\n  font-family: 'Playfair Display', serif;\n  font-size: clamp(1.5rem, 3.2vw, 2.1rem);\n  color: #fff;\n  margin-bottom: 12px;\n}\n.trly-cta p {\n  color: rgba(255,255,255,0.75);\n  font-size: 0.95rem;\n  margin-bottom: 30px;\n  max-width: 480px;\n  margin-left: auto;\n  margin-right: auto;\n}\n.trly-btn {\n  display: inline-block;\n  padding: 14px 34px;\n  border: 2px solid rgba(255,255,255,0.7);\n  background: rgba(255,255,255,0.12);\n  color: #fff !important;\n  font-weight: 700;\n  font-size: 0.88rem;\n  border-radius: 8px;\n  margin: 6px;\n  transition: background 0.2s, border-color 0.2s;\n}\n.trly-btn:hover { background: rgba(255,255,255,0.22); border-color: #fff; }\n\n@media (max-width: 640px) {\n  .trly-header { padding: 44px 20px 40px; }\n  .trly-grid { grid-template-columns: 1fr; }\n  .trly-filters input, .trly-filters select { min-width: 100%; }\n}\n<\/style>\n\n<div class=\"trly-wrap\">\n\n  <!-- HEADER -->\n  <div class=\"trly-header\">\n    <div class=\"trly-badge\">Live Inventory \u00b7 Reelly.ai<\/div>\n    <h1>Off-Plan Projects in Dubai<\/h1>\n    <p>Browse the latest off-plan developments from Dubai's leading developers, updated in real time from our partner database.<\/p>\n  <\/div>\n\n  <!-- FILTERS -->\n  <div class=\"trly-filters\">\n    <div class=\"trly-filters-inner\">\n      <input id=\"trly-search\"    type=\"text\"   placeholder=\"Search project name\u2026\">\n      <input id=\"trly-developer\" type=\"text\"   placeholder=\"Developer (e.g. Emaar)\">\n      <input id=\"trly-area\"      type=\"text\"   placeholder=\"Area (e.g. Dubai Hills)\">\n      <select id=\"trly-bedrooms\">\n        <option value=\"\">All Bedrooms<\/option>\n        <option value=\"1\">1 BR<\/option>\n        <option value=\"2\">2 BR<\/option>\n        <option value=\"3\">3 BR<\/option>\n        <option value=\"4\">4 BR<\/option>\n        <option value=\"5\">5+ BR<\/option>\n      <\/select>\n      <select id=\"trly-status\">\n        <option value=\"\">All Statuses<\/option>\n        <option value=\"Available\">Available<\/option>\n        <option value=\"Sold Out\">Sold Out<\/option>\n        <option value=\"Coming Soon\">Coming Soon<\/option>\n      <\/select>\n      <button id=\"trly-apply\">Search<\/button>\n      <button class=\"trly-clear\" id=\"trly-reset\">Reset<\/button>\n    <\/div>\n  <\/div>\n\n  <!-- GRID -->\n  <div class=\"trly-grid-section\">\n    <div class=\"trly-grid-inner\">\n      <div class=\"trly-meta-bar\">\n        <div class=\"trly-count\" id=\"trly-count\">Loading projects\u2026<\/div>\n      <\/div>\n      <div id=\"trly-grid\" class=\"trly-grid\">\n        <div class=\"trly-loading\">\n          <div class=\"trly-spinner\"><\/div>\n          Loading projects from Reelly\u2026\n        <\/div>\n      <\/div>\n      <div class=\"trly-pagination\">\n        <button id=\"trly-more\" style=\"display:none;\">Load More<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  <!-- CTA -->\n  <div class=\"trly-cta\">\n    <h3>Found Something You Like?<\/h3>\n    <p>Get exclusive floor plans, payment plans, and unit availability from our team.<\/p>\n    <a class=\"trly-btn\" href=\"https:\/\/truhauz.com\/contact\/\">Talk to an Expert<\/a>\n    <a class=\"trly-btn\" href=\"https:\/\/truhauz.com\/search-results\/\">View All Listings<\/a>\n  <\/div>\n\n  <!-- MODAL -->\n  <div class=\"trly-modal-overlay\" id=\"trly-modal-overlay\">\n    <div class=\"trly-modal\" id=\"trly-modal\">\n      <button class=\"trly-modal-close\" id=\"trly-modal-close\" aria-label=\"Close\">\u00d7<\/button>\n      <div id=\"trly-modal-content\"><\/div>\n    <\/div>\n  <\/div>\n\n<\/div><!-- \/trly-wrap -->\n\n<script>\n(function () {\n  \/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n     CONFIG \u2014 points at the WP plugin's REST endpoint.\n     The API key stays SECRET on the server (in the plugin).\n     \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  var ENDPOINT = '\/wp-json\/truhauz\/v1\/projects';\n  var PER_PAGE = 20;          \/\/ Reelly's actual max page size (server-enforced)\n  var page     = 1;\n  var loaded   = 0;           \/\/ total cards loaded so far\n  var totalAll = 0;           \/\/ total reported by API\n  var current  = {};\n  var projectCache = {};      \/\/ id \u2192 full project object from list\n\n  var grid     = document.getElementById('trly-grid');\n  var countEl  = document.getElementById('trly-count');\n  var moreBtn  = document.getElementById('trly-more');\n\n  function fmtPrice(p, currency) {\n    if (p == null || p === '') return '\u2014';\n    var n = Number(p);\n    if (isNaN(n)) return p;\n    var cur = currency || 'AED';\n    if (n >= 1e6) return cur + ' ' + (n \/ 1e6).toFixed(2) + 'M';\n    if (n >= 1e3) return cur + ' ' + (n \/ 1e3).toFixed(0) + 'K';\n    return cur + ' ' + n.toLocaleString();\n  }\n\n  \/\/ Pull a string out of a value that might be a string OR an object with .name\n  function asText(v) {\n    if (v == null) return '';\n    if (typeof v === 'string' || typeof v === 'number') return String(v);\n    if (typeof v === 'object') {\n      if (v.name || v.title || v.label) return v.name || v.title || v.label;\n      \/\/ Reelly's location object: { district, sector, region, city }\n      var bits = [v.district, v.sector, v.city, v.region].filter(function (x) {\n        return x && typeof x === 'string';\n      });\n      \/\/ De-dup adjacent identical entries\n      var seen = {};\n      bits = bits.filter(function (x) { if (seen[x]) return false; seen[x] = 1; return true; });\n      return bits.join(', ');\n    }\n    return '';\n  }\n\n  \/\/ \"under_construction\" \u2192 \"Under Construction\"\n  function niceLabel(s) {\n    if (!s) return '';\n    return String(s).replace(\/_\/g, ' ').replace(\/\\b\\w\/g, function (c) { return c.toUpperCase(); });\n  }\n\n  \/\/ Strip Reelly's \"#####\" markdown headings + collapse blank lines\n  function cleanMarkdown(s) {\n    if (!s) return '';\n    return String(s)\n      .replace(\/^#{1,6}\\s+\/gm, '')           \/\/ remove leading hashes\n      .replace(\/\\n{3,}\/g, '\\n\\n')            \/\/ collapse extra blank lines\n      .trim();\n  }\n  \/\/ Convert markdown overview into HTML sections (split on headings)\n  function mdToHtml(s) {\n    if (!s) return '';\n    var blocks = String(s).split(\/\\n\\s*\\n\/);\n    var html = '';\n    blocks.forEach(function (b) {\n      b = b.trim();\n      if (!b) return;\n      var m = b.match(\/^#{1,6}\\s+(.+)$\/);\n      if (m) {\n        html += '<h5 style=\"font-family:\\'Playfair Display\\',serif;color:#660033;font-size:1rem;margin:14px 0 4px;\">' + escapeHtml(m[1]) + '<\/h5>';\n      } else {\n        html += '<p style=\"margin-bottom:10px;\">' + escapeHtml(b) + '<\/p>';\n      }\n    });\n    return html;\n  }\n\n  function pick(obj, keys, fallback) {\n    for (var i = 0; i < keys.length; i++) {\n      if (obj[keys[i]] != null && obj[keys[i]] !== '') return obj[keys[i]];\n    }\n    return fallback || '';\n  }\n\n  \/\/ RECURSIVE image scanner: walks the entire project object looking for\n  \/\/ ANY string that looks like an image URL. Field-name-agnostic.\n  var IMG_RE = \/\\.(jpe?g|png|webp|gif|avif|svg)(\\?|$)\/i;\n  function isImageUrl(s) {\n    return typeof s === 'string' && \/^https?:\\\/\\\/\/.test(s) && IMG_RE.test(s);\n  }\n  function findAllImages(obj, out, depth) {\n    out = out || [];\n    depth = depth || 0;\n    if (!obj || depth > 6 || out.length > 30) return out;\n    if (typeof obj === 'string') {\n      if (isImageUrl(obj) && out.indexOf(obj) === -1) out.push(obj);\n      return out;\n    }\n    if (Array.isArray(obj)) {\n      for (var i = 0; i < obj.length; i++) findAllImages(obj[i], out, depth + 1);\n      return out;\n    }\n    if (typeof obj === 'object') {\n      \/\/ Prefer common URL keys first\n      ['url','src','href','image','image_url','cover','cover_image','cover_image_url','thumbnail','thumb','photo','picture','main_image']\n        .forEach(function (k) {\n          if (obj[k] != null) findAllImages(obj[k], out, depth + 1);\n        });\n      \/\/ Then walk everything else\n      for (var k in obj) {\n        if (Object.prototype.hasOwnProperty.call(obj, k)) {\n          findAllImages(obj[k], out, depth + 1);\n        }\n      }\n    }\n    return out;\n  }\n  function extractImage(p) {\n    var imgs = findAllImages(p);\n    return imgs[0] || '';\n  }\n\n  function renderCard(p) {\n    var name      = pick(p, ['name','title','project_name'], 'Untitled Project');\n    var developer = asText(pick(p, ['developer','developer_name','dev_name'], ''));\n    var area      = asText(pick(p, ['location','area','address','region'], '')) || 'Dubai';\n    var price     = pick(p, ['min_price','starting_price','price_from','price'], '');\n    var currency  = pick(p, ['price_currency','currency'], 'AED');\n    var size      = pick(p, ['min_size','min_area','area_from','size'], '');\n    var areaUnit  = pick(p, ['area_unit'], 'sqft');\n    var handover  = pick(p, ['completion_date','handover','completion_year','delivery_date'], '');\n    var status    = pick(p, ['sale_status','status','availability'], '');\n    var units     = pick(p, ['units_count','units_in_sale','available_units'], '');\n    var img       = extractImage(p);\n    var id        = pick(p, ['id','project_id','slug'], '');\n\n    \/\/ Format completion_date \"2027-12-31\" \u2192 \"Q4 2027\"\n    if (handover && \/^\\d{4}-\\d{2}\/.test(handover)) {\n      var parts = handover.split('-');\n      var q = Math.ceil(parseInt(parts[1], 10) \/ 3);\n      handover = 'Q' + q + ' ' + parts[0];\n    }\n\n    var imgStyle = img ? 'background-image:url(\\'' + img + '\\');background-size:cover;background-position:center;' : '';\n\n    var detailUrl = '\/project\/?id=' + encodeURIComponent(id);\n\n    return '' +\n      '<a class=\"trly-card\" href=\"' + detailUrl + '\" target=\"_blank\" rel=\"noopener\" data-id=\"' + escapeAttr(id) + '\" data-name=\"' + escapeAttr(name) + '\">' +\n        '<div class=\"trly-card-img\" style=\"' + imgStyle + '\">' +\n          (status ? '<span class=\"trly-card-tag\">' + escapeHtml(status) + '<\/span>' : '') +\n        '<\/div>' +\n        '<div class=\"trly-card-body\">' +\n          (developer ? '<div class=\"trly-card-dev\">' + escapeHtml(developer) + '<\/div>' : '') +\n          '<h3>' + escapeHtml(name) + '<\/h3>' +\n          '<div class=\"trly-card-loc\">\ud83d\udccd ' + escapeHtml(area) + '<\/div>' +\n          '<div class=\"trly-card-specs\">' +\n            (units ? '<span>\ud83c\udfe2 ' + escapeHtml(units) + ' units<\/span>' : '') +\n            (size ? '<span>\ud83d\udcd0 ' + escapeHtml(Math.round(parseFloat(size)).toLocaleString()) + ' ' + escapeHtml(areaUnit) + '<\/span>' : '') +\n            (handover ? '<span>\ud83d\udd11 ' + escapeHtml(handover) + '<\/span>' : '') +\n          '<\/div>' +\n          '<div class=\"trly-card-price\">' +\n            '<small>Starting from<\/small>' +\n            fmtPrice(price, currency) +\n          '<\/div>' +\n          '<span class=\"trly-card-btn\">View Project Details \u2192<\/span>' +\n        '<\/div>' +\n      '<\/a>';\n  }\n\n  function escapeHtml(s) {\n    if (s == null) return '';\n    return String(s).replace(\/[&<>\"']\/g, function (c) {\n      return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c];\n    });\n  }\n  function escapeAttr(s) { return escapeHtml(s); }\n\n  function load(reset) {\n    if (reset) {\n      page = 1; loaded = 0; totalAll = 0;\n      grid.innerHTML = '<div class=\"trly-loading\"><div class=\"trly-spinner\"><\/div>Loading projects from Reelly\u2026<\/div>';\n    }\n    moreBtn.disabled = true;\n    moreBtn.textContent = 'Loading\u2026';\n\n    \/\/ Send BOTH page-style and offset-style params so the plugin\n    \/\/ forwards whatever Reelly accepts.\n    var params = Object.assign({}, current, {\n      page: page,\n      per_page: PER_PAGE,\n      limit: PER_PAGE,\n      offset: (page - 1) * PER_PAGE\n    });\n    var qs = new URLSearchParams(params).toString();\n\n    fetch(ENDPOINT + '?' + qs)\n      .then(function (r) { return r.json(); })\n      .then(function (data) {\n        if (data && data.error) throw new Error(data.error);\n\n        var items = data.results || data.projects || data.data || data.items || (Array.isArray(data) ? data : []);\n        var total = data.count || data.total || data.total_count || 0;\n\n        if (reset && items.length && window.console) {\n          console.log('[TruHauz \u00d7 Reelly] Sample project keys:', Object.keys(items[0]));\n          console.log('[TruHauz \u00d7 Reelly] Sample project:', items[0]);\n          console.log('[TruHauz \u00d7 Reelly] API count field:', total, '\u2014 next:', data.next);\n        }\n\n        if (reset) grid.innerHTML = '';\n        var loadingNode = grid.querySelector('.trly-loading');\n        if (loadingNode) loadingNode.remove();\n\n        if (!items.length && reset) {\n          grid.innerHTML = '<div class=\"trly-empty\">No projects matched your filters. Try resetting the search.<\/div>';\n          countEl.textContent = '0 projects';\n          moreBtn.style.display = 'none';\n          return;\n        }\n\n        items.forEach(function (p) {\n          var pid = pick(p, ['id','project_id','slug'], '');\n          if (pid) projectCache[pid] = p;\n          grid.insertAdjacentHTML('beforeend', renderCard(p));\n        });\n\n        loaded   += items.length;\n        totalAll  = total || totalAll;\n\n        if (totalAll) {\n          countEl.textContent = 'Showing ' + loaded + ' of ' + totalAll + ' projects';\n        } else {\n          countEl.textContent = loaded + ' projects loaded';\n        }\n\n        \/\/ Show \"Load More\" if there's a `next` URL OR we got a full page\n        \/\/ OR we know there's still more from total count.\n        var hasMore = !!data.next ||\n                      (totalAll && loaded < totalAll) ||\n                      items.length >= PER_PAGE;\n\n        if (hasMore) {\n          moreBtn.style.display = 'inline-block';\n          moreBtn.disabled = false;\n          moreBtn.textContent = 'Load More Projects';\n          page++;\n        } else {\n          moreBtn.style.display = 'none';\n        }\n      })\n      .catch(function (err) {\n        grid.innerHTML = '<div class=\"trly-error\">\u26a0 Failed to load projects: ' + err.message +\n                         '<br><small>Make sure the TruHauz Reelly plugin is installed &amp; activated.<\/small><\/div>';\n        countEl.textContent = '';\n        moreBtn.style.display = 'none';\n      });\n  }\n\n  \/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MODAL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  var modalOverlay = document.getElementById('trly-modal-overlay');\n  var modalContent = document.getElementById('trly-modal-content');\n\n  function openModal(id, fallbackName) {\n    modalOverlay.classList.add('open');\n    document.body.style.overflow = 'hidden';\n\n    \/\/ STEP 1 \u2014 render IMMEDIATELY from cached list data so the user always\n    \/\/ sees the photo + basic info, even if the detail endpoint fails.\n    var cached = id ? projectCache[id] : null;\n    if (cached) {\n      renderModal(cached, fallbackName);\n    } else {\n      modalContent.innerHTML = '<div class=\"trly-modal-loading\"><div class=\"trly-spinner\"><\/div>Loading project details\u2026<\/div>';\n    }\n\n    if (!id) return;\n\n    \/\/ STEP 2 \u2014 try to enrich with the detail endpoint in the background.\n    fetch(ENDPOINT + '\/' + encodeURIComponent(id))\n      .then(function (r) { return r.json(); })\n      .then(function (data) {\n        if (!data || data.error) return; \/\/ keep cached version\n        var p = data.result || data.data || data.project || data;\n        if (!p || typeof p !== 'object') return;\n        if (window.console) console.log('[TruHauz \u00d7 Reelly] Project detail:', p);\n        \/\/ Merge: detail fields override cached, but keep cached fallbacks\n        var merged = Object.assign({}, cached || {}, p);\n        renderModal(merged, fallbackName);\n      })\n      .catch(function () { \/* silently keep the cached render *\/ });\n  }\n\n  function closeModal() {\n    modalOverlay.classList.remove('open');\n    document.body.style.overflow = '';\n  }\n\n  \/\/ Close handlers\n  document.getElementById('trly-modal-close').addEventListener('click', closeModal);\n  modalOverlay.addEventListener('click', function (e) {\n    if (e.target === modalOverlay) closeModal();\n  });\n  document.addEventListener('keydown', function (e) {\n    if (e.key === 'Escape') closeModal();\n  });\n\n  function collectImages(p) { return findAllImages(p); }\n\n  function renderModal(p, fallbackName) {\n    var name      = p.name || fallbackName || 'Project';\n    var developer = asText(p.developer);\n    var area      = asText(p.location) || 'Dubai';\n    var price     = p.min_price;\n    var maxPrice  = p.max_price;\n    var currency  = p.price_currency || 'AED';\n    var size      = p.min_size;\n    var maxSize   = p.max_size;\n    var areaUnit  = p.area_unit || 'sqft';\n    var compDate  = p.completion_date || p.completion_datetime || '';\n    var startDate = p.construction_start_date || '';\n    var endDate   = p.construction_end_date || '';\n    var saleStat  = niceLabel(p.sale_status);\n    var conStat   = niceLabel(p.construction_status);\n    var unitsCnt  = p.units_count;\n    var bldgs     = p.building_count;\n    var desc      = p.overview || p.description || '';\n    var shortDesc = p.short_description || '';\n    var brand     = p.brand || '';\n    var managing  = p.managing_company || '';\n    var furnishing= niceLabel(p.furnishing);\n    var serviceFee= p.service_charge || '';\n    var escrow    = p.escrow_number || '';\n    var readiness = p.readiness_progress;\n    var brochure  = p.marketing_brochure || '';\n\n    \/\/ Build gallery from ALL image sources in the detail response\n    var images = [];\n    function addImg(v) {\n      var u = '';\n      if (typeof v === 'string') u = v;\n      else if (v && typeof v === 'object') u = v.url || v.src || '';\n      if (u && images.indexOf(u) === -1) images.push(u);\n    }\n    addImg(p.cover_image);\n    addImg(p.general_plan);\n    (p.lobby        || []).forEach(addImg);\n    (p.interior     || []).forEach(addImg);\n    (p.architecture || []).forEach(addImg);\n    (p.buildings    || []).forEach(function (b) { addImg(b && b.cover_image); });\n    \/\/ Fallback: recursive scan if we still have nothing\n    if (!images.length) images = collectImages(p);\n    var hero = images[0] || '';\n\n    \/\/ Date helpers\n    function fmtDate(d) {\n      if (!d) return '';\n      if (\/^\\d{4}-\\d{2}-\\d{2}\/.test(d)) {\n        var parts = d.substring(0, 10).split('-');\n        var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];\n        return parts[2] + ' ' + months[parseInt(parts[1], 10) - 1] + ' ' + parts[0];\n      }\n      return d;\n    }\n    function fmtQuarter(d) {\n      if (!d) return '';\n      d = String(d);\n      \/\/ Already formatted as \"Q2 2026\" \u2192 don't mangle it\n      if (\/^Q[1-4]\\s\/.test(d)) return d;\n      if (\/^\\d{4}-\\d{2}\/.test(d)) {\n        var parts = d.split('-');\n        var q = Math.ceil(parseInt(parts[1], 10) \/ 3);\n        return 'Q' + q + ' ' + parts[0];\n      }\n      return d;\n    }\n\n    var priceLine = fmtPrice(price, currency);\n    if (maxPrice && maxPrice !== price) priceLine += ' \u2013 ' + fmtPrice(maxPrice, currency);\n    var sizeLine = '';\n    if (size) {\n      var sMin = Math.round(Number(size));\n      var sMax = maxSize ? Math.round(Number(maxSize)) : 0;\n      sizeLine = sMin + (sMax && sMax !== sMin ? '\u2013' + sMax : '') + ' ' + areaUnit;\n    }\n    var dateRange = '';\n    if (startDate && compDate) dateRange = fmtDate(startDate) + ' \u2013 ' + fmtQuarter(compDate);\n    else if (compDate)  dateRange = fmtQuarter(compDate);\n    else if (startDate) dateRange = fmtDate(startDate);\n\n    var html = '';\n    html += '<div class=\"trly-modal-hero\" style=\"' + (hero ? \"background-image:url('\" + hero + \"');background-size:cover;background-position:center;\" : '') + '\">';\n    if (saleStat)  html += '<span class=\"trly-card-tag\" style=\"position:absolute;top:60px;left:30px;\">' + escapeHtml(saleStat) + '<\/span>';\n    if (dateRange) html += '<span class=\"trly-card-tag\" style=\"position:absolute;top:60px;left:' + (saleStat ? '160px' : '30px') + ';background:rgba(255,255,255,0.95);\">' + escapeHtml(dateRange) + '<\/span>';\n    if (images.length > 1) html += '<span class=\"trly-card-tag\" style=\"position:absolute;bottom:18px;left:30px;background:rgba(0,0,0,0.6);color:#fff;\">\ud83d\udcf7 ' + images.length + ' photos<\/span>';\n    html += '<\/div>';\n    html += '<div class=\"trly-modal-body\">';\n    if (developer) html += '<div class=\"trly-modal-dev\">' + escapeHtml(developer) + (brand && brand !== developer ? ' \u00b7 ' + escapeHtml(brand) : '') + '<\/div>';\n    html += '<h2>' + escapeHtml(name) + '<\/h2>';\n    html += '<div class=\"trly-modal-loc\">\ud83d\udccd ' + escapeHtml(area) + '<\/div>';\n    if (shortDesc) html += '<p style=\"color:#777;font-style:italic;margin:8px 0 18px;\">' + escapeHtml(shortDesc) + '<\/p>';\n\n    \/\/ Stats grid\n    html += '<div class=\"trly-modal-stats\">';\n    html += '<div class=\"trly-modal-stat\"><strong>' + priceLine + '<\/strong><span>Price From<\/span><\/div>';\n    if (sizeLine) html += '<div class=\"trly-modal-stat\"><strong>' + escapeHtml(sizeLine) + '<\/strong><span>Unit Size<\/span><\/div>';\n    if (unitsCnt) html += '<div class=\"trly-modal-stat\"><strong>' + escapeHtml(String(unitsCnt)) + '<\/strong><span>Units<\/span><\/div>';\n    if (bldgs)    html += '<div class=\"trly-modal-stat\"><strong>' + escapeHtml(String(bldgs)) + '<\/strong><span>Buildings<\/span><\/div>';\n    if (compDate) html += '<div class=\"trly-modal-stat\"><strong>' + escapeHtml(fmtQuarter(compDate)) + '<\/strong><span>Handover<\/span><\/div>';\n    if (conStat)  html += '<div class=\"trly-modal-stat\"><strong>' + escapeHtml(conStat) + '<\/strong><span>Construction<\/span><\/div>';\n    if (readiness != null) html += '<div class=\"trly-modal-stat\"><strong>' + Math.round(readiness) + '%<\/strong><span>Readiness<\/span><\/div>';\n    if (furnishing) html += '<div class=\"trly-modal-stat\"><strong>' + escapeHtml(furnishing) + '<\/strong><span>Furnishing<\/span><\/div>';\n    if (serviceFee) html += '<div class=\"trly-modal-stat\"><strong>' + escapeHtml(serviceFee) + '<\/strong><span>Service Charge<\/span><\/div>';\n    html += '<\/div>';\n\n    \/\/ Overview (markdown)\n    if (desc) {\n      html += '<div class=\"trly-modal-section\"><h4>Overview<\/h4><div>' + mdToHtml(desc) + '<\/div><\/div>';\n    }\n\n    \/\/ Typical units (bedrooms \/ prices \/ sizes)\n    if (Array.isArray(p.typical_units) && p.typical_units.length) {\n      html += '<div class=\"trly-modal-section\"><h4>Available Units<\/h4>';\n      html += '<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px;\">';\n      p.typical_units.forEach(function (u) {\n        var pf = fmtPrice(u.from_price_aed, 'AED');\n        var pt = u.to_price_aed && u.to_price_aed !== u.from_price_aed ? ' \u2013 ' + fmtPrice(u.to_price_aed, 'AED') : '';\n        var sf = u.from_size_sqft || '';\n        var st = u.to_size_sqft && u.to_size_sqft !== u.from_size_sqft ? '\u2013' + Math.round(u.to_size_sqft) : '';\n        html += '<div style=\"padding:14px;background:#f9f4f6;border-radius:10px;\">';\n        html += '<strong style=\"color:#660033;font-size:1.1rem;display:block;\">' + (u.bedrooms || '?') + ' BR<\/strong>';\n        html += '<div style=\"font-size:0.85rem;color:#555;margin-top:4px;\">' + pf + pt + '<\/div>';\n        if (sf) html += '<div style=\"font-size:0.75rem;color:#888;margin-top:2px;\">' + Math.round(sf) + st + ' sqft<\/div>';\n        html += '<\/div>';\n      });\n      html += '<\/div><\/div>';\n    }\n\n    \/\/ Payment plans\n    if (Array.isArray(p.payment_plans) && p.payment_plans.length) {\n      p.payment_plans.forEach(function (plan) {\n        if (!plan.steps || !plan.steps.length) return;\n        html += '<div class=\"trly-modal-section\"><h4>' + escapeHtml(plan.name || 'Payment Plan') + '<\/h4>';\n        html += '<div style=\"display:flex;gap:10px;flex-wrap:wrap;\">';\n        plan.steps.forEach(function (st) {\n          html += '<div style=\"flex:1;min-width:140px;padding:14px;background:linear-gradient(135deg,#660033,#3a0020);color:#fff;border-radius:10px;text-align:center;\">';\n          html += '<div style=\"font-size:1.6rem;font-weight:700;font-family:\\'Playfair Display\\',serif;\">' + (st.percentage || 0) + '%<\/div>';\n          html += '<div style=\"font-size:0.75rem;text-transform:uppercase;letter-spacing:0.5px;opacity:0.85;margin-top:4px;\">' + escapeHtml(st.name || '') + '<\/div>';\n          html += '<\/div>';\n        });\n        html += '<\/div><\/div>';\n      });\n    }\n\n    \/\/ Amenities\n    if (Array.isArray(p.project_amenities) && p.project_amenities.length) {\n      html += '<div class=\"trly-modal-section\"><h4>Amenities<\/h4><ul>';\n      p.project_amenities.forEach(function (a) {\n        var label = (a && a.amenity && a.amenity.name) ? a.amenity.name : '';\n        if (label) html += '<li>' + escapeHtml(label) + '<\/li>';\n      });\n      html += '<\/ul><\/div>';\n    }\n\n    \/\/ Map points \/ nearby\n    if (Array.isArray(p.project_map_points) && p.project_map_points.length) {\n      html += '<div class=\"trly-modal-section\"><h4>Nearby Places<\/h4>';\n      html += '<div style=\"display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px;\">';\n      p.project_map_points.forEach(function (mp) {\n        html += '<div style=\"padding:10px 14px;background:#f9f4f6;border-radius:8px;font-size:0.85rem;\">';\n        html += '<strong style=\"color:#660033;\">' + escapeHtml(mp.map_point_name || '') + '<\/strong>';\n        html += '<div style=\"color:#888;font-size:0.75rem;margin-top:2px;\">';\n        if (mp.distance != null) html += mp.distance + ' km';\n        if (mp.distance != null && mp.time != null) html += ' \u00b7 ';\n        if (mp.time != null) html += mp.time + ' min';\n        html += '<\/div><\/div>';\n      });\n      html += '<\/div><\/div>';\n    }\n\n    \/\/ Parking\n    if (Array.isArray(p.parkings) && p.parkings.length) {\n      html += '<div class=\"trly-modal-section\"><h4>Parking<\/h4><ul>';\n      p.parkings.forEach(function (pk) {\n        html += '<li>' + (pk.unit_bedrooms || '?') + ' BR ' + niceLabel(pk.unit_type || '') + ': ' + (pk.parking_space || 0) + ' parking spaces<\/li>';\n      });\n      html += '<\/ul><\/div>';\n    }\n\n    if (managing && managing !== developer) {\n      html += '<div class=\"trly-modal-section\"><h4>Managing Company<\/h4><p>' + escapeHtml(managing) + '<\/p><\/div>';\n    }\n    if (escrow) {\n      html += '<div class=\"trly-modal-section\"><h4>Escrow Number<\/h4><p>' + escapeHtml(escrow) + '<\/p><\/div>';\n    }\n\n    if (images.length > 1) {\n      html += '<div class=\"trly-modal-section\"><h4>Gallery<\/h4><div class=\"trly-modal-gallery\">';\n      images.slice(1, 16).forEach(function (u) {\n        html += '<img decoding=\"async\" src=\"' + escapeAttr(u) + '\" alt=\"\" loading=\"lazy\">';\n      });\n      html += '<\/div><\/div>';\n    }\n\n    \/\/ Generic field dump \u2014 shows ALL non-empty primitive fields we haven't already used\n    var usedKeys = {\n      name:1,title:1,project_name:1,developer:1,developer_name:1,dev_name:1,\n      area:1,location:1,address:1,region:1,\n      min_price:1,starting_price:1,price_from:1,price:1,max_price:1,price_to:1,price_currency:1,currency:1,\n      bedrooms:1,bedroom_range:1,beds:1,\n      min_size:1,max_size:1,min_area:1,area_from:1,area_to:1,size:1,area_unit:1,\n      handover:1,completion_date:1,completion_datetime:1,completion_year:1,delivery_date:1,planned_completion_date:1,\n      construction_start_date:1,construction_end_date:1,sales_start_date:1,sales_started:1,sale_start:1,launch_date:1,\n      construction_status:1,sale_status:1,sales_status:1,status:1,availability:1,is_published:1,\n      units_in_sale:1,available_units:1,units_available:1,units_count:1,building_count:1,\n      project_amenities:1,project_map_points:1,parkings:1,typical_units:1,payment_plans:1,\n      buildings:1,floor_plans:1,marketing_brochure:1,general_plan:1,lobby:1,interior:1,architecture:1,\n      service_charge:1,furnishing:1,escrow_number:1,readiness_progress:1,post_handover:1,\n      deposit_description:1,\n      description:1,overview:1,short_description:1,tagline:1,about:1,project_description:1,full_description:1,\n      brand:1,managing_company:1,\n      payment_plan:1,payment_plans:1,payment:1,\n      updated_at:1,last_update:1,last_updated:1,modified_at:1,\n      amenities:1,facilities:1,features:1,\n      images:1,gallery:1,media:1,photos:1,pictures:1,video_reviews:1,\n      cover_image:1,cover:1,main_image:1,thumbnail:1,image:1,photo:1,picture:1,preview_image:1,\n      id:1,project_id:1,slug:1,is_partner_project:1,\n      url:1,src:1,href:1,\n      latitude:1,longitude:1,lat:1,lng:1,coordinates:1\n    };\n    var extra = [];\n    for (var k in p) {\n      if (!Object.prototype.hasOwnProperty.call(p, k)) continue;\n      if (usedKeys[k]) continue;\n      var v = p[k];\n      if (v == null || v === '' || v === false) continue;\n      if (typeof v === 'object') {\n        \/\/ Show the .name or .title of nested objects, or skip\n        if (Array.isArray(v)) {\n          if (!v.length) continue;\n          var simple = v.filter(function (x) { return typeof x === 'string' || typeof x === 'number'; });\n          if (simple.length) extra.push([k, simple.join(', ')]);\n        } else if (v.name || v.title || v.label) {\n          extra.push([k, v.name || v.title || v.label]);\n        }\n        continue;\n      }\n      extra.push([k, v]);\n    }\n    if (extra.length) {\n      html += '<div class=\"trly-modal-section\"><h4>Additional Details<\/h4><ul style=\"list-style:none;\">';\n      extra.forEach(function (kv) {\n        var label = String(kv[0]).replace(\/_\/g, ' ').replace(\/\\b\\w\/g, function (c) { return c.toUpperCase(); });\n        html += '<li style=\"padding:4px 0;\"><strong style=\"color:#660033;\">' + escapeHtml(label) + ':<\/strong> ' + escapeHtml(String(kv[1])) + '<\/li>';\n      });\n      html += '<\/ul><\/div>';\n    }\n\n    \/\/ Action buttons\n    var pid = p.id || '';\n    html += '<div class=\"trly-modal-actions\">';\n    html += '<a href=\"https:\/\/truhauz.com\/contact\/?project=' + encodeURIComponent(name) + '\">Enquire About This Project<\/a>';\n    if (brochure) {\n      html += '<a class=\"secondary\" target=\"_blank\" rel=\"noopener\" href=\"' + escapeAttr(brochure) + '\">\ud83d\udcc4 Marketing Brochure<\/a>';\n    }\n    if (Array.isArray(p.floor_plans) && p.floor_plans.length && p.floor_plans[0].file) {\n      html += '<a class=\"secondary\" target=\"_blank\" rel=\"noopener\" href=\"' + escapeAttr(p.floor_plans[0].file) + '\">\ud83d\udcd0 Floor Plans<\/a>';\n    }\n    html += '<\/div>';\n\n    html += '<\/div>'; \/\/ \/modal-body\n    modalContent.innerHTML = html;\n  }\n\n  \/\/ Cards are now real <a> links to \/project\/?id=N (open in new tab),\n  \/\/ so no click delegation is needed. The modal markup below is left\n  \/\/ hidden as a fallback in case browsers block the popup.\n\n  function readFilters() {\n    current = {};\n    var s = document.getElementById('trly-search').value.trim();\n    var d = document.getElementById('trly-developer').value.trim();\n    var a = document.getElementById('trly-area').value.trim();\n    var b = document.getElementById('trly-bedrooms').value;\n    var st= document.getElementById('trly-status').value;\n    if (s)  current.search      = s;\n    if (d)  current.developer   = d;\n    if (a)  current.area        = a;\n    if (b)  current.bedrooms    = b;\n    if (st) current.sale_status = st;\n  }\n\n  document.getElementById('trly-apply').addEventListener('click', function () {\n    readFilters(); load(true);\n  });\n  document.getElementById('trly-reset').addEventListener('click', function () {\n    document.getElementById('trly-search').value = '';\n    document.getElementById('trly-developer').value = '';\n    document.getElementById('trly-area').value = '';\n    document.getElementById('trly-bedrooms').value = '';\n    document.getElementById('trly-status').value = '';\n    current = {}; load(true);\n  });\n  moreBtn.addEventListener('click', function () { load(false); });\n\n  \/\/ initial load\n  load(true);\n})();\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Live Inventory \u00b7 Reelly.ai Off-Plan Projects in Dubai Browse the latest off-plan developments from Dubai&#8217;s leading developers, updated in real time from our partner database. All Bedrooms1 BR2 BR3 BR4 BR5+ BR All StatusesAvailableSold OutComing Soon Search Reset Loading projects\u2026 Loading projects from Reelly\u2026 Load More Found Something You Like? Get exclusive floor plans, payment [&hellip;]<\/p>\n","protected":false},"author":12,"featured_media":36297,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"_joinchat":[],"footnotes":""},"class_list":["post-36404","page","type-page","status-publish","has-post-thumbnail","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v28.3 (Yoast SEO v28.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>New Projects | Dubai Real Estate - Apartments, Villas, Townhouses, Penthouses | TruHauz<\/title>\n<meta name=\"description\" content=\"Live Inventory \u00b7 Reelly.ai Off-Plan Projects in Dubai Browse the latest off-plan developments from Dubai&#039;s leading developers, updated in real time from\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/truhauz.com\/fa\/new-projects\/\" \/>\n<meta property=\"og:locale\" content=\"fa_IR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"New Projects\" \/>\n<meta property=\"og:description\" content=\"Live Inventory \u00b7 Reelly.ai Off-Plan Projects in Dubai Browse the latest off-plan developments from Dubai&#039;s leading developers, updated in real time from\" \/>\n<meta property=\"og:url\" content=\"https:\/\/truhauz.com\/fa\/new-projects\/\" \/>\n<meta property=\"og:site_name\" content=\"Dubai Real Estate - Apartments, Villas, Townhouses, Penthouses | TruHauz\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/profile.php?id=61575393084920\" \/>\n<meta property=\"article:modified_time\" content=\"2026-04-07T13:57:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/truhauz.com\/wp-content\/uploads\/2026\/04\/DUBAI_2026_HERO_IMAGE_URL.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"772\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u0632\u0645\u0627\u0646 \u062a\u0642\u0631\u06cc\u0628\u06cc \u0628\u0631\u0627\u06cc \u062e\u0648\u0627\u0646\u062f\u0646\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 \u062f\u0642\u06cc\u0642\u0647\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/truhauz.com\\\/new-projects\\\/\",\"url\":\"https:\\\/\\\/truhauz.com\\\/new-projects\\\/\",\"name\":\"New Projects | Dubai Real Estate - Apartments, Villas, Townhouses, Penthouses | TruHauz\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/truhauz.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/truhauz.com\\\/new-projects\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/truhauz.com\\\/new-projects\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/truhauz.com\\\/wp-content\\\/uploads\\\/2026\\\/04\\\/DUBAI_2026_HERO_IMAGE_URL.jpg\",\"datePublished\":\"2026-04-07T07:58:14+00:00\",\"dateModified\":\"2026-04-07T13:57:46+00:00\",\"description\":\"Live Inventory \u00b7 Reelly.ai Off-Plan Projects in Dubai Browse the latest off-plan developments from Dubai's leading developers, updated in real time from\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/truhauz.com\\\/new-projects\\\/#breadcrumb\"},\"inLanguage\":\"fa-IR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/truhauz.com\\\/new-projects\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"fa-IR\",\"@id\":\"https:\\\/\\\/truhauz.com\\\/new-projects\\\/#primaryimage\",\"url\":\"https:\\\/\\\/truhauz.com\\\/wp-content\\\/uploads\\\/2026\\\/04\\\/DUBAI_2026_HERO_IMAGE_URL.jpg\",\"contentUrl\":\"https:\\\/\\\/truhauz.com\\\/wp-content\\\/uploads\\\/2026\\\/04\\\/DUBAI_2026_HERO_IMAGE_URL.jpg\",\"width\":1200,\"height\":772,\"caption\":\"DUBAI 2026 HERO IMAGE URL\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/truhauz.com\\\/new-projects\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/truhauz.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"New Projects\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/truhauz.com\\\/#website\",\"url\":\"https:\\\/\\\/truhauz.com\\\/\",\"name\":\"TruHauz\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/truhauz.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/truhauz.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"fa-IR\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/truhauz.com\\\/#organization\",\"name\":\"TruHauz\",\"url\":\"https:\\\/\\\/truhauz.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fa-IR\",\"@id\":\"https:\\\/\\\/truhauz.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/truhauz.com\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/truhauz-logo.png\",\"contentUrl\":\"https:\\\/\\\/truhauz.com\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/truhauz-logo.png\",\"width\":2498,\"height\":676,\"caption\":\"TruHauz\"},\"image\":{\"@id\":\"https:\\\/\\\/truhauz.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/profile.php?id=61575393084920\",\"https:\\\/\\\/www.instagram.com\\\/truhauz\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/truhauz\\\/\",\"https:\\\/\\\/www.tiktok.com\\\/@truhauz\",\"https:\\\/\\\/www.youtube.com\\\/@TruHauz\"]}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"New Projects | Dubai Real Estate - Apartments, Villas, Townhouses, Penthouses | TruHauz","description":"Live Inventory \u00b7 Reelly.ai Off-Plan Projects in Dubai Browse the latest off-plan developments from Dubai's leading developers, updated in real time from","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/truhauz.com\/fa\/new-projects\/","og_locale":"fa_IR","og_type":"article","og_title":"New Projects","og_description":"Live Inventory \u00b7 Reelly.ai Off-Plan Projects in Dubai Browse the latest off-plan developments from Dubai's leading developers, updated in real time from","og_url":"https:\/\/truhauz.com\/fa\/new-projects\/","og_site_name":"Dubai Real Estate - Apartments, Villas, Townhouses, Penthouses | TruHauz","article_publisher":"https:\/\/www.facebook.com\/profile.php?id=61575393084920","article_modified_time":"2026-04-07T13:57:46+00:00","og_image":[{"width":1200,"height":772,"url":"https:\/\/truhauz.com\/wp-content\/uploads\/2026\/04\/DUBAI_2026_HERO_IMAGE_URL.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"\u0632\u0645\u0627\u0646 \u062a\u0642\u0631\u06cc\u0628\u06cc \u0628\u0631\u0627\u06cc \u062e\u0648\u0627\u0646\u062f\u0646":"1 \u062f\u0642\u06cc\u0642\u0647"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/truhauz.com\/new-projects\/","url":"https:\/\/truhauz.com\/new-projects\/","name":"New Projects | Dubai Real Estate - Apartments, Villas, Townhouses, Penthouses | TruHauz","isPartOf":{"@id":"https:\/\/truhauz.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/truhauz.com\/new-projects\/#primaryimage"},"image":{"@id":"https:\/\/truhauz.com\/new-projects\/#primaryimage"},"thumbnailUrl":"https:\/\/truhauz.com\/wp-content\/uploads\/2026\/04\/DUBAI_2026_HERO_IMAGE_URL.jpg","datePublished":"2026-04-07T07:58:14+00:00","dateModified":"2026-04-07T13:57:46+00:00","description":"Live Inventory \u00b7 Reelly.ai Off-Plan Projects in Dubai Browse the latest off-plan developments from Dubai's leading developers, updated in real time from","breadcrumb":{"@id":"https:\/\/truhauz.com\/new-projects\/#breadcrumb"},"inLanguage":"fa-IR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/truhauz.com\/new-projects\/"]}]},{"@type":"ImageObject","inLanguage":"fa-IR","@id":"https:\/\/truhauz.com\/new-projects\/#primaryimage","url":"https:\/\/truhauz.com\/wp-content\/uploads\/2026\/04\/DUBAI_2026_HERO_IMAGE_URL.jpg","contentUrl":"https:\/\/truhauz.com\/wp-content\/uploads\/2026\/04\/DUBAI_2026_HERO_IMAGE_URL.jpg","width":1200,"height":772,"caption":"DUBAI 2026 HERO IMAGE URL"},{"@type":"BreadcrumbList","@id":"https:\/\/truhauz.com\/new-projects\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/truhauz.com\/"},{"@type":"ListItem","position":2,"name":"New Projects"}]},{"@type":"WebSite","@id":"https:\/\/truhauz.com\/#website","url":"https:\/\/truhauz.com\/","name":"\u062a\u0631\u0648\u0647\u0648\u0632","description":"","publisher":{"@id":"https:\/\/truhauz.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/truhauz.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"fa-IR"},{"@type":"Organization","@id":"https:\/\/truhauz.com\/#organization","name":"\u062a\u0631\u0648\u0647\u0648\u0632","url":"https:\/\/truhauz.com\/","logo":{"@type":"ImageObject","inLanguage":"fa-IR","@id":"https:\/\/truhauz.com\/#\/schema\/logo\/image\/","url":"https:\/\/truhauz.com\/wp-content\/uploads\/2026\/08\/truhauz-logo.png","contentUrl":"https:\/\/truhauz.com\/wp-content\/uploads\/2026\/08\/truhauz-logo.png","width":2498,"height":676,"caption":"TruHauz"},"image":{"@id":"https:\/\/truhauz.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/profile.php?id=61575393084920","https:\/\/www.instagram.com\/truhauz","https:\/\/www.linkedin.com\/company\/truhauz\/","https:\/\/www.tiktok.com\/@truhauz","https:\/\/www.youtube.com\/@TruHauz"]}]}},"_links":{"self":[{"href":"https:\/\/truhauz.com\/fa\/wp-json\/wp\/v2\/pages\/36404","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/truhauz.com\/fa\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/truhauz.com\/fa\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/truhauz.com\/fa\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/truhauz.com\/fa\/wp-json\/wp\/v2\/comments?post=36404"}],"version-history":[{"count":0,"href":"https:\/\/truhauz.com\/fa\/wp-json\/wp\/v2\/pages\/36404\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/truhauz.com\/fa\/wp-json\/wp\/v2\/media\/36297"}],"wp:attachment":[{"href":"https:\/\/truhauz.com\/fa\/wp-json\/wp\/v2\/media?parent=36404"}],"curies":[{"name":"\u0648\u06cc\u200c\u067e\u06cc","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}