Chore: Miscellaneous UI review changes

- Added bg (variable) to pages, card space separation visible
- Removed `show brand line` in settings, shown by default
- Re-arranged settings by importance
- View toggling primary colour is grey
- Only populate recent searches on successful search
- Hit only one server side api, once while searching
- List view primary button float right
- Discounts takes upper limit eg. 10% and below
- Navbar icons only wiggle on qty increase in cart/wishlist
- Pay button in SO portal
- Remove bottom white space below item full page image, min-height fits to content
- List view vertical space between heading and item code
- Empty offer subtitle handled
diff --git a/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.json b/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.json
index fc2a565..67b4a3d 100644
--- a/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.json
+++ b/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.json
@@ -6,6 +6,11 @@
  "engine": "InnoDB",
  "field_order": [
   "products_per_page",
+  "filter_categories_section",
+  "enable_field_filters",
+  "filter_fields",
+  "enable_attribute_filters",
+  "filter_attributes",
   "display_settings_section",
   "hide_variants",
   "enable_variants",
@@ -18,15 +23,6 @@
   "show_apply_coupon_code_in_website",
   "show_contact_us_button",
   "show_attachments",
-  "guest_display_settings_section",
-  "hide_price_for_guest",
-  "redirect_on_action",
-  "add_ons_section",
-  "enable_wishlist",
-  "column_break_22",
-  "enable_reviews",
-  "column_break_23",
-  "enable_recommendations",
   "section_break_18",
   "company",
   "price_list",
@@ -42,19 +38,22 @@
   "save_quotations_as_draft",
   "payment_gateway_account",
   "payment_success_url",
-  "filter_categories_section",
-  "enable_field_filters",
-  "filter_fields",
-  "enable_attribute_filters",
-  "filter_attributes",
-  "shop_by_category_section",
-  "slideshow",
+  "add_ons_section",
+  "enable_wishlist",
+  "column_break_22",
+  "enable_reviews",
+  "column_break_23",
+  "enable_recommendations",
   "item_search_settings_section",
   "redisearch_warning",
   "search_index_fields",
   "show_categories_in_search_autocomplete",
-  "show_brand_line",
-  "is_redisearch_loaded"
+  "is_redisearch_loaded",
+  "shop_by_category_section",
+  "slideshow",
+  "guest_display_settings_section",
+  "hide_price_for_guest",
+  "redirect_on_action"
  ],
  "fields": [
   {
@@ -311,14 +310,6 @@
   },
   {
    "default": "0",
-   "description": "e.g. \"iPhone 12 by Apple\"",
-   "fieldname": "show_brand_line",
-   "fieldtype": "Check",
-   "label": "Show Brand Line",
-   "read_only_depends_on": "eval:!doc.is_redisearch_loaded"
-  },
-  {
-   "default": "0",
    "fieldname": "is_redisearch_loaded",
    "fieldtype": "Check",
    "hidden": 1,
@@ -379,7 +370,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-08-24 21:10:45.669526",
+ "modified": "2021-08-31 12:23:06.187619",
  "modified_by": "Administrator",
  "module": "E-commerce",
  "name": "E Commerce Settings",
diff --git a/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.py b/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.py
index cade54d..ece60d4 100644
--- a/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.py
+++ b/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.py
@@ -3,7 +3,7 @@
 # For license information, please see license.txt
 
 import frappe
-from frappe.utils import comma_and
+from frappe.utils import comma_and, flt
 from frappe import _, msgprint
 from frappe.model.document import Document
 from frappe.utils import unique
@@ -20,11 +20,10 @@
 		self.validate_field_filters()
 		self.validate_attribute_filters()
 		self.validate_checkout()
-		self.validate_brand_check()
 		self.validate_search_index_fields()
 
 		if self.enabled:
-			self.validate_exchange_rates_exist()
+			self.validate_price_list_exchange_rate()
 
 		frappe.clear_document_cache("E Commerce Settings", "E Commerce Settings")
 
@@ -70,48 +69,33 @@
 
 		self.search_index_fields = ','.join(fields)
 
-	def validate_brand_check(self):
-		if self.show_brand_line and not ("brand" in self.search_index_fields):
-			self.search_index_fields += ",brand"
+	def validate_price_list_exchange_rate(self):
+		"Check if exchange rate exists for Price List currency (to Company's currency)."
+		from erpnext.setup.utils import get_exchange_rate
 
-	def validate_exchange_rates_exist(self):
-		"""check if exchange rates exist for all Price List currencies (to company's currency)"""
-		company_currency = frappe.get_cached_value('Company',  self.company,  "default_currency")
+		if not self.enabled or not self.company or not self.price_list:
+			return # this function is also called from hooks, check values again
+
+		company_currency = frappe.get_cached_value("Company", self.company, "default_currency")
+		price_list_currency = frappe.db.get_value("Price List", self.price_list, "currency")
+
 		if not company_currency:
-			msgprint(_("Please specify currency in Company") + ": " + self.company,
-				raise_exception=ShoppingCartSetupError)
+			msg = f"Please specify currency in Company {self.company}"
+			frappe.throw(_(msg), title=_("Missing Currency"), exc=ShoppingCartSetupError)
 
-		price_list_currency_map = frappe.db.get_values("Price List",
-			[self.price_list], "currency")
+		if not price_list_currency:
+			msg = f"Please specify currency in Price List {frappe.bold(self.price_list)}"
+			frappe.throw(_(msg), title=_("Missing Currency"), exc=ShoppingCartSetupError)
 
-		price_list_currency_map = dict(price_list_currency_map)
+		if price_list_currency != company_currency:
+			from_currency, to_currency = price_list_currency, company_currency
 
-		# check if all price lists have a currency
-		for price_list, currency in price_list_currency_map.items():
-			if not currency:
-				frappe.throw(_("Currency is required for Price List {0}").format(price_list))
+			# Get exchange rate checks Currency Exchange Records too
+			exchange_rate = get_exchange_rate(from_currency, to_currency, args="for_selling")
 
-		expected_to_exist = [currency + "-" + company_currency
-			for currency in price_list_currency_map.values()
-			if currency != company_currency]
-
-		# manqala 20/09/2016: set up selection parameters for query from tabCurrency Exchange
-		from_currency = [currency for currency in price_list_currency_map.values() if currency != company_currency]
-		to_currency = company_currency
-		# manqala end
-
-		if expected_to_exist:
-			# manqala 20/09/2016: modify query so that it uses date in the selection from Currency Exchange.
-			# exchange rates defined with date less than the date on which this document is being saved will be selected
-			exists = frappe.db.sql_list("""select CONCAT(from_currency,'-',to_currency) from `tabCurrency Exchange`
-				where from_currency in (%s) and to_currency = "%s" and date <= curdate()""" % (", ".join(["%s"]*len(from_currency)), to_currency), tuple(from_currency))
-			# manqala end
-
-			missing = list(set(expected_to_exist).difference(exists))
-
-			if missing:
-				msgprint(_("Missing Currency Exchange Rates for {0}").format(comma_and(missing)),
-					raise_exception=ShoppingCartSetupError)
+			if not flt(exchange_rate):
+				msg = f"Missing Currency Exchange Rates for {from_currency}-{to_currency}"
+				frappe.throw(_(msg), title=_("Missing"), exc=ShoppingCartSetupError)
 
 	def validate_tax_rule(self):
 		if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart" : 1}, "name"):
@@ -136,7 +120,7 @@
 			if not (new_fields == old_fields):
 				create_website_items_index()
 
-def validate_cart_settings(doc, method):
+def validate_cart_settings(doc=None, method=None):
 	frappe.get_doc("E Commerce Settings", "E Commerce Settings").run_method("validate")
 
 def get_shopping_cart_settings():
diff --git a/erpnext/e_commerce/doctype/website_item/website_item.py b/erpnext/e_commerce/doctype/website_item/website_item.py
index 59a1eb6..5eb6184 100644
--- a/erpnext/e_commerce/doctype/website_item/website_item.py
+++ b/erpnext/e_commerce/doctype/website_item/website_item.py
@@ -187,12 +187,17 @@
 
 	def get_context(self, context):
 		context.show_search = True
-		context.search_link = '/search'
+		context.search_link = "/search"
+		context.body_class = "product-page"
 
 		context.parents = get_parent_item_groups(self.item_group, from_item=True) # breadcumbs
 		self.attributes = frappe.get_all("Item Variant Attribute",
 			fields=["attribute", "attribute_value"],
 			filters={"parent": self.item_code})
+
+		if self.slideshow:
+			context.update(get_slideshow(self))
+
 		self.set_variant_context(context)
 		self.set_attribute_context(context)
 		self.set_disabled_attributes(context)
@@ -254,11 +259,9 @@
 
 					context[fieldname] = value
 
-		if self.slideshow:
-			if context.variant and context.variant.slideshow:
-				context.update(get_slideshow(context.variant))
-			else:
-				context.update(get_slideshow(self))
+		if self.slideshow and context.variant and context.variant.slideshow:
+			context.update(get_slideshow(context.variant))
+
 
 	def set_attribute_context(self, context):
 		if not self.has_variants:
diff --git a/erpnext/e_commerce/product_data_engine/filters.py b/erpnext/e_commerce/product_data_engine/filters.py
index 7ae87eb..daf679f 100644
--- a/erpnext/e_commerce/product_data_engine/filters.py
+++ b/erpnext/e_commerce/product_data_engine/filters.py
@@ -129,11 +129,15 @@
 		min_discount, max_discount = discounts[0], discounts[1]
 		# [25, 60] rounded min max
 		min_range_absolute, max_range_absolute = floor(min_discount), floor(max_discount)
+
 		min_range = int(min_discount - (min_range_absolute % 10)) # 20
 		max_range = int(max_discount - (max_range_absolute % 10)) # 60
 
+		min_range = (min_range + 10) if min_range != min_range_absolute else min_range # 30 (upper limit of 25.89 in range of 10)
+		max_range = (max_range + 10) if max_range != max_range_absolute else max_range # 60
+
 		for discount in range(min_range, (max_range + 1), 10):
-			label = f"{discount}% and above"
+			label = f"{discount}% and below"
 			discount_filters.append([discount, label])
 
 		return discount_filters
diff --git a/erpnext/e_commerce/product_data_engine/test_product_data_engine.py b/erpnext/e_commerce/product_data_engine/test_product_data_engine.py
index f6ff2d1..577c11b 100644
--- a/erpnext/e_commerce/product_data_engine/test_product_data_engine.py
+++ b/erpnext/e_commerce/product_data_engine/test_product_data_engine.py
@@ -226,7 +226,7 @@
 
 		self.assertEqual(len(discount_filters[0]), 2)
 		self.assertEqual(discount_filters[0][0], 10)
-		self.assertEqual(discount_filters[0][1], "10% and above")
+		self.assertEqual(discount_filters[0][1], "10% and below")
 
 	def test_product_list_with_discount_filters(self):
 		"Test if discount filters are applied correctly."
@@ -261,7 +261,7 @@
 		)
 		items = result.get("items")
 
-		# check if only product with 10% and above discount are fetched in the right order
+		# check if only product with 10% and below discount are fetched in the right order
 		self.assertEqual(len(items), 2)
 		self.assertEqual(items[0].get("item_code"), "Test 13I Laptop")
 		self.assertEqual(items[1].get("item_code"), "Test 12I Laptop")
diff --git a/erpnext/e_commerce/product_ui/grid.js b/erpnext/e_commerce/product_ui/grid.js
index d0b0e3b..51a13b0 100644
--- a/erpnext/e_commerce/product_ui/grid.js
+++ b/erpnext/e_commerce/product_ui/grid.js
@@ -143,7 +143,7 @@
 
 	get_stock_availability(item, settings) {
 		if (settings.show_stock_availability && !item.has_variants && !item.in_stock) {
-			return `<span class="out-of-stock">${ __("Out of stock") }</span>`;
+			return `<span class="out-of-stock mb-2 mt-1">${ __("Out of stock") }</span>`;
 		}
 		return ``;
 	}
@@ -161,7 +161,7 @@
 			return `
 				<div id="${ item.name }" class="btn
 					btn-sm btn-primary btn-add-to-cart-list
-					w-100 mt-4 ${ item.in_cart ? 'hidden' : '' }"
+					w-100 mt-2 ${ item.in_cart ? 'hidden' : '' }"
 					data-item-code="${ item.item_code }">
 					<span class="mr-2">
 						<svg class="icon icon-md">
diff --git a/erpnext/e_commerce/product_ui/list.js b/erpnext/e_commerce/product_ui/list.js
index e5791bb..7056a1a 100644
--- a/erpnext/e_commerce/product_ui/list.js
+++ b/erpnext/e_commerce/product_ui/list.js
@@ -24,7 +24,7 @@
 			let title = item.web_item_name || item.item_name || item.item_code || "";
 			title =  title.length > 200 ? title.substr(0, 200) + "..." : title;
 
-			html += `<div class='row list-row w-100'>`;
+			html += `<div class='row list-row w-100 mb-4'>`;
 			html += me.get_image_html(item, title, me.settings);
 			html += me.get_row_body_html(item, title, me.settings);
 			html += `</div>`;
@@ -86,7 +86,7 @@
 		`;
 
 		if (settings.enabled) {
-			title_html += `<div class="col-4" style="display:flex">`;
+			title_html += `<div class="col-4 cart-action-container ${item.in_cart ? 'd-flex' : ''}">`;
 			title_html += this.get_primary_button(item, settings);
 			title_html += `</div>`;
 		}
@@ -151,9 +151,7 @@
 		if (item.has_variants) {
 			return `
 				<a href="/${ item.route || '#' }">
-					<div class="btn btn-sm btn-explore-variants btn"
-					style="margin-bottom: 0; max-height: 30px; float: right;
-						padding: 0.25rem 1rem; min-width: 135px;">
+					<div class="btn btn-sm btn-explore-variants btn mb-0 mt-0">
 						${ __('Explore') }
 					</div>
 				</a>
@@ -161,10 +159,10 @@
 		} else if (settings.enabled && (settings.allow_items_not_in_stock || item.in_stock)) {
 			return `
 				<div id="${ item.name }" class="btn
-					btn-sm btn-primary btn-add-to-cart-list
+					btn-sm btn-primary btn-add-to-cart-list mb-0
 					${ item.in_cart ? 'hidden' : '' }"
 					data-item-code="${ item.item_code }"
-					style="margin-bottom: 0; margin-top: 0px !important; max-height: 30px; float: right;
+					style="margin-top: 0px !important; max-height: 30px; float: right;
 						padding: 0.25rem 1rem; min-width: 135px;">
 					<span class="mr-2">
 						<svg class="icon icon-md">
@@ -174,14 +172,14 @@
 					${ __('Add to Cart') }
 				</div>
 
-				<div class="cart-indicator ${item.in_cart ? '' : 'hidden'}" style="position: unset;">
+				<div class="cart-indicator list-indicator ${item.in_cart ? '' : 'hidden'}">
 					1
 				</div>
 
 				<a href="/cart">
 					<div id="${ item.name }" class="btn
 						btn-sm btn-primary btn-add-to-cart-list
-						ml-4 go-to-cart
+						ml-4 go-to-cart mb-0 mt-0
 						${ item.in_cart ? '' : 'hidden' }"
 						data-item-code="${ item.item_code }"
 						style="padding: 0.25rem 1rem; min-width: 135px;">
diff --git a/erpnext/e_commerce/product_ui/search.js b/erpnext/e_commerce/product_ui/search.js
index ebe0076..9bae1c1 100644
--- a/erpnext/e_commerce/product_ui/search.js
+++ b/erpnext/e_commerce/product_ui/search.js
@@ -38,39 +38,37 @@
 			let query = e.target.value;
 
 			if (query.length == 0) {
-				me.populateResults([]);
-				me.populateCategoriesList([]);
+				me.populateResults(null);
+				me.populateCategoriesList(null);
 			}
 
 			if (query.length < 3 || !query.length) return;
 
-			// Populate recent search chips
-			me.setRecentSearches(query);
-
-			// Fetch and populate product results
 			frappe.call({
 				method: "erpnext.templates.pages.product_search.search",
 				args: {
 					query: query
 				},
 				callback: (data) => {
-					me.populateResults(data);
+					let product_results = null, category_results = null;
+
+					// Populate product results
+					product_results = data.message ? data.message.product_results : null;
+					me.populateResults(product_results);
+
+					// Populate categories
+					if (me.category_container) {
+						category_results = data.message ? data.message.category_results : null;
+						me.populateCategoriesList(category_results);
+					}
+
+					// Populate recent search chips only on successful queries
+					if (!$.isEmptyObject(product_results) || !$.isEmptyObject(category_results)) {
+						me.setRecentSearches(query);
+					}
 				}
 			});
 
-			// Populate categories
-			if (me.category_container) {
-				frappe.call({
-					method: "erpnext.templates.pages.product_search.get_category_suggestions",
-					args: {
-						query: query
-					},
-					callback: (data) => {
-						me.populateCategoriesList(data);
-					}
-				});
-			}
-
 			this.search_dropdown.removeClass("hidden");
 		});
 	}
@@ -186,17 +184,16 @@
 		this.attachEventListenersToChips();
 	}
 
-	populateResults(data) {
-		if (data.length === 0 || data.message.results.length === 0) {
+	populateResults(product_results) {
+		if (!product_results || product_results.length === 0) {
 			let empty_html = ``;
 			this.products_container.html(empty_html);
 			return;
 		}
 
 		let html = "";
-		let search_results = data.message.results;
 
-		search_results.forEach((res) => {
+		product_results.forEach((res) => {
 			let thumbnail = res.thumbnail || '/assets/erpnext/images/ui-states/cart-empty-state.png';
 			html += `
 				<div class="dropdown-item" style="display: flex;">
@@ -212,8 +209,8 @@
 		this.products_container.html(html);
 	}
 
-	populateCategoriesList(data) {
-		if (data.length === 0 || data.message.results.length === 0) {
+	populateCategoriesList(category_results) {
+		if (!category_results || category_results.length === 0) {
 			let empty_html = `
 				<div class="category-container mt-2">
 					<div class="category-chips">
@@ -229,8 +226,8 @@
 				<b>${ __("Categories") }</b>
 			</div>
 		`;
-		let search_results = data.message.results;
-		search_results.forEach((category) => {
+
+		category_results.forEach((category) => {
 			html += `
 				<a href="/${category.route}" class="btn btn-sm category-chip mr-2 mb-2"
 					style="font-size: 13px" role="button">
diff --git a/erpnext/e_commerce/product_ui/views.js b/erpnext/e_commerce/product_ui/views.js
index 993fd5c..99b91af 100644
--- a/erpnext/e_commerce/product_ui/views.js
+++ b/erpnext/e_commerce/product_ui/views.js
@@ -129,7 +129,7 @@
 
 	prepare_product_area_wrapper(view) {
 		let left_margin = view == "list" ? "ml-2" : "";
-		let top_margin = view == "list" ? "mt-8" : "mt-4";
+		let top_margin = view == "list" ? "mt-6" : "mt-minus-1";
 		return this.products_section.append(`
 			<br>
 			<div id="products-${view}-area" class="row products-list ${ top_margin } ${ left_margin }"></div>
@@ -191,7 +191,7 @@
 
 	prepare_search() {
 		$(".toolbar").append(`
-			<div class="input-group col-6 p-0">
+			<div class="input-group col-8 p-0">
 				<div class="dropdown w-100" id="dropdownMenuSearch">
 					<input type="search" name="query" id="search-box" class="form-control font-md"
 						placeholder="Search for Products"
@@ -213,7 +213,7 @@
 	}
 
 	render_view_toggler() {
-		$(".toolbar").append(`<div class="toggle-container col-6 p-0"></div>`);
+		$(".toolbar").append(`<div class="toggle-container col-4 p-0"></div>`);
 
 		["btn-list-view", "btn-grid-view"].forEach(view => {
 			let icon = view === "btn-list-view" ? "list" : "image-view";
diff --git a/erpnext/public/js/shopping_cart.js b/erpnext/public/js/shopping_cart.js
index 127fa22..d99063b 100644
--- a/erpnext/public/js/shopping_cart.js
+++ b/erpnext/public/js/shopping_cart.js
@@ -51,6 +51,7 @@
 	if (referral_sales_partner) {
 		$(".txtreferral_sales_partner").val(referral_sales_partner);
 	}
+
 	// update login
 	shopping_cart.show_shoppingcart_dropdown();
 	shopping_cart.set_cart_count();
@@ -95,7 +96,7 @@
 				btn: opts.btn,
 				callback: function(r) {
 					shopping_cart.unfreeze();
-					shopping_cart.set_cart_count();
+					shopping_cart.set_cart_count(true);
 					if(opts.callback)
 						opts.callback(r);
 				}
@@ -103,7 +104,7 @@
 		}
 	},
 
-	set_cart_count: function() {
+	set_cart_count: function(animate=false) {
 		var cart_count = frappe.get_cookie("cart_count");
 		if(frappe.session.user==="Guest") {
 			cart_count = 0;
@@ -129,10 +130,13 @@
 
 		if(cart_count) {
 			$badge.html(cart_count);
-			$cart.addClass('cart-animate');
-			setTimeout(() => {
-				$cart.removeClass('cart-animate');
-			}, 500);
+
+			if (animate) {
+				$cart.addClass("cart-animate");
+				setTimeout(() => {
+					$cart.removeClass("cart-animate");
+				}, 500);
+			}
 		} else {
 			$badge.remove();
 		}
@@ -187,6 +191,7 @@
 			}
 
 			$btn.addClass('hidden');
+			$btn.closest('.cart-action-container').addClass('d-flex');
 			$btn.parent().find('.go-to-cart').removeClass('hidden');
 			$btn.parent().find('.go-to-cart-grid').removeClass('hidden');
 			$btn.parent().find('.cart-indicator').removeClass('hidden');
diff --git a/erpnext/public/js/wishlist.js b/erpnext/public/js/wishlist.js
index ca5af96..f6599e9 100644
--- a/erpnext/public/js/wishlist.js
+++ b/erpnext/public/js/wishlist.js
@@ -5,7 +5,7 @@
 var shopping_cart = erpnext.e_commerce.shopping_cart;
 
 $.extend(wishlist, {
-	set_wishlist_count: function() {
+	set_wishlist_count: function(animate=false) {
 		// set badge count for wishlist icon
 		var wish_count = frappe.get_cookie("wish_count");
 		if (frappe.session.user==="Guest") {
@@ -26,10 +26,12 @@
 		}
 		if (wish_count) {
 			$badge.html(wish_count);
-			$wishlist.addClass('cart-animate');
-			setTimeout(() => {
-				$wishlist.removeClass('cart-animate');
-			}, 500);
+			if (animate) {
+				$wishlist.addClass('cart-animate');
+				setTimeout(() => {
+					$wishlist.removeClass('cart-animate');
+				}, 500);
+			}
 		} else {
 			$badge.remove();
 		}
@@ -98,7 +100,7 @@
 		}
 
 		let success_action = function() {
-			erpnext.e_commerce.wishlist.set_wishlist_count();
+			erpnext.e_commerce.wishlist.set_wishlist_count(true);
 		};
 
 		if ($wish_icon.hasClass('wished')) {
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
index 8648cdb..4697ab7 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -3,10 +3,11 @@
 :root {
 	--green-info: #38A160;
 	--product-bg-color: white;
+	--body-bg-color:  var(--gray-50);
 }
 
 body.product-page {
-	background: var(--gray-50);
+	background: var(--body-bg-color);
 }
 
 .item-breadcrumbs {
@@ -175,6 +176,7 @@
 		font-weight: 600;
 		color: var(--text-color);
 		margin: var(--margin-sm) 0;
+		margin-bottom: auto !important;
 
 		.striked-price {
 			font-weight: 500;
@@ -203,7 +205,12 @@
 	}
 }
 
+#products-list-area, #products-grid-area {
+	padding: 0 5px;
+}
+
 .list-row {
+	background-color: white;
 	padding-bottom: 1rem;
 	padding-top: 1.5rem !important;
 	border-radius: 8px;
@@ -223,6 +230,17 @@
 			visibility: visible;
 		}
 	}
+
+	.product-code {
+		padding-top: 0 !important;
+	}
+
+	.btn-explore-variants {
+		min-width: 135px;
+		max-height: 30px;
+		float: right;
+		padding: 0.25rem 1rem;
+	}
 }
 
 [data-doctype="Item Group"],
@@ -288,7 +306,7 @@
 .product-container {
 	@include card($padding: var(--padding-md));
 	background-color: var(--product-bg-color) !important;
-	min-height: 70vh;
+	min-height: fit-content;
 
 	.product-details {
 		max-width: 50%;
@@ -372,7 +390,7 @@
 			max-height: 430px;
 		}
 
-		overflow: scroll;
+		overflow: auto;
 	}
 
 	.item-slideshow-image {
@@ -443,7 +461,7 @@
 		.r-item-image {
 			width: 40%;
 
-			.product-image {
+			.r-product-image {
 				padding: 2px 15px;
 			}
 
@@ -920,6 +938,11 @@
 	background: white;
 	color: var(--primary-color);
 	font-size: 14px;
+
+	&.list-indicator {
+		position: unset;
+		margin-left: auto;
+	}
 }
 
 
@@ -1021,6 +1044,10 @@
 	}
 }
 
+#pay-for-order {
+	padding: .5rem 1rem; // Pay button in SO
+}
+
 .btn-explore-variants {
 	visibility: hidden;
 	box-shadow: none;
@@ -1044,7 +1071,7 @@
 	visibility: hidden;
 	box-shadow: none;
 	margin: var(--margin-sm) 0;
-	margin-top: auto !important;
+	// margin-top: auto !important;
 	max-height: 50px; // to avoid resizing on window resize
 	flex: none;
 	transition: 0.3s ease;
@@ -1231,6 +1258,7 @@
 }
 
 #search-results-container {
+	border: 1px solid var(--gray-200);
 	padding: .25rem 1rem;
 
 	.category-chip {
@@ -1250,7 +1278,10 @@
 }
 
 #search-box {
+	background-color: white;
+	height: 100%;
 	padding-left: 2.5rem;
+	border: 1px solid var(--gray-200);
 }
 
 .search-icon {
@@ -1267,6 +1298,11 @@
 
 #toggle-view {
 	float: right;
+
+	.btn-primary {
+		background-color: var(--gray-600);
+		box-shadow: 0 0 0 0.2rem var(--gray-400);
+	}
 }
 
 .placeholder-div {
@@ -1328,3 +1364,7 @@
 .mt-minus-2 {
 	margin-top: -2rem;
 }
+
+.mt-minus-1 {
+	margin-top: -1rem;
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 3d1a1d0..b41a01b 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -62,6 +62,7 @@
 
 	def get_context(self, context):
 		context.show_search = True
+		context.body_class = "product-page"
 		context.page_length = cint(frappe.db.get_single_value('E Commerce Settings', 'products_per_page')) or 6
 		context.search_link = '/product_search'
 
diff --git a/erpnext/templates/generators/item/item_add_to_cart.html b/erpnext/templates/generators/item/item_add_to_cart.html
index 399240b..77ee901 100644
--- a/erpnext/templates/generators/item/item_add_to_cart.html
+++ b/erpnext/templates/generators/item/item_add_to_cart.html
@@ -71,7 +71,7 @@
 					</div>
 					<p class="mr-1 mb-1">
 						{{ _(offer.offer_title) }}:
-						{{ _(offer.offer_subtitle) }}
+						{{ _(offer.offer_subtitle) if offer.offer_subtitle else '' }}
 						<a class="offer-details" href="#"
 							data-offer-title="{{ offer.offer_title }}" data-offer-id="{{ offer.name }}"
 							role="button">
@@ -117,7 +117,7 @@
 			const $btn = $(e.currentTarget);
 			$btn.prop('disabled', true);
 			const item_code = $btn.data('item-code');
-			e_commerce.shopping_cart.update_cart({
+			erpnext.e_commerce.shopping_cart.update_cart({
 				item_code,
 				qty: 1,
 				callback(r) {
diff --git a/erpnext/templates/generators/item/item_details.html b/erpnext/templates/generators/item/item_details.html
index 04a4aee..028936b 100644
--- a/erpnext/templates/generators/item/item_details.html
+++ b/erpnext/templates/generators/item/item_details.html
@@ -58,6 +58,6 @@
 	$('.page_content').on('click', '.like-action-item-fp', (e) => {
 			// Bind action on wishlist button
 			const $btn = $(e.currentTarget);
-			e_commerce.wishlist.wishlist_action($btn);
+			erpnext.e_commerce.wishlist.wishlist_action($btn);
 		});
 </script>
\ No newline at end of file
diff --git a/erpnext/templates/generators/item/item_image.html b/erpnext/templates/generators/item/item_image.html
index 21145c0..930bb7a 100644
--- a/erpnext/templates/generators/item/item_image.html
+++ b/erpnext/templates/generators/item/item_image.html
@@ -1,30 +1,30 @@
 {% set column_size = 5 if slides else 4 %}
 <div class="col-md-{{ column_size }} h-100 d-flex mb-4">
 	{% if slides %}
-	<div class="item-slideshow d-flex flex-column mr-3">
-		{% for item in slides %}
-		<img class="item-slideshow-image mb-2 {% if loop.first %}active{% endif %}"
-				src="{{ item.image }}" alt="{{ item.heading }}">
-		{% endfor %}
-	</div>
-	{{ product_image(slides[0].image, 'product-image') }}
-	<!-- Simple image slideshow -->
-	<script>
-		frappe.ready(() => {
-			$('.page_content').on('click', '.item-slideshow-image', (e) => {
-				const $img = $(e.currentTarget);
-				const link = $img.prop('src');
-				const $product_image = $('.product-image');
-				$product_image.find('a').prop('href', link);
-				$product_image.find('img').prop('src', link);
+		<div class="item-slideshow d-flex flex-column mr-3">
+			{% for item in slides %}
+			<img class="item-slideshow-image mb-2 {% if loop.first %}active{% endif %}"
+					src="{{ item.image }}" alt="{{ item.heading }}">
+			{% endfor %}
+		</div>
+		{{ product_image(slides[0].image, 'product-image') }}
+		<!-- Simple image slideshow -->
+		<script>
+			frappe.ready(() => {
+				$('.page_content').on('click', '.item-slideshow-image', (e) => {
+					const $img = $(e.currentTarget);
+					const link = $img.prop('src');
+					const $product_image = $('.product-image');
+					$product_image.find('a').prop('href', link);
+					$product_image.find('img').prop('src', link);
 
-				$('.item-slideshow-image').removeClass('active');
-				$img.addClass('active');
-			});
-		})
-	</script>
+					$('.item-slideshow-image').removeClass('active');
+					$img.addClass('active');
+				});
+			})
+		</script>
 	{% else %}
-	{{ product_image(doc.website_image or doc.image, alt=doc.website_image_alt or doc.item_name) }}
+		{{ product_image(doc.website_image or doc.image, alt=doc.website_image_alt or doc.item_name) }}
 	{% endif %}
 
 	<!-- Simple image preview -->
diff --git a/erpnext/templates/generators/item/item_specifications.html b/erpnext/templates/generators/item/item_specifications.html
index 4a59f83..0814d81 100644
--- a/erpnext/templates/generators/item/item_specifications.html
+++ b/erpnext/templates/generators/item/item_specifications.html
@@ -1,9 +1,9 @@
 <!-- Is reused to render within tabs as well as independently -->
 {% if website_specifications %}
-<div class="mt-5 item-website-specification">
+<div class="{{ 'mt-2' if not show_tabs else 'mt-5'}} item-website-specification">
 	<div class="col-md-11">
 		{% if not show_tabs %}
-			<div class="product-title mb-5 mt-8">
+			<div class="product-title mb-5 mt-4">
 				Product Details
 			</div>
 		{% endif %}
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index 9663b92..889cf1a 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -363,9 +363,9 @@
 <div class="recommended-item mb-6 d-flex">
 	<div class="r-item-image">
 		{% if item.website_item_thumbnail %}
-			{{ product_image(item.website_item_thumbnail, alt="item.website_item_name", no_border=True) }}
+			{{ product_image(item.website_item_thumbnail, css_class="r-product-image", alt="item.website_item_name", no_border=True) }}
 		{% else %}
-			<div class = "no-image-r-item">
+			<div class="no-image-r-item">
 				{{ frappe.utils.get_abbr(item.website_item_name) or "NA" }}
 			</div>
 		{% endif %}
diff --git a/erpnext/templates/pages/cart.py b/erpnext/templates/pages/cart.py
index 1f0cd5c..cadb46f 100644
--- a/erpnext/templates/pages/cart.py
+++ b/erpnext/templates/pages/cart.py
@@ -7,4 +7,5 @@
 
 
 def get_context(context):
+	context.body_class = "product-page"
 	context.update(get_cart_quotation())
diff --git a/erpnext/templates/pages/customer_reviews.py b/erpnext/templates/pages/customer_reviews.py
index 02c03d3..10cb28a 100644
--- a/erpnext/templates/pages/customer_reviews.py
+++ b/erpnext/templates/pages/customer_reviews.py
@@ -6,6 +6,7 @@
 from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import get_shopping_cart_settings
 
 def get_context(context):
+	context.body_class = "product-page"
 	context.no_cache = 1
 	context.full_page = True
 	context.reviews = None
@@ -14,6 +15,7 @@
 		context.web_item = frappe.form_dict.get("web_item")
 		context.user_is_customer = check_if_user_is_customer()
 		context.enable_reviews = get_shopping_cart_settings().enable_reviews
+
 		if context.enable_reviews:
 			reviews_data = get_item_reviews(context.web_item)
 			context.update(reviews_data)
diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html
index 28faea8..19191d8 100644
--- a/erpnext/templates/pages/order.html
+++ b/erpnext/templates/pages/order.html
@@ -139,9 +139,12 @@
 				<div class="form-column col-sm-6">
 					<div id="loyalty-points-status" style="text-align: right"></div>
 					<div class="page-header-actions-block" data-html-block="header-actions">
-						<p>
+						<p class="mt-2" style="float: right;">
 							<a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
-								class="btn btn-primary btn-sm" id="pay-for-order">{{ _("Pay") }} {{ doc.get_formatted("grand_total") }} </a>
+								class="btn btn-primary btn-sm"
+								id="pay-for-order">
+								{{ _("Pay") }} {{ doc.get_formatted("grand_total") }}
+							</a>
 						</p>
 					</div>
 				</div>
diff --git a/erpnext/templates/pages/product_search.py b/erpnext/templates/pages/product_search.py
index 00aace4..bfee793 100644
--- a/erpnext/templates/pages/product_search.py
+++ b/erpnext/templates/pages/product_search.py
@@ -59,7 +59,17 @@
 	}, as_dict=1)
 
 @frappe.whitelist(allow_guest=True)
-def search(query, limit=10, fuzzy_search=True):
+def search(query):
+	product_results = product_search(query)
+	category_results = get_category_suggestions(query)
+
+	return {
+		"product_results": product_results.get("results") or [],
+		"category_results": category_results.get("results") or []
+	}
+
+@frappe.whitelist(allow_guest=True)
+def product_search(query, limit=10, fuzzy_search=True):
 	search_results = {"from_redisearch": True, "results": []}
 
 	if not is_search_module_loaded():
diff --git a/erpnext/templates/pages/wishlist.py b/erpnext/templates/pages/wishlist.py
index 9fa83a9..339e51b 100644
--- a/erpnext/templates/pages/wishlist.py
+++ b/erpnext/templates/pages/wishlist.py
@@ -14,6 +14,7 @@
 
 	items = set_stock_price_details(items, settings, selling_price_list)
 
+	context.body_class = "product-page"
 	context.items = items
 	context.settings = settings
 	context.no_cache = 1
diff --git a/erpnext/www/all-products/index.py b/erpnext/www/all-products/index.py
index c66924e..0f6f59f 100644
--- a/erpnext/www/all-products/index.py
+++ b/erpnext/www/all-products/index.py
@@ -6,6 +6,7 @@
 
 def get_context(context):
 	# Add homepage as parent
+	context.body_class = "product-page"
 	context.parents = [{"name": frappe._("Home"), "route":"/"}]
 
 	filter_engine = ProductFiltersBuilder()
diff --git a/erpnext/www/shop-by-category/index.py b/erpnext/www/shop-by-category/index.py
index 7dfbd76..fecc05b 100644
--- a/erpnext/www/shop-by-category/index.py
+++ b/erpnext/www/shop-by-category/index.py
@@ -4,6 +4,8 @@
 sitemap = 1
 
 def get_context(context):
+	context.body_class = "product-page"
+
 	settings = frappe.get_cached_doc("E Commerce Settings")
 	context.categories_enabled = settings.enable_field_filters