From 9304fb16136654ec9e39cb1bf3b7da8e85d5bd5d Mon Sep 17 00:00:00 2001
From: Bryan Stopp <bstopp@users.noreply.github.com>
Date: Mon, 20 May 2024 09:24:53 -0700
Subject: [PATCH] Feat/property search improvements (#199)

* Some improvements to loading and Accessibility.

* Fix icons.

* More icon fixing.

* Need to test intermediate logic on site.

* Remove references to partytown. (#178)

* add style for section top-border (#179)

Co-authored-by: Bryan Stopp <bstopp@users.noreply.github.com>

* added style to override margin bottom (#180)

Co-authored-by: Bryan Stopp <bstopp@users.noreply.github.com>

* update host for dev publishing (#182)

* starter hero slides

* mocked listings

* Fix images in default content. (#184)

* fix the gradiant overlay, less opacity (#185)

* Update styles on Shade Icon card variation. (#186)

* css layout

* hide paging

* rearrange functions

* disable linting on specific functions

* css linting

* style updates

* added class that scales images

* js linting

* added section full-bleed to allow full-witdh scaled image

* create div for headline

* add row for headline to block

* js clean up

* linting

* linting

* linting css

* js linting

* update logic around classlist

* create helix-query and start lookahead dropdown

* display list w/ listeners

* css tune

* css clean up

* js clean up

* js update

* js linting

* css linting

* css linting color notation

* add communities search styles

* Feat/login2 (#190)

* Cherry-pick feat/login changes

* Fix JS errors

* Missing from merge

* Missed in the merge

* Adding delay logic to load the delayed part of the form

* Added more utility functions around login/logout and session state tracking for logged in user

* treat invalid login as a logout as well

* More login handling of errors, fetching profile, and showing user name in navigation

* Remove external ID from initial login

* Handle logged-in user on page load

* Fix lint issue

* Remove console logging

---------

Co-authored-by: Brendan Robert <brobert@adobe.com>

* add style to adjust hero brightness in community dir

* Adjusted the city text and styling

* add braces

* css linting

* Feat/profile (#194)

* Update profile code implemetation

* Start of profile UI implementation and saving routine

* Tabs are working, needs more form styling and validation though

* Style improvements, also adjusted selectors to make linter happy

* Dropdown values implemented

* More styling work and visual support for required fields

* Updated form placeholders to match site

* Remove empty selections for regional preferences

* Skip missing profile check

* Improvements to error reporting and form submission.

* Profile saves working!

* Password reset working

* Navigation and login/logout starting to work.  Needs more testing

* Small cleanup

* Fix linting gripes

* Better session handling and also moved header visibility changes into header block (and out of login-delayed)

* Refactored i18n to be in utils

* Add i18n support to header nav

* Added i18n to login form

* Add i18n to login form

* Missing two text strings in i18n for login

---------

Co-authored-by: Brendan Robert <brobert@adobe.com>

* Intermediate work.

* Intermediate work with property search bar refactor.

* Final work for updating Property Search Bar.

* Fix some lint.

* Functional Search results list.

* Functional Search results list.

* Add pagination and all associated logic.

* Intermediate work on map.

* Intermediate info window work.

* More intermediate pin work.

* Finalize info window views.

* Finish mapping logic.

* Push first search off til after CWV

* No redraw on pagination.

* Trying css based animation.

* Fix some minor visual bugs.

---------

Co-authored-by: Rob Rusher <rrusher@adobe.com>
Co-authored-by: Rob Rusher <robrusher@gmail.com>
Co-authored-by: Brendan Robert <brendan.robert@gmail.com>
Co-authored-by: Brendan Robert <brobert@adobe.com>
---
 .eslintrc.js => .eslintrc.cjs                 |    2 +
 .github/workflows/run-tests.yaml              |    1 +
 .mocharc.json                                 |    3 +
 blocks/agent-search/builders/tags.js          |    1 +
 blocks/header/header.css                      |    5 +-
 blocks/hero/search/agent.css                  |    3 -
 blocks/hero/search/home-delayed.js            |  227 ---
 blocks/hero/search/home.css                   |    8 +-
 blocks/hero/search/home.js                    |  128 +-
 blocks/hero/search/home/filters.js            |   74 +
 blocks/hero/search/search.css                 |   19 +-
 blocks/login/login.js                         |    4 +-
 blocks/property-listing/map-search.js         |   25 -
 blocks/property-listing/property-listing.css  |    2 +-
 blocks/property-listing/property-listing.js   |  121 +-
 blocks/property-listing/radius-search.js      |   22 -
 blocks/property-listing/search.js             |   59 -
 .../property-result-listing.css               |  350 ----
 .../property-result-listing.js                |  200 ---
 blocks/property-result-map/Template.js        |   93 --
 blocks/property-result-map/map-delayed.js     | 1069 ------------
 blocks/property-result-map/map.css            |  449 ------
 blocks/property-result-map/map.js             |   54 -
 blocks/property-search-bar/README.md          |   15 +
 blocks/property-search-bar/common-function.js |  367 -----
 blocks/property-search-bar/delayed.js         |  918 +++++++++++
 .../property-search-bar/filter-processor.js   |  367 -----
 .../additional-filter-buttons-delayed.js      |   32 -
 .../filters/additional-filter-buttons.js      |   37 -
 .../filters/additional-filters.js             |  215 ---
 .../filters/additional-params-delayed.js      |  162 --
 .../filters/top-delayed.js                    |  232 ---
 .../property-search-bar/filters/top-menu.js   |  168 --
 .../property-search-bar.css                   | 1429 ++++++++---------
 .../property-search-bar.js                    |   99 +-
 .../search-results-dropdown.css               |   66 -
 .../property-search-bar/search/suggestion.js  |   50 -
 blocks/property-search-results/README.md      |   50 +
 blocks/property-search-results/loader.js      |   10 +
 blocks/property-search-results/map.css        |  562 +++++++
 blocks/property-search-results/map.js         |  434 +++++
 .../property-search-results/map/clusters.js   |   73 +
 blocks/property-search-results/map/drawing.js |  150 ++
 blocks/property-search-results/map/pins.js    |  342 ++++
 blocks/property-search-results/observers.js   |   87 +
 .../property-search-results.css               |  502 ++++++
 .../property-search-results.js                |  264 +++
 blocks/property-search-results/results.js     |  102 ++
 .../cards => shared/property}/cards.css       |   20 +-
 .../cards => shared/property}/cards.js        |   53 +-
 .../property}/luxury-collection-template.css  |   11 +-
 .../search-countries/search-countries.js      |    2 +-
 blocks/shared/search/suggestion.js            |  103 ++
 blocks/shared/search/util.js                  |  168 ++
 icons/checkmark.svg                           |    4 +-
 icons/close-x-white.svg                       |   11 +
 icons/close-x.svg                             |   11 +
 icons/filter-white.svg                        |   18 +
 icons/globe.png                               |  Bin 0 -> 2350 bytes
 icons/heartempty.svg                          |    2 +-
 icons/heartemptydark.svg                      |    4 +-
 icons/heartfull.svg                           |    9 +
 icons/maps/loader_opt.mp4                     |  Bin 58142 -> 0 bytes
 icons/maps/loader_opt.webm                    |  Bin 33962 -> 0 bytes
 icons/maps/map-reveal-marker-standard.png     |  Bin 15748 -> 0 bytes
 icons/pencil.svg                              |    1 +
 icons/search.svg                              |   11 +
 package-lock.json                             |  463 ++++++
 package.json                                  |    9 +-
 scripts/apis/creg/ApplicationType.js          |   25 -
 scripts/apis/creg/OpenHouses.js               |    9 -
 scripts/apis/creg/PropertyType.js             |   13 -
 scripts/apis/creg/SearchParameters.js         |  155 --
 scripts/apis/creg/SearchType.js               |   55 -
 scripts/apis/creg/creg.js                     |  115 +-
 scripts/apis/creg/search/Search.js            |  391 +++++
 .../apis/creg/search/types/AddressSearch.js   |   28 +
 scripts/apis/creg/search/types/BoxSearch.js   |   81 +
 scripts/apis/creg/search/types/CitySearch.js  |   28 +
 .../search/types/ElementarySchoolSearch.js    |   10 +
 .../creg/search/types/HighSchoolSearch.js     |   10 +
 scripts/apis/creg/search/types/ListingType.js |   38 +
 .../creg/search/types/MLSListingKeySearch.js  |   38 +
 .../creg/search/types/MiddleSchoolSearch.js   |   10 +
 .../creg/search/types/NeighborhoodSearch.js   |   28 +
 scripts/apis/creg/search/types/OpenHouses.js  |   39 +
 .../apis/creg/search/types/PolygonSearch.js   |   86 +
 .../creg/search/types/PostalCodeSearch.js     |   28 +
 .../apis/creg/search/types/PropertyType.js    |   72 +
 .../apis/creg/search/types/RadiusSearch.js    |   56 +
 .../creg/search/types/SchoolDistrictSearch.js |   28 +
 .../apis/creg/search/types/SchoolSearch.js    |   23 +
 scripts/apis/creg/suggestion.js               |   72 +
 scripts/apis/creg/workers/listing.js          |   21 +
 scripts/apis/creg/workers/metadata.js         |   35 +
 scripts/apis/creg/workers/properties.js       |   47 +
 scripts/apis/creg/workers/propertySearch.js   |   16 -
 scripts/delayed.js                            |    8 +-
 scripts/dom-helpers.js                        |   99 ++
 scripts/scripts.js                            |   25 +-
 scripts/search.js                             |   44 -
 scripts/search/results.js                     |   35 -
 scripts/util.js                               |   26 +
 styles/images/loading.png                     |  Bin 0 -> 31292 bytes
 styles/styles.css                             |    2 +-
 test/apis/creg/search/Search.test.js          |  250 +++
 .../creg/search/types/AddressSearch.test.js   |   78 +
 test/apis/creg/search/types/BoxSearch.test.js |   97 ++
 .../apis/creg/search/types/CitySearch.test.js |   78 +
 .../types/ElementarySchoolSearch.test.js      |   78 +
 .../search/types/HighSchoolSearch.test.js     |   78 +
 .../search/types/MLSListingKeySearch.test.js  |   87 +
 .../search/types/MiddleSchoolSearch.test.js   |   78 +
 .../search/types/NeighborhoodSearch.test.js   |   78 +
 .../creg/search/types/PolygonSearch.test.js   |  119 ++
 .../search/types/PostalCodeSearch.test.js     |   78 +
 .../creg/search/types/RadiusSearch.test.js    |   86 +
 .../search/types/SchoolDistrictSearch.test.js |   78 +
 118 files changed, 7925 insertions(+), 5686 deletions(-)
 rename .eslintrc.js => .eslintrc.cjs (84%)
 create mode 100644 .mocharc.json
 delete mode 100644 blocks/hero/search/home-delayed.js
 create mode 100644 blocks/hero/search/home/filters.js
 delete mode 100644 blocks/property-listing/map-search.js
 delete mode 100644 blocks/property-listing/radius-search.js
 delete mode 100644 blocks/property-listing/search.js
 delete mode 100644 blocks/property-result-listing/property-result-listing.css
 delete mode 100644 blocks/property-result-listing/property-result-listing.js
 delete mode 100644 blocks/property-result-map/Template.js
 delete mode 100644 blocks/property-result-map/map-delayed.js
 delete mode 100644 blocks/property-result-map/map.css
 delete mode 100644 blocks/property-result-map/map.js
 create mode 100644 blocks/property-search-bar/README.md
 delete mode 100644 blocks/property-search-bar/common-function.js
 create mode 100644 blocks/property-search-bar/delayed.js
 delete mode 100644 blocks/property-search-bar/filter-processor.js
 delete mode 100644 blocks/property-search-bar/filters/additional-filter-buttons-delayed.js
 delete mode 100644 blocks/property-search-bar/filters/additional-filter-buttons.js
 delete mode 100644 blocks/property-search-bar/filters/additional-filters.js
 delete mode 100644 blocks/property-search-bar/filters/additional-params-delayed.js
 delete mode 100644 blocks/property-search-bar/filters/top-delayed.js
 delete mode 100644 blocks/property-search-bar/filters/top-menu.js
 delete mode 100644 blocks/property-search-bar/search-results-dropdown.css
 delete mode 100644 blocks/property-search-bar/search/suggestion.js
 create mode 100644 blocks/property-search-results/README.md
 create mode 100644 blocks/property-search-results/loader.js
 create mode 100644 blocks/property-search-results/map.css
 create mode 100644 blocks/property-search-results/map.js
 create mode 100644 blocks/property-search-results/map/clusters.js
 create mode 100644 blocks/property-search-results/map/drawing.js
 create mode 100644 blocks/property-search-results/map/pins.js
 create mode 100644 blocks/property-search-results/observers.js
 create mode 100644 blocks/property-search-results/property-search-results.css
 create mode 100644 blocks/property-search-results/property-search-results.js
 create mode 100644 blocks/property-search-results/results.js
 rename blocks/{property-listing/cards => shared/property}/cards.css (96%)
 rename blocks/{property-listing/cards => shared/property}/cards.js (67%)
 rename blocks/{property-listing/cards => shared/property}/luxury-collection-template.css (71%)
 create mode 100644 blocks/shared/search/suggestion.js
 create mode 100644 blocks/shared/search/util.js
 create mode 100644 icons/close-x-white.svg
 create mode 100644 icons/close-x.svg
 create mode 100644 icons/filter-white.svg
 create mode 100644 icons/globe.png
 create mode 100644 icons/heartfull.svg
 delete mode 100644 icons/maps/loader_opt.mp4
 delete mode 100644 icons/maps/loader_opt.webm
 delete mode 100644 icons/maps/map-reveal-marker-standard.png
 create mode 100644 icons/pencil.svg
 create mode 100644 icons/search.svg
 delete mode 100644 scripts/apis/creg/ApplicationType.js
 delete mode 100644 scripts/apis/creg/OpenHouses.js
 delete mode 100644 scripts/apis/creg/PropertyType.js
 delete mode 100644 scripts/apis/creg/SearchParameters.js
 delete mode 100644 scripts/apis/creg/SearchType.js
 create mode 100644 scripts/apis/creg/search/Search.js
 create mode 100644 scripts/apis/creg/search/types/AddressSearch.js
 create mode 100644 scripts/apis/creg/search/types/BoxSearch.js
 create mode 100644 scripts/apis/creg/search/types/CitySearch.js
 create mode 100644 scripts/apis/creg/search/types/ElementarySchoolSearch.js
 create mode 100644 scripts/apis/creg/search/types/HighSchoolSearch.js
 create mode 100644 scripts/apis/creg/search/types/ListingType.js
 create mode 100644 scripts/apis/creg/search/types/MLSListingKeySearch.js
 create mode 100644 scripts/apis/creg/search/types/MiddleSchoolSearch.js
 create mode 100644 scripts/apis/creg/search/types/NeighborhoodSearch.js
 create mode 100644 scripts/apis/creg/search/types/OpenHouses.js
 create mode 100644 scripts/apis/creg/search/types/PolygonSearch.js
 create mode 100644 scripts/apis/creg/search/types/PostalCodeSearch.js
 create mode 100644 scripts/apis/creg/search/types/PropertyType.js
 create mode 100644 scripts/apis/creg/search/types/RadiusSearch.js
 create mode 100644 scripts/apis/creg/search/types/SchoolDistrictSearch.js
 create mode 100644 scripts/apis/creg/search/types/SchoolSearch.js
 create mode 100644 scripts/apis/creg/suggestion.js
 create mode 100644 scripts/apis/creg/workers/listing.js
 create mode 100644 scripts/apis/creg/workers/metadata.js
 create mode 100644 scripts/apis/creg/workers/properties.js
 delete mode 100644 scripts/apis/creg/workers/propertySearch.js
 create mode 100644 scripts/dom-helpers.js
 delete mode 100644 scripts/search.js
 delete mode 100644 scripts/search/results.js
 create mode 100644 styles/images/loading.png
 create mode 100644 test/apis/creg/search/Search.test.js
 create mode 100644 test/apis/creg/search/types/AddressSearch.test.js
 create mode 100644 test/apis/creg/search/types/BoxSearch.test.js
 create mode 100644 test/apis/creg/search/types/CitySearch.test.js
 create mode 100644 test/apis/creg/search/types/ElementarySchoolSearch.test.js
 create mode 100644 test/apis/creg/search/types/HighSchoolSearch.test.js
 create mode 100644 test/apis/creg/search/types/MLSListingKeySearch.test.js
 create mode 100644 test/apis/creg/search/types/MiddleSchoolSearch.test.js
 create mode 100644 test/apis/creg/search/types/NeighborhoodSearch.test.js
 create mode 100644 test/apis/creg/search/types/PolygonSearch.test.js
 create mode 100644 test/apis/creg/search/types/PostalCodeSearch.test.js
 create mode 100644 test/apis/creg/search/types/RadiusSearch.test.js
 create mode 100644 test/apis/creg/search/types/SchoolDistrictSearch.test.js

diff --git a/.eslintrc.js b/.eslintrc.cjs
similarity index 84%
rename from .eslintrc.js
rename to .eslintrc.cjs
index 76f220db..57ed377a 100644
--- a/.eslintrc.js
+++ b/.eslintrc.cjs
@@ -17,5 +17,7 @@ module.exports = {
     'import/extensions': ['error', {
       js: 'always',
     }],
+    'max-len': ['error', { "code": 200 }],
+    'function-paren-newline': 'off',
   },
 };
diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml
index 27b3c3d7..9e966580 100644
--- a/.github/workflows/run-tests.yaml
+++ b/.github/workflows/run-tests.yaml
@@ -13,5 +13,6 @@ jobs:
         node-version: '16' #required for npm 8 or later.
     - run: npm install
     - run: npm run lint
+    - run: npm test
       env:
         CI: true
diff --git a/.mocharc.json b/.mocharc.json
new file mode 100644
index 00000000..3b0fdf10
--- /dev/null
+++ b/.mocharc.json
@@ -0,0 +1,3 @@
+{
+  "recursive": true
+}
diff --git a/blocks/agent-search/builders/tags.js b/blocks/agent-search/builders/tags.js
index d5bcaf58..2838541b 100644
--- a/blocks/agent-search/builders/tags.js
+++ b/blocks/agent-search/builders/tags.js
@@ -28,6 +28,7 @@ export const addSelectionTag = (wrapper, filter, value) => {
   `;
   wrapper.querySelector('.selection-tags-list').append(li);
 };
+
 /**
  * Builds the Container for the search bar selections.
  *
diff --git a/blocks/header/header.css b/blocks/header/header.css
index 5af1aa86..2b27c00c 100644
--- a/blocks/header/header.css
+++ b/blocks/header/header.css
@@ -23,7 +23,7 @@ body.light-nav {
       / 1fr min-content;
   align-items: start;
   overflow-y: scroll;
-  z-index: 50;
+  z-index: 1000;
 }
 
 .header.block nav[aria-expanded="true"] {
@@ -259,6 +259,7 @@ body.light-nav {
 }
 
 .header.block nav .nav-hamburger .open {
+  display: block;
   position: absolute;
   top: 0;
   left: 0;
@@ -444,7 +445,7 @@ body.light-nav {
     right: 0;
     height: 5px;
     background-color: var(--white);
-    z-index: 10;
+    z-index: 1010;
   }
 
   .header.block nav[aria-expanded="true"] .nav-sections > ul > li > ul {
diff --git a/blocks/hero/search/agent.css b/blocks/hero/search/agent.css
index c35d9b6c..a8d71a0a 100644
--- a/blocks/hero/search/agent.css
+++ b/blocks/hero/search/agent.css
@@ -13,9 +13,6 @@
 
 .hero.block .agent-search .selection-tags {
   position: absolute;
-}
-
-.hero.block .agent-search .selection-tags {
   padding: 0;
 }
 
diff --git a/blocks/hero/search/home-delayed.js b/blocks/hero/search/home-delayed.js
deleted file mode 100644
index 6655b4bb..00000000
--- a/blocks/hero/search/home-delayed.js
+++ /dev/null
@@ -1,227 +0,0 @@
-import { getMetadata } from '../../../scripts/aem.js';
-import { BREAKPOINTS } from '../../../scripts/scripts.js';
-import {
-  close as closeCountrySelect,
-  getSelected as getSelectedCountry,
-} from '../../shared/search-countries/search-countries.js';
-import {
-  abortSuggestions,
-  getSuggestions,
-  propertySearch,
-  DOMAIN,
-} from '../../../scripts/apis/creg/creg.js';
-import { getSpinner } from '../../../scripts/util.js';
-import SearchType from '../../../scripts/apis/creg/SearchType.js';
-import SearchParameters from '../../../scripts/apis/creg/SearchParameters.js';
-
-const noOverlayAt = BREAKPOINTS.medium;
-
-const MORE_INPUT_NEEDED = 'Please enter at least 3 characters.';
-const NO_SUGGESTIONS = 'No suggestions found. Please modify your search.';
-const SEARCHING_SUGGESTIONS = 'Looking up suggestions...';
-
-const fixOverlay = () => {
-  if (noOverlayAt.matches) {
-    document.body.style.overflowY = 'hidden';
-  } else {
-    document.body.style.overflowY = null;
-  }
-};
-
-const showFilters = (e) => {
-  e.preventDefault();
-  e.stopPropagation();
-  e.currentTarget.closest('form').classList.add('show-filters');
-  if (!noOverlayAt.matches) {
-    document.body.style.overflowY = 'hidden';
-  }
-};
-
-const closeFilters = (e) => {
-  e.preventDefault();
-  e.stopPropagation();
-  const thisForm = e.currentTarget.closest('form');
-  thisForm.classList.remove('show-filters');
-  thisForm.querySelectorAll('.select-wrapper.open').forEach((select) => {
-    select.classList.remove('open');
-  });
-
-  if (!noOverlayAt.matches) {
-    document.body.style.overflowY = 'hidden';
-  }
-};
-
-const selectClicked = (e) => {
-  e.preventDefault();
-  e.stopPropagation();
-  const wrapper = e.currentTarget.closest('.select-wrapper');
-  const wasOpen = wrapper.classList.contains('open');
-  const thisForm = e.currentTarget.closest('form');
-  thisForm.querySelectorAll('.select-wrapper.open').forEach((select) => {
-    select.classList.remove('open');
-  });
-  closeCountrySelect(thisForm);
-  if (!wasOpen) {
-    wrapper.classList.add('open');
-  }
-};
-
-const selectFilterClicked = (e) => {
-  e.preventDefault();
-  e.stopPropagation();
-  const count = e.currentTarget.textContent;
-  const wrapper = e.currentTarget.closest('.select-wrapper');
-  wrapper.querySelector('.selected').textContent = count;
-  wrapper.querySelector('ul li.selected')?.classList.toggle('selected');
-  e.currentTarget.classList.add('selected');
-  wrapper.querySelector('select option[selected="selected"]')?.removeAttribute('selected');
-  wrapper.querySelector(`select option[value="${count.replace('+', '')}"]`).setAttribute('selected', 'selected');
-  wrapper.classList.toggle('open');
-};
-
-const updateSuggestions = (suggestions, target) => {
-  // Keep the first item - required character entry count.
-  const first = target.querySelector(':scope li');
-  target.replaceChildren(first, ...suggestions);
-};
-
-const buildSuggestions = (suggestions) => {
-  const lists = [];
-  suggestions.forEach((category) => {
-    const list = document.createElement('li');
-    list.classList.add('list-title');
-    list.textContent = category.displayText;
-    lists.push(list);
-    const ul = document.createElement('ul');
-    list.append(ul);
-    category.results.forEach((result) => {
-      const li = document.createElement('li');
-      li.setAttribute('category', category.searchType);
-      li.setAttribute('display', result.displayText);
-      li.setAttribute('query', result.QueryString);
-      li.textContent = result.SearchParameter;
-      ul.append(li);
-    });
-  });
-
-  return lists;
-};
-
-/**
- * Handles the input changed event for the text field. Will add suggestions based on user input.
- *
- * @param {Event} e the change event
- * @param {HTMLElement} target the container in which to add suggestions
- */
-const inputChanged = (e, target) => {
-  const { value } = e.currentTarget;
-  if (value.length > 0) {
-    e.currentTarget.closest('.search-bar').classList.add('show-suggestions');
-  } else {
-    e.currentTarget.closest('.search-bar').classList.remove('show-suggestions');
-  }
-
-  if (value.length <= 2) {
-    abortSuggestions();
-    target.querySelector(':scope > li:first-of-type').textContent = MORE_INPUT_NEEDED;
-    updateSuggestions([], target);
-  } else {
-    target.querySelector(':scope > li:first-of-type').textContent = SEARCHING_SUGGESTIONS;
-    getSuggestions(value, getSelectedCountry(e.currentTarget.closest('form')))
-      .then((suggestions) => {
-        if (!suggestions) {
-          // Undefined suggestions means it was aborted, more input coming.
-          updateSuggestions([], target);
-          return;
-        }
-        if (suggestions.length) {
-          updateSuggestions(buildSuggestions(suggestions), target);
-        } else {
-          target.querySelector(':scope > li:first-of-type').textContent = NO_SUGGESTIONS;
-        }
-      });
-  }
-};
-
-const suggestionSelected = (e, form) => {
-  const query = e.target.getAttribute('query');
-  const keyword = e.target.getAttribute('display');
-  if (!query) {
-    return;
-  }
-  form.querySelector('input[name="keyword"]').value = keyword;
-  form.querySelector('input[name="query"]').value = query;
-  form.querySelector('.search-bar').classList.remove('show-suggestions');
-};
-
-const formSubmitted = async (e) => {
-  e.preventDefault();
-  e.stopPropagation();
-
-  const spinner = getSpinner();
-  const form = e.currentTarget.closest('form');
-  form.prepend(spinner);
-
-  const franchisee = getMetadata('office-id');
-  const type = SearchType[form.querySelector('input[name="type"]').value];
-  const query = form.querySelector('input[name="query"]').value;
-  const input = form.querySelector('input[name="keyword"]').value;
-  const params = new SearchParameters(type);
-  params.SearchInput = input;
-  if (query) {
-    params.populate(query);
-  }
-
-  if (franchisee) {
-    params.franchisee = franchisee;
-  }
-  params.PageSize = 1;
-  propertySearch(params).then((results) => {
-    if (!results?.properties) {
-      // What to do here?
-      spinner.remove();
-      return;
-    }
-
-    const domain = results.vanityDomain || `https://${DOMAIN}`;
-    const searchPath = '/search';
-    params.PageSize = SearchParameters.DEFAULT_PAGE_SIZE;
-    params.ApplicationType = results.ApplicationType || params.ApplicationType;
-    params.PropertyType = results.PropertyType || params.PropertyType;
-    window.location = `${domain}${searchPath}?${params.asQueryString()}`;
-  });
-};
-
-function addEventListeners() {
-  const form = document.querySelector('.hero.block form.homes');
-
-  noOverlayAt.addEventListener('change', fixOverlay);
-
-  form.querySelectorAll('button[type="submit"]').forEach((button) => {
-    button.addEventListener('click', formSubmitted);
-  });
-
-  form.querySelector('button.filter').addEventListener('click', showFilters);
-
-  form.querySelectorAll('button.close').forEach((button) => {
-    button.addEventListener('click', closeFilters);
-  });
-
-  form.querySelectorAll('.select-wrapper .selected').forEach((button) => {
-    button.addEventListener('click', selectClicked);
-  });
-
-  form.querySelectorAll('.select-wrapper .select-items li').forEach((li) => {
-    li.addEventListener('click', selectFilterClicked);
-  });
-
-  const suggestionsTarget = form.querySelector('.suggester-input .suggester-results');
-  form.querySelector('.suggester-input input').addEventListener('input', (e) => {
-    inputChanged(e, suggestionsTarget);
-  });
-  suggestionsTarget.addEventListener('click', (e) => {
-    suggestionSelected(e, form);
-  });
-}
-
-addEventListeners();
diff --git a/blocks/hero/search/home.css b/blocks/hero/search/home.css
index 974e2e30..962430b2 100644
--- a/blocks/hero/search/home.css
+++ b/blocks/hero/search/home.css
@@ -116,10 +116,16 @@
   right: 0;
 }
 
-.hero.block .content .homes .filters .select-wrapper.open .selected::after {
+.hero.block .content .homes .filters .select-wrapper.open > .selected::after {
   content: '\f0d8';
 }
 
+.hero.block .content .homes .filters .select-wrapper .selected span {
+  font-size: var(--body-font-size-xs);
+  color: var(--input-placeholder);
+}
+
+
 .hero.block .content .homes .filters .select-wrapper .select-items {
   display: none;
   position: absolute;
diff --git a/blocks/hero/search/home.js b/blocks/hero/search/home.js
index 3d89f4e5..fb89fad2 100644
--- a/blocks/hero/search/home.js
+++ b/blocks/hero/search/home.js
@@ -1,61 +1,83 @@
 import {
   build as buildCountrySelect,
 } from '../../shared/search-countries/search-countries.js';
+import { getMetadata, loadScript } from '../../../scripts/aem.js';
+import { getSpinner } from '../../../scripts/util.js';
+import { BED_BATHS, buildFilterSelect, getPlaceholder } from '../../shared/search/util.js';
+import Search, { SEARCH_URL } from '../../../scripts/apis/creg/search/Search.js';
+import { metadataSearch } from '../../../scripts/apis/creg/creg.js';
 
-function observeForm() {
-  const script = document.createElement('script');
-  script.type = 'module';
-  script.src = `${window.hlx.codeBasePath}/blocks/hero/search/home-delayed.js`;
-  document.head.append(script);
+async function observeForm(e) {
+  const form = e.target.closest('form');
+  try {
+    const mod = await import(`${window.hlx.codeBasePath}/blocks/shared/search/suggestion.js`);
+    mod.default(form);
+  } catch (error) {
+    // eslint-disable-next-line no-console
+    console.log('failed to load suggestion library', error);
+  }
+  e.target.removeEventListener('focus', observeForm);
 }
 
-/**
- * Creates a Select dropdown for filtering search.
- * @param {String} name
- * @param {String} placeholder
- * @param {number} number
- * @returns {HTMLDivElement}
- */
-function buildSelect(name, placeholder, number) {
-  const wrapper = document.createElement('div');
-  wrapper.classList.add('select-wrapper');
-  wrapper.innerHTML = `
-    <select name="${name}" aria-label="${placeholder}">
-      <option value="">Bedrooms</option>
-    </select>
-    <div class="selected" role="button" aria-haspopup="listbox" aria-label="${placeholder}">${placeholder}</div>
-    <ul class="select-items" role="listbox">
-      <li role="option">${placeholder}</li>
-    </ul>
-  `;
+async function submitForm(e) {
+  e.preventDefault();
+  e.stopPropagation();
+
+  const spinner = getSpinner();
+  const form = e.currentTarget.closest('form');
+  form.prepend(spinner);
+
+  const type = form.querySelector('input[name="type"]');
 
-  const select = wrapper.querySelector('select');
-  const ul = wrapper.querySelector('ul');
-  for (let i = 1; i <= number; i += 1) {
-    const option = document.createElement('option');
-    const li = document.createElement('li');
-    li.setAttribute('role', 'option');
-
-    option.value = `${i}`;
-    // eslint-disable-next-line no-multi-assign
-    option.textContent = li.textContent = `${i}+`;
-    select.append(option);
-    ul.append(li);
+  let search = new Search();
+  if (type && type.value) {
+    try {
+      const mod = await import(`${window.hlx.codeBasePath}/scripts/apis/creg/search/types/${type.value}Search.js`);
+      if (mod.default) {
+        // eslint-disable-next-line new-cap
+        search = new mod.default();
+      }
+    } catch (error) {
+      // eslint-disable-next-line no-console
+      console.log(`failed to load Search Type for ${type.value}`, error);
+    }
   }
-  return wrapper;
-}
+  search.populateFromSuggestion(new URLSearchParams(form.querySelector('input[name="query"]').value));
+  search.input = form.querySelector('input[name="keyword"]').value;
 
-function getPlaceholder(country) {
-  if (country && country !== 'US') {
-    return 'Enter City';
+  search.minPrice = form.querySelector('input[name="minPrice"]').value;
+  search.maxPrice = form.querySelector('input[name="maxPrice"]').value;
+  search.minBedrooms = form.querySelector('select[name="bedrooms"]').value;
+  search.minBathrooms = form.querySelector('select[name="bathrooms"]').value;
+
+  const franchisee = getMetadata('office-id');
+  if (franchisee) {
+    search.franchisee = franchisee;
   }
-  return 'Enter City, Address, Zip/Postal Code, Neighborhood, School or MLS#';
+  metadataSearch(search).then((results) => {
+    if (results) {
+      let url = '';
+      if (window.location.href.includes('localhost')) {
+        url += `/search?${search.asURLSearchParameters()}`;
+      } else if (results.vanityDomain) {
+        if (getMetadata('vanity-domain') === results.vanityDomain) {
+          url += `/search?${search.asURLSearchParameters()}`;
+        } else {
+          url += `${results.vanityDomain}/search?${search.asCregURLSearchParameters()}`;
+        }
+      } else {
+        url = `https://www.bhhs.com${results.searchPath}/search?${search.asCregURLSearchParameters()}`;
+      }
+      window.location = url;
+    }
+    spinner.remove();
+  });
 }
 
 async function buildForm() {
   const form = document.createElement('form');
   form.classList.add('homes');
-  form.setAttribute('action', '/search');
+  form.setAttribute('action', SEARCH_URL);
 
   form.innerHTML = `
     <div class="mobile-header">
@@ -97,15 +119,16 @@ async function buildForm() {
     <div class="filters">
       <input type="text" placeholder="$ Minimum Price" name="MinPrice" aria-label="minimum price">
       <input type="text" placeholder="$ Maximum Price" name="MaxPrice" aria-label="maximum price">
-      ${buildSelect('MinBedroomsTotal', 'Bedrooms', 12).outerHTML}
-      ${buildSelect('MinBathroomsTotal', 'Bathrooms', 8).outerHTML}
+      ${buildFilterSelect('MinBedroomsTotal', 'Bedrooms', BED_BATHS).outerHTML}
+      ${buildFilterSelect('MinBathroomsTotal', 'Bathrooms', BED_BATHS).outerHTML}
     </div>
     <button class="submit" type="submit">Search</button>
-`;
+  `;
+
+  const input = form.querySelector('.suggester-input input');
 
   const changeCountry = (country) => {
     const placeholder = getPlaceholder(country);
-    const input = form.querySelector('.suggester-input input');
     input.setAttribute('placeholder', placeholder);
     input.setAttribute('aria-label', placeholder);
   };
@@ -115,7 +138,16 @@ async function buildForm() {
       form.querySelector('.search-country-select-parent').append(select);
     }
   });
-  window.setTimeout(observeForm, 3000);
+
+  window.setTimeout(() => {
+    loadScript(`${window.hlx.codeBasePath}/blocks/hero/search/home/filters.js`, { type: 'module' });
+  }, 3000);
+  input.addEventListener('focus', observeForm);
+
+  form.querySelectorAll('button[type="submit"]').forEach((button) => {
+    button.addEventListener('click', submitForm);
+  });
+
   return form;
 }
 
diff --git a/blocks/hero/search/home/filters.js b/blocks/hero/search/home/filters.js
new file mode 100644
index 00000000..0f7bfb41
--- /dev/null
+++ b/blocks/hero/search/home/filters.js
@@ -0,0 +1,74 @@
+import { close as closeCountrySelect } from '../../../shared/search-countries/search-countries.js';
+import { BREAKPOINTS } from '../../../../scripts/scripts.js';
+import { closeOnBodyClick, filterItemClicked } from '../../../shared/search/util.js';
+
+const noOverlayAt = BREAKPOINTS.medium;
+
+const fixOverlay = () => {
+  if (noOverlayAt.matches) {
+    document.body.style.overflowY = 'hidden';
+  } else {
+    document.body.style.overflowY = null;
+  }
+};
+
+const showFilters = (e) => {
+  e.preventDefault();
+  e.stopPropagation();
+  e.currentTarget.closest('form').classList.add('show-filters');
+  if (!noOverlayAt.matches) {
+    document.body.style.overflowY = 'hidden';
+  }
+};
+
+const closeFilters = (e) => {
+  e.preventDefault();
+  e.stopPropagation();
+  const thisForm = e.currentTarget.closest('form');
+  thisForm.classList.remove('show-filters');
+  thisForm.querySelectorAll('.select-wrapper.open').forEach((select) => {
+    select.classList.remove('open');
+  });
+  document.body.style.overflowY = '';
+};
+
+const updateExpanded = (wrapper) => {
+  const wasOpen = wrapper.classList.contains('open');
+  const thisForm = wrapper.closest('form');
+  thisForm.querySelectorAll('.open').forEach((item) => {
+    item.classList.remove('open');
+    item.querySelector('[aria-expanded="true"]')?.setAttribute('aria-expanded', 'false');
+  });
+  if (!wasOpen) {
+    wrapper.classList.add('open');
+    wrapper.querySelector('[aria-expanded="false"]')?.setAttribute('aria-expanded', 'true');
+  }
+  closeOnBodyClick(thisForm);
+};
+
+function addEventListeners() {
+  const form = document.querySelector('.hero.block form.homes');
+  noOverlayAt.addEventListener('change', fixOverlay);
+
+  form.querySelector('button.filter').addEventListener('click', showFilters);
+
+  form.querySelectorAll('button.close').forEach((button) => {
+    button.addEventListener('click', closeFilters);
+  });
+
+  form.querySelectorAll('.select-wrapper .selected').forEach((button) => {
+    button.addEventListener('click', (e) => {
+      e.stopPropagation();
+      e.preventDefault();
+      const thisForm = e.currentTarget.closest('form');
+      closeCountrySelect(thisForm);
+      updateExpanded(e.currentTarget.closest('.select-wrapper'));
+    });
+  });
+
+  form.querySelectorAll('.select-wrapper .select-items li').forEach((li) => {
+    li.addEventListener('click', filterItemClicked);
+  });
+}
+
+addEventListeners();
diff --git a/blocks/hero/search/search.css b/blocks/hero/search/search.css
index 0e4ee323..7f83c4fa 100644
--- a/blocks/hero/search/search.css
+++ b/blocks/hero/search/search.css
@@ -26,7 +26,7 @@
   border-top-right-radius: 0px;
   color: var(--primary-color);
   cursor: default;
-  font-weight: 600;
+  font-weight: var(--font-weight-semibold);
 }
 
 .hero.block > div .content .search .options .option[data-option="agents"] {
@@ -77,17 +77,14 @@
   background-color: var(--white);
   border: 1px solid var(--grey);
   box-shadow: 0 3px 9px 2px rgba(0 0 0 / 23%);
-  z-index: 10;
   line-height: 1.5;
+  z-index: 1000;
 }
 
 .hero.block .content .search-bar.show-suggestions .suggester-results {
   display: block;
 }
 
-.hero.block .content .search-bar .suggester-results > li:first-child:not(:only-child){
-  display: none;
-}
 
 .hero.block .content .search-bar .suggester-results > li > ul {
   padding: 0 15px;
@@ -96,16 +93,20 @@
 .hero.block .content .search-bar .suggester-results > li > ul > li {
   padding: 8px 0;
   font-size: var(--body-font-size-m);
-  font-weight: 400;
+  font-weight: var(--font-weight-normal);
   text-transform: none;
   letter-spacing: normal;
 }
 
+.hero.block .content .search-bar .suggester-results > li:first-child:not(:only-child){
+  display: none;
+}
+
 .hero.block .content .search-bar .suggester-results .list-title {
   padding: 15px 15px 5px;
   font-family: var(--font-family-primary);
   font-size: var(--body-font-size-s);
-  font-weight: 700;
+  font-weight: var(--font-weight-bold);
   text-transform: uppercase;
   letter-spacing: .5px;
 }
@@ -113,7 +114,6 @@
 .hero.block .content .search-bar .search-submit {
   background: var(--primary-color);
   border: none;
-  color: var(--white);
   cursor: pointer;
   flex: unset;
   height: 35px;
@@ -130,6 +130,7 @@
   display: block;
   font-size: var(--body-font-size-xs);
   font-weight: var(--font-weight-bold);
+  color: var(--white);
   text-align: center;
   width: 100%;
 }
@@ -143,7 +144,7 @@
 
 @media screen and (min-width: 900px) {
   .hero.block .content .search-bar {
-    width: 620px;
+    width: 680px;
     padding: 10px;
   }
 }
diff --git a/blocks/login/login.js b/blocks/login/login.js
index 4367f789..7a40b4b1 100644
--- a/blocks/login/login.js
+++ b/blocks/login/login.js
@@ -72,7 +72,7 @@ function initLogin() {
 
 export default async function decorate(block) {
   i18n = await i18nLookup();
-
+  /* eslint-disable max-len */
   block.innerHTML = `
     <div class="login-overlay"></div>
     <div class="login-form">
@@ -139,6 +139,8 @@ export default async function decorate(block) {
       </div>
     </div>
   `;
+  /* eslint-enable max-len */
+
   observeForm();
   initLogin();
 }
diff --git a/blocks/property-listing/map-search.js b/blocks/property-listing/map-search.js
deleted file mode 100644
index 3501c1d1..00000000
--- a/blocks/property-listing/map-search.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import SearchType from '../../scripts/apis/creg/SearchType.js';
-import Search from './search.js';
-
-/**
- * Create and render property search based on a bounding box.
- */
-export default class MapSearch extends Search {
-  more = false;
-
-  #minLat;
-
-  #minLon;
-
-  #maxLat;
-
-  #maxLon;
-
-  constructor(minLat, minLon, maxLat, maxLon) {
-    super(SearchType.Map, SearchType.Map.paramBuilder(minLat, maxLat, minLon, maxLon));
-    this.#minLat = minLat;
-    this.#minLon = minLon;
-    this.#maxLat = maxLat;
-    this.#maxLon = maxLon;
-  }
-}
diff --git a/blocks/property-listing/property-listing.css b/blocks/property-listing/property-listing.css
index 91e4cca1..021d44fc 100644
--- a/blocks/property-listing/property-listing.css
+++ b/blocks/property-listing/property-listing.css
@@ -1,5 +1,5 @@
 @import url('luxury-collection-template.css');
-@import url('./cards/cards.css');
+@import url('../shared/property/cards.css');
 
 .property-listing.block {
   overflow: hidden;
diff --git a/blocks/property-listing/property-listing.js b/blocks/property-listing/property-listing.js
index b5587445..7c714bb4 100644
--- a/blocks/property-listing/property-listing.js
+++ b/blocks/property-listing/property-listing.js
@@ -1,64 +1,7 @@
 import { getMetadata, readBlockConfig } from '../../scripts/aem.js';
-import ApplicationType from '../../scripts/apis/creg/ApplicationType.js';
-import SearchType, { searchTypeFor } from '../../scripts/apis/creg/SearchType.js';
-import PropertyType from '../../scripts/apis/creg/PropertyType.js';
-import MapSearch from './map-search.js';
-import RadiusSearch from './radius-search.js';
-
-/* eslint-disable no-param-reassign */
-const buildListingTypes = (configEntry) => {
-  const types = [];
-  if (!configEntry) {
-    types.push(ApplicationType.FOR_SALE);
-    return types;
-  }
-
-  const [, configStr] = configEntry;
-  if (configStr.match(/sale/i)) {
-    types.push(ApplicationType.FOR_SALE);
-  }
-  if (configStr.match(/rent/gi)) {
-    types.push(ApplicationType.FOR_RENT);
-  }
-  if (configStr.match(/pending/gi)) {
-    types.push(ApplicationType.PENDING);
-  }
-  if (configStr.match(/sold/gi)) {
-    types.push(ApplicationType.RECENTLY_SOLD);
-  }
-  return types;
-};
-/* eslint-enable no-param-reassign */
-
-const buildPropertyTypes = (configEntry) => {
-  const types = [];
-  if (!configEntry) {
-    types.push(PropertyType.CONDO_TOWNHOUSE);
-    types.push(PropertyType.SINGLE_FAMILY);
-    return types;
-  }
-
-  const [, configStr] = configEntry;
-  if (configStr.match(/(condo|townhouse)/i)) {
-    types.push(PropertyType.CONDO_TOWNHOUSE);
-  }
-  if (configStr.match(/single\sfamily/gi)) {
-    types.push(PropertyType.SINGLE_FAMILY);
-  }
-  if (configStr.match(/commercial/gi)) {
-    types.push(PropertyType.COMMERCIAL);
-  }
-  if (configStr.match(/multi\s+family/gi)) {
-    types.push(PropertyType.MULTI_FAMILY);
-  }
-  if (configStr.match(/(lot|land)/gi)) {
-    types.push(PropertyType.LAND);
-  }
-  if (configStr.match(/(farm|ranch)/gi)) {
-    types.push(PropertyType.FARM);
-  }
-  return types;
-};
+import { render as renderCards } from '../shared/property/cards.js';
+import Search from '../../scripts/apis/creg/search/Search.js';
+import { propertySearch } from '../../scripts/apis/creg/creg.js';
 
 export default async function decorate(block) {
   // Find and process list type configurations.
@@ -85,54 +28,12 @@ export default async function decorate(block) {
     block.innerHTML = '';
   }
 
-  let search;
-
-  const entries = Object.entries(config);
-  const type = searchTypeFor(entries.find(([k]) => k.match(/search.*type/i))[1]);
-
-  if (type === SearchType.Map) {
-    const minLat = entries.find(([k]) => k.includes('min') && k.includes('lat'))[1];
-    const maxLat = entries.find(([k]) => k.includes('max') && k.includes('lat'))[1];
-    const minLon = entries.find(([k]) => k.includes('min') && k.includes('lon'))[1];
-    const maxLon = entries.find(([k]) => k.includes('max') && k.includes('lon'))[1];
-    search = new MapSearch(minLat, minLon, maxLat, maxLon);
-  } else if (type === SearchType.Radius) {
-    let lat = entries.find(([k]) => k.includes('lat'))[1];
-    let lon = entries.find(([k]) => k.includes('lon'))[1];
-    const radius = entries.find(([k]) => k.includes('distance'))[1];
-
-    // Go looking for the search parameters.
-    if (!lat) {
-      const urlParams = new URLSearchParams(window.location.search);
-      lat = urlParams.get('latitude');
-      lon = urlParams.get('longitude');
-    }
-
-    search = new RadiusSearch(lat, lon, radius);
-  } else if (type === SearchType.Community) {
-    const { bbox } = window.liveby.geometry;
-    const minLon = Math.min(...bbox.map((e) => e[0]));
-    const maxLon = Math.max(...bbox.map((e) => e[0]));
-    const minLat = Math.min(...bbox.map((e) => e[1]));
-    const maxLat = Math.max(...bbox.map((e) => e[1]));
-    search = new MapSearch(minLat, minLon, maxLat, maxLon);
-  } else {
-    search = new MapSearch(0, 0, 0, 0);
-  }
-
-  search.listingTypes = buildListingTypes(entries.find(([k]) => k.match(/listing.*type/i)));
-  search.propertyTypes = buildPropertyTypes(entries.find(([k]) => k.match(/property.*type/i)));
-
-  search.isNew = !!entries.find(([k]) => k.match(/new/i));
-  search.isOpenHouse = !!entries.find(([k]) => k.match(/open.*house/i));
-
-  [, search.minPrice] = entries.find(([k]) => k.match(/min.*price/i)) || [];
-  [, search.maxPrice] = entries.find(([k]) => k.match(/max.*price/i)) || [];
-
-  [, search.pageSize] = entries.find(([k]) => k.match(/page.*size/i)) || [];
-  search.sortBy = config['sort-by'];
-  search.sortDirection = config['sort-direction'];
-  search.officeId = getMetadata('office-id');
-
-  await search.render(block, false);
+  const search = await Search.fromBlockConfig(config);
+  search.franchiseeCode = getMetadata('office-id');
+  const list = document.createElement('div');
+  list.classList.add('property-list-cards', `rows-${Math.floor(search.pageSize / 8)}`);
+  block.append(list);
+  propertySearch(search).then((results) => {
+    renderCards(list, results.properties);
+  });
 }
diff --git a/blocks/property-listing/radius-search.js b/blocks/property-listing/radius-search.js
deleted file mode 100644
index 5fc78824..00000000
--- a/blocks/property-listing/radius-search.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import SearchType from '../../scripts/apis/creg/SearchType.js';
-import Search from './search.js';
-
-/**
- * Create and render property search based on a point and radius.
- */
-export default class RadiusSearch extends Search {
-  more = false;
-
-  #lat;
-
-  #lon;
-
-  #radius;
-
-  constructor(lat, lon, radius) {
-    super(SearchType.Radius, SearchType.Radius.paramBuilder(lat, lon, radius));
-    this.#lat = lat;
-    this.#lon = lon;
-    this.#radius = radius;
-  }
-}
diff --git a/blocks/property-listing/search.js b/blocks/property-listing/search.js
deleted file mode 100644
index a9fdac62..00000000
--- a/blocks/property-listing/search.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import SearchParameters, { SortDirections, SortOptions } from '../../scripts/apis/creg/SearchParameters.js';
-import { render as renderCards } from './cards/cards.js';
-// eslint-disable-next-line no-unused-vars
-import SearchType from '../../scripts/apis/creg/SearchType.js';
-
-// function addMoreButton() {
-// TODO: add this logic if there's supposed to be more results;
-// }
-
-export default class Search {
-  #searchParams;
-
-  /**
-   * Create a new Search object. (should not be called directly)
-   *
-   * @param {SearchType} type
-   * @param {string} params the result of the paramBuilder for the specified type.
-   */
-  constructor(type, params) {
-    this.#searchParams = new SearchParameters(type, params);
-  }
-
-  isNew;
-
-  isOpenHouse;
-
-  listingTypes;
-
-  maxPrice;
-
-  minPrice;
-
-  officeId;
-
-  pageSize;
-
-  propertyTypes;
-
-  sortBy;
-
-  sortDirection;
-
-  // eslint-disable-next-line no-unused-vars
-  async render(parent, enableMore = false) {
-    this.#searchParams.MinPrice = this.minPrice;
-    this.#searchParams.MaxPrice = this.maxPrice;
-    this.#searchParams.PageSize = this.pageSize || SearchParameters.DEFAULT_PAGE_SIZE;
-    this.#searchParams.sortBy = this.sortBy || SortOptions.DATE;
-    this.#searchParams.sortDirection = this.sortDirection || SortDirections.DESC;
-    this.#searchParams.propertyTypes = this.propertyTypes;
-    this.#searchParams.applicationTypes = this.listingTypes;
-    this.#searchParams.NewListing = this.isNew || this.#searchParams.NewListing;
-    this.#searchParams.OpenHouses = this.isOpenHouse ? '7' : undefined;
-    this.#searchParams.franchisee = this.officeId;
-
-    await renderCards(this.#searchParams, parent);
-    // TODO: Enable the "Load More" for the Property Search page.
-  }
-}
diff --git a/blocks/property-result-listing/property-result-listing.css b/blocks/property-result-listing/property-result-listing.css
deleted file mode 100644
index be4683ee..00000000
--- a/blocks/property-result-listing/property-result-listing.css
+++ /dev/null
@@ -1,350 +0,0 @@
-@import url('../property-listing/cards/cards.css');
-@import url('../property-search-bar/search-results-dropdown.css');
-@import url('../property-result-map/map.css');
-
-.property-result-listing.block {
-  display: flex;
-  flex-wrap: wrap;
-}
-
-.property-result-listing.block .search-results-loader {
-  position: relative;
-  overflow: hidden;
-  z-index: 0;
-}
-
-.property-result-listing.block .search-results-loader-image.enter {
-  opacity: 1;
-}
-
-.property-result-listing.block .search-results-loader-image.exit {
-  opacity: 0;
-  pointer-events: none;
-  z-index: -1;
-}
-
-.property-result-listing.block .search-results-loader-image {
-  text-align: center;
-  margin: 0 !important;
-  z-index: 1;
-  height: 100%;
-  width: 100%;
-  display: flex;
-  align-items: flex-start;
-  justify-content: center;
-  background-color: var(--white);
-  transition: all 1s ease-in;
-}
-
-.property-search-template.search-map-active .property-result-listing.block > div {
-  flex: 0 0 50%;
-  max-width: 50%;
-  padding: 0 15px;
-}
-
-.property-result-listing.block .button-container {
-  display: flex;
-  margin-bottom: 1.5rem;
-}
-
-.property-result-listing.block .hide {
-  display: none;
-}
-
-.property-result-listing.block .property-list-cards {
-  display: grid;
-  grid-template: repeat(8, 1fr) / repeat(4, 1fr);
-  height: 3340px;
-  grid-gap: 20px;
-}
-
-.search-map-active .property-result-listing.block .property-list-cards{
-  height: 6520px;
-  grid-template: repeat(16, 1fr) / repeat(2, 1fr);
-}
-
-
-.property-result-listing.block .button-container a {
-  cursor:pointer;
-  font-family: var(--font-family-primary);
-  letter-spacing: 1px;
-  text-transform: uppercase;
-  text-decoration: none;
-  padding: 7px 25px;
-  font-size: var(--body-font-size-xs);
-  line-height: 1.5;
-  border-radius: 0;
-  background: var(--white);
-  color: var(--black);
-  display: inline-block;
-  font-weight: 400;
-  text-align: center;
-  white-space: nowrap;
-  vertical-align: middle;
-  border: 1px solid var(--black);
-}
-
-.property-result-listing.block .button-container a:hover {
-  border-color: var(--grey);
-}
-
-.property-result-listing.block .property-list-cards .property-labels .property-label.new-listing {
-  text-transform: initial;
-}
-
-.property-result-listing.block [name="Page"].multiple-inputs .select-item{
-  left: 0;
-  border: 1px solid var(--platinum);
-  max-height: 185px;
-  overflow-y: scroll;
-  overflow-x: hidden;
-  width: 93px;
-  display: block;
-}
-
-.property-result-listing.block [name="Page"].multiple-inputs .select-item.hide {
-  display: none;
-}
-
-.property-result-listing.block [name="Page"] {
-  display: flex;
-  justify-content: flex-end;
-}
-
-.property-result-listing.block [name="Page"] .select-selected,
-.property-result-listing.block [name="Page"] .search-results-dropdown .select-item li {
-  font-size: var(--body-font-size-xs);
-  letter-spacing: var(--letter-spacing-reg);
-  color: var(--body-color);
-  cursor: pointer;
-}
-
-.property-result-listing.block [name="Page"] .select-wrapper {
-  position: relative;
-  width: 91px;
-}
-
-.property-result-listing.block [name="Page"] .select-selected {
-  border: 1px solid var(--grey);
-  height: 35px;
-  line-height: 35px;
-  padding: 0 15px;
-  white-space: nowrap;
-}
-
-.property-result-listing.block [name="Page"] .select-selected::after {
-  right: 5px;
-}
-
-.property-result-listing.block [name="Page"] .search-results-dropdown .select-item li:first-child {
-  border-top: none;
-}
-
-.property-result-listing.block [name="Page"] .search-results-dropdown .select-item li:last-child {
-  border-bottom: none;
-}
-
-.property-result-listing.block .pagination-arrows {
-  display: flex;
-  justify-content: flex-end;
-  line-height: 32px;
-}
-
-.property-result-listing.block .pagination-arrows .arrow {
-  border: 1px solid #ced4da;
-  position: relative;
-  height: 35px;
-  width: 35px;
-  padding: 4px;
-  cursor: pointer;
-  text-align: center
-}
-
-.property-result-listing.block .pagination-arrows .arrow.disabled {
-  cursor: auto;
-  border: 1px solid #adb5bd;
-}
-
-.property-result-listing.block .pagination-arrows .arrow.disabled::after {
-  border: solid #ced4da;
-  border-width: 0 2px 2px 0;
-}
-
-.property-result-listing.block .pagination-arrows .arrow.prev {
-  margin-left: 0.5rem !important
-}
-
-.property-result-listing.block .pagination-arrows .arrow::after {
-  content: "";
-  border: solid black;
-  border-width: 0 2px 2px 0;
-  display: inline-block;
-  padding: 7px;
-}
-
-.property-result-listing.block .pagination-arrows .arrow.prev::after {
-  transform: rotate(135deg) translate(-3px,-3px);
-}
-
-.property-result-listing.block .pagination-arrows .arrow.next::after {
-  transform: rotate(-45deg) translate(-3px,-3px);
-}
-
-.property-result-listing.block .disclaimer {
-  font-family: var(--font-family-primary);
-  font-size: var(--body-font-size-xs);
-  font-weight: var(--font-weight-normal);
-  letter-spacing: var(--letter-spacing-s);
-  color: var(--dark-grey);
-  line-height: var(--line-height-m);
-}
-
-.property-result-listing.block .disclaimer hr {
-  height: 1px;
-  background: var(--grey);
-  width: 100%;
-  margin: 30px 0 0;
-  padding: 0;
-  display: block;
-  border: 0
-}
-
-.property-result-listing.block .disclaimer td[align="center"] {
-text-align: center;
-}
-
-.property-result-listing.block .disclaimer td[align="left"] {
-  text-align: left;
-}
-
-.property-result-listing.block .disclaimer td[align="right"] {
-  text-align: right;
-}
-
-.property-result-listing.block .disclaimer * {
-  font-size: var(--body-font-size-xs);
-}
-
-.property-result-listing.block .disclaimer .text {
-  color: var(--body-color);
-  font-size: var(--body-font-size-xs);
-  line-height: var(--line-height-s);
-  margin: 30px 0;
-  column-gap: 50px;
-}
-
-.property-result-listing.block .disclaimer .text-center {
-  text-align: center;
-}
-
-.property-result-listing.block .disclaimer .text img {
-  height: auto;
-  margin: 0;
-  padding: 0;
-  width: 30%
-}
-
-.property-result-listing.block .property-search-results-buttons {
-  display: flex;
-  position: fixed;
-  bottom: 0;
-  left: 0;
-  z-index: 5;
-  background: var(--white);
-  width: 100%;
-  justify-content: center;
-  padding: 10px 0;
-  box-shadow: 0 0 6px 0 rgb(0 0 0 / 23%);
-  cursor: pointer;
-}
-
-.property-result-listing.block .property-search-results-buttons .btn.btn-map {
-  font-size: var(--body-font-size-xs);
-  height: 35px;
-  background: var(--white);
-  border: 1px solid var(--grey);
-  padding: 0 15px;
-  line-height: var(--line-height-xxl);
-  display: inline-block;
-}
-
-.property-result-listing.block .property-search-results-buttons section:first-of-type {
-  margin-right: 16px;
-}
-
-.property-result-listing.block .property-search-results-buttons .btn.btn-map span {
-  font-size: var(--body-font-size-xs);
-  color: var(--body-color);
-}
-
-@media (min-width: 900px) {
-  .property-result-listing.block .button-container {
-    justify-content: flex-end;
-  }
-
-  .property-result-listing.block [class*="disclaimer"] * {
-    font-family: var(--font-family-primary);
-    font-size: var(--body-font-size-xs);
-    color: var(--dark-grey);
-    line-height: var(--line-height-s);
-    letter-spacing: var(--letter-spacing-s);
-    opacity: 1;
-  }
-
-  .property-result-listing.block [class*="disclaimer"] * p {
-    font-family: var(--font-family-primary);
-    font-size: var(--body-font-size-xs);
-    color: var(--dark-grey);
-    line-height: var(--line-height-s);
-    letter-spacing: var(--letter-spacing-s);
-  }
-
-  .property-result-listing.block .property-search-results-buttons {
-    display: none;
-  }
-}
-
-@media (max-width: 899px) {
-  .property-result-listing.block {
-    width: 100%;
-    flex-direction: column-reverse;
-  }
-
-  .property-result-listing.block .property-list-cards {
-    grid-template: repeat(32, 1fr) / repeat(1, 1fr);
-    height: 13440px;
-  }
-
-  .property-result-listing.block .property-list-cards .listing-tile {
-    width: 100%;
-    max-width: 100%;
-  }
-
-  .search-map-active .property-result-listing.block {
-    width: 100%;
-    min-height: 800px;
-  }
-
-  .search-map-active .property-result-listing.block .property-list-cards,
-  .search-map-active .property-result-listing.block [name="Page"],
-  .search-map-active .property-result-listing.block .property-list-cards .property-result-content .disclaimer {
-    display: none;
-  }
-
-  .property-search-template.search-map-active .property-result-listing.block > div {
-    flex: 0 0 100%;
-    max-width: 100%;
-    padding: 0 15px;
-  }
-}
-
-
-@media (min-width: 1200px) {
-  .property-result-listing.block .property-info-wrapper {
-    font-size: var(--body-font-size-xl);
-  }
-
-  .property-result-listing.block .property-list-cards {
-    grid-template: repeat(8, 1fr) / repeat(4, 1fr);
-  }
-}
diff --git a/blocks/property-result-listing/property-result-listing.js b/blocks/property-result-listing/property-result-listing.js
deleted file mode 100644
index c72db6ab..00000000
--- a/blocks/property-result-listing/property-result-listing.js
+++ /dev/null
@@ -1,200 +0,0 @@
-import { createCard } from '../property-listing/cards/cards.js';
-import {
-  getDisclaimer,
-  getPropertiesCount,
-  getPropertyDetails,
-  getAllData,
-} from '../../scripts/search/results.js';
-import { getValueFromStorage, searchProperty, setFilterValue } from '../property-search-bar/filter-processor.js';
-import renderMap from '../property-result-map/map.js';
-import {
-  showModal,
-} from '../../scripts/util.js';
-
-const event = new Event('onFilterChange');
-const ITEMS_PER_PAGE = 32;
-function buildLoader() {
-  const wrapper = document.createElement('div');
-  wrapper.classList.add('search-results-loader');
-  wrapper.innerHTML = `
-    <div class="search-results-loader-image enter">
-    <video autoplay loop muted playsinline>
-        <source src="/icons/maps/loader_opt.webm" type="video/webm" />
-        <source src="/icons/maps/loader_opt.mp4" type="video/mp4" />
-     </video>
-    </div>
-  `;
-  return wrapper;
-}
-function updateStyles(count, div, items = 4) {
-  if (count < ITEMS_PER_PAGE) {
-    // adjust block height
-    const lines = Math.ceil(count / items);
-    const height = lines * 400 + 20 * (lines - 1);
-    div.style.height = `${height}px`;
-    div.style.gridTemplate = `repeat(${lines}, 400px) / repeat(${items}, 1fr)`;
-  } else {
-    div.style = '';
-  }
-}
-
-function buildPropertySearchResultsButton() {
-  const wrapper = document.createElement('div');
-  wrapper.classList.add('property-search-results-buttons');
-  wrapper.innerHTML = `
-      <section>
-        <a rel="noopener" target="_blank" tabIndex="" class="btn btn-map" role="button">
-          <span class="text-up">Save</span>
-        </a>
-      </section>
-      <section>
-          <a rel="noopener" target="_blank" tabIndex="" class="btn btn-map map" role="button">
-            <span class="text-up">list view</span>
-          </a>
-        </section>
-    `;
-  return wrapper;
-}
-
-function buildDisclaimer(html) {
-  const wrapper = document.createElement('div');
-  wrapper.classList.add('disclaimer');
-  wrapper.innerHTML = `
-    <hr role="presentation" aria-hidden="true" tabindex="-1"> 
-    <div class="text">
-    ${html}
-    </div>
-  `;
-  return wrapper;
-}
-
-function buildPagination(currentPage, totalPages) {
-  // set map view
-  document.querySelector('body').classList.add('search-map-active');
-  const wrapper = document.createElement('div');
-  wrapper.setAttribute('name', 'Page');
-  wrapper.classList.add('multiple-inputs');
-  let options = '';
-  let list = '';
-  for (let i = 1; i <= totalPages; i += 1) {
-    options += `<option value="${i}">${i}</option>`;
-  }
-  for (let i = 1; i <= totalPages; i += 1) {
-    list += `<li data-value="${i}" role="option">${i}</li>`;
-  }
-  wrapper.innerHTML = `
-        <div class="search-results-dropdown">
-            <div class="select-wrapper">
-                <select class ="hide" aria-label="${`${currentPage} of ${totalPages}`}">${options}</select>
-                <div class="select-selected text-up" role="button" aria-haspopup="listbox">
-                    ${`${currentPage} of ${totalPages}`}
-                </div>
-                <ul class="select-item hide" role="listbox">
-                    ${list}
-                </ul>
-            </div>
-        </div>
-        <div class="pagination-arrows">
-          <a class="prev arrow ${currentPage === 1 && 'disabled'}" role="button" aria-label="Previous Page"></a> 
-          <a class="next arrow ${currentPage === totalPages && 'disabled'}" role="button" aria-label="Next Page"></a>
-        </div>`;
-  return wrapper;
-}
-
-export default async function decorate(block) {
-  block.textContent = '';
-  block.append(buildLoader());
-  await renderMap(block);
-  window.dispatchEvent(event);
-  window.addEventListener('onResultUpdated', () => {
-    if (getPropertiesCount() > 0) {
-      document.querySelector('.property-result-map-container').style.display = 'block';
-      const propertyResultContent = document.createElement('div');
-      propertyResultContent.classList.add('property-result-content');
-      const listings = getPropertyDetails();
-      const div = document.createElement('div');
-      div.classList.add('property-list-cards');
-      const currentPage = parseInt(getValueFromStorage('Page'), 10);
-      const totalPages = Math.ceil(getPropertiesCount() / ITEMS_PER_PAGE);
-      const disclaimerHtml = getDisclaimer() === '' ? '' : getDisclaimer().Text;
-
-      const disclaimerBlock = buildDisclaimer(disclaimerHtml);
-      let nextPage;
-      listings.forEach((listing) => {
-        div.append(createCard(listing));
-      });
-      updateStyles(listings.length, div, 2);
-      propertyResultContent.append(div);
-      /** add pagination */
-      propertyResultContent.append(buildPagination(currentPage, totalPages));
-      /** add property search results button */
-      propertyResultContent.append(buildPropertySearchResultsButton());
-      /** build disclaimer */
-      propertyResultContent.append(buildDisclaimer(disclaimerHtml));
-      block.prepend(propertyResultContent);
-
-      // update map
-      window.updatePropertyMap(getAllData(), false);
-
-      document.querySelector('.property-result-map-container').append(disclaimerBlock);
-      /** update page on select change */
-      block.querySelector('[name="Page"] .select-selected').addEventListener('click', () => {
-        block.querySelector('[name="Page"] ul').classList.toggle('hide');
-      });
-      block.querySelector('[name="Page"] ul').addEventListener('click', (e) => {
-        e.preventDefault();
-        e.stopPropagation();
-        nextPage = e.target.closest('li').getAttribute('data-value');
-        setFilterValue('Page', nextPage);
-        block.querySelector('[name="Page"] ul').classList.toggle('hide');
-        searchProperty();
-      });
-      /** update page on arrow click */
-      block.querySelector('.pagination-arrows .arrow.prev').addEventListener('click', (e) => {
-        if (!e.target.closest('.arrow').classList.contains('disabled')) {
-          e.preventDefault();
-          e.stopPropagation();
-          setFilterValue('Page', currentPage - 1);
-          searchProperty();
-        }
-      });
-      block.querySelector('.pagination-arrows .arrow.next').addEventListener('click', (e) => {
-        if (!e.target.closest('.arrow').classList.contains('disabled')) {
-          e.preventDefault();
-          e.stopPropagation();
-          setFilterValue('Page', currentPage + 1);
-          searchProperty();
-        }
-      });
-      document.querySelector('.map-toggle > a').addEventListener('click', (e) => {
-        const span = e.target.closest('span');
-        if (span.innerText === 'GRID VIEW') {
-          span.innerText = 'map view';
-          document.querySelector('body').classList.remove('search-map-active');
-          updateStyles(listings.length, div, 4);
-        } else {
-          span.innerText = 'grid view';
-          document.querySelector('body').classList.add('search-map-active');
-          updateStyles(listings.length, div, 2);
-        }
-      });
-      block.querySelector('.property-search-results-buttons .map').addEventListener('click', (e) => {
-        e.preventDefault();
-        e.stopPropagation();
-        const span = e.target.closest('span');
-        if (span.innerText === 'LIST VIEW') {
-          span.innerText = 'map view';
-          document.querySelector('body').classList.remove('search-map-active');
-          updateStyles(listings.length, div, 1);
-        } else {
-          span.innerText = 'list view';
-          document.querySelector('body').classList.add('search-map-active');
-        }
-      });
-    } else {
-      document.querySelector('.property-result-map-container').style.display = 'none';
-      showModal('Your search returned 0 results.\n'
-          + 'Please modify your search and try again.');
-    }
-  });
-}
diff --git a/blocks/property-result-map/Template.js b/blocks/property-result-map/Template.js
deleted file mode 100644
index 9c98da94..00000000
--- a/blocks/property-result-map/Template.js
+++ /dev/null
@@ -1,93 +0,0 @@
-export default class Template {
-  // eslint-disable-next-line class-methods-use-this
-  render = (data) => {
-    const luxuryHTML = data.luxury && data.isCompanyListing
-      ? `div class="position-absolute top w-100">
-                <div class="cmp-property-tile__image-labels">
-                    <span class="cmp-property-tile__label--luxury text-uppercase">${data.luxuryLabel}</span>
-                </div>
-            </div>`
-      : '';
-    const soldHTML = data.sellingOfficeName ? `<div class="text-danger">${data.mlsStatus} ${data.ClosedDate}<br/></div>` : '';
-    const municipalityHTML = data.municipality ? `<div class="address">${data.municipality}</div>` : '';
-    const CourtesyOfHr = data.CourtesyOf ? `
-          <hr style="margin-top: 0px; margin-bottom: 0px;">` : '';
-    const addMlsFlagHTML = data.addMlsFlag ? `<span  class="cmp-property-tile__extra-info" style="padding-left: 0px">MLS ID: ${data.ListingId} </span>` : '';
-    const courtersyHTML = data.CourtesyOf ? `
-      <span class="cmp-property-tile__extra-info" style="padding-left: 0px">Listing courtesy of: ${data.CourtesyOf} </span>` : '';
-    const sellingOfficeNameHTML = data.sellingOfficeName ? `
-          <span class="cmp-property-tile__extra-info" style="padding-left: 0px">Listing sold by: ${data.sellingOfficeName} </span>` : '';
-    const addMLsFlagHTML = data.addMlsFlag ? `
-          <div class="cmp-property-tile__extra-info d-flex align-items-center justify-content-between" style="padding: 0px; margin-top: -5px;"><div>Listing Provided by: ${data.listAor}</div>
-  ${data.listAor}
-  ${data.brImageUrl}
-      <div class="cmp-property-search-results__disclaimer__logo" >
-          <div style="background-image:url(${data.brImageUrl}); background-size: contain;
-                background-repeat: no-repeat;
-                width: 60px;
-                height: 30px;"></div>
-          ${data.ImageUrl}
-      </div>
-  </div>
-      ${data.ddMlsFlag}` : '';
-    return `<div class="info-window">
-    <a href="${data.linkUrl}" rel="noopener">
-        <div class="property-image" style="background-image:url(${data.image}); background-size:cover;">
-            ${luxuryHTML}
-        </div>
-        <div class="info" style="padding: 5px">
-            <div class="d-flex align-items-center p-0" style="flex-wrap:wrap;">
-                <div class="price">${data.price}</div><br/>
-                <div class="altPrice">${data.altCurrencyPrice || ''}</div>
-                <div class="btn-contact-property p-0 mr-2"
-                     data-brand="undefined"
-                     data-lead-param="CompanyKey=CA321&amp;LeadBrand=11413101001000010000"
-                     data-pdp-path="https://www.bhhsfranciscan.com/ca/224-sea-cliff-avenue-san-francisco-94121/pid-2217354422?lead=CompanyKey%3DCA321%26LeadBrand%3D11413101001000010000"
-                     data-prop-id="${data.propertyId}"
-                     data-street-name="${data.address}"
-                     data-city="${data.city}"
-                     data-state-or-province="${data.stateOrProvince}"
-                     data-postal-code="${data.postalCode}"
-                     data-providers="${data.providers || ''}"
-                >
-                    <svg class="envelope">
-                        <use xlink:href="/icons/icons.svg#envelope"></use>
-                    </svg>
-                    <svg class="envelope-dark">
-                        <use xlink:href="/icons/icons.svg#envelope-dark"></use>
-                    </svg>
-                </div>
-                <div class="btn-save-property p-0 mr-2" data-prop-id="${data.propertyId}" data-street-name="${data.address}">
-                    <svg class="empty">
-                        <use xlink:href="/icons/icons.svg#heart-empty"></use>
-                    </svg>
-                    <svg class="empty-dark">
-                        <use xlink:href="/icons/icons.svg#heart-empty-dark"></use>
-                    </svg>
-                    <svg class="full">
-                        <use xlink:href="/icons/icons.svg#heart-full"></use>
-                    </svg>
-                </div>
-            </div>
-            <div class="address">
-                ${soldHTML}
-                <div>
-                    ${data.address || ''}<br/>
-                    ${data.city || ''}, ${data.stateOrProvince || ''} ${data.postalCode || ''}
-                </div>
-            </div>
-            ${municipalityHTML}
-            <div class="providers">${data.providers || ''}</div>
-            ${CourtesyOfHr}
-            <div>
-                ${addMlsFlagHTML}
-                ${courtersyHTML}
-                ${sellingOfficeNameHTML}
-            </div>
-            ${addMLsFlagHTML}
-        </div>
-    </a>
-    <div class="arrow"></div>
-</div>`;
-  };
-}
diff --git a/blocks/property-result-map/map-delayed.js b/blocks/property-result-map/map-delayed.js
deleted file mode 100644
index f9c4ab81..00000000
--- a/blocks/property-result-map/map-delayed.js
+++ /dev/null
@@ -1,1069 +0,0 @@
-/* global google */
-/* eslint-disable no-param-reassign,  no-shadow,  prefer-rest-params */
-
-import { fetchPlaceholders } from '../../scripts/aem.js';
-import { removeFilterValue, searchProperty, setFilterValue } from '../property-search-bar/filter-processor.js';
-import Template from './Template.js';
-import SearchParameters from '../../scripts/apis/creg/SearchParameters.js';
-import { propertySearch } from '../../scripts/apis/creg/creg.js';
-
-const Nr = [{
-  featureType: 'administrative',
-  elementType: 'labels.text.fill',
-  stylers: [{
-    color: '#444444',
-  }],
-}, {
-  featureType: 'administrative.locality',
-  elementType: 'labels.text.fill',
-  stylers: [{
-    saturation: '-42',
-  }, {
-    lightness: '-53',
-  }, {
-    gamma: '2.98',
-  }],
-}, {
-  featureType: 'administrative.neighborhood',
-  elementType: 'labels.text.fill',
-  stylers: [{
-    saturation: '1',
-  }, {
-    lightness: '31',
-  }, {
-    weight: '1',
-  }],
-}, {
-  featureType: 'administrative.neighborhood',
-  elementType: 'labels.text.stroke',
-  stylers: [{
-    visibility: 'off',
-  }],
-}, {
-  featureType: 'administrative.land_parcel',
-  elementType: 'labels.text.fill',
-  stylers: [{
-    lightness: '12',
-  }],
-}, {
-  featureType: 'landscape',
-  elementType: 'all',
-  stylers: [{
-    saturation: '67',
-  }],
-}, {
-  featureType: 'landscape.man_made',
-  elementType: 'geometry.fill',
-  stylers: [{
-    visibility: 'on',
-  }, {
-    color: '#ececec',
-  }],
-}, {
-  featureType: 'landscape.natural',
-  elementType: 'geometry.fill',
-  stylers: [{
-    visibility: 'on',
-  }],
-}, {
-  featureType: 'landscape.natural.landcover',
-  elementType: 'geometry.fill',
-  stylers: [{
-    visibility: 'on',
-  }, {
-    color: '#ffffff',
-  }, {
-    saturation: '-2',
-  }, {
-    gamma: '7.94',
-  }],
-}, {
-  featureType: 'landscape.natural.terrain',
-  elementType: 'geometry',
-  stylers: [{
-    visibility: 'on',
-  }, {
-    saturation: '94',
-  }, {
-    lightness: '-30',
-  }, {
-    gamma: '8.59',
-  }, {
-    weight: '5.38',
-  }],
-}, {
-  featureType: 'poi',
-  elementType: 'all',
-  stylers: [{
-    visibility: 'off',
-  }],
-}, {
-  featureType: 'poi.park',
-  elementType: 'geometry',
-  stylers: [{
-    saturation: '-26',
-  }, {
-    lightness: '20',
-  }, {
-    weight: '1',
-  }, {
-    gamma: '1',
-  }],
-}, {
-  featureType: 'poi.park',
-  elementType: 'geometry.fill',
-  stylers: [{
-    visibility: 'on',
-  }],
-}, {
-  featureType: 'road',
-  elementType: 'all',
-  stylers: [{
-    saturation: -100,
-  }, {
-    lightness: 45,
-  }],
-}, {
-  featureType: 'road',
-  elementType: 'geometry.fill',
-  stylers: [{
-    visibility: 'on',
-  }, {
-    color: '#fafafa',
-  }],
-}, {
-  featureType: 'road',
-  elementType: 'geometry.stroke',
-  stylers: [{
-    visibility: 'off',
-  }],
-}, {
-  featureType: 'road',
-  elementType: 'labels.text.fill',
-  stylers: [{
-    gamma: '0.95',
-  }, {
-    lightness: '3',
-  }],
-}, {
-  featureType: 'road',
-  elementType: 'labels.text.stroke',
-  stylers: [{
-    visibility: 'off',
-  }],
-}, {
-  featureType: 'road.highway',
-  elementType: 'all',
-  stylers: [{
-    visibility: 'simplified',
-  }],
-}, {
-  featureType: 'road.highway',
-  elementType: 'geometry',
-  stylers: [{
-    lightness: '100',
-  }, {
-    gamma: '5.22',
-  }],
-}, {
-  featureType: 'road.highway',
-  elementType: 'geometry.stroke',
-  stylers: [{
-    visibility: 'on',
-  }],
-}, {
-  featureType: 'road.arterial',
-  elementType: 'labels.icon',
-  stylers: [{
-    visibility: 'off',
-  }],
-}, {
-  featureType: 'transit',
-  elementType: 'all',
-  stylers: [{
-    visibility: 'off',
-  }],
-}, {
-  featureType: 'water',
-  elementType: 'all',
-  stylers: [{
-    color: '#b3dced',
-  }, {
-    visibility: 'on',
-  }],
-}, {
-  featureType: 'water',
-  elementType: 'labels.text.fill',
-  stylers: [{
-    visibility: 'on',
-  }, {
-    color: '#ffffff',
-  }],
-}, {
-  featureType: 'water',
-  elementType: 'labels.text.stroke',
-  stylers: [{
-    visibility: 'off',
-  }, {
-    color: '#e6e6e6',
-  }],
-}];
-
-let rd = [];
-let lg = [];
-let uf = [];
-let Zd = !1;
-const Bj = [];
-const Cj = [];
-let map;
-// eslint-disable-next-line no-unused-vars
-let hi = !1;
-const Hh = [];
-const rn = !0;
-
-function Yd(a) {
-  this.baseMarker = a;
-  const c = a.getPosition().lat();
-  const f = a.getPosition().lng();
-  this.lat = c;
-  this.lng = f;
-  this.pos = new google.maps.LatLng(c, f);
-  this.icon = a.icon;
-  this.propId = a.propId;
-}
-
-const bA = (d, h, k, m) => {
-  d.forEach((d) => {
-    h.push(d);
-    d = new Yd(d);
-    d.setMap(m);
-    k.push(d);
-  });
-};
-
-function ln(a) {
-  google.maps.event.addListener(a, 'domready', () => {
-    uf.push(a);
-  });
-}
-// load Listing info by id
-async function yj(listingId) {
-  // @todo generate dynamicly from result response MLSFlag, AddMlsFlag, OfficeCode
-  const params = new SearchParameters('ListingId');
-  params.ListingId = listingId;
-  params.MLSFlag = 'false';
-  params.AddMlsFlag = 'false';
-  params.OfficeCode = 'MA312';
-  params.SearchType = 'ListingId';
-  return propertySearch(params);
-}
-
-function nn(a) {
-  return a && a.smallPhotos && a.smallPhotos.length > 0 ? a.smallPhotos[0].mediaUrl : '';
-}
-function zj(a, c, f) {
-  const path = f || '/property/detail';
-  const d = nn(a);
-  const h = a.ListPriceUS;
-  const q = a.municipality;
-  const m = a.addMlsFlag;
-  const p = a.listAor;
-  const k = a.mlsLogo;
-  const n = a.mlsStatus;
-  const B = a.ClosedDate;
-  const t = a.ListingId;
-  const y = a.CourtesyOf;
-  const A = a.sellingOfficeName;
-  const H = a.ApplicationType;
-  const J = a.listPriceAlternateCurrency;
-  const I = a.brImageUrl;
-  const P = a.StreetName;
-  const u = a.City;
-  const v = a.PostalCode;
-  const gb = a.PropId;
-  const ea = a.StateOrProvince;
-  let ka = a.PdpPath;
-  const Uh = a.luxury;
-  const E = a.isCompanyListing;
-  a = a.originatingSystemName === '' || undefined === a.originatingSystemName || a.originatingSystemName === null ? ' ' : `Listing Provided by  ${a.originatingSystemName}`;
-  c = c || ka.split('/');
-  ka = `${path}/${c[4]}/${c[5]}`;
-  return {
-    propertyImage: d,
-    propertyPrice: h,
-    municipality: q,
-    addMlsFlag: m,
-    listAor: p,
-    mlsLogo: k,
-    mlsStatus: n,
-    ClosedDate: B,
-    ListingId: t,
-    CourtesyOf: y,
-    sellingOfficeName: A,
-    ApplicationType: H,
-    propertyAltCurrencyPrice: J,
-    brImageUrl: I,
-    propertyAddress: P,
-    propertyLinkUrl: ka,
-    propertyProviders: a,
-    propertyData: {
-      city: u,
-      zipCode: v,
-      id: gb,
-      stateOrProvince: ea,
-      luxury: Uh,
-      isCompanyListing: E,
-    },
-  };
-}
-function Yt(a) {
-  a = a.listingPins;
-  return (undefined === a ? [] : a).reduce((a, f) => {
-    const c = `${f.lat}${f.lon}`;
-    // eslint-disable-next-line no-unused-expressions
-    Array.isArray(a[c]) || (a[c] = []);
-    a[c].push(f);
-    return a;
-  }, {});
-}
-
-const U = {
-  isXs() {
-    return window.innerWidth <= 575;
-  },
-  isSm() {
-    const a = window.innerWidth;
-    return a >= 576 && a <= 599;
-  },
-  isMd() {
-    const a = window.innerWidth;
-    return a >= 600 && a <= 991;
-  },
-  isLg() {
-    const a = window.innerWidth;
-    return a >= 992 && a <= 1199;
-  },
-  isXl() {
-    return window.innerWidth >= 1200;
-  },
-};
-
-function on(a) {
-  const c = [];
-  a.getListingPins().forEach((a) => {
-    c.push(yj(a.listingKey, a.officeCode));
-  });
-  return c;
-}
-function Xt(a) {
-  on(a);
-}
-
-function $t() {
-  return rn;
-}
-
-function vj(a, c) {
-  let f = '/icons/maps/map-marker-standard.png';
-  let d = 50;
-  let h = 25;
-  if (c === 'cluster') {
-    f = '/icons/maps/map-clusterer-blue.png';
-    h = 30;
-    d = 30;
-  }
-  return (q) => {
-    let m = q.labelText;
-    let p = undefined === m ? '' : m;
-    m = q.groupCount;
-    const k = q.listingKey;
-    q = new google.maps.LatLng(q.latitude, q.longitude);
-    let n = 0;
-    // eslint-disable-next-line no-unused-expressions
-    c === 'cluster' && (n = (Math.round(2 * Math.log10(m)) / 2) * 6);
-    n = {
-      url: f,
-      scaledSize: new google.maps.Size(d + n, h + n),
-    };
-    p = new google.maps.Marker({
-      position: q,
-      icon: n,
-      map: a,
-      anchor: new google.maps.Point(0, 0),
-      label: {
-        fontFamily: 'var(--font-family-primary)',
-        fontWeight: 'var(--font-weight-semibold:)',
-        fontSize: '12px',
-        text: p || '',
-        color: 'var(--white)',
-        labelAnchor: new google.maps.Point(30, 0),
-      },
-      labelClass: 'no-class',
-      width: 50,
-      height: 50,
-    });
-    p.groupCount = m;
-    p.listingKey = k;
-    return p;
-  };
-}
-
-function Jd() {
-  uf.forEach((a) => {
-    const c = a.anchor;
-    // eslint-disable-next-line no-unused-expressions
-    c && c.setOptions({
-      zIndex: c.bhhsInitialZIndex,
-    });
-    a.close();
-  });
-  uf = [];
-  Zd = !0;
-  document.querySelector('.mobile-info-window').classList.remove('is-active');
-  document.querySelector('.mobile-cluster-info-window').innerHTML = null;
-}
-
-function au(a) {
-  let c = a.groupOfListingPins;
-  const f = undefined === c ? [] : c;
-  const d = a.propertiesMap;
-  const h = a.isAgentPage;
-  const q = a.agentHomePath;
-  a = vj(d, 'cluster');
-  c = [];
-  const m = f[0];
-  const p = f.length;
-  const k = m.lat;
-  const n = m.lon;
-  const B = a({
-    latitude: k,
-    longitude: n,
-    labelText: `${p}`,
-    visible: !0,
-    groupCount: p,
-  });
-  c.push(B);
-  B.setZIndex(0);
-  B.bhhsInitialZIndex = B.getZIndex();
-  const t = {
-    getListingPins() {
-      return [].concat(f);
-    },
-    getCenter() {
-      return new google.maps.LatLng(k, n);
-    },
-  };
-  // eslint-disable-next-line no-unused-expressions
-  U.isXs() ? B.addListener('click', () => {
-    Jd();
-    Xt(t, h, q);
-  }) : (B.addListener('mouseover', () => {
-    // eslint-disable-next-line no-unused-expressions
-    $t && Zd && (Jd(),
-    Zd = !1
-    // Wt(t, d, B, h, q)
-    );
-  })
-  );
-  return c;
-}
-
-function Pt() {
-  Yd.prototype = new google.maps.OverlayView();
-  // eslint-disable-next-line func-names
-  Yd.prototype.onRemove = function () {};
-  // eslint-disable-next-line func-names
-  Yd.prototype.onAdd = function () {
-    const a = document.createElement('DIV');
-    a.style.position = 'absolute';
-    a.className = 'RevealMarker';
-    const c = this.icon.scaledSize.height;
-    const f = this.icon.scaledSize.width;
-    let d = '50%';
-    let h = '50%';
-    // eslint-disable-next-line no-unused-expressions
-    this.baseMarker.icon.labelOrigin && (h = `${this.baseMarker.icon.labelOrigin.x}px`,
-    d = `${this.baseMarker.icon.labelOrigin.y}px`);
-    a.innerHTML = `\x3cdiv class\x3d"reveal-marker"\x3e\x3cimg src\x3d"${this.icon.url.replace('map-marker', 'map-reveal-marker')}" style\x3d"width:${f}px;height:${c}px" alt\x3d"Marker image"\x3e\x3cspan class\x3d"reveal-marker__text" style\x3d"top:${d};left: ${h}"\x3e${this.baseMarker.label.text}\x3c/span\x3e\x3c/div\x3e`;
-    a.style.visibility = 'hidden';
-    this.getPanes().floatPane.appendChild(a);
-    this.div = a;
-  };
-  // eslint-disable-next-line func-names
-  Yd.prototype.draw = function () {
-    this.getProjection();
-    const a = this.icon.scaledSize.width;
-    this.div.style.top = `${-1 * this.icon.scaledSize.height}px`;
-    this.div.style.left = `${-1 * Math.round(a / 2)}px`;
-  };
-  // eslint-disable-next-line func-names
-  Yd.prototype.hide = function () {
-    // eslint-disable-next-line no-unused-expressions
-    this.div && (this.div.style.visibility = 'hidden');
-  };
-  // eslint-disable-next-line func-names
-  Yd.prototype.show = function () {
-    // eslint-disable-next-line no-unused-expressions
-    this.div && (this.div.style.visibility = 'visible');
-  };
-  // eslint-disable-next-line func-names
-  Yd.prototype.getPosition = function () {
-    return this.baseMarker.getPosition();
-  };
-}
-
-function bu() {
-  for (let a = 0; a < rd.length; a += 1) {
-    rd[a].setMap(null);
-    rd[a] = null;
-  }
-  rd = [];
-  lg.forEach((a) => {
-    a.clearMarkers();
-  });
-  lg = [];
-}
-
-function sn() {
-  if (Bj.length > 0) for (let a = 0; a < Bj.length; a += 1) Bj[a].close();
-  if (Cj.length > 0) for (let a = 0; a < Cj.length; a += 1) Cj[a].close();
-  document.querySelector('.mobile-cluster-info-window').style.display = 'none';
-  document.querySelector('.mobile-info-window').classList.remove('is-active');
-}
-
-function cu(a) {
-  const c = new google.maps.LatLngBounds();
-  a.forEach((a) => {
-    c.extend(a.getPosition());
-  });
-  // eslint-disable-next-line no-unused-expressions
-  a.length > 0 && (map.setCenter(c.getCenter()),
-  map.fitBounds(c));
-}
-
-function Zt(a) {
-  a.addListener('click', () => {
-    Jd();
-  });
-}
-
-function Qt() {
-  const a = arguments.length > 0 && undefined !== arguments[0] ? arguments[0] : [];
-  const c = vj(arguments[1], 'cluster');
-  const f = [];
-  a.forEach((a, h) => {
-    const d = a.count;
-    h = a.neLat;
-    const m = a.neLon;
-    const p = a.swLat;
-    const k = a.swLon;
-    a = c({
-      latitude: a.centerLat,
-      longitude: a.centerLon,
-      labelText: `${d}`,
-      visible: !0,
-      groupCount: d,
-    });
-    a.neLat = h;
-    a.neLon = m;
-    a.swLat = p;
-    a.swLon = k;
-    f.push(a);
-  });
-  return f;
-}
-
-function Rt(a) {
-  a.filter((a) => a.visible).forEach((a) => {
-    a.addListener('click', () => {
-      const event = new CustomEvent(
-        'search-by-cluster-click',
-        {
-          detail: {
-            northEastLatitude: a.neLat,
-            northEastLongitude: a.neLon,
-            southWestLatitude: a.swLat,
-            southWestLongitude: a.swLon,
-          },
-        },
-      );
-      window.dispatchEvent(event);
-      const c = new google.maps.LatLngBounds();
-      c.extend(new google.maps.LatLng(a.neLat, a.neLon));
-      c.extend(new google.maps.LatLng(a.swLat, a.swLon));
-      a.map.panTo(c.getCenter());
-    });
-  });
-}
-
-function commaSeparatedPriceToFloat(a) {
-  a = (`${a}`).replace('$', '');
-  a = a.replace(/,/g, '');
-  a = parseFloat(a);
-  return Number.isNaN(a) ? 0 : a;
-}
-
-function nFormatter(a, c) {
-  const f = [{
-    value: 1,
-    symbol: '',
-  }, {
-    value: 1E3,
-    symbol: 'k',
-  }, {
-    value: 1E6,
-    symbol: 'M',
-  }, {
-    value: 1E9,
-    symbol: 'G',
-  }, {
-    value: 1E12,
-    symbol: 'T',
-  }, {
-    value: 1E15,
-    symbol: 'P',
-  }, {
-    value: 1E18,
-    symbol: 'E',
-  }]; let
-    d;
-  for (d = f.length - 1; d > 0 && !(a >= f[d].value); d -= 1) ;
-  return (a / f[d].value).toFixed(c).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + f[d].symbol;
-}
-
-function Tt(a) {
-  a = commaSeparatedPriceToFloat(a);
-  return `$${nFormatter(a, 1)}`;
-}
-
-function Aj(a) {
-  let c = a.propertyData;
-  let f = undefined === c ? {
-    city: '',
-    zipCode: '',
-    id: '',
-    stateOrProvince: '',
-    luxury: !1,
-    isCompanyListing: !1,
-  } : c;
-  c = a.propertyImage;
-  const d = a.propertyPrice;
-  const h = a.municipality;
-  const q = a.addMlsFlag;
-  const m = a.listAor;
-  const p = a.mlsLogo;
-  const k = a.mlsStatus;
-  const n = a.ClosedDate;
-  const B = a.ListingId;
-  const t = a.CourtesyOf;
-  const y = a.sellingOfficeName;
-  const A = a.ApplicationType;
-  const H = a.propertyAltCurrencyPrice;
-  const J = a.brImageUrl;
-  const I = a.propertyAddress;
-  const P = a.propertyPdpPath;
-  f = {
-    city: f.city,
-    state: f.stateOrProvince,
-    postalCode: f.zipCode,
-    listingKey: f.id,
-    luxury: f.luxury,
-    isCompanyListing: f.isCompanyListing,
-  };
-  f = undefined === f ? {
-    city: '',
-    state: '',
-    postalCode: '',
-    listingKey: '',
-    luxury: !1,
-    isCompanyListing: !1,
-  } : f;
-  a = a.propertyProviders;
-  // @todo prepare content for info window
-  const cont = new Template().render({
-    image: c,
-    price: d,
-    municipality: h,
-    addMlsFlag: q,
-    listAor: m,
-    mlsLogo: p,
-    mlsStatus: k,
-    ClosedDate: n,
-    ListingId: B,
-    CourtesyOf: t,
-    sellingOfficeName: y,
-    ApplicationType: A,
-    altCurrencyPrice: H,
-    brImageUrl: J,
-    address: I,
-    city: f.city,
-    stateOrProvince: f.state,
-    postalCode: f.postalCode,
-    propertyId: f.listingKey,
-    linkUrl: P,
-    luxury: f.luxury,
-    luxuryLabel: 'luxury collection',
-    isCompanyListing: f.isCompanyListing,
-    providers: a,
-  });
-  return new google.maps.InfoWindow({
-    content: cont,
-  });
-}
-
-function mn(a) {
-  google.maps.event.addListener(a, 'domready', () => {
-    uf.push(a);
-  });
-}
-
-function jn(a) {
-  return {
-    leadParam: a.propertyLeadParam,
-    StreetName: a.propertyAddress,
-    PropId: a.propertyId,
-    ApplicationType: a.propertyApplicationType,
-    NotificationId: a.NotificationId,
-    originatingSystemName: a.originatingSystemName,
-  };
-}
-
-function St() {
-  const a = arguments.length > 0 && undefined !== arguments[0] ? arguments[0] : [];
-  const c = arguments[1];
-  const f = arguments[2];
-  const d = arguments[3];
-  const h = vj(c);
-  const q = [];
-  a.forEach((a, p) => {
-    const m = a.lat;
-    const n = a.lon;
-    const B = Tt(a.price);
-    const t = a.listingKey;
-    const y = a.officeCode;
-    a = h({
-      latitude: m,
-      longitude: n,
-      labelText: `${B}`,
-      visible: !0,
-      groupCount: 1,
-      listingKey: t,
-    });
-    // eslint-disable-next-line no-unused-expressions
-    U.isXs() ? (a.addListener('click', () => {
-      Jd();
-    }),
-    a.bhhsInitialZIndex = a.getZIndex(),
-    // eslint-disable-next-line func-names
-    a.addListener('click', function () {
-      this.setOptions({
-        zIndex: 1000002,
-      });
-
-      // eslint-disable-next-line func-names
-    })) : (a.addListener('mouseover', function () {
-      if (Zd) {
-        Jd();
-        Zd = !1;
-        const a = this;
-        if (this.propertyPdpPath) {
-          let h = a.propertyImage;
-          const m = a.propertyPrice;
-          const q = a.municipality;
-          const p = a.addMlsFlag;
-          const n = a.listAor;
-          const k = a.mlsLogo;
-          const x = a.mlsStatus;
-          const B = a.ClosedDate;
-          const u = a.ListingId;
-          const v = a.CourtesyOf;
-          const E = a.sellingOfficeName;
-          const G = a.ApplicationType;
-          const X = a.propertyAltCurrencyPrice;
-          const Jb = a.brImageUrl;
-          const Ab = a.propertyAddress;
-          const Ba = a.propertyProviders || a.originatingSystemName;
-          const da = a.propertyId;
-          const Id = a.propertyCity;
-          const Ma = a.propertyZipcode;
-          const Wh = a.propertyState;
-          const aa = a.propertyPdpPath;
-          const qd = a.propertyLuxury;
-          const L = a.propertyIsCompanyListing;
-          const O = jn(a);
-          h = Aj({
-            propertyImage: h,
-            propertyPrice: m,
-            municipality: q,
-            addMlsFlag: p,
-            listAor: n,
-            mlsLogo: k,
-            mlsStatus: x,
-            ClosedDate: B,
-            ListingId: u,
-            CourtesyOf: v,
-            sellingOfficeName: E,
-            ApplicationType: G,
-            propertyAltCurrencyPrice: X,
-            brImageUrl: Jb,
-            propertyAddress: Ab,
-            propertyPdpPath: aa,
-            propertyProviders: Ba,
-            propertyData: {
-              city: Id,
-              zipCode: Ma,
-              id: da,
-              stateOrProvince: Wh,
-              luxury: qd,
-              isCompanyListing: L,
-            },
-          });
-          h.open(c, a);
-          ln(h, O);
-          Zd = !0;
-        } else {
-          const F = Aj({
-            propertyImage: '',
-            propertyPrice: 'loading...',
-            propertyAltCurrencyPrice: '',
-            brImageUrl: '',
-            propertyAddress: '-',
-            municipality: '',
-            addMlsFlag: '',
-            listAor: '',
-            mlsLogo: '',
-            mlsStatus: '',
-            ClosedDate: '',
-            ListingId: '',
-            CourtesyOf: '',
-            sellingOfficeName: '',
-            ApplicationType: '',
-            propertyPdpPath: '',
-            propertyProviders: '-',
-            propertyData: {},
-          });
-          mn(F);
-          F.open(c, a);
-          // @todo fix property info window with link to property detal page
-
-          yj(t, y).then((h) => {
-            F.close();
-            Zd = !0;
-            let m = zj(h, f, d);
-            m = Aj({
-              propertyImage: m.propertyImage,
-              propertyPrice: m.propertyPrice,
-              municipality: m.municipality,
-              addMlsFlag: m.addMlsFlag,
-              listAor: m.listAor,
-              mlsLogo: m.mlsLogo,
-              mlsStatus: m.mlsStatus,
-              ClosedDate: m.ClosedDate,
-              ListingId: m.ListingId,
-              CourtesyOf: m.CourtesyOf,
-              sellingOfficeName: m.sellingOfficeName,
-              ApplicationType: m.ApplicationType,
-              propertyAltCurrencyPrice: m.propertyAltCurrencyPrice,
-              brImageUrl: m.brImageUrl,
-              propertyAddress: m.propertyAddress,
-              propertyProviders: m.propertyProviders,
-              propertyPdpPath: m.propertyLinkUrl,
-              propertyData: {
-                city: m.propertyData.city,
-                zipCode: m.propertyData.zipCode,
-                id: m.propertyData.id,
-                stateOrProvince: m.propertyData.stateOrProvince,
-                luxury: m.propertyData.luxury,
-                isCompanyListing: m.propertyData.isCompanyListing,
-              },
-            });
-            m.open(c, a);
-            ln(m, h);
-          });
-        }
-      }
-    }),
-    // eslint-disable-next-line func-names
-    a.addListener('mouseover', function () {
-      this.setOptions({
-        zIndex: 1000002,
-      });
-    }));
-    a.setZIndex(200 + p);
-    a.bhhsInitialZIndex = a.getZIndex();
-    q.push(a);
-  });
-  return q;
-}
-
-function aA(d, h, k, m, p) {
-  h = h || [];
-  k = k || [];
-  let q = [];
-  Zt(d);
-  if (h.length > 0) {
-    k = Qt(h, d);
-    Rt(k);
-    q = q.concat(k);
-  } else if (k.length > 0) {
-    const n = Yt({
-      listingPins: k,
-    });
-    const B = [];
-    Object.keys(n).forEach((h) => {
-      h = n[h];
-      // eslint-disable-next-line no-unused-expressions
-      h.length > 1 ? (h = au({
-        groupOfListingPins: h,
-        propertiesMap: d,
-        isAgentPage: m,
-        agentHomePath: p,
-      }),
-      q = q.concat(h)) : B.push(h[0]);
-    });
-    k = St(B, d, m, p);
-    q = q.concat(k);
-  }
-  return {
-    markers: q,
-    markerClusters: [],
-  };
-}
-
-// @todo move to search class
-function createMapSearchGeoJsonParameter(coordinates) {
-  return {
-    type: 'FeatureCollection',
-    features: [{
-      type: 'Feature',
-      properties: {},
-      geometry: {
-        type: 'Polygon',
-        coordinates: [coordinates],
-      },
-    }],
-  };
-}
-
-async function initMap() {
-  Pt();
-  const mapDiv = document.querySelector('.property-result-map');
-  const { Map } = await google.maps.importLibrary('maps');
-  map = new Map(mapDiv, {
-    zoom: 10,
-    maxZoom: 18,
-    center: new google.maps.LatLng(41.24216, -96.20799),
-    mapTypeId: 'roadmap',
-    clickableIcons: false,
-    gestureHandling: 'greedy',
-    styles: Nr,
-    visualRefresh: true,
-    disableDefaultUI: true,
-  });
-  window.mapInitialized = !0;
-  window.renderPropertyMap = (d) => {
-    const h = arguments.length > 1 && undefined !== arguments[1] ? arguments[1] : !0;
-    // eslint-disable-next-line no-new
-    new google.maps.InfoWindow({
-      pixelOffset: new google.maps.Size(0, 0),
-    });
-    Jd();
-    sn();
-    // eslint-disable-next-line no-unused-expressions
-    d && (Promise.resolve(1).then(() => {
-      // update map center
-      // eslint-disable-next-line no-unused-expressions,no-mixed-operators
-      !h && window.boundsInitialized || cu(rd);
-    }));
-    document.querySelector('.map-style-hybrid').addEventListener('click', () => {
-      document.querySelector('.map-style-hybrid').classList.toggle('activated');
-      if (document.querySelector('.map-style-hybrid').classList.contains('activated')) {
-        map.setMapTypeId(google.maps.MapTypeId.HYBRID);
-        map.setOptions({
-          styles: [],
-        });
-      } else {
-        map.setOptions({ styles: Nr });
-        map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
-      }
-    });
-    document.querySelector('.map-zoom-in').addEventListener('click', () => {
-      hi = !0;
-      map.setZoom(map.getZoom() + 1);
-    });
-    document.querySelector('.map-zoom-out').addEventListener('click', () => {
-      hi = !0;
-      map.setZoom(map.getZoom() - 1);
-    });
-  };
-
-  window.updatePropertyMap = (d, h, k, m) => {
-    // eslint-disable-next-line no-unused-expressions
-    window.mapInitialized ? (clearTimeout(window.queuedRenderPropertyMap),
-    bu(),
-    window.renderPropertyMap(d, h),
-    h = aA(map, d && d.listingClusters && d.listingClusters.length > 0
-      ? d.listingClusters : [], d && d.listingPins && d.listingPins.length > 0
-      ? d.listingPins
-      : [], k, m),
-    k = h.markerClusters,
-    bA(h.markers, rd, Hh, map),
-    lg = [].concat(k)) : window.queuedRenderPropertyMap = setTimeout(() => {
-      window.updatePropertyMap(d);
-    }, 200);
-  };
-  window.addEventListener('search-by-cluster-click', (e) => {
-    // set Search params
-    setFilterValue('NorthEastLatitude', e.detail.northEastLatitude);
-    setFilterValue('NorthEastLongitude', e.detail.northEastLongitude);
-    setFilterValue('SouthWestLatitude', e.detail.southWestLatitude);
-    setFilterValue('SouthWestLongitude', e.detail.southWestLongitude);
-    setFilterValue('SearchType', 'Map');
-    let m = [];
-    const p = [e.detail.southWestLongitude, e.detail.northEastLatitude];
-    const q = [e.detail.northEastLongitude, e.detail.northEastLatitude];
-    const x = [e.detail.northEastLongitude, e.detail.southWestLatitude];
-    const T = [e.detail.southWestLongitude, e.detail.southWestLatitude];
-    m.push(p);
-    m.push(T);
-    m.push(x);
-    m.push(q);
-    m.push(p);
-    m = createMapSearchGeoJsonParameter(m);
-    m = JSON.stringify(m);
-    removeFilterValue('MapSearchType');
-    setFilterValue('SearchParameter', m);
-    searchProperty();
-  });
-
-  // add custom events handling
-}
-
-function loadJS(src) {
-  const script = document.createElement('script');
-  script.type = 'text/javascript';
-  script.async = true;
-  script.defer = true;
-  script.innerHTML = `
-    (()=>{
-      let script = document.createElement('script');
-      script.src = '${src}';
-      document.head.append(script);
-    })();
-  `;
-  document.head.append(script);
-}
-
-async function initGoogleMapsAPI() {
-  const placeholders = await fetchPlaceholders();
-  const CALLBACK_FN = 'initMap';
-  window[CALLBACK_FN] = initMap;
-  const { mapsApiKey } = placeholders;
-
-  const clusterSrc = 'https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js';
-  loadJS(clusterSrc);
-  const src = `https://maps.googleapis.com/maps/api/js?key=${mapsApiKey}&libraries=places&callback=${CALLBACK_FN}`;
-  loadJS(src);
-}
-
-initGoogleMapsAPI();
diff --git a/blocks/property-result-map/map.css b/blocks/property-result-map/map.css
deleted file mode 100644
index 215c9c17..00000000
--- a/blocks/property-result-map/map.css
+++ /dev/null
@@ -1,449 +0,0 @@
-.property-search-template.search-map-active .property-result-listing.block .d-none {
-    display: none;
-}
-
-.property-search-template.search-map-active .info-window div {
-    padding: 3px;
-}
-
-.property-search-template.search-map-active .property-result-listing.block > div:last-of-type {
-    position: fixed;
-    width: 50%;
-    left: 50%;
-    top: calc(var(--nav-height) + 50px + 120px);
-
-    /* todo need to figureout on how to do this dynamicly */
-    height: 600px;
-    max-width: calc(1400px/2 - 30px);
-}
-
-.property-search-template.search-map-active .info-window {
-    width: 178px;
-    pointer-events: all;
-}
-
-.property-search-template.search-map-active .info-window a {
-    color: inherit;
-    text-decoration: none;
-}
-
-.property-search-template.search-map-active .info-window .info .price {
-    font-size: var(--body-font-size-m);
-    font-family: var(--font-family-primary);
-    font-weight: var(--font-weight-bold);
-}
-
-.property-search-template.search-map-active svg:not(:root) {
-    overflow: hidden;
-}
-
-.property-search-template.search-map-active .info-window .btn-contact-property svg,
-.property-search-template.search-map-active .info-window .btn-save-property svg {
-    width: 100%;
-    height: 100%;
-}
-
-.property-search-template.search-map-active .info-window .btn-contact-property .envelope,
-.property-search-template.search-map-active .btn-save-property .empty{
-    position: absolute;
-    opacity: 1;
-}
-
-.property-search-template.search-map-active .info-window .btn-contact-property .envelope-dark,
-.property-search-template.search-map-active .btn-save-property .empty-dark {
-    position: absolute;
-    opacity: 0;
-}
-
-.property-search-template.search-map-active .info-window .btn-save-property .full {
-    position: absolute;
-    display: none;
-}
-
-/* stylelint-disable selector-class-pattern */
-.property-search-template.search-map-active .info-window .info .altPrice {
-    font-size: var(--body-font-size-s);
-    font-family: var(--font-family-primary);
-    font-weight: var(--font-weight-light);
-}
-
-.property-search-template.search-map-active .info-window .info .address,
-.property-search-template.search-map-active .info-window .info .providers {
-    font-size: var(--body-font-size-xs);
-}
-
-.property-search-template.search-map-active .cmp-property-tile__extra-info {
-    display: block;
-    font-size: var(--body-font-size-xs);
-    font-family: var(--font-family-primary);
-    font-weight: var(--font-weight-light);
-    padding-left: 10px;
-    opacity: 1;
-    color: var(--dark-grey);
-    letter-spacing: 0;
-    line-height: var(--line-height-xs);
-}
-
-.property-search-template.search-map-active .info-window .arrow {
-    width: 0;
-    border-top: 20px solid transparent;
-    border-left: 20px solid transparent;
-    border-right: 20px solid transparent;
-    cursor: pointer;
-    content: "";
-    position: absolute;
-    bottom: 0;
-    left: 50%;
-    transform: translateX(-50%);
-    transition: .2s bottom opacity ease-out;
-    opacity: 1;
-}
-
-.property-search-template.search-map-active .info-window .text-danger {
-    color: #dc3545 !important;
-}
-
-.property-search-template.search-map-active .gm-ui-hover-effect {
-    display: none !important;
-}
-
-.property-search-template.search-map-active .gm-ui-hover-effect, button[draggable] {
-    opacity: 0;
-}
-
-.property-search-template hr {
-    margin-top: 1rem;
-    margin-bottom: 1rem;
-    border: 0;
-    border-top: 1px solid rgb(0 0 0 / 10%);
-    box-sizing: content-box;
-    height: 0;
-    overflow: visible;
-}
-
-.property-search-template.search-map-active .info-window .property-image {
-    width: 100%;
-    height: 131px;
-    background-size: cover;
-    background-repeat: no-repeat;
-    position: relative;
-}
-
-.property-search-template.search-map-active .btn-contact-property,
-.property-search-template.search-map-active .btn-save-property {
-    display: block;
-    position: relative;
-    width: 18px;
-    height: 18px;
-    cursor: pointer;
-    margin-left: auto;
-}
-
-.property-search-template .d-flex {
-    display: flex !important;
-
-}
-
-.property-search-template .align-items-center {
-    align-items: center !important;
-
-}
-
-.property-search-template .p-0 {
-   padding: 0 !important;
-}
-
-.property-search-template .mr-2 {
-    margin-right: 0.5rem !important;
-}
-
-.property-search-template.search-map-active .info-window .info {
-    background: var(--white);
-}
-
-.property-search-template.search-map-active .info-window::before,
-.property-search-template.search-map-active .info-window::after {
-    content: "";
-    bottom: 0;
-    opacity: 0;
-    transition: .2s bottom opacity ease-in;
-}
-
-
-.property-search-template .property-result-map {
-    height: 600px;
-    width: 100%;
-    display: none;
-    position: absolute;
-}
-
-.property-search-template.search-map-active .property-result-map {
-    display: block;
-
-}
-
-.property-search-template .map-controls-container {
-    display: none;
-}
-
-
-.property-search-template.search-map-active  .map-controls-container {
-    height: 100%;
-    width: 100% !important;
-    padding-left: 0;
-    padding-right: 0;
-    max-width: 1350px;
-    margin: 0 auto;
-    display: block;
-}
-
-.property-search-template.search-map-active .custom-controls a {
-    pointer-events: all;
-    height: 45px;
-    width: 45px;
-    background: var(--white);
-    display: block;
-    position: relative;
-    cursor: pointer;
-}
-
-.property-search-template.search-map-active .custom-controls a.map-style-hybrid {
-    position: relative;
-    box-shadow: 0 0 3px 2px rgb(0 0 0 / 30%);
-}
-
-.property-search-template.search-map-active .custom-controls a.map-style-hybrid::before {
-    background-image: url("data:image/png;base64,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");
-    content: " ";
-    height: 22px;
-    width: 22px;
-    top: 5px;
-    left: 50%;
-    transform: translateX(-50%);
-    position: absolute;
-    background-repeat: no-repeat;
-    background-size: contain;
-}
-
-.property-search-template.search-map-active .custom-controls a.map-style-hybrid::after {
-    content: attr(data-text);
-    position: absolute;
-    text-align: center;
-    width: 100%;
-    bottom: 8px;
-    line-height: 0;
-    font-size: var(--body-font-size-xs);
-    color: var(--body-color);
-}
-
-.property-search-template.search-map-active a.map-draw-complete {
-    display: flex;
-    margin-top: 15px;
-    box-shadow: 0 0 3px 2px rgb(0 0 0 / 30%);
-}
-
-.property-search-template.search-map-active .custom-controls a.map-draw {
-    margin-top: 15px;
-    box-shadow: 0 0 3px 2px rgb(0 0 0 / 30%);
-
-    /* @todo change visibility for draw functionality https://github.com/hlxsites/hsf-commonmoves/issues/122 */
-    visibility: hidden;
-}
-
-.property-search-template.search-map-active .custom-controls a.map-draw::before {
-    background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIxN3B4IiBoZWlnaHQ9IjE3cHgiIHZpZXdCb3g9IjAgMCAxNyAxNyIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj4gICAgICAgIDx0aXRsZT5Db21iaW5lZCBTaGFwZTwvdGl0bGU+ICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPiAgICA8ZyBpZD0iRG9jdW1lbnQtU3ltYm9scyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+ICAgICAgICA8ZyBpZD0iVUkvUGVuY2lsIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTMuMDAwMDAwLCAtOC4wMDAwMDApIiBmaWxsPSIjM0EzQTNBIj4gICAgICAgICAgICA8cGF0aCBkPSJNMTUuNzY0MTY1LDggTDE3LjYwNzQ2MTksOS44NDI4MDc5IEwxNC44NDIyMzQzLDEyLjYwNzk5OTMgTDEzLDEwLjc2NDE2MiBMMTUuNzY0MTY1LDggWiBNMzAsMjUgTDI2LjkwODAwNDIsMjQuNjcyMTczNSBMMjkuNjcyNjY3MywyMS45MDc5NzgzIEwzMCwyNSBaIE0yOC43NTA3MywyMC45ODU1OTE1IEwyNS45ODYwNjY5LDIzLjc1MDc0OTYgTDE1Ljc2NDE3NSwxMy41MjkzODk5IEwxOC41MjkzMDI5LDEwLjc2NDE2NTQgTDI4Ljc1MDczLDIwLjk4NTU5MTUgWiIgaWQ9IkNvbWJpbmVkLVNoYXBlIj48L3BhdGg+ICAgICAgICA8L2c+ICAgIDwvZz48L3N2Zz4=");
-    content: " ";
-    height: 17px;
-    width: 17px;
-    top: 8px;
-    left: 13px;
-    position: absolute;
-    background-repeat: no-repeat;
-    background-size: contain;
-}
-
-.property-search-template.search-map-active .custom-controls a.map-draw::after {
-    content: attr(data-text);
-    position: absolute;
-    text-align: center;
-    width: 100%;
-    bottom: 8px;
-    line-height: 0;
-    font-size: var(--body-font-size-xs);
-    color: var(--body-color);
-}
-
-.property-search-template.search-map-active .custom-controls {
-    position: absolute;
-    left: auto;
-    right: 15px;
-    pointer-events: none;
-    bottom: 15px;
-}
-
-.property-search-template.search-map-active .custom-controls .zoom-controls {
-    box-shadow: 0 0 3px 2px rgb(0 0 0 / 30%);
-    bottom: 0;
-    right: 0;
-    z-index: 0;
-    pointer-events: all;
-}
-
-.property-search-template.search-map-active .custom-controls a.map-zoom-in::before {
-    content: " ";
-    position: absolute;
-    display: block;
-    background-color: var(--body-color);
-    width: 1px;
-    margin-left: 0;
-    left: 50%;
-    top: calc(50% - 8px);
-    z-index: 9;
-    height: 16px;
-}
-
-.property-search-template.search-map-active .custom-controls a.map-zoom-in::after {
-    content: " ";
-    position: absolute;
-    display: block;
-    background-color: var(--body-color);
-    height: 1px;
-    top: calc(50% - 1px);
-    left: calc(50% - 8px);
-    width: 16px;
-    z-index: 9;
-}
-
-.property-search-template.search-map-active .custom-controls a.map-zoom-out::after {
-    content: " ";
-    position: absolute;
-    display: block;
-    background-color: var(--body-color);
-    height: 1px;
-    top: calc(50% - 1px);
-    left: calc(50% - 8px);
-    width: 16px;
-    z-index: 9;
-}
-
-.property-search-template.search-map-active .map-draw-tooltip {
-    position: absolute;
-    width: 100%;
-    height: 30px;
-    line-height: var(--line-height-xl);
-    font-size: var(--body-font-size-xs);
-    background: var(--light-grey);
-    text-align: center;
-    color: var(--body-color);
-    font-family: var(--font-family-primary);
-    z-index: 1;
-}
-
-.property-search-template.search-map-active .map-search-wrapper {
-    position: absolute;
-    top: 0;
-    left: 0;
-    width: 100%;
-    overflow: hidden;
-}
-
-.property-search-template.search-map-active .map-search-wrapper a.map-search-toggle {
-    box-shadow: 0 0 3px 2px rgb(0 0 0 / 30%);
-    width: 100%;
-    text-align: center;
-    height: 30px;
-    font-size: 12px;
-    line-height: 30px;
-    background: #fff;
-    margin-bottom: 10px;
-    cursor: pointer;
-    display: none;
-}
-
-/* hide google map keyboard shortcuts text and google logo */
-.property-search-template.search-map-active .gm-style-cc {
-    display: none;
-}
-
-.property-search-template.search-map-active a[href^="http://maps.google.com/maps"] {
-    display: none !important
-}
-
-.property-search-template.search-map-active a[href^="https://maps.google.com/maps"] {
-    display: none !important
-}
-
-/* end */
-
-@media (min-width: 600px) {
-    .property-search-template.search-map-active  .custom-controls {
-        bottom: 16vw;
-    }
-
-    .property-search-template.search-map-active .property-result-listing.block > div:last-of-type {
-        width: 100%;
-        left: 0;
-        top: calc(var(--nav-height) + 50px + 120px);
-        height: 600px;
-
-    }
-}
-
-.property-result-listing.block .property-result-map-container .disclaimer {
-    display: none;
-}
-
-@media (max-width: 899px) {
-    .property-search-template.search-map-active .property-result-listing.block .property-result-map-container .disclaimer {
-        display: block;
-    }
-}
-
-@media (min-width: 900px) {
-    .property-search-template.search-map-active .property-result-listing.block > div:last-of-type {
-        position: fixed;
-        width: 100%;
-        left: 50%;
-        top: calc(var(--nav-height) + 50px + 120px);
-
-        /* todo need to figureout on how to do this dynamicly */
-        height: 600px;
-    }
-
-    .property-search-template.search-map-active  .custom-controls {
-        right: 20px;
-        bottom: 20px;
-        position: absolute;
-        left: auto;
-        pointer-events: none;
-    }
-
-    .property-search-template.search-map-active .custom-controls .zoom-controls {
-        margin-top: 15px;
-    }
-
-    .property-search-template.search-map-active .map-draw-tooltip {
-        font-size: 16px;
-        height: 65px;
-        line-height: 65px;
-    }
-
-    .property-search-template.search-map-active .map-search-wrapper {
-        left: 20px;
-        right: auto;
-        top: auto;
-        bottom: 25vw;
-        width: 165px;
-        overflow: visible;
-    }
-
-    .property-search-template.search-map-active .map-search-wrapper a.map-search-toggle {
-        margin: 0;
-    }
-}
-
-@media (min-width: 1200px) {
-    .property-search-template.search-map-active .property-result-listing.block > div:last-of-type {
-        max-width: calc(1400px/2 - 30px);
-    }
-}
diff --git a/blocks/property-result-map/map.js b/blocks/property-result-map/map.js
deleted file mode 100644
index 2334af35..00000000
--- a/blocks/property-result-map/map.js
+++ /dev/null
@@ -1,54 +0,0 @@
-let alreadyDeferred = false;
-
-function buildCustomControls() {
-  const container = document.createElement('div');
-  container.classList.add('map-controls-container');
-  container.innerHTML = `<div class="custom-controls">
-        <a data-text="Satellite" data-text-map="Map" class="map-style-hybrid" role="button" aria-label="Satellite View"></a> 
-        <a data-text="Draw" data-text-close="Complete Draw" class="map-draw-complete d-none" role="button" aria-label="Complete Draw"></a>
-        <a data-text="Draw" data-text-close="Close" class="map-draw" role="button" aria-label="Close"></a> 
-        <div class="zoom-controls">
-            <a class="map-zoom-in" role="button" aria-label="Zoom In"></a> 
-            <a class="map-zoom-out" role="button" aria-label="Zoom Out"></a>
-        </div>
-    </div>
-    <div class="map-draw-tooltip d-none">
-       Click points on the map to draw your search
-    </div>
-    <div class="map-search-wrapper">
-    <a data-text-add="Add map boundary" data-text-remove="Remove map boundary" class="map-search-toggle" role="button" aria-label="Remove Map Boundary"></a>
-    </div>
-    `;
-  return container;
-}
-
-function initGoogleMapsAPI() {
-  if (alreadyDeferred) {
-    return;
-  }
-  alreadyDeferred = true;
-  const script = document.createElement('script');
-  script.type = 'text/partytown';
-  script.id = crypto.randomUUID();
-  script.innerHTML = `
-    const script = document.createElement('script');
-    script.type = 'module';
-    script.src = '${window.hlx.codeBasePath}/blocks/property-result-map/map-delayed.js';
-    document.head.append(script);
-  `;
-  document.head.append(script);
-}
-
-export default async function renderMap(block) {
-  const container = document.createElement('div');
-  const mobileClusterInfo = document.createElement('div');
-  mobileClusterInfo.classList.add('mobile-cluster-info-window');
-  const mobileInfo = document.createElement('div');
-  mobileInfo.classList.add('mobile-info-window');
-  container.classList.add('property-result-map-container');
-  const map = document.createElement('div');
-  map.classList.add('property-result-map');
-  container.append(map, buildCustomControls(), mobileClusterInfo, mobileInfo);
-  block.append(container);
-  initGoogleMapsAPI();
-}
diff --git a/blocks/property-search-bar/README.md b/blocks/property-search-bar/README.md
new file mode 100644
index 00000000..9879bf9b
--- /dev/null
+++ b/blocks/property-search-bar/README.md
@@ -0,0 +1,15 @@
+### Property Search Bar 
+
+#### State Changes
+
+Search bar contains all filters, details on what will be searched.
+
+* Opening advanced search, or changing viewport to < 900px, synchronizes the Property attributes from the bar to the advanced filter list.
+
+* Closing the advanced search, changing the viewport to > 900px, or applying the parameters, synchronizes the Property attributes from the advanced list, to the bar.
+
+#### Searching
+
+Clicking Search on bar, or Clicking 'Apply' in the advanced filter view, will either: 
+  1. Change the URL to the search results page, if not there
+  1. Emit the Search Event with the parameters as a payload. Search Results block handles everything else.
diff --git a/blocks/property-search-bar/common-function.js b/blocks/property-search-bar/common-function.js
deleted file mode 100644
index 50e212e5..00000000
--- a/blocks/property-search-bar/common-function.js
+++ /dev/null
@@ -1,367 +0,0 @@
-/* eslint-disable no-param-reassign, no-plusplus, no-mixed-operators, no-unused-expressions, no-nested-ternary, eqeqeq, max-len */
-
-import ApplicationType from '../../scripts/apis/creg/ApplicationType.js';
-
-export const TOP_LEVEL_FILTERS = {
-  Price: { label: 'price', type: 'range' },
-  MinBedroomsTotal: { label: 'beds', type: 'select' },
-  MinBathroomsTotal: { label: 'baths', type: 'select' },
-  LivingArea: { label: 'square feet', type: 'range' },
-};
-export const EXTRA_FILTERS = {
-  PropertyType: { label: 'property type', type: 'property' },
-  Features: { label: 'keyword search', type: 'keywords-search' },
-  MatchAnyFeatures: { label: 'Match', type: 'child' },
-  YearBuilt: { label: 'year built', type: 'range' },
-  NewListing: { label: 'new listings', type: 'toggle' },
-  RecentPriceChange: { label: 'recent price change', type: 'toggle' },
-  OpenHouses: { label: 'open houses', type: 'open-houses' },
-  Luxury: { label: 'luxury', type: 'toggle' },
-  FeaturedCompany: { label: 'berkshire hathaway homeServices listings only', type: 'toggle' },
-};
-
-export const BOTTOM_LEVEL_FILTERS = {
-  ApplicationType: { label: 'Search Types', type: 'search-types' },
-  Sort: { label: 'Sort By', type: 'select' },
-  Page: { label: '', type: 'child' },
-};
-
-const SQUARE_FEET = [
-  { value: '500', label: '500 Sq Ft' },
-  { value: '750', label: '750 Sq Ft' },
-  { value: '1000', label: '1,000 Sq Ft' },
-  { value: '1250', label: '1,250  Sq Ft' },
-  { value: '1500', label: '1,500 Sq Ft' },
-  { value: '1750', label: '1,750 Sq Ft' },
-  { value: '2000', label: '2,000 Sq Ft' },
-  { value: '2250', label: '2,250 Sq Ft' },
-  { value: '2500', label: '2,500 Sq Ft' },
-  { value: '2750', label: '2,750 Sq Ft' },
-  { value: '3000', label: '3,000 Sq Ft' },
-  { value: '3500', label: '3,500 Sq Ft' },
-  { value: '4000', label: '4,000 Sq Ft' },
-  { value: '5000', label: '5,000 Sq Ft' },
-  { value: '7500', label: '7,500 Sq Ft' },
-];
-
-const YEAR_BUILT = [
-  { value: '1900', label: '1900' },
-  { value: '1920', label: '1920' },
-  { value: '1940', label: '1940' },
-  { value: '1950', label: '1950' },
-  { value: '1960', label: '1960' },
-  { value: '1970', label: '1970' },
-  { value: '1980', label: '1980' },
-  { value: '1990', label: '1990' },
-  { value: '1995', label: '1995' },
-  { value: '2000', label: '2000' },
-  { value: '2005', label: '2005' },
-  { value: '2014', label: '2014' },
-  { value: '2015', label: '2015' },
-  { value: '2016', label: '2016' },
-  { value: '2017', label: '2017' },
-  { value: '2018', label: '2018' },
-  { value: '2019', label: '2019' },
-];
-
-const SORT_BY = [
-  { value: 'DISTANCE_ASCENDING', label: 'Distance' },
-  { value: 'PRICE_DESCENDING', label: 'Price (Hi-Lo)' },
-  { value: 'PRICE_ASCENDING', label: 'Price (Lo-Hi)' },
-  { value: 'DATE_DESCENDING', label: 'DATE (NEW-OLD)' },
-  { value: 'DATE_ASCENDING', label: 'DATE (OLD-NEW)' },
-];
-
-export function getFilterLabel(filterName) {
-  let config;
-  switch (filterName) {
-    case 'Price':
-    case 'MinBedroomsTotal':
-    case 'MinBathroomsTotal':
-    case 'LivingArea':
-      config = TOP_LEVEL_FILTERS;
-      break;
-    case 'ApplicationType':
-    case 'Sort':
-      config = BOTTOM_LEVEL_FILTERS;
-      break;
-    default:
-      config = EXTRA_FILTERS;
-      break;
-  }
-  return config[filterName].label;
-}
-export function getConfig(filterName) {
-  let output = '';
-  switch (filterName) {
-    case 'MinBedroomsTotal':
-    case 'MinBathroomsTotal':
-      output = 5;
-      break;
-    case 'LivingArea':
-      output = SQUARE_FEET;
-      break;
-    case 'YearBuilt':
-      output = YEAR_BUILT;
-      break;
-    case 'ApplicationType':
-      output = [ApplicationType.FOR_SALE.label, ApplicationType.FOR_RENT.label, ApplicationType.PENDING.label, ApplicationType.RECENTLY_SOLD.label];
-      break;
-    case 'Sort':
-      output = SORT_BY;
-      break;
-    default:
-      break;
-  }
-  return output;
-}
-
-export function toggleOverlay() {
-  const hideClass = 'hide';
-  const overlay = document.querySelector('.property-search-bar.block .overlay');
-  overlay.classList.toggle(hideClass);
-  if (overlay.classList.contains(hideClass)) {
-    document.getElementsByTagName('body')[0].classList.remove('no-scroll');
-  } else {
-    document.getElementsByTagName('body')[0].classList.add('no-scroll');
-  }
-}
-
-export function hideOverlay() {
-
-}
-/**
- *
- * @param {string} filterName
- * @param {string} defaultValue
- * @returns {string}
- */
-function buildSelectOptions(filterName, defaultValue) {
-  const conf = getConfig(filterName);
-  let output = `<option value="">${defaultValue}</option>`;
-  if (Array.isArray(conf)) {
-    conf.forEach((el) => {
-      output += `<option value="${el.value}">${el.label}</option>`;
-    });
-  } else {
-    const labelSuf = `+ ${defaultValue.split(' ')[1]}`;
-    for (let i = 1; i <= conf; i += 1) {
-      const label = `${i} ${labelSuf}`;
-      output += `<option value="${i}">${label}</option>`;
-    }
-  }
-  return output;
-}
-
-/**
- * @param {string} filterName
- * @param {string} defaultValue
- * @returns {string}
- */
-function buildListBoxOptions(filterName, defaultValue) {
-  const config = getConfig(filterName);
-  let output = `<li data-value="" class="tooltip-container highlighted">${defaultValue}</li>`;
-  if (Array.isArray(config)) {
-    config.forEach((conf) => {
-      output += `<li data-value="${conf.value}" class="tooltip-container">${conf.label}</li>`;
-    });
-  } else {
-    const labelSuf = `+ ${defaultValue.split(' ')[1]}`;
-    for (let i = 1; i <= config; i += 1) {
-      const label = `${i} ${labelSuf}`;
-      output += `<li  data-value="${i}" class="tooltip-container">${label}</li>`;
-    }
-  }
-
-  return output;
-}
-
-export function addOptions(filterName, defaultValue = '', mode = '', name = '') {
-  let output = `<section>
-        <div>
-            <select class="hide" aria-label="${defaultValue}">${buildSelectOptions(filterName, defaultValue, mode)}</select>`;
-  if (mode === 'multi') {
-    output += `<div class="select-selected" role="button" aria-haspopup="listbox" name=${name}>${defaultValue}</div>`;
-  }
-  output += `<ul class="select-item" role="listbox">${buildListBoxOptions(filterName, defaultValue, mode)}</ul>
-        </div>
-    </section>`;
-  return output;
-}
-
-export function formatInput(string) {
-  return string.replace(/[/\s]/g, '-').toLowerCase();
-}
-
-export function getPlaceholder(country) {
-  return country === 'US' ? 'Enter City, Address, Zip/Postal Code, Neighborhood, School or MLS#' : 'Enter City';
-}
-
-export function addRangeOption(filterName) {
-  const config = { ...TOP_LEVEL_FILTERS, ...EXTRA_FILTERS };
-  const { label } = config[filterName];
-  const filterLabel = label.charAt(0).toLocaleUpperCase() + label.slice(1).toLowerCase();
-  const fromLabel = 'No Min';
-  const toLabel = 'No Max';
-  const maxLength = 14;
-  let output = '';
-  if (filterName === 'Price') {
-    output = `<div class="multiple-inputs">
-                <div id="Min${filterLabel}" class="input-dropdown">
-                <input type="text" maxLength="${maxLength}" list="listMin${filterLabel}"
-                    name="Min${filterLabel}" aria-describedby="Min${filterLabel}"
-                    placeholder="${fromLabel}" aria-label="Minimum ${filterLabel}"
-                    class="price-range-input min-price">
-                <datalist id="listMinPrice" class="list${filterLabel}"></datalist>
-            </div>
-        <span class="range-label text-up">to</span>
-        <div id="Max${filterLabel}" class="input-dropdown">
-            <input type="text" maxLength="${maxLength}" list="listMax${filterLabel}" name="Max${filterLabel}" aria-describedby="Max${filterLabel}"
-                  placeholder="${toLabel}" aria-label="Maximum ${filterLabel}"
-                  class="price-range-input max-price">
-            <datalist id="listMax${filterLabel}" class="list${filterLabel}"></datalist>
-            </div>
-        </div>`;
-  }
-  if (filterName === 'LivingArea' || filterName === 'YearBuilt') {
-    const fromName = filterName === 'LivingArea' ? 'MinLivingArea' : '';
-    const toName = filterName === 'LivingArea' ? 'MaxLivingArea' : '';
-    output = `<div class="multiple-inputs">
-                ${addOptions(filterName, fromLabel, 'multi', fromName)}
-                <span class="range-label text-up">to</span>
-                ${addOptions(filterName, toLabel, 'multi', toName)}
-                </section>
-            </div>
-            `;
-  }
-  return output;
-}
-
-function abbrNum(d, h) {
-  h = 10 ** h;
-  const k = ['k', 'm', 'b', 't']; let
-    m;
-  for (m = k.length - 1; m >= 0; m--) {
-    const n = 10 ** (3 * (m + 1));
-    if (n <= d) {
-      d = Math.round(d * h / n) / h;
-      d === 1E3 && m < k.length - 1 && (d = 1, m++);
-      d += k[m];
-      break;
-    }
-  }
-  return d;
-}
-
-export function formatPriceLabel(minPrice, maxPrice) {
-  const d = minPrice.replace(/[^0-9]/g, '');
-  const h = maxPrice.replace(/[^0-9]/g, '');
-  return d !== '' && h !== ''
-    ? `$${abbrNum(d, 2)} - $${abbrNum(h, 2)}`
-    : d !== '' ? `$${abbrNum(d, 2)}`
-      : d == '' && h !== '' ? `$0 - $${abbrNum(h, 2)}`
-        : 'Price';
-}
-
-export function processSearchType(value, defaultInput = ApplicationType.FOR_SALE.type) {
-  const name = value.replace(' ', '_').toUpperCase();
-  const wrapper = document.createElement('div');
-  wrapper.classList.add('filter-toggle', formatInput(value), 'flex-row', 'mb-1');
-  wrapper.setAttribute('name', name);
-  wrapper.innerHTML = `
-                <input hidden="hidden" type="checkbox" aria-label="Hidden checkbox" value="${value.toLowerCase() === defaultInput}">
-                <div class="checkbox ${value.toLowerCase() === defaultInput ? 'checked' : ''}"></div>
-                <label role="presentation" class="ml-1">${value}</label>
-            </div>`;
-  return wrapper;
-}
-
-export function buildKeywordEl(keyword, removeItemCallback) {
-  const item = document.createElement('span');
-  const keywordInput = document.querySelector('[name="Features"] input[type="text"]');
-  const keywordContainer = document.querySelector('#container-tags');
-  item.classList.add('tag');
-  item.textContent = `${keyword} `;
-  const closeBtn = document.createElement('span');
-  closeBtn.classList.add('close');
-  item.appendChild(closeBtn);
-  keywordContainer.append(item);
-  closeBtn.addEventListener(
-    'click',
-    (e) => {
-      e.preventDefault();
-      e.stopPropagation();
-      const itemEl = e.target.closest('.tag');
-      removeItemCallback('Features', itemEl.textContent.trim());
-      itemEl.remove();
-    },
-  );
-  keywordInput.value = '';
-}
-
-export function buildFilterSearchTypesElement() {
-  const config = getConfig('ApplicationType');
-  const columns = [[config[0], config[1]], [config[2], config[3]]];
-  let el;
-  let output = '<div class="column-2 flex-row">';
-
-  columns.forEach((column) => {
-    output += '<div class="column">';
-    column.forEach((value) => {
-      el = processSearchType(value);
-      el.querySelector('label').classList.add('text-up');
-      output += el.outerHTML;
-    });
-    output += '</div>';
-  });
-  output += '</div>';
-  return output;
-}
-
-export function hideFilter(element) {
-  element.classList.remove('open');
-  element.querySelector('.search-results-dropdown').classList.add('hide');
-}
-
-export function togglePropertyForm() {
-  const hideClass = 'hide';
-  document.querySelector('.filter-block').classList.toggle(hideClass);
-  toggleOverlay();
-  document.querySelector('.filter-buttons').classList.toggle(hideClass);
-  document.querySelectorAll('.filter-container svg').forEach(
-    (el) => el.classList.toggle(hideClass),
-  );
-}
-
-export function closeTopLevelFilters(all = true) {
-  if (all && document.querySelector('[name="AdditionalFilters"] a >svg:first-of-type').classList.contains('hide')) {
-    togglePropertyForm();
-  }
-  document.querySelectorAll('.container-item .header').forEach((elem) => {
-    if (elem.parentElement.classList.contains('open')) {
-      hideFilter(elem.parentElement);
-    }
-    if (elem.parentElement.querySelectorAll('.select-item').length > 0) {
-      elem.parentElement.querySelectorAll('.select-item').forEach((el) => {
-        el.classList.remove('show');
-      });
-    }
-  });
-  if (document.querySelector('.search-bar').classList.contains('show-suggestions')) {
-    document.querySelector('.search-bar').classList.remove('show-suggestions');
-  }
-  if (document.querySelector('[name="Sort"] .select-item').classList.contains('show')) {
-    document.querySelector('[name="Sort"] .select-item').classList.remove('show');
-  }
-}
-
-export function updateFilters(el) {
-  const filter = el.closest('.filter');
-  const forRentEl = filter.querySelector('.for-rent');
-  const pendingEl = filter.querySelector('.pending');
-  const isForRentChecked = filter.querySelector('.for-rent .checkbox').classList.contains('checked');
-  const isPendingChecked = filter.querySelector('.pending .checkbox').classList.contains('checked');
-
-  forRentEl.classList.toggle('disabled', isPendingChecked);
-  pendingEl.classList.toggle('disabled', isForRentChecked);
-}
diff --git a/blocks/property-search-bar/delayed.js b/blocks/property-search-bar/delayed.js
new file mode 100644
index 00000000..256fbc4c
--- /dev/null
+++ b/blocks/property-search-bar/delayed.js
@@ -0,0 +1,918 @@
+import { BREAKPOINTS } from '../../scripts/scripts.js';
+import { closeOnBodyClick, filterItemClicked } from '../shared/search/util.js';
+import { SQUARE_FEET } from './property-search-bar.js';
+import ListingType from '../../scripts/apis/creg/search/types/ListingType.js';
+import Search, { UPDATE_SEARCH_EVENT, SEARCH_URL } from '../../scripts/apis/creg/search/Search.js';
+
+function toggleAdvancedFilters(e) {
+  const open = e.currentTarget.classList.toggle('open');
+  const wrapper = e.currentTarget.closest('.search-form-wrapper');
+  const filters = wrapper.querySelector('.advanced-filters');
+  filters.classList.toggle('open');
+  filters.scrollTo({ top: 0, behavior: 'smooth' });
+  wrapper.querySelector('.search-overlay').classList.toggle('visible');
+
+  if (open) {
+    document.body.style.overflowY = 'hidden';
+  } else {
+    document.body.style.overflowY = '';
+  }
+}
+
+const updateExpanded = (wrapper) => {
+  const wasOpen = wrapper.classList.contains('open');
+  const thisForm = wrapper.closest('form');
+  thisForm.querySelectorAll('[class*="-wrapper"][class*="open"]').forEach((item) => {
+    if (item !== wrapper && item.contains(wrapper)) {
+      return;
+    }
+    item.classList.remove('open');
+    item.querySelector('[aria-expanded="true"]')?.setAttribute('aria-expanded', 'false');
+  });
+  if (!wasOpen) {
+    wrapper.classList.add('open');
+    wrapper.querySelector('[aria-expanded="false"]')?.setAttribute('aria-expanded', 'true');
+    closeOnBodyClick(wrapper);
+  }
+};
+
+async function observeSearchInput(e) {
+  e.preventDefault();
+  const form = e.target.closest('form');
+  try {
+    const mod = await import(`${window.hlx.codeBasePath}/blocks/shared/search/suggestion.js`);
+    mod.default(form);
+  } catch (error) {
+    // eslint-disable-next-line no-console
+    console.log('failed to load suggestion library', error);
+  }
+  e.target.removeEventListener('focus', observeSearchInput);
+}
+
+const createPriceList = (d) => {
+  let options = '';
+  const k = [10, 100, 1E3, 1E4, 1E5, 1E6];
+  // eslint-disable-next-line no-plusplus
+  if (d) for (let m = 1; m <= 6; m++) options += `<option> ${d * k[m - 1]} </option>`;
+  return options;
+};
+
+function abbrNum(value, exp) {
+  let abbr = value;
+  const factor = 10 ** exp;
+  const k = ['k', 'm', 'b', 't'];
+  let m;
+  for (m = k.length - 1; m >= 0; m -= 1) {
+    const n = 10 ** (3 * (m + 1));
+    if (n <= abbr) {
+      abbr = Math.round((value * factor) / n) / factor;
+      if (abbr === 1E3 && m < k.length - 1) {
+        abbr = 1;
+        m += 1;
+      }
+      abbr += k[m];
+      break;
+    }
+  }
+  return abbr;
+}
+
+function updatePriceLabel(wrapper) {
+  const min = wrapper.querySelector('input[name="min-price"]').value;
+  const max = wrapper.querySelector('input[name="max-price"]').value;
+
+  let content;
+  const low = min.replace(/[^0-9]/g, '');
+  const high = max.replace(/[^0-9]/g, '');
+  if (low !== '' && high !== '') {
+    content = `$${abbrNum(low, 2)} -<br/>$${abbrNum(high, 2)}`;
+  } else if (low !== '') {
+    content = `$${abbrNum(low, 2)}`;
+  } else if (high !== '') {
+    content = `$0 -<br/>$${abbrNum(high, 2)}`;
+  } else {
+    content = 'Price';
+  }
+  wrapper.querySelector('.selected span').innerHTML = content;
+}
+
+function observePriceInput(e) {
+  e.preventDefault();
+  const { target } = e;
+  const { value } = target;
+  const datalist = target.closest('.input-dropdown').querySelector('datalist');
+  datalist.innerHTML = createPriceList(value);
+}
+
+function filterSelectClicked(e) {
+  e.preventDefault();
+  e.stopPropagation();
+  updateExpanded(e.currentTarget.closest('.select-wrapper'));
+}
+
+function rangeSelectClicked(e) {
+  e.preventDefault();
+  e.stopPropagation();
+  updateExpanded(e.currentTarget.closest('.range-wrapper'));
+}
+
+function sqftSelectClicked(e) {
+  e.preventDefault();
+  e.stopPropagation();
+  updateExpanded(e.currentTarget.closest('.select-wrapper'));
+}
+
+function updateSqftLabel(wrapper) {
+  const min = wrapper.querySelector('#list-min-sqft li.selected');
+  const max = wrapper.querySelector('#list-max-sqft li.selected');
+
+  let label = wrapper.querySelector('div.selected').getAttribute('aria-label');
+
+  if (min.getAttribute('data-value') || max.getAttribute('data-value')) {
+    label = `${min.textContent} -<br/>${max.textContent}`;
+  }
+  wrapper.querySelector('span').innerHTML = label;
+}
+
+function addKeyword(wrapper, value) {
+  const keyword = document.createElement('div');
+  keyword.classList.add('keyword');
+  keyword.innerHTML = `
+    <span>${value}</span>
+    <span class="close">X</span>
+  `;
+  keyword.querySelector('.close').addEventListener('click', (localE) => {
+    localE.stopPropagation();
+    localE.preventDefault();
+    localE.currentTarget.closest('.keyword').remove();
+  });
+
+  wrapper.querySelector('.keywords-list').append(keyword);
+}
+
+async function updateParameters() {
+  const form = document.querySelector('.property-search-bar.block form');
+  // Build Search Obj and store it.
+  let search;
+  if (window.location.pathname !== SEARCH_URL) {
+    let type = form.querySelector('input[name="type"]').value;
+    if (type) {
+      type = type.replaceAll(/\s/g, '');
+      if (type === 'ZipCode') {
+        type = 'PostalCode';
+      } else if (type === 'MLS #') {
+        type = 'MLSListingKey';
+      }
+    }
+    search = await Search.load(type);
+  } else {
+    search = await Search.fromQueryString(window.location.search);
+  }
+  let input = form.querySelector('.suggester-input input[type="text"]');
+  if (input.value) search.input = input.value;
+  input = form.querySelector('.result-filters input[name="min-price"]');
+  if (input.value) search.minPrice = input.value;
+  input = form.querySelector('.result-filters input[name="max-price"]');
+  if (input.value) search.maxPrice = input.value;
+  input = form.querySelector('.result-filters .bedrooms select');
+  if (input.value) search.minBedrooms = input.value;
+  input = form.querySelector('.result-filters .bathrooms select');
+  if (input.value) search.minBathrooms = input.value;
+  input = form.querySelector('.result-filters #min-sqft select');
+  if (input.value) search.minSqft = input.value;
+  input = form.querySelector('.result-filters #max-sqft select');
+  if (input.value) search.maxSqft = input.value;
+  search.listingTypes = [];
+  input = form.querySelector('.listing-types input[name="FOR_SALE"]');
+  if (input.checked) search.addListingType(ListingType.FOR_SALE);
+  input = form.querySelector('.listing-types input[name="FOR_RENT"]');
+  if (input.checked) search.addListingType(ListingType.FOR_RENT);
+  input = form.querySelector('.listing-types input[name="PENDING"]');
+  if (input.checked) search.addListingType(ListingType.PENDING);
+  input = form.querySelector('.listing-types input[name="RECENTLY_SOLD"]');
+  if (input.checked) search.addListingType(ListingType.RECENTLY_SOLD);
+  search.propertyTypes = [];
+  form.querySelectorAll('.property-types button.selected').forEach((btn) => search.addPropertyType(btn.name));
+  search.keyword = [];
+  form.querySelectorAll('.keywords .keywords-list .keyword span:first-of-type').forEach((kw) => search.keywords.push(kw.textContent));
+  if (form.querySelector('.keywords input[name="matchType"]').value === 'any') {
+    search.matchAnyKeyword = true;
+  }
+  input = form.querySelector('.year-range #min-year select');
+  if (input.value) search.minYear = input.value;
+  input = form.querySelector('.year-range #max-year select');
+  if (input.value) search.maxYear = input.value;
+  search.isNew = form.querySelector('.is-new input').checked;
+  search.priceChange = form.querySelector('.price-change input').checked;
+  input = form.querySelector('.open-houses input');
+  if (input.checked) search.openHouses = form.querySelector('.open-houses input[name="open-houses-timeframe"]:checked').value;
+  input = form.querySelector('.lux input');
+  if (input.checked) search.luxury = true;
+  input = form.querySelector('.bhhs-only input');
+  if (input.checked) search.bhhsOnly = true;
+
+  form.querySelector('a.filter.open')?.dispatchEvent(new MouseEvent('click'));
+  if (window.location.pathname !== SEARCH_URL) {
+    window.location = `${SEARCH_URL}?${search.asURLSearchParameters().toString()}`;
+  } else {
+    window.dispatchEvent(new CustomEvent(UPDATE_SEARCH_EVENT, { detail: { search } }));
+  }
+}
+
+function syncToBar() {
+  const bar = document.querySelector('.property-search-bar.block form .result-filters');
+  const attrib = document.querySelector('.property-search-bar.block form .advanced-filters .attributes');
+  bar.querySelector('input[name="min-price"]').value = attrib.querySelector('input[name="adv-min-price"]').value;
+  bar.querySelector('input[name="max-price"]').value = attrib.querySelector('input[name="adv-max-price"]').value;
+  updatePriceLabel(bar.querySelector('.range-wrapper.price'));
+
+  const bedrooms = attrib.querySelector('.bedrooms li input:checked').value;
+  bar.querySelector(`.select-wrapper.bedrooms li[data-value="${bedrooms}"]`).dispatchEvent(new MouseEvent('click'));
+  const bathrooms = attrib.querySelector('.bathrooms li input:checked').value;
+  bar.querySelector(`.select-wrapper.bathrooms li[data-value="${bathrooms}"]`).dispatchEvent(new MouseEvent('click'));
+
+  const minSqft = attrib.querySelector('#adv-min-sqft select').value;
+  bar.querySelector(`.range-wrapper.sqft #min-sqft ul li[data-value="${minSqft}"]`).dispatchEvent(new MouseEvent('click'));
+  const maxSqft = attrib.querySelector('#adv-max-sqft select').value;
+  bar.querySelector(`.range-wrapper.sqft #max-sqft ul li[data-value="${maxSqft}"]`).dispatchEvent(new MouseEvent('click'));
+}
+
+function syncToAdvanced() {
+  const bar = document.querySelector('.property-search-bar.block form .result-filters');
+  const attrib = document.querySelector('.property-search-bar.block form .advanced-filters .attributes');
+  attrib.querySelector('input[name="adv-min-price"]').value = bar.querySelector('input[name="min-price"]').value;
+  attrib.querySelector('input[name="adv-max-price"]').value = bar.querySelector('input[name="max-price"]').value;
+
+  const bedrooms = bar.querySelector('.bedrooms select').value;
+  attrib.querySelector(`.bedrooms li[data-value="${bedrooms}"] input`).checked = true;
+  const bathrooms = bar.querySelector('.bathrooms select').value;
+  attrib.querySelector(`.bathrooms li[data-value="${bathrooms}"] input`).checked = true;
+
+  const minSqft = bar.querySelector('#min-sqft select').value;
+  attrib.querySelector(`.sqft #adv-min-sqft ul li[data-value="${minSqft}"]`).dispatchEvent(new MouseEvent('click'));
+  const maxSqft = bar.querySelector('#max-sqft select').value;
+  attrib.querySelector(`.sqft #adv-max-sqft ul li[data-value="${maxSqft}"]`).dispatchEvent(new MouseEvent('click'));
+}
+
+function resetForm(e) {
+  e.stopPropagation();
+  e.preventDefault();
+  const form = e.currentTarget.closest('form');
+  form.querySelectorAll('.advanced-filters .listing-types input[checked="checked"]').forEach((input) => input.closest('.filter-toggle').dispatchEvent(new MouseEvent('click')));
+  form.querySelector('.advanced-filters input[name="FOR_SALE"]').closest('.filter-toggle').dispatchEvent(new MouseEvent('click'));
+  form.querySelectorAll('.advanced-filters .range-wrapper.price input[type="text"]').forEach((input) => {
+    input.value = '';
+  });
+  form.querySelectorAll('.advanced-filters .bedrooms li[data-value=""] input').forEach((li) => li.dispatchEvent(new MouseEvent('click')));
+  form.querySelectorAll('.advanced-filters .bathrooms li[data-value=""] input').forEach((li) => li.dispatchEvent(new MouseEvent('click')));
+  form.querySelectorAll('.advanced-filters .sqft li[data-value=""]').forEach((li) => li.dispatchEvent(new MouseEvent('click')));
+  form.querySelectorAll('.advanced-filters .property-types button').forEach((button) => button.classList.add('selected'));
+  form.querySelectorAll('.advanced-filters .property-types button[name="COMMERCIAL"]').forEach((button) => button.classList.remove('selected'));
+  form.querySelector('.advanced-filters .property-types .all input[type="checkbox"]').checked = false;
+  form.querySelectorAll('.advanced-filters .misc .year-range li[data-value=""]').forEach((li) => li.dispatchEvent(new MouseEvent('click')));
+  form.querySelectorAll('.advanced-filters .misc .filter-toggle input[checked="checked"]').forEach((input) => input.closest('.filter-toggle').dispatchEvent(new MouseEvent('click')));
+}
+
+/**
+ * Updates the bar and advanced form parameters based on the provided Search object.
+ * @param {Search} search
+ */
+// eslint-disable-next-line import/prefer-default-export
+export function updateForm(search) {
+  const bar = document.querySelector('.property-search-bar.block .search-form-wrapper');
+  const advanced = document.querySelector('.property-search-bar.block .advanced-filters');
+
+  bar.querySelector('input[name="type"]').value = search.type;
+  bar.querySelector('input[name="keyword"]').value = search.input || '';
+  bar.querySelector('input[name="min-price"]').value = search.minPrice || '';
+  advanced.querySelector('input[name="adv-min-price"]').value = search.minPrice || '';
+  bar.querySelector('input[name="max-price"]').value = search.maxPrice || '';
+  advanced.querySelector('input[name="adv-max-price"]').value = search.maxPrice || '';
+  updatePriceLabel(bar.querySelector('.range-wrapper.price'));
+
+  const beds = search.minBedrooms;
+  let display;
+  bar.querySelector('.select-wrapper.bedrooms ul li.selected')?.classList.toggle('selected');
+  if (beds) {
+    bar.querySelector(`.select-wrapper.bedrooms select option[value="${beds}"]`).selected = true;
+    advanced.querySelector(`div.bedrooms input[value="${beds}"]`).checked = true;
+    const selected = bar.querySelector(`.select-wrapper.bedrooms ul li[data-value="${beds}"]`);
+    selected.classList.add('selected');
+    display = selected.textContent;
+  } else {
+    bar.querySelector('.select-wrapper.bedrooms select option[value=""]').selected = true;
+    advanced.querySelector('div.bedrooms input[value=""]').checked = true;
+    const selected = bar.querySelector('.select-wrapper.bedrooms ul li[data-value=""]');
+    selected.classList.add('selected');
+    display = selected.textContent;
+  }
+
+  bar.querySelector('.select-wrapper.bedrooms div.selected span').textContent = display;
+  const baths = search.minBathrooms;
+  bar.querySelector('.select-wrapper.bathrooms ul li.selected')?.classList.toggle('selected');
+  if (baths) {
+    bar.querySelector(`.select-wrapper.bathrooms select option[value="${baths}"]`).selected = true;
+    advanced.querySelector(`div.bathrooms input[value="${baths}"]`).checked = true;
+    const selected = bar.querySelector(`.select-wrapper.bathrooms ul li[data-value="${baths}"]`);
+    selected.classList.add('selected');
+    display = selected.textContent;
+  } else {
+    bar.querySelector('.select-wrapper.bathrooms select option[value=""]').selected = true;
+    advanced.querySelector('div.bathrooms input[value=""]').checked = true;
+    const selected = bar.querySelector('.select-wrapper.bathrooms ul li[data-value=""]');
+    selected.classList.add('selected');
+    display = selected.textContent;
+  }
+  bar.querySelector('.select-wrapper.bathrooms div.selected span').textContent = display;
+
+  const { minSqft, maxSqft } = search;
+  bar.querySelector('.range-wrapper.sqft #min-sqft ul li.selected').classList.remove('selected');
+  advanced.querySelector('div.sqft #adv-min-sqft ul li.selected').classList.remove('selected');
+  if (minSqft) {
+    bar.querySelector(`.range-wrapper.sqft #min-sqft select option[value="${minSqft}"]`).selected = true;
+    bar.querySelector(`.range-wrapper.sqft #min-sqft ul li[data-value="${minSqft}"]`).classList.add('selected');
+    advanced.querySelector(`div.sqft #adv-min-sqft select option[value="${minSqft}"]`).selected = true;
+    advanced.querySelector(`div.sqft #adv-min-sqft ul li[data-value="${minSqft}"]`).classList.add('selected');
+  } else {
+    bar.querySelector('.range-wrapper.sqft #min-sqft select option[value=""]').selected = true;
+    bar.querySelector('.range-wrapper.sqft #min-sqft ul li[data-value=""]').classList.add('selected');
+    advanced.querySelector('div.sqft #adv-min-sqft select option[value=""]').selected = true;
+    advanced.querySelector('div.sqft #adv-min-sqft ul li[data-value=""]').classList.add('selected');
+  }
+  bar.querySelector('.range-wrapper.sqft #min-sqft div.selected span').textContent = bar.querySelector('.range-wrapper.sqft #min-sqft ul li.selected').textContent;
+  advanced.querySelector('div.sqft #adv-min-sqft div.selected span').textContent = advanced.querySelector('div.sqft #adv-min-sqft ul li.selected').textContent;
+
+  bar.querySelector('.range-wrapper.sqft #max-sqft ul li.selected').classList.remove('selected');
+  advanced.querySelector('div.sqft #adv-max-sqft ul li.selected').classList.remove('selected');
+  if (maxSqft) {
+    bar.querySelector(`.range-wrapper.sqft #max-sqft select option[value="${maxSqft}"]`).selected = true;
+    bar.querySelector(`.range-wrapper.sqft #max-sqft ul li[data-value="${maxSqft}"]`).classList.add('selected');
+    advanced.querySelector(`div.sqft #adv-max-sqft select option[value="${maxSqft}"]`).selected = true;
+    advanced.querySelector(`div.sqft #adv-max-sqft ul li[data-value="${maxSqft}"]`).classList.add('selected');
+  } else {
+    bar.querySelector('.range-wrapper.sqft #max-sqft select option[value=""]').selected = true;
+    bar.querySelector('.range-wrapper.sqft #max-sqft ul li[data-value=""]').classList.add('selected');
+    advanced.querySelector('div.sqft #adv-max-sqft select option[value=""]').selected = true;
+    advanced.querySelector('div.sqft #adv-max-sqft ul li[data-value=""]').classList.add('selected');
+  }
+  bar.querySelector('.range-wrapper.sqft #max-sqft div.selected span').textContent = bar.querySelector('.range-wrapper.sqft #max-sqft ul li.selected').textContent;
+  advanced.querySelector('div.sqft #adv-max-sqft div.selected span').textContent = advanced.querySelector('div.sqft #adv-max-sqft ul li.selected').textContent;
+  updateSqftLabel(bar.querySelector('.range-wrapper.sqft'));
+
+  advanced.querySelectorAll('.listing-types .filter-toggle.disabled').forEach((t) => t.classList.remove('disabled'));
+  advanced.querySelectorAll('.listing-types .filter-toggle input[type="checkbox"]').forEach((c) => {
+    c.removeAttribute('checked');
+    c.nextElementSibling.classList.remove('checked');
+  });
+  search.listingTypes.forEach((t) => {
+    const chkbx = advanced.querySelector(`.listing-types .filter-toggle input[name="${t.type}"]`);
+    chkbx.checked = true;
+    chkbx.nextElementSibling.classList.add('checked');
+    if (t.type === ListingType.FOR_RENT.type) {
+      advanced.querySelector(`.listing-types .filter-toggle input[name="${ListingType.PENDING.type}"]`).closest('.filter-toggle').classList.add('disabled');
+    } else if (t.type === ListingType.PENDING.type) {
+      advanced.querySelector(`.listing-types .filter-toggle input[name="${ListingType.FOR_RENT.type}"]`).closest('.filter-toggle').classList.add('disabled');
+    }
+  });
+
+  advanced.querySelectorAll('.property-types button.selected').forEach((b) => b.classList.remove('selected'));
+  search.propertyTypes.forEach((t) => {
+    advanced.querySelector(`.property-types button[name="${t.name}"]`).classList.add('selected');
+  });
+  const unselected = advanced.querySelector('.property-types button:not(.selected)');
+  if (unselected) {
+    advanced.querySelector('.property-types .all label input').checked = false;
+  } else {
+    advanced.querySelector('.property-types .all label input').checked = true;
+  }
+
+  const kwWrapper = advanced.querySelector('.keywords');
+  kwWrapper.querySelector('.keywords-list').replaceChildren();
+  search.keywords.forEach((kw) => addKeyword(kwWrapper, kw));
+  if (search.matchAnyKeyword) {
+    advanced.querySelector('.keywords input[value="any"]').checked = true;
+  } else {
+    advanced.querySelector('.keywords input[value="all"]').checked = true;
+  }
+
+  const { minYear, maxYear } = search;
+  const minYearWrapper = advanced.querySelector('div.year-range #min-year');
+  minYearWrapper.querySelector('ul li.selected').classList.remove('selected');
+  if (minYear) {
+    minYearWrapper.querySelector(`select option[value="${minYear}"]`).selected = true;
+    minYearWrapper.querySelector(`ul li[data-value="${minYear}"]`).classList.add('selected');
+  } else {
+    minYearWrapper.querySelector('select option[value=""]').selected = true;
+    minYearWrapper.querySelector('ul li[data-value=""]').classList.add('selected');
+  }
+  minYearWrapper.querySelector('div.selected span').textContent = minYearWrapper.querySelector('ul li.selected').textContent;
+
+  const maxYearWrapper = advanced.querySelector('div.year-range #max-year');
+  maxYearWrapper.querySelector('ul li.selected').classList.remove('selected');
+  if (maxYear) {
+    maxYearWrapper.querySelector(`select option[value="${maxYear}"]`).selected = true;
+    maxYearWrapper.querySelector(`ul li[data-value="${maxYear}"]`).classList.add('selected');
+  } else {
+    maxYearWrapper.querySelector('select option[value=""]').selected = true;
+    maxYearWrapper.querySelector('ul li[data-value=""]').classList.add('selected');
+  }
+  maxYearWrapper.querySelector('div.selected span').textContent = maxYearWrapper.querySelector('ul li.selected').textContent;
+
+  if (search.isNew) {
+    advanced.querySelector('.is-new .filter-toggle input').checked = true;
+    advanced.querySelector('.is-new .filter-toggle .checkbox').classList.add('checked');
+  } else {
+    advanced.querySelector('.is-new .filter-toggle input').checked = false;
+    advanced.querySelector('.is-new .filter-toggle .checkbox').classList.remove('checked');
+  }
+
+  if (search.priceChange) {
+    advanced.querySelector('.price-change .filter-toggle input').checked = true;
+    advanced.querySelector('.price-change .filter-toggle .checkbox').classList.add('checked');
+  } else {
+    advanced.querySelector('.price-change .filter-toggle input').checked = false;
+    advanced.querySelector('.price-change .filter-toggle .checkbox').classList.remove('checked');
+  }
+
+  if (search.openHouses) {
+    advanced.querySelector('.open-houses .filter-toggle input').checked = true;
+    advanced.querySelector('.open-houses .filter-toggle .checkbox').classList.add('checked');
+    advanced.querySelector('.open-houses .open-houses-timeframe').classList.add('visible');
+    advanced.querySelector(`.open-houses input[value=${search.openHouses.name}]`).checked = true;
+  } else {
+    advanced.querySelector('.open-houses .filter-toggle input').checked = false;
+    advanced.querySelector('.open-houses .filter-toggle .checkbox').classList.remove('checked');
+    advanced.querySelector('.open-houses .open-houses-timeframe').classList.remove('visible');
+  }
+
+  if (search.luxury) {
+    advanced.querySelector('.lux .filter-toggle input').checked = true;
+    advanced.querySelector('.lux .filter-toggle .checkbox').classList.add('checked');
+  } else {
+    advanced.querySelector('.lux .filter-toggle input').checked = false;
+    advanced.querySelector('.lux .filter-toggle .checkbox').classList.remove('checked');
+  }
+
+  if (search.luxury) {
+    advanced.querySelector('.bhhs-only .filter-toggle input').checked = true;
+    advanced.querySelector('.bhhs-only .filter-toggle .checkbox').classList.add('checked');
+  } else {
+    advanced.querySelector('.bhhs-only .filter-toggle input').checked = false;
+    advanced.querySelector('.bhhs-only .filter-toggle .checkbox').classList.remove('checked');
+  }
+}
+
+function buildAdvancedFilters() {
+  const wrapper = document.querySelector('.property-search-bar.block .advanced-filters');
+  wrapper.innerHTML = `
+    <div class="listing-types">
+      <label class="section-label">Search Types</label>
+      <div class="filter-toggle">
+        <input name="${ListingType.FOR_SALE.type}" hidden="hidden" type="checkbox" aria-label="Hidden checkbox" checked="checked" value="${ListingType.FOR_SALE.type}">
+        <div class="checkbox checked"></div>
+        <label role="presentation">${ListingType.FOR_SALE.label}</label>
+      </div>
+      <div class="filter-toggle">
+        <input name="${ListingType.FOR_RENT.type}" hidden="hidden" type="checkbox" aria-label="Hidden checkbox" value="${ListingType.FOR_RENT.type}">
+        <div class="checkbox"></div>
+        <label role="presentation">${ListingType.FOR_RENT.label}</label>
+      </div>
+      <div class="filter-toggle">
+        <input name="${ListingType.PENDING.type}" hidden="hidden" type="checkbox" aria-label="Hidden checkbox" value="${ListingType.PENDING.type}">
+        <div class="checkbox"></div>
+        <label role="presentation">${ListingType.PENDING.label}</label>
+      </div>
+      <div class="filter-toggle">
+        <input name="${ListingType.RECENTLY_SOLD.type}" hidden="hidden" type="checkbox" aria-label="Hidden checkbox" value="${ListingType.RECENTLY_SOLD.type}">
+        <div class="checkbox"></div>
+        <label role="presentation">${ListingType.RECENTLY_SOLD.label}</label>
+      </div>
+    </div>
+    <div class="attributes">
+      <div class="range-wrapper price">
+        <label class="section-label" role="presentation">Price</label>
+        <div class="range-items">
+          <div id="adv-min-price" class="input-dropdown">
+            <input type="text" name="adv-min-price" maxlength="14" aria-describedby="adv-min-price" aria-label="Minimum price" placeholder="No Min" list="adv-list-min-price">
+            <datalist id="adv-list-min-price"></datalist> 
+          </div> 
+          <span>to</span>
+          <div id="adv-max-price" class="input-dropdown">
+            <input type="text" name="adv-max-price" maxlength="14" aria-describedby="adv-max-price" aria-label="Maximum price" placeholder="No Max" list="adv-list-max-price">
+            <datalist id="adv-list-max-price"></datalist> 
+          </div> 
+        </div>
+      </div>
+      <div class="bedrooms">
+        <label class="section-label" role="presentation">Bedrooms</label>
+        <ul>
+          <li data-value=""><input name="bedrooms" aria-describedby="bedrooms-any" type="radio" id="bedrooms-any" value="" tabindex="0" checked><label for="bedrooms-any">Any</label></li>
+          <li data-value="1"><input name="bedrooms" aria-describedby="bedrooms-1" type="radio" id="bedrooms-1" value="1" tabindex="0"><label for="bedrooms-1">1+</label></li>
+          <li data-value="2"><input name="bedrooms" aria-describedby="bedrooms-2" type="radio" id="bedrooms-2" value="2" tabindex="0"><label for="bedrooms-2">2+</label></li>
+          <li data-value="3"><input name="bedrooms" aria-describedby="bedrooms-3" type="radio" id="bedrooms-3" value="3" tabindex="0"><label for="bedrooms-3">3+</label></li>
+          <li data-value="4"><input name="bedrooms" aria-describedby="bedrooms-4" type="radio" id="bedrooms-4" value="4" tabindex="0"><label for="bedrooms-4">4+</label></li>
+          <li data-value="5"><input name="bedrooms" aria-describedby="bedrooms-5" type="radio" id="bedrooms-5" value="5" tabindex="0"><label for="bedrooms-5">5+</label></li>
+        </ul>
+      </div>
+      <div class="bathrooms">
+        <label class="section-label" role="presentation">Bathroom</label>
+        <ul>
+          <li data-value=""><input name="bathrooms" aria-describedby="bathrooms-any" type="radio" id="bathrooms-any" value="" tabindex="0" checked><label for="bathrooms-any">Any</label></li>
+          <li data-value="1"><input name="bathrooms" aria-describedby="bathrooms-1" type="radio" id="bathrooms-1" value="1" tabindex="0"><label for="bathrooms-1">1+</label></li>
+          <li data-value="2"><input name="bathrooms" aria-describedby="bathrooms-2" type="radio" id="bathrooms-2" value="2" tabindex="0"><label for="bathrooms-2">2+</label></li>
+          <li data-value="3"><input name="bathrooms" aria-describedby="bathrooms-3" type="radio" id="bathrooms-3" value="3" tabindex="0"><label for="bathrooms-3">3+</label></li>
+          <li data-value="4"><input name="bathrooms" aria-describedby="bathrooms-4" type="radio" id="bathrooms-4" value="4" tabindex="0"><label for="bathrooms-4">4+</label></li>
+          <li data-value="5"><input name="bathrooms" aria-describedby="bathrooms-5" type="radio" id="bathrooms-5" value="5" tabindex="0"><label for="bathrooms-5">5+</label></li>
+        </ul>
+      </div>
+      <div class="sqft">
+        <label class="section-label" role="presentation">Square Feet</label>
+        <div class="range-items">
+          <div id="adv-min-sqft" class="select-wrapper">
+            <select name="adv-min-sqft" aria-label="No Min">
+              <option value="">No Min</option>
+            </select>
+            <div class="selected" role="combobox" aria-haspopup="listbox" aria-label="No Min" aria-expanded="false" aria-controls="adv-list-min-sqft" tabindex="0"><span>No Min</span></div>
+            <ul id="adv-list-min-sqft" class="select-items" role="listbox">
+              <li data-value="" role="option" class="selected">No Min</li>
+            </ul>
+          </div>
+          <span>to</span>
+          <div id="adv-max-sqft" class="select-wrapper">
+            <select name="adv-max-sqft" aria-label="No Max">
+              <option value="">No Max</option>
+            </select>
+            <div class="selected" role="combobox" aria-haspopup="listbox" aria-label="No Max" aria-expanded="false" aria-controls="adv-list-max-sqft" tabindex="0"><span>No Max</span></div>
+            <ul id="adv-list-max-sqft" class="select-items" role="listbox">
+              <li data-value="" role="option" class="selected">No Max</li>
+            </ul>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="property-types">
+      <label class="section-label" role="presentation">Property Type</label>
+      <div class="options">
+        <button name="CONDO_TOWNHOUSE" type="button" class="selected" tabindex="0">
+          <svg role="presentation" aria-hidden="true" tabindex="-1"><use xlink:href="${window.hlx.codeBasePath}/icons/icons.svg#condo-townhouse"></use></svg>
+          <span>Condo / Townhouse</span>
+        </button>
+        <button name="SINGLE_FAMILY" type="button" class="selected" tabindex="0">
+          <svg role="presentation" aria-hidden="true" tabindex="-1"><use xlink:href="${window.hlx.codeBasePath}/icons/icons.svg#single-family"></use></svg>
+          <span>Single Family</span>
+        </button>
+        <button name="COMMERCIAL" type="button" class="" tabindex="0">
+          <svg role="presentation" aria-hidden="true" tabindex="-1"><use xlink:href="${window.hlx.codeBasePath}/icons/icons.svg#commercial"></use></svg>
+          <span>Commercial</span>
+        </button>
+        <button name="MULTI_FAMILY" type="button" class="selected" tabindex="0">
+          <svg role="presentation" aria-hidden="true" tabindex="-1"><use xlink:href="${window.hlx.codeBasePath}/icons/icons.svg#multi-family"></use></svg>
+          <span>Multi Family</span>
+        </button>
+        <button name="LAND" type="button" class="selected" tabindex="0">
+          <svg role="presentation" aria-hidden="true" tabindex="-1"><use xlink:href="${window.hlx.codeBasePath}/icons/icons.svg#lot-land"></use></svg>
+          <span>Lot / Land</span>
+        </button>
+        <button name="FARM" type="button" class="selected" tabindex="0">
+          <svg role="presentation" aria-hidden="true" tabindex="-1"><use xlink:href="${window.hlx.codeBasePath}/icons/icons.svg#farm-ranch"></use></svg>
+          <span>Farm / Ranch</span>
+        </button>
+      </div>
+      <div class="all">
+        <label for="select-all-property-types">
+          <input type="checkbox" value="" id="select-all-property-types" tabindex="0">
+          <div class="checkbox">
+            <svg class="empty" role="presentation" aria-hidden="true" tabindex="-1"><use xlink:href="${window.hlx.codeBasePath}/icons/icons.svg#checkmark"></use></svg>
+          </div>
+          <span class="label">Select All</span>
+        </label>
+      </div>
+    </div>
+    <div class="keywords">
+      <label class="section-label" role="presentation">Keyword Search</label>
+      <div class="keywords-input">
+        <input name="keywords" type="text" placeholder="Pool, Offices, Fireplace..." aria-label="Pool, Offices, Fireplace...">
+        <button><span>Add</span></button>
+      </div>
+      <div class="keywords-list">
+      
+      </div>
+      <div class="keywords-match">
+        <label role="presentation">Match</label>
+        <label role="presenation">
+          <input type="radio" name="matchType" value="any">
+          <div class="radio-button"></div>
+          <span>Any</span>
+        </label>
+        <label role="presenation">
+          <input type="radio" name="matchType" value="all" checked="checked">
+          <div class="radio-button"></div>
+          <span>All</span>
+        </label>
+      </div>
+    </div>
+    <div class="misc">
+      <div class="year-range">
+        <label class="section-label" role="presentation">Year Built</label>
+        <div class="range-items">
+          <div id="min-year" class="select-wrapper">
+            <select name="min-year" aria-label="No Min">
+              <option value="">No Min</option>
+            </select>
+            <div class="selected" role="combobox" aria-haspopup="listbox" aria-label="No Min" aria-expanded="false" aria-controls="list-min-year" tabindex="0"><span>No Min</span></div>
+            <ul id="list-min-year" class="select-items" role="listbox">
+              <li data-value="" role="option" class="selected">No Min</li>
+            </ul>
+          </div>
+          <span>to</span>
+          <div id="max-year" class="select-wrapper">
+            <select name="max-year" aria-label="No Max">
+              <option value="">No Max</option>
+            </select>
+            <div class="selected" role="combobox" aria-haspopup="listbox" aria-label="No Max" aria-expanded="false" aria-controls="list-max-year" tabindex="0"><span>No Max</span></div>
+            <ul id="list-max-year" class="select-items" role="listbox">
+              <li data-value="" role="option" class="selected">No Max</li>
+            </ul>
+          </div>
+        </div>
+      </div>
+      <hr>
+      <div class="is-new">
+        <div class="filter-toggle">
+          <label role="presentation">New Listings</label>
+          <input name="is-new" hidden="hidden" type="checkbox" aria-label="Hidden checkbox" value="true">
+          <div class="checkbox"></div>
+        </div>
+      </div>
+      <hr>
+      <div class="price-change">
+        <div class="filter-toggle">
+          <label role="presentation">Recent Price Changes</label>
+          <input name="price-change" hidden="hidden" type="checkbox" aria-label="Hidden checkbox" value="true">
+          <div class="checkbox"></div>
+        </div>
+      </div>
+      <hr>
+      <div class="open-houses">
+        <div class="filter-toggle">
+          <label role="presentation">Open Houses Only</label>
+          <input name="open-houses" hidden="hidden" type="checkbox" aria-label="Hidden checkbox" value="true">
+          <div class="checkbox"></div>
+        </div>
+        <div class="open-houses-timeframe">
+          <label role="presenation">
+            <input type="radio" name="open-houses-timeframe" value="ONLY_WEEKEND" checked="checked">
+            <div class="radio-button"></div>
+            <span>This Weekend</span>
+          </label>
+          <label role="presenation">
+            <input type="radio" name="open-houses-timeframe" value="ANYTIME">
+            <div class="radio-button"></div>
+            <span>Anytime</span>
+          </label>
+        </div>
+      </div>
+      <hr>
+      <div class="lux">
+        <div class="filter-toggle">
+          <label role="presentation">Luxury</label>
+          <input name="lux" hidden="hidden" type="checkbox" aria-label="Hidden checkbox" value="true">
+          <div class="checkbox"></div>
+        </div>
+      </div>
+      <hr>
+      <div class="bhhs-only">
+        <div class="filter-toggle">
+          <label role="presentation">Berkshire Hathaway Home Services Listings Only</label>
+          <input name="bhhs-only" hidden="hidden" type="checkbox" aria-label="Hidden checkbox" value="true">
+          <div class="checkbox"></div>
+        </div>
+      </div>
+    </div>
+    <div class="buttons">
+      <p class="button-container">
+        <a id="search-apply" href="#" title="Apply">Apply</a>
+      </p>
+      <p class="button-container secondary">
+        <a id="search-cancel" href="#" title="Cancel">Cancel</a>
+      </p>
+      <p class="button-container secondary">
+        <a id="search-reset" href="#" title="Reset">Reset</a>
+      </p>
+    </div>
+  `;
+
+  wrapper.querySelectorAll('#adv-min-sqft, #adv-max-sqft').forEach((item) => {
+    SQUARE_FEET.forEach((b) => {
+      const opt = document.createElement('option');
+      opt.value = b.value;
+      opt.textContent = b.label;
+      item.querySelector('select').append(opt);
+      const li = document.createElement('li');
+      li.setAttribute('data-value', b.value);
+      li.setAttribute('role', 'option');
+      li.textContent = b.label;
+      item.querySelector('ul').append(li);
+    });
+  });
+
+  wrapper.querySelectorAll('#min-year, #max-year').forEach((item) => {
+    let year = new Date().getFullYear();
+    const select = item.querySelector('select');
+    const ul = item.querySelector('ul');
+
+    const addOption = (value) => {
+      const opt = document.createElement('option');
+      opt.value = value;
+      opt.textContent = value;
+      select.append(opt);
+      const li = document.createElement('li');
+      li.setAttribute('data-value', value);
+      li.setAttribute('role', 'option');
+      li.textContent = value;
+      ul.append(li);
+    };
+
+    // Last 6 years individually
+    for (let i = 0; i < 6; i += 1) {
+      addOption(year);
+      year -= 1;
+    }
+
+    // 6 blocks of 5 year increments
+    year -= year % 5;
+    for (let i = 1; i < 6; i += 1) {
+      addOption(year);
+      year -= 5;
+    }
+
+    // 6 blocks of 10 year increments
+    year -= year % 10;
+    for (let i = 1; i < 6; i += 1) {
+      addOption(year);
+      year -= 10;
+    }
+
+    // remaining at 20 year increments
+    while (year >= 1900) {
+      addOption(year);
+      year -= 20;
+    }
+  });
+}
+
+function observeForm(form) {
+  const searchInput = form.querySelector('.suggester-input input');
+  searchInput.addEventListener('focus', observeSearchInput);
+
+  form.querySelector('a.search-submit').addEventListener('click', (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    if (!BREAKPOINTS.medium.matches) {
+      syncToBar();
+    }
+    updateParameters();
+  });
+
+  form.querySelectorAll('.result-filters > .select-wrapper div.selected, .advanced-filters .misc .select-wrapper div.selected').forEach((button) => {
+    button.addEventListener('click', filterSelectClicked);
+  });
+
+  form.querySelectorAll('.select-wrapper .select-items li').forEach((li) => {
+    li.addEventListener('click', filterItemClicked);
+  });
+
+  form.querySelectorAll('.range-wrapper > div.selected').forEach((button) => {
+    button.addEventListener('click', rangeSelectClicked);
+  });
+
+  form.querySelectorAll('.range-wrapper .range-items div[id="min-price"], .range-wrapper .range-items div[id="max-price"]').forEach((price) => {
+    price.addEventListener('keyup', (e) => {
+      observePriceInput(e);
+      updatePriceLabel(price.closest('.range-wrapper'));
+    });
+  });
+
+  form.querySelectorAll('.filter-toggle').forEach((t) => {
+    t.addEventListener('click', (e) => {
+      e.preventDefault();
+      const { currentTarget } = e;
+      const ipt = currentTarget.querySelector('input');
+      ipt.checked = currentTarget.querySelector('div.checkbox').classList.toggle('checked');
+    });
+  });
+
+  form.querySelectorAll('.range-wrapper .range-items div[id="adv-min-price"], .range-wrapper .range-items div[id="adv-max-price"]').forEach((price) => {
+    price.addEventListener('keyup', observePriceInput);
+  });
+
+  form.querySelector('.listing-types').addEventListener('click', (e) => {
+    e.preventDefault();
+    const input = e.target.closest('.filter-toggle')?.querySelector('input');
+    if (input && input.value === ListingType.FOR_RENT.type) {
+      e.currentTarget.querySelector(`input[value="${ListingType.PENDING.type}"]`).closest('.filter-toggle').classList.toggle('disabled');
+    } else if (input && input.value === ListingType.PENDING.type) {
+      e.currentTarget.querySelector(`input[value="${ListingType.FOR_RENT.type}"]`).closest('.filter-toggle').classList.toggle('disabled');
+    }
+  });
+
+  form.querySelectorAll('.range-items div[id$="-sqft"] > .selected').forEach((sqft) => {
+    sqft.addEventListener('click', sqftSelectClicked);
+  });
+
+  form.querySelectorAll('.range-wrapper .range-items div[id$="-sqft"] .select-items li').forEach((li) => {
+    li.addEventListener('click', (e) => {
+      e.preventDefault();
+      updateSqftLabel(e.currentTarget.closest('.range-wrapper'));
+    });
+  });
+
+  const allTypes = form.querySelector('.property-types .all');
+  form.querySelectorAll('.property-types .options button').forEach((b) => {
+    b.addEventListener('click', (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      const exists = e.currentTarget.classList.toggle('selected');
+      if (!exists) {
+        allTypes.querySelector('input[type="checkbox"]').checked = false;
+      }
+    });
+  });
+
+  form.querySelector('.property-types .all label').addEventListener('click', (e) => {
+    if (e.currentTarget.querySelector('input').checked) {
+      e.currentTarget.closest('.property-types').querySelectorAll('.options button').forEach((b) => b.classList.add('selected'));
+    } else {
+      e.currentTarget.closest('.property-types').querySelectorAll('.options button').forEach((b) => b.classList.remove('selected'));
+    }
+  });
+
+  form.querySelector('.advanced-filters .keywords button').addEventListener('click', (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    const wrapper = e.currentTarget.closest('.keywords');
+    const input = wrapper.querySelector('.keywords-input input[type="text"]');
+    const { value } = input;
+    if (!value) {
+      return;
+    }
+    addKeyword(wrapper, value);
+    input.value = '';
+  });
+
+  form.querySelectorAll('.year-range .select-wrapper div.selected').forEach((button) => {
+    button.addEventListener('click', filterSelectClicked);
+  });
+
+  form.querySelector('.advanced-filters .open-houses .filter-toggle').addEventListener('click', (e) => {
+    const input = e.currentTarget.querySelector('input');
+    const timeframe = e.currentTarget.closest('.open-houses').querySelector('.open-houses-timeframe');
+    if (input.checked) {
+      timeframe.classList.add('visible');
+    } else {
+      timeframe.classList.remove('visible');
+    }
+  });
+
+  const filterBtn = form.querySelector('a.filter');
+  filterBtn.addEventListener('click', (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    window.scrollTo({ top: 0, behavior: 'smooth' });
+    toggleAdvancedFilters(e);
+  });
+
+  form.querySelector('a#search-apply').addEventListener('click', (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    if (!BREAKPOINTS.medium.matches) {
+      syncToBar();
+    }
+    updateParameters();
+  });
+
+  form.querySelector('a#search-cancel').addEventListener('click', (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    filterBtn.dispatchEvent(new MouseEvent('click'));
+  });
+
+  form.querySelector('a#search-reset').addEventListener('click', resetForm);
+
+  BREAKPOINTS.medium.addEventListener('change', (e) => {
+    if (e.matches) {
+      syncToBar();
+    } else {
+      syncToAdvanced();
+    }
+  });
+}
+
+buildAdvancedFilters();
+observeForm(document.querySelector('.property-search-bar.block form'));
+// Reset bar if user moves through history state.
+window.addEventListener('popstate', async () => {
+  document.querySelectorAll('.property-search-bar .open').forEach((el) => el.classList.remove('open'));
+  document.querySelectorAll('.property-search-bar .search-overlay.visible').forEach((el) => el.classList.remove('visible'));
+  document.querySelectorAll('.property-search-bar [aria-expanded="true"]').forEach((el) => el.setAttribute('aria-expanded', 'false'));
+});
diff --git a/blocks/property-search-bar/filter-processor.js b/blocks/property-search-bar/filter-processor.js
deleted file mode 100644
index caa77140..00000000
--- a/blocks/property-search-bar/filter-processor.js
+++ /dev/null
@@ -1,367 +0,0 @@
-import {
-  setParam, getParam, removeParam, getSearchObject, buildUrl,
-} from '../../scripts/search.js';
-import {
-  buildKeywordEl, formatPriceLabel,
-  TOP_LEVEL_FILTERS, EXTRA_FILTERS, BOTTOM_LEVEL_FILTERS, getConfig,
-} from './common-function.js';
-
-import {
-  propertySearch,
-} from '../../scripts/apis/creg/creg.js';
-
-import { setPropertyDetails as setResults } from '../../scripts/search/results.js';
-import SearchParameters from '../../scripts/apis/creg/SearchParameters.js';
-
-import SearchType from '../../scripts/apis/creg/SearchType.js';
-import ApplicationType from '../../scripts/apis/creg/ApplicationType.js';
-
-export function searchProperty() {
-  if (document.querySelector('.property-result-content')) {
-    document.querySelector('.property-result-content').remove();
-  }
-  if (document.querySelector('.property-result-map-container .disclaimer')) {
-    document.querySelector('.property-result-map-container .disclaimer').remove();
-  }
-  document.querySelector('.search-results-loader').style.display = 'block';
-  const overlay = document.querySelector('.search-results-loader-image');
-  overlay.classList.remove('exit');
-  overlay.classList.add('enter');
-  const type = getParam('SearchType');
-  const searchParams = getSearchObject();
-  const params = new SearchParameters(SearchType[type]);
-  const result = {
-    properties: [],
-    cont: 0,
-    disclaimer: {},
-    listingClusters: [],
-    result: {},
-  };
-  // set params from session storage
-  Object.keys(searchParams).forEach((key) => {
-    if (key === 'ApplicationType') {
-      params.applicationTypes = searchParams[key].split(',').map((propertyType) => ApplicationType[propertyType]);
-    } else if (key === 'PropertyType') {
-      params.propertyTypes = searchParams[key].split(',');
-    } else if (key === 'franchiseeCode') {
-      params.franchisee = searchParams[key];
-    } else if (key === 'Sort') {
-      params.sortBy = searchParams[key];
-    } else if (key === 'isFranchisePage') {
-      // do nothing
-    } else {
-      params[key] = searchParams[key];
-    }
-  });
-
-  propertySearch(params).then((results) => {
-    result.properties = results.properties;
-    result.count = results['@odata.count'];
-    result.disclaimer = results.disclaimer;
-    result.listingClusters = results.listingClusters;
-    result.result = results;
-    setResults(result);
-  }).catch(() => {
-    setResults(result);
-  }).finally(() => {
-    document.querySelector('.search-results-loader').style.display = 'none';
-    overlay.classList.remove('enter');
-    overlay.classList.add('exit');
-  });
-
-  // update url
-  const nextUrl = buildUrl();
-  const nextTitle = 'Property Search Results Commonwealth Real Estate | Berkshire Hathaway HomeServices';
-  const nextState = { additionalInformation: 'Updated the URL with JS' };
-  window.history.replaceState(nextState, nextTitle, nextUrl);
-}
-/**
- *
- * @param filterName
- * @param value
- * @returns {string|string|*}
- */
-export function formatValue(filterName, value) {
-  let conf; let
-    formattedValue = '';
-  switch (filterName) {
-    case 'Price':
-      formattedValue = formatPriceLabel(value.min, value.max);
-      break;
-    case 'MinBedroomsTotal':
-      formattedValue = value ? `${value}+ Beds` : 'Any Beds';
-      break;
-    case 'MinBathroomsTotal':
-      formattedValue = value ? `${value}+ Baths` : 'Any Baths';
-      break;
-    case 'LivingArea':
-      formattedValue = `${value.min}Sq Ft-${value.max} Sq Ft`;
-      if (value.min === '') {
-        formattedValue = `no min- ${value.max} Sq Ft`;
-      }
-      if (value.max === '') {
-        formattedValue = `${value.min} Sq Ft - no max`;
-      }
-      if (value.min === '' && value.max === '') {
-        formattedValue = 'square feet';
-      }
-      break;
-    case 'Sort':
-      conf = getConfig(filterName);
-      for (let i = 0; i < conf.length; i += 1) {
-        if (conf[i].value === value) {
-          formattedValue = conf[i].label;
-        }
-      }
-      break;
-    default:
-      formattedValue = value;
-  }
-  return formattedValue;
-}
-
-/**
- * Get filter value
- * @param {string} filterName
- * @returns {string}
- *
- */
-export function getValueFromStorage(filterName) {
-  let minValue = '';
-  let maxValue = '';
-  let value = '';
-  switch (filterName) {
-    case 'Price':
-    case 'LivingArea':
-      value = { min: getParam(`Min${filterName}`) ?? '', max: getParam(`Max${filterName}`) ?? '' };
-      break;
-    case 'Features':
-    case 'ApplicationType':
-    case 'PropertyType':
-      value = getParam(filterName) ? getParam(filterName).split(',') : [];
-      break;
-    case 'YearBuilt':
-      [minValue, maxValue] = (getParam('YearBuilt') || '-').split('-').map((val) => {
-        if (val === '1899') return 'No Min';
-        if (val === '2100') return 'No Max';
-        return val;
-      });
-      value = { min: minValue, max: maxValue };
-      break;
-    case 'FeaturedCompany':
-      value = getParam('FeaturedCompany') === 'BHHS';
-      break;
-    default:
-      value = getParam(filterName) ?? false;
-  }
-  return value;
-}
-
-/**
- *
- * @param {string} name
- * @param {string|obj} value
- */
-export function setFilterValue(name, value) {
-  let params;
-  let values;
-  switch (name) {
-    case 'PropertyType':
-      params = getValueFromStorage('PropertyType');
-      if (value.length === 1) {
-        params.push(value);
-        params = params.join(',');
-        setParam('PropertyType', params);
-      } else if (value.length > 1) {
-        values = value.split(',');
-        values = [...params, ...values];
-        values = [...new Set(values)];
-        values = values.join(',');
-        setParam('PropertyType', values);
-      }
-      break;
-    case 'FeaturedCompany':
-      // eslint-disable-next-line no-unused-expressions
-      value ? setParam('FeaturedCompany', 'BHHS') : removeParam('FeaturedCompany');
-      break;
-    case 'Luxury':
-    case 'RecentPriceChange':
-      // eslint-disable-next-line no-unused-expressions
-      value ? setParam(name, true) : removeParam(name);
-      break;
-    case 'Features':
-      params = getParam(name) ?? '';
-      params = params.length > 0 ? params.concat(',', value) : value;
-      values = params.split(',');
-      values = [...new Set(values)];
-      setParam(name, values.join(','));
-      break;
-    case 'ApplicationType':
-      if (value.length > 0) {
-        setParam(name, value);
-        values = value.split(',');
-        params = values.map((val) => {
-          let param;
-          if (val === ApplicationType.FOR_SALE.type
-              || val === ApplicationType.FOR_RENT.type) param = 1;
-          if (val === ApplicationType.PENDING.type) param = 2;
-          if (val === ApplicationType.RECENTLY_SOLD.type) param = 3;
-          return param;
-        });
-        const unique = [...new Set(params)];
-        setParam('ListingStatus', unique.join(','));
-      } else {
-        removeParam(name);
-        removeParam('ListingStatus');
-      }
-      break;
-    case 'MinPrice':
-    case 'MaxPrice':
-    case 'MinBedroomsTotal':
-    case 'MinBathroomsTotal':
-      // eslint-disable-next-line no-unused-expressions
-      value.length > 0 ? setParam(name, value) : removeParam(name);
-      break;
-    default:
-      setParam(name, value);
-  }
-}
-export function removeFilterValue(name, value = '') {
-  let params;
-  let paramsToArray;
-  switch (name) {
-    case 'Features':
-      params = getParam('Features') ?? '';
-      paramsToArray = params.split(',');
-      paramsToArray = paramsToArray.filter((i) => i !== value);
-      params = paramsToArray.join(',');
-      setParam('Features', params);
-      break;
-    case 'PropertyType':
-      if (value.length > 0) {
-        params = getValueFromStorage('PropertyType');
-        params = params.filter((i) => i !== value);
-        setParam('PropertyType', params.join(','));
-      } else {
-        removeParam('PropertyType');
-      }
-      break;
-    default:
-      removeParam(name);
-  }
-}
-
-export function setInitialValuesFromUrl() {
-  const url = window.location.href;
-  const queryString = url.split('?')[1];
-  if (queryString) {
-    queryString.split('&').forEach((query) => {
-      // eslint-disable-next-line prefer-const
-      let [key, value] = query.split('=');
-      value = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : '';
-      setFilterValue(key, value);
-    });
-  }
-}
-
-export function populatePreSelectedFilters(topMenu = true) {
-  let filters; let
-    el;
-  let value = '';
-  if (topMenu) {
-    filters = { ...TOP_LEVEL_FILTERS, ...BOTTOM_LEVEL_FILTERS };
-    Object.keys(filters).forEach((name) => {
-      const selector = `[name="${name}"] .title span`;
-      value = getValueFromStorage(name);
-      if (Object.keys(BOTTOM_LEVEL_FILTERS).includes(name)) {
-        if (name === 'ApplicationType') {
-          value.forEach((key) => {
-            document.querySelector(`[name="${name}"] > [name="${key}"] .checkbox`).classList.add('checked');
-          });
-        }
-        if (name === 'Sort' && value) {
-          el = document.querySelector('[name="Sort"]');
-          el.querySelector('.select-selected').innerText = formatValue(name, value);
-          el.querySelector('.highlighted').classList.toggle('highlighted');
-          el.querySelector(`[data-value="${value}"]`).classList.toggle('highlighted');
-        }
-      } else {
-        document.querySelector(selector).innerText = formatValue(name, value);
-      }
-    });
-  } else {
-    const storageKeyToName = { ...TOP_LEVEL_FILTERS, ...EXTRA_FILTERS, ...BOTTOM_LEVEL_FILTERS };
-    Object.keys(storageKeyToName).forEach((name) => {
-      value = getValueFromStorage(name);
-      let min;
-      let max;
-      let filter;
-      switch (name) {
-        case 'Price':
-          document.querySelector('.filter [name="MinPrice"]').value = value.min;
-          document.querySelector('.filter [name="MaxPrice"]').value = value.max;
-          break;
-        case 'MinBedroomsTotal':
-        case 'MinBathroomsTotal':
-          value = value || 'Any';
-          document.querySelectorAll(`[name="${name}"] input`).forEach(
-            (input) => { input.checked = (input.value === value); },
-          );
-          break;
-        case 'LivingArea':
-          document.querySelector('.filter [name="MinLivingArea"]').innerText = value.min.length > 0 ? `${value.min} Sq Ft` : 'No Min';
-          document.querySelector('.filter [name="MaxLivingArea"]').innerText = value.max.length > 0 ? `${value.max} Sq Ft` : 'No Max';
-          document.querySelectorAll('.filter [name="MinLivingArea"] ~ul li').forEach((li) => {
-            li.classList.toggle('highlighted', li.getAttribute('data-value') === value.min);
-          });
-          document.querySelectorAll('.filter [name="MaxLivingArea"] ~ul li').forEach((li) => {
-            li.classList.toggle('highlighted', li.getAttribute('data-value') === value.max);
-          });
-
-          break;
-        case 'PropertyType':
-          document.querySelectorAll('.filter[name="PropertyType"] button').forEach((button) => {
-            button.classList.toggle('selected', value.includes(button.value));
-          });
-          break;
-        case 'Features':
-          if (document.querySelector('#container-tags').childElementCount === 0) {
-            value.forEach((key) => {
-              buildKeywordEl(key, removeFilterValue);
-            });
-          }
-          break;
-        case 'YearBuilt':
-          [min, max] = [value.min !== '' ? value.min : 'No Min', value.max !== '' ? value.max : 'No Max'];
-          document.querySelectorAll('[name="YearBuilt"] .select-selected').forEach((elem, i) => {
-            elem.innerText = i === 0 ? min : max;
-          });
-          break;
-        case 'OpenHouses':
-          filter = document.querySelector('[name="OpenHouses"]');
-          filter.classList.toggle('selected', !!value);
-          filter.querySelector('input[type="checkbox"]').checked = !!value;
-          if (value) {
-            filter.querySelector(`[name="OpenHouses"] input[value="${value}"]`).checked = true;
-          }
-          break;
-        case 'MatchAnyFeatures':
-          document.querySelector('[name="matchTagsAll"]').checked = !value;
-          document.querySelector('[name="matchTagsAny"]').checked = value;
-          break;
-        case 'ApplicationType':
-          value.forEach((key) => {
-            document.querySelector(`[name="${name}"] .column [name="${key}"] .checkbox`).classList.add('checked');
-          });
-          break;
-        case 'Sort':
-        case 'Page':
-          // do nothing
-          break;
-        default:
-          document.querySelector(`.filter[name="${name}"] .checkbox`).classList.toggle('checked', value);
-          document.querySelector(`.filter[name="${name}"] input`).value = value;
-      }
-    });
-  }
-}
diff --git a/blocks/property-search-bar/filters/additional-filter-buttons-delayed.js b/blocks/property-search-bar/filters/additional-filter-buttons-delayed.js
deleted file mode 100644
index 0e7e34e6..00000000
--- a/blocks/property-search-bar/filters/additional-filter-buttons-delayed.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { togglePropertyForm } from '../common-function.js';
-import { populatePreSelectedFilters, setFilterValue, setInitialValuesFromUrl } from '../filter-processor.js';
-
-const event = new Event('onFilterChange');
-
-function addEventListeners() {
-  const block = document.querySelector('.property-search-bar.block');
-  // close form on click cancel button
-  block.querySelector('.filter-buttons a[title="cancel"]').addEventListener('click', () => {
-    togglePropertyForm();
-  });
-  // reset form on click reset button
-  block.querySelector('.filter-buttons a[title="reset"]').addEventListener('click', () => {
-    // @todo set up initial values
-    setInitialValuesFromUrl();
-    // layout fields
-    populatePreSelectedFilters(false);
-    // top menu
-    populatePreSelectedFilters();
-  });
-  // apply filters on click apply button
-  block.querySelector('.filter-buttons a[title="apply"]').addEventListener('click', (e) => {
-    e.preventDefault();
-    e.stopPropagation();
-    togglePropertyForm();
-    setFilterValue('MinPrice', document.querySelector('.filter [name="MinPrice"]').value);
-    setFilterValue('MaxPrice', document.querySelector('.filter [name="MaxPrice"]').value);
-    populatePreSelectedFilters();
-    window.dispatchEvent(event);
-  });
-}
-addEventListeners();
diff --git a/blocks/property-search-bar/filters/additional-filter-buttons.js b/blocks/property-search-bar/filters/additional-filter-buttons.js
deleted file mode 100644
index cf9eb666..00000000
--- a/blocks/property-search-bar/filters/additional-filter-buttons.js
+++ /dev/null
@@ -1,37 +0,0 @@
-function observeButtons() {
-  const script = document.createElement('script');
-  script.id = crypto.randomUUID();
-  script.type = 'text/partytown';
-  script.innerHTML = `
-    const script = document.createElement('script');
-    script.type = 'module';
-    script.src = '${window.hlx.codeBasePath}/blocks/property-search-bar/filters/additional-filter-buttons-delayed.js';
-    document.head.append(script);
-  `;
-  document.head.append(script);
-}
-
-function build() {
-  const buttons = ['cancel', 'reset'];
-  const wrapper = document.createElement('div');
-  wrapper.classList.add('filter-buttons', 'button-container', 'flex-row', 'vertical-center', 'hide');
-  let output = `
-    <a title="apply" rel="noopener" target="_blank" tabindex="" class="btn btn-primary center" role="button">
-      <span class="text-up btn-primary c-w">apply</span>
-    </a>`;
-  buttons.forEach((button) => {
-    output += `
-      <a title="${button}" rel="noopener" target="_blank" tabindex="" class="btn btn-secondary center" role="button">
-        <span class="text-up">${button}</span>
-      </a>`;
-  });
-  wrapper.innerHTML = output;
-  observeButtons();
-  return wrapper;
-}
-
-const layoutButtons = {
-  build,
-};
-
-export default layoutButtons;
diff --git a/blocks/property-search-bar/filters/additional-filters.js b/blocks/property-search-bar/filters/additional-filters.js
deleted file mode 100644
index 3e657747..00000000
--- a/blocks/property-search-bar/filters/additional-filters.js
+++ /dev/null
@@ -1,215 +0,0 @@
-import {
-  addRangeOption, EXTRA_FILTERS, formatInput, TOP_LEVEL_FILTERS,
-  getConfig, buildFilterSearchTypesElement, getFilterLabel,
-} from '../common-function.js';
-import PropertyType from '../../../scripts/apis/creg/PropertyType.js';
-import OpenHouses from '../../../scripts/apis/creg/OpenHouses.js';
-
-const SEARCH_TYPES = { ApplicationType: { label: 'Search Types', type: 'search-types' } };
-const FILTERS = { ...SEARCH_TYPES, ...TOP_LEVEL_FILTERS, ...EXTRA_FILTERS };
-
-function observeFilters() {
-  const script = document.createElement('script');
-  script.id = crypto.randomUUID();
-  script.type = 'text/partytown';
-  script.innerHTML = `
-    const script = document.createElement('script');
-    script.type = 'module';
-    script.src = '${window.hlx.codeBasePath}/blocks/property-search-bar/filters/additional-params-delayed.js';
-    document.head.append(script);
-  `;
-  document.head.append(script);
-}
-
-function buildPropertyColumn(properties = []) {
-  let output = '';
-  [...properties].forEach((property) => {
-    output += `<button type="button" class="flex-row" value=${property.ID}>
-                <svg role="presentation">
-                    <use xlink:href="/icons/icons.svg#${formatInput(property.Label)}"></use>
-                </svg>
-                <span class="ml-1">${property.Label}</span>
-            </button>`;
-  });
-  return output;
-}
-
-function buildCheckBox(ariaLabel, label = '') {
-  return `<div class=" filter-checkbox mt-1">
-        <label role="presentation" class="flex-row mb-1">
-            <input type="checkbox" aria-label="${ariaLabel}">
-            <div class="checkbox">
-                <svg role="presentation">
-                    <use xlink:href="/icons/icons.svg#checkmark"></use>
-                </svg>
-            </div>
-            <span class="label">${label}</span>
-        </label>
-    </div>`;
-}
-
-function buildPropertyFilterHtml(label) {
-  const firstColumnValues = [
-    PropertyType.CONDO_TOWNHOUSE,
-    PropertyType.COMMERCIAL,
-    PropertyType.LAND,
-  ];
-  const secondColumnValues = [
-    PropertyType.SINGLE_FAMILY,
-    PropertyType.MULTI_FAMILY,
-    PropertyType.FARM,
-  ];
-  return `
-    <div class="column-2 flex-row">
-    <div class="column">${buildPropertyColumn(firstColumnValues)}</div>
-    <div class="column">${buildPropertyColumn(secondColumnValues)}</div>
-    </div>
-    ${buildCheckBox(label, 'Select All')}
-`;
-}
-
-function buildFilterOpenHouses() {
-  return `
-    <div class="flex-row vertical-center">
-    ${buildCheckBox('Open Houses Only')}
-        <div class="ml-1 mr-1">
-            <label role="presentation" class="flex-row center">
-                <input type="radio" value=${OpenHouses.ONLY_WEEKEND.value}>
-            <div class="radio-btn"></div>
-            <span class="">${OpenHouses.ONLY_WEEKEND.label}</span>
-            </label>
-        </div>
-        <div>
-            <label role="presentation" class="flex-row vertical-center">
-            <input type="radio" value=${OpenHouses.ANYTIME.value}>
-            <div class="radio-btn"></div>
-            <span class="">${OpenHouses.ANYTIME.label}</span>
-            </label>
-        </div>
-    </div>
-`;
-}
-function buildKeywordSearch() {
-  return `
-    <div class="flex-row vertical-center container-input">
-            <input type="text" placeholder="Pool, Offices, Fireplace..." aria-label="Pool, Offices, Fireplace...">
-            <button type="submit" class="btn secondary center">
-                <span class="text-up">add</span>
-            </button>
-    </div>
-    <div id="container-tags" class="mt-1"></div>
-       <br>
-        <div class="flex-row vertical-center">
-            <label class="text-up vertical-center" role="presentation">match</label>
-            <div class="filter-radiobutton">
-                <label role="presentation" class="flex-row vertical-center ml-1 mr-1">
-                    <input type="radio" name="matchTagsAny" value="false">
-                    <div class="radio-btn"></div>
-                    <span class="fs-1">Any</span>
-                </label>
-            </div>
-            <div class="filter-radiobutton">
-                <label role="presentation" class="flex-row vertical-center">
-                    <input type="radio" name="matchTagsAll" value="true">
-                    <div class="radio-btn"></div>
-                    <span class="fs-1">All</span>
-                </label>
-            </div>
-        </div>
-</div>`;
-}
-
-function buildFilterToggle() {
-  return `
-    <div>
-       <div class="filter-toggle">
-           <input hidden="hidden" type="checkbox" aria-label="Hidden checkbox" value="true">
-           <div class="checkbox"></div>
-       </div>
-    </div>`;
-}
-
-function buildSectionFilter(filterName) {
-  const number = getConfig(filterName);
-  const defaultValue = 'Any';
-  const name = filterName.toLowerCase();
-  let output = `
-    <ul class="flex-row tile">
-    <li>
-            <input aria-describedby="${name}${defaultValue}" type="radio" id="${name}${defaultValue}" value=${defaultValue}>
-            <label for="${name}${defaultValue}">${defaultValue}</label>
-    </li>`;
-
-  for (let i = 1; i <= number; i += 1) {
-    output += `<li>
-            <input aria-describedby="${name}${i}" type="radio" id="${name}${i}" value=${i}>
-            <label for="${name}${i}">${`${i}+`}</label>
-        </li>`;
-  }
-
-  output += '</ul>';
-  return output;
-}
-
-function getOptions(name) {
-  let options = '';
-  const { type } = FILTERS[name];
-  switch (type) {
-    case 'select':
-      options = buildSectionFilter(name);
-      break;
-    case 'range':
-      options = addRangeOption(name);
-      break;
-    case 'toggle':
-      options = buildFilterToggle();
-      break;
-    case 'keywords-search':
-      options = buildKeywordSearch();
-      break;
-    case 'open-houses':
-      options = buildFilterOpenHouses();
-      break;
-    case 'property':
-      options = buildPropertyFilterHtml();
-      break;
-    case 'search-types':
-      options = buildFilterSearchTypesElement();
-      break;
-    default:
-      break;
-  }
-  return options;
-}
-
-function buildPlaceholder(filterName) {
-  const { type } = FILTERS[filterName];
-  if (type === 'child') {
-    return '';
-  }
-  const placeholder = document.createElement('div');
-  const label = getFilterLabel(filterName);
-  const options = getOptions(filterName);
-  placeholder.setAttribute('name', filterName);
-  placeholder.classList.add('filter');
-  placeholder.innerHTML = ` <label class="section-label text-up">${label}</label>
-  ${options}`;
-  return placeholder.outerHTML;
-}
-
-async function build() {
-  const wrapper = document.createElement('div');
-  let output = '';
-  Object.keys(FILTERS).forEach((filter) => { output += buildPlaceholder(filter); });
-  wrapper.classList.add('filter-block', 'hide', 'input');
-  wrapper.innerHTML = ` 
-    ${output}`;
-  observeFilters();
-  return wrapper;
-}
-
-const additionalFilters = {
-  build,
-};
-
-export default additionalFilters;
diff --git a/blocks/property-search-bar/filters/additional-params-delayed.js b/blocks/property-search-bar/filters/additional-params-delayed.js
deleted file mode 100644
index 5b8c8c22..00000000
--- a/blocks/property-search-bar/filters/additional-params-delayed.js
+++ /dev/null
@@ -1,162 +0,0 @@
-import {
-  removeFilterValue,
-  setFilterValue,
-} from '../filter-processor.js';
-import { buildKeywordEl, updateFilters } from '../common-function.js';
-import OpenHouses from '../../../scripts/apis/creg/OpenHouses.js';
-
-const event = new Event('onFilterChange');
-
-function toggleFilter(el) {
-  const div = el.querySelector('.checkbox');
-  const name = el.closest('.filter').getAttribute('name');
-  div.classList.toggle('checked');
-  let value = div.classList.contains('checked');
-  el.querySelector('input').value = value;
-  if (name === 'ApplicationType') {
-    value = [];
-    el.closest('[name="ApplicationType"]').querySelectorAll('.filter-toggle .checked').forEach((elem) => {
-      value.push(elem.parentElement.getAttribute('name'));
-    });
-    value = value.join(',');
-  }
-  setFilterValue(name, value);
-}
-
-function addEventListeners() {
-  const block = document.querySelector('.property-search-bar.block');
-  const propertyButtons = block.querySelectorAll('[name="PropertyType"] button');
-  const openHousesFilter = block.querySelector('[name="OpenHouses"]');
-  const openHousesCheckbox = openHousesFilter.querySelector('input[type="checkbox"]');
-  const keyWordSearchAny = block.querySelector('[name="Features"] .filter-radiobutton input[name="matchTagsAny"]');
-  const keyWordSearchAll = block.querySelector('[name="Features"] .filter-radiobutton input[name="matchTagsAll"]');
-  // events for filters with type toggle
-  block.querySelectorAll('.filter-toggle').forEach((el) => {
-    el.addEventListener('click', (e) => {
-      toggleFilter(el);
-      if (el.classList.contains('for-rent') || el.classList.contains('pending')) {
-        updateFilters(el);
-      }
-      if (el.parentNode.classList.contains('top-menu')) {
-        // search property if we click top level filter
-        e.preventDefault();
-        e.stopPropagation();
-        window.dispatchEvent(event);
-      }
-    });
-  });
-  // select all property filters on select all
-  block.querySelector('[name="PropertyType"] input[type="checkbox"]').addEventListener('change', () => {
-    const isChecked = block.querySelector('[name="PropertyType"] input[type="checkbox"]').checked;
-    propertyButtons.forEach((el) => {
-      el.classList.toggle('selected', isChecked);
-    });
-    if (isChecked) {
-      setFilterValue('PropertyType', '1,2,3,5,4,6');
-    } else {
-      removeFilterValue('PropertyType');
-    }
-  });
-
-  // add logic to select property type on click
-  propertyButtons.forEach((el) => {
-    let value;
-    el.addEventListener('click', () => {
-      el.classList.toggle('selected');
-      value = el.getAttribute('value');
-      // eslint-disable-next-line no-unused-expressions
-      el.classList.contains('selected') ? setFilterValue('PropertyType', value) : removeFilterValue('PropertyType', value);
-    });
-  });
-
-  openHousesCheckbox.addEventListener('change', () => {
-    openHousesFilter.classList.toggle('selected');
-    if (!openHousesCheckbox.checked) {
-      removeFilterValue('OpenHouses');
-    } else if
-    (openHousesFilter.querySelector('input[type="radio"]:checked')) {
-      setFilterValue('OpenHouses', openHousesFilter.querySelector('input[type="radio"]:checked').getAttribute('value'));
-    }
-  });
-  block.querySelectorAll('[name="OpenHouses"] input[type="radio"]').forEach((el) => {
-    el.addEventListener('change', () => {
-      if (el.checked) {
-        setFilterValue('OpenHouses', el.getAttribute('value'));
-      }
-      if (el.getAttribute('value') === '7') {
-        block.querySelector(`[name="OpenHouses"] input[value="${OpenHouses.ANYTIME.value}"]`).checked = false;
-      } else {
-        block.querySelector(`[name="OpenHouses"] input[value="${OpenHouses.ONLY_WEEKEND.value}"]`).checked = false;
-      }
-    });
-  });
-  block.querySelectorAll('#container-tags .close').forEach((el) => {
-    el.addEventListener('click', (e) => {
-      e.target.parentNode.remove();
-    });
-  });
-  keyWordSearchAny.addEventListener('change', () => {
-    if (keyWordSearchAny.checked) {
-      keyWordSearchAll.checked = false;
-      setFilterValue('MatchAnyFeatures', true);
-    }
-  });
-
-  keyWordSearchAll.addEventListener('change', () => {
-    if (keyWordSearchAll.checked) {
-      keyWordSearchAny.checked = false;
-      removeFilterValue('MatchAnyFeatures');
-    }
-  });
-  // add key words to search
-  block.querySelector('[name="Features"] .btn').addEventListener('click', () => {
-    const keyword = block.querySelector('[name="Features"] input[type="text"]').value;
-    if (keyword) {
-      buildKeywordEl(keyword, removeFilterValue);
-      setFilterValue('Features', keyword.trim());
-    }
-  });
-  // year, square feet, sort input logic on additional filters
-  block.querySelectorAll('.filter .select-item .tooltip-container').forEach((element) => {
-    element.addEventListener('click', (e) => {
-      const selectedElValue = element.innerText;
-      const container = element.closest('section');
-      const filter = element.closest('.filter');
-      let name = filter.getAttribute('name');
-      let value = element.getAttribute('data-value');
-      container.querySelector('.highlighted').classList.remove('highlighted');
-      element.classList.toggle('highlighted');
-      const headerTitle = container.querySelector('.select-selected');
-      if (name === 'Sort') {
-        headerTitle.innerText = selectedElValue;
-      } else {
-        headerTitle.innerHTML = `<span>${selectedElValue}</span>`;
-      }
-      if (filter.querySelector('.multiple-inputs')) {
-        if (name !== 'YearBuilt') {
-          name = element.closest('section > div').querySelector('.select-selected').getAttribute('name');
-        }
-        if (name === 'YearBuilt') {
-          const values = element.closest('.multiple-inputs').querySelectorAll('.select-selected');
-          if (values[0].innerText === 'No Min' && values[1].innerText === 'No Max') {
-            removeFilterValue('YearBuilt');
-            return;
-          }
-          const minYear = values[0].innerText === 'No Min' ? 1899 : values[0].innerText;
-          const maxYear = values[1].innerText === 'No Max' ? 2100 : values[1].innerText;
-          value = `${minYear}-${maxYear}`;
-        }
-        element.closest('.select-item').classList.remove('show');
-      }
-      setFilterValue(name, value);
-      if (name === 'Sort') {
-        e.stopPropagation();
-        e.preventDefault();
-        window.dispatchEvent(event);
-      }
-      element.closest('.select-item').classList.remove('show');
-    });
-  });
-}
-
-addEventListeners();
diff --git a/blocks/property-search-bar/filters/top-delayed.js b/blocks/property-search-bar/filters/top-delayed.js
deleted file mode 100644
index 8973e943..00000000
--- a/blocks/property-search-bar/filters/top-delayed.js
+++ /dev/null
@@ -1,232 +0,0 @@
-import { abortSuggestions, getSuggestions } from '../../../scripts/apis/creg/creg.js';
-import { getAttributes, setSearchParams } from '../search/suggestion.js';
-import {
-  populatePreSelectedFilters,
-  setFilterValue,
-} from '../filter-processor.js';
-import {
-  formatPriceLabel, closeTopLevelFilters, togglePropertyForm, hideFilter,
-} from '../common-function.js';
-import { getPropertiesCount } from '../../../scripts/search/results.js';
-
-const event = new Event('onFilterChange');
-
-const MORE_INPUT_NEEDED = 'Please enter at least 3 characters.';
-const NO_SUGGESTIONS = 'No suggestions found. Please modify your search.';
-const SEARCHING_SUGGESTIONS = 'Looking up suggestions...';
-
-function showFilter(element) {
-  element.classList.add('open');
-  element.querySelector('.search-results-dropdown').classList.remove('hide');
-}
-
-const updateSuggestions = (suggestions, target) => {
-  // Keep the first item - required character entry count.
-  const first = target.querySelector(':scope li');
-  target.replaceChildren(first, ...suggestions);
-};
-
-const createPriceList = (d) => {
-  let optionlist = '';
-  const k = [10, 100, 1E3, 1E4, 1E5, 1E6];
-  // eslint-disable-next-line no-plusplus
-  if (d) for (let m = 1; m <= 6; m++) optionlist += `<option> ${d * k[m - 1]} </option>`;
-  return optionlist;
-};
-
-function addChangeHandler(filter) {
-  let value;
-  filter.forEach((el) => {
-    el.addEventListener('change', () => {
-      if (el.checked) {
-        filter.forEach((input) => {
-          if (input.id !== el.id) input.checked = false;
-        });
-        value = el.value === 'Any' ? '' : el.value;
-        setFilterValue(el.closest('.filter').getAttribute('name'), value);
-      }
-    });
-  });
-}
-
-const buildSuggestions = (suggestions) => {
-  const lists = [];
-  let attr;
-  suggestions.forEach((category) => {
-    const list = document.createElement('li');
-    list.classList.add('list-title');
-    list.textContent = category.displayText;
-    lists.push(list);
-    const ul = document.createElement('ul');
-    list.append(ul);
-    category.results.forEach((result) => {
-      const li = document.createElement('li');
-      attr = getAttributes(result);
-      Object.keys(attr).forEach((key) => {
-        li.setAttribute(key, attr[key]);
-      });
-      li.textContent = result.SearchParameter;
-      ul.append(li);
-    });
-  });
-
-  return lists;
-};
-
-/**
- * Handles the input changed event for the text field. Will add suggestions based on user input.
- *
- * @param {Event} e the change event
- * @param {HTMLElement} target the container in which to add suggestions
- */
-const inputChanged = (e, target) => {
-  const { value } = e.currentTarget;
-  if (value.length > 0) {
-    e.currentTarget.closest('.search-bar').classList.add('show-suggestions');
-  } else {
-    e.currentTarget.closest('.search-bar').classList.remove('show-suggestions');
-  }
-
-  if (value.length <= 2) {
-    abortSuggestions();
-    target.querySelector(':scope > li:first-of-type').textContent = MORE_INPUT_NEEDED;
-    updateSuggestions([], target);
-  } else {
-    target.querySelector(':scope > li:first-of-type').textContent = SEARCHING_SUGGESTIONS;
-    getSuggestions(value)
-      .then((suggestions) => {
-        if (!suggestions) {
-          // Undefined suggestions means it was aborted, more input coming.
-          updateSuggestions([], target);
-          return;
-        }
-        if (suggestions.length) {
-          updateSuggestions(buildSuggestions(suggestions), target);
-        } else {
-          target.querySelector(':scope > li:first-of-type').textContent = NO_SUGGESTIONS;
-        }
-      });
-  }
-};
-
-const suggestionSelected = (e, block) => {
-  e.stopPropagation();
-  e.preventDefault();
-  const searchParameter = e.target.getAttribute('search-parameter');
-  const keyword = e.target.getAttribute('search-input');
-  if (!searchParameter) {
-    return;
-  }
-  setSearchParams(e.target);
-  block.querySelector('input[name="keyword"]').value = keyword;
-  block.querySelector('.search-bar').classList.remove('show-suggestions');
-
-  window.dispatchEvent(event);
-};
-
-function addEventListeners() {
-  const block = document.querySelector('.property-search-bar.block');
-  const priceRangeInputs = block.querySelector('.container-item[name="Price"] .multiple-inputs');
-
-  // update top menu  input placeholder on click
-  block.querySelectorAll('.container-item .select-item .tooltip-container').forEach((element) => {
-    element.addEventListener('click', () => {
-      let selectedElValue = element.innerText;
-      const value = element.getAttribute('data-value');
-      const container = element.closest('.container-item');
-      let name = container.getAttribute('name');
-      container.querySelector('.highlighted').classList.remove('highlighted');
-      element.classList.toggle('highlighted');
-      const headerTitle = container.querySelector('.header .title');
-      if (container.querySelector('.multiple-inputs')) {
-        // logic
-        element.closest('section > div').querySelector('.select-selected').innerHTML = selectedElValue;
-        name = element.closest('section > div').querySelector('.select-selected').getAttribute('name');
-        const headerItems = container.querySelectorAll('.multiple-inputs .select-selected');
-        const fromSelectedValue = headerItems[0].innerText;
-        const toSelectedValue = headerItems[1].innerText;
-        if (fromSelectedValue === 'No Min' && toSelectedValue === 'No Max') {
-          selectedElValue = 'square feet';
-        } else {
-          selectedElValue = `${fromSelectedValue}-${toSelectedValue}`;
-        }
-        element.closest('.select-item').classList.remove('show');
-      } else {
-        hideFilter(container);
-      }
-      setFilterValue(name, value);
-      headerTitle.innerHTML = `<span>${selectedElValue}</span>`;
-      window.dispatchEvent(event);
-    });
-  });
-
-  // add logic on price range change
-  priceRangeInputs.addEventListener('keyup', (e) => {
-    const minPrice = priceRangeInputs.querySelector('[name="MinPrice"]').value;
-    const maxPrice = priceRangeInputs.querySelector('[name="MaxPrice"]').value;
-    // display datalist
-    const activeElement = e.target.closest('.price-range-input');
-    const name = activeElement.getAttribute('name');
-    const { value } = activeElement;
-    activeElement.list.innerHTML = createPriceList(activeElement.value);
-
-    // update label
-    block.querySelector('[name="Price"] .title > span').innerText = formatPriceLabel(minPrice, maxPrice);
-    setFilterValue(name, value);
-    window.dispatchEvent(event);
-  });
-
-  block.querySelectorAll('.container-item .header').forEach((selectedFilter) => {
-    selectedFilter.addEventListener('click', () => {
-      const isOpened = selectedFilter.parentElement.classList.contains('open');
-      closeTopLevelFilters();
-      if (!isOpened) {
-        showFilter(selectedFilter.parentElement);
-      }
-    });
-  });
-  // baths and beds
-  addChangeHandler(block.querySelectorAll('[name="MinBathroomsTotal"] input'));
-  addChangeHandler(block.querySelectorAll('[name="MinBedroomsTotal"] input'));
-
-  // open additional filters
-  block.querySelector('.filter-container').addEventListener('click', () => {
-    togglePropertyForm();
-    const overlay = document.querySelector('.property-search-bar.block .overlay');
-    const toggledOnClose = overlay.classList.contains('hide');
-    closeTopLevelFilters(false);
-    if (toggledOnClose) {
-      setFilterValue('MinPrice', document.querySelector('.filter [name="MinPrice"]').value);
-      setFilterValue('MaxPrice', document.querySelector('.filter [name="MaxPrice"]').value);
-    }
-    populatePreSelectedFilters(toggledOnClose);
-  });
-
-  block.querySelectorAll('.select-selected').forEach((el) => {
-    let isOpened;
-    el.addEventListener('click', () => {
-      if (el.closest('.multiple-inputs').getAttribute('name') === 'Sort') {
-        isOpened = document.querySelector('[name="Sort"] .select-item').classList.contains('show');
-        closeTopLevelFilters();
-        if (isOpened) {
-          document.querySelector('[name="Sort"] .select-item').classList.add('show');
-        }
-      }
-      el.closest('section > div').querySelector('.select-item').classList.toggle('show');
-    });
-  });
-  // suggestions
-  const suggestionsTarget = block.querySelector('.suggester-input .suggester-results');
-  block.querySelector('.search-listing-block  [name="keyword"]').addEventListener('input', (e) => {
-    inputChanged(e, suggestionsTarget);
-  });
-  suggestionsTarget.addEventListener('click', (e) => {
-    suggestionSelected(e, block);
-  });
-  window.addEventListener('onResultUpdated', () => {
-    const count = getPropertiesCount();
-    block.querySelector('.total-results > div').textContent = `Showing ${count} of ${count} Properties`;
-  });
-}
-
-addEventListeners();
diff --git a/blocks/property-search-bar/filters/top-menu.js b/blocks/property-search-bar/filters/top-menu.js
deleted file mode 100644
index 6ee162a1..00000000
--- a/blocks/property-search-bar/filters/top-menu.js
+++ /dev/null
@@ -1,168 +0,0 @@
-import {
-  getPlaceholder,
-  addRangeOption,
-  addOptions,
-  TOP_LEVEL_FILTERS,
-  getConfig,
-  processSearchType,
-  getFilterLabel,
-} from '../common-function.js';
-
-function observeFilters() {
-  const script = document.createElement('script');
-  script.id = crypto.randomUUID();
-  script.type = 'text/partytown';
-  script.innerHTML = `
-    const script = document.createElement('script');
-    script.type = 'module';
-    script.src = '${window.hlx.codeBasePath}/blocks/property-search-bar/filters/top-delayed.js';
-    document.head.append(script);
-  `;
-  document.head.append(script);
-}
-
-function buildTotalResults() {
-  const wrapper = document.createElement('div');
-  wrapper.classList.add('total-results');
-  wrapper.innerHTML = '<div role="heading" aria-level="1"/>';
-  return wrapper;
-}
-
-function buildMapToggle() {
-  const wrapper = document.createElement('div');
-  wrapper.classList.add('map-toggle', 'flex-row', 'center');
-  wrapper.innerHTML = `
-            <a rel="noopener" target="_blank" tabindex="" class="btn btn-map-toggle" role="button">
-            <span class="text-up">
-            grid view
-        </span></a>`;
-  return wrapper;
-}
-
-function buildButton(label, primary = false) {
-  const button = document.createElement('div');
-  button.classList.add('button-container');
-  button.innerHTML = `
-    <a target="_blank" tabindex="" class="btn center ${primary ? 'btn-primary' : 'btn-secondary'}" role="button">
-            <span>${label}</span>
-    </a>`;
-  return button;
-}
-
-function buildFilterToggle() {
-  const wrapper = document.createElement('div');
-  wrapper.setAttribute('name', 'AdditionalFilters');
-  wrapper.classList.add('filter-container', 'flex-row', 'center', 'bl');
-  wrapper.innerHTML = `
-            <a role="button" aria-label="Filter">
-                <svg role="presentation">
-                    <use xlink:href="/icons/icons.svg#filter-white"></use>
-                </svg>
-                <svg role="presentation" class="hide">
-                <use xlink:href="/icons/icons.svg#close-x-white"></use></svg>
-            </a>`;
-  return wrapper;
-}
-
-function buildSortByEl() {
-  const filterName = 'Sort';
-  const label = getFilterLabel(filterName);
-  const defaultValue = 'Price (Hi-Lo)';
-  const options = addOptions(filterName, defaultValue, 'multi', filterName);
-  const dropdownContainer = document.createElement('div');
-  dropdownContainer.classList.add('flex-row', 'multiple-inputs', 'filter');
-  dropdownContainer.setAttribute('name', filterName);
-  dropdownContainer.innerHTML = `<div class="header">
-             <div class="title mr-1"><span>${label}</span></div>
-             </div>
-       <div class="search-results-dropdown">${options}</div>`;
-  dropdownContainer.querySelector('.select-selected').classList.add('text-up');
-  dropdownContainer.querySelectorAll('.select-item li').forEach((el) => {
-    el.classList.add('text-up');
-    if (el.getAttribute('data-value') === '') {
-      el.remove();
-    }
-    if (el.innerText === defaultValue) {
-      el.classList.add('highlighted');
-    }
-  });
-  return dropdownContainer;
-}
-
-function buildTopFilterPlaceholder(filterName) {
-  const dropdownContainer = document.createElement('div');
-  const { type } = TOP_LEVEL_FILTERS[filterName];
-  let label = getFilterLabel(filterName);
-  let options = addRangeOption(filterName);
-  if (type === 'select') {
-    options = addOptions(filterName, `Any ${label}`);
-    label = `Any ${label}`;
-  }
-  dropdownContainer.classList.add('bl', 'container-item');
-  dropdownContainer.setAttribute('name', filterName);
-  dropdownContainer.innerHTML = `<div class="header">
-             <div class="title text-up"><span>${label}</span></div>
-             </div>
-       <div class="search-results-dropdown input hide shadow">${options}</div>`;
-
-  return dropdownContainer;
-}
-function buildFilterSearchTypesElement() {
-  const wrapper = document.createElement('div');
-  let el;
-  wrapper.classList.add('filter', 'flex-row', 'center', 'top-menu');
-  wrapper.setAttribute('name', 'ApplicationType');
-  getConfig('ApplicationType').forEach((value) => {
-    el = processSearchType(value);
-    el.classList.add('center', 'ml-1');
-    el.querySelector('label').classList.add('fs-xs');
-    wrapper.append(el);
-  });
-  return wrapper;
-}
-
-async function build() {
-  const wrapper = document.createElement('div');
-  const container = document.createElement('div');
-  const div = document.createElement('div');
-  const bfContainer = document.createElement('div');
-  const bfRightSection = document.createElement('div');
-  const filterContainer = document.createElement('div');
-  filterContainer.classList.add('result-filters', 'flex-row');
-  bfRightSection.classList.add('flex-row', 'space-between');
-  bfContainer.classList.add('bf-container');
-  container.classList.add('search-listing-container', 'flex-row');
-  wrapper.classList.add('search-listing-block');
-
-  const primaryFilters = document.createElement('div');
-  primaryFilters.classList.add('primary-search', 'flex-row');
-  primaryFilters.innerHTML = `    <div class="search-bar search-bar" role="search">
-      <div class="search-suggester suggester-input">
-          <input type="text" placeholder="${getPlaceholder('US')}" aria-label="${getPlaceholder('US')}" name="keyword">
-          <input type="hidden" name="query">
-          <input type="hidden" name="type">
-          <ul class="suggester-results">
-            <li class="list-title">Please enter at least 3 characters.</li>
-          </ul>
-        </div>
-      </div>`;
-  wrapper.prepend(primaryFilters, buildButton('Search', true));
-  Object.keys(TOP_LEVEL_FILTERS).forEach((filter) => {
-    const filterElement = buildTopFilterPlaceholder(filter);
-    wrapper.append(filterElement);
-  });
-  wrapper.append(buildFilterToggle(), buildButton('save search', true));
-  div.append(wrapper);
-  bfRightSection.append(buildSortByEl(), buildMapToggle());
-  bfContainer.append(buildFilterSearchTypesElement(), bfRightSection);
-  filterContainer.append(buildTotalResults(), bfContainer);
-  container.append(div, filterContainer);
-  observeFilters();
-  return container;
-}
-
-const topMenu = {
-  build,
-};
-
-export default topMenu;
diff --git a/blocks/property-search-bar/property-search-bar.css b/blocks/property-search-bar/property-search-bar.css
index 30f82d71..d00c5d1b 100644
--- a/blocks/property-search-bar/property-search-bar.css
+++ b/blocks/property-search-bar/property-search-bar.css
@@ -1,1017 +1,958 @@
-@import url('./search-results-dropdown.css');
+/* stylelint-disable no-descending-specificity */
 
+/** Override global settings **/
 main .section.property-search-bar-container {
-    max-width: 100vw;
-    padding: 0;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-}
-
-.property-search-template .section.property-search-bar-container {
-    margin-bottom: 0;
-    position: sticky;
-    top: 65px;
-    z-index: 10;
-    background: white;
+  max-width: 100vw;
+  padding: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin: 0;
 }
 
-.property-search-template header {
-    position: sticky;
-    top: 0;
-    background: white;
-    z-index: 11;
+main .section.property-search-bar-container .property-search-bar-wrapper {
+  padding: 0;
 }
 
-.property-search-template footer {
-    background-color: var(--light-grey);
-    border-top: 1px solid var(--platinum);
-    position: relative;
-    z-index: 4;
-}
+/** End overrides **/
 
 .property-search-bar.block {
-    width: 100vw;
+  width: 100vw;
+  background-color: var(--primary-color);
 }
 
-main .section .property-search-bar .mb-1 {
-    margin-bottom: 1em;
+.property-search-bar.block .search-form-wrapper form {
+  position: relative;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+  height: 50px;
+  padding: 0 15px;
+  margin: 0 auto;
+  max-width: 1500px;
 }
 
-main .section .property-search-bar .mt-1 {
-    margin-top: 1em;
+.property-search-bar.block .search-form-wrapper span.icon {
+  height: 20px;
+  width: 20px;
 }
 
-main .section .property-search-bar .ml-1 {
-    margin-left: 1em;
+.property-search-bar.block .search-form-wrapper span.icon > img {
+  height: 100%;
+  width: 100%;
+  filter: brightness(0) invert(1);
 }
 
-main .section .property-search-bar .mr-1 {
-    margin-right: 1em;
+.property-search-bar.block form .search-bar {
+  position: relative;
+  flex-grow: 1;
+  max-width: 550px;
 }
 
-main .section .property-search-bar .fs-1 {
-    font-size: var(--body-font-size-s)
+.property-search-bar.block .search-bar input[name="keyword"] {
+  padding: 10px;
+  border: 1px solid var(--grey);
+  height: 36px;
+  width: 100%;
+  background-color: rgba(194 153 175 / 30%);
+  color: var(--primary-light);
+  letter-spacing: normal;
+  font-size: var(--body-font-size-s);
 }
 
-main .section .property-search-bar .c-w {
-    color:var(--white);
+.property-search-bar.block .search-bar input[name="keyword"]::placeholder {
+  color: var(--primary-light);
 }
 
-main .section .property-search-bar .center {
-    text-align: center;
+.property-search-bar.block .search-bar input[name="keyword"]:focus {
+  color: var(--body-color);
+  background-color: var(--white);
 }
 
-main .section .property-search-bar .bl {
-    border-left: 1px solid var(--black);
+.property-search-bar.block form .result-filters {
+  display: flex;
+  align-items: center;
 }
 
-main .section .property-search-bar .fs-xs {
-    font-size: var(--body-font-size-xs);
+.property-search-bar.block form .result-filters .selected span {
+  color: var(--white);
 }
 
-main .section .property-search-bar .flex-column {
-    display: flex;
-    flex-direction: column;
-}
 
-main .section .property-search-bar .flex-row {
-    display: flex;
-    flex-direction: row;
+.property-search-bar.block .result-filters .range-wrapper,
+.property-search-bar.block .result-filters .select-wrapper {
+  display: none;
+  position: relative;
+  align-items: center;
+  margin: 0;
+  padding: 0 15px;
+  height: 50px;
+  text-overflow: ellipsis;
+  border-left: 1px solid var(--black);
 }
 
-main .section .property-search-bar .flex-row.center {
-    justify-content: center;
-    align-items: center
+.property-search-bar.block .result-filters .range-wrapper:last-of-type {
+  border-right: 1px solid var(--black);
 }
 
-main .section .property-search-bar .flex-row.vertical-center {
-    align-items: center;
-}
 
-main .section .property-search-bar .flex-row.space-between {
-    justify-content: space-between;
+.property-search-bar.block .result-filters .range-wrapper .select-wrapper {
+  border: none;
+  padding: 0;
+  height: 45px;
 }
 
-.property-search-bar.block .search-listing-container {
-    justify-content: flex-start;
-    flex-wrap: wrap;
-
+.property-search-bar.block .result-filters .select-wrapper select,
+.property-search-bar.block .advanced-filters .misc .select-wrapper select {
+  display: none;
 }
 
-.property-search-bar.block .total-results {
-    flex-basis: 100%;
-    max-width: var(--normal-page-width);
-    padding: 20px 0 0 30px;
-    color: var(--body-color);
-    font-size: var(--body-font-size-s);
+.property-search-bar.block .result-filters .range-wrapper > .selected,
+.property-search-bar.block .result-filters .select-wrapper > .selected {
+  display: flex;
+  position: relative;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  height: 100%;
+  min-width: 100px;
+  line-height: 40px;
+  color: var(--white);
 }
 
-main .section .property-search-bar .overlay {
-    position: absolute;
-    overflow-y: auto;
-    left: 0;
-    top: 50px;
-    width: 100vw;
-    height: 100vh;
-    background-color: #212529;
-    opacity: .5;
-    z-index: 998;
+.property-search-bar.block .result-filters .range-wrapper .select-wrapper > .selected {
+  padding: 0 15px;
+  width: 140px;
+  height: 45px;
+  color: var(--body-color);
+  border: 1px solid var(--platinum);
 }
 
-main .section .property-search-bar .hide {
-    display: none;
+.property-search-bar.block .result-filters .range-wrapper > .selected span,
+.property-search-bar.block .result-filters .select-wrapper > .selected span {
+  display: block;
+  font-size: var(--body-font-size-xs);
+  font-weight: var(--font-weight-semibold);
+  letter-spacing: unset;
+  line-height: normal;
+  text-transform: uppercase;
 }
 
-main .section .property-search-bar .button-container {
-    margin: 0 15px 0 8px;
+.property-search-bar.block .result-filters .range-wrapper .select-wrapper > .selected span {
+  text-transform: none;
 }
 
-.property-search-bar.block .container-item *,
-.property-search-bar.block .filter-block * ,
-.property-search-bar.block .filter-buttons * {
-    font-size: var(--body-font-size-s);
+.property-search-bar.block .result-filters .range-wrapper > .selected::after,
+.property-search-bar.block .result-filters .select-wrapper > .selected::after {
+  display: block;
+  content: '\f0d7';
+  font-family: var(--font-family-fontawesome);
+  text-align: right;
+  width: 25px;
 }
 
-.property-search-bar.block .search-listing-block .button-container * {
-    font-size: var(--body-font-size-xs);
+.property-search-bar.block .result-filters .range.open > .selected::after,
+.property-search-bar.block .result-filters .select-wrapper.open > .selected::after {
+  content: '\f0d8';
 }
 
-.property-search-bar.block .filter-container li,
-.property-search-bar.block .filter-container input,
-.property-search-bar.block .filter-container label,
-.property-search-bar.block .filter-container a,
-.property-search-bar.block .filter-container svg{
-    cursor: pointer;
+.property-search-bar.block .result-filters .range-wrapper .range-items,
+.property-search-bar.block .result-filters .select-wrapper .select-items {
+  display: none;
+  position: absolute;
+  top: 100%;
+  left: 0;
+  padding: 10px;
+  background-color: var(--white);
+  z-index: 501;
+  box-shadow: 0 .5rem 1rem rgba(0 0 0 / 15%);
 }
 
-.property-search-bar.block .result-filters {
-    flex-wrap: wrap;
-    width: 100%;
+.property-search-bar.block .result-filters .range-wrapper .select-wrapper .select-items {
+  padding: 0;
+  max-height: 185px;
+  overflow-y: scroll;
+  width: 100%;
+  border: 1px solid var(--platinum);
 }
 
-.property-search-bar.block .bf-container {
-    display: flex;
-    flex-basis: 100%;
-    max-width: var(--normal-page-width);
-    justify-content: flex-end;
+.property-search-bar.block .result-filters .range-wrapper:first-of-type .range-items {
+  left: 0;
+  right: unset;
 }
 
-.property-search-bar.block .result-filters >div:last-of-type {
-    width: 100%;
+.property-search-bar.block .result-filters .range-wrapper .range-items {
+  left: unset;
+  right: 0;
+  color: var(--body-color);
 }
 
-.property-search-bar.block .filter-container a {
-    display: block;
-    width: 35px;
-    height: 35px;
-    position: relative;
+.property-search-bar.block .result-filters .select-wrapper.open .select-items {
+  display: block;
 }
 
-main .section .property-search-bar .button-container a {
-    text-transform: uppercase;
+.property-search-bar.block .result-filters .select-wrapper .select-items li {
+  display: flex;
+  font-size: var(--body-font-size-s);
+  padding: 4px 15px;
+  line-height: 30px;
+  cursor: pointer;
+  border-left: 1px solid var(--platinum);
+  border-right: 1px solid var(--platinum);
 }
 
-.property-search-bar.block .property-search-bar-wrapper {
-    width: 100%;
+.property-search-bar.block .result-filters .range-wrapper .select-wrapper .select-items li {
+  border: none;
+  padding: 4px 8px;
 }
 
-.property-search-bar.block .search-listing-block {
-    padding: 0 15px;
-    text-align: center;
-    display: flex;
-    height: 50px;
-    width: 100vw;
-    background-color: var(--primary-color);
-    color: var(--white);
-    align-items: center;
-    cursor: pointer;
-    justify-content: flex-start;
+.property-search-bar.block .result-filters > .select-wrapper .select-items li:first-of-type {
+  border-top: 1px solid var(--platinum);
 }
 
-.property-search-bar.block .search-listing-block span{
-    color: var(--white);
+.property-search-bar.block .result-filters > .select-wrapper .select-items li:last-of-type {
+  border-bottom: 1px solid var(--platinum);
 }
 
-.property-search-bar.block .search-listing-container > div:first-of-type {
-    width: 100%;
-    justify-content: flex-start;
+.property-search-bar.block .result-filters .select-wrapper .select-items li:hover {
+  color: var(--body-color);
+  background-color: var(--light-grey);
 }
 
-.property-search-bar.block [name="ApplicationType"] {
-    padding: 0 20px;
+.property-search-bar.block .result-filters .select-wrapper .select-items li.selected {
+  color: var(--body-color);
+  background-color: var(--light-grey);
 }
 
-.property-search-bar.block .result-filters [name="ApplicationType"] {
-    display: none
+.property-search-bar.block .result-filters .range-wrapper.open .range-items {
+  display: flex;
+  align-items: center;
 }
 
-.property-search-bar.block .result-filters .map-toggle {
-    display: none
+.property-search-bar.block .result-filters .range-wrapper .range-items .input-dropdown select {
+  display: none;
+  visibility: hidden;
 }
 
-.property-search-bar.block .filter {
-    padding: 20px;
+.property-search-bar.block .result-filters .range-wrapper .range-items .input-dropdown input {
+  padding: 10px;
+  height: 45px;
+  width: 115px;
+  font-size: var(--body-font-size-s);
+  letter-spacing: normal;
+  border: 1px solid var(--platinum);
 }
 
-.property-search-bar.block .container-item .header {
-    position: relative;
-    display: flex;
-    justify-content: center;
-
+.property-search-bar.block .result-filters .range-wrapper .range-items > span {
+  text-align: center;
+  margin: 0 16px;
+  text-transform: uppercase;
+  font-weight: var(--font-weight-light);
 }
 
-main .section .property-search-bar .title {
-    font-size: var(--body-font-size-s);
-    white-space: pre;
-    line-height: 50px;
-    position: relative;
-}
-
-/* arrow near dropdown start */
-main .section .property-search-bar .title::after {
-    display: inline;
-    position: absolute;
-    right: -20px;
-    width: 10px;
-    content: '\f0d7';
-    font-family: var(--font-family-fontawesome);
-    height: unset;
-    color: var(--white);
+.property-search-bar.block .result-filters a.filter {
+  display: flex;
+  margin: 0 8px;
+  height: 35px;
+  width: 35px;
+  align-items: center;
+  justify-content: center;
 }
 
-main .section .property-search-bar .open .title::after {
-    content: '\f0d8';
+.property-search-bar.block .result-filters a.filter span.icon-close-x-white,
+.property-search-bar.block .result-filters a.filter.open span.icon-filter-white {
+  display: none;
 }
 
-/* end */
-
-.property-search-bar.block .filter-buttons {
-    padding: 15px;
-    justify-content: center;
-    box-shadow: 0 0 4px 0 rgb(0 0 0 / 50%);
-    width: 100vw;
-    position: fixed;
-    bottom: 0;
-    left: 0;
-    background-color: var(--white);
-    height: 64px;
-    margin: 0;
-    z-index: 1000;
+.property-search-bar.block .result-filters a.filter span.icon-filter-white,
+.property-search-bar.block .result-filters a.filter.open span.icon-close-x-white {
+  display: block;
 }
 
-.property-search-bar.block .btn-map-toggle > span {
-    display: block;
-    font-size: var(--body-font-size-xs);
-    height: 35px;
-    background: var(--white);
-    color: var(--body-color);
-    border: 1px solid var(--grey);
-    padding: 0 10px;
-    line-height: 35px;
+.property-search-bar.block form a.save-search {
+  display: none;
 }
 
-main .section .property-search-bar .btn.btn-secondary {
-    background: #fff;
-    color: var(--black);
-    border: 1px solid var(--black);
-}
 
-main .section .property-search-bar .btn.btn-primary   {
-    background: var(--primary-color);
-    color: var(--white);
-    border: 1px solid var(--grey);
-    min-width: 70px;
-    padding: 10px;
-    font-size: var(--body-font-size-xs);
-    white-space: nowrap;
+.property-search-bar.block form a.search-submit {
+  height: 36px;
+  width: 36px;
+  padding: 7px;
+  color: var(--body-color);
+  border: 1px solid var(--grey);
+  background-color: transparent;
 }
 
-main .section .property-search-bar .filter-buttons .btn,
-.property-search-bar.block [name="Features"] button{
-    padding: 7px 25px;
-    margin-right: 10px;
-    vertical-align: middle;
+.property-search-bar.block .advanced-filters {
+  display: none;
+  position: absolute;
+  top: 100%;
+  left: 0;
+  right: 0;
+  height: calc(100vh - var(--nav-height) - 50px);
+  overflow-y: scroll;
+  z-index: 500;
+  background-color: var(--white);
 }
 
-main .section .property-search-bar .title span {
-    position: relative;
-    letter-spacing: var(--letter-spacing-s);
+.property-search-bar.block .advanced-filters.open {
+  display: block;
 }
 
-main .section .property-search-bar .btn.btn-secondary:hover {
-    color: var(--black);
-    border: 1px solid var(--grey);
-    box-shadow: none;
+.property-search-bar.block .advanced-filters > div {
+  padding: 20px;
+  border-bottom: 1px solid var(--grey);
 }
 
-.property-search-bar.block [name="Features"] button {
-    background: var(--white);
-    border: 1px solid var(--grey);
+.property-search-bar.block .advanced-filters .listing-types {
+  display: flex;
+  flex-wrap: wrap;
 }
 
-.property-search-bar.block [name="Sort"] .title span {
-    font-size: var(--body-font-size-s);
-    letter-spacing: normal;
+.property-search-bar.block .advanced-filters .listing-types > label {
+  flex-basis: 100%;
 }
 
-.property-search-bar.block .filter-buttons .btn-primary:hover,
-.property-search-bar.block .filter-buttons .btn-primary span:hover {
-    background-color: var(--white);
-    color: var(--body-color);
+.property-search-bar.block .advanced-filters .listing-types > div {
+  flex-basis: 50%;
 }
 
-.property-search-bar.block .input-container input {
-    padding: 10px;
-    border: 1px solid var(--grey);
-    letter-spacing: normal;
-    height: 36px;
-    background-color: rgb(241 241 241 / 10%);
-    width: 100%;
-}
 
-.property-search-bar.block .input-dropdown input {
-    width: 100%;
-    height: 55px;
-    padding: 10px;
-    border: 1px solid var(--grey);
-    color: var(--black);
+.property-search-bar.block .advanced-filters .attributes > div:not(:last-of-type) {
+  margin-bottom: 1.5rem;
 }
 
 
-.property-search-bar.block .filter-block input,
-.property-search-bar.block .filter-block input::placeholder,
-.property-search-bar.block .filter-block .select-selected {
-    font-weight: 300;
-    font-size: var(--body-font-size-m);
-    color: var(--input-placeholder);
-    letter-spacing: normal;
+.property-search-bar.block .advanced-filters .select-wrapper {
+  position: relative;
 }
 
-.property-search-bar.block input:focus {
-    background: var(--white);
-    color: var(--body-color);
-    outline: none;
+.property-search-bar.block .advanced-filters .select-wrapper > .selected {
+  display: flex;
+  position: relative;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  height: 100%;
+  min-width: 100px;
+  line-height: 40px;
+  color: var(--white);
 }
 
-.property-search-bar.block .search-bar input:first-of-type {
-    padding: 10px;
-    border: 1px solid var(--grey);
-    letter-spacing: normal;
-    height: 36px;
-    background-color: rgb(241 241 241 / 10%);
-    width: 100%;
-    color: var(--white);
+.property-search-bar.block .advanced-filters .attributes .select-wrapper > .selected,
+.property-search-bar.block .advanced-filters .misc .select-wrapper > .selected {
+  padding: 0 15px;
+  height: 45px;
+  color: var(--body-color);
+  border: 1px solid var(--platinum);
 }
 
-.property-search-bar.block .filter .multiple-inputs .input-dropdown,
-.property-search-bar.block .filter .multiple-inputs section{
-    flex: 0 0 41.6667%;
-    max-width: 41.6667%;
+.property-search-bar.block .advanced-filters .attributes .select-wrapper > .selected span,
+.property-search-bar.block .advanced-filters .misc .select-wrapper > .selected span {
+  overflow: hidden;
+  font-size: var(--body-font-size-s);
+  font-weight: var(--font-weight-light);
+  line-height: var(--line-height-xs);
 }
 
-.property-search-bar.block .multiple-inputs .range-label {
-    margin: 0 1rem;
-    color: var(--body-color);
-    font-weight: 300;
-    font-size: 15px;
-    letter-spacing: var(--letter-spacing-xxs);
+.property-search-bar.block .advanced-filters .select-wrapper > .selected::after {
+  display: block;
+  content: '\f0d7';
+  font-family: var(--font-family-fontawesome);
+  text-align: right;
+  width: 15px;
 }
 
-.property-search-bar.block .filter .multiple-inputs .range-label {
-    flex: 0 0 16.6667%;
-    max-width: 16.6667%;
-    text-align: center;
+.property-search-bar.block .advanced-filters .select-wrapper.open > .selected::after {
+  content: '\f0d8';
 }
 
-.property-search-bar.block .filter .multiple-inputs .input-dropdown input {
-    width: 100%
+.property-search-bar.block .advanced-filters .select-wrapper .select-items {
+  display: none;
+  position: absolute;
+  top: 100%;
+  left: 0;
+  padding: 10px;
+  background-color: var(--white);
+  z-index: 501;
+  box-shadow: 0 .5rem 1rem rgba(0 0 0 / 15%);
 }
 
-.property-search-bar.block .filter-checkbox .checkbox {
-    cursor: pointer;
-    height: 24px;
-    width: 24px;
-    border: 1px solid var(--grey);
-    margin-right: 0.5rem;
-    position: relative;
+.property-search-bar.block .advanced-filters .attributes .select-wrapper .select-items,
+.property-search-bar.block .advanced-filters .misc .select-wrapper .select-items {
+  padding: 0;
+  max-height: 185px;
+  overflow-y: scroll;
+  width: 100%;
+  border: 1px solid var(--platinum);
 }
 
-.property-search-bar.block .filter .filter-toggle .checkbox {
-    width: 24px;
-    height: 16px;
-    border-radius: 100px;
-    position: relative;
-    border: 1px solid #b4b4b4;
-    background: var(--white);
+.property-search-bar.block .advanced-filters .select-wrapper.open .select-items {
+  display: block;
 }
 
-.property-search-bar.block .filter .filter-toggle .checkbox::before {
-    content: '';
-    position: absolute;
-    right: 2px;
-    top: 2px;
-    height: 10px;
-    width: 10px;
-    border-radius: 10px;
-    z-index: 1;
-    background: #b4b4b4;
+.property-search-bar.block .advanced-filters .select-wrapper .select-items li {
+  display: flex;
+  font-size: var(--body-font-size-s);
+  padding: 4px 15px;
+  line-height: 30px;
+  cursor: pointer;
+  border-left: 1px solid var(--platinum);
+  border-right: 1px solid var(--platinum);
 }
 
-.property-search-bar.block .filter .filter-toggle .checkbox.checked {
-    background: var(--body-color);
-    border: 1px solid transparent
+.property-search-bar.block .advanced-filters .attributes .select-wrapper .select-items li,
+.property-search-bar.block .advanced-filters .misc .select-wrapper .select-items li {
+  border: none;
+  padding: 4px 8px;
 }
 
-.property-search-bar.block .filter .filter-toggle .checkbox.checked::before{
-    transform: translateX(-8px);
-    background: var(--white);
+.property-search-bar.block .advanced-filters .select-wrapper .select-items li:hover {
+  color: var(--body-color);
+  background-color: var(--light-grey);
 }
 
-.property-search-bar.block .filter .filter-toggle.disabled {
-    pointer-events: none;
-    opacity: .3;
+.property-search-bar.block .advanced-filters .select-wrapper .select-items li.selected{
+  color: var(--body-color);
+  background-color: var(--light-grey);
 }
 
-.property-search-bar.block .container {
-    margin-right: 0.5rem;
-    margin-left: 0.5rem;
-    padding: 0 15px;
+.property-search-bar.block .advanced-filters .attributes .price .range-items,
+.property-search-bar.block .advanced-filters .attributes .sqft .range-items,
+.property-search-bar.block .advanced-filters .misc .year-range .range-items {
+  display: flex;
+  align-items: center;
+  color: var(--body-color);
 }
 
-.property-search-bar.block .container-item {
-    margin: 0 0.5rem;
-    order: 3;
-    padding: 0 15px;
+.property-search-bar.block .advanced-filters .attributes .sqft .range-items > *,
+.property-search-bar.block .advanced-filters .misc .year-range .range-items > * {
+  flex: 1 1 auto;
 }
 
-.property-search-bar.block .primary-search {
-    width: 550px;
-    order: 1;
+.property-search-bar.block .advanced-filters .attributes .range-items .select-wrapper select,
+.property-search-bar.block .advanced-filters .year-range .range-items .select-wrapper select {
+  display: none;
+  visibility: hidden;
 }
 
-.property-search-bar.block .square-feet {
-    border-right: 1px solid var(--black);
-    padding-right: 30px;
+.property-search-bar.block .advanced-filters .attributes .price .range-items > span,
+.property-search-bar.block .advanced-filters .attributes .sqft .range-items > span,
+.property-search-bar.block .advanced-filters .misc .year-range .range-items > span {
+  text-align: center;
+  margin: 0 16px;
+  text-transform: uppercase;
+  font-weight: var(--font-weight-light);
 }
 
-.property-search-bar.block .filter-container {
-    width: 35px;
-    order: 2;
+
+.property-search-bar.block .advanced-filters .attributes .price .range-items .input-dropdown {
+  flex: 1 1 auto;
 }
 
-.property-search-bar.block .filter-container a svg {
-    width: 21px;
-    height: 20px;
-    position: absolute;
-    top: calc(50% - 10px);
-    left: calc(50% - 10px);
+.property-search-bar.block .advanced-filters .attributes .price .range-items .input-dropdown input {
+  padding: 10px;
+  height: 50px;
+  width: 100%;
+  font-size: var(--body-font-size-s);
+  letter-spacing: normal;
+  border: 1px solid var(--platinum);
 }
 
-.property-search-bar.block .label-image {
-    height: auto;
-    width: 25px;
-    margin-right: 5px;
-    padding: 5px;
+.property-search-bar.block .advanced-filters .attributes .bedrooms ul,
+.property-search-bar.block .advanced-filters .attributes .bathrooms ul {
+  display: flex;
+  align-items: center;
 }
 
-.property-search-bar.block .search-bar {
-    flex-grow: 1;
-    position: relative;
+.property-search-bar.block .advanced-filters .attributes .bedrooms ul li,
+.property-search-bar.block .advanced-filters .attributes .bathrooms ul li {
+  flex: 1;
+  border: 1px solid var(--platinum);
+  border-right: none;
 }
 
-.property-search-bar.block .input-container {
-    flex-grow: 1;
+.property-search-bar.block .advanced-filters .attributes .bedrooms ul li:last-of-type,
+.property-search-bar.block .advanced-filters .attributes .bathrooms ul li:last-of-type {
+  border-right: 1px solid var(--platinum);
 }
 
-.property-search-bar.block .select-item {
-    padding: 10px;
-    box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 15%);
-    width: 120px;
-    color: var(--body-color);
-    position: absolute;
-    background: var(--white);
-    z-index: 99;
-    white-space: nowrap;
-    left: -15px;
-    display: none;
+  .property-search-bar.block .advanced-filters .attributes .bedrooms ul li input[type="radio"],
+.property-search-bar.block .advanced-filters .attributes .bathrooms ul li input[type="radio"] {
+  display: none;
 }
 
-.property-search-bar.block .open .select-item {
-    display: block;
+.property-search-bar.block .advanced-filters .attributes .bedrooms ul li label,
+.property-search-bar.block .advanced-filters .attributes .bathrooms ul li label {
+  display: flex;
+  height: 50px;
+  margin: 0;
+  align-items: center;
+  justify-content: center;
+  font-size: var(--body-font-size-m);
+  font-weight: var(--font-weight-light);
+  color: var(--body-color);
+  text-transform: capitalize;
 }
 
-.property-search-bar.block .open .multiple-inputs .select-item {
-    display: none;
+.property-search-bar.block .advanced-filters .attributes .bedrooms ul li input[type="radio"]:checked+label,
+.property-search-bar.block .advanced-filters .attributes .bathrooms ul li input[type="radio"]:checked+label {
+  background-color: var(--light-grey);
 }
 
-.property-search-bar.block .multiple-inputs .select-item.show {
-    display: block;
+.property-search-bar.block .advanced-filters .section-label {
+  display: block;
+  margin-bottom: 16px;
+  font-weight: var(--font-weight-bold);
+  font-size: var(--body-font-size-xs);
+  letter-spacing: var(--letter-spacing-xs);
+  text-transform: uppercase;
 }
 
-.property-search-bar.block [name="Sort"].multiple-inputs .select-item,
-.property-search-bar.block .search-results-dropdown .multiple-inputs .select-item{
-    width: 125px;
-    left: 0;
-    border: 1px solid var(--platinum);
-    max-height: 185px;
-    overflow-y: scroll;
+.property-search-bar.block .advanced-filters label {
+  display: block;
+  margin: 8px 0;
+  font-size: var(--body-font-size-s);
+  letter-spacing: var(--letter-spacing-xs);
+  text-transform: uppercase;
 }
 
-.property-search-bar.block .filter .tile li {
-    flex: 1;
-    border: 1px solid #dee2e6;
-    border-left: none;
-    text-align: center;
+
+.property-search-bar.block .advanced-filters input[type="radio"] {
+  position: absolute;
+  width: 20px;
+  height: 20px;
+  opacity: 0;
 }
 
-.property-search-bar.block .filter li:first-of-type  {
-    border-left: 1px solid #dee2e6;
+.property-search-bar.block .advanced-filters .radio-button {
+  position: relative;
+  width: 20px;
+  height: 20px;
+  border: 1px solid var(--grey);
+  border-radius: 100%;
 }
 
-.property-search-bar.block .filter-checkbox label {
-    display: flex;
-    justify-content: flex-start;
-    align-items: center;
+.property-search-bar.block .advanced-filters input[type="radio"]:checked+.radio-button {
+  background-color: var(--black);
+  border-color: var(--black);
 }
 
-.property-search-bar.block .filter input[type="radio"] {
-    position: absolute;
-    width: 20px;
-    height: 20px;
-    min-width: 20px;
-    opacity: 0
+.property-search-bar.block .advanced-filters input[type="radio"]:checked+.radio-button::after {
+  position: absolute;
+  content: '';
+  display: block;
+  width: 10px;
+  height: 10px;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  background-color: var(--white);
+  border-radius: 100%;
 }
 
-.property-search-bar.block .filter li label{
-    height: 50px;
-    display: flex;
-    justify-content: center;
-    align-content: center;
-    flex-wrap: wrap;
-    font-weight: 300;
-    color: #495057;
+.property-search-bar.block .advanced-filters .filter-toggle {
+  display: flex;
+  gap: 1em;
+  align-items: center;
+  font-size: var(--body-font-size-s);
+  text-transform: uppercase;
 }
 
-.property-search-bar.block .filter li input[type="radio"]:checked+label {
-    background-color: var(--light-grey);
-    text-align: center;
+.property-search-bar.block .advanced-filters .filter-toggle .checkbox {
+  min-width: 24px;
+  height: 16px;
+  border-radius: 100px;
+  position: relative;
+  border: 1px solid #b4b4b4;
+  background: var(--white);
 }
 
-.property-search-bar.block .filter .multiple-inputs .select-item{
-    border-bottom: 1px solid var(--platinum);
-    max-height: 185px;
-    overflow-y: scroll;
-    width: 100%;
-    left: 0;
+.property-search-bar.block .advanced-filters .filter-toggle .checkbox::before {
+  content: '';
+  position: absolute;
+  right: 2px;
+  top: 2px;
+  height: 10px;
+  width: 10px;
+  border-radius: 10px;
+  z-index: 1;
+  background: #b4b4b4;
+}
 
+.property-search-bar.block .advanced-filters .filter-toggle .checkbox.checked {
+  background: var(--body-color);
+  border: 1px solid transparent
 }
 
-/* suggestions */
-.property-search-bar.block  .search-bar .suggester-results {
-    display: none;
-    position: absolute;
-    left: 0;
-    width: 100%;
-    max-height: 300px;
-    overflow-y: scroll;
-    background-color: var(--white);
-    border: 1px solid var(--grey);
-    box-shadow: 0 3px 9px 2px rgba(0 0 0 / 23%);
-    z-index: 10;
-    line-height: 1.5;
+.property-search-bar.block .advanced-filters .filter-toggle .checkbox.checked::before {
+  transform: translateX(-8px);
+  background: var(--white);
 }
 
-.property-search-bar.block .search-bar.show-suggestions .suggester-results {
-    display: block;
+.property-search-bar.block .advanced-filters .filter-toggle.disabled {
+  pointer-events: none;
+  opacity: .3;
 }
 
-.property-search-bar.block .search-bar .suggester-results > li > ul {
-    padding: 0 15px;
+.property-search-bar.block .advanced-filters .property-types div.options {
+  display: flex;
+  flex-wrap: wrap;
+  margin-bottom: 16px;
 }
 
-.property-search-bar.block .search-bar .suggester-results > li > ul > li {
-    padding: 8px 0;
-    font-size: var(--body-font-size-m);
-    font-weight: 400;
-    text-transform: none;
-    letter-spacing: normal;
+.property-search-bar.block .advanced-filters .property-types div.options button {
+  flex-basis: 50%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  gap: 5px;
+  height: 80px;
+  width: 100%;
+  border: 1px solid var(--platinum);
+  background-color: var(--white);
 }
 
-.property-search-bar.block .search-bar .suggester-results .list-title {
-    padding: 15px 15px 5px;
-    font-family: var(--font-family-primary);
-    font-size: var(--body-font-size-s);
-    font-weight: 700;
-    text-transform: uppercase;
-    letter-spacing: .5px;
-    color: var(--black);
+.property-search-bar.block .advanced-filters .property-types div.options button.selected {
+  background-color: var(--platinum);
+  border: 1px solid var(--grey);
 }
 
-.property-search-bar.block [name="Sort"].multiple-inputs .select-item li,
-.property-search-bar.block .filter .multiple-inputs .select-item li {
-    border: none;
+.property-search-bar.block .advanced-filters .property-types div.options button > svg {
+  height: 21px;
+  width: 21px;
 }
 
+.property-search-bar.block .advanced-filters .property-types div.options button > span {
+  text-align: center;
+  white-space: break-spaces;
+  font-size: var(--body-font-size-s);
+  line-height: var(--line-height-xs);
+}
 
-.property-search-bar.block .search-results-dropdown .select-item li:first-child {
-    border-top: 1px solid var(--platinum);
+.property-search-bar.block .advanced-filters .property-types .all label {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 16px;
 }
 
-.property-search-bar.block .search-results-dropdown .select-item li:last-child {
-    border-bottom: 1px solid var(--platinum);
+.property-search-bar.block .property-types .all input[type="checkbox"] {
+  position: absolute;
+  height: 24px;
+  width: 24px;
+  margin: 0;
+  opacity: 0;
 }
 
+.property-search-bar.block .advanced-filters .property-types .all .checkbox {
+  position: relative;
+  height: 24px;
+  width: 24px;
+  border: 1px solid var(--grey);
+  z-index: 100;
+}
 
-.property-search-bar.block .search-results-dropdown .multiple-inputs .select-item li {
-    border: none;
+.property-search-bar.block .advanced-filters .property-types .all .checkbox svg {
+  display: none;
+  position: absolute;
+  top: calc(50% - 5px);
+  left: 5px;
+  height: 10px;
+  width: 12px;
+  filter: brightness(0) saturate(100%) invert(12%) sepia(4%) saturate(1639%) hue-rotate(303deg) brightness(97%) contrast(94%);
 }
 
-.property-search-bar.block .search-results-dropdown  .select-item .custom-tooltip {
-    background: var(--white);
-    position: absolute;
-    left: 100%;
-    top: 0;
+.property-search-bar.block .advanced-filters .property-types .all input[type="checkbox"]:checked+.checkbox svg {
+  display: block;
 }
 
-.property-search-bar.block .search-results-dropdown .select-item li a {
-    display: flex;
-    align-items: center;
+.property-search-bar.block .advanced-filters .property-types .all span.label {
+  font-size: var(--body-font-size-s);
+  letter-spacing: var(--letter-spacing-m);
+  text-transform: initial;
+  line-height: unset;
 }
 
-.property-search-bar.block .multiple-inputs {
-    display: flex;
-    align-items: center;
-    color: var(--body-color);
-    background-color: var(--white);
+.property-search-bar.block .advanced-filters .keywords {
+  background-color: var(--light-grey);
 }
 
-.property-search-bar.block .input-dropdown input::placeholder {
-    color: var(--input-placeholder);
-    opacity: 1; /* Firefox */
+.property-search-bar.block .advanced-filters .keywords .keywords-input {
+  display: flex;
+  padding: 1px 7px;
+  height: 50px;
+  align-items: center;
+  gap: 7px;
+  background-color: var(--white);
+  border: 1px solid var(--grey);
 }
 
-.property-search-bar.block [name="Price"] .search-results-dropdown,
-.property-search-bar.block [name="LivingArea"] .search-results-dropdown
-{
-    position: absolute;
-    padding: 10px;
-    background-color: var(--white);
-    z-index: 1000;
+.property-search-bar.block .advanced-filters .keywords .keywords-input input {
+  flex: 1 1 auto;
+  height: 35px;
+  border: none;
+  font-weight: var(--font-weight-light);
+  line-height: var(--line-height-m);
+  letter-spacing: normal;
 }
 
-.property-search-bar.block .shadow {
-    box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 15%) !important;
+.property-search-bar.block .advanced-filters .keywords .keywords-input input::placeholder {
+  font-weight: var(--font-weight-light);
+  line-height: var(--line-height-m);
+  letter-spacing: normal;
 }
 
-.property-search-bar.block .multiple-inputs section div:first-child {
-    width: 125px;
+.property-search-bar.block .advanced-filters .keywords .keywords-input button {
+  padding: 7px 25px;
+  background-color: var(--white);
+  border: 1px solid var(--grey);
+  vertical-align: middle;
+  text-align: center;
 }
 
-.property-search-bar.block .multiple-inputs .select-selected {
-    color: var(--black);
-    text-align: left;
-    font-size: var(--body-font-size-s);
-    height: 45px;
-    font-family: var(--font-family-primary);
-    line-height: 45px;
-    border: 1px solid var(--platinum);
-    padding: 0 15px;
-    position: relative;
-    letter-spacing: var(--letter-spacing-xxs);
+.property-search-bar.block .advanced-filters .keywords .keywords-input button span {
+  font-size: var(--body-font-size-s);
+  letter-spacing: var(--letter-spacing-m);
+  text-transform: uppercase;
 }
 
-.property-search-bar.block .search-listing-block > .button-container {
-    order: 3;
+.property-search-bar.block .advanced-filters .keywords .keywords-list {
+  margin: 8px 0;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
 }
 
-.property-search-bar.block .container-item,
-.property-search-bar.block .search-listing-block .button-container:last-child {
-    display: none;
+.property-search-bar.block .advanced-filters .keywords .keywords-list .keyword {
+  padding: 10px;
+  background-color: var(--white);
 }
 
-.property-search-template.no-scroll {
-    height: 100%;
-    overflow: hidden;
+.property-search-bar.block .advanced-filters .keywords .keywords-list .keyword span {
+  font-size: var(--body-font-size-m);
+  line-height: var(--line-height-xs);
+  color: var(--body-color);
 }
 
-.property-search-bar.block .filter-block {
-    top: 115px;
-    letter-spacing: 0.5px;
-    position: fixed;
-    overflow-y: auto;
-    left: 0;
-    width: 100vw;
-    height: calc(100% - var(--nav-height) - 115px);
-    background-color:  var(--white);
-    z-index: 999;
+.property-search-bar.block .advanced-filters .keywords .keywords-list .keyword span.close {
+  color: var(--black);
+  margin-left: 4px;
 }
 
-.property-search-bar.block .filter-block .multiple-inputs {
-    margin-right: 2rem;
+.property-search-bar.block .advanced-filters .keywords .keywords-match {
+  display: flex;
+  gap: 14px;
 }
 
-.property-search-bar.block [name="OpenHouses"] > div > div:not(.filter-checkbox) {
-    display: none;
+.property-search-bar.block .advanced-filters .keywords .keywords-match label,
+.property-search-bar.block .advanced-filters .open-houses .open-houses-timeframe label {
+  display: flex;
+  margin: 0;
+  gap: 5px;
+  align-items: center;
 }
 
-.property-search-bar.block [name="Sort"].select-selected,
-.property-search-bar.block [name="Sort"] .search-results-dropdown .select-item li {
-    font-size: var(--body-font-size-xs);
-    letter-spacing: var(--letter-spacing-reg);
-    color: var(--body-color);
-    cursor: pointer;
+.property-search-bar.block .advanced-filters .keywords .keywords-match label span,
+.property-search-bar.block .advanced-filters .open-houses .open-houses-timeframe label span {
+  font-size: var(--body-font-size-s);
+  text-transform: capitalize;
 }
 
-.property-search-bar.block .search-bar .suggester-results > li:first-child:not(:only-child){
-    display: none;
+.property-search-bar.block .advanced-filters .misc hr {
+  margin: 16px 0;
+  border: none;
+  border-top: 1px solid var(--platinum);
 }
 
-.property-search-bar.block [name="Sort"].select-selected {
-    border: 1px solid var(--grey);
-    height: 35px;
-    line-height: 35px;
+.property-search-bar.block .advanced-filters .misc .filter-toggle {
+  justify-content: space-between;
 }
 
-.property-search-bar.block [name="Sort"].multiple-inputs .select-item {
-    left: 0;
-    width: 100%;
+.property-search-bar.block .advanced-filters .misc .filter-toggle label {
+  font-size: var(--body-font-size-s);
+  font-weight: var(--font-weight-bold);
 }
 
-.property-search-bar.block [name="Sort"].multiple-inputs section div:first-child {
-    width: 145px;
+.property-search-bar.block .advanced-filters .misc .open-houses .open-houses-timeframe {
+  display: none;
 }
 
-.property-search-bar.block [name="Sort"] .search-results-dropdown .select-item li:first-child {
-    border-top: none;
+.property-search-bar.block .advanced-filters .misc .open-houses .open-houses-timeframe.visible {
+  display: flex;
+  gap: 16px;
 }
 
-.property-search-bar.block [name="Sort"] .search-results-dropdown .select-item li:last-child {
-    border-bottom: none;
+.property-search-bar.block .advanced-filters .buttons {
+  position: sticky;
+  bottom: 0;
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: center;
+  z-index: 502;
+  background-color: var(--white);
+  box-shadow: 0 0 4px 0 rgb(0 0 0 / 50%);
 }
 
-.property-search-bar.block .filter-block .multiple-inputs section div:first-child {
-    width: 100%;
-    position: relative;
+.property-search-bar.block .advanced-filters .buttons p.button-container {
+  margin-bottom: 0;
+}
 
+.property-search-bar.block .advanced-filters .buttons p.button-container a {
+  padding: 7px 25px;
 }
 
-.property-search-bar.block .filter-block button {
-    font-family: var(--font-family-primary);
+.property-search-bar.block .advanced-filters .buttons p.button-container a,
+.property-search-bar.block .advanced-filters .buttons p.button-container.secondary a:hover {
+  background-color: var(--primary-color);
+  border-color: var(--white);
+  color: var(--white);
 }
 
-.property-search-bar.block .filter-block [name="Features"] {
-    background: var(--light-grey);
-    padding: 27px 20px;
+.property-search-bar.block .advanced-filters .buttons p.button-container a:hover,
+.property-search-bar.block .advanced-filters .buttons p.button-container.secondary a {
+  background-color: var(--white);
+  color: var(--primary-color);
+  border-color: var(--primary-color);
 }
 
-.property-search-bar.block [name="Features"] input[type="text"]{
-    height: 35px;
-    border: none;
-    flex: 0 0 83.3333%;
-    padding: 1px 15px 1px 7px;
+.property-search-bar.block .search-overlay {
+  display: none;
+  position: absolute;
+  width: 100vw;
+  height: calc(100vh - var(--nav-height) - 50px);
+  top: 50px;
+  left: 0;
+  background-color: var(--dark-grey);
+  opacity: .5;
+  z-index: 2;
 }
 
-.property-search-bar.block .container-input {
-    height: 50px;
-    border: 1px solid var(--grey);
-    padding-right: 7px;
-    background: var(--white);
+.property-search-bar.block .search-overlay.visible {
+  display: block;
 }
 
-.property-search-bar.block .container-input .button.secondary {
-    flex: 0 0 16.6667%;
-    border: 1px solid var(--grey);
+
+/* !* suggestions *! */
+.property-search-bar.block .search-bar .suggester-results {
+  display: none;
+  position: absolute;
+  left: 0;
+  width: 100%;
+  max-height: 300px;
+  overflow-y: scroll;
+  background-color: var(--white);
+  border: 1px solid var(--grey);
+  box-shadow: 0 3px 9px 2px rgba(0 0 0 / 23%);
+  z-index: 510;
+  line-height: 1.5;
 }
 
-.property-search-bar.block .filter li input[type="radio"] {
-    display: none;
+.property-search-bar.block .search-bar.show-suggestions .suggester-results {
+  display: block;
 }
 
-.property-search-bar.block .filter .radio-btn {
-    width: 20px;
-    height: 20px;
-    border: 1.4px solid #cecece;
-    margin-right: 8px;
-    position: relative;
-    border-radius: 100%;
-    overflow: hidden;
+.property-search-bar.block .search-bar .suggester-results .list-title {
+  padding: 15px 15px 5px;
+  font-family: var(--font-family-primary);
+  font-size: var(--body-font-size-s);
+  font-weight: var(--font-weight-bold);
+  text-transform: uppercase;
+  letter-spacing: .5px;
+  color: var(--black);
 }
 
-.property-search-bar.block .filter input[type="radio"]:checked+.radio-btn {
-    background: black;
-    border-color: black;
+.property-search-bar.block .search-bar .suggester-results > li > ul {
+  padding: 0 15px;
 }
 
-.property-search-bar.block .filter input[type="radio"]:checked+.radio-btn::after {
-    content: "";
-    display: block;
-    width: 10px;
-    height: 10px;
-    background: white;
-    border-radius: 100%;
-    position: absolute;
-    left: 50%;
-    top: 50%;
-    transform: translate(-50%, -50%);
+.property-search-bar.block .search-bar .suggester-results > li > ul > li {
+  padding: 8px 0;
+  font-size: var(--body-font-size-m);
+  font-weight: 400;
+  text-transform: none;
+  letter-spacing: normal;
 }
 
-.property-search-bar.block .column-2 .column {
-    flex: 0 0 50%;
-    width: 100%;
+.property-search-bar.block .search-bar .suggester-results > li:first-child:not(:only-child) {
+  display: none;
 }
 
-.property-search-bar.block .column-2 .column button {
-    border: 1px solid #e7e7e7;
-    flex-direction: column;
-    height: 80px;
+@media screen and (min-width: 600px) {
+  .property-search-bar.block .advanced-filters .property-types div.options {
+    gap: 8px;
+  }
+
+  .property-search-bar.block .advanced-filters .property-types div.options button {
+    flex-basis: calc(50% - 4px);
+    display: flex;
+    flex-direction: row;
     align-items: center;
+    justify-content: flex-start;
+    gap: 16px;
+    height: 40px;
     width: 100%;
-    justify-content: center;
-    overflow: visible;
-    background: var(--white);
+  }
 }
 
-.property-search-bar.block .filter .column svg {
-     height: 21px;
-     width: 20px;
-     pointer-events: none;
-}
+@media screen and (min-width: 900px) {
+  .property-search-bar.block .search-bar {
+    flex: 1 1 auto;
+  }
 
-.property-search-bar.block .column-2 .column button.selected {
-    background: var(--platinum);
-    border: 1px solid grey;
-}
+  .property-search-bar.block form .result-filters {
+    order: 3;
+  }
+
+  .property-search-bar.block .result-filters .range-wrapper,
+  .property-search-bar.block .result-filters .select-wrapper {
+    display: flex;
+  }
+
+  .property-search-bar.block form a.search-submit {
+    order: 2;
+  }
 
-.property-search-bar.block .section-label {
-    font-family: var(--font-family-primary);
-    font-weight: 700;
+  .property-search-bar.block form a.save-search {
+    display: initial;
+    padding: 7px 10px;
+    border: 1px solid var(--white);
     font-size: var(--body-font-size-s);
-    color: var(--body-color);
-    margin: 0 0 16px;
-    line-height: 1;
-    display: block;
-}
+    font-weight: var(--font-weight-bold);
+    letter-spacing: var(--letter-spacing-m);
+    line-height: var(--line-height-s);
+    white-space: nowrap;
+  }
 
-.property-search-bar.block .filter-checkbox input[type="checkbox"] {
-    height: 24px;
-    min-width: 24px;
-    width: 24px;
-    border-radius: 50%;
-    border: 1px solid var(--body-color);
-    opacity: 0;
-    position: absolute;
-    z-index: 1;
-}
+  .property-search-bar.block form a.save-search span {
+    font-size: inherit;
+    font-weight: inherit;
+    letter-spacing: inherit;
+    line-height: inherit;
+    color: var(--white);
+    text-transform: uppercase;
+  }
 
-.property-search-bar.block .filter-checkbox .checkbox svg {
+  .property-search-bar.block .advanced-filters {
+    width: 600px;
+    right: 0;
+    left: unset;
+  }
+
+  .property-search-bar.block .advanced-filters .attributes {
     display: none;
-    height: 10px;
-    width: 12px;
-    top: calc(50% - 5px);
-    position: absolute;
-    left: 5px;
-}
+  }
 
-.property-search-bar.block .filter-checkbox input[type="checkbox"]:checked+.checkbox svg {
-    display: block;
+  .property-search-bar.block .search-overlay {
+    position: fixed;
+    height: unset;
+    top: calc(var(--nav-height) + 50px);
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background-color: var(--dark-grey);
+    opacity: .5;
+  }
 }
-
-.property-search-bar.block [name="FeaturedCompany"],
-.property-search-bar.block [name="Luxury"], [name="RecentPriceChange"], [name="NewListing"] {
-    display: flex;
-    justify-content: space-between;
-}
-
-.property-search-bar.block .tag {
-    background-color: var(--white);
-    padding: 10px;
-    margin-top: 10px;
-    margin-right: 10px;
-    font-size: var(--body-font-size-m);
-    letter-spacing: initial;
-    line-height: 33px;
-}
-
-.tag .close::after {
-    content: "x";
-}
-
-.property-search-bar.block .filter-buttons.button-container.flex-row.vertical-center {
-    margin: 0;
-}
-
-@media (min-width: 600px) {
-    .property-search-bar.block .column-2 .column button {
-        flex-direction: row;
-        height: 40px;
-        align-items: center;
-        width: 100%;
-        justify-content: start;
-        overflow: visible;
-        margin-bottom: 0.5rem;
-    }
-
-    .property-search-bar.block .filter .column svg {
-        height: 21px;
-        width: 20px;
-        pointer-events: none;
-    }
-
-    .property-search-bar.block .column-2 .column:last-child {
-        padding-left: 0.5rem;
-    }
-}
-
-.property-search-bar.block [name="OpenHouses"].selected > div > div:not(.filter-checkbox) {
-    display: block;
-}
-
-@media (min-width: 900px) {
-    .property-search-template .section.property-search-bar-container {
-        margin-bottom: 0;
-        position: sticky;
-        top: 140px;
-        z-index: 10;
-        background: white;
-    }
-
-    .property-search-bar.block .overlay {
-        top: calc(var(--nav-height) + 50px);
-    }
-
-    .property-search-bar.block .search-listing-container {
-        justify-content: center;
-    }
-
-    .property-search-bar.block .search-listing-block {
-        max-width: var(--normal-page-width);
-        justify-content: space-between;
-    }
-
-    .property-search-bar.block .container-item,
-    .property-search-bar.block .search-listing-block .button-container:last-child {
-        display: block;
-    }
-
-    .property-search-bar.block .filter-block {
-        width: 600px;
-        height: calc(100% - 110px - var(--nav-height));
-        top: calc(var(--nav-height) + 50px);
-        left: calc(100% - 600px);
-    }
-
-    .property-search-bar.block .filter-buttons {
-        justify-content: flex-start;
-        padding: 15px 15px 15px 20px;
-        width: 600px;
-        left: calc(100% - 600px);
-        box-shadow: none;
-        border-top: 1px solid var(--body-color);
-    }
-
-    .property-search-bar.block .filter-block [name="Price"],
-    .property-search-bar.block .filter-block [name="LivingArea"],
-    .property-search-bar.block .filter-block [name="MinBedroomsTotal"],
-    .property-search-bar.block .filter-block [name="MinBathroomsTotal"],
-    .property-search-bar.block .filter-block [name="ApplicationType"] {
-        display: none;
-    }
-
-    .property-search-bar.block .search-listing-block > div {
-        order: 3;
-    }
-
-    .property-search-bar.block .search-listing-container > div:first-of-type {
-        display: flex;
-        width: 100%;
-        justify-content: space-evenly;
-        background: var(--primary-color);
-    }
-
-    .property-search-bar.block .search-listing-container > div:last-of-type {
-        display: flex;
-        flex-basis: 100%;
-        max-width: var(--normal-page-width);
-    }
-
-    .property-search-bar.block .result-filters [name="ApplicationType"],
-    .property-search-bar.block .result-filters .map-toggle {
-        display: flex
-    }
-
-    .property-search-bar.block .bf-container {
-        justify-content: space-between;
-    }
-
-    .property-search-bar.block .primary-search {
-        max-width: 40vw;
-    }
-
-    .property-search-bar.block .search-listing-block .multiple-inputs input {
-        border: 1px solid #dee2e6;
-        margin: 0;
-        color: var(--black);
-        width: 165px;
-    }
-}
\ No newline at end of file
diff --git a/blocks/property-search-bar/property-search-bar.js b/blocks/property-search-bar/property-search-bar.js
index 74406e02..5a432e3b 100644
--- a/blocks/property-search-bar/property-search-bar.js
+++ b/blocks/property-search-bar/property-search-bar.js
@@ -1,40 +1,71 @@
 import {
-  populatePreSelectedFilters, setInitialValuesFromUrl, searchProperty,
-} from './filter-processor.js';
+  BED_BATHS,
+  buildDataListRange,
+  buildFilterSelect,
+  buildSelectRange,
+  getPlaceholder,
+} from '../shared/search/util.js';
+import { decorateIcons, loadScript } from '../../scripts/aem.js';
 
-import {
-  buildFilterSearchTypesElement, closeTopLevelFilters,
-} from './common-function.js';
-import topMenu from './filters/top-menu.js';
-import additionalFilters from './filters/additional-filters.js';
-import layoutButtons from './filters/additional-filter-buttons.js';
+export const SQUARE_FEET = [
+  { value: '500', label: '500 Sq Ft' },
+  { value: '750', label: '750 Sq Ft' },
+  { value: '1000', label: '1,000 Sq Ft' },
+  { value: '1250', label: '1,250  Sq Ft' },
+  { value: '1500', label: '1,500 Sq Ft' },
+  { value: '1750', label: '1,750 Sq Ft' },
+  { value: '2000', label: '2,000 Sq Ft' },
+  { value: '2250', label: '2,250 Sq Ft' },
+  { value: '2500', label: '2,500 Sq Ft' },
+  { value: '2750', label: '2,750 Sq Ft' },
+  { value: '3000', label: '3,000 Sq Ft' },
+  { value: '3500', label: '3,500 Sq Ft' },
+  { value: '4000', label: '4,000 Sq Ft' },
+  { value: '5000', label: '5,000 Sq Ft' },
+  { value: '7500', label: '7,500 Sq Ft' },
+];
 
-// const event = new Event('onFilterChange');
+function buildBar() {
+  const div = document.createElement('div');
+  div.classList.add('search-form-wrapper');
+  div.innerHTML = `
+    <form action="/search"> 
+      <div class="search-bar" role="search">
+        <div class="search-suggester suggester-input">
+          <input type="text" placeholder="${getPlaceholder()}" aria-label="${getPlaceholder()}" name="keyword">
+          <input type="hidden" name="query">
+          <input type="hidden" name="type">
+          <ul class="suggester-results">
+            <li class="list-title">Please enter at least 3 characters.</li>
+          </ul>
+        </div>
+      </div>
+      <div class="result-filters">
+        ${buildDataListRange('price', 'Price').outerHTML}
+        ${buildFilterSelect('bedrooms', 'Beds', BED_BATHS).outerHTML}
+        ${buildFilterSelect('bathrooms', 'Baths', BED_BATHS).outerHTML}
+        ${buildSelectRange('sqft', 'Square Feet', SQUARE_FEET).outerHTML}
+        <a class="filter" type="button" aria-label="More Filters" aria-haspopup="true">
+          <span class="icon icon-filter-white"></span>
+          <span class="icon icon-close-x-white"></span>
+        </a>
+        <a class="save-search" type="button" aria-label="Save Search" role="button"><span>Save Search</span></a>
+      </div>
+      <a href="#" class="search-submit" aria-label="Search">
+        <span class="icon icon-search"></span>
+      </a>
+      <div class="advanced-filters">
+      </div>
+      <div class="search-overlay"></div>
+    </form>
+  `;
+  return div;
+}
 
 export default async function decorate(block) {
-  setInitialValuesFromUrl();
-  /** build top menu html */
-  const overlay = document.createElement('div');
-  overlay.classList.add('overlay', 'hide');
-  const additionalConfig = document.createElement('div');
-  additionalConfig.append(buildFilterSearchTypesElement());
-  const topMenuBlock = await topMenu.build();
-  const additionalFiltersBlock = await additionalFilters.build();
-  const buttons = await layoutButtons.build();
-  block.append(topMenuBlock, additionalFiltersBlock, overlay, buttons);
-
-  populatePreSelectedFilters();
-
-  // close filters on click outside
-  document.addEventListener('click', (e) => {
-    if (!block.contains(e.target)) {
-      closeTopLevelFilters();
-    }
-  });
-
-  window.addEventListener('onFilterChange', (e) => {
-    e.preventDefault();
-    e.stopPropagation();
-    searchProperty();
-  });
+  block.replaceChildren(buildBar());
+  decorateIcons(block);
+  window.setTimeout(() => {
+    loadScript(`${window.hlx.codeBasePath}/blocks/property-search-bar/delayed.js`, { type: 'module' });
+  }, 3000);
 }
diff --git a/blocks/property-search-bar/search-results-dropdown.css b/blocks/property-search-bar/search-results-dropdown.css
deleted file mode 100644
index 36ad67c5..00000000
--- a/blocks/property-search-bar/search-results-dropdown.css
+++ /dev/null
@@ -1,66 +0,0 @@
-.property-search-template .highlighted {
-    background: var(--light-grey);
-}
-
-.property-search-template .select-item::-webkit-scrollbar {
-    width: 14px;
-}
-
-.property-search-template .select-item::-webkit-scrollbar-thumb{
-    background: #c1c1c1;
-    border-radius: 14px;
-    border: 3px solid var(--platinum)
-}
-
-.property-search-template .select-item::-webkit-scrollbar-track{
-    border-radius: 0;
-    background: var(--platinum);
-}
-
-.property-search-template .multiple-inputs .select-selected::after {
-    position: absolute;
-    content: "";
-    height: 7px;
-    width: 12px;
-    background-size: cover;
-    background-position: 50% 50%;
-    background-repeat: no-repeat;
-    top: calc(50% - 3.5px);
-    right: 15px;
-    background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIxMnB4IiBoZWlnaHQ9IjdweCIgdmlld0JveD0iMCAwIDEyIDciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+ICAgICAgICA8dGl0bGU+VUkvQ2Fycm90L0NvbGxhcHNlL0RhcmtHcmF5IENvcHkgMzwvdGl0bGU+ICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPiAgICA8ZGVmcz48L2RlZnM+ICAgIDxnIGlkPSItLS0t4pe877iOLVVJLUVsZW1lbnRzIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4gICAgICAgIDxnIGlkPSJVSS1FbGVtZW50cy9JY29ucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTM5NC4wMDAwMDAsIC0yODguMDAwMDAwKSIgZmlsbD0iI0FBQUFBQSI+ICAgICAgICAgICAgPGcgaWQ9IlVJL0NhcnJvdC9FeHBhbmQvR3JheSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzk0LjAwMDAwMCwgMjg4LjAwMDAwMCkiPiAgICAgICAgICAgICAgICA8cG9seWdvbiBpZD0iUGF0aC0yIiBwb2ludHM9IjAuNzM0NTU4NTc2IDAuNjcxMzk5NzczIDExLjI5MzM0NTkgMC42NzEzOTk3NzMgNi4wMTM5NTIyNSA2LjY2MDUzMjIiPjwvcG9seWdvbj4gICAgICAgICAgICA8L2c+ICAgICAgICA8L2c+ICAgIDwvZz48L3N2Zz4=");
-}
-
-.property-search-template .select-item {
-    padding: 10px;
-    box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 15%);
-    width: 120px;
-    color: var(--body-color);
-    position: absolute;
-    background: var(--white);
-    z-index: 99;
-    white-space: nowrap;
-    left: -15px;
-    display: none;
-}
-
-.property-search-template .search-results-dropdown div:first-child{
-    position: relative;
-}
-
-.property-search-template .select-item li,
-.property-search-template .search-results-dropdown .select-item li{
-    display: flex;
-    border-left: 1px solid var(--platinum);
-    border-right: 1px solid var(--platinum);
-    padding: 4px 10px;
-    line-height: 30px;
-    letter-spacing: var(--letter-spacing-xxs);
-    font-size: var(--body-font-size-s);
-    align-items: center;
-    justify-content: flex-start;
-    position: relative
-}
-
-.property-search-template .select-item li:hover {
-    background: var(--light-grey);
-}
\ No newline at end of file
diff --git a/blocks/property-search-bar/search/suggestion.js b/blocks/property-search-bar/search/suggestion.js
deleted file mode 100644
index 36ca8cd1..00000000
--- a/blocks/property-search-bar/search/suggestion.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { setFilterValue } from '../filter-processor.js';
-
-const CONFIG = {
-  Address: 'CoverageZipcode',
-  PostalCode: 'CoverageZipcode',
-  Neighborhood: 'BID',
-  School: 'BID',
-  'School District': 'BID',
-  MLSListingKey: 'ListingId',
-};
-
-function parseQueryString(queryString) {
-  return queryString.split('&').reduce((resultObject, pair) => {
-    const [key, value] = pair.split('=');
-    resultObject[key] = decodeURIComponent(value.replace(/\+/g, '%20'));
-    return resultObject;
-  }, {});
-}
-
-export function getAttributes(result) {
-  const query = parseQueryString(result.QueryString);
-  query.BID = result.BID ?? '';
-  const type = query.SearchType;
-  const key = CONFIG[type];
-  const output = {
-    'search-input': result.displayText,
-    'search-type': type,
-    'search-parameter': query.SearchParameter,
-  };
-  if (Object.keys(CONFIG).includes(type)) {
-    output[key] = query[key];
-  }
-  return output;
-}
-
-export function setSearchParams(target) {
-  const searchParameter = target.getAttribute('search-parameter');
-  const keyword = target.getAttribute('search-input');
-  const type = target.getAttribute('search-type');
-  let attr;
-  setFilterValue('SearchType', type);
-  setFilterValue('SearchInput', keyword);
-  setFilterValue('SearchParameterOriginal', searchParameter);
-  Object.keys(CONFIG).forEach((key) => {
-    attr = CONFIG[key].toLowerCase();
-    if (target.hasAttribute(attr)) {
-      setFilterValue(CONFIG[key], target.getAttribute(attr));
-    }
-  });
-}
diff --git a/blocks/property-search-results/README.md b/blocks/property-search-results/README.md
new file mode 100644
index 00000000..a8bf35a1
--- /dev/null
+++ b/blocks/property-search-results/README.md
@@ -0,0 +1,50 @@
+### Property Search Results
+
+This block renders the map and list of properties returned from a search.
+
+#### Default Search
+
+If no parameters were used (i.e. someone typed in the URL of the page), a default Search parameter set is used.
+
+#### Keeping in Sync
+
+This and the Property Search Bar block have shared parameters. When this block is used to set parameters, the search is performed immediately and the Search Bar state is updated (see `updateForm` in the Property Search Bar `delayed.js`)
+
+If the Property Search Bar is updated and a search submitted or applied, it emits an event, which is processed by this block. The `updateFilters` block will keep the few items in sync when the new search is executed.
+
+#### Results, Map and Browser History
+
+This page rendering these results should not refresh each time a new search is performed. So we're using `pushState` and `popstate` history manipulation.
+
+When new search parameters are provided, push that state to the history, then perform the search (via `doSearch`);
+
+The trick here is making sure that cyclic searching doesn't occur.
+
+When the page is first rendered:
+  1. Generate and center the map
+  1. Perform the search.
+  1. Render results
+  1. Decorate the map.
+
+Any time a Search Event occurs:
+  1. Perform the search.
+  1. Render results
+  1. Decorate the map.
+
+If the Map bounds change:
+  1. Create a new Search object with the bounds
+  1. Emit the Search Event with the payload
+
+If the Search Filters change:
+  1. Create a new Search object with the bounds
+  1. Emit the Search Event with the payload
+
+If a history pop-state occurs:
+  1. Sync the Filters to the history state
+  1. Tell Search Bar to sync its state.
+  1. Create search from history URL, then perform the search.
+  1. Render results
+  1. Decorate the map.
+
+
+Anytime the Map is decorating, which causes the bounds to change, flag that it's rendering. This prevents a render event from causing a second, new search.
diff --git a/blocks/property-search-results/loader.js b/blocks/property-search-results/loader.js
new file mode 100644
index 00000000..152bbf10
--- /dev/null
+++ b/blocks/property-search-results/loader.js
@@ -0,0 +1,10 @@
+import { div, img, domEl } from '../../scripts/dom-helpers.js';
+
+const loader = div({ class: 'search-results-loader' },
+  div({ class: 'animation' },
+    domEl('picture', img({ src: '/styles/images/loading.png' })),
+    div({ class: 'pulse' }),
+  ),
+);
+
+export default loader;
diff --git a/blocks/property-search-results/map.css b/blocks/property-search-results/map.css
new file mode 100644
index 00000000..f4eabc63
--- /dev/null
+++ b/blocks/property-search-results/map.css
@@ -0,0 +1,562 @@
+.property-search-results.block .search-map-container {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  background-color: var(--white);
+  min-height: 250px;
+}
+
+.property-search-results.block .search-map-container.drawing {
+  cursor: pointer;
+}
+
+.property-search-results.block .search-map-container .search-results-map {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+}
+
+.property-search-results.block .search-map-container .search-results-map #gmap-canvas {
+  height: 100%;
+  width: 100%;
+}
+
+.property-search-results.block .search-map-container .map-controls-wrapper {
+  position: absolute;
+  display: flex;
+  flex-direction: column;
+  right: 15px;
+  bottom: 15px;
+  pointer-events: none;
+  z-index: 1;
+}
+
+.property-search-results.block .search-map-container .map-controls-wrapper .custom-controls {
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+}
+
+.property-search-results.block .search-map-container .custom-controls > a {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: space-evenly;
+  height: 45px;
+  width: 45px;
+  box-shadow: 0 0 3px 2px rgba(0 0 0 / 30%);
+  pointer-events: all;
+  background-color: var(--white);
+  cursor: pointer;
+}
+
+.property-search-results.block .search-map-container .custom-controls a span {
+  font-family: var(--font-family-proxima);
+  font-size: var(--body-font-size-xxs);
+  line-height: 1em;
+  letter-spacing: normal;
+  color: var(--body-color);
+}
+
+.property-search-results.block .search-map-container.drawing .custom-controls .map-style {
+  pointer-events: none;
+}
+
+.property-search-results.block .search-map-container.satellite .custom-controls .map-style span.map {
+  display: none;
+}
+
+.property-search-results.block .search-map-container.map .custom-controls .map-style span.satellite {
+  display: none;
+}
+
+.property-search-results.block .search-map-container .custom-controls .map-style img {
+  height: 24px;
+  width: 24px;
+}
+
+.property-search-results.block .search-map-container.drawing .custom-controls .map-style * {
+  opacity: .3;
+}
+
+.property-search-results.block .search-map-container .custom-controls .map-draw img.draw {
+  height: 17px;
+  width: 17px;
+}
+
+.property-search-results.block .search-map-container .custom-controls .map-draw img.close {
+  height: 22px;
+  width: 22px;
+}
+
+.property-search-results.block .search-map-container .custom-controls .map-draw img.close,
+.property-search-results.block .search-map-container .custom-controls .map-draw span.close {
+  display: none;
+}
+
+.property-search-results.block .search-map-container.drawing .custom-controls .map-draw img.draw,
+.property-search-results.block .search-map-container.drawing .custom-controls .map-draw span.draw {
+  display: none;
+}
+
+.property-search-results.block .search-map-container.drawing .custom-controls .map-draw img.close,
+.property-search-results.block .search-map-container.drawing .custom-controls .map-draw span.close {
+  display: initial;
+}
+
+.property-search-results.block .search-map-container .custom-controls .map-draw-complete {
+  display: none;
+}
+
+.property-search-results.block .search-map-container .custom-controls .map-draw-complete.disabled {
+  pointer-events: none;
+}
+
+.property-search-results.block .search-map-container .custom-controls .map-draw-complete.disabled * {
+  opacity: .3;
+}
+
+.property-search-results.block .search-map-container.drawing .custom-controls .map-draw-complete {
+  display: flex;
+}
+
+.property-search-results.block .search-map-container.drawing .custom-controls .map-draw-complete img {
+  height: 33px;
+  width: 33px;
+}
+
+.property-search-results.block .search-map-container .custom-controls .zoom-controls {
+  display: none;
+}
+
+.property-search-results.block .search-map-container.drawing .custom-controls .zoom-controls a {
+  pointer-events: none;
+}
+
+.property-search-results.block .search-map-container.drawing .custom-controls .zoom-controls a::before,
+.property-search-results.block .search-map-container.drawing .custom-controls .zoom-controls a::after {
+  opacity: .3;
+}
+
+
+.property-search-results.block .search-map-container .map-draw-info {
+  display: none;
+}
+
+.property-search-results.block .search-map-container.drawing .map-draw-info {
+  display: block;
+  position: absolute;
+  top: 0;
+  width: 100%;
+  background-color: var(--light-grey);
+}
+
+.property-search-results.block .search-map-container.drawing .map-draw-info p {
+  padding: 0;
+  margin: 0;
+  font-family: var(--font-family-proxima);
+  font-size: var(--body-font-size-xs);
+  line-height: var(--line-height-l);
+  text-align: center;
+  letter-spacing: normal;
+}
+
+.property-search-results.block .search-map-container .map-draw-info .map-draw-boundary-link {
+  display: none;
+}
+
+.property-search-results.block .search-map-container.bound .map-draw-info .map-draw-boundary-link {
+  display: initial;
+}
+
+.property-search-results.block .search-map-wrapper .info-window {
+  position: relative;
+  background-color: var(--white);
+  z-index: 1;
+  border-bottom: 1px solid var(--platinum);
+}
+
+.property-search-results.block .search-map-wrapper .info-window.cluster {
+  max-height: calc(var(--nav-height) + 50px); /* Search bar */
+  overflow-y: scroll;
+}
+
+.property-search-results.block .search-map-wrapper .info-window .loading {
+  padding: 10px;
+  margin: 20px;
+}
+
+.property-search-results.block .search-map-wrapper .info-window .loading p {
+  font-size: var(--body-font-size-xl);
+  font-weight: var(--font-weight-semibold);
+  text-align: center;
+  margin: 0;
+}
+
+.property-search-results.block .search-map-wrapper .info-window .loading p::after {
+  content: '';
+  display: inline-block;
+  position: absolute;
+  right: 30px;
+  top: 0;
+  height: 100%;
+  width: 25px;
+  vertical-align: bottom;
+  animation: ellipsis 3s infinite;
+  background-color: white;
+}
+
+@keyframes ellipsis {
+  to {
+    width: 0;
+  }
+}
+
+.property-search-results.block .search-map-wrapper .info-window a.info-wrapper,
+.property-search-results.block .search-map-wrapper .info-window.cluster a.info-wrapper {
+  display: grid;
+  margin: 10px;
+  align-items: center;
+  padding-bottom: 10px;
+  gap: 10px;
+  border-bottom: 1px solid var(--grey);
+  text-decoration: none;
+  grid-template:
+      "image info"
+      / 50px 1fr;
+}
+
+.property-search-results.block .search-map-wrapper .info-window a.info-wrapper:last-of-type {
+  border-bottom: none;
+  padding-bottom: 0;
+}
+
+.property-search-results.block .search-map-wrapper .info-window .info-wrapper .image-wrapper {
+  grid-area: image;
+  position: relative;
+  height: 105px;
+  width: 150px;
+}
+
+.property-search-results.block .search-map-wrapper .mobile-info-window .info-wrapper .image-wrapper,
+.property-search-results.block .search-map-wrapper .info-window.cluster .info-wrapper .image-wrapper {
+  position: relative;
+  height: 35px;
+  width: 50px;
+}
+
+.property-search-results.block .search-map-wrapper .mobile-info-window .info-wrapper .image-wrapper .luxury,
+.property-search-results.block .search-map-wrapper .info-window.cluster .info-wrapper .image-wrapper .luxury {
+  display: none;
+}
+
+.property-search-results.block .search-map-wrapper .info-window .info-wrapper .image-wrapper img {
+  position: absolute;
+  top: 0;
+  left: 0;
+  height: 100%;
+  width: 100%;
+  object-fit: contain;
+  object-position: center;
+}
+
+.property-search-results.block .search-map-wrapper .info-window .info-wrapper .info {
+  grid-area: info;
+  display: flex;
+  flex-direction: column;
+}
+
+.property-search-results.block .search-map-wrapper .mobile-info-window .info-wrapper .info hr,
+.property-search-results.block .search-map-wrapper .info-window.cluster .info-wrapper .info hr {
+  display: none;
+
+}
+
+.property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .price span {
+  display: block;
+  font-size: var(--body-font-size-l);
+  font-weight: var(--font-weight-semibold);
+  line-height: var(--line-height-s);
+  letter-spacing: var(--letter-spacing-xxs);
+}
+
+.property-search-results.block .search-map-wrapper .mobile-info-window .info-wrapper .info .price .alt,
+.property-search-results.block .search-map-wrapper .info-window.cluster .info-wrapper .info .price .alt {
+  display: none;
+}
+
+.property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .details span {
+  display: block;
+  font-size: var(--body-font-size-xs);
+  letter-spacing: normal;
+  line-height: var(--line-height-xs);
+}
+
+.property-search-results.block .search-map-wrapper .mobile-info-window .info-wrapper .info .details .address .danger,
+.property-search-results.block .search-map-wrapper .info-window.cluster .info-wrapper .info .details .address .danger,
+.property-search-results.block .search-map-wrapper .mobile-info-window .info-wrapper .info .details .address .locality,
+.property-search-results.block .search-map-wrapper .info-window.cluster .info-wrapper .info .details .address .locality {
+  display: none;
+}
+
+.property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .providers {
+  padding: 3px 0;
+  font-size: var(--body-font-size-xxs);
+  line-height: var(--line-height-m);
+  letter-spacing: normal;
+}
+
+.property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons,
+.property-search-results.block .search-map-wrapper .info-window.cluster .info-wrapper .info .property-buttons {
+  display: none;
+}
+
+.property-search-results.block .search-map-wrapper .mobile-info-window .info-wrapper .info .listing-info,
+.property-search-results.block .search-map-wrapper .info-window.cluster .info-wrapper .info .listing-info {
+  display: none;
+}
+
+#gmap-canvas a[href^="https://maps.google.com/maps"] {
+  display: none !important; /* Don't want to use this, but theres an inline style we have to override. */
+}
+
+#gmap-canvas .gm-style-cc {
+  display: none;
+}
+
+/* overriding some google styles */
+.gm-style .gm-style-iw-d {
+  overflow: initial !important;
+}
+
+.gm-style .gm-style-iw-d::-webkit-scrollbar-track,
+.gm-style .gm-style-iw-d::-webkit-scrollbar-track-piece,
+.gm-style .gm-style-iw-t::after,
+.gm-style .gm-style-iw-c {
+  box-shadow: none !important;
+  border-radius: 0 !important;
+  padding: 0 !important;
+  overflow: initial !important;
+}
+
+.cmp-properties-map .gm-ui-hover-effect {
+  display: none !important;
+}
+
+.button.gm-ui-hover-effect, button[draggable] {
+  opacity: 0 !important;
+}
+
+@media screen and (min-width: 900px) {
+  .property-search-results.block .search-map-container .map-controls-wrapper {
+    bottom: 50%;
+    transform: translateY(50%);
+  }
+
+  .property-search-results.block .search-map-wrapper .mobile-info-window {
+    display: none;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window {
+    max-width: 250px;
+    max-height: 250px;
+    overflow-y: scroll;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window:not(.cluster) {
+    max-width: 200px;
+    padding: 0;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window a.info-wrapper {
+    grid-template:
+      "image"
+      "info";
+    margin: 0;
+    max-height: 250px;
+    overflow-y: scroll;
+    gap: 0;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .image-wrapper {
+    grid-area: image;
+    position: relative;
+    width: 100%;
+    padding-top: 73.5%;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .image-wrapper img {
+    object-fit: cover;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .image-wrapper .luxury {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: 30px;
+    text-transform: uppercase;
+    text-align: center;
+    background-color: var(--black);
+    z-index: 1;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .image-wrapper .luxury span {
+    font-size: var(--body-font-size-xs);
+    font-weight: var(--font-weight-bold);
+    letter-spacing: var(--letter-spacing-m);
+    color: var(--white);
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info {
+    padding: 5px;
+    flex-flow: row wrap;
+    justify-content: space-between;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .price .alt {
+    display: block;
+    font-size: var(--body-font-size-s);
+    font-weight: var(--font-weight-normal);
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons {
+    display: flex;
+    gap: 8px;
+    align-items: center;
+    margin: 0 5px;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons a {
+    position: relative;
+    width: 18px;
+    height: 18px;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons span {
+    position: absolute;
+    top: 0;
+    left: 0;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons img {
+    width: 18px;
+    height: 18px;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons a span.icon-envelopedark,
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons a span.icon-heartemptydark,
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons a:hover span.icon-envelope,
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons a:hover span.icon-heartempty {
+    display: none;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons a:hover span.icon-envelopedark,
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons a:hover span.icon-heartemptydark {
+    display: block;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .property-buttons a span.icon-heartfull {
+    display: none;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .details > * {
+    padding: 3px;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .details .address .danger {
+    display: block;
+    color: #832b39;
+    font-size: var(--body-font-size-xxs);
+    font-weight: var(--font-weight-bold);
+    line-height: var(--line-height-m);
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info hr {
+    width: 100%;
+    border: none;
+    border-top: 1px solid var(--platinum);
+    margin: 0;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .listing-info {
+    display: block;
+    padding: 3px;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .listing-info span {
+    display: block;
+    font-size: 8px;
+    line-height: var(--line-height-s);
+    letter-spacing: normal;
+    color: var(--dark-grey);
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .listing-info .aor-img {
+    height: 30px;
+    width: 60px;
+    position: relative;
+  }
+
+  .property-search-results.block .search-map-wrapper .info-window .info-wrapper .info .listing-info .aor-img img {
+    position: absolute;
+    top: 0;
+    left: 0;
+    height: 100%;
+    width: 100%;
+    object-fit: contain;
+    object-position: center;
+  }
+
+  .property-search-results.block .search-map-container.drawing .map-draw-info p {
+    font-size: var(--body-font-size-m);
+    line-height: 65px;
+  }
+
+
+  .property-search-results.block .search-map-container .custom-controls .zoom-controls {
+    display: block;
+    box-shadow: 0 0 3px 2px rgba(0 0 0 / 30%);
+  }
+
+  /* stylelint-disable-next-line no-descending-specificity */
+  .property-search-results.block .search-map-container .custom-controls .zoom-controls a {
+    display: block;
+    position: relative;
+    height: 45px;
+    width: 45px;
+    background-color: var(--white);
+    cursor: pointer;
+    pointer-events: all;
+
+  }
+
+  .property-search-results.block .search-map-container .custom-controls .zoom-controls a::before {
+    content: ' ';
+    position: absolute;
+    display: block;
+    background-color: var(--body-color);
+    height: 1px;
+    left: calc(50% - 8px);
+    top: 50%;
+    width: 16px;
+  }
+
+
+  .property-search-results.block .search-map-container .custom-controls .zoom-controls a.zoom-in::after {
+    content: ' ';
+    position: absolute;
+    display: block;
+    background-color: var(--body-color);
+    width: 1px;
+    top: calc(50% - 8px);
+    left: 50%;
+    height: 16px;
+  }
+
+}
diff --git a/blocks/property-search-results/map.js b/blocks/property-search-results/map.js
new file mode 100644
index 00000000..4fe764ea
--- /dev/null
+++ b/blocks/property-search-results/map.js
@@ -0,0 +1,434 @@
+/* global google */
+
+import { loadScript } from '../../scripts/aem.js';
+import loadMaps from '../../scripts/google-maps/index.js';
+import {
+  a, div, img, p, span,
+} from '../../scripts/dom-helpers.js';
+import displayClusters from './map/clusters.js';
+import { UPDATE_SEARCH_EVENT } from '../../scripts/apis/creg/search/Search.js';
+import BoxSearch from '../../scripts/apis/creg/search/types/BoxSearch.js';
+import {
+  clearInfos,
+  hideInfos,
+  getMarkerClusterer,
+  displayPins,
+} from './map/pins.js';
+import {
+  startPolygon,
+  addPolygonPoint,
+  closePolygon,
+  clearPolygon,
+} from './map/drawing.js';
+import PolygonSearch from '../../scripts/apis/creg/search/types/PolygonSearch.js';
+
+const zoom = 10;
+const maxZoom = 18;
+
+let gmap;
+let renderInProgress = false;
+
+const mapMarkers = [];
+let clusterer;
+let boundsTimeout;
+
+let drawingClickListener;
+let polygon;
+
+const MAP_STYLE = [{
+  featureType: 'administrative',
+  elementType: 'labels.text.fill',
+  stylers: [{ color: '#444444' }],
+}, {
+  featureType: 'administrative.locality',
+  elementType: 'labels.text.fill',
+  stylers: [{ saturation: '-42' }, { lightness: '-53' }, { gamma: '2.98' }],
+}, {
+  featureType: 'administrative.neighborhood',
+  elementType: 'labels.text.fill',
+  stylers: [{ saturation: '1' }, { lightness: '31' }, { weight: '1' }],
+}, {
+  featureType: 'administrative.neighborhood',
+  elementType: 'labels.text.stroke',
+  stylers: [{ visibility: 'off' }],
+}, {
+  featureType: 'administrative.land_parcel',
+  elementType: 'labels.text.fill',
+  stylers: [{ lightness: '12' }],
+}, {
+  featureType: 'landscape',
+  elementType: 'all',
+  stylers: [{ saturation: '67' }],
+}, {
+  featureType: 'landscape.man_made',
+  elementType: 'geometry.fill',
+  stylers: [{ visibility: 'on' }, { color: '#ececec' }],
+}, {
+  featureType: 'landscape.natural',
+  elementType: 'geometry.fill',
+  stylers: [{ visibility: 'on' }],
+}, {
+  featureType: 'landscape.natural.landcover',
+  elementType: 'geometry.fill',
+  stylers: [{ visibility: 'on' }, { color: '#ffffff' }, { saturation: '-2' }, { gamma: '7.94' }],
+}, {
+  featureType: 'landscape.natural.terrain',
+  elementType: 'geometry',
+  stylers: [{ visibility: 'on' }, { saturation: '94' }, { lightness: '-30' }, { gamma: '8.59' }, { weight: '5.38' }],
+}, {
+  featureType: 'poi',
+  elementType: 'all',
+  stylers: [{ visibility: 'off' }],
+}, {
+  featureType: 'poi.park',
+  elementType: 'geometry',
+  stylers: [{ saturation: '-26' }, { lightness: '20' }, { weight: '1' }, { gamma: '1' }],
+}, {
+  featureType: 'poi.park',
+  elementType: 'geometry.fill',
+  stylers: [{ visibility: 'on' }],
+}, {
+  featureType: 'road',
+  elementType: 'all',
+  stylers: [{ saturation: -100 }, { lightness: 45 }],
+}, {
+  featureType: 'road',
+  elementType: 'geometry.fill',
+  stylers: [{ visibility: 'on' }, { color: '#fafafa' }],
+}, {
+  featureType: 'road',
+  elementType: 'geometry.stroke',
+  stylers: [{ visibility: 'off' }],
+}, {
+  featureType: 'road',
+  elementType: 'labels.text.fill',
+  stylers: [{ gamma: '0.95' }, { lightness: '3' }],
+}, {
+  featureType: 'road',
+  elementType: 'labels.text.stroke',
+  stylers: [{ visibility: 'off' }],
+}, {
+  featureType: 'road.highway',
+  elementType: 'all',
+  stylers: [{ visibility: 'simplified' }],
+}, {
+  featureType: 'road.highway',
+  elementType: 'geometry',
+  stylers: [{ lightness: '100' }, { gamma: '5.22' }],
+}, {
+  featureType: 'road.highway',
+  elementType: 'geometry.stroke',
+  stylers: [{ visibility: 'on' }],
+}, {
+  featureType: 'road.arterial',
+  elementType: 'labels.icon',
+  stylers: [{ visibility: 'off' }],
+}, {
+  featureType: 'transit',
+  elementType: 'all',
+  stylers: [{ visibility: 'off' }],
+}, {
+  featureType: 'water',
+  elementType: 'all',
+  stylers: [{ color: '#b3dced' }, { visibility: 'on' }],
+}, {
+  featureType: 'water',
+  elementType: 'labels.text.fill',
+  stylers: [{ visibility: 'on' }, { color: '#ffffff' }],
+}, {
+  featureType: 'water',
+  elementType: 'labels.text.stroke',
+  stylers: [{ visibility: 'off' }, { color: '#e6e6e6' }],
+}];
+
+function decorateMap(parent) {
+  /* @formatter:off */
+  const controls = div({ class: 'map-controls-wrapper' },
+    div({ class: 'custom-controls' },
+      a({
+        class: 'map-style',
+        role: 'button',
+        'aria-label': 'Satellite View',
+      },
+      img({ src: '/icons/globe.png' }),
+      span({ class: 'satellite' }, 'Satellite'),
+      span({ class: 'map' }, 'Map'),
+      ),
+      a({
+        class: 'map-draw-complete disabled',
+        role: 'button',
+        'aria-label': 'Complete Draw',
+      },
+      img({ src: '/icons/checkmark.svg' }),
+      span('Done')),
+      a({
+        class: 'map-draw',
+        role: 'button',
+        'aria-label': 'Draw',
+      },
+      img({ class: 'draw', src: '/icons/pencil.svg' }),
+      img({ class: 'close', src: '/icons/close-x.svg' }),
+      span({ class: 'draw' }, 'Draw'),
+      span({ class: 'close' }, 'Close'),
+      ),
+      div({ class: 'zoom-controls' },
+        a({ class: 'zoom-in', role: 'button', 'aria-label': 'Zoom In' }),
+        a({ class: 'zoom-out', role: 'button', 'aria-label': 'Zoom Out' }),
+      ),
+    ),
+  );
+  const info = div({ class: 'map-draw-info' },
+    p({ class: 'map-draw-tooltip' }, 'Click points on the map to draw your search.'),
+    p({ class: 'map-draw-boundary-link' },
+      a({ role: 'button', 'aria-label': 'Remove Map Boundary' }, 'Add Map Boundary'),
+    ),
+  );
+
+  /* @formatter:on */
+  parent.append(controls, info);
+}
+
+async function boundsChanged() {
+  if (polygon) return;
+  window.clearTimeout(boundsTimeout);
+  boundsTimeout = window.setTimeout(() => {
+    const bounds = gmap.getBounds();
+    const search = new BoxSearch();
+    search.populateFromURLSearchParameters(new URLSearchParams(window.location.search));
+    search.maxLat = bounds.getNorthEast().lat();
+    search.maxLon = bounds.getNorthEast().lng();
+    search.minLat = bounds.getSouthWest().lat();
+    search.minLon = bounds.getSouthWest().lng();
+    window.dispatchEvent(new CustomEvent(UPDATE_SEARCH_EVENT, { detail: { search } }));
+  }, 1000);
+}
+
+function doneDrawing() {
+  polygon = closePolygon();
+  drawingClickListener.remove();
+  gmap.setOptions({ gestureHandling: 'cooperative' });
+  document.querySelector('.property-search-results.block .search-map-container').classList.remove('drawing');
+  const search = new PolygonSearch();
+  search.populateFromURLSearchParameters(new URLSearchParams(window.location.search));
+  polygon.getPath().forEach((latLng) => {
+    search.addPoint({ lat: latLng.lat(), lon: latLng.lng() });
+  });
+  window.dispatchEvent(new CustomEvent(UPDATE_SEARCH_EVENT, { detail: { search } }));
+}
+
+function endDrawing() {
+  clearPolygon();
+  polygon = undefined;
+  drawingClickListener.remove();
+  gmap.setOptions({ gestureHandling: 'cooperative' });
+  document.querySelector('.property-search-results.block .search-map-container').classList.remove('drawing');
+  boundsChanged();
+}
+
+function drawingClickHandler(e) {
+  if (addPolygonPoint(e.latLng)) {
+    doneDrawing();
+  }
+}
+
+function startDrawing() {
+  gmap.setOptions({ gestureHandling: 'none' });
+  drawingClickListener = gmap.addListener('click', drawingClickHandler);
+  startPolygon(gmap);
+}
+
+function observeControls(block) {
+  block.querySelector('.search-map-container a.map-draw').addEventListener('click', (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    const start = e.currentTarget.closest('.search-map-container').classList.toggle('drawing');
+    if (start) {
+      startDrawing(gmap);
+    } else {
+      endDrawing();
+    }
+  });
+
+  block.querySelector('.search-map-container a.map-draw-complete').addEventListener('click', (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    doneDrawing();
+  });
+
+  block.querySelector('.search-map-container a.map-style').addEventListener('click', (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    e.currentTarget.closest('.search-map-container').classList.toggle('map');
+    e.currentTarget.closest('.search-map-container').classList.toggle('satellite');
+    const type = gmap.getMapTypeId();
+    if (type === google.maps.MapTypeId.ROADMAP) {
+      gmap.setMapTypeId(google.maps.MapTypeId.SATELLITE);
+    } else {
+      gmap.setMapTypeId(google.maps.MapTypeId.ROADMAP);
+    }
+  });
+
+  block.querySelector('.search-map-container a.zoom-in').addEventListener('click', (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    gmap.setZoom(gmap.getZoom() + 1);
+  });
+
+  block.querySelector('.search-map-container a.zoom-out').addEventListener('click', (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    gmap.setZoom(gmap.getZoom() - 1);
+  });
+}
+
+function clearMarkers() {
+  clearInfos();
+  clusterer.clearMarkers();
+  if (mapMarkers.length) {
+    mapMarkers.forEach((marker) => {
+      marker.setVisible(false);
+      marker.setMap(null);
+    });
+  }
+  mapMarkers.length = 0;
+}
+
+function getMarkerBounds(markers) {
+  const bounds = new google.maps.LatLngBounds();
+  markers.forEach((m) => {
+    bounds.extend(m.getPosition());
+  });
+  return bounds;
+}
+
+/**
+ * Updates the map view with the new results.
+ * @param results
+ */
+async function displayResults(results) {
+  renderInProgress = true;
+  // Map isn't loaded yet.
+  if (!gmap) {
+    window.setTimeout(() => {
+      displayResults(results);
+    }, 1000);
+    return;
+  }
+
+  // Map needs to be initialized.
+  if (gmap.getRenderingType() === google.maps.RenderingType.UNINITIALIZED) {
+    gmap.addListener('renderingtype_changed', () => {
+      displayResults(results);
+    });
+    return;
+  }
+  // Clear any info windows
+  // Clear any existing Markers.
+  if (!results.properties || results.properties.length === 0) return;
+
+  clearMarkers();
+
+  if (results.clusters.length) {
+    mapMarkers.push(...(await displayClusters(gmap, results.clusters)));
+  } else if (results.pins.length) {
+    mapMarkers.push(...(await displayPins(gmap, results.pins)));
+    clusterer.addMarkers(mapMarkers);
+  }
+
+  const bounds = getMarkerBounds(mapMarkers);
+  if (!gmap.getBounds().contains(bounds.getCenter())) {
+    gmap.fitBounds(bounds);
+  }
+  renderInProgress = false;
+}
+
+/**
+ * Reinitialize the Map based on history navigation.
+ *
+ * @param search the search that will be performed.
+ */
+function reinitMap(search) {
+  clearMarkers();
+  clearPolygon();
+  if (search instanceof PolygonSearch) {
+    startPolygon(gmap);
+    search.points.forEach((point) => {
+      const { lat, lon } = point;
+      addPolygonPoint(new google.maps.LatLng({ lat: parseFloat(lat), lng: parseFloat(lon) }));
+    });
+    polygon = closePolygon();
+  }
+}
+
+/**
+ * Loads Google Maps and draws the initial view.
+ * @param block
+ * @return {Promise<void>}
+ */
+async function initMap(block, search) {
+  const ele = block.querySelector('#gmap-canvas');
+
+  gmap = new google.maps.Map(ele, {
+    zoom,
+    maxZoom,
+    center: { lat: 41.24216, lng: -96.207990 },
+    mapTypeId: google.maps.MapTypeId.ROADMAP,
+    clickableIcons: false,
+    gestureHandling: 'cooperative',
+    styles: MAP_STYLE,
+    visualRefresh: true,
+    disableDefaultUI: true,
+  });
+
+  decorateMap(block.querySelector('.search-results-map'));
+  block.querySelector('.search-map-wrapper').append(div({ class: 'mobile-info-window info-window' }));
+  observeControls(block);
+
+  gmap.addListener('click', () => {
+    hideInfos();
+  });
+
+  // Don't use 'bounds_changed' event for updating results - fires too frequently.
+  gmap.addListener('dragend', () => {
+    hideInfos();
+    boundsChanged();
+  });
+  gmap.addListener('dblclick', () => {
+    hideInfos();
+    boundsChanged();
+  });
+
+  gmap.addListener('zoom_changed', () => {
+    if (renderInProgress) {
+      return;
+    }
+    hideInfos();
+    boundsChanged();
+  });
+
+  clusterer = getMarkerClusterer(gmap);
+  if (search instanceof PolygonSearch) {
+    startPolygon(gmap);
+    search.points.forEach((point) => {
+      const { lat, lon } = point;
+      addPolygonPoint(new google.maps.LatLng({ lat: parseFloat(lat), lng: parseFloat(lon) }));
+    });
+    polygon = closePolygon();
+  }
+}
+
+// Anytime a search is performed, hide any existing markers.
+// window.addEventListener(EVENT_NAME, hideMarkers);
+
+/* Load all the map libraries here */
+loadMaps();
+await google.maps.importLibrary('core');
+await google.maps.importLibrary('maps');
+await google.maps.importLibrary('marker');
+await loadScript('https://unpkg.com/@googlemaps/markerclusterer/dist/index.min.js', { type: 'application/javascript' });
+await loadScript('https://unpkg.com/jsts/dist/jsts.min.js', { type: 'application/javascript' });
+export {
+  displayResults,
+  initMap,
+  reinitMap,
+};
diff --git a/blocks/property-search-results/map/clusters.js b/blocks/property-search-results/map/clusters.js
new file mode 100644
index 00000000..79c0b65d
--- /dev/null
+++ b/blocks/property-search-results/map/clusters.js
@@ -0,0 +1,73 @@
+/* global google */
+
+import Search, { UPDATE_SEARCH_EVENT } from '../../../scripts/apis/creg/search/Search.js';
+import { DRAWING_ENDED, DRAWING_STARTED } from './drawing.js';
+
+let drawing = false;
+
+const clusterClickHandler = async (map, cluster) => {
+  if (drawing) return;
+  const center = new google.maps.LatLng(cluster.centerLat, cluster.centerLon);
+  map.panTo(center);
+  const search = await Search.load('Box');
+  search.populateFromURLSearchParameters(new URLSearchParams(window.location.search));
+  search.minLat = cluster.swLat;
+  search.minLon = cluster.swLon;
+  search.maxLat = cluster.neLat;
+  search.maxLon = cluster.neLon;
+  window.dispatchEvent(new CustomEvent(UPDATE_SEARCH_EVENT, { detail: { search } }));
+};
+
+const compensateForCluster = (count) => {
+  let increase = 0;
+  const log = Math.log10(count);
+  increase = 6 * (Math.round(log * 2) / 2);
+  return increase;
+};
+
+/**
+ * Create a cluster marker from a search result cluster.
+ * @param {Object} cluster
+ * @param {Number} cluster.centerLat Latitude center of the cluster
+ * @param {Number} cluster.centerLon Longitude center of the cluster
+ * @param {Number} cluster.count Number of properties in cluster.
+ */
+export function createClusterMaker(cluster) {
+  // const dimensions = { width: 30, height: 30 };
+  const sizeCompensation = compensateForCluster(cluster.count);
+  const size = 30 + sizeCompensation;
+  const icon = {
+    url: '/icons/maps/map-clusterer-blue.png',
+    scaledSize: new google.maps.Size(size, size),
+    anchor: new google.maps.Point(size / 2, size / 2),
+  };
+
+  return new google.maps.Marker({
+    position: new google.maps.LatLng(cluster.centerLat, cluster.centerLon),
+    zIndex: cluster.count,
+    icon,
+    label: {
+      fontFamily: 'sans-serif',
+      fontSize: '12px',
+      text: `${cluster.count}`,
+      color: 'white',
+      className: 'no-class',
+    },
+  });
+}
+
+export default async function displayClusters(map, clusters) {
+  map.getDiv().addEventListener(DRAWING_STARTED, () => { drawing = true; });
+  map.getDiv().addEventListener(DRAWING_ENDED, () => { drawing = false; });
+
+  const markers = [];
+  clusters.forEach((cluster) => {
+    const marker = createClusterMaker(cluster);
+    marker.setMap(map);
+    marker.addListener('click', () => {
+      clusterClickHandler(marker.map, cluster);
+    });
+    markers.push(marker);
+  });
+  return markers;
+}
diff --git a/blocks/property-search-results/map/drawing.js b/blocks/property-search-results/map/drawing.js
new file mode 100644
index 00000000..81d870f2
--- /dev/null
+++ b/blocks/property-search-results/map/drawing.js
@@ -0,0 +1,150 @@
+/* global google */
+/* global jsts */
+
+const DRAWING_STARTED = 'MapDrawingStarted';
+const DRAWING_ENDED = 'MapDrawingEnded';
+
+let gmap;
+
+let mouseListener;
+const lines = [];
+let activeLine;
+let polygon;
+
+function mouseHandler(e) {
+  if (activeLine.getPath().length) {
+    activeLine.getPath().setAt(1, e.latLng);
+  }
+}
+
+/**
+ * Check if the line intersects any of the existing ones.
+ * @param {Array<google.map.Polyline>} existing list of existing lines
+ * @param {google.map.Polyline} potential potential line that may intersect
+ * @return {boolean} whether or not the line intersects
+ */
+function intersects(existing, potential) {
+  const coords = [];
+  if (existing.length) {
+    coords.push(new jsts.geom.Coordinate(existing[0].getPath().getAt(0).lat(), existing[0].getPath().getAt(0).lng()));
+    existing.forEach((line) => {
+      coords.push(new jsts.geom.Coordinate(line.getPath().getAt(1).lat(), line.getPath().getAt(1).lng()));
+    });
+    coords.push(new jsts.geom.Coordinate(potential.getPath().getAt(1).lat(), potential.getPath().getAt(1).lng()));
+    const simple = jsts.operation.IsSimpleOp.isSimple(new jsts.geom.GeometryFactory().createLineString(coords));
+    return !simple; // Simple LineStrings do not intersect.
+  }
+  return false;
+}
+
+/**
+ * Clears the map of any lines or polygon
+ */
+function clearPolygon() {
+  lines.forEach((l) => { l.setMap(null); });
+  lines.length = 0;
+  if (activeLine) {
+    activeLine.getPath().clear();
+    activeLine.setMap(null);
+  }
+  if (polygon) {
+    polygon.setMap(null);
+    polygon = undefined;
+  }
+}
+
+/**
+ * Closes the active polygon, creating the instance and returning it.
+ * @return {google.maps.Polygon} the completed polygon
+ */
+function closePolygon() {
+  // eslint-disable-next-line no-unused-expressions
+  mouseListener && mouseListener.remove();
+
+  activeLine.getPath().clear();
+  activeLine.setMap(null);
+  if (lines.length === 1) {
+    lines[0].setMap(null);
+    lines.length = 0;
+  }
+
+  const points = [];
+  points.push(lines[0].getPath().getAt(0));
+  lines.forEach((line) => {
+    points.push(line.getPath().getAt(1));
+  });
+  polygon = new google.maps.Polygon({
+    map: gmap,
+    paths: points,
+    strokeColor: '#BA9BB2',
+    strokeWeight: 2,
+    clickable: false,
+    fillOpacity: 0,
+  });
+  return polygon;
+}
+
+/**
+ * Adds a point to the polygon.
+ * If the next line intersects an existing line, it closes the polygon and returns it.
+ * @param {google.maps.LatLng} point
+ * @return {boolean} if adding this point closed the polygon
+ */
+function addPolygonPoint(point) {
+  const prev = activeLine.getPath().getAt(0);
+  if (prev) {
+    const line = new google.maps.Polyline({
+      clickable: false,
+      strokeColor: '#BA9BB2',
+      strokeWeight: 2,
+      path: [prev, point],
+    });
+    if (intersects(lines, line)) {
+      return true;
+    }
+    line.setMap(gmap);
+    lines.push(line);
+  }
+  if (lines.length > 1) {
+    document.querySelector('.property-search-results.block .search-map-container .custom-controls .map-draw-complete.disabled')?.classList.remove('disabled');
+  }
+  activeLine.getPath().setAt(0, point);
+  return false;
+}
+
+/**
+ * Starts drawing the polygon by adding a line to the map.
+ * Also initiates the tracking line for potential next line in polygon definition.
+ *
+ * @param {google.maps.Map} map
+ */
+function startPolygon(map) {
+  clearPolygon();
+  gmap = map;
+  activeLine = new google.maps.Polyline({
+    map: gmap,
+    clickable: false,
+    strokeOpacity: 0,
+    icons: [{
+      icon: {
+        path: 'M 0,-1 0,1',
+        strokeOpacity: 1,
+        scale: 2,
+        strokeColor: '#BA9BB2',
+      },
+      offset: 0,
+      repeat: '20px',
+    }],
+  });
+  mouseListener = gmap.addListener('mousemove', mouseHandler);
+  gmap.getDiv().dispatchEvent(new CustomEvent(DRAWING_STARTED));
+}
+
+export {
+  DRAWING_STARTED,
+  DRAWING_ENDED,
+  startPolygon,
+  addPolygonPoint,
+  closePolygon,
+  clearPolygon,
+};
diff --git a/blocks/property-search-results/map/pins.js b/blocks/property-search-results/map/pins.js
new file mode 100644
index 00000000..22988f30
--- /dev/null
+++ b/blocks/property-search-results/map/pins.js
@@ -0,0 +1,342 @@
+/* global google */
+/* global markerClusterer */
+
+import { formatPrice } from '../../../scripts/util.js';
+import { createClusterMaker } from './clusters.js';
+import { BREAKPOINTS } from '../../../scripts/scripts.js';
+import { getDetails } from '../../../scripts/apis/creg/creg.js';
+import {
+  a, p, div, img, span, domEl,
+} from '../../../scripts/dom-helpers.js';
+import { DRAWING_ENDED, DRAWING_STARTED } from './drawing.js';
+
+let drawing;
+let moTimeout;
+let moController;
+
+const infoWindows = [];
+
+function createInfo(property) {
+  const href = property.PdpPath.includes('www.commonmoves.com') ? `/property/detail/pid-${property.ListingId}` : property.PdpPath;
+  const providers = [];
+  if (property.propertyProviders || property.originatingSystemName) {
+    providers.push('Listing Provided by: ');
+    providers.push(property.propertyProviders || property.originatingSystemName);
+  }
+
+  const details = div({ class: 'details' },
+    div({ class: 'address' },
+      span({ class: 'street' }, property.StreetName || ''),
+      span({ class: 'locality' }, `${`${property.City}, ` || ' '} ${`${property.StateOrProvince} ` || ' '} ${property.PostalCode || ''}`),
+    ),
+  );
+
+  if (property.sellingOfficeName) {
+    const address = details.querySelector('.address');
+    address.prepend(
+      span({ class: 'danger' }, `${property.mlsStatus || ''} ${property.ClosedDate || ''}`),
+    );
+  }
+
+  if (property.municipality) {
+    details.append(span({ class: 'municipality' }, property.municipality));
+  }
+
+  details.append(span({ class: 'providers' }, ...providers));
+
+  const listing = div({ class: 'listing-info' });
+  if (property.addMlsFlag === 'true') {
+    listing.append(span({ class: 'mls' }, `MLS ID: ${property.ListingId}`));
+  }
+  if (property.CourtesyOf) {
+    listing.append(span({ class: 'courtesy' }, `Listing courtesy of: ${property.CourtesyOf}`));
+  }
+  if (property.sellingOfficeName) {
+    listing.append(span({ class: 'courtesy' }, `Listing sold by: ${property.sellingOfficeName}`));
+  }
+  if (property.addMlsFlag && property.listAor) {
+    const aor = div({ class: 'aor' }, span(`Listing provided by: ${property.listAor}`));
+    if (property.brImageUrl) {
+      aor.append(span({ class: 'aor-img' }, img({ src: property.brImageUrl })));
+    }
+    listing.append(aor);
+  }
+
+  const image = div({ class: 'image-wrapper' },
+    div({ class: 'luxury' }, span('Luxury Collection')),
+    img({ src: property.smallPhotos[0]?.mediaUrl }),
+  );
+  const info = div({ class: 'info' },
+    div({ class: 'price' },
+      span({ class: 'us' }, property.ListPriceUS || ''),
+      span({ class: 'alt' }, property.listPriceAlternateCurrency || ''),
+    ),
+    div({ class: 'property-buttons' },
+      a({ class: 'contact-us', 'aria-label': `Contact us about ${property.StreetName}` },
+        span({ class: 'icon icon-envelope' }, img({
+          'data-icon-name': 'envelope',
+          src: '/icons/envelope.svg',
+          alt: 'envelope',
+        })),
+        span({ class: 'icon icon-envelopedark' }, img({
+          'data-icon-name': 'envelopedark',
+          src: '/icons/envelopedark.svg',
+          alt: 'envelope',
+        })),
+      ),
+      a({ class: 'save', 'aria-label': `Save ${property.StreetName}` },
+        span({ class: 'icon icon-heartempty' }, img({
+          'data-icon-name': 'heartempty',
+          src: '/icons/heartempty.svg',
+          alt: 'heart',
+        })),
+        span({ class: 'icon icon-heartemptydark' }, img({
+          'data-icon-name': 'heartemptydark',
+          src: '/icons/heartemptydark.svg',
+          alt: 'heart',
+        })),
+        span({ class: 'icon icon-heartfull' }, img({
+          'data-icon-name': 'heartfull',
+          src: '/icons/heartfull.svg',
+          alt: 'heart',
+        })),
+      ),
+    ),
+    details,
+    domEl('hr'),
+    listing,
+  );
+
+  return a({ class: 'info-wrapper', rel: 'noopener', href }, image, info);
+}
+
+/**
+ * Removes all Info Windows that may be on the map or attached to markers.
+ */
+function clearInfos() {
+  document.querySelector('.property-search-results.block .mobile-info-window').replaceChildren();
+  infoWindows.forEach((iw) => {
+    iw.close();
+    iw.visible = false;
+  });
+  infoWindows.length = 0;
+}
+
+/**
+ * Hides any visible Info Windows on the map.
+ */
+function hideInfos() {
+  document.querySelector('.property-search-results.block .mobile-info-window').replaceChildren();
+  infoWindows.forEach((iw) => {
+    if (iw.visible) {
+      iw.close();
+      iw.visible = false;
+    }
+  });
+}
+
+async function clusterMouseHandler(marker, cluster) {
+  moController?.abort();
+  moController = new AbortController();
+  const controller = moController;
+  if (marker.infoWindow?.visible) {
+    return;
+  }
+  hideInfos();
+  if (!marker.infoWindow && !controller.signal.aborted) {
+    const content = div({ class: 'info-window cluster' }, div({ class: 'loading' }, p('Loading...')));
+    const tmp = new google.maps.InfoWindow({ content });
+    tmp.open({ anchor: marker, shouldFocus: false });
+    const center = marker.getMap().getCenter();
+    // But if this fetch was canceled, don't show the info window.
+    const ids = [];
+    cluster.markers.forEach((m) => {
+      ids.push(m.listingKey);
+    });
+    await getDetails(...ids).then((listings) => {
+      // If we got this far, may as well add the content to info window.
+      const infos = [];
+      listings.forEach((property) => {
+        infos.push(createInfo(property));
+      });
+      content.replaceChildren(...infos);
+      const iw = new google.maps.InfoWindow({ content });
+      iw.setContent(content);
+      iw.addListener('close', () => marker.getMap().panTo(center));
+      infoWindows.push(iw);
+      marker.infoWindow = iw;
+      tmp.close();
+    });
+  }
+  if (controller.signal.aborted) {
+    return;
+  }
+  marker.infoWindow.open({ anchor: marker, shouldFocus: false });
+  marker.infoWindow.visible = true;
+}
+
+/**
+ * Display the Mobile Info Window with the desired content.
+ * @param {Promise<Array<HTMLElement>>} promise a promise that resolves to the content to display
+ * @param cluster flag to indicate if this is a list of properties
+ */
+async function showMobileInfoWindow(promise, cluster = false) {
+  window.scrollTo({ top: 115, behavior: 'smooth' });
+  const iw = document.querySelector('.property-search-results.block .search-map-wrapper .mobile-info-window');
+  if (cluster) iw.classList.add('cluster');
+  iw.replaceChildren(div({ class: 'loading' }, p('Loading...')));
+  promise.then((content) => {
+    // eslint-disable-next-line no-param-reassign
+    content = content.length ? content : [content];
+    iw.replaceChildren(...content);
+  });
+}
+
+/*
+  See https://googlemaps.github.io/js-markerclusterer/interfaces/MarkerClustererOptions.html#renderer
+ */
+const ClusterRenderer = {
+  render: (cluster) => {
+    const marker = createClusterMaker({
+      centerLat: cluster.position.lat(),
+      centerLon: cluster.position.lng(),
+      count: cluster.count,
+    });
+
+    // Do not fire the fetch immediately, give the user a beat to move their mouse to desired target.
+    marker.addListener('mouseout', () => window.clearTimeout(moTimeout));
+    marker.addListener('mouseover', () => {
+      if (drawing) return;
+      if (BREAKPOINTS.medium.matches) {
+        moTimeout = window.setTimeout(() => clusterMouseHandler(marker, cluster), 500);
+      }
+    });
+    return marker;
+  },
+};
+
+function pinGroupClickHandler(e, cluster) {
+  if (drawing) return;
+  if (BREAKPOINTS.medium.matches && e.domEvent instanceof TouchEvent) {
+    clusterMouseHandler(cluster.marker, cluster);
+  } else {
+    const listings = cluster.markers.map((m) => m.listingKey);
+    const promise = getDetails(...listings).then((details) => {
+      const links = [];
+      details.forEach((property) => {
+        links.push(createInfo(property));
+      });
+      return links;
+    });
+    showMobileInfoWindow(promise, true);
+  }
+}
+
+/**
+ * Generate a new Marker Clusterer from the map.
+ * @param map
+ * @return {markerClusterer.MarkerClusterer}
+ */
+function getMarkerClusterer(map) {
+  return new markerClusterer.MarkerClusterer({ map, renderer: ClusterRenderer, onClusterClick: pinGroupClickHandler });
+}
+
+async function pinMouseHandler(marker, pin) {
+  moController?.abort();
+  moController = new AbortController();
+  const controller = moController;
+  if (marker.infoWindow?.visible) {
+    return;
+  }
+  hideInfos();
+  if (!marker.infoWindow && !controller.signal.aborted) {
+    const content = div({ class: 'info-window' }, div({ class: 'loading' }, p('Loading...')));
+    const tmp = new google.maps.InfoWindow({ content });
+    tmp.open({ anchor: marker, shouldFocus: false });
+    const center = marker.getMap().getCenter();
+    // But if this fetch was canceled, don't show the info window.
+    await getDetails(pin.listingKey).then((listings) => {
+      content.replaceChildren(createInfo(listings[0]));
+      const iw = new google.maps.InfoWindow({ content });
+      iw.setContent(content);
+      iw.addListener('close', () => marker.getMap().panTo(center));
+      infoWindows.push(iw);
+      marker.infoWindow = iw;
+      tmp.close();
+    });
+  }
+  if (controller.signal.aborted) {
+    return;
+  }
+  marker.infoWindow.open({ anchor: marker, shouldFocus: false });
+  marker.infoWindow.visible = true;
+}
+
+/**
+ * Create a cluster marker from a search result cluster.
+ * @param {Object} pin
+ * @param {Number} pin.lat Latitude of the pin
+ * @param {Number} pin.lon Longitude of the pin
+ * @param {Number} pin.price Price of the pin listing
+ * @param {Number} pin.listingKey Listing id of the pin
+ * @param {Number} pin.officeCode Office code of the listing.
+ */
+function createPinMarker(pin) {
+  const icon = {
+    url: '/icons/maps/map-marker-standard.png',
+    scaledSize: new google.maps.Size(50, 25),
+    anchor: new google.maps.Point(25, 0),
+  };
+
+  const marker = new google.maps.Marker({
+    position: new google.maps.LatLng(pin.lat, pin.lon),
+    zIndex: 1,
+    icon,
+    label: {
+      fontFamily: 'sans-serif',
+      fontSize: '12px',
+      text: `$${formatPrice(pin.price)}`,
+      color: 'white',
+      className: 'no-class',
+    },
+  });
+  marker.addListener('click', (e) => {
+    if (drawing) return;
+    if (BREAKPOINTS.medium.matches && e.domEvent instanceof TouchEvent) {
+      pinMouseHandler(marker, pin);
+    } else {
+      showMobileInfoWindow(getDetails(pin.listingKey).then((details) => createInfo(details[0])));
+    }
+  });
+  // Do not fire the fetch immediately, give the user a beat to move their mouse to desired target.
+  marker.addListener('mouseout', () => window.clearTimeout(moTimeout));
+  marker.addListener('mouseover', () => {
+    if (drawing) return;
+    if (BREAKPOINTS.medium.matches) {
+      moTimeout = window.setTimeout(() => pinMouseHandler(marker, pin), 500);
+    }
+  });
+
+  marker.listingKey = pin.listingKey;
+  return marker;
+}
+
+async function displayPins(map, pins) {
+  map.getDiv().addEventListener(DRAWING_STARTED, () => { drawing = true; });
+  map.getDiv().addEventListener(DRAWING_ENDED, () => { drawing = false; });
+
+  const markers = [];
+  pins.forEach((pin) => {
+    const marker = createPinMarker(pin);
+    marker.setMap(map);
+    markers.push(marker);
+  });
+  return markers;
+}
+
+export {
+  clearInfos,
+  hideInfos,
+  getMarkerClusterer,
+  displayPins,
+};
diff --git a/blocks/property-search-results/observers.js b/blocks/property-search-results/observers.js
new file mode 100644
index 00000000..5b513a7f
--- /dev/null
+++ b/blocks/property-search-results/observers.js
@@ -0,0 +1,87 @@
+import Search, { UPDATE_SEARCH_EVENT } from '../../scripts/apis/creg/search/Search.js';
+import { input } from '../../scripts/dom-helpers.js';
+import ListingType from '../../scripts/apis/creg/search/types/ListingType.js';
+import { closeOnBodyClick } from '../shared/search/util.js';
+
+export default function observe(block) {
+  block.querySelectorAll('a.map-view').forEach((btn) => {
+    btn.addEventListener('click', (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      const blk = e.currentTarget.closest('.block');
+      blk.classList.remove('list-view');
+      blk.classList.add('map-view');
+    });
+  });
+
+  block.querySelectorAll('a.list-view').forEach((btn) => {
+    btn.addEventListener('click', (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      const blk = e.currentTarget.closest('.block');
+      blk.classList.remove('map-view');
+      blk.classList.add('list-view');
+    });
+  });
+
+  block.querySelectorAll('.listing-types .filter-toggle').forEach((t) => {
+    t.addEventListener('click', async (e) => {
+      e.preventDefault();
+      const { currentTarget } = e;
+      const search = await Search.fromQueryString(window.location.search);
+      const checked = currentTarget.querySelector('div.checkbox').classList.toggle('checked');
+      const ipt = currentTarget.querySelector('input');
+      input.checked = checked;
+      if (checked) {
+        search.addListingType(ipt.value);
+      } else {
+        search.removeListingType(ipt.value);
+      }
+      window.dispatchEvent(new CustomEvent(UPDATE_SEARCH_EVENT, { detail: { search } }));
+    });
+  });
+
+  block.querySelector('.listing-types').addEventListener('click', (e) => {
+    e.preventDefault();
+    const ipt = e.target.closest('.filter-toggle')?.querySelector('input');
+    if (ipt && ipt.value === ListingType.FOR_RENT.type) {
+      e.currentTarget.querySelector(`input[value="${ListingType.PENDING.type}"]`).closest('.filter-toggle').classList.toggle('disabled');
+    } else if (ipt && ipt.value === ListingType.PENDING.type) {
+      e.currentTarget.querySelector(`input[value="${ListingType.FOR_RENT.type}"]`).closest('.filter-toggle').classList.toggle('disabled');
+    }
+  });
+
+  const sortSelect = block.querySelector('.sort-options .select-wrapper div.selected');
+  sortSelect.addEventListener('click', (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    const button = e.currentTarget;
+    const wrapper = button.closest('.select-wrapper');
+    const open = wrapper.classList.toggle('open');
+    button.setAttribute('aria-expanded', open);
+    if (open) {
+      closeOnBodyClick(wrapper);
+    }
+  });
+
+  sortSelect.querySelectorAll('.select-items li').forEach((opt) => {
+    opt.addEventListener('click', async (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      const target = e.currentTarget;
+      const value = target.getAttribute('data-value');
+      const wrapper = target.closest('.select-wrapper');
+      wrapper.querySelector('.selected span').textContent = target.textContent;
+      wrapper.querySelector('ul li.selected')?.classList.toggle('selected');
+      const selected = wrapper.querySelector(`select option[value="${value}"]`);
+      selected.selected = true;
+      target.classList.add('selected');
+      wrapper.classList.remove('open');
+      wrapper.querySelector('[aria-expanded="true"]')?.setAttribute('aria-expanded', 'false');
+      const search = await Search.fromQueryString(window.location.search);
+      search.sortBy = selected.getAttribute('data-sort-by');
+      search.sortDirection = selected.getAttribute('data-sort-direction');
+      window.dispatchEvent(new CustomEvent(UPDATE_SEARCH_EVENT, { detail: { search } }));
+    });
+  });
+}
diff --git a/blocks/property-search-results/property-search-results.css b/blocks/property-search-results/property-search-results.css
new file mode 100644
index 00000000..425edb6a
--- /dev/null
+++ b/blocks/property-search-results/property-search-results.css
@@ -0,0 +1,502 @@
+@import url('../shared/property/cards.css');
+@import url('map.css');
+
+
+/* Override global settings */
+main .section.property-search-results-container {
+  padding: 0;
+  margin: 0 auto;
+}
+
+.property-search-results-wrapper {
+  padding: 0;
+  margin: 0;
+}
+
+/* End global overrides */
+
+.property-search-results.block {
+  position: relative;
+  min-height: calc(100vh - var(--nav-height) - 50px - 40px);
+
+  --map-height: calc(100vh - var(--nav-height) - 50px - 75px - 55px); /* Nav, search bar, sort options, mobile links */
+}
+
+.property-search-results.block.map-view .search-map-wrapper {
+  height: var(--map-height);
+}
+
+.property-search-results.block .search-results-loader {
+  position: absolute;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  top: 0;
+  left: 50%;
+  height: 100%;
+  width: 100%;
+  max-width: 400px;
+  transform: translateX(-50%);
+  margin: 0 auto;
+  opacity: 0;
+  visibility: hidden;
+  transition: all 2s linear;
+  z-index: 2
+}
+
+.property-search-results.block .loading .search-results-loader {
+  opacity: 1;
+  visibility: visible;
+  transition: all 2s linear;
+}
+
+.property-search-results.block .search-results-loader .animation {
+  position: relative;
+  width: 100%;
+}
+
+@keyframes pulse {
+  from {
+    border: 0 solid white;
+  }
+
+  to {
+    border: 75px solid white
+  }
+}
+
+.property-search-results.block .search-results-loader .pulse {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  border-radius: 50%;
+  overflow: hidden;
+  animation: linear 2s infinite alternate pulse;
+  z-index: 2;
+}
+
+.property-search-results.block .search-results-loader picture {
+  position: relative;
+  display: block;
+  width: 100%;
+  padding-bottom: 100%;
+  border-radius: 50%;
+  overflow: hidden;
+}
+
+.property-search-results.block .search-results-loader picture img {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  object-position: center;
+  object-fit: cover;
+}
+
+.property-search-results.block .search-results-content {
+  position: relative;
+}
+
+.property-search-results.block .search-results-wrapper {
+  min-height: 400px;
+  padding: 10px;
+  opacity: 1;
+  visibility: visible;
+  transition: all 2s linear;
+}
+
+.property-search-results.block .loading .search-results-wrapper {
+  opacity: 0;
+  visibility: hidden;
+  transition: all 2s linear;
+}
+
+.property-search-results.block.list-view .search-map-wrapper {
+  display: none;
+}
+
+.property-search-results.block.map-view .search-results-wrapper {
+  display: none;
+}
+
+.property-search-results.block .view-options a {
+  padding: 0 15px;
+  height: 35px;
+  font-size: var(--body-font-size-xs);
+  letter-spacing: var(--letter-spacing-m);
+  line-height: 35px;
+  border: 1px solid var(--grey);
+  white-space: nowrap;
+}
+
+.property-search-results.block.list-view .view-options a.list-view {
+  display: none;
+}
+
+.property-search-results.block.map-view .view-options a.map-view {
+  display: none;
+}
+
+.property-search-results.block .select-wrapper select {
+  display: none;
+}
+
+.property-search-results.block .select-wrapper > .selected {
+  display: flex;
+  position: relative;
+  padding: 0 15px;
+  align-items: center;
+  justify-content: space-between;
+  gap: 3px;
+  width: 100%;
+  height: 35px;
+  min-width: 100px;
+  line-height: 35px;
+  color: var(--body-color);
+  border: 1px solid var(--grey);
+}
+
+.property-search-results.block .select-wrapper > .selected::after {
+  display: block;
+  content: '\f0d7';
+  font-family: var(--font-family-fontawesome);
+  color: var(--dark-grey);
+  text-align: right;
+  width: 15px;
+}
+
+.property-search-results.block .select-wrapper.open > .selected::after {
+  content: '\f0d8';
+}
+
+.property-search-results.block .select-wrapper .select-items {
+  display: none;
+  position: absolute;
+  padding: 0;
+  max-height: 185px;
+  top: 100%;
+  left: -1px;
+  width: 145px;
+  overflow-y: scroll;
+  background-color: var(--white);
+  border: 1px solid var(--grey);
+  box-shadow: 0 .5rem 1rem rgba(0 0 0 / 15%);
+  white-space: nowrap;
+  z-index: 1;
+}
+
+.property-search-results.block .select-wrapper.open .select-items {
+  display: block;
+}
+
+.property-search-results.block .select-wrapper > .selected span {
+  overflow: hidden;
+  font-size: var(--body-font-size-xs);
+  font-weight: var(--font-weight-light);
+  line-height: var(--line-height-xl);
+  letter-spacing: var(--letter-spacing-m);
+  text-transform: uppercase;
+  white-space: nowrap;
+}
+
+.property-search-results.block .select-wrapper .select-items li {
+  display: flex;
+  padding: 4px 15px;
+  cursor: pointer;
+  font-size: var(--body-font-size-xs);
+  color: var(--body-color);
+  text-transform: uppercase;
+  line-height: var(--line-height-xl);
+  letter-spacing: var(--letter-spacing-xs);
+}
+
+.property-search-results.block .select-wrapper .select-items li:hover {
+  color: var(--body-color);
+  background-color: var(--light-grey);
+}
+
+.property-search-results.block .select-wrapper .select-items li.selected {
+  color: var(--body-color);
+  background-color: var(--light-grey);
+}
+
+
+.property-search-results.block .property-search-filters {
+  display: grid;
+  grid-template-columns: 1fr;
+  padding: 0 15px;
+  gap: 30px;
+  margin: 20px 0;
+}
+
+.property-search-results.block .listing-types {
+  display: none;
+  padding: 0 15px;
+  gap: 15px;
+}
+
+.property-search-results.block .listing-types .filter-toggle {
+  display: flex;
+  gap: 10px;
+  align-items: center;
+  font-size: var(--body-font-size-s);
+}
+
+.property-search-results.block .listing-types .filter-toggle label {
+  font-size: var(--body-font-size-xs);
+  letter-spacing: var(--letter-spacing-xs);
+  line-height: normal;
+  color: var(--body-color);
+}
+
+.property-search-results.block .listing-types .filter-toggle .checkbox {
+  min-width: 24px;
+  height: 16px;
+  border-radius: 100px;
+  position: relative;
+  border: 1px solid #b4b4b4;
+  background: var(--white);
+}
+
+.property-search-results.block .listing-types .filter-toggle .checkbox::before {
+  content: '';
+  position: absolute;
+  right: 2px;
+  top: 2px;
+  height: 10px;
+  width: 10px;
+  border-radius: 10px;
+  z-index: 1;
+  background: #b4b4b4;
+}
+
+.property-search-results.block .listing-types .filter-toggle .checkbox.checked {
+  background: var(--body-color);
+  border: 1px solid transparent
+}
+
+.property-search-results.block .listing-types .filter-toggle .checkbox.checked::before {
+  transform: translateX(-8px);
+  background: var(--white);
+}
+
+.property-search-results.block .listing-types .filter-toggle.disabled {
+  pointer-events: none;
+  opacity: .3;
+}
+
+.property-search-results.block .sort-options {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  justify-self: flex-end;
+}
+
+/* stylelint-disable-next-line no-descending-specificity */
+.property-search-results.block .sort-options label {
+  font-size: var(--body-font-size-s);
+  line-height: var(--line-height-m);
+  color: var(--body-color);
+  white-space: nowrap;
+}
+
+.property-search-results.block .sort-options .select-wrapper {
+  position: relative;
+  width: 145px;
+}
+
+.property-search-results.block .search-results-content .search-results-disclaimer-wrapper {
+  margin: 30px 0;
+}
+
+.property-search-results.block .search-results-disclaimer-wrapper .search-results-disclaimer {
+  margin: 15px 0;
+  padding: 0 16px;
+}
+
+.property-search-results.block .search-results-disclaimer > div {
+  margin: 16px 0;
+}
+
+.property-search-results.block .search-results-disclaimer p {
+  margin: 5px 0;
+  font-size: var(--body-font-size-xs);
+  line-height: var(--line-height-xs);
+  letter-spacing: var(--letter-spacing-s);
+  color: var(--dark-grey);
+}
+
+.property-search-results.block .search-results-disclaimer p.image:not(.img-first) {
+  line-height: 0;
+  margin: 5px auto;
+  text-align: center;
+}
+
+.property-search-results.block .search-results-disclaimer p.image img {
+  height: auto;
+  width: auto;
+  max-width: 140px;
+  max-height: 30px;
+}
+
+.property-search-results.block .pagination-wrapper .select-wrapper {
+  position: relative;
+  width: 145px;
+}
+
+.property-search-results.block .search-results-pagination .pagination-wrapper {
+  display: flex;
+  margin-top: 30px;
+  align-items: center;
+  justify-content: flex-end;
+  gap: 15px;
+}
+
+.property-search-results.block .search-results-wrapper .search-results-pagination .link-wrapper {
+  display: flex;
+  gap: 15px;
+}
+
+.property-search-results.block .search-results-wrapper .search-results-pagination .link-wrapper a {
+  height: 35px;
+  width: 35px;
+  border: 1px solid var(--grey);
+}
+
+.property-search-results.block .search-results-wrapper .search-results-pagination .link-wrapper a.disabled {
+  pointer-events: none;
+  border: 1px solid var(--platinum);
+}
+
+.property-search-results.block .search-results-wrapper .search-results-pagination .link-wrapper a svg {
+  padding: 5px;
+  height: 100%;
+  width: 100%;
+}
+
+.property-search-results.block .search-results-wrapper .search-results-pagination .link-wrapper a.disabled svg {
+  filter: invert(99%) sepia(0%) saturate(1103%) hue-rotate(210deg) brightness(113%) contrast(81%);
+}
+
+
+.property-search-results.block .search-results-wrapper .search-results-pagination .link-wrapper a.prev svg {
+  transform: rotate(-180deg);
+}
+
+
+.property-search-results.block .view-options p {
+  margin: 0;
+}
+
+.property-search-results.block .mobile-view-options {
+  position: sticky;
+  bottom: 0;
+  padding: 10px 0;
+  box-shadow: 0 0 6px 0 rgba(0 0 0 / 23%);
+  background-color: var(--white);
+  z-index: 100;
+}
+
+.property-search-results.block .mobile-view-options p {
+  display: flex;
+  justify-content: center;
+  gap: 16px;
+}
+
+.property-search-results.block .desktop-view-options {
+  display: none;
+}
+
+/** Override the default card display */
+
+.property-search-results.block .search-results-wrapper .property-list-cards {
+  display: grid;
+  grid-template-columns: 1fr;
+  gap: 30px;
+}
+
+.property-search-results.block .search-results-wrapper .property-list-cards .listing-tile {
+  width: 100%;
+  max-width: unset;
+}
+
+@media screen and (min-width: 600px) {
+  .property-search-results.block .search-results-wrapper .property-list-cards {
+    grid-template-columns: repeat(3, 1fr);
+    gap: 15px;
+  }
+}
+
+@media screen and (min-width: 900px) {
+  .property-search-results.block.map-view {
+    display: grid;
+    grid-template:
+      "filters filters"
+      "map results"
+      / 58% 1fr;
+  }
+
+  .property-search-results.block .property-search-filters {
+    grid-area: filters;
+    grid-template-columns: 1fr min-content min-content;
+  }
+
+  .property-search-results.block .search-map-wrapper {
+    grid-area: map;
+    overflow: scroll;
+  }
+
+  .property-search-results.block .search-results-content {
+    padding: 0;
+    grid-area: results;
+    max-height: var(--map-height);
+    overflow: scroll;
+  }
+
+    /* Override the Property Bar listing type section when this block's are visible */
+  .property-search-bar.block .listing-types {
+    display: none;
+  }
+
+  .property-search-results.block .desktop-view-options {
+    display: flex;
+    align-items: center;
+  }
+
+  .property-search-results.block .listing-types {
+    display: flex;
+  }
+
+  .property-search-results.block .mobile-view-options {
+    display: none;
+  }
+
+  .property-search-results.block .search-results-wrapper {
+    padding: 0 10px;
+  }
+
+  .property-search-results.block.map-view .search-results-wrapper {
+    display: block;
+  }
+
+  .property-search-results.block .search-results-wrapper .property-list-cards {
+    grid-template-columns: repeat(3, 1fr);
+  }
+
+  .property-search-results.block.map-view .search-results-wrapper .property-list-cards {
+    grid-template-columns: 1fr
+  }
+}
+
+@media screen and (min-width: 1200px) {
+  .property-search-results.block .search-results-wrapper .property-list-cards {
+    grid-template-columns: repeat(4, 1fr);
+  }
+
+  .property-search-results.block.map-view .search-results-wrapper .property-list-cards {
+    grid-template-columns: repeat(2, 1fr);
+  }
+}
diff --git a/blocks/property-search-results/property-search-results.js b/blocks/property-search-results/property-search-results.js
new file mode 100644
index 00000000..7a12daad
--- /dev/null
+++ b/blocks/property-search-results/property-search-results.js
@@ -0,0 +1,264 @@
+import {
+  a, div, input, label, li, option, p, select, span, ul, img, domEl,
+} from '../../scripts/dom-helpers.js';
+import Search, {
+  UPDATE_SEARCH_EVENT,
+  SEARCH_URL,
+  STORAGE_KEY,
+} from '../../scripts/apis/creg/search/Search.js';
+import ListingType from '../../scripts/apis/creg/search/types/ListingType.js';
+import { propertySearch } from '../../scripts/apis/creg/creg.js';
+import { getMetadata, readBlockConfig } from '../../scripts/aem.js';
+import { updateForm } from '../property-search-bar/delayed.js';
+import { BREAKPOINTS } from '../../scripts/scripts.js';
+import observe from './observers.js';
+import loader from './loader.js';
+import { displayResults as displayList } from './results.js';
+import { displayResults as displayMap, reinitMap } from './map.js';
+
+let searchController;
+
+let initMap;
+
+/**
+ * Converts the Disclaimer returned from search results and extracts images and text.
+ * @param {String} disclaimer
+ */
+function sanitizeDisclaimer(disclaimer) {
+  const tmp = document.createElement('div');
+  tmp.innerHTML = disclaimer;
+  const content = [];
+  tmp.querySelectorAll(':scope > div').forEach((d) => {
+    const text = [];
+    let image;
+    let imgFirst = false;
+    // eslint-disable-next-line no-bitwise
+    const walker = document.createTreeWalker(d, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
+    let next = walker.firstChild();
+    while (next) {
+      if (next.nodeType === Node.TEXT_NODE && next.textContent.trim() !== '') {
+        text.push(p(next.textContent));
+      } else if (next.nodeName === 'IMG') {
+        if (text.length === 0) imgFirst = true;
+        const config = { src: next.src };
+        if (next.height) config.height = next.height;
+        if (next.width) config.width = next.width;
+        image = p({ class: `image ${imgFirst ? 'img-first' : ''}` }, img(config));
+      }
+      next = walker.nextNode();
+    }
+    if (image) {
+      if (imgFirst) {
+        text.unshift(image);
+      } else {
+        text.push(image);
+      }
+    }
+    content.push(div(...text));
+  });
+  return content;
+}
+
+function updateFilters(search) {
+  const filters = document.querySelector('.property-search-results.block .property-search-filters');
+  filters.querySelectorAll('.listing-types .filter-toggle.disabled').forEach((t) => t.classList.remove('disabled'));
+  filters.querySelectorAll('.listing-types .filter-toggle input[type="checkbox"]').forEach((c) => {
+    c.removeAttribute('checked');
+    c.nextElementSibling.classList.remove('checked');
+  });
+  search.listingTypes.forEach((t) => {
+    const chkbx = filters.querySelector(`.listing-types .filter-toggle input[name="${t.type}"]`);
+    chkbx.setAttribute('checked', 'checked');
+    chkbx.nextElementSibling.classList.add('checked');
+    if (t.type === ListingType.FOR_RENT.type) {
+      filters.querySelector(`.listing-types .filter-toggle input[name="${ListingType.PENDING.type}"]`).closest('.filter-toggle').classList.add('disabled');
+    } else if (t.type === ListingType.PENDING.type) {
+      filters.querySelector(`.listing-types .filter-toggle input[name="${ListingType.FOR_RENT.type}"]`).closest('.filter-toggle').classList.add('disabled');
+    }
+  });
+
+  const sort = `${search.sortBy}_${search.sortDirection}`;
+  filters.querySelector('.sort-options ul li.selected').classList.remove('selected');
+  filters.querySelector(`.sort-options select option[value="${sort}"]`).selected = true;
+  filters.querySelector(`.sort-options ul li[data-value="${sort}"]`).classList.add('selected');
+  filters.querySelector('.selected span').textContent = filters.querySelector('.sort-options ul li.selected').textContent;
+}
+
+/**
+ * Perform the search
+ * @param {Search} search the search to perform
+ * @param {boolean} redraw if the map should be updated
+ * @return {Promise<void>}
+ */
+async function doSearch(search, redraw = true) {
+  searchController?.abort();
+  searchController = new AbortController();
+  window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(search));
+  search.franchiseeCode = getMetadata('office-id');
+  const contentWrapper = document.querySelector('.property-search-results.block .search-results-content');
+  contentWrapper.classList.add('loading');
+  contentWrapper.scrollTo({ top: 0, behavior: 'smooth' });
+  const parent = document.querySelector('.property-search-results.block .search-results-wrapper');
+  return new Promise(() => {
+    const controller = searchController;
+    propertySearch(search).then((results) => {
+      if (!controller.signal.aborted) {
+        displayList(parent, results);
+        contentWrapper.querySelector('.search-results-disclaimer-wrapper').replaceChildren(
+          domEl('hr', { role: 'presentation', 'aria-hidden': true, tabindex: -1 }),
+          div({ class: 'search-results-disclaimer' }, ...sanitizeDisclaimer(results.disclaimer)),
+        );
+        contentWrapper.classList.remove('loading');
+        if (redraw) displayMap(results);
+      }
+    });
+  });
+}
+
+export default async function decorate(block) {
+  const config = readBlockConfig(block);
+
+  const view = BREAKPOINTS.medium.matches ? 'map-view' : 'list-view';
+  block.classList.add(view);
+  /* @formatter:off */
+  const filters = div({ class: 'property-search-filters' },
+    div({ class: 'listing-types' },
+      div({ class: 'filter-toggle' },
+        input({
+          name: 'FOR_SALE',
+          hidden: 'hidden',
+          type: 'checkbox',
+          'aria-label': 'Hidden Checkbox',
+          checked: 'checked',
+          value: `${ListingType.FOR_SALE.type}`,
+        }),
+        div({ class: 'checkbox checked' }),
+        label({ role: 'presentation' }, ListingType.FOR_SALE.label),
+      ),
+      div({ class: 'filter-toggle' },
+        input({
+          name: 'FOR_RENT',
+          hidden: 'hidden',
+          type: 'checkbox',
+          'aria-label': 'Hidden Checkbox',
+          value: `${ListingType.FOR_RENT.type}`,
+        }),
+        div({ class: 'checkbox' }),
+        label({ role: 'presentation' }, ListingType.FOR_RENT.label),
+      ),
+      div({ class: 'filter-toggle' },
+        input({
+          name: 'PENDING',
+          hidden: 'hidden',
+          type: 'checkbox',
+          'aria-label': 'Hidden Checkbox',
+          value: `${ListingType.PENDING.type}`,
+        }),
+        div({ class: 'checkbox' }),
+        label({ role: 'presentation' }, ListingType.PENDING.label),
+      ),
+      div({ class: 'filter-toggle' },
+        input({
+          name: 'RECENTLY_SOLD',
+          hidden: 'hidden',
+          type: 'checkbox',
+          'aria-label': 'Hidden Checkbox',
+          value: `${ListingType.RECENTLY_SOLD.type}`,
+        }),
+        div({ class: 'checkbox' }),
+        label({ role: 'presentation' }, 'Sold'),
+      ),
+    ),
+    div({ class: 'sort-options' },
+      label({ role: 'presentation' }, 'Sort by'),
+      div({ class: 'select-wrapper' },
+        select({ name: 'sort', 'aria-label': 'Distance' },
+          // eslint-disable-next-line object-curly-newline
+          option({ value: 'DISTANCE_ASC', 'data-sort-by': 'DISTANCE', 'data-sort-direction': 'ASC', selected: 'selected' }, 'Distance'),
+          option({ value: 'PRICE_DESC', 'data-sort-by': 'PRICE', 'data-sort-direction': 'DESC' }, 'Price (Hi-Lo)'),
+          option({ value: 'PRICE_ASC', 'data-sort-by': 'PRICE', 'data-sort-direction': 'ASC' }, 'Price (Lo-Hi)'),
+          option({ value: 'DATE_DESC', 'data-sort-by': 'DATE', 'data-sort-direction': 'DESC' }, 'Date (New-Old)'),
+          option({ value: 'DATE_ASC', 'data-sort-by': 'DATE', 'data-sort-direction': 'ASC' }, 'Date (Old-New)'),
+        ),
+        // eslint-disable-next-line object-curly-newline
+        div({ class: 'selected', role: 'combobox', 'aria-haspopup': 'listbox', 'aria-label': 'Distance', 'aria-expanded': false, 'aria-controls': 'search-results-sort', tabindex: 0 },
+          span('Distance'),
+        ),
+        ul({ id: 'search-results-sort', class: 'select-items', role: 'listbox' },
+          li({ 'data-value': 'DISTANCE_ASC', role: 'option', class: 'selected' }, 'Distance'),
+          li({ 'data-value': 'PRICE_DESC', role: 'option' }, 'Price (Hi-Lo)'),
+          li({ 'data-value': 'PRICE_ASC', role: 'option' }, 'Price (Lo-Hi)'),
+          li({ 'data-value': 'DATE_DESC', role: 'option' }, 'Date (New-Old)'),
+          li({ 'data-value': 'DATE_ASC', role: 'option' }, 'Date (Old-New)'),
+        ),
+      ),
+    ),
+    div({ class: 'desktop-view-options view-options' },
+      p({ class: 'button-container' },
+        a({ class: 'map-view', role: 'button', rel: 'noopener noreferrer' }, 'Map View'),
+        a({ class: 'list-view', role: 'button', rel: 'noopener noreferrer' }, 'List View'),
+      ),
+    ),
+  );
+
+  const map = div({ class: 'search-map-wrapper' },
+    div({ class: 'search-map-container satellite' },
+      div({ class: 'search-results-map' }, div({ id: 'gmap-canvas' })),
+    ),
+  );
+  /* @formatter:on */
+
+  const list = div({ class: 'search-results-wrapper' });
+  const disclaimer = div({ class: 'search-results-disclaimer-wrapper' });
+
+  const content = div({ class: 'search-results-content loading' }, loader, list, disclaimer);
+
+  const buttons = div({ class: 'mobile-view-options view-options' },
+    p({ class: 'button-container' },
+      a({ target: '_blank', role: 'button', rel: 'noopener noreferrer' }, 'Save'),
+      a({ class: 'map-view', role: 'button', rel: 'noopener noreferrer' }, 'Map View'),
+      a({ class: 'list-view', role: 'button', rel: 'noopener noreferrer' }, 'List View'),
+    ),
+  );
+
+  block.replaceChildren(filters, map, content, buttons);
+
+  // Default the search results.
+  let search;
+  if (window.location.search === '') {
+    const data = window.sessionStorage.getItem(STORAGE_KEY);
+    if (data) {
+      search = await Search.fromJSON(JSON.parse(data));
+    } else {
+      search = await Search.fromBlockConfig(config);
+    }
+    window.history.replaceState(null, '', new URL(`/search?${search.asURLSearchParameters()}`, window.location));
+  } else {
+    search = await Search.fromQueryString(window.location.search);
+  }
+  updateFilters(search);
+  updateForm(search);
+  observe(block);
+
+  window.addEventListener('popstate', async () => {
+    const newSearch = await Search.fromQueryString(window.location.search);
+    updateFilters(newSearch);
+    updateForm(newSearch);
+    reinitMap(newSearch);
+    doSearch(newSearch);
+  });
+
+  window.addEventListener(UPDATE_SEARCH_EVENT, async (e) => {
+    const { search: newSearch, redraw } = e.detail;
+    updateFilters(newSearch);
+    window.history.pushState(null, '', new URL(`${SEARCH_URL}?${newSearch.asURLSearchParameters().toString()}`, window.location));
+    doSearch(newSearch, redraw);
+  });
+
+  window.setTimeout(async () => {
+    const mod = await import(`${window.hlx.codeBasePath}/blocks/property-search-results/map.js`);
+    initMap = mod.initMap;
+    initMap(block, search);
+    doSearch(search);
+  }, 3000);
+}
diff --git a/blocks/property-search-results/results.js b/blocks/property-search-results/results.js
new file mode 100644
index 00000000..980aa2b0
--- /dev/null
+++ b/blocks/property-search-results/results.js
@@ -0,0 +1,102 @@
+import {
+  a, div, li, option, select, span, ul,
+} from '../../scripts/dom-helpers.js';
+import { closeOnBodyClick } from '../shared/search/util.js';
+import Search, { UPDATE_SEARCH_EVENT } from '../../scripts/apis/creg/search/Search.js';
+import { render as renderCards } from '../shared/property/cards.js';
+
+/**
+ * Builds the pagination of results
+ * @param {Number} total total number of pages
+ * @param {Number} current current page number
+ */
+function buildPagination(total, current) {
+  if (Number.isNaN(total) || Number.isNaN(current)) return div();
+  const options = [];
+  const lis = [];
+  for (let i = 1; i <= total; i += 1) {
+    options.push(option({ value: i }, i));
+    const config = { 'data-value': i };
+    if (i === current) config.class = 'selected';
+    lis.push(li(config, i));
+  }
+  const displayLabel = `${current} of ${total}`;
+  const wrapper = div({ class: 'pagination-wrapper' },
+    div({ class: 'select-wrapper' },
+      select({ name: 'page', 'aria-label': displayLabel }, ...options),
+      div({
+        class: 'selected',
+        role: 'button',
+        'aria-haspopup': 'listbox',
+        'aria-label': displayLabel,
+        'aria-expanded': false,
+        tabindex: 0,
+      }, span(displayLabel)),
+      ul({ class: 'select-items', role: 'listbox' }, ...lis),
+    ),
+    div({ class: 'link-wrapper' }),
+  );
+
+  const prev = a({
+    class: 'prev',
+    'aria-label': 'Previous Page',
+    role: 'button',
+    'data-value': `${current - 1}`,
+  });
+  prev.innerHTML = '<svg><use xlink:href="/icons/icons.svg#carrot"/></svg>';
+  const next = a({
+    class: 'next',
+    'aria-label': 'Next Page',
+    role: 'button',
+    'data-value': `${current + 1}`,
+  });
+  next.innerHTML = '<svg><use xlink:href="/icons/icons.svg#carrot"/></svg>';
+
+  if (current === 1) {
+    prev.classList.add('disabled');
+  } else if (current === total) {
+    next.classList.add('disabled');
+  }
+
+  wrapper.querySelector('.link-wrapper').append(prev, next);
+
+  closeOnBodyClick(wrapper);
+  const selectWrapper = wrapper.querySelector('.select-wrapper');
+  selectWrapper.querySelector('.selected').addEventListener('click', (e) => {
+    e.stopPropagation();
+    e.preventDefault();
+    const open = selectWrapper.classList.toggle('open');
+    e.currentTarget.setAttribute('aria-expanded', open);
+  });
+
+  const changePage = async (e) => {
+    e.preventDefault();
+    e.stopPropagation();
+    const page = e.currentTarget.getAttribute('data-value');
+    const search = await Search.fromQueryString(window.location.search);
+    search.page = page;
+    window.dispatchEvent(new CustomEvent(UPDATE_SEARCH_EVENT, { detail: { search, redraw: false } }));
+  };
+
+  selectWrapper.querySelectorAll('.select-items li').forEach((opt) => {
+    opt.addEventListener('click', changePage);
+  });
+  prev.addEventListener('click', changePage);
+  next.addEventListener('click', changePage);
+  return wrapper;
+}
+
+/**
+ * Renders the search results as cards into the specified contianer
+ * @param parent
+ * @param results
+ */
+// eslint-disable-next-line import/prefer-default-export
+export function displayResults(parent, results) {
+  const cards = div({ class: 'search-results-cards property-list-cards' });
+  renderCards(cards, results.properties);
+  const pagination = div({ class: 'search-results-pagination' },
+    buildPagination(parseInt(results.pages, 10), parseInt(results.page, 10)),
+  );
+  parent.replaceChildren(cards, pagination);
+}
diff --git a/blocks/property-listing/cards/cards.css b/blocks/shared/property/cards.css
similarity index 96%
rename from blocks/property-listing/cards/cards.css
rename to blocks/shared/property/cards.css
index 3ac54d1f..cca4a1f2 100644
--- a/blocks/property-listing/cards/cards.css
+++ b/blocks/shared/property/cards.css
@@ -2,7 +2,6 @@
 
 .property-list-cards {
   display: flex;
-  height: 400px;
   overflow-x: auto;
   scroll-snap-type: x mandatory;
   scroll-behavior: smooth;
@@ -11,9 +10,6 @@
   padding-bottom: 10px;
 }
 
-.property-list-cards::-webkit-scrollbar {
-  display: none;
-}
 
 .property-list-cards .listing-tile {
   display: flex;
@@ -55,7 +51,7 @@
 
 .property-list-cards .listing-image-container {
   position: relative;
-  height: 100%;
+  padding-top: 73.5294%;
 }
 
 .property-list-cards .listing-image-container .property-image {
@@ -66,6 +62,7 @@
   right: 0;
   bottom: 0;
   object-fit: cover;
+  object-position: center;
 }
 
 .property-list-cards .is-sold .listing-image-container .property-image {
@@ -148,7 +145,7 @@
   justify-content: center;
 }
 
-.property-list-cards .property-labels .property-label.open-house svg {
+.property-list-cards .property-labels .property-label.open-house img {
   height: 24px;
   width: 24px;
   margin-right: 5px;
@@ -178,13 +175,13 @@
   bottom: 0;
 }
 
-.property-list-cards .listing-image-container .property-price {
-  padding-top: 7px;
-  padding-left: 10px;
+.property-list-cards .listing-image-container .property-price p {
+  display: inline-block;;
+  margin: 0;
+  padding: 7px 10px;
   font-weight: var(--font-weight-bold);
   font-size: var(--body-font-size-l);
   line-height: var(--line-height-s);
-  max-width: 70%;
   background-color: var(--white);
   color: var(--body-color);
 }
@@ -265,7 +262,7 @@
   left: 0;
 }
 
-.property-list-cards .property-details .property-buttons .button-property svg {
+.property-list-cards .property-details .property-buttons .button-property img {
   width: 24px;
   height: 24px;
 }
@@ -334,7 +331,6 @@
 @media (min-width: 1200px) {
   .property-list-cards {
     display: grid;
-    height: 820px;
     grid-template: repeat(2, 1fr) / repeat(4, 1fr);
     gap: 20px;
     padding-bottom: 20px;
diff --git a/blocks/property-listing/cards/cards.js b/blocks/shared/property/cards.js
similarity index 67%
rename from blocks/property-listing/cards/cards.js
rename to blocks/shared/property/cards.js
index d690fc3e..10092676 100644
--- a/blocks/property-listing/cards/cards.js
+++ b/blocks/shared/property/cards.js
@@ -1,9 +1,6 @@
-import { propertySearch } from '../../../scripts/apis/creg/creg.js';
-import { decorateIcons } from '../../../scripts/aem.js';
-
 function createImage(listing) {
   if (listing.SmallMedia?.length > 0) {
-    return `<img src="${listing.SmallMedia[0].mediaUrl}" alt="Property Image" loading="lazy" class="property-thumbnail">`;
+    return `<img src="${listing.SmallMedia[0].mediaUrl}" alt="${listing.StreetName}" loading="lazy" class="property-thumbnail">`;
   }
   return '<div class="property-no-available-image"><span>no images available</span></div>';
 }
@@ -41,7 +38,7 @@ export function createCard(listing) {
   if (listing.PdpPath.includes('LuxuryTheme=true')) {
     item.classList.add('is-luxury');
   }
-  const applicationType = listing.ApplicationType && listing.ApplicationType === 'For Rent' ? `<span class="property-label new-listing">${listing.ApplicationType}</span>` : '';
+  const applicationType = listing.ListingType && listing.ListingType === 'For Rent' ? `<span class="property-label new-listing">${listing.ListingType}</span>` : '';
 
   if (listing.ClosedDate !== '01/01/0001') {
     item.classList.add('is-sold');
@@ -49,7 +46,7 @@ export function createCard(listing) {
   }
 
   item.innerHTML = `
-    <a href="${detailsPath}" rel="noopener" aria-label="${listing.StreetName}">
+    <a href="${detailsPath}" rel="noopener" aria-labelledby="listing-${listing.ListingId}-address">
       <div class="listing-image-container"> 
         <div class="property-image"> 
           ${createImage(listing)} 
@@ -70,7 +67,7 @@ export function createCard(listing) {
             <span class="property-label">${listing.mlsStatus}</span>
           </div>
           <div class="property-price">
-              ${listing.ListPriceUS}
+            <p>${listing.ListPriceUS}</p>
           </div> 
         </div> 
       </div>
@@ -79,7 +76,7 @@ export function createCard(listing) {
       <div class="property-info-wrapper"> 
         <div class="property-info"> 
           <div class="sold-date">Closed: ${listing.ClosedDate}</div>
-          <div class="address"> 
+          <div id="listing-${listing.ListingId}-address" class="address"> 
             ${listing.StreetName}
             <br> 
             ${listing.City}, ${listing.StateOrProvince} ${listing.PostalCode} 
@@ -89,13 +86,21 @@ export function createCard(listing) {
       </div> 
       <div class="property-buttons"> 
         <div class="buttons-row-flex"> 
-          <a aria-label="Contact Form" href="#" class="button-property"> 
-            <span class="icon icon-envelope"></span>
-            <span class="icon icon-envelopedark"></span>
+          <a aria-label="Contact us about ${listing.StreetName}" href="#" class="button-property"> 
+            <span class="icon icon-envelope">
+              <img data-icon-name="envelope" src="/icons/envelope.svg" loading="lazy" alt="envelope">
+            </span>
+            <span class="icon icon-envelopedark">
+              <img data-icon-name="envelopedark" src="/icons/envelopedark.svg" loading="lazy" alt="envelope">
+            </span>
           </a> 
-          <a aria-label="Save" href="#" class="button-property"> 
-            <span class="icon icon-heartempty"></span>
-            <span class="icon icon-heartemptydark"></span>
+          <a aria-label="Save ${listing.StreetName} to saved properties." href="#" class="button-property"> 
+            <span class="icon icon-heartempty">
+              <img data-icon-name="heartempty" src="/icons/heartempty.svg" loading="lazy" alt="heart">
+            </span>
+            <span class="icon icon-heartemptydark">
+              <img data-icon-name="heartempty" src="/icons/heartemptydark.svg" loading="lazy" alt="heart">
+            </span>
           </a>
         </div>
       </div>
@@ -117,21 +122,13 @@ export function createCard(listing) {
 /**
  * Render the results of the provided search into the specified parent element.
  *
- * @param {SearchParameters} searchParams
  * @param {HTMLElement} parent
- * @return {Promise<void>}
+ * @param {Object[]} properties results from CREG
  */
-export async function render(searchParams, parent) {
-  const list = document.createElement('div');
-  list.classList.add('property-list-cards');
-  parent.append(list);
-
-  propertySearch(searchParams).then((results) => {
-    if (results?.properties) {
-      results.properties.forEach((listing) => {
-        list.append(createCard(listing));
-      });
-      decorateIcons(parent);
-    }
+export function render(parent, properties = []) {
+  const cards = [];
+  properties.forEach((listing) => {
+    cards.push(createCard(listing));
   });
+  parent.replaceChildren(...cards);
 }
diff --git a/blocks/property-listing/cards/luxury-collection-template.css b/blocks/shared/property/luxury-collection-template.css
similarity index 71%
rename from blocks/property-listing/cards/luxury-collection-template.css
rename to blocks/shared/property/luxury-collection-template.css
index 3d516487..0c7326cc 100644
--- a/blocks/property-listing/cards/luxury-collection-template.css
+++ b/blocks/shared/property/luxury-collection-template.css
@@ -1,11 +1,12 @@
 .luxury-collection .property-list-cards .listing-image-container .property-image {
-    z-index: 1;
+  z-index: 1;
 }
+
 .luxury-collection .property-list-cards .property-labels {
-    background: initial;
+  background: initial;
 }
 
 .luxury-collection .property-list-cards .property-price {
-    background: initial;
-    z-index: 2;
-}
\ No newline at end of file
+  background: initial;
+  z-index: 2;
+}
diff --git a/blocks/shared/search-countries/search-countries.js b/blocks/shared/search-countries/search-countries.js
index 27fef4e5..ed7640d2 100644
--- a/blocks/shared/search-countries/search-countries.js
+++ b/blocks/shared/search-countries/search-countries.js
@@ -21,7 +21,7 @@ function addListeners(wrapper, cbs) {
       wrapper.querySelector('.select-items .item.selected')?.classList.remove('selected');
       e.currentTarget.classList.add('selected');
 
-      wrapper.querySelector('select option[selected="selected"]')?.removeAttribute('selected');
+      wrapper.querySelectorAll('select option').forEach((o) => { o.selected = false; });
       wrapper.querySelector(`select option[value="${selected}"]`).setAttribute('selected', 'selected');
       wrapper.classList.toggle('open');
       if (cbs) {
diff --git a/blocks/shared/search/suggestion.js b/blocks/shared/search/suggestion.js
new file mode 100644
index 00000000..e613be74
--- /dev/null
+++ b/blocks/shared/search/suggestion.js
@@ -0,0 +1,103 @@
+import {
+  getSelected as getSelectedCountry,
+} from '../search-countries/search-countries.js';
+import {
+  abort as abortSuggestions,
+  get as getSuggestions,
+} from '../../../scripts/apis/creg/suggestion.js';
+
+const MORE_INPUT_NEEDED = 'Please enter at least 3 characters.';
+const NO_SUGGESTIONS = 'No suggestions found. Please modify your search.';
+const SEARCHING_SUGGESTIONS = 'Looking up suggestions...';
+
+const updateSuggestions = (suggestions, target) => {
+  // Keep the first item - required character entry count.
+  const first = target.querySelector(':scope li');
+  target.replaceChildren(first, ...suggestions);
+};
+
+const buildSuggestions = (suggestions) => {
+  const lists = [];
+  suggestions.forEach((category) => {
+    const list = document.createElement('li');
+    list.classList.add('list-title');
+    list.textContent = category.displayText;
+    lists.push(list);
+    const ul = document.createElement('ul');
+    list.append(ul);
+    category.results.forEach((result) => {
+      const li = document.createElement('li');
+      li.setAttribute('category', category.searchType);
+      li.setAttribute('display', result.displayText.trim());
+      li.setAttribute('query', result.QueryString);
+      li.setAttribute('type', new URLSearchParams(result.QueryString).get('SearchType'));
+      li.textContent = result.SearchParameter;
+      ul.append(li);
+    });
+  });
+
+  return lists;
+};
+
+/**
+ * Handles the input changed event for the text field. Will add suggestions based on user input.
+ *
+ * @param {Event} e the change event
+ * @param {HTMLElement} target the container in which to add suggestions
+ */
+const inputChanged = (e, target) => {
+  const { currentTarget } = e;
+  const { value } = currentTarget;
+  const searchBar = currentTarget.closest('.search-bar');
+  if (value.length > 0) {
+    searchBar.classList.add('show-suggestions');
+  } else {
+    searchBar.classList.remove('show-suggestions');
+    searchBar.querySelector('input[name="query"]').value = '';
+    searchBar.querySelector('input[name="type"]').value = '';
+  }
+
+  if (value.length <= 2) {
+    abortSuggestions();
+    target.querySelector(':scope > li:first-of-type').textContent = MORE_INPUT_NEEDED;
+    updateSuggestions([], target);
+  } else {
+    target.querySelector(':scope > li:first-of-type').textContent = SEARCHING_SUGGESTIONS;
+    getSuggestions(value, getSelectedCountry(currentTarget.closest('form')))
+      .then((suggestions) => {
+        if (!suggestions) {
+          // Undefined suggestions means it was aborted, more input coming.
+          updateSuggestions([], target);
+          return;
+        }
+        if (suggestions.length) {
+          updateSuggestions(buildSuggestions(suggestions), target);
+        } else {
+          target.querySelector(':scope > li:first-of-type').textContent = NO_SUGGESTIONS;
+        }
+      });
+  }
+};
+
+const suggestionSelected = (e, form) => {
+  const query = e.target.getAttribute('query');
+  const keyword = e.target.getAttribute('display');
+  const type = e.target.getAttribute('type');
+  if (!query) {
+    return;
+  }
+  form.querySelector('input[name="keyword"]').value = keyword;
+  form.querySelector('input[name="query"]').value = query;
+  form.querySelector('input[name="type"]').value = type;
+  form.querySelector('.search-bar').classList.remove('show-suggestions');
+};
+
+export default function addEventListeners(form) {
+  const suggestionsTarget = form.querySelector('.suggester-input .suggester-results');
+  form.querySelector('.suggester-input input').addEventListener('input', (e) => {
+    inputChanged(e, suggestionsTarget);
+  });
+  suggestionsTarget.addEventListener('click', (e) => {
+    suggestionSelected(e, form);
+  });
+}
diff --git a/blocks/shared/search/util.js b/blocks/shared/search/util.js
new file mode 100644
index 00000000..832212ac
--- /dev/null
+++ b/blocks/shared/search/util.js
@@ -0,0 +1,168 @@
+import { getMetadata } from '../../../scripts/aem.js';
+
+export const BED_BATHS = [
+  { value: 1, label: '1+' },
+  { value: 2, label: '2+' },
+  { value: 3, label: '3+' },
+  { value: 4, label: '4+' },
+  { value: 5, label: '5+' },
+];
+
+export function getPlaceholder() {
+  const country = getMetadata('country') || 'US';
+  return country === 'US' ? 'Enter City, Address, Zip/Postal Code, Neighborhood, School or MLS#' : 'Enter City';
+}
+
+let bodyCloseListener;
+/**
+ * Helper function to close an expanded item when click events occur elsewhere on the page.
+ * @param {HTMLElement} root context for closing elements
+ */
+export function closeOnBodyClick(root) {
+  if (bodyCloseListener) {
+    document.body.removeEventListener('click', bodyCloseListener);
+  }
+  bodyCloseListener = (e) => {
+    // Don't close if we clicked somewhere inside of the context.
+    if (root.contains(e.target)) {
+      return;
+    }
+    root.classList.remove('open');
+    root.querySelectorAll('.open').forEach((open) => open.classList.remove('open'));
+    root.querySelectorAll('[aria-expanded="true"]').forEach((expanded) => expanded.setAttribute('aria-expanded', 'false'));
+    document.body.removeEventListener('click', bodyCloseListener);
+    bodyCloseListener = undefined;
+  };
+  document.body.addEventListener('click', bodyCloseListener);
+}
+
+/**
+ * Creates a Select dropdown for filtering search.
+ * @param {String} name name of select
+ * @param {String} placeholder label
+ * @param {Array[Object]} options max number of options
+ * @param {String} options.value value for option entry
+ * @param {String} options.label label for option entry
+ * @returns {HTMLDivElement}
+ */
+export function buildFilterSelect(name, placeholder, options) {
+  const wrapper = document.createElement('div');
+  wrapper.classList.add('select-wrapper', name);
+  wrapper.innerHTML = `
+    <select name="${name}" aria-label="${placeholder}">
+      <option value="">Any ${placeholder}</option>
+    </select>
+    <div class="selected" role="button" aria-haspopup="listbox" aria-label="${placeholder}" aria-expanded="false" tabindex="0"><span>Any ${placeholder}</span></div>
+    <ul class="select-items" role="listbox">
+      <li role="option" class="selected" data-value="">Any ${placeholder}</li>
+    </ul>
+  `;
+
+  const select = wrapper.querySelector('select');
+  const ul = wrapper.querySelector('ul');
+  options.forEach((option) => {
+    const ele = document.createElement('option');
+    const li = document.createElement('li');
+    li.setAttribute('role', 'option');
+    li.setAttribute('data-value', option.value);
+    ele.value = option.value;
+    // eslint-disable-next-line no-multi-assign
+    ele.textContent = li.textContent = `${option.label} ${placeholder}`;
+    select.append(ele);
+    ul.append(li);
+  });
+  return wrapper;
+}
+
+export function filterItemClicked(e) {
+  e.preventDefault();
+  e.stopPropagation();
+  const value = e.currentTarget.getAttribute('data-value');
+  const wrapper = e.currentTarget.closest('.select-wrapper');
+  wrapper.querySelector('.selected span').textContent = e.currentTarget.textContent;
+  wrapper.querySelector('ul li.selected')?.classList.toggle('selected');
+  e.currentTarget.classList.add('selected');
+  wrapper.querySelectorAll('select option').forEach((o) => { o.selected = false; });
+  if (!value) {
+    wrapper.querySelector('select option[value=""]').selected = true;
+  } else {
+    wrapper.querySelector(`select option[value="${value}"]`).selected = true;
+  }
+  wrapper.classList.remove('open');
+  wrapper.querySelector('[aria-expanded="true"]')?.setAttribute('aria-expanded', 'false');
+}
+
+/**
+ * Creates a from/to range input field for the search filter
+ * @param name parameter name
+ * @param placeholder label
+ */
+export function buildDataListRange(name, placeholder) {
+  const wrapper = document.createElement('div');
+  wrapper.classList.add('range-wrapper', name);
+  wrapper.innerHTML = `
+    <div class="selected" role="button" aria-haspopup="listbox" aria-label="${placeholder}" aria-expanded="false" tabindex="0"><span>${placeholder}</span></div>
+    <div class="range-items">
+      <div id="min-${name}" class="input-dropdown">
+        <input type="text" name="min-${name}" maxlength="14" aria-describedby="min-${name}" aria-label="Minimum ${name}" placeholder="No Min" list="list-min-${name}">
+        <datalist id="list-min-${name}"></datalist> 
+      </div> 
+      <span>to</span>
+      <div id="max-${name}" class="input-dropdown">
+        <input type="text" name="max-${name}" maxlength="14" aria-describedby="max-${name}" aria-label="Maximum ${name}" placeholder="No Max" list="list-max-${name}">
+        <datalist id="list-max-${name}"></datalist> 
+      </div> 
+    </div>
+  `;
+  return wrapper;
+}
+
+/**
+ * Creates a from/to range input field with selections for the options
+ * @param name parameter name
+ * @param placeholder placeholder
+ * @param boundaries boundaries for ranges.
+ */
+export function buildSelectRange(name, placeholder, boundaries) {
+  const wrapper = document.createElement('div');
+  wrapper.classList.add('range-wrapper', name);
+  wrapper.innerHTML = `
+    <div class="selected" role="button" aria-haspopup="listbox" aria-expanded="false" aria-label="${placeholder}" tabindex="0"><span>${placeholder}</span></div>
+    <div class="range-items">
+      <div id="min-${name}" class="select-wrapper">
+        <select name="min-${name}" aria-label="No Min">
+          <option value="">No Min</option>
+        </select>
+        <div class="selected" role="combobox" aria-haspopup="listbox" aria-label="No Min" aria-expanded="false" aria-controls="list-min-${name}" tabindex="0"><span>No Min</span></div>
+        <ul id="list-min-${name}" class="select-items" role="listbox">
+          <li data-value="" role="option" class="selected">No Min</li>
+        </ul>
+      </div>
+      <span>to</span>
+      <div id="max-${name}" class="select-wrapper">
+        <select name="${name}" aria-label="No Max">
+          <option value="">No Max</option>
+        </select>
+        <div class="selected" role="combobox" aria-haspopup="listbox" aria-label="No Max" aria-expanded="false" aria-controls="list-max-${name}" tabindex="0"><span>No Max</span></div>
+        <ul id="list-max-${name}" class="select-items" role="listbox">
+          <li data-value="" role="option" class="selected">No Max</li>
+        </ul>
+      </div>
+    </div>
+  `;
+
+  wrapper.querySelectorAll(`#min-${name}, #max-${name}`).forEach((item) => {
+    boundaries.forEach((b) => {
+      const opt = document.createElement('option');
+      opt.value = b.value;
+      opt.textContent = b.label;
+      item.querySelector('select').append(opt);
+      const li = document.createElement('li');
+      li.setAttribute('data-value', b.value);
+      li.setAttribute('role', 'option');
+      li.textContent = b.label;
+      item.querySelector('ul').append(li);
+    });
+  });
+  return wrapper;
+}
diff --git a/icons/checkmark.svg b/icons/checkmark.svg
index b888e84f..db7e1ffc 100644
--- a/icons/checkmark.svg
+++ b/icons/checkmark.svg
@@ -1 +1,3 @@
-<svg width="33" height="32" viewBox="0 0 33 32" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.74609 18.9141L13.6491 24.541L25.8671 8.54102" stroke="#3A3A3A"/><rect x="1.49609" y="0.5" width="31" height="31" stroke="#3A3A3A"/></svg>
\ No newline at end of file
+<svg width="33" height="32" viewBox="0 0 33 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <path d="M7.74609 18.9141L13.6491 24.541L25.8671 8.54102" stroke="#3A3A3A"/>
+</svg>
diff --git a/icons/close-x-white.svg b/icons/close-x-white.svg
new file mode 100644
index 00000000..bfdb1439
--- /dev/null
+++ b/icons/close-x-white.svg
@@ -0,0 +1,11 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns="http://www.w3.org/2000/svg"
+     class="filter"
+     role="img"
+     aria-hidden="true"
+     tabindex="-1"
+     viewBox="0 0 22 22">
+    <g fill="#FFF" fill-rule="evenodd">
+        <rect transform="rotate(45 11 11)" x="-3" y="10" width="28" height="2" rx="1"/>
+        <rect transform="rotate(-45 11 11)" x="-3" y="10" width="28" height="2" rx="1"/>
+    </g>
+</svg>
diff --git a/icons/close-x.svg b/icons/close-x.svg
new file mode 100644
index 00000000..f3d89559
--- /dev/null
+++ b/icons/close-x.svg
@@ -0,0 +1,11 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns="http://www.w3.org/2000/svg"
+     class="filter"
+     role="img"
+     aria-hidden="true"
+     tabindex="-1"
+     viewBox="0 0 22 22">
+    <g fill="#3A3A3A" fill-rule="evenodd">
+        <rect transform="rotate(45 11 11)" x="-3" y="10" width="28" height="2" rx="1"/>
+        <rect transform="rotate(-45 11 11)" x="-3" y="10" width="28" height="2" rx="1"/>
+    </g>
+</svg>
diff --git a/icons/filter-white.svg b/icons/filter-white.svg
new file mode 100644
index 00000000..52cc5962
--- /dev/null
+++ b/icons/filter-white.svg
@@ -0,0 +1,18 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns="http://www.w3.org/2000/svg"
+     class="filter"
+     role="img"
+     aria-hidden="true"
+     tabindex="-1"
+     viewBox="0 0 23 22">
+    <g fill="none" fill-rule="evenodd">
+        <rect fill="#FFF" x="3" width="1.25" height="2.993" rx=".625"/>
+        <rect fill="#FFF" x="11" width="1.25" height="13" rx=".625"/>
+        <rect fill="#FFF" x="19" width="1.25" height="6" rx=".625"/>
+        <rect fill="#FFF" x="3" y="8" width="1.25" height="14" rx=".625"/>
+        <rect fill="#FFF" x="11" y="18.067" width="1.25" height="3.933" rx=".625"/>
+        <rect fill="#FFF" x="19" y="11" width="1.25" height="11" rx=".625"/>
+        <circle stroke="#FFF" stroke-width="1.25" cx="3.5" cy="5.5" r="2.5"/>
+        <circle stroke="#FFF" stroke-width="1.25" cx="11.5" cy="15.5" r="2.5"/>
+        <circle stroke="#FFF" stroke-width="1.25" cx="19.5" cy="8.5" r="2.5"/>
+    </g>
+</svg>
diff --git a/icons/globe.png b/icons/globe.png
new file mode 100644
index 0000000000000000000000000000000000000000..7717876f0907b0c292c2ffa2ccc6bbea2adbec14
GIT binary patch
literal 2350
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
Ux?lW#%K!iX07*qoM6N<$f(TMm6aWAK

literal 0
HcmV?d00001

diff --git a/icons/heartempty.svg b/icons/heartempty.svg
index 5c92e930..623bab0d 100644
--- a/icons/heartempty.svg
+++ b/icons/heartempty.svg
@@ -5,5 +5,5 @@
      tabindex="-1"
      viewBox="0 0 24 21">
     <path d="M6.853 0C4.865 0 2.979.903 1.678 2.48.478 3.93-.112 5.787.018 7.705c.128 1.918.96 3.668 2.342 4.928l.274.25 8.55 7.797c.234.213.526.32.816.32.29 0 .583-.107.816-.32l8.55-7.798.273-.249c1.382-1.26 2.215-3.01 2.344-4.928.128-1.918-.461-3.774-1.66-5.226C21.02.904 19.134 0 17.146 0a6.661 6.661 0 0 0-4.488 1.761L12 2.364l-.659-.602A6.66 6.66 0 0 0 6.853 0m0 1.309c1.302 0 2.61.474 3.671 1.441L12 4.096l1.475-1.346a5.43 5.43 0 0 1 3.673-1.441c1.567 0 3.126.687 4.234 2.029 2.03 2.456 1.779 6.175-.559 8.307l-.273.25L12 19.692l-8.55-7.798-.273-.25C.839 9.513.589 5.793 2.618 3.337 3.727 1.995 5.285 1.308 6.853 1.31"
-          fill="#4A4A4A"/>
+          fill="#AAA"/>
 </svg>
diff --git a/icons/heartemptydark.svg b/icons/heartemptydark.svg
index 9efbc173..e94647b4 100644
--- a/icons/heartemptydark.svg
+++ b/icons/heartemptydark.svg
@@ -1,9 +1,9 @@
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns="http://www.w3.org/2000/svg"
      class="heart-empty-dark"
      role="img"
      aria-hidden="true"
      tabindex="-1"
-viewBox="0 0 24 21">
+     viewBox="0 0 24 21">
     <path d="M6.853 0C4.865 0 2.979.903 1.678 2.48.478 3.93-.112 5.787.018 7.705c.128 1.918.96 3.668 2.342 4.928l.274.25 8.55 7.797c.234.213.526.32.816.32.29 0 .583-.107.816-.32l8.55-7.798.273-.249c1.382-1.26 2.215-3.01 2.344-4.928.128-1.918-.461-3.774-1.66-5.226C21.02.904 19.134 0 17.146 0a6.661 6.661 0 0 0-4.488 1.761L12 2.364l-.659-.602A6.66 6.66 0 0 0 6.853 0m0 1.309c1.302 0 2.61.474 3.671 1.441L12 4.096l1.475-1.346a5.43 5.43 0 0 1 3.673-1.441c1.567 0 3.126.687 4.234 2.029 2.03 2.456 1.779 6.175-.559 8.307l-.273.25L12 19.692l-8.55-7.798-.273-.25C.839 9.513.589 5.793 2.618 3.337 3.727 1.995 5.285 1.308 6.853 1.31"
           fill="#4A4A4A"/>
 </svg>
diff --git a/icons/heartfull.svg b/icons/heartfull.svg
new file mode 100644
index 00000000..01c8256f
--- /dev/null
+++ b/icons/heartfull.svg
@@ -0,0 +1,9 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xmlns="http://www.w3.org/2000/svg"
+     class="heart-full"
+     role="img"
+     aria-hidden="true"
+     tabindex="-1"
+     viewBox="0 0 24 21">
+    <path d="M6.853 0C4.865 0 2.979.903 1.678 2.48.478 3.93-.112 5.787.018 7.705c.128 1.918.96 3.668 2.342 4.928l.274.25 8.55 7.797c.234.213.526.32.816.32.29 0 .583-.107.816-.32l8.55-7.798.273-.249c1.382-1.26 2.215-3.01 2.344-4.928.128-1.918-.461-3.774-1.66-5.226C21.02.904 19.134 0 17.146 0a6.661 6.661 0 0 0-4.488 1.761L12 2.364l-.659-.602A6.66 6.66 0 0 0 6.853 0"
+          fill="#552448"/>
+</svg>
diff --git a/icons/maps/loader_opt.mp4 b/icons/maps/loader_opt.mp4
deleted file mode 100644
index 7e9da187b91147077036fe0e79153944867345e7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 58142
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%0A1tGxR
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
US}O`YreAj!r3MG#%EUqVcgSR)lmGw#

diff --git a/icons/maps/loader_opt.webm b/icons/maps/loader_opt.webm
deleted file mode 100644
index 90ba4065d4bda74b7d8a2683a50dc9df62892633..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 33962
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

diff --git a/icons/maps/map-reveal-marker-standard.png b/icons/maps/map-reveal-marker-standard.png
deleted file mode 100644
index cfb600ea93afd439e7332124f68c47d221ac3bc1..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 15748
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
AAOHXW

diff --git a/icons/pencil.svg b/icons/pencil.svg
new file mode 100644
index 00000000..c1fb1664
--- /dev/null
+++ b/icons/pencil.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg width="17px" height="17px" viewBox="0 0 17 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">        <title>Combined Shape</title>    <desc>Created with Sketch.</desc>    <g id="Document-Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">        <g id="UI/Pencil" transform="translate(-13.000000, -8.000000)" fill="#3A3A3A">            <path d="M15.764165,8 L17.6074619,9.8428079 L14.8422343,12.6079993 L13,10.764162 L15.764165,8 Z M30,25 L26.9080042,24.6721735 L29.6726673,21.9079783 L30,25 Z M28.75073,20.9855915 L25.9860669,23.7507496 L15.764175,13.5293899 L18.5293029,10.7641654 L28.75073,20.9855915 Z" id="Combined-Shape"></path>        </g>    </g></svg>
\ No newline at end of file
diff --git a/icons/search.svg b/icons/search.svg
new file mode 100644
index 00000000..aa6794ae
--- /dev/null
+++ b/icons/search.svg
@@ -0,0 +1,11 @@
+<svg aria-hidden="true"
+     focusable="false"
+     data-prefix="fal"
+     data-icon="house"
+     class="svg-inline--fa fa-search"
+     role="img"
+     xmlns="http://www.w3.org/2000/svg"
+     viewBox="0 0 22 22">
+    <path d="M1.28 9.036c0-4.277 3.48-7.757 7.756-7.757 4.278 0 7.758 3.48 7.758 7.757 0 4.277-3.48 7.757-7.758 7.757-4.277 0-7.757-3.48-7.757-7.757m20.533 11.872l-5.954-5.954a8.997 8.997 0 0 0 2.215-5.918C18.073 4.054 14.019 0 9.036 0 4.053 0 0 4.054 0 9.037c0 4.982 4.053 9.036 9.036 9.036 2.262 0 4.33-.837 5.917-2.215l5.955 5.954a.638.638 0 0 0 .904 0 .64.64 0 0 0 0-.904"
+          fill="#3A3A3A" fill-rule="evenodd"/>
+</svg>
diff --git a/package-lock.json b/package-lock.json
index 2b02f397..77f02222 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
         "eslint": "8.35.0",
         "eslint-config-airbnb-base": "15.0.0",
         "eslint-plugin-import": "2.27.5",
+        "mocha": "^10.2.0",
         "sinon": "15.0.1",
         "stylelint": "15.2.0",
         "stylelint-config-standard": "30.0.1"
@@ -1425,6 +1426,15 @@
         "url": "https://github.com/sponsors/epoberezkin"
       }
     },
+    "node_modules/ansi-colors": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/ansi-escapes": {
       "version": "4.3.2",
       "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
@@ -1703,6 +1713,12 @@
         "node": ">=8"
       }
     },
+    "node_modules/browser-stdout": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+      "dev": true
+    },
     "node_modules/browserslist": {
       "version": "4.22.1",
       "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz",
@@ -2087,6 +2103,67 @@
         "node": ">=8"
       }
     },
+    "node_modules/cliui": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
+      }
+    },
+    "node_modules/cliui/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/cliui/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/cliui/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/cliui/node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
     "node_modules/clone": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
@@ -3304,6 +3381,15 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/flat": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+      "dev": true,
+      "bin": {
+        "flat": "cli.js"
+      }
+    },
     "node_modules/flat-cache": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz",
@@ -3413,6 +3499,15 @@
         "node": ">=6.9.0"
       }
     },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true,
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
     "node_modules/get-func-name": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
@@ -3702,6 +3797,15 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/he": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+      "dev": true,
+      "bin": {
+        "he": "bin/he"
+      }
+    },
     "node_modules/hosted-git-info": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
@@ -4264,6 +4368,18 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/is-weakref": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
@@ -4680,6 +4796,92 @@
       "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
       "dev": true
     },
+    "node_modules/log-symbols": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/log-symbols/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/log-symbols/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/log-symbols/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/log-symbols/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/log-symbols/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/log-symbols/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/log-update": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
@@ -4959,6 +5161,171 @@
       "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
       "dev": true
     },
+    "node_modules/mocha": {
+      "version": "10.2.0",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
+      "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-colors": "4.1.1",
+        "browser-stdout": "1.3.1",
+        "chokidar": "3.5.3",
+        "debug": "4.3.4",
+        "diff": "5.0.0",
+        "escape-string-regexp": "4.0.0",
+        "find-up": "5.0.0",
+        "glob": "7.2.0",
+        "he": "1.2.0",
+        "js-yaml": "4.1.0",
+        "log-symbols": "4.1.0",
+        "minimatch": "5.0.1",
+        "ms": "2.1.3",
+        "nanoid": "3.3.3",
+        "serialize-javascript": "6.0.0",
+        "strip-json-comments": "3.1.1",
+        "supports-color": "8.1.1",
+        "workerpool": "6.2.1",
+        "yargs": "16.2.0",
+        "yargs-parser": "20.2.4",
+        "yargs-unparser": "2.0.0"
+      },
+      "bin": {
+        "_mocha": "bin/_mocha",
+        "mocha": "bin/mocha.js"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/mochajs"
+      }
+    },
+    "node_modules/mocha/node_modules/diff": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/mocha/node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mocha/node_modules/glob": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+      "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/mocha/node_modules/glob/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/mocha/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/mocha/node_modules/minimatch": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
+      "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/mocha/node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true
+    },
+    "node_modules/mocha/node_modules/nanoid": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
+      "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
+      "dev": true,
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/mocha/node_modules/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
+    "node_modules/mocha/node_modules/yargs-parser": {
+      "version": "20.2.4",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -5744,6 +6111,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
     "node_modules/raw-body": {
       "version": "2.5.2",
       "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
@@ -5990,6 +6366,15 @@
         "url": "https://github.com/sponsors/mysticatea"
       }
     },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/require-from-string": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
@@ -6217,6 +6602,15 @@
         "semver": "bin/semver.js"
       }
     },
+    "node_modules/serialize-javascript": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
+      "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+      "dev": true,
+      "dependencies": {
+        "randombytes": "^2.1.0"
+      }
+    },
     "node_modules/set-function-length": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
@@ -7296,6 +7690,12 @@
         "node": ">=8"
       }
     },
+    "node_modules/workerpool": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
+      "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
+      "dev": true
+    },
     "node_modules/wrap-ansi": {
       "version": "6.2.0",
       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
@@ -7395,12 +7795,39 @@
         }
       }
     },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/yallist": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
       "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
       "dev": true
     },
+    "node_modules/yargs": {
+      "version": "16.2.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+      "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+      "dev": true,
+      "dependencies": {
+        "cliui": "^7.0.2",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.0",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^20.2.2"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/yargs-parser": {
       "version": "20.2.9",
       "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
@@ -7410,6 +7837,42 @@
         "node": ">=10"
       }
     },
+    "node_modules/yargs-unparser": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+      "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^6.0.0",
+        "decamelize": "^4.0.0",
+        "flat": "^5.0.2",
+        "is-plain-obj": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs-unparser/node_modules/decamelize": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+      "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/yargs-unparser/node_modules/is-plain-obj": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/yauzl": {
       "version": "2.10.0",
       "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
diff --git a/package.json b/package.json
index da0ff83e..e452355c 100644
--- a/package.json
+++ b/package.json
@@ -2,8 +2,10 @@
   "name": "hsf-commonmoves",
   "private": true,
   "version": "1.0.0",
+  "type": "module",
   "description": "Starter project for Adobe Helix",
   "scripts": {
+    "test": "mocha",
     "lint:js": "eslint .",
     "lint:css": "stylelint blocks/**/*.css styles/*.css",
     "lint": "npm run lint:js && npm run lint:css"
@@ -21,13 +23,14 @@
   "devDependencies": {
     "@babel/core": "7.21.0",
     "@babel/eslint-parser": "7.19.1",
+    "@esm-bundle/chai": "4.3.4-fix.0",
+    "@web/test-runner": "0.15.1",
+    "@web/test-runner-commands": "0.6.5",
     "chai": "4.3.7",
     "eslint": "8.35.0",
     "eslint-config-airbnb-base": "15.0.0",
     "eslint-plugin-import": "2.27.5",
-    "@esm-bundle/chai": "4.3.4-fix.0",
-    "@web/test-runner": "0.15.1",
-    "@web/test-runner-commands": "0.6.5",
+    "mocha": "^10.2.0",
     "sinon": "15.0.1",
     "stylelint": "15.2.0",
     "stylelint-config-standard": "30.0.1"
diff --git a/scripts/apis/creg/ApplicationType.js b/scripts/apis/creg/ApplicationType.js
deleted file mode 100644
index 950daa53..00000000
--- a/scripts/apis/creg/ApplicationType.js
+++ /dev/null
@@ -1,25 +0,0 @@
-export default class ApplicationType {
-  constructor(type, label) {
-    this.type = type;
-    this.label = label;
-  }
-}
-
-ApplicationType.FOR_SALE = new ApplicationType('FOR_SALE', 'For Sale');
-ApplicationType.FOR_RENT = new ApplicationType('FOR_RENT', 'For Rent');
-ApplicationType.PENDING = new ApplicationType('PENDING', 'Pending');
-ApplicationType.RECENTLY_SOLD = new ApplicationType('RECENTLY_SOLD', 'Recently Sold');
-
-/**
-* Returns the ApplicationType for the specified string.
-*
-* @param {string} type
-* @returns {ApplicationType} the matching type.
-*/
-export function applicationTypeFor(type) {
-  const [found] = Object.getOwnPropertyNames(ApplicationType)
-    .filter((t) => t.toLowerCase() === type.toLowerCase())
-    .map((t) => ApplicationType[t]);
-
-  return found;
-}
diff --git a/scripts/apis/creg/OpenHouses.js b/scripts/apis/creg/OpenHouses.js
deleted file mode 100644
index 89e24046..00000000
--- a/scripts/apis/creg/OpenHouses.js
+++ /dev/null
@@ -1,9 +0,0 @@
-export default class OpenHouses {
-  constructor(value, label) {
-    this.value = value;
-    this.label = label;
-  }
-}
-
-OpenHouses.ONLY_WEEKEND = new OpenHouses(7, 'This Weekend');
-OpenHouses.ANYTIME = new OpenHouses(365, 'Anytime');
diff --git a/scripts/apis/creg/PropertyType.js b/scripts/apis/creg/PropertyType.js
deleted file mode 100644
index 7cad72b7..00000000
--- a/scripts/apis/creg/PropertyType.js
+++ /dev/null
@@ -1,13 +0,0 @@
-export default class PropertyType {
-  constructor(id, label) {
-    this.ID = id;
-    this.Label = label;
-  }
-}
-
-PropertyType.CONDO_TOWNHOUSE = new PropertyType(1, 'Condo/Townhouse');
-PropertyType.SINGLE_FAMILY = new PropertyType(2, 'Single Family');
-PropertyType.COMMERCIAL = new PropertyType(3, 'Commercial');
-PropertyType.MULTI_FAMILY = new PropertyType(4, 'Multi Family');
-PropertyType.LAND = new PropertyType(5, 'Lot/Land');
-PropertyType.FARM = new PropertyType(6, 'Farm/Ranch');
diff --git a/scripts/apis/creg/SearchParameters.js b/scripts/apis/creg/SearchParameters.js
deleted file mode 100644
index 2e964c0c..00000000
--- a/scripts/apis/creg/SearchParameters.js
+++ /dev/null
@@ -1,155 +0,0 @@
-import SearchType from './SearchType.js';
-import PropertyType from './PropertyType.js';
-import ApplicationType from './ApplicationType.js';
-
-const parseQuery = (queryString) => {
-  const parsed = {};
-  queryString.split('&').map((kvp) => kvp.split('=')).forEach((kv) => {
-    parsed[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]);
-  });
-  return parsed;
-};
-
-export const SortDirections = Object.freeze({
-  ASC: 'ASCENDING',
-  DESC: 'DESCENDING',
-});
-
-export const SortOptions = Object.freeze({
-  DATE: 'DATE',
-  PRICE: 'PRICE',
-  DISTANCE: 'DISTANCE',
-});
-
-export default class SearchParameters {
-  static DEFAULT_PAGE_SIZE = 32;
-
-  ListingStatus; // TODO: Find out what this means
-
-  MinPrice;
-
-  NewListing = false;
-
-  OpenHouses;
-
-  Page = 1;
-
-  PageSize = 32;
-
-  SearchInput = '';
-
-  SearchType = '';
-
-  #ApplicationType = ApplicationType.FOR_SALE.type;
-
-  #PropertyType = [PropertyType.CONDO_TOWNHOUSE, PropertyType.SINGLE_FAMILY].join(',');
-
-  #franchiseeCode;
-
-  #isFranchisePage = false;
-
-  #params = '';
-
-  #sort = 'PRICE_DESCENDING';
-
-  /**
-   * Create a new instance of the SearchParameters.
-   *
-   * @param {SearchType} type the type of search to perform
-   * @param {string} params the formatted params using the 'paramFormatterBuilder' from the type
-   */
-  constructor(type = SearchType.Empty, params = '') {
-    this.SearchType = type.type;
-    this.#params = params;
-  }
-
-  /**
-   * Set the types of property status type to include in search.
-   *
-   * @param {ApplicationType[]} types
-   */
-  set applicationTypes(types) {
-    this.#ApplicationType = types.map((t) => t.type).join(',');
-  }
-
-  /**
-   * Set the franchisee ID for context search.
-   *
-   * @param id
-   */
-  set franchisee(id) {
-    if (id) {
-      this.#franchiseeCode = id.toUpperCase();
-      this.#isFranchisePage = true;
-    } else {
-      this.#franchiseeCode = undefined;
-      this.#isFranchisePage = false;
-    }
-  }
-
-  /**
-   * Set the property types to search against.
-   *
-   * @param {PropertyType[]} types
-   */
-  set propertyTypes(types) {
-    this.#PropertyType = types.map((t) => t.ID).join(',');
-  }
-
-  /**
-   * Set the sort type
-   *
-   * @param {('DATE'|'PRICE')} sort property on which to sort
-   */
-  set sortBy(sort) {
-    const formatted = sort.toUpperCase();
-    if (SortOptions[formatted]) {
-      this.#sort = `${SortOptions[formatted]}_${this.#sort.split('_')[1]}`;
-    }
-  }
-
-  /**
-   * Set the sort direction
-   *
-   * @param {('ASC'|'DESC')} direction the direction of the sort
-   */
-  set sortDirection(direction) {
-    const formatted = direction.toUpperCase();
-    if (SortDirections[formatted]) {
-      this.#sort = `${this.#sort.split('_')[0]}_${SortDirections[formatted]}`;
-    }
-  }
-
-  /**
-   * Populates this search parameter from the provided query string.
-   *
-   * @param {String} queryString the query string to parse
-   */
-  populate(queryString) {
-    const query = parseQuery(queryString);
-    Object.keys(this).forEach((p) => {
-      if (query[p]) {
-        this[p] = query[p];
-      }
-    });
-  }
-
-  /**
-   * Converts this Search Parameter object into its URL query parameter equivalent
-   *
-   * @return {String} URL encoded representation of this
-   */
-  asQueryString() {
-    let query = Object.keys(this).filter((k) => this[k]).map((k) => `${k}=${encodeURIComponent(this[k])}`).join('&');
-    query += `&PropertyType=${this.#PropertyType}&ApplicationType=${this.#ApplicationType}`;
-    query += `&Sort=${this.#sort}&isFranchisePage=${this.#isFranchisePage}`;
-    if (this.#params) {
-      query += `&${this.#params}`;
-    }
-    if (this.#franchiseeCode) {
-      query += `&franchiseeCode=${this.#franchiseeCode}`;
-    }
-
-    return query;
-  }
-}
diff --git a/scripts/apis/creg/SearchType.js b/scripts/apis/creg/SearchType.js
deleted file mode 100644
index ae22b6b9..00000000
--- a/scripts/apis/creg/SearchType.js
+++ /dev/null
@@ -1,55 +0,0 @@
-const defaultParameterBuilder = (v) => `SearchParameter=${encodeURIComponent(v)}`;
-
-const mapParameterBuilder = (minLat, maxLat, minLon, maxLon) => {
-  const obj = {
-    type: 'FeatureCollection',
-    features: [{
-      type: 'Feature',
-      geometry: {
-        type: 'Polygon',
-        coordinates: [[
-          [minLon, minLat], // Bottom left
-          [minLon, maxLat], // Top left
-          [maxLon, maxLat], // Top right
-          [maxLon, minLat], // Bottom right
-          [minLon, minLat], // Close the box
-        ]],
-      },
-    }],
-  };
-  return `SearchParameter=${encodeURIComponent(JSON.stringify(obj))}`;
-};
-
-const radiusParameterBuilder = (lat, lon, radius) => `Latitude=${lat}&Longitude=${lon}&Distance=${radius}`;
-
-export default class SearchType {
-  constructor(type, parameterBuilder) {
-    this.type = type;
-    this.paramBuilder = parameterBuilder;
-  }
-}
-
-SearchType.Address = new SearchType('Address', defaultParameterBuilder);
-SearchType.City = new SearchType('City', defaultParameterBuilder);
-SearchType.Community = new SearchType('Community', mapParameterBuilder);
-SearchType.Empty = new SearchType('Empty', () => '');
-SearchType.Map = new SearchType('Map', mapParameterBuilder);
-SearchType.Neighborhood = new SearchType('Neighborhood', defaultParameterBuilder);
-SearchType.Radius = new SearchType('Radius', radiusParameterBuilder);
-SearchType.School = new SearchType('School', defaultParameterBuilder);
-SearchType.SchoolDistrict = new SearchType('School District', defaultParameterBuilder);
-SearchType.ZipCode = new SearchType('ZipCode', defaultParameterBuilder);
-SearchType.listingId = new SearchType('listingId', defaultParameterBuilder);
-
-/**
- * Returns the SearchType for the specified string.
- *
- * @param {string} type
- * @returns {SearchType} the matching type.
- */
-export function searchTypeFor(type) {
-  const [found] = Object.getOwnPropertyNames(SearchType)
-    .filter((t) => t.toLowerCase() === type.toLowerCase())
-    .map((t) => SearchType[t]);
-  return found;
-}
diff --git a/scripts/apis/creg/creg.js b/scripts/apis/creg/creg.js
index 4080f9e4..50a93e5b 100644
--- a/scripts/apis/creg/creg.js
+++ b/scripts/apis/creg/creg.js
@@ -1,92 +1,69 @@
 /* Wrapper for all Creg API endpoints */
 
-// eslint-disable-next-line no-unused-vars
-import SearchParameters from './SearchParameters.js';
+// TODO: Use Sidekick Plugin for this
+import { getMetadata } from '../../aem.js';
 
 const urlParams = new URLSearchParams(window.location.search);
 export const DOMAIN = urlParams.get('env') === 'stage' ? 'ignite-staging.bhhs.com' : 'www.bhhs.com';
 const CREG_API_URL = `https://${DOMAIN}/bin/bhhs`;
 
-let suggestionFetchController;
-
-const mapSuggestions = (json) => {
-  const results = [];
-  const { searchTypes, suggestions } = json;
-
-  if (!suggestions) {
-    return results;
-  }
-
-  const keys = Object.keys(suggestions);
-  keys.forEach((k) => {
-    if (!suggestions[k.toLowerCase()]) {
-      suggestions[k.toLowerCase()] = suggestions[k];
-    }
-  });
-  searchTypes.forEach((type) => {
-    const name = type.searchType.replaceAll(/\s+/g, '').toLowerCase();
-    if (suggestions[name] && suggestions[name].length) {
-      results.push({
-        ...type,
-        results: suggestions[name],
-      });
-    }
-  });
-
-  return results;
-};
+/**
+ * @typedef {Object} SearchResults
+ * @property {Array<Object>} properties
+ * @property {String} disclaimer
+ * @property {Array<Object>} clusters
+ * @property {String} pages
+ * @property {String} count
+ */
 
 /**
- * Get suggestions for users based on their input and optional country.
- *
- * @param {String} keyword the partial for suggestion search
- * @param {String} [country=undefined] optional country for narrowing search
+ * Perform a search and return only the properties.
  *
- * @return {Promise<Object[]>|undefined}
- *    Any available suggestions, or undefined if the search was aborted.
+ * @param {Search} search the Search object instance
+ * @return {Promise<SearchResults>} resolving the properties fetched
  */
-export async function getSuggestions(keyword, country = undefined) {
-  suggestionFetchController?.abort();
-  suggestionFetchController = new AbortController();
-
-  const { signal } = suggestionFetchController;
-
-  let endpoint = `${CREG_API_URL}/cregSearchSuggesterServlet?Keyword=${keyword}&_=${Date.now()}`;
-  if (country) {
-    endpoint += `&Country=${country}`;
-  }
-
-  return fetch(endpoint, { signal })
-    .then((resp) => {
-      if (resp.ok) {
-        return resp.json().then(mapSuggestions);
-      }
-      // eslint-disable-next-line no-console
-      console.log('Unable to fetch suggestions.');
-      return [];
-    }).catch((err) => {
-      if (err.name === 'AbortError') {
-        return undefined;
-      }
-      throw err;
+export async function propertySearch(search) {
+  return new Promise((resolve) => {
+    const worker = new Worker(`${window.hlx.codeBasePath}/scripts/apis/creg/workers/properties.js`, { type: 'module' });
+    worker.onmessage = (e) => resolve(e.data);
+    worker.postMessage({
+      api: CREG_API_URL,
+      search,
     });
+  });
 }
 
-export function abortSuggestions() {
-  suggestionFetchController?.abort();
+/**
+ * Perform a search, returning the metadata.
+ *
+ * @param {Search} search the Search object instance
+ * @return {Promise<Property[]>} resolving the properties fetched
+ */
+export async function metadataSearch(search) {
+  return new Promise((resolve) => {
+    const worker = new Worker(`${window.hlx.codeBasePath}/scripts/apis/creg/workers/metadata.js`, { type: 'module' });
+    worker.onmessage = (e) => resolve(e.data);
+    worker.postMessage({
+      api: CREG_API_URL,
+      search,
+    });
+  });
 }
 
 /**
- * Perform a search.
+ * Gets the details for the specified listings.
  *
- * @param {SearchParameters} params the parameters
+ * @param {string[]} listingIds list of listing ids
  */
-export function propertySearch(params) {
+export async function getDetails(...listingIds) {
   return new Promise((resolve) => {
-    const queryParams = params.asQueryString();
-    const worker = new Worker(`${window.hlx.codeBasePath}/scripts/apis/creg/workers/propertySearch.js`);
-    const url = `${CREG_API_URL}/CregPropertySearchServlet?${queryParams}&_=${Date.now()}`;
+    const officeId = getMetadata('office-id');
+    const worker = new Worker(`${window.hlx.codeBasePath}/scripts/apis/creg/workers/listing.js`, { type: 'module' });
     worker.onmessage = (e) => resolve(e.data);
-    worker.postMessage({ url });
+    worker.postMessage({
+      api: CREG_API_URL,
+      ids: listingIds,
+      officeId,
+    });
   });
 }
diff --git a/scripts/apis/creg/search/Search.js b/scripts/apis/creg/search/Search.js
new file mode 100644
index 00000000..ca11f0f0
--- /dev/null
+++ b/scripts/apis/creg/search/Search.js
@@ -0,0 +1,391 @@
+import ListingType from './types/ListingType.js';
+import PropertyType from './types/PropertyType.js';
+import OpenHouses from './types/OpenHouses.js';
+
+export const UPDATE_SEARCH_EVENT = 'UpdateSearch';
+
+export const STORAGE_KEY = 'CommonMovesSearchParams';
+export const SEARCH_URL = '/search';
+
+export default class Search {
+  input;
+
+  type = 'Empty';
+
+  minPrice;
+
+  maxPrice;
+
+  minBedrooms;
+
+  minBathrooms;
+
+  minSqft;
+
+  maxSqft;
+
+  keywords = [];
+
+  matchAnyKeyword = false;
+
+  minYear;
+
+  maxYear;
+
+  isNew = false;
+
+  priceChange = false;
+
+  luxury = false;
+
+  bhhsOnly = false;
+
+  page = '1';
+
+  pageSize = '36';
+
+  franchiseeCode;
+
+  // Private
+  #openHouses;
+
+  #listingTypes = [ListingType.FOR_SALE];
+
+  #propertyTypes = [PropertyType.CONDO_TOWNHOUSE, PropertyType.SINGLE_FAMILY];
+
+  #sortBy = 'PRICE';
+
+  #sortDirection = 'DESC';
+
+  constructor() {
+    Object.defineProperties(this, {
+      openHouses: {
+        enumerable: true,
+        set: (value) => {
+          if (typeof value === 'object' && OpenHouses[value.name]) {
+            this.#openHouses = OpenHouses[value.name];
+          } else {
+            this.#openHouses = OpenHouses[value] ? OpenHouses[value] : undefined;
+          }
+        },
+        get: () => this.#openHouses,
+      },
+
+      listingTypes: {
+        enumerable: true,
+        set: (types) => {
+          this.#listingTypes = [];
+          // eslint-disable-next-line no-param-reassign
+          types = !Array.isArray(types) ? [types] : types;
+          types.forEach((type) => {
+            this.addListingType(type);
+          });
+        },
+        get: () => [...this.#listingTypes],
+      },
+
+      propertyTypes: {
+        enumerable: true,
+        set: (types) => {
+          this.#propertyTypes = [];
+          // eslint-disable-next-line no-param-reassign
+          types = !Array.isArray(types) ? [types] : types;
+          types.forEach((type) => {
+            this.addPropertyType(type);
+          });
+        },
+        get: () => [...this.#propertyTypes],
+      },
+
+      sortBy: {
+        enumerable: true,
+        set: (value) => {
+          if (['DATE', 'PRICE', 'DISTANCE'].includes(value.toUpperCase())) {
+            this.#sortBy = value.toUpperCase();
+          }
+        },
+        get: () => this.#sortBy,
+      },
+
+      sortDirection: {
+        enumerable: true,
+        set: (value) => {
+          ['ASC', 'DESC'].forEach((d) => {
+            if (value.toUpperCase().indexOf(d) > -1) {
+              this.#sortDirection = d;
+            }
+          });
+        },
+        get: () => this.#sortDirection,
+      },
+    });
+  }
+
+  /**
+   * Adds a property type to the current list.
+   *
+   * @param {ListingType|String} type
+   */
+  addListingType(type) {
+    let t;
+    if (typeof type === 'object' && ListingType[type.type]) {
+      t = ListingType[type.type];
+    } else if (typeof type === 'string' && ListingType[type]) {
+      t = ListingType[type];
+    }
+    if (t && !this.#listingTypes.includes(t)) this.#listingTypes.push(t);
+  }
+
+  removeListingType(type) {
+    let t;
+    if (typeof type === 'object' && ListingType[type.type]) {
+      t = ListingType[type.type];
+    } else if (typeof type === 'string' && ListingType[type]) {
+      t = ListingType[type];
+    }
+    if (t && this.#listingTypes.includes(t)) {
+      const idx = this.#listingTypes.indexOf(t);
+      this.#listingTypes.splice(idx, 1);
+    }
+  }
+
+  /**
+   * Adds a property type to the current list.
+   *
+   * @param {PropertyType|String} type
+   */
+  addPropertyType(type) {
+    let t;
+    if (typeof type === 'object') {
+      if (type.name) {
+        t = PropertyType[type.name];
+      } else if (type.id) {
+        t = PropertyType.fromId(type.id);
+      }
+    } else if (typeof type === 'string') {
+      t = PropertyType[type];
+    } else if (typeof type === 'number') {
+      t = PropertyType.fromId(type);
+    }
+    if (t && !this.#propertyTypes.includes(t)) this.#propertyTypes.push(t);
+  }
+
+  /**
+   * Removes a property type to the current list.
+   *
+   * @param {PropertyType|String} type
+   */
+  removePropertyType(type) {
+    let t;
+    if (typeof type === 'object') {
+      if (type.name) {
+        t = PropertyType[type.name];
+      } else if (type.id) {
+        t = PropertyType.fromId(type.id);
+      }
+    } else if (typeof type === 'string') {
+      t = PropertyType[type];
+    } else if (typeof type === 'number') {
+      t = PropertyType.fromId(type);
+    }
+    if (t && this.#propertyTypes.includes(t)) {
+      const idx = this.#propertyTypes.indexOf(t);
+      this.#propertyTypes.splice(idx, 1);
+    }
+  }
+
+  /**
+   * Converts this Search instance into URL Search Parameters for the CREG API.
+   * @return {URLSearchParams}
+   */
+  asCregURLSearchParameters() {
+    const params = new URLSearchParams();
+    params.set('SearchType', this.type);
+
+    if (this.input) params.set('SearchInput', this.input);
+    if (this.minPrice) params.set('MinPrice', this.minPrice);
+    if (this.maxPrice) params.set('MaxPrice', this.maxPrice);
+    if (this.minBedrooms) params.set('MinBedroomsTotal', this.minBedrooms);
+    if (this.minBathrooms) params.set('MinBathroomsTotal', this.minBathrooms);
+    if (this.minSqft) params.set('MinLivingArea', this.minSqft);
+    if (this.maxSqft) params.set('MaxLivingArea', this.maxSqft);
+    if (this.keywords && this.keywords.length > 0) params.set('Features', this.keywords.join(','));
+    if (this.matchAnyKeyword) params.set('MatchAnyFeatures', 'true');
+    if (this.minYear || this.maxYear) {
+      params.set('YearBuilt', `${this.minYear || 1800}-${this.maxYear || 2100}`);
+    }
+    if (this.isNew) params.set('NewListing', 'true');
+    if (this.priceChange) params.set('RecentPriceChange', 'true');
+    if (this.luxury) params.set('Luxury', 'true');
+    if (this.bhhsOnly) params.set('FeaturedCompany', 'BHHS');
+    if (this.openHouses) params.set('OpenHouses', this.openHouses.value);
+
+    params.set('Page', this.page);
+    params.set('PageSize', this.pageSize);
+
+    params.set('ApplicationType', this.listingTypes.map((t) => t.type).join(','));
+    params.set('PropertyType', this.propertyTypes.map((t) => t.id).join(','));
+
+    if (this.franchiseeCode) {
+      params.set('isFranchisePage', 'true');
+      params.set('franchiseeCode', this.franchiseeCode.toUpperCase());
+    }
+
+    params.set('Sort', `${this.sortBy}_${this.sortDirection}ENDING`);
+    return params;
+  }
+
+  /**
+   * Returns a URLSearchParameter representing this object.
+   * @return {URLSearchParams}
+   */
+  asURLSearchParameters() {
+    const params = [];
+    Object.entries(this).forEach(([key, value]) => {
+      if (value) {
+        if (Array.isArray(value)) {
+          value.forEach((v) => {
+            params.push([key, v]);
+          });
+        } else {
+          params.push([key, value]);
+        }
+      }
+    });
+    return new URLSearchParams(params);
+  }
+
+  populateFromURLSearchParameters(params) {
+    [...params.entries()].forEach(([k, v]) => {
+      if (k === 'type') {
+        return;
+      }
+      // Fill object.
+      if (Object.hasOwn(this, k)) {
+        this[k] = v;
+      }
+    });
+    this.listingTypes = params.getAll('listingTypes');
+    this.propertyTypes = params.getAll('propertyTypes');
+    this.keywords = params.getAll('keywords');
+    // Coerce boolean
+    if (typeof this.isNew === 'string') {
+      this.isNew = Boolean(this.isNew).valueOf();
+    }
+    if (typeof this.matchAnyKeyword === 'string') {
+      this.matchAnyKeyword = Boolean(this.matchAnyKeyword).valueOf();
+    }
+    if (typeof this.priceChange === 'string') {
+      this.priceChange = Boolean(this.priceChange).valueOf();
+    }
+    if (typeof this.luxury === 'string') {
+      this.luxury = Boolean(this.luxury).valueOf();
+    }
+    if (typeof this.bhhsOnly === 'string') {
+      this.bhhsOnly = Boolean(this.bhhsOnly).valueOf();
+    }
+  }
+
+  populateFromConfig(entries) {
+    let entry = entries.find(([k]) => k.match(/min.*price/i));
+    if (entry) [, this.minPrice] = entry;
+    entry = entries.find(([k]) => k.match(/max.*price/i));
+
+    if (entry) [, this.maxPrice] = entry;
+    this.isNew = !!entries.find(([k]) => k.match(/new/i));
+
+    entry = entries.find(([k]) => k.match(/open.*house/i));
+    if (entry) this.openHouses = OpenHouses.fromBlockConfig(entry);
+
+    entry = entries.find(([k]) => k.match(/page.*size/i));
+    if (entry) [, this.pageSize] = entry;
+
+    this.listingTypes = ListingType.fromBlockConfig(entries.find(([k]) => k.match(/(listing|application).*type/i)));
+    this.propertyTypes = PropertyType.fromBlockConfig(entries.find(([k]) => k.match(/property.*type/i)));
+
+    entry = entries.find(([k]) => k.match(/sort.*by/i));
+    if (entry) this.sortBy = entry[1].toUpperCase();
+
+    entry = entries.find(([k]) => k.match(/sort.*direction/i));
+    if (entry) this.sortDirection = entry[1].toUpperCase();
+  }
+
+  /**
+   * Populates from the Suggestion URL Parameters
+   * @param {URLSearchParams} params
+   */
+  populateFromSuggestion(params) {
+    this.input = params.get('SearchInput');
+  }
+
+  /**
+   * Loads the specified search type.
+   *
+   * @param {string} type
+   * @return {Promise<Search>}
+   */
+  static async load(type) {
+    let search = new Search();
+    if (type && type !== 'Empty') {
+      try {
+        const mod = await import(`./types/${type}Search.js`);
+        if (mod.default) {
+          // eslint-disable-next-line new-cap
+          search = new mod.default();
+        }
+      } catch (error) {
+        // eslint-disable-next-line no-console
+        console.log(`failed to load Search Type for ${type}`, error);
+      }
+    }
+    return search;
+  }
+
+  /**
+   * Builds a new Search instance from a URL query string
+   * @param {String} query the query string
+   * @return {Promise<Search>} the search instance
+   */
+  static async fromQueryString(query) {
+    const params = new URLSearchParams(query);
+    let search = new Search();
+    if (params.has('type') && params.get('type') !== 'Empty') {
+      const type = params.get('type').replace(/(^\w)|\s+(\w)/g, (letter) => letter.toUpperCase());
+      search = await Search.load(type);
+    }
+    search.populateFromURLSearchParameters(params);
+    return search;
+  }
+
+  /**
+   * Builds a new Search instance from a Block Config.
+   * @param {Object} config the block config
+   * @return {Promise<Search>} the search instance
+   */
+  static async fromBlockConfig(config) {
+    const entries = Object.entries(config);
+    let search = new Search();
+    const typeInput = entries.find(([k]) => k.match(/search.*type/i));
+    if (typeInput) {
+      const type = typeInput[1].replace(/(^\w)|\s+(\w)/g, (letter) => letter.toUpperCase()).replaceAll(/\s/g, '');
+      search = await Search.load(type);
+    }
+    search.populateFromConfig(entries);
+    return search;
+  }
+
+  /**
+   * Creates Search instance from a JSON Object.
+   * @param {Object} json
+   * @return {Promise<Search>} the search instance
+   */
+  static async fromJSON(json) {
+    let search = new Search();
+    const { type } = json;
+    if (type && type !== 'Empty') {
+      search = await Search.load(type);
+    }
+    Object.assign(search, json);
+    return search;
+  }
+}
diff --git a/scripts/apis/creg/search/types/AddressSearch.js b/scripts/apis/creg/search/types/AddressSearch.js
new file mode 100644
index 00000000..c727905c
--- /dev/null
+++ b/scripts/apis/creg/search/types/AddressSearch.js
@@ -0,0 +1,28 @@
+import Search from '../Search.js';
+
+export default class AddressSearch extends Search {
+  address;
+
+  constructor() {
+    super();
+    this.type = 'Address';
+  }
+
+  asCregURLSearchParameters() {
+    const params = super.asCregURLSearchParameters();
+    params.set('SearchType', 'Address');
+    params.set('SearchParameter', this.address);
+    return params;
+  }
+
+  populateFromConfig(entries) {
+    super.populateFromConfig(entries);
+    const entry = entries.find(([k]) => k.includes('address'));
+    if (entry) [, this.address] = entry;
+  }
+
+  populateFromSuggestion(params) {
+    super.populateFromSuggestion(params);
+    this.address = params.get('SearchParameter');
+  }
+}
diff --git a/scripts/apis/creg/search/types/BoxSearch.js b/scripts/apis/creg/search/types/BoxSearch.js
new file mode 100644
index 00000000..6ab30697
--- /dev/null
+++ b/scripts/apis/creg/search/types/BoxSearch.js
@@ -0,0 +1,81 @@
+import Search from '../Search.js';
+
+export default class BoxSearch extends Search {
+  #minLat;
+
+  #maxLat;
+
+  #minLon;
+
+  #maxLon;
+
+  constructor() {
+    super();
+    this.type = 'Box';
+    Object.defineProperties(this, {
+      minLat: {
+        enumerable: true,
+        set: (value) => {
+          this.#minLat = `${parseFloat(`${value}`).toFixed(7)}`;
+        },
+        get: () => this.#minLat,
+      },
+      maxLat: {
+        enumerable: true,
+        set: (value) => {
+          this.#maxLat = `${parseFloat(`${value}`).toFixed(7)}`;
+        },
+        get: () => this.#maxLat,
+      },
+      minLon: {
+        enumerable: true,
+        set: (value) => {
+          this.#minLon = `${parseFloat(`${value}`).toFixed(7)}`;
+        },
+        get: () => this.#minLon,
+      },
+      maxLon: {
+        enumerable: true,
+        set: (value) => {
+          this.#maxLon = `${parseFloat(`${value}`).toFixed(7)}`;
+        },
+        get: () => this.#maxLon,
+      },
+    });
+  }
+
+  asCregURLSearchParameters() {
+    const params = super.asCregURLSearchParameters();
+    params.set('SearchType', 'Map');
+    const obj = {
+      type: 'FeatureCollection',
+      features: [{
+        type: 'Feature',
+        geometry: {
+          type: 'Polygon',
+          coordinates: [[
+            [this.minLon, this.minLat], // Bottom left
+            [this.minLon, this.maxLat], // Top left
+            [this.maxLon, this.maxLat], // Top right
+            [this.maxLon, this.minLat], // Bottom right
+            [this.minLon, this.minLat], // Close the box
+          ]],
+        },
+      }],
+    };
+    params.set('SearchParameter', JSON.stringify(obj));
+    return params;
+  }
+
+  populateFromConfig(entries) {
+    super.populateFromConfig(entries);
+    let entry = entries.find(([k]) => k.includes('min') && k.includes('lat'));
+    if (entry) [, this.minLat] = entry;
+    entry = entries.find(([k]) => k.includes('max') && k.includes('lat'));
+    if (entry) [, this.maxLat] = entry;
+    entry = entries.find(([k]) => k.includes('min') && k.includes('lon'));
+    if (entry) [, this.minLon] = entry;
+    entry = entries.find(([k]) => k.includes('max') && k.includes('lon'));
+    if (entry) [, this.maxLon] = entry;
+  }
+}
diff --git a/scripts/apis/creg/search/types/CitySearch.js b/scripts/apis/creg/search/types/CitySearch.js
new file mode 100644
index 00000000..fd318d62
--- /dev/null
+++ b/scripts/apis/creg/search/types/CitySearch.js
@@ -0,0 +1,28 @@
+import Search from '../Search.js';
+
+export default class CitySearch extends Search {
+  city;
+
+  constructor() {
+    super();
+    this.type = 'City';
+  }
+
+  asCregURLSearchParameters() {
+    const params = super.asCregURLSearchParameters();
+    params.set('SearchType', 'City');
+    params.set('SearchParameter', this.city);
+    return params;
+  }
+
+  populateFromConfig(entries) {
+    super.populateFromConfig(entries);
+    const entry = entries.find(([k]) => k.includes('city'));
+    if (entry) [, this.city] = entry;
+  }
+
+  populateFromSuggestion(params) {
+    super.populateFromSuggestion(params);
+    this.city = params.get('SearchParameter');
+  }
+}
diff --git a/scripts/apis/creg/search/types/ElementarySchoolSearch.js b/scripts/apis/creg/search/types/ElementarySchoolSearch.js
new file mode 100644
index 00000000..c83ff476
--- /dev/null
+++ b/scripts/apis/creg/search/types/ElementarySchoolSearch.js
@@ -0,0 +1,10 @@
+import SchoolSearch from './SchoolSearch.js';
+
+export default class ElementarySchoolSearch extends SchoolSearch {
+  school;
+
+  constructor() {
+    super();
+    this.type = 'ElementarySchool';
+  }
+}
diff --git a/scripts/apis/creg/search/types/HighSchoolSearch.js b/scripts/apis/creg/search/types/HighSchoolSearch.js
new file mode 100644
index 00000000..1223df4e
--- /dev/null
+++ b/scripts/apis/creg/search/types/HighSchoolSearch.js
@@ -0,0 +1,10 @@
+import SchoolSearch from './SchoolSearch.js';
+
+export default class HighSchoolSearch extends SchoolSearch {
+  school;
+
+  constructor() {
+    super();
+    this.type = 'HighSchool';
+  }
+}
diff --git a/scripts/apis/creg/search/types/ListingType.js b/scripts/apis/creg/search/types/ListingType.js
new file mode 100644
index 00000000..abffdc0b
--- /dev/null
+++ b/scripts/apis/creg/search/types/ListingType.js
@@ -0,0 +1,38 @@
+export default class ListingType {
+  constructor(type, label) {
+    this.type = type;
+    this.label = label;
+  }
+
+  toString() {
+    return this.type;
+  }
+
+  static fromBlockConfig(configEntry) {
+    const types = [];
+    if (!configEntry) {
+      types.push(ListingType.FOR_SALE);
+      return types;
+    }
+
+    const [, configStr] = configEntry;
+    if (configStr.match(/sale/i)) {
+      types.push(ListingType.FOR_SALE);
+    }
+    if (configStr.match(/rent/gi)) {
+      types.push(ListingType.FOR_RENT);
+    }
+    if (configStr.match(/pending/gi)) {
+      types.push(ListingType.PENDING);
+    }
+    if (configStr.match(/sold/gi)) {
+      types.push(ListingType.RECENTLY_SOLD);
+    }
+    return types;
+  }
+}
+
+ListingType.FOR_SALE = new ListingType('FOR_SALE', 'For Sale');
+ListingType.FOR_RENT = new ListingType('FOR_RENT', 'For Rent');
+ListingType.PENDING = new ListingType('PENDING', 'Pending');
+ListingType.RECENTLY_SOLD = new ListingType('RECENTLY_SOLD', 'Recently Sold');
diff --git a/scripts/apis/creg/search/types/MLSListingKeySearch.js b/scripts/apis/creg/search/types/MLSListingKeySearch.js
new file mode 100644
index 00000000..232a54b8
--- /dev/null
+++ b/scripts/apis/creg/search/types/MLSListingKeySearch.js
@@ -0,0 +1,38 @@
+import Search from '../Search.js';
+
+/**
+ * Special case of search - not to be confused with searching for a specific property based on the listing ID.
+ * MLS Key searches require the context of the ID to validate franchisee metadata (e.g. vanityDomain)
+ */
+export default class MLSListingKeySearch extends Search {
+  listingId;
+
+  context;
+
+  constructor() {
+    super();
+    this.type = 'MLSListingKey';
+  }
+
+  asCregURLSearchParameters() {
+    const params = super.asCregURLSearchParameters();
+    params.set('SearchType', 'MLSListingKey');
+    params.set('ListingId', this.listingId);
+    params.set('SearchParameter', this.context);
+    return params;
+  }
+
+  populateFromConfig(entries) {
+    super.populateFromConfig(entries);
+    let entry = entries.find(([k]) => k.match(/mls.*listing.*key/i));
+    if (entry) [, this.listingId] = entry;
+    entry = entries.find(([k]) => k.match(/context/));
+    if (entry) [, this.context] = entry;
+  }
+
+  populateFromSuggestion(params) {
+    super.populateFromSuggestion(params);
+    this.listingId = params.get('ListingId');
+    this.context = params.get('SearchParameter');
+  }
+}
diff --git a/scripts/apis/creg/search/types/MiddleSchoolSearch.js b/scripts/apis/creg/search/types/MiddleSchoolSearch.js
new file mode 100644
index 00000000..e7207b9d
--- /dev/null
+++ b/scripts/apis/creg/search/types/MiddleSchoolSearch.js
@@ -0,0 +1,10 @@
+import SchoolSearch from './SchoolSearch.js';
+
+export default class MiddleSchoolSearch extends SchoolSearch {
+  school;
+
+  constructor() {
+    super();
+    this.type = 'MiddleSchool';
+  }
+}
diff --git a/scripts/apis/creg/search/types/NeighborhoodSearch.js b/scripts/apis/creg/search/types/NeighborhoodSearch.js
new file mode 100644
index 00000000..b61323d6
--- /dev/null
+++ b/scripts/apis/creg/search/types/NeighborhoodSearch.js
@@ -0,0 +1,28 @@
+import Search from '../Search.js';
+
+export default class NeighborhoodSearch extends Search {
+  neighborhood;
+
+  constructor() {
+    super();
+    this.type = 'Neighborhood';
+  }
+
+  asCregURLSearchParameters() {
+    const params = super.asCregURLSearchParameters();
+    params.set('SearchType', 'Neighborhood');
+    params.set('SearchParameter', this.neighborhood);
+    return params;
+  }
+
+  populateFromConfig(entries) {
+    super.populateFromConfig(entries);
+    const entry = entries.find(([k]) => k.includes('neighborhood'));
+    if (entry) [, this.neighborhood] = entry;
+  }
+
+  populateFromSuggestion(params) {
+    super.populateFromSuggestion(params);
+    this.neighborhood = params.get('SearchParameter');
+  }
+}
diff --git a/scripts/apis/creg/search/types/OpenHouses.js b/scripts/apis/creg/search/types/OpenHouses.js
new file mode 100644
index 00000000..996c94ff
--- /dev/null
+++ b/scripts/apis/creg/search/types/OpenHouses.js
@@ -0,0 +1,39 @@
+export default class OpenHouses {
+  constructor(name, value, label) {
+    this.name = name;
+    this.value = value;
+    this.label = label;
+  }
+
+  toString() {
+    return this.name;
+  }
+
+  static fromBlockConfig(configEntry) {
+    if (configEntry && /weekend/i.test(configEntry)) {
+      return OpenHouses.ONLY_WEEKEND;
+    }
+    return OpenHouses.ANYTIME;
+  }
+
+  /**
+   * Finds the OpenHouse based on the value.
+   *
+   * @param value the value of the OpenHouse type
+   * @return {undefined|OpenHouses}
+   */
+  static fromValue(value) {
+    // eslint-disable-next-line no-param-reassign
+    value = (typeof value === 'number') ? value.toFixed(0) : value;
+    if (value === OpenHouses.ONLY_WEEKEND.value.toFixed(0)) {
+      return OpenHouses.ONLY_WEEKEND;
+    }
+    if (value === OpenHouses.ANYTIME.value.toFixed(0)) {
+      return OpenHouses.ANYTIME;
+    }
+    return undefined;
+  }
+}
+
+OpenHouses.ONLY_WEEKEND = new OpenHouses('ONLY_WEEKEND', 7, 'This Weekend');
+OpenHouses.ANYTIME = new OpenHouses('ANYTIME', 365, 'Anytime');
diff --git a/scripts/apis/creg/search/types/PolygonSearch.js b/scripts/apis/creg/search/types/PolygonSearch.js
new file mode 100644
index 00000000..4a065283
--- /dev/null
+++ b/scripts/apis/creg/search/types/PolygonSearch.js
@@ -0,0 +1,86 @@
+import Search from '../Search.js';
+
+export default class PolygonSearch extends Search {
+  #points = [];
+
+  constructor() {
+    super();
+    this.type = 'Polygon';
+    Object.defineProperties(this, {
+      points: {
+        enumerable: true,
+        set: (value) => {
+          this.#points.length = 0;
+          if (value instanceof Array) {
+            value.forEach((item) => {
+              const { lat, lon } = item;
+              if (lat && lon) {
+                this.#points.push({ lat, lon });
+              }
+            });
+          }
+        },
+        get: () => structuredClone(this.#points),
+      },
+    });
+  }
+
+  /**
+   * Add a point to the list of points in this Polygon search.
+   * @param {Object} point the point
+   * @param {number|String} point.lat the latitude of the point
+   * @param {number|String} point.lon the longitude of the point
+   */
+  addPoint(point) {
+    const { lat, lon } = point;
+    if (lat && lon) {
+      this.#points.push({ lat, lon });
+    }
+  }
+
+  asCregURLSearchParameters() {
+    const coordinates = [];
+    this.points.forEach((p) => {
+      coordinates.push([p.lon, p.lat]);
+    });
+    coordinates.push([this.points[0].lon, this.points[0].lat]);
+    const params = super.asCregURLSearchParameters();
+    params.set('SearchType', 'Map');
+    const obj = {
+      type: 'FeatureCollection',
+      features: [{
+        type: 'Feature',
+        geometry: {
+          type: 'Polygon',
+          coordinates: [coordinates],
+        },
+      }],
+    };
+    params.set('SearchParameter', JSON.stringify(obj));
+    return params;
+  }
+
+  asURLSearchParameters() {
+    const params = super.asURLSearchParameters();
+    params.delete('points');
+    this.#points.forEach((p) => {
+      params.append('point', `${p.lat},${p.lon}`);
+    });
+    return params;
+  }
+
+  populateFromURLSearchParameters(params) {
+    const points = params.getAll('point');
+    params.delete('point');
+    super.populateFromURLSearchParameters(params);
+    points.forEach((p) => {
+      const [lat, lon] = p.split(',');
+      this.addPoint({ lat, lon });
+    });
+  }
+
+  // eslint-disable-next-line class-methods-use-this
+  populateFromConfig() {
+    throw new Error('PolygonSearch cannot be used in Block config.');
+  }
+}
diff --git a/scripts/apis/creg/search/types/PostalCodeSearch.js b/scripts/apis/creg/search/types/PostalCodeSearch.js
new file mode 100644
index 00000000..d6c154f2
--- /dev/null
+++ b/scripts/apis/creg/search/types/PostalCodeSearch.js
@@ -0,0 +1,28 @@
+import Search from '../Search.js';
+
+export default class PostalCodeSearch extends Search {
+  code;
+
+  constructor() {
+    super();
+    this.type = 'PostalCode';
+  }
+
+  asCregURLSearchParameters() {
+    const params = super.asCregURLSearchParameters();
+    params.set('SearchType', 'PostalCode');
+    params.set('CoverageZipcode', this.code);
+    return params;
+  }
+
+  populateFromConfig(entries) {
+    super.populateFromConfig(entries);
+    const entry = entries.find(([k]) => k.match(/postal.*code/i));
+    if (entry) [, this.code] = entry;
+  }
+
+  populateFromSuggestion(params) {
+    super.populateFromSuggestion(params);
+    this.code = params.get('CoverageZipcode');
+  }
+}
diff --git a/scripts/apis/creg/search/types/PropertyType.js b/scripts/apis/creg/search/types/PropertyType.js
new file mode 100644
index 00000000..9115ef90
--- /dev/null
+++ b/scripts/apis/creg/search/types/PropertyType.js
@@ -0,0 +1,72 @@
+export default class PropertyType {
+  constructor(name, value, label) {
+    this.name = name;
+    this.id = value;
+    this.label = label;
+  }
+
+  toString() {
+    return this.name;
+  }
+
+  /**
+   * Finds the Property type based on the provided id.
+   * @param {integer} id the id
+   * @return {PropertyType} the type for the id
+   */
+  static fromId(id) {
+    // eslint-disable-next-line no-use-before-define
+    if (id < 0 || id > ALL.length - 1) {
+      return undefined;
+    }
+    // eslint-disable-next-line no-use-before-define
+    return ALL[id];
+  }
+
+  static fromBlockConfig(configEntry) {
+    const types = [];
+    if (!configEntry) {
+      types.push(PropertyType.CONDO_TOWNHOUSE);
+      types.push(PropertyType.SINGLE_FAMILY);
+      return types;
+    }
+
+    const [, configStr] = configEntry;
+    if (configStr.match(/(condo|townhouse)/i)) {
+      types.push(PropertyType.CONDO_TOWNHOUSE);
+    }
+    if (configStr.match(/single\s+family/gi)) {
+      types.push(PropertyType.SINGLE_FAMILY);
+    }
+    if (configStr.match(/commercial/gi)) {
+      types.push(PropertyType.COMMERCIAL);
+    }
+    if (configStr.match(/multi\s+family/gi)) {
+      types.push(PropertyType.MULTI_FAMILY);
+    }
+    if (configStr.match(/(lot|land)/gi)) {
+      types.push(PropertyType.LAND);
+    }
+    if (configStr.match(/(farm|ranch)/gi)) {
+      types.push(PropertyType.FARM);
+    }
+    return types;
+  }
+}
+
+PropertyType.CONDO_TOWNHOUSE = new PropertyType('CONDO_TOWNHOUSE', 1, 'Condo/Townhouse');
+PropertyType.SINGLE_FAMILY = new PropertyType('SINGLE_FAMILY', 2, 'Single Family');
+PropertyType.COMMERCIAL = new PropertyType('COMMERCIAL', 3, 'Commercial');
+PropertyType.MULTI_FAMILY = new PropertyType('MULTI_FAMILY', 4, 'Multi Family');
+PropertyType.LAND = new PropertyType('LAND', 5, 'Lot/Land');
+PropertyType.FARM = new PropertyType('FARM', 6, 'Farm/Ranch');
+
+const ALL = [
+  undefined, // Empty space
+  PropertyType.CONDO_TOWNHOUSE,
+  PropertyType.SINGLE_FAMILY,
+  PropertyType.COMMERCIAL,
+  PropertyType.MULTI_FAMILY,
+  PropertyType.LAND,
+  PropertyType.FARM,
+];
diff --git a/scripts/apis/creg/search/types/RadiusSearch.js b/scripts/apis/creg/search/types/RadiusSearch.js
new file mode 100644
index 00000000..37ac7d96
--- /dev/null
+++ b/scripts/apis/creg/search/types/RadiusSearch.js
@@ -0,0 +1,56 @@
+import Search from '../Search.js';
+
+export default class RadiusSearch extends Search {
+  #lat;
+
+  #lon;
+
+  #distance;
+
+  constructor() {
+    super();
+    this.type = 'Radius';
+    Object.defineProperties(this, {
+      lat: {
+        enumerable: true,
+        set: (value) => {
+          this.#lat = `${parseFloat(`${value}`).toFixed(7)}`;
+        },
+        get: () => this.#lat,
+      },
+      lon: {
+        enumerable: true,
+        set: (value) => {
+          this.#lon = `${parseFloat(`${value}`).toFixed(7)}`;
+        },
+        get: () => this.#lon,
+      },
+      distance: {
+        enumerable: true,
+        set: (value) => {
+          this.#distance = `${value}`;
+        },
+        get: () => this.#distance,
+      },
+    });
+  }
+
+  asCregURLSearchParameters() {
+    const params = super.asCregURLSearchParameters();
+    params.set('SearchType', this.type);
+    params.set('Latitude', this.lat);
+    params.set('Longitude', this.lon);
+    params.set('Distance', this.distance);
+    return params;
+  }
+
+  populateFromConfig(entries) {
+    super.populateFromConfig(entries);
+    let entry = entries.find(([k]) => k.includes('lat'));
+    if (entry) [, this.lat] = entry;
+    entry = entries.find(([k]) => k.includes('lon'));
+    if (entry) [, this.lon] = entry;
+    entry = entries.find(([k]) => k.includes('dist'));
+    if (entry) [, this.distance] = entry;
+  }
+}
diff --git a/scripts/apis/creg/search/types/SchoolDistrictSearch.js b/scripts/apis/creg/search/types/SchoolDistrictSearch.js
new file mode 100644
index 00000000..b574e54a
--- /dev/null
+++ b/scripts/apis/creg/search/types/SchoolDistrictSearch.js
@@ -0,0 +1,28 @@
+import Search from '../Search.js';
+
+export default class SchoolDistrictSearch extends Search {
+  district;
+
+  constructor() {
+    super();
+    this.type = 'SchoolDistrict';
+  }
+
+  asCregURLSearchParameters() {
+    const params = super.asCregURLSearchParameters();
+    params.set('SearchType', 'SchoolDistrict');
+    params.set('SearchParameter', this.district);
+    return params;
+  }
+
+  populateFromConfig(entries) {
+    super.populateFromConfig(entries);
+    const entry = entries.find(([k]) => k.match(/school.*district/i));
+    if (entry) [, this.district] = entry;
+  }
+
+  populateFromSuggestion(params) {
+    super.populateFromSuggestion(params);
+    this.district = params.get('SearchParameter');
+  }
+}
diff --git a/scripts/apis/creg/search/types/SchoolSearch.js b/scripts/apis/creg/search/types/SchoolSearch.js
new file mode 100644
index 00000000..d934f74c
--- /dev/null
+++ b/scripts/apis/creg/search/types/SchoolSearch.js
@@ -0,0 +1,23 @@
+import Search from '../Search.js';
+
+export default class SchoolSearch extends Search {
+  school;
+
+  asCregURLSearchParameters() {
+    const params = super.asCregURLSearchParameters();
+    params.set('SearchType', this.type);
+    params.set('SearchParameter', this.school);
+    return params;
+  }
+
+  populateFromConfig(entries) {
+    super.populateFromConfig(entries);
+    const entry = entries.find(([k]) => k.includes('school'));
+    if (entry) [, this.school] = entry;
+  }
+
+  populateFromSuggestion(params) {
+    super.populateFromSuggestion(params);
+    this.school = params.get('SearchParameter');
+  }
+}
diff --git a/scripts/apis/creg/suggestion.js b/scripts/apis/creg/suggestion.js
new file mode 100644
index 00000000..50198598
--- /dev/null
+++ b/scripts/apis/creg/suggestion.js
@@ -0,0 +1,72 @@
+const urlParams = new URLSearchParams(window.location.search);
+export const DOMAIN = urlParams.get('env') === 'stage' ? 'ignite-staging.bhhs.com' : 'www.bhhs.com';
+const CREG_API_URL = `https://${DOMAIN}/bin/bhhs`;
+
+let suggestionFetchController;
+
+const mapSuggestions = (json) => {
+  const results = [];
+  const { searchTypes, suggestions } = json;
+
+  if (!suggestions) {
+    return results;
+  }
+  const keys = Object.keys(suggestions);
+  keys.forEach((k) => {
+    if (!suggestions[k.toLowerCase()]) {
+      suggestions[k.toLowerCase()] = suggestions[k];
+    }
+  });
+  searchTypes.forEach((type) => {
+    let name = type.searchType.replaceAll(/\s+/g, '').toLowerCase();
+    if (name === 'zip') name = 'zipcode'; // ZipCode != Zip - and broke somewhere along the way.
+    if (suggestions[name] && suggestions[name].length) {
+      results.push({
+        ...type,
+        results: suggestions[name],
+      });
+    }
+  });
+
+  return results;
+};
+
+/**
+ * Get suggestions for users based on their input and optional country.
+ *
+ * @param {String} keyword the partial for suggestion search
+ * @param {String} [country=undefined] optional country for narrowing search
+ *
+ * @return {Promise<Object[]>|undefined}
+ *    Any available suggestions, or undefined if the search was aborted.
+ */
+export async function get(keyword, country = undefined) {
+  suggestionFetchController?.abort();
+  suggestionFetchController = new AbortController();
+
+  const { signal } = suggestionFetchController;
+
+  let endpoint = `${CREG_API_URL}/cregSearchSuggesterServlet?Keyword=${keyword}&_=${Date.now()}`;
+  if (country) {
+    endpoint += `&Country=${country}`;
+  }
+
+  return fetch(endpoint, { signal })
+    .then((resp) => {
+      if (resp.ok) {
+        return resp.json().then(mapSuggestions);
+      }
+      // eslint-disable-next-line no-console
+      console.log('Unable to fetch suggestions.');
+      return [];
+    }).catch((err) => {
+      if (err.name === 'AbortError') {
+        return undefined;
+      }
+      throw err;
+    });
+}
+
+export function abort() {
+  suggestionFetchController?.abort();
+}
diff --git a/scripts/apis/creg/workers/listing.js b/scripts/apis/creg/workers/listing.js
new file mode 100644
index 00000000..4872eefa
--- /dev/null
+++ b/scripts/apis/creg/workers/listing.js
@@ -0,0 +1,21 @@
+/**
+ * Handle the Worker event. Fetches details for each provided listing id.
+ *
+ * @param {Object} event the worker event.
+ * @param {string} event.data.api the URL to fetch.
+ * @param {string[]} event.data.ids list of listing ids
+ */
+onmessage = async (event) => {
+  const { api, ids, officeId } = event.data;
+  const promises = [];
+  ids.forEach((id) => {
+    promises.push(
+      fetch(`${api}/CregPropertySearchServlet?SearchType=ListingId&ListingId=${id}${officeId ? `&OfficeCode=${officeId}` : ''}`)
+        .then((resp) => (resp.ok ? resp.json() : undefined)),
+    );
+  });
+
+  Promise.all(promises).then((values) => {
+    postMessage(values.filter((v) => v));
+  });
+};
diff --git a/scripts/apis/creg/workers/metadata.js b/scripts/apis/creg/workers/metadata.js
new file mode 100644
index 00000000..a1b3b156
--- /dev/null
+++ b/scripts/apis/creg/workers/metadata.js
@@ -0,0 +1,35 @@
+import Search from '../search/Search.js';
+
+/**
+ * Handle the Worker event.
+ *
+ * @param {Object} event the worker event.
+ * @param {string} event.data.api the URL to fetch.
+ * @param {Search} event.data.searches search context
+ *
+ */
+onmessage = async (event) => {
+  const { api, search } = event.data;
+  const results = await Search.fromJSON(search)
+    .then((s) => {
+      try {
+        return fetch(`${api}/CregPropertySearchServlet?${s.asCregURLSearchParameters()}`);
+      } catch (error) {
+        // eslint-disable-next-line no-console
+        console.log('Failed to fetch properties from API.', error);
+        return {};
+      }
+    })
+    .then((resp) => {
+      if (resp.ok) {
+        return resp.json();
+      }
+      return {};
+    }) || {};
+  Object.keys(results).forEach((k) => {
+    if (typeof results[k] === 'object' || Array.isArray(results[k])) {
+      delete results[k];
+    }
+  });
+  postMessage(results);
+};
diff --git a/scripts/apis/creg/workers/properties.js b/scripts/apis/creg/workers/properties.js
new file mode 100644
index 00000000..0f856ff1
--- /dev/null
+++ b/scripts/apis/creg/workers/properties.js
@@ -0,0 +1,47 @@
+import Search from '../search/Search.js';
+
+/**
+ * Handle the Worker event.
+ *
+ * @param {Object} event the worker event.
+ * @param {string} event.data.api the URL to fetch.
+ * @param {Search} event.data.searches search context
+ */
+onmessage = async (event) => {
+  const { api, search } = event.data;
+  const results = await Search.fromJSON(search)
+    .then((s) => {
+      try {
+        return fetch(`${api}/CregPropertySearchServlet?${s.asCregURLSearchParameters()}`);
+      } catch (error) {
+        // eslint-disable-next-line no-console
+        console.log('Failed to fetch properties from API.', error);
+        return {};
+      }
+    })
+    .then((resp) => {
+      if (resp.ok) {
+        return resp.json();
+      }
+      return {};
+    })
+    .catch((error) => {
+      // eslint-disable-next-line no-console
+      console.log('Failed to fetch properties from API.', error);
+      return {};
+    });
+  if (results) {
+    const resp = {
+      properties: results.properties || [],
+      disclaimer: results.disclaimer.Text,
+      clusters: results.listingClusters || [],
+      pins: results.listingPins || [],
+      pages: results['@odata.context'],
+      page: search.page,
+      count: results['@odata.count'],
+    };
+    postMessage(resp);
+  } else {
+    postMessage([]);
+  }
+};
diff --git a/scripts/apis/creg/workers/propertySearch.js b/scripts/apis/creg/workers/propertySearch.js
deleted file mode 100644
index f8009564..00000000
--- a/scripts/apis/creg/workers/propertySearch.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * Handle the Worker event.
- *
- * @param {Object} event the worker event.
- * @param {string} event.data.url the URL to fetch.
- *
- */
-onmessage = (event) => {
-  fetch(event.data.url).then(async (resp) => {
-    if (resp.ok) {
-      postMessage(await resp.json());
-    } else {
-      postMessage({});
-    }
-  });
-};
diff --git a/scripts/delayed.js b/scripts/delayed.js
index 168bdd44..e61213ba 100644
--- a/scripts/delayed.js
+++ b/scripts/delayed.js
@@ -17,4 +17,10 @@ function loadAdobeLaunch() {
   });
 }
 
-if (!window.location.host.includes('localhost')) loadAdobeLaunch();
+if (!window.location.host.includes('localhost')
+  && !window.location.host.includes('.hlx.live')
+  && !window.location.host.includes('.hlx.page')
+  && !window.location.host.includes('.aem.live')
+  && !window.location.host.includes('.aem.page')) {
+  loadAdobeLaunch();
+}
diff --git a/scripts/dom-helpers.js b/scripts/dom-helpers.js
new file mode 100644
index 00000000..1fce908c
--- /dev/null
+++ b/scripts/dom-helpers.js
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2023 Adobe. All rights reserved.
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License. You may obtain a copy
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
+ * OF ANY KIND, either express or implied. See the License for the specific language
+ * governing permissions and limitations under the License.
+ */
+
+/* eslint-disable no-param-reassign */
+
+/**
+ * Example Usage:
+ *
+ * domEl('main',
+ *  div({ class: 'card' },
+ *  a({ href: item.path },
+ *    div({ class: 'card-thumb' },
+ *     createOptimizedPicture(item.image, item.title, 'lazy', [{ width: '800' }]),
+ *    ),
+ *   div({ class: 'card-caption' },
+ *      h3(item.title),
+ *      p({ class: 'card-description' }, item.description),
+ *      p({ class: 'button-container' },
+ *       a({ href: item.path, 'aria-label': 'Read More', class: 'button primary' }, 'Read More'),
+ *     ),
+ *   ),
+ *  ),
+ * )
+ */
+
+/**
+ * Helper for more concisely generating DOM Elements with attributes and children
+ * @param {string} tag HTML tag of the desired element
+ * @param  {[Object?, ...Element]} items: First item can optionally be an object of attributes,
+ *  everything else is a child element
+ * @returns {Element} The constructred DOM Element
+ */
+export function domEl(tag, ...items) {
+  const element = document.createElement(tag);
+
+  if (!items || items.length === 0) return element;
+
+  if (!(items[0] instanceof Element || items[0] instanceof HTMLElement) && typeof items[0] === 'object') {
+    const [attributes, ...rest] = items;
+    items = rest;
+
+    Object.entries(attributes).forEach(([key, value]) => {
+      if (!key.startsWith('on')) {
+        element.setAttribute(key, Array.isArray(value) ? value.join(' ') : value);
+      } else {
+        element.addEventListener(key.substring(2).toLowerCase(), value);
+      }
+    });
+  }
+
+  items.forEach((item) => {
+    item = item instanceof Element || item instanceof HTMLElement
+      ? item
+      : document.createTextNode(item);
+    element.appendChild(item);
+  });
+
+  return element;
+}
+
+/*
+  More short hand functions can be added for very common DOM elements below.
+  domEl function from above can be used for one off DOM element occurrences.
+*/
+export function div(...items) { return domEl('div', ...items); }
+export function p(...items) { return domEl('p', ...items); }
+export function a(...items) { return domEl('a', ...items); }
+export function h1(...items) { return domEl('h1', ...items); }
+export function h2(...items) { return domEl('h2', ...items); }
+export function h3(...items) { return domEl('h3', ...items); }
+export function h4(...items) { return domEl('h4', ...items); }
+export function h5(...items) { return domEl('h5', ...items); }
+export function h6(...items) { return domEl('h6', ...items); }
+export function ul(...items) { return domEl('ul', ...items); }
+export function ol(...items) { return domEl('ol', ...items); }
+export function li(...items) { return domEl('li', ...items); }
+export function i(...items) { return domEl('i', ...items); }
+export function img(...items) { return domEl('img', ...items); }
+export function span(...items) { return domEl('span', ...items); }
+export function form(...items) { return domEl('form', ...items); }
+export function input(...items) { return domEl('input', ...items); }
+export function label(...items) { return domEl('label', ...items); }
+export function button(...items) { return domEl('button', ...items); }
+export function iframe(...items) { return domEl('iframe', ...items); }
+export function nav(...items) { return domEl('nav', ...items); }
+export function fieldset(...items) { return domEl('fieldset', ...items); }
+export function article(...items) { return domEl('article', ...items); }
+export function strong(...items) { return domEl('strong', ...items); }
+export function select(...items) { return domEl('select', ...items); }
+export function option(...items) { return domEl('option', ...items); }
diff --git a/scripts/scripts.js b/scripts/scripts.js
index 2bc96e4f..06b553ce 100644
--- a/scripts/scripts.js
+++ b/scripts/scripts.js
@@ -43,6 +43,7 @@ export function preloadHeroImage(picture) {
   link.setAttribute('type', src.getAttribute('type'));
   document.head.append(link);
 }
+
 /**
  * load fonts.css and set a session storage flag
  */
@@ -54,6 +55,16 @@ async function loadFonts() {
     // do nothing
   }
 }
+
+function buildSearchBar(main) {
+  const metadata = getMetadata('header');
+  if (metadata.match(/search bar/i)) {
+    const section = document.createElement('div');
+    section.append(buildBlock('property-search-bar', { elems: [] }));
+    main.prepend(section);
+  }
+}
+
 /**
  * Builds hero block and prepends to main in a new section.
  * @param {Element} main The container element
@@ -208,18 +219,6 @@ function buildSeparator(main) {
   });
 }
 
-/**
- * Build Property Search Block top nav menu
- * @param main
- */
-function buildPropertySearchBlock(main) {
-  if (getMetadata('template') === 'property-search-template') {
-    const section = document.createElement('div');
-    section.append(buildBlock('property-search-bar', { elems: [] }));
-    main.prepend(section);
-  }
-}
-
 /**
  * Add luxury collection css for page with template
  */
@@ -236,12 +235,12 @@ function buildLuxuryTheme() {
 function buildAutoBlocks(main) {
   try {
     buildHeroBlock(main);
+    buildSearchBar(main);
     buildLiveByMetadata(main);
     buildFloatingImages(main);
     buildSeparator(main);
     buildBlogDetails(main);
     buildBlogNav(main);
-    buildPropertySearchBlock(main);
     buildLuxuryTheme();
   } catch (error) {
     // eslint-disable-next-line no-console
diff --git a/scripts/search.js b/scripts/search.js
deleted file mode 100644
index bf46594e..00000000
--- a/scripts/search.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Build the query string for the search API
- * @returns {string}
- */
-export function getSearchObject() {
-  const search = sessionStorage.getItem('search') ?? '{}';
-  return JSON.parse(search);
-}
-
-function buildQueryParameters() {
-  const search = getSearchObject();
-  return Object.keys(search).map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(search[key])}`).join('&');
-}
-
-/**
- * Build the query string for the search API
- * @returns {string}
- */
-export function buildUrl() {
-  const host = window.location.origin;
-  return `${host}/search?${buildQueryParameters()}`;
-}
-
-/**
- * public methods for search
- * @param key
- * @param value
- */
-export function setParam(key, value) {
-  const parameters = getSearchObject();
-  parameters[key] = value;
-  sessionStorage.setItem('search', JSON.stringify(parameters));
-}
-
-export function getParam(key) {
-  const parameters = getSearchObject();
-  return parameters[key];
-}
-
-export function removeParam(key) {
-  const parameters = getSearchObject();
-  delete parameters[key];
-  sessionStorage.setItem('search', JSON.stringify(parameters));
-}
diff --git a/scripts/search/results.js b/scripts/search/results.js
deleted file mode 100644
index f503fc06..00000000
--- a/scripts/search/results.js
+++ /dev/null
@@ -1,35 +0,0 @@
-const event = new Event('onResultUpdated');
-
-function getResults() {
-  return sessionStorage.getItem('result') ? JSON.parse(sessionStorage.getItem('result')) : {
-    properties: '[]', count: '0', disclaimer: '', listingClusters: '[]', result: '{}',
-  };
-}
-
-export function getPropertyDetails() {
-  return getResults().properties;
-}
-
-export function getPropertiesCount() {
-  return getResults().count;
-}
-
-export function getDisclaimer() {
-  return getResults().disclaimer;
-}
-
-export function getListingClusters() {
-  return getResults().listingClusters;
-}
-
-export function getAllData() {
-  return getResults().result;
-}
-/**
- *
- * @param value
- */
-export function setPropertyDetails(value) {
-  sessionStorage.setItem('result', JSON.stringify(value));
-  window.dispatchEvent(event);
-}
diff --git a/scripts/util.js b/scripts/util.js
index 150548dc..dc7724b7 100644
--- a/scripts/util.js
+++ b/scripts/util.js
@@ -95,6 +95,32 @@ export function getEnvType(hostname = window.location.hostname) {
   return fqdnToEnvType[hostname] || 'dev';
 }
 
+/**
+ * Format a provided value to a shorthand number.
+ * From: https://reacthustle.com/blog/how-to-convert-number-to-kmb-format-in-javascript
+ * @param {String|Number} num the number to format
+ * @param {Number} precision
+ */
+export function formatPrice(num, precision = 1) {
+  if (Number.isNaN(Number.parseFloat(num))) {
+    // eslint-disable-next-line no-param-reassign
+    num = Number.parseFloat(num.replaceAll(/,/g, '').replace('$', ''));
+  }
+  const map = [
+    { suffix: 'T', threshold: 1e12 },
+    { suffix: 'B', threshold: 1e9 },
+    { suffix: 'M', threshold: 1e6 },
+    { suffix: 'k', threshold: 1e3 },
+    { suffix: '', threshold: 1 },
+  ];
+
+  const found = map.find((x) => Math.abs(num) >= x.threshold);
+  if (found) {
+    return (num / found.threshold).toFixed(precision) + found.suffix;
+  }
+  return num;
+}
+
 export function phoneFormat(num) {
   // Remove any non-digit characters from the string
   let phoneNum = num.replace(/\D/g, '');
diff --git a/styles/images/loading.png b/styles/images/loading.png
new file mode 100644
index 0000000000000000000000000000000000000000..6469b7fefc6193fe7172fc2d2e6a1e6c69f22251
GIT binary patch
literal 31292
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
G2K^7oM9ee*

literal 0
HcmV?d00001

diff --git a/styles/styles.css b/styles/styles.css
index 957bd55a..aa09cbc9 100644
--- a/styles/styles.css
+++ b/styles/styles.css
@@ -173,6 +173,7 @@ p, span, input {
   font-weight: var(--font-weight-normal);
   letter-spacing: var(--letter-spacing-reg);
   line-height: var(--line-height-m);
+  color: var(--body-color);
 }
 
 p {
@@ -517,7 +518,6 @@ form button[type="submit"]:hover {
   .section .block.hide-on-mobile {
     display: none;
   }
-
 }
 
 @media screen and (min-width: 600px) {
diff --git a/test/apis/creg/search/Search.test.js b/test/apis/creg/search/Search.test.js
new file mode 100644
index 00000000..f469e45a
--- /dev/null
+++ b/test/apis/creg/search/Search.test.js
@@ -0,0 +1,250 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../scripts/apis/creg/search/Search.js';
+import ListingType from '../../../../scripts/apis/creg/search/types/ListingType.js';
+import OpenHouses from '../../../../scripts/apis/creg/search/types/OpenHouses.js';
+import PropertyType from '../../../../scripts/apis/creg/search/types/PropertyType.js';
+
+describe('Search', () => {
+  it('should have defaults', () => {
+    const search = new Search();
+    assert.equal(search.page, '1', 'Default page parameter.');
+    assert.equal(search.pageSize, '36', 'Default page size parameter.');
+    assert.equal(search.isNew, false, 'Default new listing parameter.');
+    assert.deepStrictEqual(search.listingTypes, [ListingType.FOR_SALE], 'Default listing type parameter.');
+    assert.deepStrictEqual(search.propertyTypes, [PropertyType.CONDO_TOWNHOUSE, PropertyType.SINGLE_FAMILY], 'Default property type parameter.');
+  });
+
+  it('should populate listing types correctly', () => {
+    const search = new Search();
+    search.listingTypes = [{ type: 'PENDING' }, 'FOR_RENT', { type: 'UNKNOWN' }, { type: 'RECENTLY_SOLD' }];
+    assert.deepStrictEqual(search.listingTypes, [ListingType.PENDING, ListingType.FOR_RENT, ListingType.RECENTLY_SOLD], 'Set the listing types correctly.');
+
+    search.listingTypes = [{ type: 'UNKNOWN' }];
+    assert.deepStrictEqual(search.listingTypes, [], 'Does not set unknown type.');
+
+    search.addListingType({ type: 'UNKNOWN' });
+    assert.deepStrictEqual(search.listingTypes, [], 'Does not add unknown type');
+
+    search.addListingType({ type: 'PENDING' });
+    search.addListingType(ListingType.RECENTLY_SOLD);
+    search.addListingType('FOR_SALE');
+    assert.deepStrictEqual(search.listingTypes, [ListingType.PENDING, ListingType.RECENTLY_SOLD, ListingType.FOR_SALE], 'Set the listing types correctly.');
+  });
+
+  it('should populate property types correctly', async () => {
+    const search = new Search();
+    search.propertyTypes = [{ name: 'SINGLE_FAMILY' }, 'COMMERCIAL', { name: 'UNKNOWN' }, { name: 'LAND' }];
+    assert.deepStrictEqual(search.propertyTypes, [PropertyType.SINGLE_FAMILY, PropertyType.COMMERCIAL, PropertyType.LAND], 'Set the property types correctly.');
+
+    search.propertyTypes = [{ name: 'UNKNOWN' }];
+    assert.deepStrictEqual(search.propertyTypes, [], 'Does not set unknown type.');
+
+    search.addPropertyType('UNKNOWN');
+    assert.deepStrictEqual(search.propertyTypes, [], 'Does not add unknown type');
+
+    search.addPropertyType({ id: 6 });
+    search.addPropertyType(PropertyType.COMMERCIAL);
+    search.addPropertyType('LAND');
+    assert.deepStrictEqual(search.propertyTypes, [PropertyType.FARM, PropertyType.COMMERCIAL, PropertyType.LAND], 'Set the property types correctly.');
+  });
+
+  describe('create from block config', () => {
+    it('should create with defaults', async () => {
+      const search = await Search.fromBlockConfig({});
+      assert.deepStrictEqual(search, new Search(), 'Created default instance.');
+    });
+
+    it('support configurations', async () => {
+      const search = await Search.fromBlockConfig({
+        'Min price': '2000',
+        'max price': '2000000',
+        new: true,
+        'Open houses': 'true',
+        'page size': '12',
+        'listing type': 'pending \n\t\n for rent',
+        'pRoPerTy TYPES': '\n\n   farm\n\n   condo',
+        'sort by': 'DATE',
+        'sort direction': 'ascending',
+      });
+
+      assert.equal(search.minPrice, '2000', 'Min price set');
+      assert.equal(search.maxPrice, '2000000', 'Max price set');
+      assert(search.isNew, 'New property flag set.');
+      assert.equal(search.openHouses, OpenHouses.ANYTIME, 'Open houses set.');
+      assert.equal(search.page, '1', 'Page set.');
+      assert.equal(search.pageSize, '12', 'Page size set.');
+      assert.deepStrictEqual(search.listingTypes, [ListingType.FOR_RENT, ListingType.PENDING], 'Listing types set.');
+      assert.deepStrictEqual(search.propertyTypes, [PropertyType.CONDO_TOWNHOUSE, PropertyType.FARM], 'Property types set.');
+      assert.equal(search.sortBy, 'DATE', 'Sort type set.');
+      assert.equal(search.sortDirection, 'ASC', 'Sort direction set.');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new Search();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /page=1/, 'Query string includes page parameter.');
+      assert.match(queryStr, /pageSize=36/, 'Query string includes page size parameter.');
+      assert.match(queryStr, /listingTypes=FOR_SALE/, 'Query string includes listing types parameter.');
+      assert.match(queryStr, /propertyTypes=CONDO_TOWNHOUSE&propertyTypes=SINGLE_FAMILY/, 'Query string includes property type parameter.');
+      assert.match(queryStr, /sortBy=PRICE/, 'Query string includes sort property parameter.');
+      assert.match(queryStr, /sortDirection=DESC/, 'Query string includes sort direction parameter.');
+
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+
+    it('should support all parameters', async () => {
+      const search = new Search();
+      search.input = 'foo';
+      search.minPrice = '10000';
+      search.maxPrice = '1000008';
+      search.minBedrooms = '6';
+      search.minBathrooms = '3';
+      search.minSqft = '500';
+      search.maxSqft = '1000';
+      search.keywords = ['test1', 'test2'];
+      search.matchAnyKeyword = true;
+      search.minYear = '1920';
+      search.maxYear = '2005';
+      search.isNew = true;
+      search.priceChange = true;
+      search.openHouses = 'ONLY_WEEKEND';
+      search.luxury = true;
+      search.bhhsOnly = true;
+      search.page = '2';
+      search.pageSize = '8';
+      search.listingTypes = [ListingType.FOR_SALE, ListingType.RECENTLY_SOLD];
+      search.propertyTypes = [PropertyType.MULTI_FAMILY, PropertyType.LAND];
+      search.sortBy = 'DISTANCE';
+      search.sortDirection = 'ASC';
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /input=foo/, 'Query string includes search input parameter.');
+      assert.match(queryStr, /minPrice=10000/, 'Query string includes min price.');
+      assert.match(queryStr, /maxPrice=1000008/, 'Query string includes max price.');
+      assert.match(queryStr, /minBedrooms=6/, 'Query string includes bedrooms.');
+      assert.match(queryStr, /minBathrooms=3/, 'Query string includes bathrooms.');
+      assert.match(queryStr, /minSqft=500/, 'Query string includes min sqft.');
+      assert.match(queryStr, /maxSqft=1000/, 'Query string includes max sqft.');
+      assert.match(queryStr, /keywords=test1/, 'Query String includes first keyword');
+      assert.match(queryStr, /keywords=test2/, 'Query String includes second keyword');
+      assert.match(queryStr, /matchAnyKeyword=true/, 'Query string includes keyword match rule.');
+      assert.match(queryStr, /minYear=1920/, 'Query string includes min year.');
+      assert.match(queryStr, /maxYear=2005/, 'Query string includes min year.');
+      assert.match(queryStr, /isNew=true/, 'Query string includes new listing flag');
+      assert.match(queryStr, /priceChange=true/, 'Query string includes price change flag');
+      assert.match(queryStr, /openHouses=ONLY_WEEKEND/, 'Query string includes search open house parameter.');
+      assert.match(queryStr, /luxury=true/, 'Query string includes luxury parameter.');
+      assert.match(queryStr, /bhhsOnly=true/, 'Query string includes BHHS parameter.');
+      assert.match(queryStr, /page=2/, 'Query string includes updated page parameter.');
+      assert.match(queryStr, /pageSize=8/, 'Query string includes updated page size parameter.');
+      assert.match(queryStr, /propertyTypes=MULTI_FAMILY&propertyTypes=LAND/, 'Query string includes Property Types');
+      assert.match(queryStr, /listingTypes=FOR_SALE&listingTypes=RECENTLY_SOLD/, 'Query string includes Application Types');
+      assert.match(queryStr, /sortBy=DISTANCE/, 'Query string includes sort type');
+      assert.match(queryStr, /sortDirection=ASC/, 'Query string includes sort direction.');
+
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new Search();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+
+    it('should support all parameters', async () => {
+      const search = new Search();
+      search.input = 'foo';
+      search.minPrice = '10000';
+      search.maxPrice = '1000000';
+      search.minBedrooms = '6';
+      search.minBathrooms = '3';
+      search.minSqft = '500';
+      search.maxSqft = '1000';
+      search.keywords = ['test1', 'test2'];
+      search.matchAnyKeyword = true;
+      search.minYear = '1920';
+      search.maxYear = '2005';
+      search.isNew = true;
+      search.openHouses = 'ONLY_WEEKEND';
+      search.luxury = true;
+      search.bhhsOnly = true;
+      search.page = '2';
+      search.pageSize = '8';
+      search.listingTypes = [ListingType.FOR_SALE, ListingType.RECENTLY_SOLD];
+      search.propertyTypes = [PropertyType.MULTI_FAMILY, PropertyType.LAND];
+      search.sortBy = 'DISTANCE';
+      search.sortDirection = 'ASC';
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have defaults', () => {
+      const search = new Search();
+      const queryStr = search.asCregURLSearchParameters().toString();
+
+      assert.match(queryStr, /Page=1/, 'Query string includes updated page parameter.');
+      assert.match(queryStr, /PageSize=36/, 'Query string includes updated page size parameter.');
+      assert.match(queryStr, /ApplicationType=FOR_SALE/, 'Query string includes Application type parameter.');
+      assert.match(queryStr, /PropertyType=1%2C2/, 'Query string includes property type parameter.');
+      assert.match(queryStr, /Sort=PRICE_DESCENDING/, 'Query string includes sort parameter.');
+    });
+
+    it('should support all parameters', () => {
+      const search = new Search();
+      search.input = 'foo';
+      search.minPrice = '10000';
+      search.maxPrice = '1000000';
+      search.minBedrooms = '6';
+      search.minBathrooms = '3';
+      search.minSqft = '500';
+      search.maxSqft = '1000';
+      search.keywords = ['test1', 'test2'];
+      search.matchAnyKeyword = true;
+      search.minYear = '1920';
+      search.maxYear = '2005';
+      search.isNew = true;
+      search.priceChange = true;
+      search.openHouses = 'ONLY_WEEKEND';
+      search.luxury = true;
+      search.bhhsOnly = true;
+      search.page = '2';
+      search.pageSize = '8';
+      search.listingTypes = [ListingType.FOR_SALE, ListingType.RECENTLY_SOLD];
+      search.propertyTypes = [PropertyType.MULTI_FAMILY, PropertyType.LAND];
+      search.sortBy = 'DISTANCE';
+      search.sortDirection = 'ASC';
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchInput=foo/, 'Query string includes search input parameter.');
+      assert.match(queryStr, /MinPrice=10000/, 'Query string includes min price.');
+      assert.match(queryStr, /MaxPrice=1000000/, 'Query string includes max price.');
+      assert.match(queryStr, /MinBedroomsTotal=6/, 'Query string includes min bedrooms.');
+      assert.match(queryStr, /MinBathroomsTotal=3/, 'Query string includes min bathrooms.');
+      assert.match(queryStr, /MinLivingArea=500/, 'Query string includes min sqft');
+      assert.match(queryStr, /MaxLivingArea=1000/, 'Query string includes max sqft');
+      assert.match(queryStr, /Features=test1%2Ctest2/, 'Query string includes feature keywords.');
+      assert.match(queryStr, /MatchAnyFeatures=true/, 'Query string include keyword match any');
+      assert.match(queryStr, /YearBuilt=1920-2005/, 'Query string includes year built.');
+      assert.match(queryStr, /NewListing=true/, 'Query string includes new listing flag');
+      assert.match(queryStr, /RecentPriceChange=true/, 'Query string includes price change flag');
+      assert.match(queryStr, /OpenHouses=7/, 'Query string includes search open house parameter.');
+      assert.match(queryStr, /Luxury=true/, 'Query string includes luxury parameter.');
+      assert.match(queryStr, /FeaturedCompany=BHHS/, 'Query string includes BHHS parameter.');
+      assert.match(queryStr, /Page=2/, 'Query string includes updated page parameter.');
+      assert.match(queryStr, /PageSize=8/, 'Query string includes updated page size parameter.');
+      assert.match(queryStr, /PropertyType=4%2C5/, 'Query string includes Property Types');
+      assert.match(queryStr, /ApplicationType=FOR_SALE%2CRECENTLY_SOLD/, 'Query string includes Application Types');
+      assert.match(queryStr, /Sort=DISTANCE_ASCENDING/, 'Query string includes sort type');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/AddressSearch.test.js b/test/apis/creg/search/types/AddressSearch.test.js
new file mode 100644
index 00000000..6b28f933
--- /dev/null
+++ b/test/apis/creg/search/types/AddressSearch.test.js
@@ -0,0 +1,78 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import AddressSearch from '../../../../../scripts/apis/creg/search/types/AddressSearch.js';
+
+describe('AddressSearch', () => {
+  describe('create from block config', () => {
+    it('should have defaults', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'Address',
+      });
+      assert(search instanceof AddressSearch, 'Created correct type.');
+    });
+    it('should populate Address specific values', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'address',
+        address: '123 Elm Street, Nowhere, NO 12345',
+      });
+      assert(search instanceof AddressSearch, 'Created correct type.');
+      assert.equal(search.address, '123 Elm Street, Nowhere, NO 12345', 'Address set');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new AddressSearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=Address/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+    it('should read address specific parameters', async () => {
+      const search = new AddressSearch();
+      search.address = '123 Elm Street, Nowhere, NO 12345';
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=Address/, 'Query string includes search type parameter.');
+      assert.match(queryStr, /address=123\+Elm\+Street%2C\+Nowhere%2C\+NO\+12345/, 'Query string includes address.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new AddressSearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+    it('should read address specific parameters', async () => {
+      const search = new AddressSearch();
+      search.address = '123 Elm Street, Nowhere, NO 12345';
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('from suggestion results', () => {
+    it('should create address search', async () => {
+      const search = new AddressSearch();
+      search.populateFromSuggestion(new URLSearchParams('SearchType\u003dAddress\u0026SearchParameter\u003d123%20Elm%20Street%2C%20Nowhere%2C%20NO%2012345'));
+      assert(search instanceof AddressSearch, 'Created correct type.');
+      assert.equal(search.address, '123 Elm Street, Nowhere, NO 12345', 'Address was correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have address search parameters', () => {
+      const search = new AddressSearch();
+      search.address = '123 Elm Street, Nowhere, NO 12345';
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=Address/, 'Query string includes search type.');
+      assert.match(queryStr, /SearchParameter=123\+Elm\+Street%2C\+Nowhere%2C\+NO\+12345/, 'Query string includes Search parameter structure.');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/BoxSearch.test.js b/test/apis/creg/search/types/BoxSearch.test.js
new file mode 100644
index 00000000..4ba8bc4d
--- /dev/null
+++ b/test/apis/creg/search/types/BoxSearch.test.js
@@ -0,0 +1,97 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import BoxSearch from '../../../../../scripts/apis/creg/search/types/BoxSearch.js';
+
+describe('BoxSearch', () => {
+  describe('create from block config', () => {
+    it('should have defaults', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'Box',
+      });
+      assert(search instanceof BoxSearch, 'Created correct type.');
+    });
+
+    it('should populate Box specific values', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'box',
+        'min lat': '75.987654321',
+        'maximum latitude': '76.987654321',
+        'minimum long': '-100.123456789',
+        'max longitude': '-101.123456789',
+      });
+      assert(search instanceof BoxSearch, 'Created correct type.');
+      assert.equal(search.minLat, '75.9876543', 'Minimum Latitude set.');
+      assert.equal(search.maxLat, '76.9876543', 'Maximum Latitude set.');
+      assert.equal(search.minLon, '-100.1234568', 'Minimum Longitude set.');
+      assert.equal(search.maxLon, '-101.1234568', 'Maximum Longitude set.');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new BoxSearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=Box/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+
+    it('should read box specific parameters', async () => {
+      const search = new BoxSearch();
+      search.minLat = 75.987654321;
+      search.maxLat = 76.987654321;
+      search.minLon = -100.123456789;
+      search.maxLon = -101.123456789;
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=Box/, 'Query string includes search type parameter.');
+
+      assert.match(queryStr, /minLat=75.9876543/, 'Query string includes min lat.');
+      assert.match(queryStr, /maxLat=76.9876543/, 'Query string includes max lat.');
+      assert.match(queryStr, /minLon=-100.1234568/, 'Query string includes min lon.');
+      assert.match(queryStr, /maxLon=-101.1234568/, 'Query string includes max lon.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new BoxSearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+
+    it('should read box specific parameters', async () => {
+      const search = new BoxSearch();
+      search.minLat = 75.987654321;
+      search.maxLat = 76.987654321;
+      search.minLon = -100.123456789;
+      search.maxLon = -101.123456789;
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have Box search parameters', () => {
+      const search = new BoxSearch();
+      search.minLat = 75.987654321;
+      search.maxLat = 76.987654321;
+      search.minLon = -100.123456789;
+      search.maxLon = -101.123456789;
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=Map/, 'Query string includes search type.');
+      assert.match(queryStr, /SearchParameter=%7B%22type%22%3A%22FeatureCollection%22%2C%22features%22%3A%5B%7B%22type%22%3A%22Feature%22%2C%/, 'Query string includes Base structure.');
+      assert.match(queryStr, /22geometry%22%3A%7B%22type%22%3A%22Polygon%22%2C%22coordinates%22%3A%5B%5B%5B%22/, 'Query string includes geometry beginning.');
+      assert.match(queryStr, /%22%3A%5B%5B%5B%22-100.1234568%22%2C%2275.9876543/, 'Query string includes first minLon/minLat point.');
+      assert.match(queryStr, /-100.1234568%22%2C%2276.9876543/, 'Query string includes minLon/maxLat point.');
+      assert.match(queryStr, /-101.1234568%22%2C%2276.9876543/, 'Query string includes maxLon/maxLat point.');
+      assert.match(queryStr, /-101.1234568%22%2C%2275.9876543/, 'Query string includes maxLon/minLat point.');
+      assert.match(queryStr, /-100.1234568%22%2C%2275.9876543%22%5D%5D%5D%7D%7D%5D%7D/, 'Query string includes close-the-box minLon/minLat point.');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/CitySearch.test.js b/test/apis/creg/search/types/CitySearch.test.js
new file mode 100644
index 00000000..fa41819c
--- /dev/null
+++ b/test/apis/creg/search/types/CitySearch.test.js
@@ -0,0 +1,78 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import CitySearch from '../../../../../scripts/apis/creg/search/types/CitySearch.js';
+
+describe('CitySearch', () => {
+  describe('create from block config', () => {
+    it('should have defaults', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'City',
+      });
+      assert(search instanceof CitySearch, 'Created correct type.');
+    });
+    it('should populate City specific values', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'city',
+        city: 'Nowhere, NO',
+      });
+      assert(search instanceof CitySearch, 'Created correct type.');
+      assert.equal(search.city, 'Nowhere, NO', 'City set');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new CitySearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=City/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+    it('should read city specific parameters', async () => {
+      const search = new CitySearch();
+      search.city = 'Nowhere, NO';
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=City/, 'Query string includes search type parameter.');
+      assert.match(queryStr, /city=Nowhere%2C\+NO/, 'Query string includes city.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new CitySearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+    it('should read city specific parameters', async () => {
+      const search = new CitySearch();
+      search.city = 'Nowhere, NO';
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('from suggestion results', () => {
+    it('should create city search', async () => {
+      const search = new CitySearch();
+      search.populateFromSuggestion(new URLSearchParams('SearchType\u003dCity\u0026SearchParameter\u003dNowhere%2C%20NO'));
+      assert(search instanceof CitySearch, 'Created correct type.');
+      assert.equal(search.city, 'Nowhere, NO', 'City was correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have city search parameters', () => {
+      const search = new CitySearch();
+      search.city = 'Nowhere, NO';
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=City/, 'Query string includes search type.');
+      assert.match(queryStr, /SearchParameter=Nowhere%2C\+NO/, 'Query string includes Search parameter structure.');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/ElementarySchoolSearch.test.js b/test/apis/creg/search/types/ElementarySchoolSearch.test.js
new file mode 100644
index 00000000..5745c21a
--- /dev/null
+++ b/test/apis/creg/search/types/ElementarySchoolSearch.test.js
@@ -0,0 +1,78 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import ElementarySchoolSearch from '../../../../../scripts/apis/creg/search/types/ElementarySchoolSearch.js';
+
+describe('ElementarySchoolSearch', () => {
+  describe('create from block config', () => {
+    it('should have defaults', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'Elementary School',
+      });
+      assert(search instanceof ElementarySchoolSearch, 'Created correct type.');
+    });
+    it('should populate ElementarySchool specific values', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'elementary school',
+        'elementary school': 'Elementary School on elm street',
+      });
+      assert(search instanceof ElementarySchoolSearch, 'Created correct type.');
+      assert.equal(search.school, 'Elementary School on elm street', 'ElementarySchool set');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new ElementarySchoolSearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=ElementarySchool/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+    it('should read School specific parameters', async () => {
+      const search = new ElementarySchoolSearch();
+      search.school = 'Elementary School on elm street';
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=ElementarySchool/, 'Query string includes search type parameter.');
+      assert.match(queryStr, /school=Elementary\+School\+on\+elm\+street/, 'Query string includes elementary school.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new ElementarySchoolSearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+    it('should read school specific parameters', async () => {
+      const search = new ElementarySchoolSearch();
+      search.school = 'Elementary School on elm street';
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('from suggestion results', () => {
+    it('should create elementary school search', async () => {
+      const search = new ElementarySchoolSearch();
+      search.populateFromSuggestion(new URLSearchParams('SearchType\u003dElementary%20School\u0026SearchParameter\u003dElementary%20School%20on%20elm%20street'));
+      assert(search instanceof ElementarySchoolSearch, 'Created correct type.');
+      assert.equal(search.school, 'Elementary School on elm street', 'School was correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have school search parameters', () => {
+      const search = new ElementarySchoolSearch();
+      search.school = 'Elementary School on elm street';
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=ElementarySchool/, 'Query string includes search type.');
+      assert.match(queryStr, /SearchParameter=Elementary\+School\+on\+elm\+street/, 'Query string includes Search parameter structure.');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/HighSchoolSearch.test.js b/test/apis/creg/search/types/HighSchoolSearch.test.js
new file mode 100644
index 00000000..7007e34a
--- /dev/null
+++ b/test/apis/creg/search/types/HighSchoolSearch.test.js
@@ -0,0 +1,78 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import HighSchoolSearch from '../../../../../scripts/apis/creg/search/types/HighSchoolSearch.js';
+
+describe('HighSchoolSearch', () => {
+  describe('create from block config', () => {
+    it('should have defaults', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'High School',
+      });
+      assert(search instanceof HighSchoolSearch, 'Created correct type.');
+    });
+    it('should populate HighSchool specific values', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'High School',
+        'high school': 'High School on elm street',
+      });
+      assert(search instanceof HighSchoolSearch, 'Created correct type.');
+      assert.equal(search.school, 'High School on elm street', 'HighSchool set');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new HighSchoolSearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=HighSchool/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+    it('should read school specific parameters', async () => {
+      const search = new HighSchoolSearch();
+      search.school = 'High School on elm street';
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=HighSchool/, 'Query string includes search type parameter.');
+      assert.match(queryStr, /school=High\+School\+on\+elm\+street/, 'Query string includes school.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new HighSchoolSearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+    it('should read school specific parameters', async () => {
+      const search = new HighSchoolSearch();
+      search.school = 'High School on elm street';
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('from suggestion results', () => {
+    it('should create high school search', async () => {
+      const search = new HighSchoolSearch();
+      search.populateFromSuggestion(new URLSearchParams('SearchType\u003dHigh%20School\u0026SearchParameter\u003dHigh%20School%20on%20elm%20street'));
+      assert(search instanceof HighSchoolSearch, 'Created correct type.');
+      assert.equal(search.school, 'High School on elm street', 'School was correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have school search parameters', () => {
+      const search = new HighSchoolSearch();
+      search.school = 'High School on elm street';
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=HighSchool/, 'Query string includes search type.');
+      assert.match(queryStr, /SearchParameter=High\+School\+on\+elm\+street/, 'Query string includes Search parameter structure.');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/MLSListingKeySearch.test.js b/test/apis/creg/search/types/MLSListingKeySearch.test.js
new file mode 100644
index 00000000..4283a4bd
--- /dev/null
+++ b/test/apis/creg/search/types/MLSListingKeySearch.test.js
@@ -0,0 +1,87 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import MLSListingKeySearch from '../../../../../scripts/apis/creg/search/types/MLSListingKeySearch.js';
+
+describe('MLSListingKeySearch', () => {
+  describe('create from block config', () => {
+    it('should have defaults', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'MLS Listing Key',
+      });
+      assert(search instanceof MLSListingKeySearch, 'Created correct type.');
+    });
+    it('should populate MLS Listing Key specific values', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'MLS listing key',
+        'MLS Listing Key': '12345678',
+        context: 'Boston, MA',
+      });
+      assert(search instanceof MLSListingKeySearch, 'Created correct type.');
+      assert.equal(search.listingId, '12345678', 'MLS Listing Key set');
+      assert.equal(search.context, 'Boston, MA');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new MLSListingKeySearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=MLSListingKey/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+    it('should read address specific parameters', async () => {
+      const search = new MLSListingKeySearch();
+      search.listingId = '12345678';
+      search.context = 'Boston, MA';
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=MLSListingKey/, 'Query string includes search type parameter.');
+      assert.match(queryStr, /listingId=12345678/, 'Query string includes listing id.');
+      assert.match(queryStr, /context=Boston%2C\+MA/, 'Query string includes context.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new MLSListingKeySearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+    it('should read address specific parameters', async () => {
+      const search = new MLSListingKeySearch();
+      search.listingId = '12345678';
+      search.context = 'Boston, MA';
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('from suggestion results', () => {
+    it('should create MLS search', async () => {
+      const search = new MLSListingKeySearch();
+      search.populateFromSuggestion(new URLSearchParams('ListingId=12345678\u0026SearchType\u003dMLSListingKey\u0026SearchParameter\u003dBoston%2C%20MA'));
+
+      assert(search instanceof MLSListingKeySearch, 'Created correct type.');
+      assert.equal(search.listingId, '12345678', 'Listing id was correct.');
+      assert.equal(search.context, 'Boston, MA', 'Context was correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have address search parameters', () => {
+      const search = new MLSListingKeySearch();
+      search.listingId = '12345678';
+      search.context = 'Boston, MA';
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=MLSListingKey/, 'Query string includes search type.');
+      assert.match(queryStr, /ListingId=12345678/, 'Query string includes listing id');
+      assert.match(queryStr, /SearchParameter=Boston%2C\+MA/, 'Query string includes Search parameter structure.');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/MiddleSchoolSearch.test.js b/test/apis/creg/search/types/MiddleSchoolSearch.test.js
new file mode 100644
index 00000000..9398b075
--- /dev/null
+++ b/test/apis/creg/search/types/MiddleSchoolSearch.test.js
@@ -0,0 +1,78 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import MiddleSchoolSearch from '../../../../../scripts/apis/creg/search/types/MiddleSchoolSearch.js';
+
+describe('MiddleSchoolSearch', () => {
+  describe('create from block config', () => {
+    it('should have defaults', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'Middle School',
+      });
+      assert(search instanceof MiddleSchoolSearch, 'Created correct type.');
+    });
+    it('should populate MiddleSchool specific values', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'middle School',
+        'middle school': 'Middle School on elm street',
+      });
+      assert(search instanceof MiddleSchoolSearch, 'Created correct type.');
+      assert.equal(search.school, 'Middle School on elm street', 'MiddleSchool set');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new MiddleSchoolSearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=MiddleSchool/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+    it('should read school specific parameters', async () => {
+      const search = new MiddleSchoolSearch();
+      search.school = 'Middle School on elm street';
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=MiddleSchool/, 'Query string includes search type parameter.');
+      assert.match(queryStr, /school=Middle\+School\+on\+elm\+street/, 'Query string includes school.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new MiddleSchoolSearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+    it('should read school specific parameters', async () => {
+      const search = new MiddleSchoolSearch();
+      search.school = 'Middle School on elm street';
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('from suggestion results', () => {
+    it('should create middle school search', async () => {
+      const search = new MiddleSchoolSearch();
+      search.populateFromSuggestion(new URLSearchParams('SearchType\u003dMiddle%20School\u0026SearchParameter\u003dMiddle%20School%20on%20elm%20street'));
+      assert(search instanceof MiddleSchoolSearch, 'Created correct type.');
+      assert.equal(search.school, 'Middle School on elm street', 'School was correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have school search parameters', () => {
+      const search = new MiddleSchoolSearch();
+      search.school = 'Middle School on elm street';
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=MiddleSchool/, 'Query string includes search type.');
+      assert.match(queryStr, /SearchParameter=Middle\+School\+on\+elm\+street/, 'Query string includes Search parameter structure.');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/NeighborhoodSearch.test.js b/test/apis/creg/search/types/NeighborhoodSearch.test.js
new file mode 100644
index 00000000..e22592d3
--- /dev/null
+++ b/test/apis/creg/search/types/NeighborhoodSearch.test.js
@@ -0,0 +1,78 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import NeighborhoodSearch from '../../../../../scripts/apis/creg/search/types/NeighborhoodSearch.js';
+
+describe('NeighborhoodSearch', () => {
+  describe('create from block config', () => {
+    it('should have defaults', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'Neighborhood',
+      });
+      assert(search instanceof NeighborhoodSearch, 'Created correct type.');
+    });
+    it('should populate Neighborhood specific values', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'neighborhood',
+        neighborhood: '123 Elm Street, Nowhere, NO 12345',
+      });
+      assert(search instanceof NeighborhoodSearch, 'Created correct type.');
+      assert.equal(search.neighborhood, '123 Elm Street, Nowhere, NO 12345', 'Neighborhood set');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new NeighborhoodSearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=Neighborhood/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+    it('should read neighborhood specific parameters', async () => {
+      const search = new NeighborhoodSearch();
+      search.neighborhood = '123 Elm Street, Nowhere, NO 12345';
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=Neighborhood/, 'Query string includes search type parameter.');
+      assert.match(queryStr, /neighborhood=123\+Elm\+Street%2C\+Nowhere%2C\+NO\+12345/, 'Query string includes neighborhood.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new NeighborhoodSearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+    it('should read neighborhood specific parameters', async () => {
+      const search = new NeighborhoodSearch();
+      search.neighborhood = '123 Elm Street, Nowhere, NO 12345';
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('from suggestion results', () => {
+    it('should create Neighborhood search', async () => {
+      const search = new NeighborhoodSearch();
+      search.populateFromSuggestion(new URLSearchParams('SearchType\u003dNeighborhood\u0026SearchParameter\u003d123%20Elm%20Street%2C%20Nowhere%2C%20NO%2012345'));
+      assert(search instanceof NeighborhoodSearch, 'Created correct type.');
+      assert.equal(search.neighborhood, '123 Elm Street, Nowhere, NO 12345', 'Neighborhood was correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have neighborhood search parameters', () => {
+      const search = new NeighborhoodSearch();
+      search.neighborhood = '123 Elm Street, Nowhere, NO 12345';
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=Neighborhood/, 'Query string includes search type.');
+      assert.match(queryStr, /SearchParameter=123\+Elm\+Street%2C\+Nowhere%2C\+NO\+12345/, 'Query string includes Search parameter structure.');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/PolygonSearch.test.js b/test/apis/creg/search/types/PolygonSearch.test.js
new file mode 100644
index 00000000..d0bcf31e
--- /dev/null
+++ b/test/apis/creg/search/types/PolygonSearch.test.js
@@ -0,0 +1,119 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import PolygonSearch from '../../../../../scripts/apis/creg/search/types/PolygonSearch.js';
+
+describe('PolygonSearch', () => {
+  it('cannot be created create from block config', async () => {
+    await assert.rejects(Search.fromBlockConfig({
+      'search type': 'Polygon',
+    }), Error, 'Does not create instance.');
+  });
+
+  it('can add a point', () => {
+    const search = new PolygonSearch();
+    search.addPoint('Not An object.');
+    assert.deepStrictEqual(search.points, [], 'Ignored invalid object.');
+    search.addPoint({});
+    assert.deepStrictEqual(search.points, [], 'Ignored invalid object.');
+    search.addPoint([]);
+    assert.deepStrictEqual(search.points, [], 'Ignored invalid object.');
+    search.addPoint({ lat: '123' });
+    assert.deepStrictEqual(search.points, [], 'Ignored invalid object.');
+    search.addPoint({ lon: '123' });
+    assert.deepStrictEqual(search.points, [], 'Ignored invalid object.');
+
+    search.addPoint({ lat: '123', lon: '123' });
+    assert.deepStrictEqual(search.points, [{ lat: '123', lon: '123' }], 'Ignored invalid object.');
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new PolygonSearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=Polygon/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+
+    it('should read Polygon specific parameters', async () => {
+      const search = new PolygonSearch();
+      search.addPoint({ lat: '42.14299778443187', lon: '-70.99324744939803' });
+      search.addPoint({ lat: '42.038540372268336', lon: '-71.10242408514021' });
+      search.addPoint({ lat: '41.941061865983954', lon: '-70.96578162908553' });
+      search.addPoint({ lat: '41.928291852269396', lon: '-70.72339576482771' });
+      search.addPoint({ lat: '42.01150632664794', lon: '-70.67807716131209' });
+      search.addPoint({ lat: '42.10785815410172', lon: '-70.74536842107771' });
+      search.addPoint({ lat: '42.16946694504556', lon: '-70.71515601873396' });
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=Polygon/, 'Query string includes search type parameter.');
+
+      assert.match(queryStr, /point=42.14299778443187%2C-70.99324744939803/, 'Query string includes first point');
+      assert.match(queryStr, /point=42.038540372268336%2C-71.10242408514021/, 'Query string includes second point');
+      assert.match(queryStr, /point=41.941061865983954%2C-70.96578162908553/, 'Query string includes third point');
+      assert.match(queryStr, /point=41.928291852269396%2C-70.72339576482771/, 'Query string includes fourth point');
+      assert.match(queryStr, /point=42.01150632664794%2C-70.67807716131209/, 'Query string includes fifth point');
+      assert.match(queryStr, /point=42.10785815410172%2C-70.74536842107771/, 'Query string includes sixth point');
+      assert.match(queryStr, /point=42.16946694504556%2C-70.71515601873396/, 'Query string includes seventh point');
+
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new PolygonSearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+
+    it('should read polygon specific parameters', async () => {
+      const points = [
+        { lat: '42.14299778443187', lon: '-70.99324744939803' },
+        { lat: '42.038540372268336', lon: '-71.10242408514021' },
+        { lat: '41.941061865983954', lon: '-70.96578162908553' },
+        { lat: '41.928291852269396', lon: '-70.72339576482771' },
+        { lat: '42.01150632664794', lon: '-70.67807716131209' },
+        { lat: '42.10785815410172', lon: '-70.74536842107771' },
+        { lat: '42.16946694504556', lon: '-70.71515601873396' },
+      ];
+
+      const search = new PolygonSearch();
+      search.points = points;
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have Polygon search parameters', () => {
+      const points = [
+        { lat: '42.14299778443187', lon: '-70.99324744939803' },
+        { lat: '42.038540372268336', lon: '-71.10242408514021' },
+        { lat: '41.941061865983954', lon: '-70.96578162908553' },
+        { lat: '41.928291852269396', lon: '-70.72339576482771' },
+        { lat: '42.01150632664794', lon: '-70.67807716131209' },
+        { lat: '42.10785815410172', lon: '-70.74536842107771' },
+        { lat: '42.16946694504556', lon: '-70.71515601873396' },
+      ];
+      const search = new PolygonSearch();
+      search.points = points;
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=Map/, 'Query string includes search type.');
+      assert.match(queryStr, /SearchParameter=%7B%22type%22%3A%22FeatureCollection%22%2C%22features%22%3A%5B%7B%22type%22%3A%22Feature%22%2C%/, 'Query string includes Base structure.');
+      assert.match(queryStr, /22geometry%22%3A%7B%22type%22%3A%22Polygon%22%2C%22coordinates%22%3A%5B%5B%5B%22/, 'Query string includes geometry beginning.');
+      assert.match(queryStr, /%22%3A%5B%5B%5B%22-70.99324744939803%22%2C%2242.14299778443187/, 'Query string includes first point.');
+      assert.match(queryStr, /-71.10242408514021%22%2C%2242.038540372268336/, 'Query string includes second point.');
+      assert.match(queryStr, /-70.96578162908553%22%2C%2241.941061865983954/, 'Query string includes third point.');
+      assert.match(queryStr, /-70.72339576482771%22%2C%2241.928291852269396/, 'Query string includes fourth point.');
+      assert.match(queryStr, /-70.67807716131209%22%2C%2242.01150632664794/, 'Query string includes fifth point.');
+      assert.match(queryStr, /-70.74536842107771%22%2C%2242.10785815410172/, 'Query string includes sixth point.');
+      assert.match(queryStr, /-70.71515601873396%22%2C%2242.16946694504556/, 'Query string includes seventh point.');
+      assert.match(queryStr, /-70.99324744939803%22%2C%2242.14299778443187%22%5D%5D%5D%7D%7D%5D%7D/, 'Query string includes closing point.');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/PostalCodeSearch.test.js b/test/apis/creg/search/types/PostalCodeSearch.test.js
new file mode 100644
index 00000000..8b6e4d32
--- /dev/null
+++ b/test/apis/creg/search/types/PostalCodeSearch.test.js
@@ -0,0 +1,78 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import PostalCodeSearch from '../../../../../scripts/apis/creg/search/types/PostalCodeSearch.js';
+
+describe('PostalCodeSearch', () => {
+  describe('create from block config', () => {
+    it('should have defaults', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'postal code',
+      });
+      assert(search instanceof PostalCodeSearch, 'Created correct type from postal code.');
+    });
+    it('should populate PostalCode specific values', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'postal Code',
+        'postAl coDe': '12345',
+      });
+      assert(search instanceof PostalCodeSearch, 'Created correct type.');
+      assert.equal(search.code, '12345', 'PostalCode set');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new PostalCodeSearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=PostalCode/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+    it('should read postal code specific parameters', async () => {
+      const search = new PostalCodeSearch();
+      search.code = '12345';
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=PostalCode/, 'Query string includes search type parameter.');
+      assert.match(queryStr, /code=12345/, 'Query string includes postal code.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new PostalCodeSearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+    it('should read postal code specific parameters', async () => {
+      const search = new PostalCodeSearch();
+      search.code = '12345';
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('from suggestion results', () => {
+    it('should create Postal Code search', async () => {
+      const search = new PostalCodeSearch();
+      search.populateFromSuggestion(new URLSearchParams('SearchType\u003dPostalCode\u0026CoverageZipcode\u003d12345'));
+      assert(search instanceof PostalCodeSearch, 'Created correct type.');
+      assert.equal(search.code, '12345', 'Postal Code was correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have postal code search parameters', () => {
+      const search = new PostalCodeSearch();
+      search.code = '12345';
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=PostalCode/, 'Query string includes search type.');
+      assert.match(queryStr, /CoverageZipcode=12345/, 'Query string includes Search parameter structure.');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/RadiusSearch.test.js b/test/apis/creg/search/types/RadiusSearch.test.js
new file mode 100644
index 00000000..b3f8534d
--- /dev/null
+++ b/test/apis/creg/search/types/RadiusSearch.test.js
@@ -0,0 +1,86 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import RadiusSearch from '../../../../../scripts/apis/creg/search/types/RadiusSearch.js';
+import BoxSearch from '../../../../../scripts/apis/creg/search/types/BoxSearch.js';
+
+describe('RadiusSearch', () => {
+  describe('create from block config', () => {
+    it('should have defaults', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'Radius',
+      });
+      assert(search instanceof RadiusSearch, 'Created correct type.');
+    });
+
+    it('should populate Radius specific values', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'radius',
+        lat: 75.987654321,
+        longitude: -101.123456789,
+        dist: 5,
+      });
+      assert(search instanceof RadiusSearch, 'Created correct type.');
+      assert.equal(search.lat, '75.9876543', 'Longitude set.');
+      assert.equal(search.lon, '-101.1234568', 'Latitude set.');
+      assert.equal(search.distance, '5', 'Distance set.');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new RadiusSearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=Radius/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+
+    it('should read radius specific parameters', async () => {
+      const search = new RadiusSearch();
+      search.lat = 75.987654321;
+      search.lon = -101.123456789;
+      search.distance = 10;
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=Radius/, 'Query string includes search type parameter.');
+      assert.match(queryStr, /lat=75.9876543/, 'Query string includes lat.');
+      assert.match(queryStr, /lon=-101.1234568/, 'Query string includes lon.');
+      assert.match(queryStr, /distance=10/, 'Query string includes distance');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new BoxSearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+
+    it('should read radius specific parameters', async () => {
+      const search = new RadiusSearch();
+      search.lat = 75.987654321;
+      search.lon = -101.123456789;
+      search.distance = 10;
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have Radius search parameters', () => {
+      const search = new RadiusSearch();
+      search.lat = 75.987654321;
+      search.lon = -101.123456789;
+      search.distance = 10;
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=Radius/, 'Query string includes search type.');
+      assert.match(queryStr, /Latitude=75.9876543/, 'Query string includes lat.');
+      assert.match(queryStr, /Longitude=-101.1234568/, 'Query string includes lon.');
+      assert.match(queryStr, /Distance=10/, 'Query string includes distance');
+    });
+  });
+});
diff --git a/test/apis/creg/search/types/SchoolDistrictSearch.test.js b/test/apis/creg/search/types/SchoolDistrictSearch.test.js
new file mode 100644
index 00000000..a6139095
--- /dev/null
+++ b/test/apis/creg/search/types/SchoolDistrictSearch.test.js
@@ -0,0 +1,78 @@
+import { describe, it } from 'node:test';
+import { strict as assert } from 'node:assert';
+import Search from '../../../../../scripts/apis/creg/search/Search.js';
+import SchoolDistrictSearch from '../../../../../scripts/apis/creg/search/types/SchoolDistrictSearch.js';
+
+describe('SchoolDistrictSearch', () => {
+  describe('create from block config', () => {
+    it('should have defaults', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'School District',
+      });
+      assert(search instanceof SchoolDistrictSearch, 'Created correct type.');
+    });
+    it('should populate SchoolDistrict specific values', async () => {
+      const search = await Search.fromBlockConfig({
+        'search type': 'school district',
+        'school district': 'School District in Nowhere, NO',
+      });
+      assert(search instanceof SchoolDistrictSearch, 'Created correct type.');
+      assert.equal(search.district, 'School District in Nowhere, NO', 'School District set');
+    });
+  });
+
+  describe('to/from URL Search Parameters', () => {
+    it('should have defaults', async () => {
+      const search = new SchoolDistrictSearch();
+      const queryStr = search.asURLSearchParameters().toString();
+
+      assert.match(queryStr, /type=SchoolDistrict/, 'Query string includes search type parameter.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+    it('should read school district specific parameters', async () => {
+      const search = new SchoolDistrictSearch();
+      search.district = 'School District in Nowhere, NO';
+
+      const queryStr = search.asURLSearchParameters().toString();
+      assert.match(queryStr, /type=SchoolDistrict/, 'Query string includes search type parameter.');
+      assert.match(queryStr, /district=School\+District\+in\+Nowhere%2C\+NO/, 'Query string includes school district.');
+      const created = await Search.fromQueryString(queryStr);
+      assert.deepStrictEqual(created, search, 'Object was parsed from query string correctly.');
+    });
+  });
+
+  describe('to/from JSON', () => {
+    it('should have defaults', async () => {
+      const search = new SchoolDistrictSearch();
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+    it('should read school district specific parameters', async () => {
+      const search = new SchoolDistrictSearch();
+      search.district = 'School District in Nowhere, NO';
+      const created = await Search.fromJSON(JSON.parse(JSON.stringify(search)));
+      assert.deepStrictEqual(created, search, 'To/From JSON correct.');
+    });
+  });
+
+  describe('from suggestion results', () => {
+    it('should create school district search', async () => {
+      const search = new SchoolDistrictSearch();
+      search.populateFromSuggestion(new URLSearchParams('SearchType\u003dSchoolDistrict\u0026SearchParameter\u003dSchool%20District%20in%20Nowhere%2C%20NO'));
+      assert(search instanceof SchoolDistrictSearch, 'Created correct type.');
+      assert.equal(search.district, 'School District in Nowhere, NO', 'School district was correct.');
+    });
+  });
+
+  describe('to CREG URL Search Parameters', () => {
+    it('should have school district search parameters', () => {
+      const search = new SchoolDistrictSearch();
+      search.district = 'School District in Nowhere, NO';
+
+      const queryStr = search.asCregURLSearchParameters().toString();
+      assert.match(queryStr, /SearchType=SchoolDistrict/, 'Query string includes search type.');
+      assert.match(queryStr, /SearchParameter=School\+District\+in\+Nowhere%2C\+NO/, 'Query string includes Search parameter structure.');
+    });
+  });
+});