+
+
+
+
+
+ Community
+
+
+
+ Enterprise
+
+
+
+
+
+
+
+
+
+ This module helps to Retrieve product information from Icecat and display it on the website shop.
+
+
Odoo Icecat Connector
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Key
+ Highlights
+
+
+
+
+
+
+
+ Product Details Retrieval
+
+
+ The core feature of the module would be the ability to fetch detailed product information from
+ Icecat using the product code and brand specified in the Odoo website.
+ This should include data such as product specifications, images, descriptions, and other relevant details.
+
+
+
+
+
+
+
+
+ Efficient Data Retrieval
+
+
+ Ensure that the module is optimized for efficient data retrieval. This includes minimizing
+ the number of API calls to Icecat, caching data locally in Odoo to reduce load times,
+ and providing options for scheduled updates to keep product information current.
+
+
+
+
+
+
+
+
+
+
+ User-Friendly Configuration
+
+
+ A user-friendly configuration interface within Odoo that allows administrators to
+ easily set up and manage the connection to Icecat. This should include fields for API credentials,
+ mapping Odoo product attributes to Icecat attributes, and other relevant settings
+
+
+
+
+
+
+
+
+
+
+ Compatible with both Community and Enterprise EditionsOdoo 18.0 .
+
+
+ Compactible with both community and enterprise editions
+
+
+
+
+
+
+
+
+
+
+ Automatic Synchronization
+
+
+ Implement an automatic synchronization mechanism that periodically updates product information from Icecat without manual intervention.
+ This ensures that the Odoo website always reflects the latest details for products sourced from Icecat.
+
+
+
+
+
+
+
+
+
+
+ No Database Load
+
+
+ This module has key feature would be to minimize database load in Odoo. This can be achieved by storing Icecat data in a separate Odoo model or table and only
+ fetching the necessary details when required, avoiding unnecessary duplication or storage of redundant information.
+
+
+
+
+
+
+
+
+
+
Odoo Icecat Connector
+
+ Are you ready to make your business more
+ organized?
+ Improve now!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set User Name on Odoo
+
+
+
+
+
+ First set your username of Icecat for that go to Settings --> Website --> Website Info --> Icecat User Id Ensure that you have entered the correct Icecat username;
+ otherwise, no product information will not be available on the website shop.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Copy content from Icecat
+
+
+
+
+
+ Please visit the Icecat website and navigate to the desired product. Subsequently,
+ retrieve the Product Code and Brand information by copying the relevant details from the product page.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add Details on Product
+
+
+
+
+
+ Create or import the product in Odoo, specifying the Internal Reference as the Product code from Icecat,
+ and associating the Brand of the product with the corresponding Brand information in Icecat.
+ Ensure that accurate and complete details have been provided in the product form view.
+ Otherwise, no product information will not be available on the website shop.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open Product from Website
+
+
+
+
+
+ You can view the comprehensive details of the product on the website (only if you have provided that accurate and complete details).
+ All information displayed originates from the Icecat database.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Time Efficiency:
+
+
+
+
+
+
+
+
+
+
+ No additional configuration required.
+
+
+
+
+
+
+
+
+
+
+
+ Product Information Enrichment.
+
+
+
+
+
+
+
+
+
+
+
+ Real-Time Price and Availability Updates
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No, We cannot import or export product .We can display all the specifications for the product on website
+
+
+
+
+
+
+
+
+ No ,This module is available from odoo 16 onwards .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latest Release 18.0.1.0.0
+
+
+ 13 th June, 2025
+
+
+
+
+
+
+
+
+
+
+
+
+ Related Products
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/odoo_icecat_connector/static/src/js/icecat.js b/odoo_icecat_connector/static/src/js/icecat.js
new file mode 100755
index 0000000000..f8096dc430
--- /dev/null
+++ b/odoo_icecat_connector/static/src/js/icecat.js
@@ -0,0 +1,40 @@
+/** @odoo-module **/
+import { rpc } from "@web/core/network/rpc";
+/**
+ * Fetches Icecat product details based on the provided product ID.
+ */
+function fetchIcecatProductDetails() {
+ // Get the product ID from the element with the class 'product_id'
+ var productElement = document.querySelector('.product_id');
+ var product_id = productElement ? productElement.value : undefined;
+ // Check if the product ID is defined
+ if (typeof $('.product_id').val() !== "undefined") {
+ // Make a RPC call to retrieve Icecat product details
+ rpc('/get_icecat_product_details', {
+ 'product_id': product_id,
+ }).then((data) => {
+ if (data.status) {
+ IcecatLive.getDatasheet({
+ 'title': '#icecat_title',
+ 'essentialinfo': '#icecat_essentialinfo',
+ 'marketingtext': '#icecat_marketingtext',
+ 'manuals': '#icecat_manuals',
+ 'reasonstobuy': '#icecat_reasonstobuy',
+ 'reviews': '#icecat_reviews',
+ 'featuregroups': '#icecat_featuregroups',
+ 'gallery': '#icecat_gallery',
+ 'featurelogos': '#icecat_featurelogos',
+ 'tours3d': '#icecat_tours3d',
+ 'videos': '#icecat_videos',
+ 'productstory': '#icecat_productstory'
+ }, {
+ Brand: data.brand,
+ PartCode: data.product_code,
+ UserName: data.username,
+ }, 'en');
+ }
+ });
+ }
+}
+// Call the function to fetch Icecat product details
+fetchIcecatProductDetails();
diff --git a/odoo_icecat_connector/views/product_template_views.xml b/odoo_icecat_connector/views/product_template_views.xml
new file mode 100755
index 0000000000..11f4429984
--- /dev/null
+++ b/odoo_icecat_connector/views/product_template_views.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ product.template.view.form.inherit.odoo.icecat.connector
+ product.template
+
+
+
+
+
+
+
+
diff --git a/odoo_icecat_connector/views/res_config_settings_views.xml b/odoo_icecat_connector/views/res_config_settings_views.xml
new file mode 100755
index 0000000000..a72f06cb3a
--- /dev/null
+++ b/odoo_icecat_connector/views/res_config_settings_views.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+ res.config.settings.view.form.inherit.odoo.icecat.connector
+ res.config.settings
+
+
+
+
+
+
+
+
+
+
+ Select your Icecat username here
+
+
+
+
+
+
+
+
+
+
+
diff --git a/odoo_icecat_connector/views/shop_templates.xml b/odoo_icecat_connector/views/shop_templates.xml
new file mode 100755
index 0000000000..3b0308c46e
--- /dev/null
+++ b/odoo_icecat_connector/views/shop_templates.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Brand:
+
+
+
+
+
+ Product name:
+
+
+
+
+
+
+ Product code:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openai_product_images/models/dalle_image_suggestion.py b/openai_product_images/models/dalle_image_suggestion.py
index 92ed0a17da..00464d743f 100644
--- a/openai_product_images/models/dalle_image_suggestion.py
+++ b/openai_product_images/models/dalle_image_suggestion.py
@@ -49,3 +49,4 @@ def action_make_as_product_image(self):
'domain': [('id', '=', self.product_tmpl_id.id)],
'target': 'current',
}
+
diff --git a/openai_product_images/models/product_template.py b/openai_product_images/models/product_template.py
index 9bab44c840..0325b7a0c0 100644
--- a/openai_product_images/models/product_template.py
+++ b/openai_product_images/models/product_template.py
@@ -50,7 +50,7 @@ def get_dall_e_image(self):
"""
return {
'name': self.name,
- 'view_mode': 'list,form',
+ 'view_mode': 'tree,form',
'res_model': 'dalle.image.suggestion',
'type': 'ir.actions.act_window',
'domain': [('product_tmpl_id', '=', self.id)],
diff --git a/openai_product_images/wizard/image_suggestion.py b/openai_product_images/wizard/image_suggestion.py
index b6afefd274..538f15e48b 100644
--- a/openai_product_images/wizard/image_suggestion.py
+++ b/openai_product_images/wizard/image_suggestion.py
@@ -19,73 +19,89 @@
# If not, see
.
#
################################################################################
-import requests
-from requests.structures import CaseInsensitiveDict
-import json
-import base64
from odoo import fields, models, _
-from odoo.exceptions import ValidationError
+from odoo.exceptions import UserError, ValidationError
+from urllib.request import urlopen
+from openai import OpenAI
+import base64
class ImageSuggestion(models.TransientModel):
- """image for product from dalle"""
+ """Image generator for product from OpenAI DALL·E 3"""
_name = 'image.suggestion'
_rec_name = 'product_tmpl_id'
- _description = 'model for creation of dalle image '
+ _description = 'Model for creation of product images using DALL·E'
- image_prompt = fields.Char(string="Prompt for image",
- help="field to fill prompt", required=True)
- product_tmpl_id = fields.Many2one('product.template', string="Product",
- help="field to store product",
- required=True)
- num_image = fields.Integer(string="Number of image needed",
- help="field to store number of image",
- required=True,
- default=1)
+ image_prompt = fields.Char(
+ string="Prompt for Image",
+ help="Describe the image you want to generate",
+ required=True
+ )
+ product_tmpl_id = fields.Many2one(
+ 'product.template',
+ string="Product",
+ help="Select the product for which image needs to be generated",
+ required=True
+ )
+ num_image = fields.Integer(
+ string="Number of Images",
+ help="Number of images to generate",
+ required=True,
+ default=1
+ )
size_image = fields.Selection(
- [('256x256', '256x256'), ('512x512', '512x512')], string="Resolution",
- help="field to store image size", required=True)
+ [
+ ('1024x1024', '1024x1024'),
+ ('1024x1792', '1024x1792 (Portrait)'),
+ ('1792x1024', '1792x1024 (Landscape)')
+ ],
+ string="Resolution",
+ help="Resolution of generated images",
+ required=True,
+ default='1024x1024'
+ )
+ quality = fields.Selection(
+ [
+ ('standard', 'Standard'),
+ ('hd', 'High Definition')
+ ],
+ string="Quality",
+ help="Image quality setting for DALL·E 3",
+ required=True,
+ default='standard'
+ )
def action_search(self):
- """Summary:
- Function to search image suggestion from dalle
- Returns:
- returns the created media image of corresponding product
- """
- api_key = self.env['ir.config_parameter'].sudo().get_param(
- 'openai_api_key')
- if not api_key:
- raise ValidationError(
- _("Invalid API key provided. Please ensure that you have "
- "entered the correct API key. "))
- headers = CaseInsensitiveDict()
- headers["Content-Type"] = "application/json"
- headers["Authorization"] = f"Bearer {api_key}"
- data = '{"model": "dall-e-2",' \
- ' "prompt": "' + self.image_prompt + '", "num_images": ' + \
- str(self.num_image) + ', "size": "' \
- + self.size_image + '", "response_format": "url"}'
- resp = requests.post("https://api.openai.com/v1/images/generations",
- headers=headers, data=data)
- if resp.status_code != 200:
- raise ValidationError("Failed to generate image")
- response_text = json.loads(resp.text)
- for url in response_text['data']:
- image_url = url['url']
- # Get image data and encode it in base64
- image_resp = requests.get(image_url)
- if image_resp.status_code != 200:
- raise ValidationError("Failed to retrieve image")
- image_b64 = base64.b64encode(image_resp.content)
- # Store encoded image as binary field on model
- self.env['dalle.image.suggestion'].create(
- {'product_image': image_b64,
- 'product_tmpl_id': self.product_tmpl_id.id, })
- return {
- 'name': self.product_tmpl_id.name,
- 'view_mode': 'list,form',
- 'res_model': 'dalle.image.suggestion',
- 'type': 'ir.actions.act_window',
- 'domain': [('product_tmpl_id', '=', self.product_tmpl_id.id)],
- 'target': 'current',
- }
+ """Generate product images from OpenAI DALL·E 3"""
+ # Hardcoded API key as requested
+ api_key = self.env['ir.config_parameter'].sudo().get_param('openai_api_key')
+
+ client = OpenAI(api_key=api_key)
+ try:
+ response = client.images.generate(
+ model="dall-e-3",
+ prompt=self.image_prompt, # Use image_prompt field
+ size=self.size_image,
+ quality=self.quality,
+ n=self.num_image,
+ )
+ # Process the first image (DALL-E 3 typically returns one image)
+ image_url = response.data[0].url
+ image_content = urlopen(image_url).read()
+ image_b64_encoded = base64.b64encode(image_content)
+
+ # Update the product's image_1920 field
+ self.product_tmpl_id.write({'image_1920': image_b64_encoded})
+
+ # Optionally store in dalle.image.suggestion (if needed for history)
+ self.env['dalle.image.suggestion'].create({
+ 'product_image': image_b64_encoded,
+ 'product_tmpl_id': self.product_tmpl_id.id,
+ })
+
+ # Return action to close wizard or refresh product form
+ return {
+ 'type': 'ir.actions.act_window_close',
+ }
+ except Exception as e:
+ raise UserError(f"Error generating image: {str(e)}")
\ No newline at end of file
diff --git a/openai_product_images/wizard/image_suggestion_views.xml b/openai_product_images/wizard/image_suggestion_views.xml
index 37b0e4af6b..91167b85eb 100644
--- a/openai_product_images/wizard/image_suggestion_views.xml
+++ b/openai_product_images/wizard/image_suggestion_views.xml
@@ -13,6 +13,7 @@
+
diff --git a/payment_status_in_sale/__manifest__.py b/payment_status_in_sale/__manifest__.py
index e26af79338..e610ba2bad 100644
--- a/payment_status_in_sale/__manifest__.py
+++ b/payment_status_in_sale/__manifest__.py
@@ -21,7 +21,7 @@
###############################################################################
{
'name': 'Sale Order Payment Status',
- 'version': '18.0.1.0.1',
+ 'version': '18.0.1.0.3',
'category': 'Sales',
'summary': 'Displays the payment status and details in the Sale Order.',
'description': """This module is used to display the invoice status of the
diff --git a/payment_status_in_sale/doc/RELEASE_NOTES.md b/payment_status_in_sale/doc/RELEASE_NOTES.md
index 3ac9a32e0e..0a6c91a61c 100644
--- a/payment_status_in_sale/doc/RELEASE_NOTES.md
+++ b/payment_status_in_sale/doc/RELEASE_NOTES.md
@@ -13,4 +13,9 @@
#### 15.07.2025
#### Version 18.0.1.0.2
##### ADD
-- Issue resolved in computing the amount due by considering only posted invoices.
\ No newline at end of file
+- Issue resolved in computing the amount due by considering only posted invoices.
+
+#### 20.09.2025
+#### Version 18.0.1.0.3
+##### ADD
+- Issue resolved while clicking view from payment info.
\ No newline at end of file
diff --git a/payment_status_in_sale/models/sale_order.py b/payment_status_in_sale/models/sale_order.py
index edb6b91f3d..d7a5252cad 100644
--- a/payment_status_in_sale/models/sale_order.py
+++ b/payment_status_in_sale/models/sale_order.py
@@ -105,6 +105,7 @@ def _compute_amount_due(self):
total_invoiced -= invoice.amount_total
total_paid -= (
invoice.amount_total - invoice.amount_residual)
+
rec.amount_due = total_invoiced - total_paid
def action_open_business_doc(self):
@@ -117,7 +118,10 @@ def action_open_business_doc(self):
name = _("Journal Entry")
move = self.env['account.move'].browse(self.id)
res_model = 'account.payment'
- res_id = move.payment_id.id
+ payments = move.payment_ids
+ res_id = payments.id
+
+ # res_id = move.payment_id.id
return {
'name': name,
'type': 'ir.actions.act_window',
diff --git a/pivot_conditional_formatting/README.rst b/pivot_conditional_formatting/README.rst
new file mode 100644
index 0000000000..086ac86928
--- /dev/null
+++ b/pivot_conditional_formatting/README.rst
@@ -0,0 +1,50 @@
+.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg
+ :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+Conditional Formatting in Pivot View
+====================================
+This module helps you to setup conditional formatting in the pivot view of a
+model.
+
+Configuration
+=============
+* No additional configurations needed
+
+Company
+-------
+* `Cybrosys Techno Solutions `__
+
+License
+-------
+General Public License, Version 3 (AGPL v3).
+(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
+
+Credits
+-------
+* Developers: (V18) Manasa T P
+ (V17) Shikhil Raj
+
+* Contact: odoo@cybrosys.com
+
+Contacts
+--------
+* Mail Contact : odoo@cybrosys.com
+* Website : https://cybrosys.com
+
+Bug Tracker
+-----------
+Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
+
+Maintainer
+==========
+.. image:: https://cybrosys.com/images/logo.png
+ :target: https://cybrosys.com
+
+This module is maintained by Cybrosys Technologies.
+
+For support and more information, please visit `Our Website `__
+
+Further information
+===================
+HTML Description: ``__
diff --git a/pivot_conditional_formatting/__init__.py b/pivot_conditional_formatting/__init__.py
new file mode 100644
index 0000000000..ab18f66488
--- /dev/null
+++ b/pivot_conditional_formatting/__init__.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program
+# If not, see .
+#
+#############################################################################
+from . import models
diff --git a/pivot_conditional_formatting/__manifest__.py b/pivot_conditional_formatting/__manifest__.py
new file mode 100644
index 0000000000..d270ef5e1b
--- /dev/null
+++ b/pivot_conditional_formatting/__manifest__.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program
+# If not, see .
+#
+#############################################################################
+{
+ "name": "Conditional Formatting in Pivot View",
+ "version": "18.0.1.0.0",
+ "category": "Extra Tools",
+ "summary": "This Module allows to setup conditional formatting in "
+ "the pivot view of models",
+ "description": "The module is used for using conditional formatting option"
+ "in the pivot view of different models, you can setup"
+ " default formatting rules in the settings or add new rules"
+ " from the UI.",
+ "author": "Cybrosys Techno Solutions",
+ "company": "Cybrosys Techno Solutions",
+ "maintainer": "Cybrosys Techno Solutions",
+ "website": "https://www.cybrosys.com",
+ "depends": ["base", "web"],
+ "data": [
+ "security/pivot_conditional_formatting_groups.xml",
+ "security/pivot_conditional_settings_security.xml",
+ "security/ir.model.access.csv",
+ "views/pivot_conditional_settings_views.xml",
+ ],
+ "assets": {
+ "web.assets_backend": [
+ "pivot_conditional_formatting/static/src/xml/pivot_conditional_formatting.xml",
+ "pivot_conditional_formatting/static/src/css/pivot_conditional_formatting.css",
+ "pivot_conditional_formatting/static/src/js/pivot_conditional_formatting.js",
+ ],
+ },
+ "images": ["static/description/banner.jpg"],
+ "license": "AGPL-3",
+ "installable": True,
+ "auto_install": False,
+ "application": False,
+}
diff --git a/pivot_conditional_formatting/doc/RELEASE_NOTES.md b/pivot_conditional_formatting/doc/RELEASE_NOTES.md
new file mode 100644
index 0000000000..db5e18a55e
--- /dev/null
+++ b/pivot_conditional_formatting/doc/RELEASE_NOTES.md
@@ -0,0 +1,6 @@
+## Module
+
+#### 26.06.2025
+#### Version 18.0.1.0.0
+#### ADD
+- Initial Commit for Conditional Formatting in Pivot View
diff --git a/pivot_conditional_formatting/models/__init__.py b/pivot_conditional_formatting/models/__init__.py
new file mode 100644
index 0000000000..aab2fe2d2f
--- /dev/null
+++ b/pivot_conditional_formatting/models/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program
+# If not, see .
+#
+#############################################################################
+"""init file"""
+from . import conditional_rules
+from . import pivot_conditional_settings
diff --git a/pivot_conditional_formatting/models/conditional_rules.py b/pivot_conditional_formatting/models/conditional_rules.py
new file mode 100644
index 0000000000..10873308ad
--- /dev/null
+++ b/pivot_conditional_formatting/models/conditional_rules.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program
+# If not, see .
+#
+#############################################################################
+from odoo import fields, models
+
+
+class ConditionalRules(models.Model):
+ """Model Class for the different Pivot view table, conditional formatting
+ rules"""
+ _name = 'conditional.rules'
+ _description = 'Conditional formatting'
+ _rec_name = "rule"
+
+
+ rule = fields.Selection(string='Rule',
+ selection=[('greater_than', 'Greater Than'),
+ ('less_than', 'Less Than'),
+ ('is_empty', 'Is Empty'),
+ ('in_between', 'In Between')],
+ help="Different conditions for rules")
+ value = fields.Float( string='Value', help="Value for comparing the rule")
+ second_value = fields.Float(string='Second Value',
+ help="Second value for comparing the "
+ "'In Between' rule")
+ color = fields.Char(string='Color', required=True,
+ help="Background color for the cells")
+ text_color = fields.Char(string='Text Color', required=True,
+ help="Text color for the cells")
+ model_id = fields.Many2one('ir.model',
+ related='conditional_id.model_id',
+ string="Model", help="Model related to the rule")
+ view_id = fields.Many2one('ir.ui.view',
+ related='conditional_id.view_id', string="View",
+ help="View related to the rule")
+ conditional_id = fields.Many2one('pivot.conditional.settings',
+ string="Condition",
+ help="Pivot Condition setting related to "
+ "the rule")
+ company_id = fields.Many2one('res.company', string='Company',
+ default=lambda self: self.env.company,
+ help="Company ID related to the rule")
diff --git a/pivot_conditional_formatting/models/pivot_conditional_settings.py b/pivot_conditional_formatting/models/pivot_conditional_settings.py
new file mode 100644
index 0000000000..e83ea4e11a
--- /dev/null
+++ b/pivot_conditional_formatting/models/pivot_conditional_settings.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program
+# If not, see .
+#
+#############################################################################
+"""Models for setting conditional formatting rules in settings"""
+from odoo import api, fields, models
+
+
+class PivotConditionalSetting(models.Model):
+ """Model Class for choosing the model and view to set the default rules"""
+ _name = 'pivot.conditional.settings'
+ _description = 'Pivot conditional setting'
+ _rec_name = "model_id"
+
+ model_id = fields.Many2one('ir.model', string="Model",
+ help="The model to set the rules for")
+ view_id = fields.Many2one('ir.ui.view', string="View",
+ help="Pivot view of the model")
+ rules_ids = fields.One2many('conditional.rules',
+ 'conditional_id', string="Rules",
+ help="List View Showing details of different rules")
+ company_id = fields.Many2one('res.company', string='Company',
+ default=lambda self: self.env.company,
+ help="Company id related to the Pivot "
+ "Condition setting")
+ view_id_domain = fields.Binary(string="View Domain",
+ compute="_compute_view_id_domain")
+
+
+ @api.depends('model_id')
+ def _compute_view_id_domain(self):
+ """
+ This method is called when the 'model_id' field is changed. It
+ updates the domain of the 'view_id' field to filter records based
+ on the selected model and view type as 'pivot'.
+
+ :return: Dictionary containing the updated domain for the 'view_id'
+ field.
+ :rtype: dict
+ """
+ for rec in self:
+ rec.view_id_domain = [('model', '=', rec.model_id.model),
+ ('type', '=', 'pivot')]
diff --git a/pivot_conditional_formatting/security/ir.model.access.csv b/pivot_conditional_formatting/security/ir.model.access.csv
new file mode 100644
index 0000000000..0c142e6851
--- /dev/null
+++ b/pivot_conditional_formatting/security/ir.model.access.csv
@@ -0,0 +1,5 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_conditional_rules_user,access.conditional.rules,model_conditional_rules,pivot_conditional_formatting.pivot_conditional_settings_group_user,1,1,1,1
+access_conditional_rules_reader,access.conditional.rules,model_conditional_rules,base.group_user,1,0,0,0
+access_pivot_conditional_settings_user,access.pivot.conditional.settings,model_pivot_conditional_settings,pivot_conditional_formatting.pivot_conditional_settings_group_user,1,1,1,1
+access_pivot_conditional_settings_reader,access.pivot.conditional.settings,model_pivot_conditional_settings,base.group_user,1,0,0,0
diff --git a/pivot_conditional_formatting/security/pivot_conditional_formatting_groups.xml b/pivot_conditional_formatting/security/pivot_conditional_formatting_groups.xml
new file mode 100644
index 0000000000..4884723ea0
--- /dev/null
+++ b/pivot_conditional_formatting/security/pivot_conditional_formatting_groups.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ Allow to Set Pivot Conditional Rules
+
+
+
diff --git a/pivot_conditional_formatting/security/pivot_conditional_settings_security.xml b/pivot_conditional_formatting/security/pivot_conditional_settings_security.xml
new file mode 100644
index 0000000000..bfeba79939
--- /dev/null
+++ b/pivot_conditional_formatting/security/pivot_conditional_settings_security.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ Pivot Conditional Formatting Rule
+
+ ['|',('company_id','=',False),('company_id', 'in', company_ids)]
+
+
+
+ Pivot Conditional Formatting Rule2
+
+ ['|',('company_id','=',False),('company_id', 'in', company_ids)]
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/cybro-icon.png b/pivot_conditional_formatting/static/description/assets/cybro-icon.png
new file mode 100755
index 0000000000..06e73e11de
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/cybro-icon.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/cybro-odoo.png b/pivot_conditional_formatting/static/description/assets/cybro-odoo.png
new file mode 100755
index 0000000000..ed02e07a48
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/cybro-odoo.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/h2.png b/pivot_conditional_formatting/static/description/assets/h2.png
new file mode 100755
index 0000000000..0bfc4707d8
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/h2.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/arrows-repeat.svg b/pivot_conditional_formatting/static/description/assets/icons/arrows-repeat.svg
new file mode 100755
index 0000000000..1d7efabc52
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/arrows-repeat.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/banner-1.png b/pivot_conditional_formatting/static/description/assets/icons/banner-1.png
new file mode 100755
index 0000000000..c180db1729
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/banner-1.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/banner-2.svg b/pivot_conditional_formatting/static/description/assets/icons/banner-2.svg
new file mode 100755
index 0000000000..e606d97d98
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/banner-2.svg
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/banner-bg.png b/pivot_conditional_formatting/static/description/assets/icons/banner-bg.png
new file mode 100755
index 0000000000..a8238d3c09
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/banner-bg.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/banner-bg.svg b/pivot_conditional_formatting/static/description/assets/icons/banner-bg.svg
new file mode 100755
index 0000000000..b1378103e2
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/banner-bg.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/banner-call.svg b/pivot_conditional_formatting/static/description/assets/icons/banner-call.svg
new file mode 100755
index 0000000000..96c687e81f
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/banner-call.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/banner-mail.svg b/pivot_conditional_formatting/static/description/assets/icons/banner-mail.svg
new file mode 100755
index 0000000000..cbf0d158d2
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/banner-mail.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/banner-pattern.svg b/pivot_conditional_formatting/static/description/assets/icons/banner-pattern.svg
new file mode 100755
index 0000000000..9c1c7e101c
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/banner-pattern.svg
@@ -0,0 +1,343 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/banner-promo.svg b/pivot_conditional_formatting/static/description/assets/icons/banner-promo.svg
new file mode 100755
index 0000000000..d52791b11e
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/banner-promo.svg
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/brand-pair.svg b/pivot_conditional_formatting/static/description/assets/icons/brand-pair.svg
new file mode 100755
index 0000000000..d8db7fc1e7
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/brand-pair.svg
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/check.png b/pivot_conditional_formatting/static/description/assets/icons/check.png
new file mode 100755
index 0000000000..c8e85f51d6
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/check.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/chevron.png b/pivot_conditional_formatting/static/description/assets/icons/chevron.png
new file mode 100755
index 0000000000..2089293d6a
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/chevron.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/close-icon.svg b/pivot_conditional_formatting/static/description/assets/icons/close-icon.svg
new file mode 100755
index 0000000000..df8cce37a5
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/close-icon.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/cogs.png b/pivot_conditional_formatting/static/description/assets/icons/cogs.png
new file mode 100755
index 0000000000..95d0bad62c
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/cogs.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/collabarate-icon.svg b/pivot_conditional_formatting/static/description/assets/icons/collabarate-icon.svg
new file mode 100755
index 0000000000..dd4e105183
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/collabarate-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/consultation.png b/pivot_conditional_formatting/static/description/assets/icons/consultation.png
new file mode 100755
index 0000000000..8319d4baa0
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/consultation.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/cybro-logo.png b/pivot_conditional_formatting/static/description/assets/icons/cybro-logo.png
new file mode 100755
index 0000000000..ff4b782205
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/cybro-logo.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/down.svg b/pivot_conditional_formatting/static/description/assets/icons/down.svg
new file mode 100755
index 0000000000..f21c36271b
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/down.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/pivot_conditional_formatting/static/description/assets/icons/ecom-black.png b/pivot_conditional_formatting/static/description/assets/icons/ecom-black.png
new file mode 100755
index 0000000000..a9385ff13f
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/ecom-black.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/education-black.png b/pivot_conditional_formatting/static/description/assets/icons/education-black.png
new file mode 100755
index 0000000000..3eb09b27b4
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/education-black.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/faq.png b/pivot_conditional_formatting/static/description/assets/icons/faq.png
new file mode 100755
index 0000000000..4250b5b817
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/faq.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/feature-icon.svg b/pivot_conditional_formatting/static/description/assets/icons/feature-icon.svg
new file mode 100755
index 0000000000..fa0ea6850a
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/feature-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/feature.png b/pivot_conditional_formatting/static/description/assets/icons/feature.png
new file mode 100755
index 0000000000..ac7a785c09
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/feature.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/gear.svg b/pivot_conditional_formatting/static/description/assets/icons/gear.svg
new file mode 100755
index 0000000000..0cc66b6ea7
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/gear.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/hero.gif b/pivot_conditional_formatting/static/description/assets/icons/hero.gif
new file mode 100644
index 0000000000..798ed71427
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/hero.gif differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/hire-odoo.svg b/pivot_conditional_formatting/static/description/assets/icons/hire-odoo.svg
new file mode 100755
index 0000000000..e1ac089b04
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/hire-odoo.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/hotel-black.png b/pivot_conditional_formatting/static/description/assets/icons/hotel-black.png
new file mode 100755
index 0000000000..130f613be0
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/hotel-black.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/license.png b/pivot_conditional_formatting/static/description/assets/icons/license.png
new file mode 100755
index 0000000000..a5869797ec
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/license.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/life-ring-icon.svg b/pivot_conditional_formatting/static/description/assets/icons/life-ring-icon.svg
new file mode 100755
index 0000000000..3ae6e1d896
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/life-ring-icon.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/lifebuoy.png b/pivot_conditional_formatting/static/description/assets/icons/lifebuoy.png
new file mode 100755
index 0000000000..658d56cccf
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/lifebuoy.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/mail.svg b/pivot_conditional_formatting/static/description/assets/icons/mail.svg
new file mode 100755
index 0000000000..1eedde695b
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/mail.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/manufacturing-black.png b/pivot_conditional_formatting/static/description/assets/icons/manufacturing-black.png
new file mode 100755
index 0000000000..697eb0e9f2
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/manufacturing-black.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/notes.png b/pivot_conditional_formatting/static/description/assets/icons/notes.png
new file mode 100755
index 0000000000..ee5e954047
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/notes.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/notification icon.svg b/pivot_conditional_formatting/static/description/assets/icons/notification icon.svg
new file mode 100755
index 0000000000..0531899736
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/notification icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/odoo-consultancy.svg b/pivot_conditional_formatting/static/description/assets/icons/odoo-consultancy.svg
new file mode 100755
index 0000000000..e05f65bde4
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/odoo-consultancy.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/odoo-licencing.svg b/pivot_conditional_formatting/static/description/assets/icons/odoo-licencing.svg
new file mode 100755
index 0000000000..2606c88b04
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/odoo-licencing.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/odoo-logo.png b/pivot_conditional_formatting/static/description/assets/icons/odoo-logo.png
new file mode 100755
index 0000000000..0e4d0eb5a4
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/odoo-logo.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/patter.svg b/pivot_conditional_formatting/static/description/assets/icons/patter.svg
new file mode 100755
index 0000000000..25c9c0a8f1
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/patter.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/pattern1.png b/pivot_conditional_formatting/static/description/assets/icons/pattern1.png
new file mode 100755
index 0000000000..09ab0fb2d9
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/pattern1.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/pos-black.png b/pivot_conditional_formatting/static/description/assets/icons/pos-black.png
new file mode 100755
index 0000000000..97c0f90c10
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/pos-black.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/puzzle-piece-icon.svg b/pivot_conditional_formatting/static/description/assets/icons/puzzle-piece-icon.svg
new file mode 100755
index 0000000000..3e9ad93738
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/puzzle-piece-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/puzzle.png b/pivot_conditional_formatting/static/description/assets/icons/puzzle.png
new file mode 100755
index 0000000000..65cf854e7e
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/puzzle.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/replace-icon.svg b/pivot_conditional_formatting/static/description/assets/icons/replace-icon.svg
new file mode 100755
index 0000000000..d0e3a7af1a
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/replace-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/restaurant-black.png b/pivot_conditional_formatting/static/description/assets/icons/restaurant-black.png
new file mode 100755
index 0000000000..4a35eb939c
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/restaurant-black.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/screenshot-main.png b/pivot_conditional_formatting/static/description/assets/icons/screenshot-main.png
new file mode 100755
index 0000000000..575f8e676b
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/screenshot-main.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/screenshot.png b/pivot_conditional_formatting/static/description/assets/icons/screenshot.png
new file mode 100755
index 0000000000..cef272529d
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/screenshot.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/service-black.png b/pivot_conditional_formatting/static/description/assets/icons/service-black.png
new file mode 100755
index 0000000000..301ab51cb1
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/service-black.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/skype-fill.svg b/pivot_conditional_formatting/static/description/assets/icons/skype-fill.svg
new file mode 100755
index 0000000000..c174236393
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/skype-fill.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/skype.png b/pivot_conditional_formatting/static/description/assets/icons/skype.png
new file mode 100755
index 0000000000..51b409fb3f
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/skype.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/skype.svg b/pivot_conditional_formatting/static/description/assets/icons/skype.svg
new file mode 100755
index 0000000000..df3dad39b5
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/skype.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/star-1.svg b/pivot_conditional_formatting/static/description/assets/icons/star-1.svg
new file mode 100755
index 0000000000..7e55ab162e
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/star-1.svg
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/star-2.svg b/pivot_conditional_formatting/static/description/assets/icons/star-2.svg
new file mode 100755
index 0000000000..5ae9f507a1
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/star-2.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/support.png b/pivot_conditional_formatting/static/description/assets/icons/support.png
new file mode 100755
index 0000000000..4f18b8b820
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/support.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/test-1 - Copy.png b/pivot_conditional_formatting/static/description/assets/icons/test-1 - Copy.png
new file mode 100755
index 0000000000..f6a9026637
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/test-1 - Copy.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/test-1.png b/pivot_conditional_formatting/static/description/assets/icons/test-1.png
new file mode 100755
index 0000000000..0908add2b0
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/test-1.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/test-2.png b/pivot_conditional_formatting/static/description/assets/icons/test-2.png
new file mode 100755
index 0000000000..4671fe91e9
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/test-2.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/trading-black.png b/pivot_conditional_formatting/static/description/assets/icons/trading-black.png
new file mode 100755
index 0000000000..9398ba2f1a
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/trading-black.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/training.png b/pivot_conditional_formatting/static/description/assets/icons/training.png
new file mode 100755
index 0000000000..884ca024d7
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/training.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/translate.svg b/pivot_conditional_formatting/static/description/assets/icons/translate.svg
new file mode 100755
index 0000000000..af9c8a1aa8
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/translate.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/update.png b/pivot_conditional_formatting/static/description/assets/icons/update.png
new file mode 100755
index 0000000000..ecbc5a01a2
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/update.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/user.png b/pivot_conditional_formatting/static/description/assets/icons/user.png
new file mode 100755
index 0000000000..6ffb23d9f0
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/user.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/video.png b/pivot_conditional_formatting/static/description/assets/icons/video.png
new file mode 100755
index 0000000000..576705b172
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/video.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/whatsapp.png b/pivot_conditional_formatting/static/description/assets/icons/whatsapp.png
new file mode 100755
index 0000000000..d513a5356b
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/whatsapp.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/icons/wrench-icon.svg b/pivot_conditional_formatting/static/description/assets/icons/wrench-icon.svg
new file mode 100755
index 0000000000..174b5a465e
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/assets/icons/wrench-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/description/assets/icons/wrench.png b/pivot_conditional_formatting/static/description/assets/icons/wrench.png
new file mode 100755
index 0000000000..6c04dea0f4
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/icons/wrench.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/modules/1.jpg b/pivot_conditional_formatting/static/description/assets/modules/1.jpg
new file mode 100644
index 0000000000..3cb15fe019
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/modules/1.jpg differ
diff --git a/pivot_conditional_formatting/static/description/assets/modules/2.jpg b/pivot_conditional_formatting/static/description/assets/modules/2.jpg
new file mode 100644
index 0000000000..662cadcc3a
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/modules/2.jpg differ
diff --git a/pivot_conditional_formatting/static/description/assets/modules/3.jpg b/pivot_conditional_formatting/static/description/assets/modules/3.jpg
new file mode 100644
index 0000000000..717a004430
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/modules/3.jpg differ
diff --git a/pivot_conditional_formatting/static/description/assets/modules/4.png b/pivot_conditional_formatting/static/description/assets/modules/4.png
new file mode 100644
index 0000000000..00ebf54ad7
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/modules/4.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/modules/5.jpg b/pivot_conditional_formatting/static/description/assets/modules/5.jpg
new file mode 100644
index 0000000000..7c67e2eec0
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/modules/5.jpg differ
diff --git a/pivot_conditional_formatting/static/description/assets/modules/6.gif b/pivot_conditional_formatting/static/description/assets/modules/6.gif
new file mode 100644
index 0000000000..a35ece8dff
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/modules/6.gif differ
diff --git a/pivot_conditional_formatting/static/description/assets/screenshots/1.png b/pivot_conditional_formatting/static/description/assets/screenshots/1.png
new file mode 100644
index 0000000000..9c653cfd70
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/screenshots/1.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/screenshots/2.png b/pivot_conditional_formatting/static/description/assets/screenshots/2.png
new file mode 100644
index 0000000000..45718c275f
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/screenshots/2.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/screenshots/3.png b/pivot_conditional_formatting/static/description/assets/screenshots/3.png
new file mode 100644
index 0000000000..2eff095ca9
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/screenshots/3.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/screenshots/4.png b/pivot_conditional_formatting/static/description/assets/screenshots/4.png
new file mode 100644
index 0000000000..d8ac1a6932
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/screenshots/4.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/screenshots/5.png b/pivot_conditional_formatting/static/description/assets/screenshots/5.png
new file mode 100644
index 0000000000..6c4ce79af5
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/screenshots/5.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/screenshots/6.png b/pivot_conditional_formatting/static/description/assets/screenshots/6.png
new file mode 100644
index 0000000000..1a3194e8cc
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/screenshots/6.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/screenshots/7.png b/pivot_conditional_formatting/static/description/assets/screenshots/7.png
new file mode 100644
index 0000000000..5f854709e1
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/screenshots/7.png differ
diff --git a/pivot_conditional_formatting/static/description/assets/y18.jpg b/pivot_conditional_formatting/static/description/assets/y18.jpg
new file mode 100755
index 0000000000..eea1714f25
Binary files /dev/null and b/pivot_conditional_formatting/static/description/assets/y18.jpg differ
diff --git a/pivot_conditional_formatting/static/description/banner.jpg b/pivot_conditional_formatting/static/description/banner.jpg
new file mode 100644
index 0000000000..86483df60f
Binary files /dev/null and b/pivot_conditional_formatting/static/description/banner.jpg differ
diff --git a/pivot_conditional_formatting/static/description/icon.png b/pivot_conditional_formatting/static/description/icon.png
new file mode 100644
index 0000000000..349ea993ce
Binary files /dev/null and b/pivot_conditional_formatting/static/description/icon.png differ
diff --git a/pivot_conditional_formatting/static/description/index.html b/pivot_conditional_formatting/static/description/index.html
new file mode 100644
index 0000000000..af909464bd
--- /dev/null
+++ b/pivot_conditional_formatting/static/description/index.html
@@ -0,0 +1,1090 @@
+
+
+
+
+
+ Conditional Formatting in Pivot View
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Community
+
+
+ Enterprise
+
+
+ Odoo.sh
+
+
+
+
+
+
+
+
+
+ Conditional Formatting in pivot view according
+ to different rules.
+
+
Conditional Formatting in Pivot View
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Key
+ Highlights
+
+
+
+
+
+
+
+ Conditional Formatting in Pivot Views
+
+
+ Allows you to visually highlight and
+ differentiate cells based on values using
+ color rules in pivot tables.
+
+
+
+
+
+
+
+
+ Predefined Default Rules
+
+
+ Can predefine formatting rules specific to a
+ model and view.
+
+
+
+
+
+
+
+
+
+
Conditional Formatting in Pivot View
+
+ Are you ready to make your business more
+ organized?
+ Improve now!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Enable option for setting conditional rules on pivot views
+
+
+
+
+
+
+ Go to Settings -> Users &
+ Companies -> Users -> under
+ "Technical" section in your
+ user, enable "Allow to Set Pivot
+ Conditional Rules option".
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pivot Settings Menu
+
+
+
+
+
+
+ Open the Pivot Setting menu.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Setup rules for the pivot view.
+
+
+
+
+
+ When you go to a pivot view with
+ Default Rules, You will see the
+ changes in the pivot according
+ to the Default Rules.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Open Pivot View
+
+
+
+
+
+
+ Open the pivot view of
+ quotation. Drag along the pivot
+ cells to select the cells you
+ want to apply the rules on.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Conditional Formatting Button
+
+
+
+
+
+ Click on the Conditional
+ Formatting button for setting
+ the Rule, then select the
+ Condition and enter the Value to
+ base the condition on, choose
+ the Background color and Text
+ color and click the Save button
+ to apply the rule.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set Conditions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Conditions Applied to Pivot Table
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Compatible with Both Community & Enterprise Editions
+
+
+
+
+
+
+
+
+
+
+
+
+ Predefined Default Rules
+
+
+
+
+
+
+
+
+
+
+
+ Makes large pivot tables more readable and actionable.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ It allows you to
+ apply conditional
+ formatting rules to
+ cells in pivot
+ views, helping you
+ visually analyze
+ data by highlighting
+ values based on
+ conditions.
+
+
+
+
+
+
+
+ Yes. You can
+ predefine default
+ formatting rules for
+ specific models, so
+ users get
+ consistent visual
+ feedback across the
+ system.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latest Release 18.0.1.0.0
+
+
+ 26th June, 2025
+
+
+
+
+
+
+
+
+
+
+
+
+ Related Products
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pivot_conditional_formatting/static/src/css/pivot_conditional_formatting.css b/pivot_conditional_formatting/static/src/css/pivot_conditional_formatting.css
new file mode 100644
index 0000000000..59a5f03607
--- /dev/null
+++ b/pivot_conditional_formatting/static/src/css/pivot_conditional_formatting.css
@@ -0,0 +1,107 @@
+.selected_cell{
+ border: 4px solid red !important;
+ opacity: 0.75;
+}
+.prevent-select {
+ -webkit-user-select: none; /* Safari */
+ -ms-user-select: none; /* IE 10 and IE 11 */
+ user-select: none; /* Standard syntax */
+}
+.conditional_container{
+ display: flex;
+ width: 30vw;
+ min-height:20vh;
+ background: #e3eaf0;
+ position: relative;
+ padding: 5px;
+ margin-top: 1vh;
+ box-shadow: 3px 3px 5px 0px rgb(0 0 0 / 32%);
+ margin-left: 1vw;
+ margin-bottom: 1vh;
+ border-radius: 5px;
+}
+
+.sub_container1{
+ height: 100%;
+ background: #e3eaf0;
+ display: flex;
+ justify-content: space-evenly;
+ align-items: center;
+ flex-direction: column;
+ width: 100%;
+}
+
+.condition_select{
+ width: 30%;
+ background: #71639e;
+ color: black;
+ font-weight: 500;
+ margin: 3%;
+ text-align: center;
+ padding: 1%;
+ border-radius: 4px;
+}
+
+.condition_val{
+ width: 61%;
+ height: 29px;
+ margin: 2%;
+ border: 2px solid #71639e;
+ border-radius: 4px;
+}
+
+.condition_button{
+ border: none;
+ background: #8b93d2;
+ margin: 4% 0;
+ padding: 1% 6%;
+ border-radius: 3px;
+ font-size: 16px;
+}
+.condition_button:hover{
+ background: #5b64ad;
+}
+
+.rule_container{
+ background: #e3eaf0;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-direction: column;
+ height: 100px;
+ border: 1px solid black;
+}
+.input_container{
+ display:flex;
+}
+
+.sub_input_container{
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ color: black;
+}
+.sub_color_container{
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ padding: 0px 30px;
+ color: black;
+}
+.color_container{
+ display: flex;
+}
+
+.color-input{
+ width: 34px;
+ height: 32px;
+ border: none;
+ outline: none;
+}
+
+.validation-error{
+ display: none;
+ color: red;
+}
diff --git a/pivot_conditional_formatting/static/src/js/pivot_conditional_formatting.js b/pivot_conditional_formatting/static/src/js/pivot_conditional_formatting.js
new file mode 100644
index 0000000000..487c20d53a
--- /dev/null
+++ b/pivot_conditional_formatting/static/src/js/pivot_conditional_formatting.js
@@ -0,0 +1,248 @@
+/** @odoo-module **/
+import { PivotRenderer } from "@web/views/pivot/pivot_renderer";
+import { useService } from "@web/core/utils/hooks";
+import { patch } from '@web/core/utils/patch';
+import { useExternalListener, useEffect } from "@odoo/owl";
+
+patch(PivotRenderer.prototype,{
+ setup() {
+ super.setup();
+ this.orm = useService("orm");
+ this.isMouseDown = false;
+ this.startRowIndex = null;
+ this.startCellIndex = null;
+ useExternalListener(document, 'mouseup', this.mouse_up_function)
+ useEffect(() => {
+ this.set_default_rules()
+ })
+ },
+
+ async set_default_rules(){
+// function for default rules to be applied on the pivot table
+ var self = this
+ var viewId = this.env.config.viewId
+ var model = this.env.searchModel.resModel
+ await this.orm.call("conditional.rules","search_read", [],{
+ domain: [['model_id','=',model],['view_id','=',viewId]],
+ }).then(function(res){
+ self.conditional_rules = res
+ })
+ var cells = this.__owl__.bdom.parentEl.querySelectorAll('td')
+ cells.forEach(function(data){
+ data.style.backgroundColor = "#f8f9fa"
+ data.style.color = "black"
+ })
+ this.__owl__.bdom.parentEl.querySelectorAll('.o_pivot.table-responsive table .selected_cell').forEach(cell => {
+ cell.classList.remove('selected_cell')});
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('.conditional_button').forEach(el => {
+ el.style.display = "none"});
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('.conditional_container').forEach(el => {
+ el.style.display = "none"});
+
+ for (let i = 0, len = this.conditional_rules.length; i < len; i++){
+ var condition = this.conditional_rules[i].rule
+ var condition_val = this.conditional_rules[i].value
+ var second_condition_val = this.conditional_rules[i].second_value
+ var color_val = this.conditional_rules[i].color
+ var text_color_val = this.conditional_rules[i].text_color
+
+ for (let j = 0, len = cells.length; j < len; j++){
+ var cell_val = cells[j].innerText
+ if(cell_val){
+ cell_val = cell_val.replace(',','')
+ }
+ if(condition == 'less_than'){
+ if(parseFloat(condition_val)>parseFloat(cell_val)){
+ cells[j].classList.remove("bg-100")
+ cells[j].style.backgroundColor = color_val
+ cells[j].style.color = text_color_val
+ }
+ }
+ if(condition == "greater_than"){
+ if(parseFloat(condition_val)< parseFloat(cell_val)){
+ cells[j].classList.remove("bg-100")
+ cells[j].style.backgroundColor = color_val
+ cells[j].style.color = text_color_val
+ }
+ }
+ if(condition == "is_empty"){
+ if(cells[j].innerText == ""){
+ cells[j].classList.remove("bg-100")
+ cells[j].style.backgroundColor = color_val
+ cells[j].style.color = text_color_val
+ }
+ }
+ if(condition == "in_between"){
+ if(parseFloat(cell_val)> parseFloat(condition_val) && parseFloat(cell_val)< parseFloat(second_condition_val)){
+ cells[j].classList.remove("bg-100")
+ cells[j].style.backgroundColor = color_val
+ cells[j].style.color = text_color_val
+ }
+ }
+ }
+ }
+ },
+ async conditional_format_tab(){
+// This function is called to display the conditional formatting
+// window/wizard in the UI.
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('.conditional_container').forEach(el => {
+ el.style.display = "block";
+ });
+ this.__owl__.bdom.parentEl.querySelectorAll("#condition_val")[0].value = ''
+ this.__owl__.bdom.parentEl.querySelectorAll("#secondcondition_val")[0].value = ''
+ if(this.__owl__.bdom.parentEl.querySelectorAll(
+ '.validation-error')[0].style.display == "inline"){
+ this.__owl__.bdom.parentEl.querySelectorAll(
+ '.validation-error')[0].style.display = "none";
+ }
+ },
+
+ conditional_formattoo(e){
+ // function for selecting table columns and adding and removing
+// classes
+ if (e.target.localName == 'td' || e.target.className == 'o_value'){
+ this.isMouseDown = true;
+ var cell;
+ if(e.target.className == 'o_value'){
+ cell = e.target.parentElement;
+ }else{
+ cell = e.target
+ }
+ this.__owl__.bdom.parentEl.querySelectorAll('.o_pivot.table-responsive table .selected_cell').forEach(cell => {
+ cell.classList.remove('selected_cell');
+ });
+ cell.className = 'selected_cell prevent-select'
+ this.startCellIndex = cell.cellIndex;
+ this.startRowIndex = cell.parentElement.cellIndex;
+ return false;
+ }
+ },
+
+
+ mouse_over_function(e){
+// function for selecting table columns
+ if (!this.isMouseDown) return;
+ if (e.target.localName == 'td' || e.target.className == 'o_value'){
+ var cell = e.target.parentElement;
+ if(e.target.className == 'o_value'){
+ cell = e.target.parentElement;
+ }else{
+ cell = e.target
+ }
+ cell.classList.add("selected_cell")
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('.conditional_button').forEach(el => {
+ el.style.display = "block"});
+ }
+ },
+
+ mouse_up_function(){
+// function for changing variable value to stop table cell selection
+ this.isMouseDown = false;
+ },
+
+ display_field(){
+// function for hiding and showing input fields inside popup window
+ var condition = this.__owl__.bdom.parentEl.querySelectorAll(
+ '.condition_select')[0].value
+ if(this.__owl__.bdom.parentEl.querySelectorAll(
+ '.validation-error')[0].style.display == "inline"){
+ this.__owl__.bdom.parentEl.querySelectorAll(
+ '.validation-error')[0].style.display = "none";
+ }
+ this.__owl__.bdom.parentEl.querySelectorAll(
+ '#condition_val')[0].value = ''
+ this.__owl__.bdom.parentEl.querySelectorAll(
+ '#secondcondition_val')[0].value = ''
+ if(condition == 'in between'){
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#secondcondition_val').forEach(el => {
+ el.style.display = "block"});
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#value_label').forEach(el => {
+ el.style.display = "block"});
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#sub_input_container2').forEach(el => {
+ el.style.display = "flex"});
+ }else{
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#secondcondition_val').forEach(el => {
+ el.style.display = "none"});
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#value_label').forEach(el => {
+ el.style.display = "none"});
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#sub_input_container2').forEach(el => {
+ el.style.display = "none"});
+ }
+ if(condition === 'null'){
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#condition_val').forEach(el => {
+ el.style.display = "none"});
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#value_label1').forEach(el => {
+ el.style.display = "none"});
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#sub_input_container1').forEach(el => {
+ el.style.display = "none"});
+ }else{
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#condition_val').forEach(el => {
+ el.style.display = "block"});
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#value_label1').forEach(el => {
+ el.style.display = "block"});
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('#sub_input_container1').forEach(el => {
+ el.style.display = "flex"});
+ }
+ },
+ set_rule(){
+// function for applying rules through popup window
+ var condition = this.__owl__.bdom.parentEl.querySelectorAll(
+ '.condition_select')[0].value
+ var color_val = this.__owl__.bdom.parentEl.querySelectorAll(
+ '.colorpicker')[0].value
+ var text_color_val = this.__owl__.bdom.parentEl.querySelectorAll(
+ '.text_color')[0].value
+ var cells = this.__owl__.bdom.parentEl.querySelectorAll(
+ '.selected_cell')
+ var condition_val = this.__owl__.bdom.parentEl.querySelectorAll(
+ '#condition_val')[0].value
+ var second_condition_val = this.__owl__.bdom.parentEl.querySelectorAll(
+ '#secondcondition_val')[0].value
+ this.__owl__.bdom.parentEl.querySelectorAll(
+ '#condition_val')[0].value = ''
+ this.__owl__.bdom.parentEl.querySelectorAll(
+ '#secondcondition_val')[0].value = ''
+ if(condition == 'in between'){
+ if(condition_val > second_condition_val){
+ this.__owl__.bdom.parentEl.parentElement.querySelectorAll('.validation-error').forEach(el => {
+ el.style.display = "inline"});
+ return
+ }
+ }
+ for (let i = 0, len = cells.length; i < len; i++){
+ var cell_val = cells[i].innerText
+ if(cell_val){
+ cell_val = cell_val.replace(',','')
+ }
+ if(condition == 'less than'){
+ if(parseFloat(condition_val)>parseFloat(cell_val)){
+ cells[i].classList.remove("bg-100")
+ cells[i].style.backgroundColor = color_val
+ cells[i].style.color = text_color_val
+ }
+ }
+ if(condition == 'greater than'){
+ if(parseFloat(condition_val)< parseFloat(cell_val)){
+ cells[i].classList.remove("bg-100")
+ cells[i].style.backgroundColor = color_val
+ cells[i].style.color = text_color_val
+ }
+ }
+ if(condition == "null"){
+ if(cells[i].innerText == ""){
+ cells[i].classList.remove("bg-100")
+ cells[i].classList.remove("bg-100")
+ cells[i].style.backgroundColor = color_val
+ cells[i].style.color = text_color_val
+ }
+ }
+ if(condition == 'in between'){
+ if(parseFloat(cell_val)> parseFloat(condition_val) && parseFloat(cell_val)< parseFloat(second_condition_val)){
+ cells[i].classList.remove("bg-100")
+ cells[i].style.backgroundColor = color_val
+ cells[i].style.color = text_color_val
+ }
+ }
+ }
+ },
+ });
\ No newline at end of file
diff --git a/pivot_conditional_formatting/static/src/xml/pivot_conditional_formatting.xml b/pivot_conditional_formatting/static/src/xml/pivot_conditional_formatting.xml
new file mode 100644
index 0000000000..5a3dc31f13
--- /dev/null
+++ b/pivot_conditional_formatting/static/src/xml/pivot_conditional_formatting.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+ Greater Than
+ In Between
+ Is Empty
+ Less Than
+
+
+
+ First input should be greater than Second
+
+
+
save
+
+
+
+
+ conditional_formattoo
+ mouse_over_function
+
+
+
+
+
+
+
+ Conditional Formatting
+
+
+
+
diff --git a/pivot_conditional_formatting/views/pivot_conditional_settings_views.xml b/pivot_conditional_formatting/views/pivot_conditional_settings_views.xml
new file mode 100644
index 0000000000..969f3deca0
--- /dev/null
+++ b/pivot_conditional_formatting/views/pivot_conditional_settings_views.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+ conditional.rules.view.form
+ conditional.rules
+
+
+
+
+
+
+
+ conditional.rule.view.list
+ conditional.rules
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pivot.conditional.settings.view.list
+ pivot.conditional.settings
+
+
+
+
+
+
+
+
+
+
+ pivot.conditional.settings.view.form
+ pivot.conditional.settings
+
+
+
+
+
+
+
+ Pivot Conditional Settings Action
+ pivot.conditional.settings
+ list,form
+
+
+
+
+
+
diff --git a/pos_delete_orderline/__manifest__.py b/pos_delete_orderline/__manifest__.py
index be55d6aa04..3ed9285b66 100644
--- a/pos_delete_orderline/__manifest__.py
+++ b/pos_delete_orderline/__manifest__.py
@@ -21,7 +21,7 @@
################################################################################
{
'name': "Remove Order Line In POS",
- 'version': '18.0.1.0.0',
+ 'version': '18.0.1.0.1',
'category': 'Point of Sale',
'summary': """Remove Individual Orderlines In Point Of Sale. """,
'description': """Remove each lines from selected order by simply
@@ -37,6 +37,7 @@
'pos_delete_orderline/static/src/app/control_buttons/control_buttons.xml',
'pos_delete_orderline/static/src/app/screens/product_screen/product_screen.js',
'pos_delete_orderline/static/src/app/screens/product_screen/product_screen.xml',
+ 'pos_delete_orderline/static/src/scss/style.scss',
],
},
'images': ['static/description/banner.jpg'],
diff --git a/pos_delete_orderline/doc/RELEASE_NOTES.md b/pos_delete_orderline/doc/RELEASE_NOTES.md
index f9c870645c..b47864f0cb 100644
--- a/pos_delete_orderline/doc/RELEASE_NOTES.md
+++ b/pos_delete_orderline/doc/RELEASE_NOTES.md
@@ -4,3 +4,8 @@
#### Version 18.0.1.0.0
#### ADD
- Initial commit for Remove Order Line In POS
+
+#### 24.09.2025
+#### Version 18.0.1.0.1
+#### FIX
+- Fixed style issue for the Order Line In POS receipt screen
diff --git a/pos_delete_orderline/static/src/app/screens/product_screen/product_screen.xml b/pos_delete_orderline/static/src/app/screens/product_screen/product_screen.xml
index ecf9136080..2e4d946b2d 100644
--- a/pos_delete_orderline/static/src/app/screens/product_screen/product_screen.xml
+++ b/pos_delete_orderline/static/src/app/screens/product_screen/product_screen.xml
@@ -12,3 +12,4 @@
+
diff --git a/pos_delete_orderline/static/src/scss/style.scss b/pos_delete_orderline/static/src/scss/style.scss
new file mode 100644
index 0000000000..53c80dd9eb
--- /dev/null
+++ b/pos_delete_orderline/static/src/scss/style.scss
@@ -0,0 +1,3 @@
+.pos-receipt #clear_icon {
+ display: none !important;
+}
diff --git a/pos_paid_order_delete/README.rst b/pos_paid_order_delete/README.rst
new file mode 100644
index 0000000000..6828653a81
--- /dev/null
+++ b/pos_paid_order_delete/README.rst
@@ -0,0 +1,49 @@
+.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg
+ :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+POS Paid Order Delete
+=====================
+ This app allow the specified user to delete the pos orders in paid state.
+
+Installation
+============
+- www.odoo.com/documentation/17.0/setup/install.html
+- Install our custom addon
+
+License
+-------
+General Public License, Version 3 (AGPL v3).
+(https://www.odoo.com/documentation/user/17.0/legal/licenses/licenses.html)
+
+Company
+-------
+* `Cybrosys Techno Solutions `__
+
+Credits
+-------
+* Developers: Cybrosys Techno Solutions odoo@cybrosys.com
+ Version 17: Nisiya K @cybrosys
+ Version 18: Bhagyadev KP @cybrosys
+
+Contacts
+--------
+* Mail Contact : odoo@cybrosys.com
+* Website : https://cybrosys.com
+
+Bug Tracker
+-----------
+Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
+
+Maintainer
+==========
+.. image:: https://cybrosys.com/images/logo.png
+ :target: https://cybrosys.com
+
+This module is maintained by Cybrosys Technologies.
+
+For support and more information, please visit `Our Website `__
+
+Further information
+===================
+HTML Description: ``__
diff --git a/pos_paid_order_delete/__init__.py b/pos_paid_order_delete/__init__.py
new file mode 100644
index 0000000000..8aa4ff19b8
--- /dev/null
+++ b/pos_paid_order_delete/__init__.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+################################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2025-TODAY Cybrosys Technologies().
+# Author: Bhagyadev KP (odoo@cybrosys.com)
+#
+# This program is free software: you can modify
+# it under the terms of the GNU Affero General Public License (AGPL) as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+################################################################################
+from .import models
+from .import wizard
+from odoo import api, SUPERUSER_ID
+
+
+def _uninstall_hook(cr, registry):
+ env = api.Environment(cr, SUPERUSER_ID, {})
+ env['ir.config_parameter'].sudo().set_param(
+ 'pos_paid_order_delete.is_delete',
+ False)
diff --git a/pos_paid_order_delete/__manifest__.py b/pos_paid_order_delete/__manifest__.py
new file mode 100644
index 0000000000..f2b09ea4db
--- /dev/null
+++ b/pos_paid_order_delete/__manifest__.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+################################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2025-TODAY Cybrosys Technologies().
+# Author: Bhagyadev KP (odoo@cybrosys.com)
+#
+# This program is free software: you can modify
+# it under the terms of the GNU Affero General Public License (AGPL) as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+################################################################################
+{
+ 'name': 'POS Paid Order Delete',
+ 'version': '18.0.1.0.0',
+ 'category': 'POS',
+ 'summary': "Can Delete POS Orders in Paid State With or Without Code",
+ 'description': "This app allow the specified user to delete the pos orders"
+ " with or without code in paid state by unlinking the "
+ "payments of corresponding order.",
+ 'author': 'Cybrosys Techno Solutions',
+ 'company': 'Cybrosys Techno Solutions',
+ 'maintainer': 'Cybrosys Techno Solutions',
+ 'website': 'https://www.cybrosys.com',
+ 'depends': ['point_of_sale'],
+ 'data':
+ [
+ 'security/ir.model.access.csv',
+ 'security/pos_order_delete_groups.xml',
+ 'data/pos_order_data.xml',
+ 'views/res_config_settings_views.xml',
+ 'wizard/delete_paid_pos_order_views.xml'
+ ],
+ 'images': ['static/description/banner.jpg'],
+ 'license': 'AGPL-3',
+ 'installable': True,
+ 'auto_install': False,
+ 'application': False,
+ 'uninstall_hook': '_uninstall_hook',
+}
+
diff --git a/pos_paid_order_delete/data/pos_order_data.xml b/pos_paid_order_delete/data/pos_order_data.xml
new file mode 100644
index 0000000000..a183226fcc
--- /dev/null
+++ b/pos_paid_order_delete/data/pos_order_data.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ Delete Paid Order
+ ir.actions.act_window
+ delete.paid.pos.order
+ form
+ new
+ action
+ list,form
+
+
+
+
diff --git a/pos_paid_order_delete/doc/RELEASE_NOTES.md b/pos_paid_order_delete/doc/RELEASE_NOTES.md
new file mode 100644
index 0000000000..9a941e336c
--- /dev/null
+++ b/pos_paid_order_delete/doc/RELEASE_NOTES.md
@@ -0,0 +1,6 @@
+## Module
+
+#### 02.05.2025
+#### Version 18.0.1.0.0
+#### ADD
+- Initial Commit for POS Paid Order Delete.
diff --git a/pos_paid_order_delete/models/__init__.py b/pos_paid_order_delete/models/__init__.py
new file mode 100644
index 0000000000..5ae1723e9c
--- /dev/null
+++ b/pos_paid_order_delete/models/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+################################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2025-TODAY Cybrosys Technologies().
+# Author: Bhagyadev KP (odoo@cybrosys.com)
+#
+# This program is free software: you can modify
+# it under the terms of the GNU Affero General Public License (AGPL) as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+################################################################################
+from .import res_config_settings
+from .import pos_order
diff --git a/pos_paid_order_delete/models/pos_order.py b/pos_paid_order_delete/models/pos_order.py
new file mode 100644
index 0000000000..d615f566cb
--- /dev/null
+++ b/pos_paid_order_delete/models/pos_order.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions()
+
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+
+from odoo import models, _
+from odoo.addons.point_of_sale.models.pos_order import PosOrder
+from odoo.exceptions import UserError
+from odoo.tools import float_compare, formatLang
+
+
+class PosOrderInherit(models.Model):
+ '''Inherit the pos.order model to override the write method'''
+ _inherit = 'pos.order'
+ _description = "POS Order Inherit"
+
+ def write(self, vals):
+ '''Monkey patching the write method of pos.order to add extra condition for UserError'''
+ is_delete = (self.env['ir.config_parameter'].sudo().get_param('pos_paid_order_delete.is_delete'))
+ for order in self:
+ if vals.get('state') and vals['state'] == 'paid' and order.name == '/':
+ vals['name'] = self._compute_order_name()
+ if vals.get('mobile'):
+ vals['mobile'] = order._phone_format(number=vals.get('mobile'),
+ country=order.partner_id.country_id or self.env.company.country_id)
+ if vals.get('has_deleted_line') is not None and self.has_deleted_line:
+ del vals['has_deleted_line']
+ allowed_vals = ['paid', 'done', 'invoiced']
+ if vals.get('state') and vals['state'] not in allowed_vals and order.state in allowed_vals and not is_delete:
+ raise UserError(_('This order has already been paid. You cannot set it back to draft or edit it.'))
+
+ list_line = self._create_pm_change_log(vals)
+
+ res = super(PosOrder, self).write(vals)
+ for order in self:
+ if vals.get('payment_ids'):
+ order.with_context(backend_recomputation=True)._compute_prices()
+ totally_paid_or_more = float_compare(order.amount_paid, self._get_rounded_amount(order.amount_total), precision_rounding=order.currency_id.rounding)
+ if totally_paid_or_more < 0 and order.state in ['paid', 'done', 'invoiced']:
+ raise UserError(_('The paid amount is different from the total amount of the order.'))
+ elif totally_paid_or_more > 0 and order.state == 'paid':
+ list_line.append(_("Warning, the paid amount is higher than the total amount. (Difference: %s)", formatLang(self.env, order.amount_paid - order.amount_total, currency_obj=order.currency_id)))
+ if order.nb_print > 0 and vals.get('payment_ids'):
+ raise UserError(_('You cannot change the payment of a printed order.'))
+
+ if len(list_line) > 0:
+ body = _("Payment changes:")
+ body += self._markup_list_message(list_line)
+ for order in self:
+ if vals.get('payment_ids'):
+ order.message_post(body=body)
+ return res
+
+ PosOrder.write = write
diff --git a/pos_paid_order_delete/models/res_config_settings.py b/pos_paid_order_delete/models/res_config_settings.py
new file mode 100644
index 0000000000..a272923f89
--- /dev/null
+++ b/pos_paid_order_delete/models/res_config_settings.py
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+################################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2025-TODAY Cybrosys Technologies().
+# Author: Bhagyadev KP (odoo@cybrosys.com)
+#
+# This program is free software: you can modify
+# it under the terms of the GNU Affero General Public License (AGPL) as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+################################################################################
+from odoo import api, models, fields
+
+
+class ResConfigSettings(models.TransientModel):
+ """Inheriting ResConfigSettings to add new fields"""
+ _inherit = 'res.config.settings'
+
+ is_delete = fields.Boolean(string='Delete Paid Order',
+ help='Based on this selection it shows the '
+ 'fields for deleting the paid pos order '
+ 'with code and without code')
+ delete_paid_order = fields.Selection(
+ [('order_with_code', 'Delete POS order with code'),
+ ('order_without_code', 'Delete POS order without code')],
+ default='order_without_code',
+ string='Delete Paid Order',
+ store=True,
+ help='Delete the paid POS order with code or without providing the '
+ 'code')
+ code = fields.Char(string='Code', help="Enter code to confirming "
+ "record deletion")
+
+ @api.model
+ def get_values(self):
+ """Get values from the fields"""
+ res = super(ResConfigSettings, self).get_values()
+ params = self.env['ir.config_parameter'].sudo().get_param
+ is_delete = params('pos_paid_order_delete.is_delete')
+ delete_paid_order = params('pos_paid_order_delete.delete_paid_order')
+ code = params('pos_paid_order_delete.code')
+ res.update(
+ is_delete=is_delete,
+ delete_paid_order=delete_paid_order,
+ code=code,
+ )
+ return res
+
+ def set_values(self):
+ """Set values in the fields"""
+ super(ResConfigSettings, self).set_values()
+ self.env['ir.config_parameter'].sudo().set_param(
+ 'pos_paid_order_delete.is_delete',
+ self.is_delete)
+ self.env['ir.config_parameter'].sudo().set_param(
+ 'pos_paid_order_delete.delete_paid_order',
+ self.delete_paid_order)
+ self.env['ir.config_parameter'].sudo().set_param(
+ 'pos_paid_order_delete.code',
+ self.code)
+ if self.is_delete:
+ self.env['ir.actions.act_window'].search([
+ ('name', '=', 'Delete Paid Order')]).update(
+ {'binding_model_id': self.env['ir.model.data']._xmlid_to_res_id
+ ('point_of_sale.model_pos_order')
+ })
+ else:
+ (self.env['ir.actions.act_window'].search([
+ ('name', '=', 'Delete Paid Order')]).update
+ ({'binding_model_id': ''}))
+
+ @api.onchange('is_delete')
+ def _onchange_is_delete(self):
+ """This function is used to st the value of code is None when we are
+ disabling the pos order delete field"""
+ if not self.is_delete:
+ self.code = None
diff --git a/pos_paid_order_delete/security/ir.model.access.csv b/pos_paid_order_delete/security/ir.model.access.csv
new file mode 100644
index 0000000000..aff4ce1f2f
--- /dev/null
+++ b/pos_paid_order_delete/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+"access_delete_paid_pos_order","delete.paid.pos.order","model_delete_paid_pos_order","base.group_user",1,1,1,1
diff --git a/pos_paid_order_delete/security/pos_order_delete_groups.xml b/pos_paid_order_delete/security/pos_order_delete_groups.xml
new file mode 100644
index 0000000000..6e51ee40ee
--- /dev/null
+++ b/pos_paid_order_delete/security/pos_order_delete_groups.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ POS Order Delete
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/cybro-icon.png b/pos_paid_order_delete/static/description/assets/cybro-icon.png
new file mode 100644
index 0000000000..06e73e11de
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/cybro-icon.png differ
diff --git a/pos_paid_order_delete/static/description/assets/cybro-odoo.png b/pos_paid_order_delete/static/description/assets/cybro-odoo.png
new file mode 100644
index 0000000000..ed02e07a48
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/cybro-odoo.png differ
diff --git a/pos_paid_order_delete/static/description/assets/h2.png b/pos_paid_order_delete/static/description/assets/h2.png
new file mode 100644
index 0000000000..0bfc4707d8
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/h2.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/arrows-repeat.svg b/pos_paid_order_delete/static/description/assets/icons/arrows-repeat.svg
new file mode 100644
index 0000000000..1d7efabc52
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/arrows-repeat.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/banner-1.png b/pos_paid_order_delete/static/description/assets/icons/banner-1.png
new file mode 100644
index 0000000000..c180db1729
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/banner-1.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/banner-2.svg b/pos_paid_order_delete/static/description/assets/icons/banner-2.svg
new file mode 100644
index 0000000000..e606d97d98
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/banner-2.svg
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/banner-bg.png b/pos_paid_order_delete/static/description/assets/icons/banner-bg.png
new file mode 100644
index 0000000000..a8238d3c09
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/banner-bg.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/banner-bg.svg b/pos_paid_order_delete/static/description/assets/icons/banner-bg.svg
new file mode 100644
index 0000000000..b1378103e2
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/banner-bg.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/banner-call.svg b/pos_paid_order_delete/static/description/assets/icons/banner-call.svg
new file mode 100644
index 0000000000..96c687e81f
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/banner-call.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/banner-mail.svg b/pos_paid_order_delete/static/description/assets/icons/banner-mail.svg
new file mode 100644
index 0000000000..cbf0d158d2
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/banner-mail.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/banner-pattern.svg b/pos_paid_order_delete/static/description/assets/icons/banner-pattern.svg
new file mode 100644
index 0000000000..9c1c7e101c
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/banner-pattern.svg
@@ -0,0 +1,343 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/banner-promo.svg b/pos_paid_order_delete/static/description/assets/icons/banner-promo.svg
new file mode 100644
index 0000000000..d52791b11e
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/banner-promo.svg
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/brand-pair.svg b/pos_paid_order_delete/static/description/assets/icons/brand-pair.svg
new file mode 100644
index 0000000000..d8db7fc1e7
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/brand-pair.svg
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/check.png b/pos_paid_order_delete/static/description/assets/icons/check.png
new file mode 100644
index 0000000000..c8e85f51d6
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/check.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/chevron.png b/pos_paid_order_delete/static/description/assets/icons/chevron.png
new file mode 100644
index 0000000000..2089293d6a
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/chevron.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/close-icon.svg b/pos_paid_order_delete/static/description/assets/icons/close-icon.svg
new file mode 100644
index 0000000000..df8cce37a5
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/close-icon.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/cogs.png b/pos_paid_order_delete/static/description/assets/icons/cogs.png
new file mode 100644
index 0000000000..95d0bad62c
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/cogs.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/collabarate-icon.svg b/pos_paid_order_delete/static/description/assets/icons/collabarate-icon.svg
new file mode 100644
index 0000000000..dd4e105183
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/collabarate-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/consultation.png b/pos_paid_order_delete/static/description/assets/icons/consultation.png
new file mode 100644
index 0000000000..8319d4baa0
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/consultation.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/cybro-logo.png b/pos_paid_order_delete/static/description/assets/icons/cybro-logo.png
new file mode 100644
index 0000000000..ff4b782205
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/cybro-logo.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/down.svg b/pos_paid_order_delete/static/description/assets/icons/down.svg
new file mode 100644
index 0000000000..f21c36271b
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/down.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/pos_paid_order_delete/static/description/assets/icons/ecom-black.png b/pos_paid_order_delete/static/description/assets/icons/ecom-black.png
new file mode 100644
index 0000000000..a9385ff13f
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/ecom-black.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/education-black.png b/pos_paid_order_delete/static/description/assets/icons/education-black.png
new file mode 100644
index 0000000000..3eb09b27b4
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/education-black.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/faq.png b/pos_paid_order_delete/static/description/assets/icons/faq.png
new file mode 100644
index 0000000000..4250b5b817
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/faq.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/feature-icon.svg b/pos_paid_order_delete/static/description/assets/icons/feature-icon.svg
new file mode 100644
index 0000000000..fa0ea6850a
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/feature-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/feature.png b/pos_paid_order_delete/static/description/assets/icons/feature.png
new file mode 100644
index 0000000000..ac7a785c09
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/feature.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/gear.svg b/pos_paid_order_delete/static/description/assets/icons/gear.svg
new file mode 100644
index 0000000000..0cc66b6ea7
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/gear.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/hero.gif b/pos_paid_order_delete/static/description/assets/icons/hero.gif
new file mode 100644
index 0000000000..380654dfe7
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/hero.gif differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/hire-odoo.svg b/pos_paid_order_delete/static/description/assets/icons/hire-odoo.svg
new file mode 100644
index 0000000000..e1ac089b04
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/hire-odoo.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/hotel-black.png b/pos_paid_order_delete/static/description/assets/icons/hotel-black.png
new file mode 100644
index 0000000000..130f613be0
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/hotel-black.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/license.png b/pos_paid_order_delete/static/description/assets/icons/license.png
new file mode 100644
index 0000000000..a5869797ec
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/license.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/life-ring-icon.svg b/pos_paid_order_delete/static/description/assets/icons/life-ring-icon.svg
new file mode 100644
index 0000000000..3ae6e1d896
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/life-ring-icon.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/lifebuoy.png b/pos_paid_order_delete/static/description/assets/icons/lifebuoy.png
new file mode 100644
index 0000000000..658d56cccf
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/lifebuoy.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/mail.svg b/pos_paid_order_delete/static/description/assets/icons/mail.svg
new file mode 100644
index 0000000000..1eedde695b
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/mail.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/manufacturing-black.png b/pos_paid_order_delete/static/description/assets/icons/manufacturing-black.png
new file mode 100644
index 0000000000..697eb0e9f2
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/manufacturing-black.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/notes.png b/pos_paid_order_delete/static/description/assets/icons/notes.png
new file mode 100644
index 0000000000..ee5e954047
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/notes.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/notification icon.svg b/pos_paid_order_delete/static/description/assets/icons/notification icon.svg
new file mode 100644
index 0000000000..0531899736
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/notification icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/odoo-consultancy.svg b/pos_paid_order_delete/static/description/assets/icons/odoo-consultancy.svg
new file mode 100644
index 0000000000..e05f65bde4
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/odoo-consultancy.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/odoo-licencing.svg b/pos_paid_order_delete/static/description/assets/icons/odoo-licencing.svg
new file mode 100644
index 0000000000..2606c88b04
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/odoo-licencing.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/odoo-logo.png b/pos_paid_order_delete/static/description/assets/icons/odoo-logo.png
new file mode 100644
index 0000000000..0e4d0eb5a4
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/odoo-logo.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/patter.svg b/pos_paid_order_delete/static/description/assets/icons/patter.svg
new file mode 100644
index 0000000000..25c9c0a8f1
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/patter.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/pattern1.png b/pos_paid_order_delete/static/description/assets/icons/pattern1.png
new file mode 100644
index 0000000000..09ab0fb2d9
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/pattern1.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/pos-black.png b/pos_paid_order_delete/static/description/assets/icons/pos-black.png
new file mode 100644
index 0000000000..97c0f90c10
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/pos-black.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/puzzle-piece-icon.svg b/pos_paid_order_delete/static/description/assets/icons/puzzle-piece-icon.svg
new file mode 100644
index 0000000000..3e9ad93738
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/puzzle-piece-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/puzzle.png b/pos_paid_order_delete/static/description/assets/icons/puzzle.png
new file mode 100644
index 0000000000..65cf854e7e
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/puzzle.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/replace-icon.svg b/pos_paid_order_delete/static/description/assets/icons/replace-icon.svg
new file mode 100644
index 0000000000..d0e3a7af1a
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/replace-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/restaurant-black.png b/pos_paid_order_delete/static/description/assets/icons/restaurant-black.png
new file mode 100644
index 0000000000..4a35eb939c
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/restaurant-black.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/screenshot-main.png b/pos_paid_order_delete/static/description/assets/icons/screenshot-main.png
new file mode 100644
index 0000000000..575f8e676b
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/screenshot-main.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/screenshot.png b/pos_paid_order_delete/static/description/assets/icons/screenshot.png
new file mode 100644
index 0000000000..cef272529d
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/screenshot.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/service-black.png b/pos_paid_order_delete/static/description/assets/icons/service-black.png
new file mode 100644
index 0000000000..301ab51cb1
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/service-black.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/skype-fill.svg b/pos_paid_order_delete/static/description/assets/icons/skype-fill.svg
new file mode 100644
index 0000000000..c174236393
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/skype-fill.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/skype.png b/pos_paid_order_delete/static/description/assets/icons/skype.png
new file mode 100644
index 0000000000..51b409fb3f
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/skype.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/skype.svg b/pos_paid_order_delete/static/description/assets/icons/skype.svg
new file mode 100644
index 0000000000..df3dad39b5
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/skype.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/star-1.svg b/pos_paid_order_delete/static/description/assets/icons/star-1.svg
new file mode 100644
index 0000000000..7e55ab162e
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/star-1.svg
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/star-2.svg b/pos_paid_order_delete/static/description/assets/icons/star-2.svg
new file mode 100644
index 0000000000..5ae9f507a1
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/star-2.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/support.png b/pos_paid_order_delete/static/description/assets/icons/support.png
new file mode 100644
index 0000000000..4f18b8b820
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/support.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/test-1 - Copy.png b/pos_paid_order_delete/static/description/assets/icons/test-1 - Copy.png
new file mode 100644
index 0000000000..f6a9026637
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/test-1 - Copy.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/test-1.png b/pos_paid_order_delete/static/description/assets/icons/test-1.png
new file mode 100644
index 0000000000..0908add2b0
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/test-1.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/test-2.png b/pos_paid_order_delete/static/description/assets/icons/test-2.png
new file mode 100644
index 0000000000..4671fe91e9
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/test-2.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/trading-black.png b/pos_paid_order_delete/static/description/assets/icons/trading-black.png
new file mode 100644
index 0000000000..9398ba2f1a
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/trading-black.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/training.png b/pos_paid_order_delete/static/description/assets/icons/training.png
new file mode 100644
index 0000000000..884ca024d7
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/training.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/translate.svg b/pos_paid_order_delete/static/description/assets/icons/translate.svg
new file mode 100644
index 0000000000..af9c8a1aa8
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/translate.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/update.png b/pos_paid_order_delete/static/description/assets/icons/update.png
new file mode 100644
index 0000000000..ecbc5a01a2
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/update.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/user.png b/pos_paid_order_delete/static/description/assets/icons/user.png
new file mode 100644
index 0000000000..6ffb23d9f0
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/user.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/video.png b/pos_paid_order_delete/static/description/assets/icons/video.png
new file mode 100644
index 0000000000..576705b172
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/video.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/whatsapp.png b/pos_paid_order_delete/static/description/assets/icons/whatsapp.png
new file mode 100644
index 0000000000..d513a5356b
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/whatsapp.png differ
diff --git a/pos_paid_order_delete/static/description/assets/icons/wrench-icon.svg b/pos_paid_order_delete/static/description/assets/icons/wrench-icon.svg
new file mode 100644
index 0000000000..174b5a465e
--- /dev/null
+++ b/pos_paid_order_delete/static/description/assets/icons/wrench-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/static/description/assets/icons/wrench.png b/pos_paid_order_delete/static/description/assets/icons/wrench.png
new file mode 100644
index 0000000000..6c04dea0f4
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/icons/wrench.png differ
diff --git a/pos_paid_order_delete/static/description/assets/modules/1.gif b/pos_paid_order_delete/static/description/assets/modules/1.gif
new file mode 100644
index 0000000000..ae3a880a29
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/modules/1.gif differ
diff --git a/pos_paid_order_delete/static/description/assets/modules/2.gif b/pos_paid_order_delete/static/description/assets/modules/2.gif
new file mode 100644
index 0000000000..d19e2b3522
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/modules/2.gif differ
diff --git a/pos_paid_order_delete/static/description/assets/modules/3.png b/pos_paid_order_delete/static/description/assets/modules/3.png
new file mode 100644
index 0000000000..8513873ea3
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/modules/3.png differ
diff --git a/pos_paid_order_delete/static/description/assets/modules/4.png b/pos_paid_order_delete/static/description/assets/modules/4.png
new file mode 100644
index 0000000000..3bedf7981f
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/modules/4.png differ
diff --git a/pos_paid_order_delete/static/description/assets/modules/5.png b/pos_paid_order_delete/static/description/assets/modules/5.png
new file mode 100644
index 0000000000..0e311ca872
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/modules/5.png differ
diff --git a/pos_paid_order_delete/static/description/assets/modules/6.jpg b/pos_paid_order_delete/static/description/assets/modules/6.jpg
new file mode 100644
index 0000000000..67c7f70629
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/modules/6.jpg differ
diff --git a/pos_paid_order_delete/static/description/assets/screenshots/1.png b/pos_paid_order_delete/static/description/assets/screenshots/1.png
new file mode 100644
index 0000000000..f75cb8d114
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/screenshots/1.png differ
diff --git a/pos_paid_order_delete/static/description/assets/screenshots/2.png b/pos_paid_order_delete/static/description/assets/screenshots/2.png
new file mode 100644
index 0000000000..075896de79
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/screenshots/2.png differ
diff --git a/pos_paid_order_delete/static/description/assets/screenshots/3.png b/pos_paid_order_delete/static/description/assets/screenshots/3.png
new file mode 100644
index 0000000000..cb560942ee
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/screenshots/3.png differ
diff --git a/pos_paid_order_delete/static/description/assets/screenshots/4.png b/pos_paid_order_delete/static/description/assets/screenshots/4.png
new file mode 100644
index 0000000000..a73c51d0cb
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/screenshots/4.png differ
diff --git a/pos_paid_order_delete/static/description/assets/screenshots/5.png b/pos_paid_order_delete/static/description/assets/screenshots/5.png
new file mode 100644
index 0000000000..08153c39a4
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/screenshots/5.png differ
diff --git a/pos_paid_order_delete/static/description/assets/screenshots/6.png b/pos_paid_order_delete/static/description/assets/screenshots/6.png
new file mode 100644
index 0000000000..610da4b8fb
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/screenshots/6.png differ
diff --git a/pos_paid_order_delete/static/description/assets/screenshots/hero.gif b/pos_paid_order_delete/static/description/assets/screenshots/hero.gif
new file mode 100644
index 0000000000..cbdeb1fad9
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/screenshots/hero.gif differ
diff --git a/pos_paid_order_delete/static/description/assets/y18.jpg b/pos_paid_order_delete/static/description/assets/y18.jpg
new file mode 100644
index 0000000000..eea1714f25
Binary files /dev/null and b/pos_paid_order_delete/static/description/assets/y18.jpg differ
diff --git a/pos_paid_order_delete/static/description/banner.jpg b/pos_paid_order_delete/static/description/banner.jpg
new file mode 100644
index 0000000000..40618f0da0
Binary files /dev/null and b/pos_paid_order_delete/static/description/banner.jpg differ
diff --git a/pos_paid_order_delete/static/description/icon.png b/pos_paid_order_delete/static/description/icon.png
new file mode 100644
index 0000000000..b164f63fd6
Binary files /dev/null and b/pos_paid_order_delete/static/description/icon.png differ
diff --git a/pos_paid_order_delete/static/description/index.html b/pos_paid_order_delete/static/description/index.html
new file mode 100644
index 0000000000..ab79ba5ddb
--- /dev/null
+++ b/pos_paid_order_delete/static/description/index.html
@@ -0,0 +1,980 @@
+
+
+
+
+
+ POS Paid Order Delete
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Community
+
+
+ Enterprise
+
+
+ Odoo.sh
+
+
+
+
+
+
+
+
+
+ This app helps you to delete the POS orders in
+ paid state.
+
+
POS Paid Order Delete
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Key
+ Highlights
+
+
+
+
+
+
+
+ Allow the user to delete the single or
+ multiple POS order in paid state.
+
+
+
+
+
+
+
+
+
+ Delete the pos order in paid state with
+ using the code or without using the code.
+
+
+
+
+
+
+
+
+
+ Available in Odoo 18.0 Community and
+ Enterprise.
+
+
+
+
+
+
+
+
+
+
+
POS Paid Order Delete
+
+ Are you ready to make your business more
+ organized?
+ Improve now!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Go to Settings --> Users & Companies --> Users --> Enable POS Order Delete. To give permission to the user to delete the paid POS orders.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Go to Point of Sale --> Configuration --> Settings --> Enable the boolean field Delete Paid Order.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Choose with or without code, Enter a code if your going with code.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Go to Point of Sale --> Orders --> Orders --> Choose Order/Orders to delete --> Select the action 'Delete Paid Order'.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Enter The Code and Click on 'Delete Paid Order'.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Enter The Code and Click on 'Delete Paid Order'.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Shows a Confirmation Wizard if Your Going Without Code.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Allow the user to delete the single or multiple POS order in paid state.
+
+
+
+
+
+
+
+
+
+
+
Delete the pos order in paid state with using the code or without using the code.
+
+
+
+
+
+
+
+
+
+
Available in Odoo 18.0 Community and Enterprise.
+
+
+
+
+
+
+
+
+
+
+
+ Latest Release 18.0.1.0.0
+
+
+ 2nd May, 2025
+
+
+
+
+
+
+
+
+
+
+
+
Related Modules
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/views/res_config_settings_views.xml b/pos_paid_order_delete/views/res_config_settings_views.xml
new file mode 100644
index 0000000000..71ec313e93
--- /dev/null
+++ b/pos_paid_order_delete/views/res_config_settings_views.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+ res.config.settings.view.form.inherit.purchase.serial.number
+ res.config.settings
+
+
+
+ Delete Paid Order
+
+
+
+
+
+
+
+
Delete Post/Paid Order
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pos_paid_order_delete/wizard/__init__.py b/pos_paid_order_delete/wizard/__init__.py
new file mode 100644
index 0000000000..85f81af69a
--- /dev/null
+++ b/pos_paid_order_delete/wizard/__init__.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+################################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2024-TODAY Cybrosys Technologies().
+# Author: Bhagyadev KP (odoo@cybrosys.com)
+#
+# This program is free software: you can modify
+# it under the terms of the GNU Affero General Public License (AGPL) as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+################################################################################
+from .import delete_paid_pos_order
diff --git a/pos_paid_order_delete/wizard/delete_paid_pos_order.py b/pos_paid_order_delete/wizard/delete_paid_pos_order.py
new file mode 100644
index 0000000000..daadc10b39
--- /dev/null
+++ b/pos_paid_order_delete/wizard/delete_paid_pos_order.py
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+################################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+# Copyright (C) 2024-TODAY Cybrosys Technologies().
+# Author: Bhagyadev KP (odoo@cybrosys.com)
+#
+# This program is free software: you can modify
+# it under the terms of the GNU Affero General Public License (AGPL) as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+################################################################################
+from odoo import api, models, fields, _
+from odoo.exceptions import UserError
+
+
+class DeletePaidPosOrder(models.TransientModel):
+ '''Wizard to delete the paid pos orders'''
+ _name = "delete.paid.pos.order"
+ _description = "Delete Paid POS Order"
+
+ pos_order_delete = fields.Boolean(string='Delete Paid Order', default=True,
+ help="Enable to delete POS orders")
+ code = fields.Char(string='Code', help="Setup code to enter "
+ "while deleting the POS order")
+
+ @api.model
+ def default_get(self, fields):
+ """The function used to update the default values"""
+ is_delete = self.env['ir.config_parameter'].sudo().get_param(
+ 'pos_paid_order_delete.is_delete')
+ result = super(DeletePaidPosOrder, self).default_get(fields)
+ if is_delete:
+ delete_paid_order = self.env[
+ 'ir.config_parameter'].sudo().get_param(
+ 'pos_paid_order_delete.delete_paid_order')
+ result['pos_order_delete'] = delete_paid_order != 'order_with_code'
+ return result
+
+ def delete_pos_paid_order(self):
+ """This function is used to delete the pos paid orders and the
+ corresponding payments"""
+ is_delete = (self.env['ir.config_parameter'].sudo().
+ get_param('pos_paid_order_delete.is_delete'))
+ if is_delete:
+ delete_paid_order = (self.env['ir.config_parameter'].sudo().
+ get_param('pos_paid_order_delete.'
+ 'delete_paid_order'
+ ))
+ pos_orders = self.env['pos.order'].browse(self.env.context.get
+ ('active_ids'))
+ code = self.env['ir.config_parameter'].sudo().get_param(
+ 'pos_paid_order_delete.code')
+ if delete_paid_order == 'order_with_code':
+ if code == self.code:
+ for order in pos_orders:
+ for payment in order.payment_ids:
+ payment.unlink()
+ order.write({'state': 'draft'})
+ order.action_pos_order_cancel()
+ order.unlink()
+ else:
+ raise UserError("The code is wrong.Plase enter the "
+ "correct code")
+ else:
+ for order in pos_orders:
+ for payment in order.payment_ids:
+ payment.unlink()
+ order.write({'state': 'draft'})
+ order.action_pos_order_cancel()
+ order.unlink()
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': _('Delete Pos Orders'),
+ 'res_model': 'pos.order',
+ 'view_mode': 'list',
+ 'view_id': self.env.ref('point_of_sale.view_pos_order_tree').id,
+ 'target': 'main',
+ }
diff --git a/pos_paid_order_delete/wizard/delete_paid_pos_order_views.xml b/pos_paid_order_delete/wizard/delete_paid_pos_order_views.xml
new file mode 100644
index 0000000000..fac5f27295
--- /dev/null
+++ b/pos_paid_order_delete/wizard/delete_paid_pos_order_views.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ delete.paid.pos.order.view.form
+ delete.paid.pos.order
+
+
+
+
+
diff --git a/rest_api_odoo/__manifest__.py b/rest_api_odoo/__manifest__.py
index 6b4811e0fb..d12ab7a61f 100644
--- a/rest_api_odoo/__manifest__.py
+++ b/rest_api_odoo/__manifest__.py
@@ -23,19 +23,23 @@
"name": "Odoo rest API",
"version": "18.0.1.0.1",
"category": "Tools",
- "summary": """This app helps to interact with odoo, backend with help of
+ "summary": """This app helps to interact with odoo, backend with help of
rest api requests""",
- "description": """The odoo Rest API module allow us to connect to database
+ "description": """The odoo Rest API module allow us to connect to database
with the help of GET , POST , PUT and DELETE requests""",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': "https://www.cybrosys.com",
"depends": ['base', 'web'],
+ "external_dependencies": {
+ "python": ["PyJWT"],
+ },
"data": [
'security/ir.model.access.csv',
'views/res_users_views.xml',
- 'views/connection_api_views.xml'
+ 'views/connection_api_views.xml',
+ 'views/api_dashboard_views.xml',
],
'images': ['static/description/banner.jpg'],
'license': 'LGPL-3',
diff --git a/rest_api_odoo/controllers/__init__.py b/rest_api_odoo/controllers/__init__.py
index 12d071cc42..f838eaa16c 100644
--- a/rest_api_odoo/controllers/__init__.py
+++ b/rest_api_odoo/controllers/__init__.py
@@ -20,3 +20,5 @@
#
#############################################################################
from . import rest_api_odoo
+from . import swagger_controller
+from . import jwt_auth
diff --git a/rest_api_odoo/controllers/jwt_auth.py b/rest_api_odoo/controllers/jwt_auth.py
new file mode 100644
index 0000000000..5afa1856f4
--- /dev/null
+++ b/rest_api_odoo/controllers/jwt_auth.py
@@ -0,0 +1,182 @@
+# -*- coding: utf-8 -*-
+try:
+ import jwt
+except ImportError:
+ raise ImportError("PyJWT is required for REST API authentication. Install with: pip install PyJWT")
+
+import base64
+import secrets
+import logging
+from datetime import datetime, timedelta
+from odoo import fields
+from odoo.http import request
+
+_logger = logging.getLogger(__name__)
+
+
+class JWTAuthMixin:
+ """Mixin para autenticación JWT reutilizable"""
+
+ def _get_jwt_secret(self):
+ """Obtiene la clave secreta para JWT desde configuración del sistema"""
+ secret = request.env['ir.config_parameter'].sudo().get_param('rest_api.jwt_secret')
+ if not secret:
+ # Generar y guardar una nueva clave secreta
+ try:
+ secret = base64.b64encode(secrets.token_bytes(32)).decode('utf-8')
+ except (ImportError, AttributeError):
+ # Fallback si secrets no está disponible
+ import uuid
+ import hashlib
+ secret = hashlib.sha256(str(uuid.uuid4()).encode()).hexdigest()
+
+ request.env['ir.config_parameter'].sudo().set_param('rest_api.jwt_secret', secret)
+ _logger.info("Generated new JWT secret key")
+
+ return secret
+
+ def _generate_jwt_token(self, user_id, expires_in_hours=24):
+ """
+ Genera un JWT token para el usuario
+ Args:
+ user_id: ID del usuario
+ expires_in_hours: Horas hasta expiración (default: 24h)
+ Returns:
+ str: JWT token o None si hay error
+ """
+ try:
+ now = datetime.utcnow()
+ payload = {
+ 'user_id': user_id,
+ 'iat': now, # Issued at
+ 'exp': now + timedelta(hours=expires_in_hours), # Expiration
+ 'iss': 'odoo-rest-api', # Issuer
+ 'aud': 'odoo-client', # Audience
+ 'jti': f"{user_id}_{int(now.timestamp())}" # JWT ID
+ }
+
+ secret = self._get_jwt_secret()
+ token = jwt.encode(payload, secret, algorithm='HS256')
+
+ _logger.info(f"Generated JWT token for user {user_id}, expires in {expires_in_hours}h")
+ return token
+
+ except Exception as e:
+ _logger.error(f"Error generating JWT token: {str(e)}")
+ return None
+
+ def _validate_jwt_token(self, token):
+ """
+ Valida un JWT token
+ Args:
+ token: Token JWT (puede incluir 'Bearer ' al inicio)
+ Returns:
+ tuple: (success: bool, user_id: int or None, error_message: str or None)
+ """
+ if not token:
+ return False, None, "Token no proporcionado"
+
+ # Limpiar token (remover 'Bearer ' si está presente)
+ if token.startswith('Bearer '):
+ token = token[7:]
+ elif token.startswith('bearer '):
+ token = token[7:]
+
+ try:
+ secret = self._get_jwt_secret()
+
+ # Decodificar y validar token
+ payload = jwt.decode(
+ token,
+ secret,
+ algorithms=['HS256'],
+ audience='odoo-client',
+ issuer='odoo-rest-api'
+ )
+
+ user_id = payload.get('user_id')
+ if not user_id:
+ return False, None, "Token inválido: user_id no encontrado"
+
+ # Verificar que el usuario existe y está activo
+ user = request.env['res.users'].sudo().browse(user_id)
+ if not user.exists():
+ return False, None, "Usuario no encontrado"
+
+ if not user.active:
+ return False, None, "Usuario inactivo"
+
+ # Configurar contexto de sesión - Método correcto para Odoo 18.0
+ request.session.uid = user_id
+ request.env = request.env(user=user)
+
+ # Log successful authentication
+ _logger.debug(f"JWT authentication successful for user {user_id} ({user.login})")
+
+ return True, user_id, None
+
+ except jwt.ExpiredSignatureError:
+ _logger.warning("JWT token expired")
+ return False, None, "Token expirado"
+ except jwt.InvalidTokenError as e:
+ _logger.warning(f"Invalid JWT token: {str(e)}")
+ return False, None, f"Token inválido: {str(e)}"
+ except jwt.InvalidAudienceError:
+ _logger.warning("JWT token has invalid audience")
+ return False, None, "Token inválido: audiencia incorrecta"
+ except jwt.InvalidIssuerError:
+ _logger.warning("JWT token has invalid issuer")
+ return False, None, "Token inválido: emisor incorrecto"
+ except Exception as e:
+ _logger.error(f"Error validating JWT token: {str(e)}")
+ return False, None, "Error interno validando token"
+
+ def _decode_jwt_payload(self, token):
+ """
+ Decodifica un JWT token sin validar (útil para debugging)
+ Args:
+ token: Token JWT
+ Returns:
+ dict: Payload del token o None si hay error
+ """
+ try:
+ if token.startswith('Bearer '):
+ token = token[7:]
+
+ # Decodificar sin verificar (solo para obtener payload)
+ payload = jwt.decode(token, options={"verify_signature": False})
+ return payload
+ except Exception as e:
+ _logger.error(f"Error decoding JWT payload: {str(e)}")
+ return None
+
+ def _get_token_info(self, token):
+ """
+ Obtiene información de un JWT token
+ Args:
+ token: Token JWT
+ Returns:
+ dict: Información del token
+ """
+ payload = self._decode_jwt_payload(token)
+ if not payload:
+ return None
+
+ try:
+ exp_timestamp = payload.get('exp')
+ iat_timestamp = payload.get('iat')
+
+ info = {
+ 'user_id': payload.get('user_id'),
+ 'issued_at': datetime.fromtimestamp(iat_timestamp) if iat_timestamp else None,
+ 'expires_at': datetime.fromtimestamp(exp_timestamp) if exp_timestamp else None,
+ 'issuer': payload.get('iss'),
+ 'audience': payload.get('aud'),
+ 'jwt_id': payload.get('jti'),
+ 'is_expired': datetime.utcnow() > datetime.fromtimestamp(exp_timestamp) if exp_timestamp else True
+ }
+
+ return info
+ except Exception as e:
+ _logger.error(f"Error getting token info: {str(e)}")
+ return None
diff --git a/rest_api_odoo/controllers/rest_api_odoo.py b/rest_api_odoo/controllers/rest_api_odoo.py
index 040a561d1f..9e17c29347 100644
--- a/rest_api_odoo/controllers/rest_api_odoo.py
+++ b/rest_api_odoo/controllers/rest_api_odoo.py
@@ -1,257 +1,706 @@
# -*- coding: utf-8 -*-
-#############################################################################
-#
-# Cybrosys Technologies Pvt. Ltd.
-#
-# Copyright (C) 2024-TODAY Cybrosys Technologies()
-# Author: Ayana KP (odoo@cybrosys.com)
-#
-# You can modify it under the terms of the GNU LESSER
-# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
-#
-# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
-# (LGPL v3) along with this program.
-# If not, see .
-#
-#############################################################################
import json
import logging
-from odoo import http
+import base64
+import ast
+from datetime import datetime, date, timedelta
+from odoo import http, fields
from odoo.http import request
-from datetime import datetime, date
+from .jwt_auth import JWTAuthMixin
_logger = logging.getLogger(__name__)
-class RestApi(http.Controller):
- """This is a controller which is used to generate responses based on the
- api requests"""
-
- def auth_api_key(self, api_key):
- """This function is used to authenticate the api-key when sending a
- request"""
- user_id = request.env['res.users'].sudo().search([('api_key', '=', api_key)])
- if api_key is not None and user_id:
- response = True
- elif not user_id:
- response = ('Invalid API Key '
- '! ')
- else:
- response = ("No API Key Provided "
- "! ")
- return response
-
- def generate_response(self, method, model, rec_id):
- """This function is used to generate the response based on the type
- of request and the parameters given"""
- option = request.env['connection.api'].search(
- [('model_id', '=', model)], limit=1)
- model_name = option.model_id.model
- if method != 'DELETE':
- data = json.loads(request.httprequest.data)
- else:
- data = {}
+class RestApi(http.Controller, JWTAuthMixin):
+ """Controlador API REST mejorado con JWT y filtrado avanzado"""
+
+ def _json_response(self, data, status=200):
+ """Genera respuesta JSON estandarizada con soporte CORS"""
+ try:
+ cors_headers = [
+ ('Content-Type', 'application/json; charset=utf-8'),
+ ('Access-Control-Allow-Origin', '*'),
+ ('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'),
+ ('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Key, api-key'),
+ ('Access-Control-Expose-Headers', 'Content-Type, Authorization'),
+ ('Access-Control-Max-Age', '86400')
+ ]
+
+ response = request.make_response(
+ json.dumps(data, ensure_ascii=False, indent=2, default=str),
+ headers=cors_headers
+ )
+ response.status_code = status
+ return response
+ except Exception as e:
+ _logger.error(f"Error creating JSON response: {str(e)}")
+ fallback_data = {
+ 'error': True,
+ 'message': 'Error interno creando respuesta JSON',
+ 'status_code': 500
+ }
+ cors_headers = [
+ ('Content-Type', 'application/json; charset=utf-8'),
+ ('Access-Control-Allow-Origin', '*'),
+ ('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'),
+ ('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Key, api-key')
+ ]
+ return request.make_response(
+ json.dumps(fallback_data, indent=2),
+ status=500,
+ headers=cors_headers
+ )
+
+ def _error_response(self, message, status=400, error_code=None):
+ """Genera respuesta de error estandarizada"""
+ error_data = {
+ 'error': True,
+ 'message': message,
+ 'status_code': status
+ }
+ if error_code:
+ error_data['error_code'] = error_code
+
+ return self._json_response(error_data, status)
+
+ def _serialize_record_values(self, records):
+ """Serializa los valores de los registros para JSON"""
+ if not records:
+ return []
+
+ serialized_records = []
+ for record in records:
+ serialized_record = {}
+ for key, value in record.items():
+ try:
+ if isinstance(value, (datetime, date)):
+ serialized_record[key] = value.isoformat()
+ elif isinstance(value, bytes):
+ serialized_record[key] = base64.b64encode(value).decode('utf-8')
+ elif isinstance(value, tuple) and len(value) == 2:
+ # Para relaciones Many2one que vienen como (id, name)
+ serialized_record[key] = list(value)
+ elif hasattr(value, '__iter__') and not isinstance(value, (str, dict, bytes)):
+ try:
+ serialized_record[key] = list(value) if value else []
+ except:
+ serialized_record[key] = str(value)
+ else:
+ serialized_record[key] = value
+ except Exception as e:
+ _logger.warning(f"Error serializing field {key}: {str(e)}")
+ serialized_record[key] = str(value) if value is not None else None
+
+ serialized_records.append(serialized_record)
+
+ return serialized_records
+
+ def _get_model_config(self, model_name):
+ """Obtiene la configuración de la API para un modelo"""
+ try:
+ model_obj = request.env['ir.model'].sudo().search([('model', '=', model_name)], limit=1)
+ if not model_obj:
+ return None, "Modelo no encontrado"
+
+ api_config = request.env['connection.api'].sudo().search([
+ ('model_id', '=', model_obj.id),
+ ('active', '=', True)
+ ], limit=1)
+
+ if not api_config:
+ return None, "Modelo no configurado para API REST"
+
+ return api_config, None
+ except Exception as e:
+ _logger.error(f"Error getting model config for {model_name}: {str(e)}")
+ return None, f"Error obteniendo configuración del modelo: {str(e)}"
+
+ def _parse_request_data(self, method):
+ """Parsea los datos de la request con parámetros avanzados"""
+ data = {}
fields = []
- if data:
- for field in data['fields']:
- fields.append(field)
- if not fields and method != 'DELETE':
- return ("No fields selected for the model"
- " ")
- if not option:
- return ("No Record Created for the model"
- " ")
+ domain = []
+ limit = None
+ offset = None
+ order = None
+
try:
if method == 'GET':
- fields = []
- for field in data['fields']:
- fields.append(field)
- if not option.is_get:
- return ("Method Not Allowed"
- " ")
- else:
- datas = []
- if rec_id != 0:
- partner_records = request.env[
- str(model_name)].search_read(
- domain=[('id', '=', rec_id)],
- fields=fields
- )
- for record in partner_records:
- for key, value in record.items():
- if isinstance(value, (datetime, date)):
- record[key] = value.isoformat()
- data = json.dumps({
- 'records': partner_records
- })
- datas.append(data)
- return request.make_response(data=datas)
- else:
- partner_records = request.env[
- str(model_name)].search_read(
- domain=[],
- fields=fields
- )
- for record in partner_records:
- for key, value in record.items():
- if isinstance(value, (datetime, date)):
- record[key] = value.isoformat()
- data = json.dumps({
- 'records': partner_records
- })
- datas.append(data)
- return request.make_response(data=datas)
- except:
- return ("Invalid JSON Data"
- " ")
- if method == 'POST':
- if not option.is_post:
- return ("Method Not Allowed"
- " ")
- else:
+ query_params = dict(request.httprequest.args)
+
+ # Parsear domain
+ if 'domain' in query_params:
+ try:
+ domain = ast.literal_eval(query_params['domain'])
+ if not isinstance(domain, list):
+ domain = []
+ except:
+ _logger.warning("Invalid domain format, ignoring")
+ domain = []
+
+ # Parsear fields
+ if 'fields' in query_params:
+ fields = [field.strip() for field in query_params['fields'].split(',') if field.strip()]
+
+ # Parsear limit
+ if 'limit' in query_params:
+ try:
+ limit = int(query_params['limit'])
+ if limit <= 0:
+ limit = None
+ except:
+ pass
+
+ # Parsear offset
+ if 'offset' in query_params:
+ try:
+ offset = int(query_params['offset'])
+ if offset < 0:
+ offset = None
+ except:
+ pass
+
+ # Parsear order
+ if 'order' in query_params:
+ order = query_params['order'].strip()
+ if not order:
+ order = None
+
+ # También intentar JSON body para GET (opcional)
try:
- data = json.loads(request.httprequest.data)
- datas = []
- new_resource = request.env[str(model_name)].create(
- data['values'])
- partner_records = request.env[
- str(model_name)].search_read(
- domain=[('id', '=', new_resource.id)],
- fields=fields
- )
- for record in partner_records:
- for key, value in record.items():
- if isinstance(value, (datetime, date)):
- record[key] = value.isoformat()
- new_data = json.dumps({'New resource': partner_records, })
- datas.append(new_data)
- return request.make_response(data=datas)
+ if request.httprequest.data:
+ json_data = json.loads(request.httprequest.data.decode('utf-8'))
+ data.update(json_data)
+ if 'fields' in json_data and not fields:
+ fields = json_data['fields']
+ if 'domain' in json_data and not domain:
+ domain = json_data['domain']
except:
- return ("Invalid JSON Data"
- " ")
- if method == 'PUT':
- if not option.is_put:
- return ("Method Not Allowed"
- " ")
- else:
- if rec_id == 0:
- return ("No ID Provided"
- " ")
- else:
- resource = request.env[str(model_name)].browse(
- int(rec_id))
- if not resource.exists():
- return ("Resource not found"
- " ")
+ pass
+
+ elif method in ['POST', 'PUT']:
+ try:
+ if request.httprequest.data:
+ data = json.loads(request.httprequest.data.decode('utf-8'))
+ if 'fields' in data:
+ fields = data['fields']
else:
- try:
- datas = []
- data = json.loads(request.httprequest.data)
- resource.write(data['values'])
- partner_records = request.env[
- str(model_name)].search_read(
- domain=[('id', '=', resource.id)],
- fields=fields
- )
- for record in partner_records:
- for key, value in record.items():
- if isinstance(value, (datetime, date)):
- record[key] = value.isoformat()
- new_data = json.dumps(
- {'Updated resource': partner_records,
- })
- datas.append(new_data)
- return request.make_response(data=datas)
+ return None, None, None, None, None, None, "No se proporcionaron datos JSON"
+ except (json.JSONDecodeError, UnicodeDecodeError) as e:
+ return None, None, None, None, None, None, f"JSON inválido: {str(e)}"
- except:
- return ("Invalid JSON Data "
- "! ")
- if method == 'DELETE':
- if not option.is_delete:
- return ("Method Not Allowed"
- " ")
+ return data, fields, domain, limit, offset, order, None
+ except Exception as e:
+ _logger.error(f"Error parsing request data: {str(e)}")
+ return None, None, None, None, None, None, f"Error procesando datos de la request: {str(e)}"
+
+ @http.route(['/api/v1/auth'], type='http', auth='none', methods=['POST', 'OPTIONS'], csrf=False)
+ def authenticate(self, **kw):
+ """Endpoint de autenticación que genera JWT token"""
+ # Manejar peticiones OPTIONS para CORS preflight
+ if request.httprequest.method == 'OPTIONS':
+ return self._handle_cors_preflight()
+
+ try:
+ if request.httprequest.data:
+ data = json.loads(request.httprequest.data.decode('utf-8'))
else:
- if rec_id == 0:
- return ("No ID Provided"
- " ")
+ data = {}
+ except (json.JSONDecodeError, UnicodeDecodeError):
+ return self._error_response("JSON inválido", 400)
+
+ username = data.get('username') or request.httprequest.headers.get('username')
+ password = data.get('password') or request.httprequest.headers.get('password')
+ database = data.get('database') or request.httprequest.headers.get('database') or request.env.cr.dbname
+ expires_in = data.get('expires_in_hours', 24)
+
+ if not all([username, password]):
+ return self._error_response("Username y password son requeridos", 400)
+
+ # Validar expires_in
+ if not isinstance(expires_in, int) or expires_in < 1 or expires_in > 168: # Max 7 días
+ expires_in = 24
+
+ try:
+ # Autenticar credenciales - Método correcto para Odoo 18.0
+ # Usar el env actual para buscar y verificar el usuario
+ try:
+ # Cambiar temporalmente la base de datos si es necesario
+ original_db = request.env.cr.dbname
+ if database != original_db:
+ # Para tests, usar la base de datos actual
+ database = original_db
+
+ # Buscar usuario con sudo para evitar restricciones de acceso
+ user_obj = request.env['res.users'].sudo()
+ user = user_obj.search([
+ '|', ('login', '=', username), ('email', '=', username)
+ ], limit=1)
+
+ if user and user._check_credentials(password, {}):
+ uid = user.id
else:
- resource = request.env[str(model_name)].browse(
- int(rec_id))
- if not resource.exists():
- return ("Resource not found"
- " ")
- else:
+ uid = False
+ except Exception:
+ uid = False
+
+ if not uid:
+ return self._error_response("Credenciales inválidas", 401)
+
+ # Generar JWT token
+ user = request.env['res.users'].browse(uid)
+ token = self._generate_jwt_token(uid, expires_in)
+
+ if not token:
+ return self._error_response("Error generando token de acceso", 500)
+
+ response_data = {
+ "success": True,
+ "message": "Autenticación exitosa",
+ "data": {
+ "user_id": user.id,
+ "username": user.login,
+ "name": user.name,
+ "access_token": token,
+ "token_type": "Bearer",
+ "expires_in": expires_in * 3600, # En segundos
+ "database": database
+ }
+ }
+
+ return self._json_response(response_data)
+
+ except Exception as e:
+ _logger.error(f"Error en autenticación: {str(e)}")
+ return self._error_response("Error interno de autenticación", 500)
+
+ @http.route(['/api/v1/refresh'], type='http', auth='none', methods=['POST'], csrf=False)
+ def refresh_token(self, **kw):
+ """Endpoint para refrescar un JWT token"""
+ try:
+ success, user_id, error_msg = self._authenticate_request()
+ if not success:
+ return self._error_response(error_msg, 401, "TOKEN_INVALID")
+
+ # Generar nuevo token
+ try:
+ data = json.loads(request.httprequest.data.decode('utf-8')) if request.httprequest.data else {}
+ expires_in = data.get('expires_in_hours', 24)
+ if not isinstance(expires_in, int) or expires_in < 1 or expires_in > 168:
+ expires_in = 24
+ except:
+ expires_in = 24
+
+ new_token = self._generate_jwt_token(user_id, expires_in)
+ if not new_token:
+ return self._error_response("Error generando nuevo token", 500)
+
+ user = request.env['res.users'].browse(user_id)
+ response_data = {
+ "success": True,
+ "message": "Token renovado exitosamente",
+ "data": {
+ "access_token": new_token,
+ "token_type": "Bearer",
+ "expires_in": expires_in * 3600,
+ "user_id": user.id,
+ "username": user.login
+ }
+ }
+
+ return self._json_response(response_data)
+
+ except Exception as e:
+ _logger.error(f"Error refreshing token: {str(e)}")
+ return self._error_response("Error interno renovando token", 500)
+
+ def _authenticate_request(self):
+ """
+ Autentica la request usando JWT token
+ Returns: (success: bool, user_id: int or None, error_message: str or None)
+ """
+ # Buscar token en headers
+ auth_header = request.httprequest.headers.get('Authorization')
+ if not auth_header:
+ # Fallback a headers alternativos para compatibilidad
+ token = request.httprequest.headers.get('X-API-Key') or request.httprequest.headers.get('api-key')
+ if token:
+ auth_header = f"Bearer {token}"
+
+ if not auth_header:
+ return False, None, "Token de autorización no proporcionado (use Authorization: Bearer )"
+
+ return self._validate_jwt_token(auth_header)
+
+ @http.route(['/api/v1/', '/api/v1//'],
+ type='http', auth='none', methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], csrf=False)
+ def api_handler(self, model_name, record_id=None, **kw):
+ """Endpoint principal de la API REST con JWT y filtrado avanzado"""
+ method = request.httprequest.method
+
+ # Manejar peticiones OPTIONS para CORS preflight
+ if method == 'OPTIONS':
+ return self._handle_cors_preflight()
+
+ # Autenticación usando JWT
+ success, user_id, error_msg = self._authenticate_request()
+ if not success:
+ return self._error_response(error_msg, 401, "AUTHENTICATION_FAILED")
+
+ # Obtener configuración del modelo
+ api_config, error_msg = self._get_model_config(model_name)
+ if not api_config:
+ return self._error_response(error_msg, 404, "MODEL_NOT_CONFIGURED")
- records = request.env[
- str(model_name)].search_read(
- domain=[('id', '=', resource.id)],
- fields=['id', 'display_name']
- )
- remove = json.dumps(
- {"Resource deleted": records,
- })
- resource.unlink()
- return request.make_response(data=remove)
-
- @http.route(['/send_request'], type='http',
- auth='none',
- methods=['GET', 'POST', 'PUT', 'DELETE'], csrf=False)
- def fetch_data(self, **kw):
- """This controller will be called when sending a request to the
- specified url, and it will authenticate the api-key and then will
- generate the result"""
- http_method = request.httprequest.method
-
- api_key = request.httprequest.headers.get('api-key')
- auth_api = self.auth_api_key(api_key)
- model = kw.get('model')
- username = request.httprequest.headers.get('login')
- password = request.httprequest.headers.get('password')
- credential = {'login': username, 'password': password, 'type': 'password'}
- request.session.authenticate(request.session.db, credential)
- model_id = request.env['ir.model'].search(
- [('model', '=', model)])
- if not model_id:
- return ("Invalid model, check spelling or maybe "
- "the related "
- "module is not installed"
- " ")
-
- if auth_api == True:
- if not kw.get('Id'):
- rec_id = 0
+ # Verificar permisos del método
+ method_permissions = {
+ 'GET': api_config.is_get,
+ 'POST': api_config.is_post,
+ 'PUT': api_config.is_put,
+ 'DELETE': api_config.is_delete
+ }
+
+ if not method_permissions.get(method, False):
+ return self._error_response(f"Método {method} no permitido para este modelo", 405, "METHOD_NOT_ALLOWED")
+
+ # Parsear datos de la request con parámetros avanzados
+ data, fields, domain, limit, offset, order, error_msg = self._parse_request_data(method)
+ if error_msg:
+ return self._error_response(error_msg, 400, "INVALID_REQUEST_DATA")
+
+ try:
+ return self._handle_request(method, api_config.model_id.model, record_id, data, fields, domain, limit, offset, order, api_config)
+ except Exception as e:
+ _logger.error(f"Error procesando request {method} para {model_name}: {str(e)}")
+ return self._error_response("Error interno del servidor", 500, "INTERNAL_SERVER_ERROR")
+
+ def _handle_request(self, method, model_name, record_id, data, fields, domain, limit, offset, order, api_config=None):
+ """Maneja las diferentes operaciones CRUD con parámetros avanzados"""
+ try:
+ model = request.env[model_name]
+
+ if method == 'GET':
+ return self._handle_get(model, record_id, fields, domain, limit, offset, order, api_config)
+ elif method == 'POST':
+ return self._handle_post(model, data, fields)
+ elif method == 'PUT':
+ return self._handle_put(model, record_id, data, fields)
+ elif method == 'DELETE':
+ return self._handle_delete(model, record_id)
+ except Exception as e:
+ _logger.error(f"Error in _handle_request: {str(e)}")
+ raise
+
+ def _handle_get(self, model, record_id, fields, domain, limit, offset, order, api_config=None):
+ """Maneja requests GET con filtrado avanzado"""
+ try:
+ # Aplicar límites de la configuración
+ max_limit = getattr(api_config, 'max_records_limit', 1000) if api_config else 1000
+ if limit and limit > max_limit:
+ limit = max_limit
+
+ if record_id:
+ # Obtener registro específico
+ search_domain = [('id', '=', record_id)]
+ search_fields = fields if fields else []
+ records = model.search_read(domain=search_domain, fields=search_fields)
+ total_count = len(records)
+
+ response_data = {
+ "success": True,
+ "count": len(records),
+ "total": total_count,
+ "data": self._serialize_record_values(records)
+ }
else:
- rec_id = int(kw.get('Id'))
- result = self.generate_response(http_method, model_id.id, rec_id)
- return result
- else:
- return auth_api
-
- @http.route(['/odoo_connect'], type="http", auth="none", csrf=False,
- methods=['GET'])
- def odoo_connect(self, **kw):
- """This is the controller which initializes the api transaction by
- generating the api-key for specific user and database"""
- username = request.httprequest.headers.get('login')
- password = request.httprequest.headers.get('password')
- db = request.httprequest.headers.get('db')
+ # Obtener registros con filtros
+ search_domain = domain if domain else []
+ search_fields = fields if fields else ['id', 'display_name']
+
+ # Contar total sin límite para metadatos
+ try:
+ total_count = model.search_count(search_domain)
+ except:
+ total_count = None
+
+ # Búsqueda con parámetros
+ search_params = {
+ 'domain': search_domain,
+ 'fields': search_fields
+ }
+
+ if limit:
+ search_params['limit'] = limit
+ if offset:
+ search_params['offset'] = offset
+ if order:
+ search_params['order'] = order
+
+ records = model.search_read(**search_params)
+
+ response_data = {
+ "success": True,
+ "count": len(records),
+ "data": self._serialize_record_values(records)
+ }
+
+ # Agregar metadatos de paginación
+ if total_count is not None:
+ response_data["total"] = total_count
+ if offset:
+ response_data["offset"] = offset
+ if limit:
+ response_data["limit"] = limit
+
+ # Información de paginación
+ if limit and total_count is not None:
+ current_offset = offset or 0
+ has_more = (current_offset + limit) < total_count
+ response_data["has_more"] = has_more
+ if has_more:
+ response_data["next_offset"] = current_offset + limit
+
+ return self._json_response(response_data)
+
+ except Exception as e:
+ _logger.error(f"Error en GET: {str(e)}")
+ return self._error_response(f"Error obteniendo registros: {str(e)}", 500)
+
+ def _handle_post(self, model, data, fields):
+ """Maneja requests POST (crear)"""
+ if not data.get('values'):
+ return self._error_response("Se requiere 'values' para crear registro", 400)
+
+ try:
+ new_record = model.create(data['values'])
+
+ # Obtener el registro creado con los campos especificados
+ search_fields = fields if fields else ['id', 'display_name']
+ record_data = new_record.read(search_fields)[0]
+
+ response_data = {
+ "success": True,
+ "message": "Registro creado exitosamente",
+ "count": 1,
+ "data": self._serialize_record_values([record_data])
+ }
+
+ return self._json_response(response_data, 201)
+
+ except Exception as e:
+ _logger.error(f"Error en POST: {str(e)}")
+ return self._error_response(f"Error creando registro: {str(e)}", 400)
+
+ def _handle_put(self, model, record_id, data, fields):
+ """Maneja requests PUT (actualizar)"""
+ if not record_id:
+ return self._error_response("ID de registro requerido para actualización", 400)
+
+ if not data.get('values'):
+ return self._error_response("Se requiere 'values' para actualizar registro", 400)
+
try:
- request.session.update(http.get_default_session(), db=db)
- credential = {'login': username, 'password': password,
- 'type': 'password'}
-
- auth = request.session.authenticate(db, credential)
- user = request.env['res.users'].browse(auth['uid'])
- api_key = request.env.user.generate_api(username)
- datas = json.dumps({"Status": "auth successful",
- "User": user.name,
- "api-key": api_key})
- return request.make_response(data=datas)
- except:
- return ("wrong login credentials"
- " ")
+ record = model.browse(record_id)
+ if not record.exists():
+ return self._error_response("Registro no encontrado", 404)
+
+ record.write(data['values'])
+
+ # Obtener el registro actualizado
+ search_fields = fields if fields else ['id', 'display_name']
+ record_data = record.read(search_fields)[0]
+
+ response_data = {
+ "success": True,
+ "message": "Registro actualizado exitosamente",
+ "count": 1,
+ "data": self._serialize_record_values([record_data])
+ }
+
+ return self._json_response(response_data)
+
+ except Exception as e:
+ _logger.error(f"Error en PUT: {str(e)}")
+ return self._error_response(f"Error actualizando registro: {str(e)}", 400)
+
+ def _handle_delete(self, model, record_id):
+ """Maneja requests DELETE"""
+ if not record_id:
+ return self._error_response("ID de registro requerido para eliminación", 400)
+
+ try:
+ record = model.browse(record_id)
+ if not record.exists():
+ return self._error_response("Registro no encontrado", 404)
+
+ # Guardar información del registro antes de eliminarlo
+ record_info = {
+ "id": record.id,
+ "display_name": record.display_name if hasattr(record, 'display_name') else str(record)
+ }
+
+ record.unlink()
+
+ response_data = {
+ "success": True,
+ "message": "Registro eliminado exitosamente",
+ "deleted_record": record_info
+ }
+
+ return self._json_response(response_data)
+
+ except Exception as e:
+ _logger.error(f"Error en DELETE: {str(e)}")
+ return self._error_response(f"Error eliminando registro: {str(e)}", 400)
+
+ @http.route(['/api/v1/models'], type='http', auth='none', methods=['GET'], csrf=False)
+ def list_available_models(self, **kw):
+ """Endpoint para listar modelos disponibles en la API"""
+ success, user_id, error_msg = self._authenticate_request()
+ if not success:
+ return self._error_response(error_msg, 401)
+
+ try:
+ api_configs = request.env['connection.api'].sudo().search([('active', '=', True)])
+ models_data = []
+
+ for config in api_configs:
+ model_info = {
+ "model": config.model_id.model,
+ "name": config.model_id.name,
+ "description": config.description or f"API REST para el modelo {config.model_id.name}",
+ "methods": {
+ "GET": config.is_get,
+ "POST": config.is_post,
+ "PUT": config.is_put,
+ "DELETE": config.is_delete
+ },
+ "max_records_limit": config.max_records_limit,
+ "endpoints": {
+ "collection": f"/api/v1/{config.model_id.model}",
+ "item": f"/api/v1/{config.model_id.model}/{{id}}",
+ "schema": f"/api/v1/schema/{config.model_id.model}"
+ }
+ }
+ models_data.append(model_info)
+
+ # Agregar información de documentación
+ base_url = request.env['ir.config_parameter'].sudo().get_param('web.base.url', 'http://localhost:8069')
+ response_data = {
+ "success": True,
+ "count": len(models_data),
+ "data": models_data,
+ "documentation": {
+ "swagger_ui": f"{base_url}/api/v1/docs",
+ "openapi_spec": f"{base_url}/api/v1/openapi.json"
+ },
+ "authentication": {
+ "type": "JWT Bearer Token",
+ "header": "Authorization: Bearer ",
+ "auth_endpoint": f"{base_url}/api/v1/auth",
+ "refresh_endpoint": f"{base_url}/api/v1/refresh"
+ }
+ }
+
+ return self._json_response(response_data)
+
+ except Exception as e:
+ _logger.error(f"Error listando modelos: {str(e)}")
+ return self._error_response("Error interno del servidor", 500)
+
+ @http.route(['/api/v1/health'], type='http', auth='none', methods=['GET'], csrf=False)
+ def health_check(self, **kwargs):
+ """Endpoint de verificación de salud de la API"""
+ try:
+ # Verificar conexión a BD
+ request.env.cr.execute("SELECT 1")
+
+ # Verificar configuraciones activas
+ active_configs = len(request.env["connection.api"].sudo().search([("active", "=", True)]))
+
+ # Verificar configuración JWT
+ jwt_secret = request.env['ir.config_parameter'].sudo().get_param('rest_api.jwt_secret')
+
+ health_status = {
+ "status": "healthy",
+ "timestamp": fields.Datetime.now().isoformat(),
+ "database": request.env.cr.dbname,
+ "active_models": active_configs,
+ "version": "2.0.0",
+ "auth_method": "JWT Bearer Token",
+ "jwt_configured": bool(jwt_secret),
+ "features": {
+ "dynamic_schemas": True,
+ "advanced_filtering": True,
+ "jwt_authentication": True,
+ "pagination": True,
+ "field_selection": True
+ }
+ }
+
+ return self._json_response(health_status)
+
+ except Exception as e:
+ error_status = {
+ "status": "unhealthy",
+ "error": str(e),
+ "timestamp": fields.Datetime.now().isoformat()
+ }
+ return request.make_response(
+ json.dumps(error_status),
+ status=503,
+ headers=[("Content-Type", "application/json; charset=utf-8")]
+ )
+
+ @http.route(['/api', '/api/'], type='http', auth='none', methods=['GET'], csrf=False)
+ def api_root(self, **kw):
+ """Endpoint raíz de la API que proporciona información básica"""
+ try:
+ base_url = request.env['ir.config_parameter'].sudo().get_param('web.base.url', 'http://localhost:8069')
+
+ api_info = {
+ "message": "Bienvenido a la REST API de Odoo v2.0",
+ "version": "2.0.0",
+ "status": "active",
+ "documentation": f"{base_url}/api/v1/docs",
+ "features": [
+ "JWT Bearer Token Authentication",
+ "Dynamic Schema Generation",
+ "Advanced Filtering with Domain",
+ "Pagination Support",
+ "Field Selection",
+ "Interactive Swagger Documentation"
+ ],
+ "endpoints": {
+ "auth": f"{base_url}/api/v1/auth",
+ "refresh": f"{base_url}/api/v1/refresh",
+ "models": f"{base_url}/api/v1/models",
+ "health": f"{base_url}/api/v1/health",
+ "docs": f"{base_url}/api/v1/docs",
+ "openapi": f"{base_url}/api/v1/openapi.json"
+ },
+ "authentication": {
+ "type": "JWT Bearer Token",
+ "header": "Authorization",
+ "format": "Bearer ",
+ "expires_in_hours": "configurable (default: 24h)"
+ }
+ }
+
+ return self._json_response(api_info)
+ except Exception as e:
+ _logger.error(f"Error en api_root: {str(e)}")
+ return self._error_response("Error interno del servidor", 500)
+
+ def _handle_cors_preflight(self):
+ """Maneja peticiones OPTIONS para CORS preflight"""
+ cors_headers = [
+ ('Content-Type', 'application/json; charset=utf-8'),
+ ('Access-Control-Allow-Origin', '*'),
+ ('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'),
+ ('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Key, api-key'),
+ ('Access-Control-Expose-Headers', 'Content-Type, Authorization'),
+ ('Access-Control-Max-Age', '86400')
+ ]
+
+ return request.make_response('', headers=cors_headers, status=200)
diff --git a/rest_api_odoo/controllers/swagger_controller.py b/rest_api_odoo/controllers/swagger_controller.py
new file mode 100755
index 0000000000..29fffe9443
--- /dev/null
+++ b/rest_api_odoo/controllers/swagger_controller.py
@@ -0,0 +1,999 @@
+# -*- coding: utf-8 -*-
+import json
+import logging
+from datetime import datetime
+from odoo import http, fields
+from odoo.http import request
+
+_logger = logging.getLogger(__name__)
+
+
+class SwaggerController(http.Controller):
+ """Controlador Swagger/OpenAPI con esquemas dinámicos mejorados"""
+
+ @http.route(["/api/v1/docs", "/api/docs"], type="http", auth="none", methods=["GET"], csrf=False)
+ def swagger_ui(self, **kwargs):
+ """Muestra la interfaz de Swagger UI mejorada"""
+ try:
+ base_url = self._get_base_url()
+
+ swagger_html = f"""
+
+
+
+
+
+ Odoo REST API - Documentation
+
+
+
+
+
+
🔐 Autenticación JWT
+
Esta API usa JWT Bearer Tokens . Usa el endpoint /auth para obtener tu token.
+
Luego agrega: Authorization: Bearer tu_token_aqui
+
+
+
+
+
+
+
+"""
+
+ return request.make_response(swagger_html, headers=[("Content-Type", "text/html; charset=utf-8")])
+
+ except Exception as e:
+ _logger.error(f"Error serving Swagger UI: {str(e)}")
+ return request.make_response(f"Error Could not load documentation: {str(e)}
", status=500)
+
+ @http.route(["/api/v1/openapi.json"], type="http", auth="none", methods=["GET"], csrf=False)
+ def openapi_spec(self, **kwargs):
+ """Genera la especificación OpenAPI/Swagger con mejoras"""
+ try:
+ base_url = self._get_base_url()
+ api_configs = []
+
+ try:
+ api_configs = request.env["connection.api"].sudo().search([("active", "=", True)])
+ except Exception as e:
+ _logger.warning(f"Could not load API configurations: {str(e)}")
+
+ # Generar esquemas dinámicos mejorados
+ dynamic_schemas = self._generate_enhanced_schemas(api_configs)
+
+ openapi_spec = {
+ "openapi": "3.0.3",
+ "info": {
+ "title": "Odoo REST API",
+ "description": self._get_enhanced_description(base_url),
+ "version": "2.0.0",
+ "contact": {"name": "API Support", "email": "support@example.com"},
+ "license": {"name": "LGPL-3", "url": "https://www.gnu.org/licenses/lgpl-3.0.html"}
+ },
+ "servers": [{"url": f"{base_url}/api/v1", "description": "Production server"}],
+ "security": [{"BearerAuth": []}],
+ "components": {
+ "securitySchemes": {
+ "BearerAuth": {
+ "type": "http",
+ "scheme": "bearer",
+ "bearerFormat": "JWT",
+ "description": "JWT Bearer token obtenido del endpoint /auth"
+ }
+ },
+ "schemas": {
+ **self._get_base_schemas(),
+ **dynamic_schemas
+ },
+ "responses": self._get_common_responses()
+ },
+ "paths": self._generate_enhanced_paths(api_configs),
+ "tags": self._generate_enhanced_tags(api_configs)
+ }
+
+ return request.make_response(
+ json.dumps(openapi_spec, indent=2, ensure_ascii=False),
+ headers=[("Content-Type", "application/json; charset=utf-8")]
+ )
+
+ except Exception as e:
+ _logger.error(f"Error generating OpenAPI spec: {str(e)}")
+ return request.make_response(
+ json.dumps({"error": f"Error loading API specification: {str(e)}"}),
+ headers=[("Content-Type", "application/json; charset=utf-8")]
+ )
+
+ @http.route(['/api/v1/schema/'], type='http', auth='none', methods=['GET'], csrf=False)
+ def get_model_schema(self, model_name, **kwargs):
+ """Obtiene el esquema de un modelo específico"""
+ try:
+ # Obtener configuración del modelo
+ model_obj = request.env['ir.model'].sudo().search([('model', '=', model_name)], limit=1)
+ if not model_obj:
+ return self._error_response("Modelo no encontrado", 404)
+
+ api_config = request.env['connection.api'].sudo().search([
+ ('model_id', '=', model_obj.id),
+ ('active', '=', True)
+ ], limit=1)
+
+ if not api_config:
+ return self._error_response("Modelo no configurado para API REST", 404)
+
+ model_class = request.env[model_name].sudo()
+ schema = self._generate_enhanced_model_schema(model_class, api_config)
+
+ response_data = {
+ "model": model_name,
+ "display_name": model_obj.name,
+ "schema": schema,
+ "endpoints": {
+ "collection": f"/api/v1/{model_name}",
+ "item": f"/api/v1/{model_name}/{{id}}"
+ },
+ "available_methods": {
+ "GET": api_config.is_get,
+ "POST": api_config.is_post,
+ "PUT": api_config.is_put,
+ "DELETE": api_config.is_delete
+ }
+ }
+
+ return request.make_response(
+ json.dumps(response_data, indent=2, ensure_ascii=False),
+ headers=[("Content-Type", "application/json; charset=utf-8")]
+ )
+
+ except Exception as e:
+ return request.make_response(
+ json.dumps({"error": f"Error getting schema: {str(e)}"}),
+ status=500,
+ headers=[("Content-Type", "application/json; charset=utf-8")]
+ )
+
+ def _get_base_url(self):
+ """Obtiene la URL base del servidor"""
+ try:
+ if request.env:
+ return request.env["ir.config_parameter"].sudo().get_param("web.base.url", "http://localhost:8069")
+ return request.httprequest.host_url.rstrip('/')
+ except:
+ return "http://localhost:8069"
+
+ def _get_enhanced_description(self, base_url):
+ """Descripción mejorada de la API"""
+ return f"""
+# Odoo REST API v2.0
+
+API REST completa para Odoo con autenticación JWT y documentación dinámica.
+
+## 🔐 Autenticación
+
+Esta API utiliza **JWT Bearer Tokens** para autenticación:
+
+1. **Obtener token:**
+```bash
+curl -X POST {base_url}/api/v1/auth \\
+ -H "Content-Type: application/json" \\
+ -d '{{"username": "DontFucking", "password": "UseTheseCredentials"}}'
+```
+
+2. **Usar token en requests:**
+```bash
+curl -X GET {base_url}/api/v1/models \\
+ -H "Authorization: Bearer YOUR_JWT_TOKEN"
+```
+
+## 📊 Características
+
+- **Esquemas dinámicos** basados en modelos reales de Odoo
+- **Filtrado avanzado** con domain, limit, offset
+- **Autenticación JWT** segura con expiración configurable
+- **Validación automática** de tipos de datos
+- **Documentación interactiva** con Swagger UI
+
+## 🚀 Endpoints Principales
+
+- `POST /auth` - Autenticación y obtención de token
+- `POST /refresh` - Renovar token JWT
+- `GET /models` - Lista de modelos disponibles
+- `GET /health` - Estado de la API
+- `GET /schema/{{model}}` - Esquema específico de un modelo
+
+## 📝 Formato de Respuestas
+
+Todas las respuestas siguen un formato consistente:
+
+**Éxito:**
+```json
+{{
+ "success": true,
+ "count": 10,
+ "data": [...]
+}}
+```
+
+**Error:**
+```json
+{{
+ "error": true,
+ "message": "Descripción del error",
+ "status_code": 400,
+ "error_code": "ERROR_CODE"
+}}
+```
+"""
+
+ def _get_base_schemas(self):
+ """Esquemas base mejorados"""
+ return {
+ "ErrorResponse": {
+ "type": "object",
+ "required": ["error", "message", "status_code"],
+ "properties": {
+ "error": {"type": "boolean", "example": True},
+ "message": {"type": "string", "example": "Error description"},
+ "status_code": {"type": "integer", "example": 400},
+ "error_code": {"type": "string", "example": "VALIDATION_ERROR"}
+ }
+ },
+ "AuthRequest": {
+ "type": "object",
+ "required": ["username", "password"],
+ "properties": {
+ "username": {"type": "string", "example": "DontFucking"},
+ "password": {"type": "string", "format": "password", "example": "UseTheseCredentials"},
+ "database": {"type": "string", "example": "odoo"},
+ "expires_in_hours": {"type": "integer", "minimum": 1, "maximum": 168, "default": 24, "example": 24}
+ }
+
+ },
+ "AuthResponse": {
+ "type": "object",
+ "properties": {
+ "success": {"type": "boolean", "example": True},
+ "message": {"type": "string", "example": "Authentication successful"},
+ "data": {
+ "type": "object",
+ "properties": {
+ "user_id": {"type": "integer", "example": 2},
+ "username": {"type": "string", "example": "DontFucking"},
+ "name": {"type": "string", "example": "Administrator"},
+ "access_token": {"type": "string", "example": "eyJ0eXAiOiJKV1QiLCJhbGc..."},
+ "token_type": {"type": "string", "example": "Bearer"},
+ "expires_in": {"type": "integer", "example": 86400},
+ "database": {"type": "string", "example": "odoo"}
+ }
+ }
+ }
+ },
+ "HealthResponse": {
+ "type": "object",
+ "properties": {
+ "status": {"type": "string", "enum": ["healthy", "unhealthy"]},
+ "timestamp": {"type": "string", "format": "date-time"},
+ "database": {"type": "string"},
+ "active_models": {"type": "integer"},
+ "version": {"type": "string"},
+ "auth_method": {"type": "string", "example": "JWT Bearer Token"}
+ }
+ }
+ }
+
+ def _get_common_responses(self):
+ """Respuestas comunes reutilizables"""
+ return {
+ "UnauthorizedError": {
+ "description": "Token JWT missing, invalid, or expired",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/ErrorResponse"},
+ "example": {
+ "error": True,
+ "message": "Token expirado",
+ "status_code": 401,
+ "error_code": "TOKEN_EXPIRED"
+ }
+ }
+ }
+ },
+ "NotFoundError": {
+ "description": "Resource not found",
+ "content": {
+ "application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}
+ }
+ },
+ "ValidationError": {
+ "description": "Invalid request data",
+ "content": {
+ "application/json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}
+ }
+ }
+ }
+
+ def _generate_enhanced_schemas(self, api_configs):
+ """Genera esquemas dinámicos mejorados"""
+ schemas = {}
+
+ for config in api_configs:
+ try:
+ if not hasattr(config, 'model_id') or not config.model_id:
+ continue
+
+ model_name = config.model_id.model
+
+ try:
+ model_class = request.env[model_name].sudo()
+ except KeyError:
+ _logger.warning(f"Model {model_name} not found")
+ continue
+
+ # Generar esquema mejorado del modelo
+ model_schema = self._generate_enhanced_model_schema(model_class, config)
+ schemas[f"{model_name}_values"] = model_schema
+
+ # Esquemas de request
+ schemas[f"{model_name}_create_request"] = {
+ "type": "object",
+ "required": ["values"],
+ "properties": {
+ "values": {"$ref": f"#/components/schemas/{model_name}_values"},
+ "fields": {
+ "type": "array",
+ "items": {"type": "string"},
+ "description": "Campos específicos a retornar en la respuesta",
+ "example": list(model_schema.get("properties", {}).keys())[:5]
+ }
+ },
+ "example": {
+ "values": self._generate_example_values(model_class, config),
+ "fields": ["id", "display_name"]
+ }
+ }
+
+ # Esquema de respuesta de lectura
+ read_properties = dict(model_schema.get("properties", {}))
+ read_properties.update({
+ "id": {"type": "integer", "description": "ID único del registro", "example": 1},
+ "display_name": {"type": "string", "description": "Nombre para mostrar"}
+ })
+
+ schemas[f"{model_name}_read_response"] = {
+ "type": "object",
+ "properties": read_properties
+ }
+
+ # Respuesta de colección con metadatos
+ schemas[f"{model_name}_collection_response"] = {
+ "type": "object",
+ "properties": {
+ "success": {"type": "boolean", "example": True},
+ "count": {"type": "integer", "example": 1},
+ "total": {"type": "integer", "description": "Total de registros (sin limit)"},
+ "offset": {"type": "integer", "description": "Registros omitidos"},
+ "limit": {"type": "integer", "description": "Límite aplicado"},
+ "data": {
+ "type": "array",
+ "items": {"$ref": f"#/components/schemas/{model_name}_read_response"}
+ }
+ }
+ }
+
+ except Exception as e:
+ _logger.error(f"Error generating enhanced schema for model {config.model_id.model}: {str(e)}")
+ continue
+
+ return schemas
+
+ def _generate_enhanced_model_schema(self, model_class, config):
+ """Genera esquema mejorado para un modelo específico"""
+ properties = {}
+ required = []
+
+ try:
+ allowed_fields = self._get_allowed_fields(config)
+ forbidden_fields = self._get_forbidden_fields(config)
+
+ for field_name, field_obj in model_class._fields.items():
+ if field_name in forbidden_fields:
+ continue
+
+ if allowed_fields and field_name not in allowed_fields:
+ continue
+
+ field_schema = self._odoo_field_to_enhanced_json_schema(field_obj, field_name, model_class)
+ if field_schema:
+ properties[field_name] = field_schema
+
+ if getattr(field_obj, 'required', False):
+ required.append(field_name)
+
+ except Exception as e:
+ _logger.warning(f"Error processing enhanced model fields: {str(e)}")
+
+ schema = {
+ "type": "object",
+ "properties": properties
+ }
+
+ if required:
+ schema["required"] = required
+
+ return schema
+
+ def _odoo_field_to_enhanced_json_schema(self, field_obj, field_name, model_class):
+ """Convierte un campo de Odoo a esquema JSON mejorado"""
+ field_type = type(field_obj).__name__
+
+ base_schema = {
+ "description": getattr(field_obj, 'help', '') or getattr(field_obj, 'string', field_name)
+ }
+
+ # Mapeo de tipos mejorado
+ type_mapping = {
+ 'Char': {"type": "string"},
+ 'Text': {"type": "string"},
+ 'Html': {"type": "string", "format": "html"},
+ 'Boolean': {"type": "boolean"},
+ 'Integer': {"type": "integer"},
+ 'Float': {"type": "number", "format": "float"},
+ 'Monetary': {"type": "number", "format": "currency"},
+ 'Date': {"type": "string", "format": "date"},
+ 'Datetime': {"type": "string", "format": "date-time"},
+ 'Binary': {"type": "string", "format": "binary"},
+ 'Selection': {"type": "string"},
+ 'Many2one': {"type": "integer"},
+ 'One2many': {"type": "array", "items": {"type": "integer"}},
+ 'Many2many': {"type": "array", "items": {"type": "integer"}},
+ }
+
+ schema = type_mapping.get(field_type, {"type": "string"})
+ schema.update(base_schema)
+
+ # Mejoras específicas por tipo de campo
+ if field_type == 'Char' and hasattr(field_obj, 'size') and field_obj.size:
+ schema["maxLength"] = field_obj.size
+
+ # Campos Selection con opciones reales
+ if field_type == 'Selection' and hasattr(field_obj, 'selection'):
+ try:
+ if callable(field_obj.selection):
+ try:
+ # Intentar obtener opciones dinámicas
+ options = field_obj.selection(model_class, field_name)
+ if options:
+ schema["enum"] = [opt[0] for opt in options if opt[0]]
+ schema["example"] = options[0][0] if options else None
+ schema["x-options"] = [{"value": opt[0], "label": opt[1]} for opt in options]
+ except:
+ schema["description"] += " (opciones dinámicas)"
+ else:
+ options = [opt[0] for opt in field_obj.selection if opt[0]]
+ if options:
+ schema["enum"] = options
+ schema["example"] = options[0]
+ schema["x-options"] = [{"value": opt[0], "label": opt[1]} for opt in field_obj.selection]
+ except Exception as e:
+ _logger.warning(f"Error getting selection options for {field_name}: {str(e)}")
+
+ # Campos relacionales con información del modelo relacionado
+ if field_type == 'Many2one':
+ comodel_name = getattr(field_obj, 'comodel_name', None)
+ if comodel_name:
+ schema.update({
+ "description": f"ID del registro relacionado del modelo {comodel_name}",
+ "x-related-model": comodel_name,
+ "minimum": 1
+ })
+
+ # Campos One2many y Many2many
+ if field_type in ['One2many', 'Many2many']:
+ comodel_name = getattr(field_obj, 'comodel_name', None)
+ if comodel_name:
+ schema["description"] = f"Lista de IDs de registros del modelo {comodel_name}"
+ schema["x-related-model"] = comodel_name
+ schema["items"]["minimum"] = 1
+
+ # Mejores ejemplos basados en el nombre del campo
+ if "example" not in schema:
+ schema["example"] = self._get_smart_example(field_name, schema.get("type"), field_type)
+
+ # Propiedades adicionales
+ if hasattr(field_obj, 'required') and field_obj.required:
+ schema["x-required"] = True
+
+ if hasattr(field_obj, 'readonly') and field_obj.readonly:
+ schema["readOnly"] = True
+
+ return schema
+
+ def _get_smart_example(self, field_name, json_type, odoo_type):
+ """Genera ejemplos inteligentes basados en el nombre del campo"""
+ field_lower = field_name.lower()
+
+ # Ejemplos específicos por nombre de campo
+ smart_examples = {
+ 'name': 'Ejemplo de nombre',
+ 'email': 'usuario@ejemplo.com',
+ 'phone': '+34123456789',
+ 'mobile': '+34987654321',
+ 'website': 'https://ejemplo.com',
+ 'url': 'https://ejemplo.com',
+ 'street': 'Calle Ejemplo 123',
+ 'city': 'Madrid',
+ 'zip': '28001',
+ 'description': 'Descripción detallada del elemento',
+ 'note': 'Nota adicional',
+ 'comment': 'Comentario del usuario',
+ 'reference': 'REF-001',
+ 'code': 'COD123',
+ 'login': 'usuario',
+ 'password': 'contraseña_segura',
+ 'price': 99.99,
+ 'amount': 100.0,
+ 'quantity': 1,
+ 'qty': 5,
+ }
+
+ # Buscar coincidencias en el nombre del campo
+ for pattern, example in smart_examples.items():
+ if pattern in field_lower:
+ return example
+
+ # Ejemplos por tipo JSON
+ type_examples = {
+ "string": f"Valor de {field_name}",
+ "integer": 1,
+ "number": 10.5,
+ "boolean": True,
+ "array": [1, 2, 3]
+ }
+
+ return type_examples.get(json_type, None)
+
+ def _generate_example_values(self, model_class, config):
+ """Genera valores de ejemplo para un modelo"""
+ example_values = {}
+
+ try:
+ allowed_fields = self._get_allowed_fields(config)
+ forbidden_fields = self._get_forbidden_fields(config)
+
+ for field_name, field_obj in model_class._fields.items():
+ if field_name in forbidden_fields:
+ continue
+ if allowed_fields and field_name not in allowed_fields:
+ continue
+ if field_name in ['id', 'create_date', 'write_date', 'create_uid', 'write_uid']:
+ continue
+
+ field_type = type(field_obj).__name__
+ example = self._get_smart_example(field_name,
+ self._get_json_type_for_odoo_field(field_type),
+ field_type)
+ if example is not None:
+ example_values[field_name] = example
+
+ except Exception as e:
+ _logger.warning(f"Error generating example values: {str(e)}")
+
+ return example_values
+
+ def _get_json_type_for_odoo_field(self, odoo_type):
+ """Mapeo simple de tipo Odoo a tipo JSON"""
+ mapping = {
+ 'Char': 'string', 'Text': 'string', 'Html': 'string', 'Selection': 'string',
+ 'Integer': 'integer', 'Many2one': 'integer',
+ 'Float': 'number', 'Monetary': 'number',
+ 'Boolean': 'boolean',
+ 'One2many': 'array', 'Many2many': 'array'
+ }
+ return mapping.get(odoo_type, 'string')
+
+ def _generate_enhanced_paths(self, api_configs):
+ """Genera paths mejorados con parámetros adicionales"""
+ paths = {
+ "/auth": {
+ "post": {
+ "tags": ["Authentication"],
+ "summary": "Authenticate and get JWT token",
+ "description": "Autentica credenciales y devuelve un JWT token para usar en requests subsiguientes",
+ "requestBody": {
+ "required": True,
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/AuthRequest"}
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Authentication successful",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/AuthResponse"}
+ }
+ }
+ },
+ "401": {"$ref": "#/components/responses/UnauthorizedError"}
+ },
+ "security": []
+ }
+ },
+ "/refresh": {
+ "post": {
+ "tags": ["Authentication"],
+ "summary": "Refresh JWT token",
+ "description": "Genera un nuevo JWT token usando el token actual",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "expires_in_hours": {"type": "integer", "default": 24}
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Token refreshed successfully",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/AuthResponse"}
+ }
+ }
+ },
+ "401": {"$ref": "#/components/responses/UnauthorizedError"}
+ }
+ }
+ },
+ "/health": {
+ "get": {
+ "tags": ["System"],
+ "summary": "API health check",
+ "description": "Verifica el estado de salud de la API y conexiones",
+ "responses": {
+ "200": {
+ "description": "API is healthy",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/HealthResponse"}
+ }
+ }
+ },
+ "503": {
+ "description": "API is unhealthy",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/HealthResponse"}
+ }
+ }
+ }
+ },
+ "security": []
+ }
+ }
+ }
+
+ # Generar paths para cada modelo configurado
+ for config in api_configs:
+ try:
+ if not hasattr(config, 'model_id') or not config.model_id:
+ continue
+
+ model_name = config.model_id.model
+ model_display_name = config.model_id.name
+
+ collection_path = f"/{model_name}"
+ item_path = f"/{model_name}/{{id}}"
+ schema_path = f"/schema/{model_name}"
+
+ # Endpoint para obtener esquema del modelo
+ paths[schema_path] = {
+ "get": {
+ "tags": ["Schemas"],
+ "summary": f"Get {model_display_name} schema",
+ "description": f"Obtiene el esquema completo del modelo {model_display_name}",
+ "responses": {
+ "200": {"description": "Schema retrieved successfully"},
+ "404": {"$ref": "#/components/responses/NotFoundError"}
+ },
+ "security": []
+ }
+ }
+
+ if collection_path not in paths:
+ paths[collection_path] = {}
+ if item_path not in paths:
+ paths[item_path] = {}
+
+ # GET endpoints con parámetros mejorados
+ if config.is_get:
+ paths[collection_path]["get"] = {
+ "tags": [model_name],
+ "summary": f"Get all {model_display_name} records",
+ "description": f"Obtiene registros del modelo {model_display_name} con filtrado avanzado",
+ "parameters": [
+ {
+ "name": "domain",
+ "in": "query",
+ "description": "Filtros en formato Odoo domain",
+ "schema": {"type": "string"},
+ "example": "[['active', '=', True]]"
+ },
+ {
+ "name": "fields",
+ "in": "query",
+ "description": "Campos específicos a retornar (separados por comas)",
+ "schema": {"type": "string"},
+ "example": "id,name,email"
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Número máximo de registros",
+ "schema": {"type": "integer", "minimum": 1, "maximum": config.max_records_limit},
+ "example": 10
+ },
+ {
+ "name": "offset",
+ "in": "query",
+ "description": "Número de registros a omitir",
+ "schema": {"type": "integer", "minimum": 0},
+ "example": 0
+ },
+ {
+ "name": "order",
+ "in": "query",
+ "description": "Ordenamiento (ej: 'name asc', 'create_date desc')",
+ "schema": {"type": "string"},
+ "example": "name asc"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "List of records",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": f"#/components/schemas/{model_name}_collection_response"}
+ }
+ }
+ },
+ "401": {"$ref": "#/components/responses/UnauthorizedError"}
+ }
+ }
+
+ paths[item_path]["get"] = {
+ "tags": [model_name],
+ "summary": f"Get specific {model_display_name} record",
+ "description": f"Obtiene un registro específico del modelo {model_display_name}",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": True,
+ "description": "ID del registro",
+ "schema": {"type": "integer", "minimum": 1}
+ },
+ {
+ "name": "fields",
+ "in": "query",
+ "description": "Campos específicos a retornar",
+ "schema": {"type": "string"}
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Record found",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": f"#/components/schemas/{model_name}_collection_response"}
+ }
+ }
+ },
+ "404": {"$ref": "#/components/responses/NotFoundError"},
+ "401": {"$ref": "#/components/responses/UnauthorizedError"}
+ }
+ }
+
+ # POST endpoint
+ if config.is_post:
+ paths[collection_path]["post"] = {
+ "tags": [model_name],
+ "summary": f"Create new {model_display_name} record",
+ "description": f"Crea un nuevo registro en el modelo {model_display_name}",
+ "requestBody": {
+ "required": True,
+ "content": {
+ "application/json": {
+ "schema": {"$ref": f"#/components/schemas/{model_name}_create_request"}
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Record created successfully",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": f"#/components/schemas/{model_name}_collection_response"}
+ }
+ }
+ },
+ "400": {"$ref": "#/components/responses/ValidationError"},
+ "401": {"$ref": "#/components/responses/UnauthorizedError"}
+ }
+ }
+
+ # PUT endpoint
+ if config.is_put:
+ paths[item_path]["put"] = {
+ "tags": [model_name],
+ "summary": f"Update {model_display_name} record",
+ "description": f"Actualiza un registro existente del modelo {model_display_name}",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": True,
+ "description": "ID del registro a actualizar",
+ "schema": {"type": "integer", "minimum": 1}
+ }
+ ],
+ "requestBody": {
+ "required": True,
+ "content": {
+ "application/json": {
+ "schema": {"$ref": f"#/components/schemas/{model_name}_create_request"}
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Record updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": f"#/components/schemas/{model_name}_collection_response"}
+ }
+ }
+ },
+ "404": {"$ref": "#/components/responses/NotFoundError"},
+ "400": {"$ref": "#/components/responses/ValidationError"},
+ "401": {"$ref": "#/components/responses/UnauthorizedError"}
+ }
+ }
+
+ # DELETE endpoint
+ if config.is_delete:
+ paths[item_path]["delete"] = {
+ "tags": [model_name],
+ "summary": f"Delete {model_display_name} record",
+ "description": f"Elimina un registro del modelo {model_display_name}",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": True,
+ "description": "ID del registro a eliminar",
+ "schema": {"type": "integer", "minimum": 1}
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Record deleted successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {"type": "boolean", "example": True},
+ "message": {"type": "string", "example": "Record deleted successfully"},
+ "deleted_record": {
+ "type": "object",
+ "properties": {
+ "id": {"type": "integer"},
+ "display_name": {"type": "string"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "404": {"$ref": "#/components/responses/NotFoundError"},
+ "401": {"$ref": "#/components/responses/UnauthorizedError"}
+ }
+ }
+
+ except Exception as e:
+ _logger.warning(f"Error generating enhanced paths for model: {str(e)}")
+ continue
+
+ return paths
+
+ def _generate_enhanced_tags(self, api_configs):
+ """Genera tags mejorados para agrupar endpoints"""
+ tags = [
+ {"name": "Authentication", "description": "Autenticación JWT y gestión de tokens"},
+ {"name": "System", "description": "Endpoints del sistema (salud, estado)"},
+ {"name": "Schemas", "description": "Esquemas de modelos disponibles"}
+ ]
+
+ for config in api_configs:
+ if hasattr(config, 'model_id') and config.model_id:
+ available_methods = []
+ if config.is_get: available_methods.append("GET")
+ if config.is_post: available_methods.append("POST")
+ if config.is_put: available_methods.append("PUT")
+ if config.is_delete: available_methods.append("DELETE")
+
+ tags.append({
+ "name": config.model_id.model,
+ "description": f"Operaciones CRUD para {config.model_id.name} - Métodos: {', '.join(available_methods)}",
+ "externalDocs": {
+ "description": "Esquema del modelo",
+ "url": f"/api/v1/schema/{config.model_id.model}"
+ }
+ })
+
+ return tags
+
+ def _get_allowed_fields(self, config):
+ """Obtiene campos permitidos de la configuración"""
+ if not hasattr(config, 'allowed_fields') or not config.allowed_fields:
+ return None
+ return [f.strip() for f in config.allowed_fields.split(',') if f.strip()]
+
+ def _get_forbidden_fields(self, config):
+ """Obtiene campos prohibidos de la configuración"""
+ default_forbidden = ['__last_update', 'create_uid', 'create_date', 'write_uid', 'write_date']
+ if not hasattr(config, 'forbidden_fields') or not config.forbidden_fields:
+ return default_forbidden
+ return [f.strip() for f in config.forbidden_fields.split(',') if f.strip()]
diff --git a/rest_api_odoo/models/connection_api.py b/rest_api_odoo/models/connection_api.py
index 52da21c0fa..1b752e2e9d 100644
--- a/rest_api_odoo/models/connection_api.py
+++ b/rest_api_odoo/models/connection_api.py
@@ -1,10 +1,11 @@
-# -*- coding:utf-8 -*-
+# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies()
# Author: Ayana KP (odoo@cybrosys.com)
+# Modified by: Broigm - API configuration improvements
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
@@ -19,29 +20,247 @@
# If not, see .
#
#############################################################################
-from odoo import fields, models
+from odoo import fields, models, api, _
+from odoo.exceptions import ValidationError
class ConnectionApi(models.Model):
- """This class is used to create an api model in which we can create
- records with models and fields, and also we can specify methods."""
+ """Configuración de modelos para REST API con mejores controles"""
_name = 'connection.api'
- _description = 'Connection Rest Api'
- _rec_name = 'model_id'
-
- model_id = fields.Many2one('ir.model', string="Model",
- domain="[('transient', '=', False)]",
- help="Select model which can be accessed by "
- "REST api requests.")
- is_get = fields.Boolean(string='GET',
- help="Select this to enable GET method "
- "while sending requests.")
- is_post = fields.Boolean(string='POST',
- help="Select this to enable POST method"
- "while sending requests.")
- is_put = fields.Boolean(string='PUT',
- help="Select this to enable PUT method "
- "while sending requests.")
- is_delete = fields.Boolean(string='DELETE',
- help="Select this to enable DELETE method "
- "while sending requests.")
+ _description = 'REST API Configuration'
+ _rec_name = 'display_name'
+
+ model_id = fields.Many2one(
+ 'ir.model',
+ string="Model",
+ required=True,
+ ondelete='cascade',
+ domain="[('transient', '=', False)]",
+ help="Modelo que será accesible a través de la REST API."
+ )
+
+ display_name = fields.Char(
+ string="Name",
+ compute='_compute_display_name',
+ store=True
+ )
+
+ # Permisos de métodos HTTP
+ is_get = fields.Boolean(
+ string='GET (Read)',
+ default=True,
+ help="Permite operaciones de lectura (GET) en este modelo."
+ )
+
+ is_post = fields.Boolean(
+ string='POST (Create)',
+ default=False,
+ help="Permite operaciones de creación (POST) en este modelo."
+ )
+
+ is_put = fields.Boolean(
+ string='PUT (Update)',
+ default=False,
+ help="Permite operaciones de actualización (PUT) en este modelo."
+ )
+
+ is_delete = fields.Boolean(
+ string='DELETE',
+ default=False,
+ help="Permite operaciones de eliminación (DELETE) en este modelo."
+ )
+
+ # Configuraciones adicionales
+ active = fields.Boolean(
+ string="Active",
+ default=True,
+ help="Si está desactivado, el modelo no estará disponible en la API."
+ )
+
+ allowed_fields = fields.Text(
+ string="Allowed Fields",
+ help="Lista de campos permitidos separados por comas. Si está vacío, todos los campos son permitidos."
+ )
+
+ forbidden_fields = fields.Text(
+ string="Forbidden Fields",
+ default="__last_update,create_uid,create_date,write_uid,write_date",
+ help="Lista de campos prohibidos separados por comas."
+ )
+
+ max_records_limit = fields.Integer(
+ string="Max Records Limit",
+ default=1000,
+ help="Límite máximo de registros que se pueden obtener en una sola request GET."
+ )
+
+ require_record_id_for_write = fields.Boolean(
+ string="Require ID for Write Operations",
+ default=True,
+ help="Si está marcado, las operaciones PUT/DELETE requieren un ID específico."
+ )
+
+ # Campos informativos
+ api_endpoint = fields.Char(
+ string="API Endpoint",
+ compute='_compute_api_endpoint',
+ help="URL del endpoint de la API para este modelo."
+ )
+
+ description = fields.Text(
+ string="Description",
+ help="Descripción del propósito de esta configuración de API."
+ )
+
+ @api.depends('model_id')
+ def _compute_display_name(self):
+ """Calcula el nombre para mostrar"""
+ for record in self:
+ if record.model_id:
+ record.display_name = f"API: {record.model_id.name}"
+ else:
+ record.display_name = "API Configuration"
+
+ @api.depends('model_id')
+ def _compute_api_endpoint(self):
+ """Calcula la URL del endpoint de la API"""
+ for record in self:
+ if record.model_id:
+ base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url', 'http://localhost:8069')
+ record.api_endpoint = f"{base_url}/api/v1/{record.model_id.model}"
+ else:
+ record.api_endpoint = ""
+
+ @api.constrains('model_id')
+ def _check_unique_model(self):
+ """Valida que no haya configuraciones duplicadas para el mismo modelo"""
+ for record in self:
+ if record.model_id:
+ existing = self.search([
+ ('model_id', '=', record.model_id.id),
+ ('id', '!=', record.id)
+ ])
+ if existing:
+ raise ValidationError(
+ _("Ya existe una configuración de API para el modelo %s") % record.model_id.name
+ )
+
+ @api.constrains('max_records_limit')
+ def _check_max_records_limit(self):
+ """Valida el límite máximo de registros"""
+ for record in self:
+ if record.max_records_limit <= 0:
+ raise ValidationError(_("El límite máximo de registros debe ser mayor a 0"))
+ if record.max_records_limit > 10000:
+ raise ValidationError(_("El límite máximo de registros no puede exceder 10,000"))
+
+ def get_allowed_fields(self):
+ """Obtiene la lista de campos permitidos para este modelo"""
+ self.ensure_one()
+
+ if not self.allowed_fields:
+ # Si no hay campos específicos permitidos, obtener todos los campos del modelo
+ model_obj = self.env[self.model_id.model]
+ all_fields = list(model_obj._fields.keys())
+ else:
+ all_fields = [field.strip() for field in self.allowed_fields.split(',') if field.strip()]
+
+ # Remover campos prohibidos
+ forbidden = []
+ if self.forbidden_fields:
+ forbidden = [field.strip() for field in self.forbidden_fields.split(',') if field.strip()]
+
+ allowed = [field for field in all_fields if field not in forbidden]
+ return allowed
+
+ def get_forbidden_fields(self):
+ """Obtiene la lista de campos prohibidos"""
+ self.ensure_one()
+
+ if not self.forbidden_fields:
+ return []
+
+ return [field.strip() for field in self.forbidden_fields.split(',') if field.strip()]
+
+ def is_method_allowed(self, method):
+ """Verifica si un método HTTP está permitido"""
+ self.ensure_one()
+
+ if not self.active:
+ return False
+
+ method_map = {
+ 'GET': self.is_get,
+ 'POST': self.is_post,
+ 'PUT': self.is_put,
+ 'DELETE': self.is_delete
+ }
+
+ return method_map.get(method.upper(), False)
+
+ def action_test_api_endpoint(self):
+ """Acción para probar el endpoint de la API (útil para botón en vista)"""
+ self.ensure_one()
+
+ if not self.model_id:
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'message': _('No model selected'),
+ 'type': 'warning',
+ }
+ }
+
+ return {
+ 'type': 'ir.actions.act_url',
+ 'url': self.api_endpoint,
+ 'target': 'new',
+ }
+
+ @api.model
+ def get_api_statistics(self):
+ """Obtiene estadísticas de uso de la API"""
+ stats = {}
+
+ # Estadísticas por modelo
+ api_configs = self.search([('active', '=', True)])
+ stats['active_models'] = len(api_configs)
+ stats['total_models'] = len(self.search([]))
+
+ # Estadísticas de usuarios con API keys
+ users_with_keys = self.env['res.users'].search([('api_key', '!=', False)])
+ stats['users_with_api_keys'] = len(users_with_keys)
+ stats['total_api_requests'] = sum(users_with_keys.mapped('api_requests_count'))
+
+ return stats
+
+ def toggle_active(self):
+ """Alterna el estado activo de la configuración"""
+ for record in self:
+ record.active = not record.active
+
+ @api.model
+ def create_default_configurations(self):
+ """Crea configuraciones por defecto para modelos comunes"""
+ default_models = [
+ ('res.partner', {'is_get': True, 'is_post': True, 'is_put': True, 'is_delete': False}),
+ ('product.product', {'is_get': True, 'is_post': True, 'is_put': True, 'is_delete': False}),
+ ('sale.order', {'is_get': True, 'is_post': True, 'is_put': True, 'is_delete': False}),
+ ('account.move', {'is_get': True, 'is_post': False, 'is_put': False, 'is_delete': False}),
+ ]
+
+ created_configs = []
+ for model_name, config in default_models:
+ model_obj = self.env['ir.model'].search([('model', '=', model_name)], limit=1)
+ if model_obj:
+ existing = self.search([('model_id', '=', model_obj.id)])
+ if not existing:
+ api_config = self.create({
+ 'model_id': model_obj.id,
+ 'description': f'Default API configuration for {model_obj.name}',
+ **config
+ })
+ created_configs.append(api_config)
+
+ return created_configs
diff --git a/rest_api_odoo/models/res_users.py b/rest_api_odoo/models/res_users.py
index b12d6e674e..5704d9dd0f 100644
--- a/rest_api_odoo/models/res_users.py
+++ b/rest_api_odoo/models/res_users.py
@@ -1,10 +1,11 @@
-# -*- coding:utf-8 -*-
+# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies()
# Author: Ayana KP (odoo@cybrosys.com)
+# Modified by: Broigm - Improvements in API key management
#
# You can modify it under the terms of the GNU LESSER
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
@@ -20,25 +21,245 @@
#
#############################################################################
import uuid
-from odoo import fields, models
+import secrets
+import string
+import logging
+from datetime import datetime, timedelta
+from odoo import fields, models, api
+
+_logger = logging.getLogger(__name__)
class ResUsers(models.Model):
- """This class is used to inherit users and add api key generation"""
+ """Extensión del modelo de usuarios para gestión de API keys"""
_inherit = 'res.users'
- api_key = fields.Char(string="API Key", readonly=True,
- help="Api key for connecting with the "
- "Database.The key will be "
- "generated when authenticating "
- "rest api.")
+ api_key = fields.Char(
+ string="API Key",
+ readonly=True,
+ help="Clave API para autenticación en REST API. Se genera automáticamente."
+ )
+ api_key_expiry = fields.Datetime(
+ string="API Key Expiry",
+ help="Fecha de expiración de la API key (opcional)"
+ )
+ api_key_created = fields.Datetime(
+ string="API Key Created",
+ help="Fecha de creación de la API key"
+ )
+ api_key_last_used = fields.Datetime(
+ string="API Key Last Used",
+ help="Última vez que se usó la API key"
+ )
+ api_requests_count = fields.Integer(
+ string="API Requests Count",
+ default=0,
+ help="Contador de requests realizados con esta API key"
+ )
- def generate_api(self, username):
- """This function is used to generate api-key for each user"""
- users = self.env['res.users'].sudo().search([('login', '=', username)])
- if not users.api_key:
- users.api_key = str(uuid.uuid4())
- key = users.api_key
+ def generate_api_key(self, force_new=False):
+ """
+ Genera una nueva API key o devuelve la existente
+ Args:
+ force_new (bool): Fuerza la generación de una nueva key
+ Returns:
+ str: API key generada
+ """
+ self.ensure_one()
+
+ if not self.api_key or force_new:
+ try:
+ # Generar una API key más segura usando secrets si está disponible
+ alphabet = string.ascii_letters + string.digits
+ api_key = ''.join(secrets.choice(alphabet) for _ in range(64))
+ except (ImportError, AttributeError):
+ # Fallback usando uuid si secrets no está disponible
+ api_key = str(uuid.uuid4()).replace('-', '') + str(uuid.uuid4()).replace('-', '')[:32]
+
+ self.sudo().write({
+ 'api_key': api_key,
+ 'api_key_created': fields.Datetime.now(),
+ 'api_key_last_used': None,
+ 'api_requests_count': 0
+ })
+
+ return self.api_key
+
+ def regenerate_api_key(self):
+ """Regenera la API key (útil para botón en interfaz)"""
+ self.ensure_one()
+ return self.generate_api_key(force_new=True)
+
+ def revoke_api_key(self):
+ """Revoca la API key actual"""
+ self.ensure_one()
+ self.sudo().write({
+ 'api_key': False,
+ 'api_key_expiry': False,
+ 'api_key_created': False,
+ 'api_key_last_used': False
+ })
+ return True
+
+ def set_api_key_expiry(self, days=None):
+ """
+ Establece fecha de expiración para la API key
+ Args:
+ days (int): Días hasta la expiración (default: sin expiración)
+ """
+ self.ensure_one()
+ if days:
+ expiry_date = fields.Datetime.now() + timedelta(days=days)
+ self.sudo().write({'api_key_expiry': expiry_date})
else:
- key = users.api_key
- return key
+ self.sudo().write({'api_key_expiry': False})
+
+ def update_api_key_usage(self):
+ """Actualiza estadísticas de uso de la API key"""
+ self.ensure_one()
+ try:
+ self.sudo().write({
+ 'api_key_last_used': fields.Datetime.now(),
+ 'api_requests_count': self.api_requests_count + 1
+ })
+ except Exception as e:
+ _logger.warning(f"Could not update API key usage for user {self.id}: {str(e)}")
+
+ @api.model
+ def cleanup_expired_api_keys(self):
+ """Limpia API keys expiradas (para ejecutar en cron)"""
+ try:
+ expired_users = self.search([
+ ('api_key_expiry', '!=', False),
+ ('api_key_expiry', '<', fields.Datetime.now())
+ ])
+
+ for user in expired_users:
+ try:
+ user.revoke_api_key()
+ except Exception as e:
+ _logger.warning(f"Could not revoke API key for user {user.id}: {str(e)}")
+
+ return len(expired_users)
+ except Exception as e:
+ _logger.error(f"Error in cleanup_expired_api_keys: {str(e)}")
+ return 0
+
+ def is_api_key_valid(self):
+ """Verifica si la API key es válida y no ha expirado"""
+ self.ensure_one()
+
+ if not self.api_key:
+ return False
+
+ if self.api_key_expiry and self.api_key_expiry < fields.Datetime.now():
+ return False
+
+ return True
+
+ def action_generate_api_key(self):
+ """Acción para generar API key desde la interfaz"""
+ self.ensure_one()
+ try:
+ api_key = self.generate_api_key()
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'message': f'API Key generada exitosamente: {api_key}',
+ 'type': 'success',
+ 'sticky': True,
+ }
+ }
+ except Exception as e:
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'message': f'Error generando API Key: {str(e)}',
+ 'type': 'danger',
+ 'sticky': True,
+ }
+ }
+
+ def action_regenerate_api_key(self):
+ """Acción para regenerar API key desde la interfaz"""
+ self.ensure_one()
+ try:
+ api_key = self.regenerate_api_key()
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'message': f'API Key regenerada exitosamente: {api_key}',
+ 'type': 'success',
+ 'sticky': True,
+ }
+ }
+ except Exception as e:
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'message': f'Error regenerando API Key: {str(e)}',
+ 'type': 'danger',
+ 'sticky': True,
+ }
+ }
+
+ def action_revoke_api_key(self):
+ """Acción para revocar API key desde la interfaz"""
+ self.ensure_one()
+ try:
+ self.revoke_api_key()
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'message': 'API Key revocada exitosamente',
+ 'type': 'warning',
+ 'sticky': False,
+ }
+ }
+ except Exception as e:
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'message': f'Error revocando API Key: {str(e)}',
+ 'type': 'danger',
+ 'sticky': True,
+ }
+ }
+
+ # Método legacy para compatibilidad con código anterior
+ def generate_api(self, username):
+ """Método de compatibilidad con la versión anterior"""
+ return self.generate_api_key()
+
+ @api.model
+ def get_api_statistics(self):
+ """Obtiene estadísticas de uso de API keys"""
+ try:
+ users_with_keys = self.search([('api_key', '!=', False)])
+ active_keys = users_with_keys.filtered(lambda u: u.is_api_key_valid())
+ expired_keys = users_with_keys.filtered(lambda u: not u.is_api_key_valid())
+
+ total_requests = sum(users_with_keys.mapped('api_requests_count'))
+
+ return {
+ 'total_users_with_keys': len(users_with_keys),
+ 'active_keys': len(active_keys),
+ 'expired_keys': len(expired_keys),
+ 'total_api_requests': total_requests,
+ 'average_requests_per_user': total_requests / len(users_with_keys) if users_with_keys else 0
+ }
+ except Exception as e:
+ _logger.error(f"Error getting API statistics: {str(e)}")
+ return {
+ 'total_users_with_keys': 0,
+ 'active_keys': 0,
+ 'expired_keys': 0,
+ 'total_api_requests': 0,
+ 'average_requests_per_user': 0
+ }
diff --git a/rest_api_odoo/requirements.txt b/rest_api_odoo/requirements.txt
new file mode 100644
index 0000000000..3f0b7dd421
--- /dev/null
+++ b/rest_api_odoo/requirements.txt
@@ -0,0 +1 @@
+PyJWT>=2.8.0
\ No newline at end of file
diff --git a/rest_api_odoo/security/ir.model.access.csv b/rest_api_odoo/security/ir.model.access.csv
index 042bd737cc..86bf3e69a6 100644
--- a/rest_api_odoo/security/ir.model.access.csv
+++ b/rest_api_odoo/security/ir.model.access.csv
@@ -1,2 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_connection_api_user,access.connection.api.user,model_connection_api,,1,1,1,1
+access_connection_api_user,access_connection_api_user,model_connection_api,base.group_user,1,0,0,0
+access_connection_api_manager,access_connection_api_manager,model_connection_api,base.group_system,1,1,1,1
+access_connection_api_all,access_connection_api_all,model_connection_api,,1,1,1,1
diff --git a/rest_api_odoo/tests/README_TESTS.md b/rest_api_odoo/tests/README_TESTS.md
new file mode 100644
index 0000000000..ed81f3df4c
--- /dev/null
+++ b/rest_api_odoo/tests/README_TESTS.md
@@ -0,0 +1,260 @@
+# 🧪 Tests Unitarios - REST API Odoo
+
+Este directorio contiene una suite completa de tests unitarios para verificar el funcionamiento del módulo REST API de Odoo.
+
+## 📁 Estructura de Tests
+
+```
+tests/
+├── __init__.py # Inicializador del paquete de tests
+├── conftest.py # Configuración de pytest y fixtures
+├── test_runner.py # Script ejecutable para correr tests
+├── test_rest_api_auth.py # Tests de autenticación JWT
+├── test_rest_api_cors.py # Tests de CORS y OPTIONS
+├── test_rest_api_crud.py # Tests de operaciones CRUD
+├── test_rest_api_errors.py # Tests de manejo de errores
+└── README_TESTS.md # Esta documentación
+```
+
+## 🚀 Métodos de Ejecución
+
+### 1. **Usando el Framework de Odoo (Recomendado)**
+
+```bash
+# Navegar al directorio de Odoo
+cd /path/to/odoo
+
+# Ejecutar todos los tests del módulo
+inv test --modules rest_api_odoo
+
+# O usando odoo-bin directamente
+python3 odoo-bin --test-enable --test-tags rest_api_odoo --stop-after-init
+```
+
+### 2. **Usando el Script Test Runner**
+
+```bash
+# Navegar al directorio del módulo
+cd odoo/custom/src/cybroaddons/rest_api_odoo
+
+# Ejecutar todos los tests
+./tests/test_runner.py
+
+# Ejecutar test específico
+./tests/test_runner.py --module test_rest_api_auth
+
+# Ejecutar con salida verbose
+./tests/test_runner.py --verbose
+
+# Ejecutar con coverage
+./tests/test_runner.py --coverage
+
+# Usar framework de Odoo
+./tests/test_runner.py --odoo
+```
+
+### 3. **Usando pytest Directamente**
+
+```bash
+# Instalar dependencias de testing
+pip install pytest pytest-cov requests
+
+# Ejecutar todos los tests
+cd tests/
+pytest -v
+
+# Ejecutar test específico
+pytest test_rest_api_auth.py -v
+
+# Ejecutar con coverage
+pytest --cov=../controllers --cov-report=term-missing
+
+# Ejecutar solo tests rápidos
+pytest -m "not slow"
+```
+
+### 4. **Usando el entorno Doodba**
+
+```bash
+# Desde el directorio raíz del proyecto
+inv test --cur-file /odoo/custom/src/cybroaddons/rest_api_odoo/tests/test_rest_api_auth.py
+
+# O para todos los tests del módulo
+inv test --modules rest_api_odoo
+```
+
+## 📊 Tipos de Tests Incluidos
+
+### 🔐 **Tests de Autenticación** (`test_rest_api_auth.py`)
+- ✅ Autenticación exitosa con credenciales válidas
+- ✅ Autenticación fallida con credenciales inválidas
+- ✅ Manejo de datos faltantes o JSON inválido
+- ✅ Validación de JWT tokens
+- ✅ Manejo de tokens expirados
+- ✅ Endpoint de refresh token
+- ✅ Health check endpoint
+- ✅ Listado de modelos disponibles
+
+### 🌐 **Tests de CORS** (`test_rest_api_cors.py`)
+- ✅ Headers CORS en respuestas de autenticación
+- ✅ Peticiones OPTIONS para preflight
+- ✅ Headers CORS en respuestas de API
+- ✅ Headers CORS en respuestas de error
+- ✅ Compatibilidad con axios
+- ✅ Headers de autenticación alternativos
+- ✅ Exposición correcta de headers
+
+### 📝 **Tests de CRUD** (`test_rest_api_crud.py`)
+- ✅ GET: Obtener todos los registros
+- ✅ GET: Obtener registro específico
+- ✅ GET: Filtro por campos específicos
+- ✅ GET: Filtro con domain
+- ✅ GET: Paginación (limit/offset)
+- ✅ GET: Ordenamiento
+- ✅ POST: Crear nuevos registros
+- ✅ PUT: Actualizar registros existentes
+- ✅ DELETE: Eliminar registros
+- ✅ Manejo de métodos no permitidos
+- ✅ Acceso a modelos no configurados
+
+### 🚨 **Tests de Errores** (`test_rest_api_errors.py`)
+- ✅ Falta de token de autenticación
+- ✅ Tokens inválidos o mal formados
+- ✅ Modelos no existentes
+- ✅ Métodos HTTP no permitidos
+- ✅ JSON inválido en requests
+- ✅ Datos faltantes en POST/PUT
+- ✅ Registros no encontrados
+- ✅ Errores de validación
+- ✅ Headers CORS en errores
+- ✅ Manejo de errores internos
+
+## 🔧 Configuración Pre-Tests
+
+### 1. **Asegurar que PyJWT esté instalado:**
+```bash
+pip install PyJWT>=2.8.0
+```
+
+### 2. **Verificar que el módulo esté instalado en Odoo:**
+```bash
+# Instalar/actualizar el módulo
+inv install --modules rest_api_odoo
+
+# O usando interface web de Odoo
+# Apps > rest_api_odoo > Install/Upgrade
+```
+
+### 3. **Configurar modelo de prueba (automático):**
+Los tests automáticamente crean configuraciones de API para `res.partner` y `res.users` durante el setup.
+
+## 📈 Interpretación de Resultados
+
+### ✅ **Test Exitoso:**
+```
+test_rest_api_auth.py::TestRestApiAuth::test_auth_endpoint_success PASSED
+```
+
+### ❌ **Test Fallido:**
+```
+test_rest_api_auth.py::TestRestApiAuth::test_auth_endpoint_success FAILED
+FAILED test_rest_api_auth.py::TestRestApiAuth::test_auth_endpoint_success - AssertionError: ...
+```
+
+### 📊 **Reporte de Coverage:**
+```
+controllers/rest_api_odoo.py 95% 12-15, 67
+controllers/jwt_auth.py 87% 143-145
+```
+
+## 🐛 Troubleshooting
+
+### **Error: "PyJWT not found"**
+```bash
+pip install PyJWT>=2.8.0
+```
+
+### **Error: "Database does not exist"**
+```bash
+# Crear base de datos de test
+inv resetdb --dbname test
+```
+
+### **Error: "Module not installed"**
+```bash
+inv install --modules rest_api_odoo
+```
+
+### **Error: "Authentication failed"**
+```bash
+# Verificar que el usuario admin existe y tiene la contraseña correcta
+# Los tests usan admin/admin por defecto
+```
+
+### **Error: "CORS headers missing"**
+```bash
+# Verificar que las correcciones de CORS se aplicaron correctamente
+# Revisar el archivo rest_api_odoo.py línea 20-27
+```
+
+## 🎯 Coverage Objetivo
+
+El objetivo es mantener **>90% de coverage** en:
+- `controllers/rest_api_odoo.py`
+- `controllers/jwt_auth.py`
+
+## 🔄 Integración Continua
+
+Para usar en CI/CD, agregar al pipeline:
+
+```yaml
+# .gitlab-ci.yml o .github/workflows/tests.yml
+test_rest_api:
+ script:
+ - pip install PyJWT pytest pytest-cov
+ - inv test --modules rest_api_odoo
+ coverage: '/TOTAL.*\\s+(\\d+%)$/'
+```
+
+## 📝 Agregar Nuevos Tests
+
+Para agregar nuevos tests:
+
+1. **Crear archivo de test:**
+ ```python
+ # tests/test_nueva_funcionalidad.py
+ from odoo.tests.common import HttpCase
+
+ class TestNuevaFuncionalidad(HttpCase):
+ def test_nueva_funcion(self):
+ # Tu test aquí
+ pass
+ ```
+
+2. **Agregar al __init__.py:**
+ ```python
+ from . import test_nueva_funcionalidad
+ ```
+
+3. **Ejecutar el nuevo test:**
+ ```bash
+ ./tests/test_runner.py --module test_nueva_funcionalidad
+ ```
+
+## 🎉 Ejecución Exitosa
+
+Una ejecución completa exitosa debería mostrar:
+
+```
+========= test session starts =========
+collected 45 items
+
+test_rest_api_auth.py ........... [24%]
+test_rest_api_cors.py ........... [48%]
+test_rest_api_crud.py ........... [71%]
+test_rest_api_errors.py ......... [100%]
+
+========= 45 passed in 12.34s =========
+```
+
+¡Con estos tests puedes verificar completamente que todas las correcciones funcionan correctamente! 🚀
\ No newline at end of file
diff --git a/rest_api_odoo/tests/__init__.py b/rest_api_odoo/tests/__init__.py
new file mode 100644
index 0000000000..33e3140732
--- /dev/null
+++ b/rest_api_odoo/tests/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+from . import test_rest_api_auth
+from . import test_rest_api_cors
+from . import test_rest_api_crud
+from . import test_rest_api_errors
\ No newline at end of file
diff --git a/rest_api_odoo/tests/conftest.py b/rest_api_odoo/tests/conftest.py
new file mode 100644
index 0000000000..c909823922
--- /dev/null
+++ b/rest_api_odoo/tests/conftest.py
@@ -0,0 +1,132 @@
+# -*- coding: utf-8 -*-
+"""
+Configuración de pytest para tests de REST API
+"""
+
+import pytest
+import os
+import sys
+
+# Agregar el directorio del módulo al path
+module_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+sys.path.insert(0, module_dir)
+
+
+@pytest.fixture(scope="session")
+def odoo_env():
+ """
+ Fixture para configurar el entorno de Odoo para tests
+ """
+ # Esta fixture se puede usar si se ejecutan tests fuera del framework de Odoo
+ pass
+
+
+@pytest.fixture
+def api_client():
+ """
+ Fixture para cliente HTTP de pruebas
+ """
+ import requests
+
+ class ApiClient:
+ def __init__(self, base_url="http://localhost:8069/api/v1"):
+ self.base_url = base_url
+ self.session = requests.Session()
+ self.token = None
+
+ def authenticate(self, username="admin", password="admin", database="test"):
+ """Autenticar y obtener token"""
+ auth_data = {
+ 'username': username,
+ 'password': password,
+ 'database': database
+ }
+
+ response = self.session.post(
+ f"{self.base_url}/auth",
+ json=auth_data
+ )
+
+ if response.status_code == 200:
+ data = response.json()
+ self.token = data['data']['access_token']
+ self.session.headers.update({
+ 'Authorization': f'Bearer {self.token}'
+ })
+ return True
+ return False
+
+ def get(self, endpoint, **kwargs):
+ """GET request"""
+ return self.session.get(f"{self.base_url}/{endpoint}", **kwargs)
+
+ def post(self, endpoint, **kwargs):
+ """POST request"""
+ return self.session.post(f"{self.base_url}/{endpoint}", **kwargs)
+
+ def put(self, endpoint, **kwargs):
+ """PUT request"""
+ return self.session.put(f"{self.base_url}/{endpoint}", **kwargs)
+
+ def delete(self, endpoint, **kwargs):
+ """DELETE request"""
+ return self.session.delete(f"{self.base_url}/{endpoint}", **kwargs)
+
+ def options(self, endpoint, **kwargs):
+ """OPTIONS request"""
+ return self.session.options(f"{self.base_url}/{endpoint}", **kwargs)
+
+ return ApiClient
+
+
+@pytest.fixture
+def sample_partner_data():
+ """
+ Fixture con datos de ejemplo para partners
+ """
+ return {
+ 'values': {
+ 'name': 'Test Partner',
+ 'email': 'test@example.com',
+ 'phone': '123456789',
+ 'is_company': False,
+ 'street': '123 Test Street',
+ 'city': 'Test City',
+ 'zip': '12345'
+ }
+ }
+
+
+@pytest.fixture
+def jwt_secret():
+ """
+ Fixture con clave secreta JWT para tests
+ """
+ return "test_jwt_secret_key_for_tests_only"
+
+
+# Configuración de pytest
+def pytest_configure(config):
+ """
+ Configuración global de pytest
+ """
+ # Agregar marcadores personalizados
+ config.addinivalue_line(
+ "markers", "slow: marca tests como lentos"
+ )
+ config.addinivalue_line(
+ "markers", "integration: marca tests de integración"
+ )
+ config.addinivalue_line(
+ "markers", "unit: marca tests unitarios"
+ )
+
+
+def pytest_collection_modifyitems(config, items):
+ """
+ Modificar items de la colección de tests
+ """
+ # Agregar marcador 'slow' a tests que tomen más tiempo
+ for item in items:
+ if "integration" in item.nodeid:
+ item.add_marker(pytest.mark.slow)
\ No newline at end of file
diff --git a/rest_api_odoo/tests/test_rest_api_auth.py b/rest_api_odoo/tests/test_rest_api_auth.py
new file mode 100644
index 0000000000..da0781450e
--- /dev/null
+++ b/rest_api_odoo/tests/test_rest_api_auth.py
@@ -0,0 +1,269 @@
+# -*- coding: utf-8 -*-
+import json
+import jwt
+from unittest.mock import patch, MagicMock
+from odoo.tests import TransactionCase
+from odoo.tests.common import HttpCase
+from odoo import http
+
+
+class TestRestApiAuth(HttpCase):
+ """Tests para autenticación JWT de la REST API"""
+
+ def setUp(self):
+ super().setUp()
+ self.api_base_url = '/api/v1'
+ self.admin_user = self.env.ref('base.user_admin')
+ self.demo_user = self.env.ref('base.user_demo')
+
+ # Limpiar configuraciones existentes de API para res.users
+ model_users = self.env['ir.model'].search([('model', '=', 'res.users')], limit=1)
+ existing_configs = self.env['connection.api'].search([('model_id', '=', model_users.id)])
+ if existing_configs:
+ existing_configs.unlink()
+
+ # Crear configuración de API para res.users
+ self.api_config = self.env['connection.api'].create({
+ 'model_id': model_users.id,
+ 'active': True,
+ 'is_get': True,
+ 'is_post': True,
+ 'is_put': True,
+ 'is_delete': False,
+ 'max_records_limit': 100
+ })
+
+ def test_auth_endpoint_success(self):
+ """Test autenticación exitosa"""
+ auth_data = {
+ 'username': 'admin',
+ 'password': 'admin',
+ 'database': self.env.cr.dbname,
+ 'expires_in_hours': 24
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/auth',
+ data=json.dumps(auth_data).encode('utf-8'),
+ headers={'Content-Type': 'application/json'}
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+ self.assertIn('data', response_data)
+ self.assertIn('access_token', response_data['data'])
+ self.assertIn('user_id', response_data['data'])
+ self.assertEqual(response_data['data']['username'], 'admin')
+ self.assertEqual(response_data['data']['token_type'], 'Bearer')
+
+ def test_auth_endpoint_invalid_credentials(self):
+ """Test autenticación con credenciales inválidas"""
+ auth_data = {
+ 'username': 'admin',
+ 'password': 'wrong_password',
+ 'database': self.env.cr.dbname
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/auth',
+ data=json.dumps(auth_data).encode('utf-8'),
+ headers={'Content-Type': 'application/json'}
+ )
+
+ self.assertEqual(response.status_code, 401)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('Credenciales inválidas', response_data.get('message', ''))
+
+ def test_auth_endpoint_missing_data(self):
+ """Test autenticación sin datos requeridos"""
+ auth_data = {
+ 'username': 'admin'
+ # password faltante
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/auth',
+ data=json.dumps(auth_data).encode('utf-8'),
+ headers={'Content-Type': 'application/json'}
+ )
+
+ self.assertEqual(response.status_code, 400)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('Username y password son requeridos', response_data.get('message', ''))
+
+ def test_auth_endpoint_invalid_json(self):
+ """Test autenticación con JSON inválido"""
+ response = self.url_open(
+ f'{self.api_base_url}/auth',
+ data=b'invalid json data',
+ headers={'Content-Type': 'application/json'}
+ )
+
+ self.assertEqual(response.status_code, 400)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('JSON inválido', response_data.get('message', ''))
+
+ def test_jwt_token_validation(self):
+ """Test validación de JWT token"""
+ # Primero obtener un token válido
+ auth_data = {
+ 'username': 'admin',
+ 'password': 'admin',
+ 'database': self.env.cr.dbname
+ }
+
+ auth_response = self.url_open(
+ f'{self.api_base_url}/auth',
+ data=json.dumps(auth_data).encode('utf-8'),
+ headers={'Content-Type': 'application/json'}
+ )
+
+ auth_data_response = json.loads(auth_response.content.decode('utf-8'))
+ token = auth_data_response['data']['access_token']
+
+ # Usar el token para hacer una petición
+ response = self.url_open(
+ f'{self.api_base_url}/res.users',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+ self.assertTrue(response_data.get('success'))
+
+ def test_expired_token(self):
+ """Test con token expirado"""
+ # Crear un token expirado manualmente
+ from datetime import datetime, timedelta
+ from odoo.addons.rest_api_odoo.controllers.jwt_auth import JWTAuthMixin
+
+ jwt_mixin = JWTAuthMixin()
+ secret = jwt_mixin._get_jwt_secret()
+
+ # Token que expira en el pasado
+ expired_payload = {
+ 'user_id': self.admin_user.id,
+ 'iat': datetime.utcnow() - timedelta(hours=25),
+ 'exp': datetime.utcnow() - timedelta(hours=1),
+ 'iss': 'odoo-rest-api',
+ 'aud': 'odoo-client'
+ }
+
+ expired_token = jwt.encode(expired_payload, secret, algorithm='HS256')
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.users',
+ headers={
+ 'Authorization': f'Bearer {expired_token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 401)
+ response_data = json.loads(response.content.decode('utf-8'))
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('Token expirado', response_data.get('message', ''))
+
+ def test_refresh_token_endpoint(self):
+ """Test endpoint de refresh token"""
+ # Primero obtener un token válido
+ auth_data = {
+ 'username': 'admin',
+ 'password': 'admin',
+ 'database': self.env.cr.dbname
+ }
+
+ auth_response = self.url_open(
+ f'{self.api_base_url}/auth',
+ data=json.dumps(auth_data).encode('utf-8'),
+ headers={'Content-Type': 'application/json'}
+ )
+
+ auth_data_response = json.loads(auth_response.content.decode('utf-8'))
+ original_token = auth_data_response['data']['access_token']
+
+ # Refrescar el token
+ refresh_data = {'expires_in_hours': 48}
+
+ refresh_response = self.url_open(
+ f'{self.api_base_url}/refresh',
+ data=json.dumps(refresh_data).encode('utf-8'),
+ headers={
+ 'Authorization': f'Bearer {original_token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(refresh_response.status_code, 200)
+ refresh_data_response = json.loads(refresh_response.content.decode('utf-8'))
+
+ self.assertTrue(refresh_data_response.get('success'))
+ self.assertIn('access_token', refresh_data_response['data'])
+ self.assertNotEqual(
+ original_token,
+ refresh_data_response['data']['access_token']
+ )
+
+ def test_health_check_endpoint(self):
+ """Test endpoint de health check"""
+ response = self.url_open(f'{self.api_base_url}/health')
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertEqual(response_data.get('status'), 'healthy')
+ self.assertIn('database', response_data)
+ self.assertIn('active_models', response_data)
+ self.assertIn('jwt_configured', response_data)
+ self.assertTrue(response_data.get('jwt_configured'))
+
+ def test_models_list_endpoint(self):
+ """Test endpoint de listado de modelos disponibles"""
+ # Primero autenticarse
+ auth_data = {
+ 'username': 'admin',
+ 'password': 'admin',
+ 'database': self.env.cr.dbname
+ }
+
+ auth_response = self.url_open(
+ f'{self.api_base_url}/auth',
+ data=json.dumps(auth_data).encode('utf-8'),
+ headers={'Content-Type': 'application/json'}
+ )
+
+ auth_data_response = json.loads(auth_response.content.decode('utf-8'))
+ token = auth_data_response['data']['access_token']
+
+ # Obtener lista de modelos
+ response = self.url_open(
+ f'{self.api_base_url}/models',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+ self.assertIn('data', response_data)
+ self.assertIn('documentation', response_data)
+ self.assertIn('authentication', response_data)
+
+ # Verificar que nuestro modelo de test está en la lista
+ models = response_data['data']
+ model_names = [model['model'] for model in models]
+ self.assertIn('res.users', model_names)
\ No newline at end of file
diff --git a/rest_api_odoo/tests/test_rest_api_cors.py b/rest_api_odoo/tests/test_rest_api_cors.py
new file mode 100644
index 0000000000..7fbd965330
--- /dev/null
+++ b/rest_api_odoo/tests/test_rest_api_cors.py
@@ -0,0 +1,246 @@
+# -*- coding: utf-8 -*-
+import json
+from odoo.tests.common import HttpCase
+
+
+class TestRestApiCors(HttpCase):
+ """Tests para soporte CORS de la REST API"""
+
+ def setUp(self):
+ super().setUp()
+ self.api_base_url = '/api/v1'
+
+ # Limpiar configuraciones existentes de API para res.partner
+ model_partner = self.env['ir.model'].search([('model', '=', 'res.partner')], limit=1)
+ existing_configs = self.env['connection.api'].search([('model_id', '=', model_partner.id)])
+ if existing_configs:
+ existing_configs.unlink()
+
+ # Crear configuración de API para res.partner
+ self.api_config = self.env['connection.api'].create({
+ 'model_id': model_partner.id,
+ 'active': True,
+ 'is_get': True,
+ 'is_post': True,
+ 'is_put': True,
+ 'is_delete': True,
+ 'max_records_limit': 100
+ })
+
+ def _get_auth_token(self):
+ """Helper para obtener token de autenticación"""
+ auth_data = {
+ 'username': 'admin',
+ 'password': 'admin',
+ 'database': self.env.cr.dbname
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/auth',
+ data=json.dumps(auth_data).encode('utf-8'),
+ headers={'Content-Type': 'application/json'}
+ )
+
+ response_data = json.loads(response.content.decode('utf-8'))
+ return response_data['data']['access_token']
+
+ def test_cors_headers_in_auth_response(self):
+ """Test que las respuestas de auth incluyen headers CORS"""
+ auth_data = {
+ 'username': 'admin',
+ 'password': 'admin',
+ 'database': self.env.cr.dbname
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/auth',
+ data=json.dumps(auth_data).encode('utf-8'),
+ headers={'Content-Type': 'application/json'}
+ )
+
+ # Verificar headers CORS
+ self.assertIn('Access-Control-Allow-Origin', response.headers)
+ self.assertEqual(response.headers['Access-Control-Allow-Origin'], '*')
+
+ self.assertIn('Access-Control-Allow-Methods', response.headers)
+ self.assertIn('GET', response.headers['Access-Control-Allow-Methods'])
+ self.assertIn('POST', response.headers['Access-Control-Allow-Methods'])
+
+ self.assertIn('Access-Control-Allow-Headers', response.headers)
+ self.assertIn('Authorization', response.headers['Access-Control-Allow-Headers'])
+
+ def test_options_preflight_auth_endpoint(self):
+ """Test petición OPTIONS al endpoint de autenticación"""
+ response = self.opener.options(f'{self.api_base_url}/auth')
+
+ self.assertEqual(response.status_code, 200)
+
+ # Verificar headers CORS específicos para preflight
+ self.assertIn('Access-Control-Allow-Origin', response.headers)
+ self.assertEqual(response.headers['Access-Control-Allow-Origin'], '*')
+
+ self.assertIn('Access-Control-Allow-Methods', response.headers)
+ methods = response.headers['Access-Control-Allow-Methods']
+ self.assertIn('POST', methods)
+ self.assertIn('OPTIONS', methods)
+
+ self.assertIn('Access-Control-Allow-Headers', response.headers)
+ headers = response.headers['Access-Control-Allow-Headers']
+ self.assertIn('Content-Type', headers)
+ self.assertIn('Authorization', headers)
+
+ self.assertIn('Access-Control-Max-Age', response.headers)
+
+ def test_options_preflight_api_endpoint(self):
+ """Test petición OPTIONS a endpoint de API"""
+ response = self.opener.options(f'{self.api_base_url}/res.partner')
+
+ self.assertEqual(response.status_code, 200)
+
+ # Verificar headers CORS
+ self.assertIn('Access-Control-Allow-Origin', response.headers)
+ self.assertIn('Access-Control-Allow-Methods', response.headers)
+ self.assertIn('Access-Control-Allow-Headers', response.headers)
+
+ methods = response.headers['Access-Control-Allow-Methods']
+ self.assertIn('GET', methods)
+ self.assertIn('POST', methods)
+ self.assertIn('PUT', methods)
+ self.assertIn('DELETE', methods)
+ self.assertIn('OPTIONS', methods)
+
+ def test_cors_headers_in_api_responses(self):
+ """Test que las respuestas de API incluyen headers CORS"""
+ token = self._get_auth_token()
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+
+ # Verificar headers CORS en respuesta de datos
+ self.assertIn('Access-Control-Allow-Origin', response.headers)
+ self.assertEqual(response.headers['Access-Control-Allow-Origin'], '*')
+
+ self.assertIn('Access-Control-Allow-Methods', response.headers)
+ self.assertIn('Access-Control-Allow-Headers', response.headers)
+
+ def test_cors_headers_in_error_responses(self):
+ """Test que las respuestas de error incluyen headers CORS"""
+ # Petición sin token (debe fallar con 401)
+ response = self.url_open(f'{self.api_base_url}/res.partner')
+
+ self.assertEqual(response.status_code, 401)
+
+ # Verificar que incluso las respuestas de error tienen headers CORS
+ self.assertIn('Access-Control-Allow-Origin', response.headers)
+ self.assertEqual(response.headers['Access-Control-Allow-Origin'], '*')
+
+ def test_cors_with_custom_origin(self):
+ """Test CORS con header Origin personalizado"""
+ token = self._get_auth_token()
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json',
+ 'Origin': 'https://example.com'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+
+ # Verificar que permite cualquier origen
+ self.assertIn('Access-Control-Allow-Origin', response.headers)
+ self.assertEqual(response.headers['Access-Control-Allow-Origin'], '*')
+
+ def test_axios_compatible_headers(self):
+ """Test compatibilidad con headers típicos de axios"""
+ token = self._get_auth_token()
+
+ # Headers típicos que envía axios
+ axios_headers = {
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json',
+ 'Accept': '*/*',
+ 'User-Agent': 'axios/1.12.2',
+ 'Accept-Encoding': 'gzip, compress, deflate, br'
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ headers=axios_headers
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+ self.assertTrue(response_data.get('success'))
+
+ def test_alternative_auth_headers(self):
+ """Test headers de autenticación alternativos (X-API-Key, api-key)"""
+ token = self._get_auth_token()
+
+ # Test con X-API-Key
+ response1 = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ headers={
+ 'X-API-Key': token,
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response1.status_code, 200)
+
+ # Test con api-key
+ response2 = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ headers={
+ 'api-key': token,
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response2.status_code, 200)
+
+ def test_options_with_custom_headers(self):
+ """Test OPTIONS con headers personalizados en preflight"""
+ headers = {
+ 'Access-Control-Request-Method': 'POST',
+ 'Access-Control-Request-Headers': 'Content-Type, Authorization, X-Custom-Header',
+ 'Origin': 'https://example.com'
+ }
+
+ response = self.opener.options(f'{self.api_base_url}/auth', headers=headers)
+
+ self.assertEqual(response.status_code, 200)
+
+ # Verificar que responde adecuadamente a preflight complejo
+ self.assertIn('Access-Control-Allow-Origin', response.headers)
+ self.assertIn('Access-Control-Allow-Methods', response.headers)
+ self.assertIn('Access-Control-Allow-Headers', response.headers)
+
+ def test_cors_expose_headers(self):
+ """Test que se exponen los headers correctos"""
+ token = self._get_auth_token()
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+
+ # Verificar Access-Control-Expose-Headers
+ self.assertIn('Access-Control-Expose-Headers', response.headers)
+ exposed_headers = response.headers['Access-Control-Expose-Headers']
+ self.assertIn('Content-Type', exposed_headers)
+ self.assertIn('Authorization', exposed_headers)
\ No newline at end of file
diff --git a/rest_api_odoo/tests/test_rest_api_crud.py b/rest_api_odoo/tests/test_rest_api_crud.py
new file mode 100644
index 0000000000..3e95e7a989
--- /dev/null
+++ b/rest_api_odoo/tests/test_rest_api_crud.py
@@ -0,0 +1,376 @@
+# -*- coding: utf-8 -*-
+import json
+from odoo.tests.common import HttpCase
+
+
+class TestRestApiCrud(HttpCase):
+ """Tests para operaciones CRUD de la REST API"""
+
+ def setUp(self):
+ super().setUp()
+ self.api_base_url = '/api/v1'
+
+ # Limpiar configuraciones existentes de API para res.partner
+ model_partner = self.env['ir.model'].search([('model', '=', 'res.partner')], limit=1)
+ existing_configs = self.env['connection.api'].search([('model_id', '=', model_partner.id)])
+ if existing_configs:
+ existing_configs.unlink()
+
+ # Crear configuración de API para res.partner
+ self.api_config = self.env['connection.api'].create({
+ 'model_id': model_partner.id,
+ 'active': True,
+ 'is_get': True,
+ 'is_post': True,
+ 'is_put': True,
+ 'is_delete': True,
+ 'max_records_limit': 100
+ })
+
+ # Crear algunos partners de prueba
+ self.test_partner1 = self.env['res.partner'].create({
+ 'name': 'Test Partner 1',
+ 'email': 'test1@example.com',
+ 'phone': '123456789',
+ 'is_company': False
+ })
+
+ self.test_partner2 = self.env['res.partner'].create({
+ 'name': 'Test Partner 2',
+ 'email': 'test2@example.com',
+ 'phone': '987654321',
+ 'is_company': True
+ })
+
+ def _get_auth_token(self):
+ """Helper para obtener token de autenticación"""
+ auth_data = {
+ 'username': 'admin',
+ 'password': 'admin',
+ 'database': self.env.cr.dbname
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/auth',
+ data=json.dumps(auth_data).encode('utf-8'),
+ headers={'Content-Type': 'application/json'}
+ )
+
+ response_data = json.loads(response.content.decode('utf-8'))
+ return response_data['data']['access_token']
+
+ def test_get_all_records(self):
+ """Test GET para obtener todos los registros"""
+ token = self._get_auth_token()
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+ self.assertIn('data', response_data)
+ self.assertIn('count', response_data)
+ self.assertIsInstance(response_data['data'], list)
+ self.assertGreater(response_data['count'], 0)
+
+ def test_get_specific_record(self):
+ """Test GET para obtener un registro específico"""
+ token = self._get_auth_token()
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner/{self.test_partner1.id}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+ self.assertEqual(response_data['count'], 1)
+
+ partner_data = response_data['data'][0]
+ self.assertEqual(partner_data['id'], self.test_partner1.id)
+
+ def test_get_with_fields_filter(self):
+ """Test GET con filtro de campos específicos"""
+ token = self._get_auth_token()
+
+ # Solo solicitar campos específicos
+ params = 'fields=id,name,email'
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner?{params}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+
+ if response_data['data']:
+ partner_data = response_data['data'][0]
+ # Verificar que solo tiene los campos solicitados (más id siempre presente)
+ expected_fields = {'id', 'name', 'email'}
+ actual_fields = set(partner_data.keys())
+ # Los campos solicitados deben estar presentes
+ self.assertTrue(expected_fields.issubset(actual_fields))
+
+ def test_get_with_domain_filter(self):
+ """Test GET con filtro de dominio"""
+ token = self._get_auth_token()
+
+ # Filtrar por companies
+ domain = json.dumps([('is_company', '=', True)])
+ params = f'domain={domain}'
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner?{params}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+ # Debería encontrar al menos nuestro test_partner2 que es company
+ self.assertGreater(response_data['count'], 0)
+
+ def test_get_with_pagination(self):
+ """Test GET con paginación"""
+ token = self._get_auth_token()
+
+ # Primera página
+ params = 'limit=1&offset=0'
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner?{params}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+ self.assertEqual(response_data['count'], 1)
+ self.assertIn('limit', response_data)
+ self.assertIn('offset', response_data)
+ self.assertEqual(response_data['limit'], 1)
+ self.assertEqual(response_data['offset'], 0)
+
+ def test_post_create_record(self):
+ """Test POST para crear un nuevo registro"""
+ token = self._get_auth_token()
+
+ new_partner_data = {
+ 'values': {
+ 'name': 'New Test Partner',
+ 'email': 'newtest@example.com',
+ 'phone': '555666777',
+ 'is_company': False
+ }
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ data=json.dumps(new_partner_data).encode('utf-8'),
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 201)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+ self.assertIn('data', response_data)
+ self.assertEqual(response_data['count'], 1)
+
+ # Verificar que el registro fue creado
+ created_partner = response_data['data'][0]
+ self.assertEqual(created_partner['name'], 'New Test Partner')
+
+ # Limpiar: eliminar el partner creado
+ partner_to_delete = self.env['res.partner'].browse(created_partner['id'])
+ partner_to_delete.unlink()
+
+ def test_put_update_record(self):
+ """Test PUT para actualizar un registro"""
+ token = self._get_auth_token()
+
+ # Crear un partner para actualizar
+ test_partner = self.env['res.partner'].create({
+ 'name': 'Partner to Update',
+ 'email': 'update@example.com'
+ })
+
+ update_data = {
+ 'values': {
+ 'name': 'Updated Partner Name',
+ 'phone': '999888777'
+ }
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner/{test_partner.id}',
+ data=json.dumps(update_data).encode('utf-8'),
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+
+ # Verificar que el registro fue actualizado
+ updated_partner = response_data['data'][0]
+ self.assertEqual(updated_partner['name'], 'Updated Partner Name')
+
+ # Verificar en la base de datos
+ test_partner.refresh()
+ self.assertEqual(test_partner.name, 'Updated Partner Name')
+ self.assertEqual(test_partner.phone, '999888777')
+
+ # Limpiar
+ test_partner.unlink()
+
+ def test_delete_record(self):
+ """Test DELETE para eliminar un registro"""
+ token = self._get_auth_token()
+
+ # Crear un partner para eliminar
+ test_partner = self.env['res.partner'].create({
+ 'name': 'Partner to Delete',
+ 'email': 'delete@example.com'
+ })
+ partner_id = test_partner.id
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner/{partner_id}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+ self.assertIn('deleted_record', response_data)
+ self.assertEqual(response_data['deleted_record']['id'], partner_id)
+
+ # Verificar que el registro ya no existe
+ self.assertFalse(self.env['res.partner'].browse(partner_id).exists())
+
+ def test_get_with_order(self):
+ """Test GET con ordenamiento"""
+ token = self._get_auth_token()
+
+ # Ordenar por nombre descendente
+ params = 'order=name desc&limit=5'
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner?{params}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+
+ # Verificar que hay datos y están ordenados
+ if len(response_data['data']) > 1:
+ names = [partner['name'] for partner in response_data['data']]
+ # Verificar orden descendente
+ self.assertTrue(all(names[i] >= names[i+1] for i in range(len(names)-1)))
+
+ def test_method_not_allowed(self):
+ """Test que métodos no permitidos devuelven error 405"""
+ token = self._get_auth_token()
+
+ # Desactivar DELETE para este test
+ self.api_config.is_delete = False
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner/{self.test_partner1.id}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 405)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('METHOD_NOT_ALLOWED', response_data.get('error_code', ''))
+
+ # Restaurar configuración
+ self.api_config.is_delete = True
+
+ def test_record_not_found(self):
+ """Test GET de registro inexistente"""
+ token = self._get_auth_token()
+
+ # ID que no existe
+ non_existent_id = 999999
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner/{non_existent_id}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ # Debería devolver lista vacía
+ self.assertTrue(response_data.get('success'))
+ self.assertEqual(response_data['count'], 0)
+ self.assertEqual(len(response_data['data']), 0)
+
+ def test_model_not_configured(self):
+ """Test acceso a modelo no configurado para API"""
+ token = self._get_auth_token()
+
+ # Intentar acceder a un modelo que no tiene configuración de API
+ response = self.url_open(
+ f'{self.api_base_url}/res.country',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 404)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('MODEL_NOT_CONFIGURED', response_data.get('error_code', ''))
\ No newline at end of file
diff --git a/rest_api_odoo/tests/test_rest_api_errors.py b/rest_api_odoo/tests/test_rest_api_errors.py
new file mode 100644
index 0000000000..658ae70bc1
--- /dev/null
+++ b/rest_api_odoo/tests/test_rest_api_errors.py
@@ -0,0 +1,451 @@
+# -*- coding: utf-8 -*-
+import json
+import jwt
+from datetime import datetime, timedelta
+from unittest.mock import patch, MagicMock
+from odoo.tests.common import HttpCase
+
+
+class TestRestApiErrors(HttpCase):
+ """Tests para manejo de errores de la REST API"""
+
+ def setUp(self):
+ super().setUp()
+ self.api_base_url = '/api/v1'
+
+ # Limpiar configuraciones existentes de API para res.partner
+ model_partner = self.env['ir.model'].search([('model', '=', 'res.partner')], limit=1)
+ existing_configs = self.env['connection.api'].search([('model_id', '=', model_partner.id)])
+ if existing_configs:
+ existing_configs.unlink()
+
+ # Crear configuración de API para res.partner
+ self.api_config = self.env['connection.api'].create({
+ 'model_id': model_partner.id,
+ 'active': True,
+ 'is_get': True,
+ 'is_post': True,
+ 'is_put': True,
+ 'is_delete': True,
+ 'max_records_limit': 10
+ })
+
+ def _get_auth_token(self):
+ """Helper para obtener token de autenticación"""
+ auth_data = {
+ 'username': 'admin',
+ 'password': 'admin',
+ 'database': self.env.cr.dbname
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/auth',
+ data=json.dumps(auth_data).encode('utf-8'),
+ headers={'Content-Type': 'application/json'}
+ )
+
+ response_data = json.loads(response.content.decode('utf-8'))
+ return response_data['data']['access_token']
+
+ def test_authentication_failed_no_token(self):
+ """Test acceso sin token de autenticación"""
+ response = self.url_open(f'{self.api_base_url}/res.partner')
+
+ self.assertEqual(response.status_code, 401)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertEqual(response_data.get('error_code'), 'AUTHENTICATION_FAILED')
+ self.assertIn('Token de autorización no proporcionado', response_data.get('message', ''))
+
+ def test_authentication_failed_invalid_token(self):
+ """Test con token inválido"""
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ headers={
+ 'Authorization': 'Bearer invalid_token_here',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 401)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertEqual(response_data.get('error_code'), 'AUTHENTICATION_FAILED')
+
+ def test_authentication_failed_malformed_token(self):
+ """Test con token mal formado"""
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ headers={
+ 'Authorization': 'InvalidFormat token_here',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 401)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertEqual(response_data.get('error_code'), 'AUTHENTICATION_FAILED')
+
+ def test_model_not_found(self):
+ """Test acceso a modelo que no existe"""
+ token = self._get_auth_token()
+
+ response = self.url_open(
+ f'{self.api_base_url}/non.existent.model',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 404)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertEqual(response_data.get('error_code'), 'MODEL_NOT_CONFIGURED')
+
+ def test_model_not_configured_for_api(self):
+ """Test acceso a modelo no configurado para API"""
+ token = self._get_auth_token()
+
+ # res.country no tiene configuración de API en este test
+ response = self.url_open(
+ f'{self.api_base_url}/res.country',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 404)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertEqual(response_data.get('error_code'), 'MODEL_NOT_CONFIGURED')
+
+ def test_method_not_allowed(self):
+ """Test método no permitido para el modelo"""
+ token = self._get_auth_token()
+
+ # Desactivar POST para este test
+ original_is_post = self.api_config.is_post
+ self.api_config.is_post = False
+
+ create_data = {
+ 'values': {
+ 'name': 'Test Partner',
+ 'email': 'test@example.com'
+ }
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ data=json.dumps(create_data).encode('utf-8'),
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 405)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertEqual(response_data.get('error_code'), 'METHOD_NOT_ALLOWED')
+
+ # Restaurar configuración
+ self.api_config.is_post = original_is_post
+
+ def test_invalid_json_in_post(self):
+ """Test POST con JSON inválido"""
+ token = self._get_auth_token()
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ data=b'{"invalid": json syntax}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 400)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertEqual(response_data.get('error_code'), 'INVALID_REQUEST_DATA')
+
+ def test_missing_values_in_post(self):
+ """Test POST sin campo 'values'"""
+ token = self._get_auth_token()
+
+ invalid_data = {
+ 'name': 'Test Partner' # Falta 'values' wrapper
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ data=json.dumps(invalid_data).encode('utf-8'),
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 400)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('values', response_data.get('message', '').lower())
+
+ def test_missing_values_in_put(self):
+ """Test PUT sin campo 'values'"""
+ token = self._get_auth_token()
+
+ # Crear un partner para intentar actualizar
+ test_partner = self.env['res.partner'].create({
+ 'name': 'Partner to Update',
+ 'email': 'update@example.com'
+ })
+
+ invalid_data = {
+ 'name': 'Updated Name' # Falta 'values' wrapper
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner/{test_partner.id}',
+ data=json.dumps(invalid_data).encode('utf-8'),
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 400)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('values', response_data.get('message', '').lower())
+
+ # Limpiar
+ test_partner.unlink()
+
+ def test_put_without_record_id(self):
+ """Test PUT sin especificar ID de registro"""
+ token = self._get_auth_token()
+
+ update_data = {
+ 'values': {
+ 'name': 'Updated Name'
+ }
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner', # Sin ID
+ data=json.dumps(update_data).encode('utf-8'),
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 400)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('ID de registro requerido', response_data.get('message', ''))
+
+ def test_put_nonexistent_record(self):
+ """Test PUT en registro que no existe"""
+ token = self._get_auth_token()
+
+ update_data = {
+ 'values': {
+ 'name': 'Updated Name'
+ }
+ }
+
+ non_existent_id = 999999
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner/{non_existent_id}',
+ data=json.dumps(update_data).encode('utf-8'),
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 404)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('Registro no encontrado', response_data.get('message', ''))
+
+ def test_delete_without_record_id(self):
+ """Test DELETE sin especificar ID de registro"""
+ token = self._get_auth_token()
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner', # Sin ID
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 400)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('ID de registro requerido', response_data.get('message', ''))
+
+ def test_delete_nonexistent_record(self):
+ """Test DELETE en registro que no existe"""
+ token = self._get_auth_token()
+
+ non_existent_id = 999999
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner/{non_existent_id}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 404)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('Registro no encontrado', response_data.get('message', ''))
+
+ def test_invalid_domain_syntax(self):
+ """Test GET con sintaxis de domain inválida"""
+ token = self._get_auth_token()
+
+ # Domain con sintaxis inválida
+ invalid_domain = "invalid domain syntax"
+ params = f'domain={invalid_domain}'
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner?{params}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ # Debería procesar la request sin el domain (ignorándolo)
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+ self.assertTrue(response_data.get('success'))
+
+ def test_limit_exceeds_maximum(self):
+ """Test GET con limit que excede el máximo configurado"""
+ token = self._get_auth_token()
+
+ # El límite configurado es 10, solicitar más
+ params = 'limit=100'
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner?{params}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('success'))
+ # Debería limitarse al máximo configurado
+ if 'limit' in response_data:
+ self.assertLessEqual(response_data['limit'], 10)
+
+ def test_invalid_limit_value(self):
+ """Test GET con valor de limit inválido"""
+ token = self._get_auth_token()
+
+ # Limit no numérico
+ params = 'limit=invalid'
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner?{params}',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ # Debería procesar sin el limit (ignorándolo)
+ self.assertEqual(response.status_code, 200)
+ response_data = json.loads(response.content.decode('utf-8'))
+ self.assertTrue(response_data.get('success'))
+
+ def test_validation_error_in_create(self):
+ """Test POST con datos que causan error de validación"""
+ token = self._get_auth_token()
+
+ # Intentar crear partner sin name (campo requerido)
+ invalid_data = {
+ 'values': {
+ 'email': 'test@example.com'
+ # name faltante
+ }
+ }
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ data=json.dumps(invalid_data).encode('utf-8'),
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 400)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertIn('Error creando registro', response_data.get('message', ''))
+
+ def test_cors_headers_in_error_responses(self):
+ """Test que las respuestas de error incluyen headers CORS"""
+ # Test con error 401
+ response = self.url_open(f'{self.api_base_url}/res.partner')
+
+ self.assertEqual(response.status_code, 401)
+
+ # Verificar headers CORS en respuesta de error
+ self.assertIn('Access-Control-Allow-Origin', response.headers)
+ self.assertEqual(response.headers['Access-Control-Allow-Origin'], '*')
+
+ @patch('odoo.addons.rest_api_odoo.controllers.rest_api_odoo._logger')
+ def test_internal_server_error_handling(self, mock_logger):
+ """Test manejo de errores internos del servidor"""
+ token = self._get_auth_token()
+
+ # Simular error interno con mock
+ with patch('odoo.http.request.env') as mock_env:
+ mock_env.__getitem__.side_effect = Exception("Simulated internal error")
+
+ response = self.url_open(
+ f'{self.api_base_url}/res.partner',
+ headers={
+ 'Authorization': f'Bearer {token}',
+ 'Content-Type': 'application/json'
+ }
+ )
+
+ self.assertEqual(response.status_code, 500)
+ response_data = json.loads(response.content.decode('utf-8'))
+
+ self.assertTrue(response_data.get('error'))
+ self.assertEqual(response_data.get('error_code'), 'INTERNAL_SERVER_ERROR')
+ self.assertIn('Error interno del servidor', response_data.get('message', ''))
\ No newline at end of file
diff --git a/rest_api_odoo/tests/test_runner.py b/rest_api_odoo/tests/test_runner.py
new file mode 100755
index 0000000000..f55b25e147
--- /dev/null
+++ b/rest_api_odoo/tests/test_runner.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Script para ejecutar tests de la REST API de forma independiente.
+Útil para CI/CD y desarrollo local.
+"""
+
+import os
+import sys
+import subprocess
+import argparse
+
+
+def run_tests(test_module=None, verbose=False, coverage=False):
+ """
+ Ejecuta los tests del módulo REST API
+
+ Args:
+ test_module: Módulo específico a testear (ej: 'test_rest_api_auth')
+ verbose: Salida verbose
+ coverage: Ejecutar con coverage
+ """
+
+ # Configurar comando base
+ cmd = ['python3', '-m', 'pytest']
+
+ if verbose:
+ cmd.extend(['-v', '--tb=short'])
+
+ if coverage:
+ cmd.extend(['--cov=controllers', '--cov-report=term-missing'])
+
+ # Directorio de tests
+ test_dir = os.path.dirname(os.path.abspath(__file__))
+
+ if test_module:
+ test_path = os.path.join(test_dir, f"{test_module}.py")
+ if not os.path.exists(test_path):
+ print(f"Error: Test module {test_module} not found")
+ return 1
+ cmd.append(test_path)
+ else:
+ cmd.append(test_dir)
+
+ print(f"Running: {' '.join(cmd)}")
+
+ try:
+ result = subprocess.run(cmd, cwd=test_dir)
+ return result.returncode
+ except FileNotFoundError:
+ print("Error: pytest not found. Install with: pip install pytest pytest-cov")
+ return 1
+
+
+def run_odoo_tests():
+ """
+ Ejecuta los tests usando el framework de testing de Odoo
+ """
+ print("Running Odoo framework tests...")
+
+ # Comando para ejecutar tests específicos del módulo en Odoo
+ cmd = [
+ 'python3', 'odoo-bin',
+ '--test-enable',
+ '--test-tags', 'rest_api_odoo',
+ '--stop-after-init',
+ '--log-level=test'
+ ]
+
+ try:
+ result = subprocess.run(cmd)
+ return result.returncode
+ except FileNotFoundError:
+ print("Error: odoo-bin not found. Make sure you're in the Odoo directory")
+ return 1
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Run REST API tests')
+ parser.add_argument('--module', '-m', help='Specific test module to run')
+ parser.add_argument('--verbose', '-v', action='store_true', help='Verbose output')
+ parser.add_argument('--coverage', '-c', action='store_true', help='Run with coverage')
+ parser.add_argument('--odoo', action='store_true', help='Use Odoo test framework')
+
+ args = parser.parse_args()
+
+ if args.odoo:
+ return run_odoo_tests()
+ else:
+ return run_tests(args.module, args.verbose, args.coverage)
+
+
+if __name__ == '__main__':
+ sys.exit(main())
\ No newline at end of file
diff --git a/rest_api_odoo/views/api_dashboard_views.xml b/rest_api_odoo/views/api_dashboard_views.xml
new file mode 100755
index 0000000000..7e10db69ed
--- /dev/null
+++ b/rest_api_odoo/views/api_dashboard_views.xml
@@ -0,0 +1,176 @@
+
+
+
+
+ API Dashboard
+ api_dashboard
+
+
+
+
+
+
+
+
+
+
+
+
+
Bienvenido a la REST API de Odoo
+
+ Esta API te permite integrar aplicaciones externas con Odoo
+ usando estándares REST y autenticación basada en API Keys.
+
+
+
+
+
+
+
+
Documentación Interactiva
+
Explora y prueba todos los endpoints disponibles
+
+ Ver Swagger UI
+
+
+
+
+
+
+
+
+
Configuración de Modelos
+
Gestiona qué modelos están disponibles en la API
+
+ Configurar API
+
+
+
+
+
+
+
+
+
+
+
+ Base URL: /api/v1
+ Autenticación: API Key
+ Formato: JSON
+ Versión: 1.0.0
+
+
+
+
+
Enlaces Útiles
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
1. Obtener API Key
+
curl -X POST /api/v1/auth \
+ -H "Content-Type: application/json" \
+ -d '{
+ "username": "tu_usuario",
+ "password": "tu_contraseña"
+ }'
+
+
+
2. Usar la API
+
curl -X GET /api/v1/models \
+ -H "X-API-Key: tu_api_key_aqui"
+
+
+
+
+
+
+
+
+
+
+
+
+
+ API Documentation
+ /api/v1/docs
+ new
+
+
+
+
+ api.stats.view
+ connection.api
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ API Statistics
+ connection.api
+ list
+
+ {'search_default_active': 1}
+
+
+
+
+
+
+
diff --git a/rest_api_odoo/views/connection_api_views.xml b/rest_api_odoo/views/connection_api_views.xml
index 1ae15d1f50..835092acf8 100644
--- a/rest_api_odoo/views/connection_api_views.xml
+++ b/rest_api_odoo/views/connection_api_views.xml
@@ -1,61 +1,239 @@
-
+
connection.api.view.form
connection.api
-
+
+
connection.api.view.list
connection.api
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+ connection.api.view.search
+ connection.api
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- Rest API Records
- ir.actions.act_window
+ REST API Configuration
connection.api
list,form
+
+ {'search_default_active': 1}
- Create!
+ Configure your first REST API endpoint!
+
+
+ Create API configurations to expose Odoo models through REST endpoints.
+
+
+
+ View API Documentation
+
-
-
-
+
+
+
+ Create Default API Configurations
+
+ code
+
+
+
+
+
+
+
+
diff --git a/rest_api_odoo/views/res_users_views.xml b/rest_api_odoo/views/res_users_views.xml
index c6a59b1ef3..f2f557543b 100644
--- a/rest_api_odoo/views/res_users_views.xml
+++ b/rest_api_odoo/views/res_users_views.xml
@@ -1,18 +1,170 @@
-
-
- view.users.form.inherit.rest.api.odoo
+
+
+ view.users.form.inherit.rest.api.enhanced
res.users
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
API Usage Instructions
+
Authentication: Include your API key in the request header:
+
X-API-Key: [Your API Key Here]
+
+
Available Endpoints:
+
+ GET /api/v1/models - List available models
+ GET /api/v1/{model} - Get all records
+ GET /api/v1/{model}/{id} - Get specific record
+ POST /api/v1/{model} - Create new record
+ PUT /api/v1/{model}/{id} - Update record
+ DELETE /api/v1/{model}/{id} - Delete record
+
+
+
Example:
+
curl -X GET http://your-server/api/v1/res.partner -H "X-API-Key: [Key]"
+
+
+
+
No API Key Generated
+
Click "Generate API Key" to create an API key for this user.
+
+
+
+
+ view.users.list.api.info
+
+ res.users
+
+
+
+
+
+
+
+
+
+
+
+ Cleanup Expired API Keys
+
+ code
+ 0:
+ message = "Cleaned " + str(cleaned_count) + " expired API keys."
+ msg_type = 'success'
+else:
+ message = "No expired API keys found."
+ msg_type = 'info'
+
+action = {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'message': message,
+ 'type': msg_type,
+ 'sticky': False,
+ }
+}
+ ]]>
+
+
+
+
+
+
+
+
+
+
+ Cleanup Expired API Keys
+
+ code
+
+ 1
+ days
+ True
+
diff --git a/sale_product_image/__manifest__.py b/sale_product_image/__manifest__.py
index 022a68e364..d8cadbe965 100644
--- a/sale_product_image/__manifest__.py
+++ b/sale_product_image/__manifest__.py
@@ -21,7 +21,7 @@
#############################################################################
{
"name": "Sale Order Line Images",
- "version": "18.0.1.0.1",
+ "version": "18.0.1.0.2",
"category": 'Sales',
"summary": "Order Line Images In Sale and Sale Report",
"description": """Order Line Images In Sale and Sale Report, odoo 17, order line images""",
diff --git a/sale_product_image/doc/RELEASE_NOTES.md b/sale_product_image/doc/RELEASE_NOTES.md
index dd65f45df9..467d8eb5d3 100644
--- a/sale_product_image/doc/RELEASE_NOTES.md
+++ b/sale_product_image/doc/RELEASE_NOTES.md
@@ -9,3 +9,9 @@
#### Version 18.0.1.0.1
##### FIX
- Fixed the issue in printing product images in the pdf report.
+
+#### 16.09.2025
+#### Version 18.0.1.0.2
+##### FIX
+- Fixed the issues with pdf report for product without images.
+
diff --git a/sale_product_image/report/sale_order_report.xml b/sale_product_image/report/sale_order_report.xml
index 27644f3570..7140e94f13 100644
--- a/sale_product_image/report/sale_order_report.xml
+++ b/sale_product_image/report/sale_order_report.xml
@@ -14,7 +14,9 @@
position="after">
-
+
diff --git a/theme_eco_refine/README.rst b/theme_eco_refine/README.rst
new file mode 100755
index 0000000000..285a5834fa
--- /dev/null
+++ b/theme_eco_refine/README.rst
@@ -0,0 +1,47 @@
+.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg
+ :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+Theme Eco Refine
+================
+Theme Eco Refine module provide attractive and unique front end theme mainly suitable for eCommerce website
+
+Configuration
+=============
+* No additional configurations needed
+
+License
+-------
+General Public License, Version 3 (AGPL v3).
+(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
+
+Company
+-------
+* `Cybrosys Techno Solutions `__
+
+Credits
+-------
+Developer: (V17) Ayana KP,
+ (V18) Rosmy John,
+Contact: odoo@cybrosys.com
+
+Contacts
+--------
+* Mail Contact : odoo@cybrosys.com
+* Website : https://cybrosys.com
+
+Bug Tracker
+-----------
+Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
+
+Maintainer
+==========
+.. image:: https://cybrosys.com/images/logo.png
+ :target: https://cybrosys.com
+This module is maintained by Cybrosys Technologies.
+
+For support and more information, please visit `Our Website `__
+
+Further information
+===================
+HTML Description: ``__
diff --git a/theme_eco_refine/__init__.py b/theme_eco_refine/__init__.py
new file mode 100755
index 0000000000..14b11c6740
--- /dev/null
+++ b/theme_eco_refine/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from . import controllers
+from . import models
diff --git a/theme_eco_refine/__manifest__.py b/theme_eco_refine/__manifest__.py
new file mode 100755
index 0000000000..11fc195c1e
--- /dev/null
+++ b/theme_eco_refine/__manifest__.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+{
+ 'name': 'Theme Eco Refine',
+ 'version': '18.0.1.0.0',
+ 'category': 'Theme/eCommerce',
+ 'summary': 'Theme Eco Refine helps to create attractive and unique front '
+ 'end theme',
+ 'description': """Theme Eco Refine module provide attractive and unique
+ front end theme mainly suitable for eCommerce website""",
+ 'author': 'Cybrosys Techno Solutions',
+ 'company': 'Cybrosys Techno Solutions',
+ 'maintainer': 'Cybrosys Techno Solutions',
+ 'website': "https://www.cybrosys.com",
+ "depends": ['base', 'web', 'website', 'website_livechat',
+ 'website_sale_wishlist', 'website_blog', 'purchase',
+ 'base_automation'],
+ 'data': [
+ 'data/theme_eco_refine_menus.xml',
+ 'views/product_template_views.xml',
+ 'views/website_blog_templates.xml',
+ 'views/templates.xml',
+ 'views/homepage_templates.xml',
+ 'views/about_us_templates.xml',
+ 'views/snippets.xml',
+ ],
+ 'assets': {
+ 'web.assets_frontend': [
+ 'https://code.jquery.com/jquery-3.2.1.slim.min.js',
+ 'https://cdn.jsdelivr.net/npm/popper.js@1.12.9/'
+ 'dist/umd/popper.min.js',
+ 'https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/'
+ 'bootstrap.min.js',
+ 'theme_eco_refine/static/src/css/contact_us.css',
+ 'theme_eco_refine/static/src/css/product.css',
+ 'theme_eco_refine/static/src/css/home.css',
+ 'theme_eco_refine/static/src/css/blog.css',
+ 'theme_eco_refine/static/src/js/product_specification.js',
+ 'theme_eco_refine/static/src/css/about_us.css',
+ 'theme_eco_refine/static/src/js/about_us.js',
+ 'theme_eco_refine/static/src/js/owl.carousel.js',
+ 'theme_eco_refine/static/src/js/owl.carousel.min.js',
+ 'theme_eco_refine/static/src/css/owl.carousel.css',
+ 'theme_eco_refine/static/src/js/collection_snippet.js',
+ 'theme_eco_refine/static/src/js/customer_response.js',
+ 'theme_eco_refine/static/src/js/best_seller_snippet.js',
+ 'theme_eco_refine/static/src/xml/best_seller_snippet_templates.xml',
+ 'theme_eco_refine/static/src/js/new_arrival_snippet.js',
+ 'theme_eco_refine/static/src/xml/new_arrival_snippet_templates.xml',
+ 'theme_eco_refine/static/src/js/top_rated_products_snippet.js',
+ 'theme_eco_refine/static/src/xml/'
+ 'top_rated_product_snippet_templates.xml',
+ ],
+ },
+ 'images': [
+ 'static/description/banner.jpg',
+ 'static/description/theme_screenshot.jpg',
+ ],
+ 'license': 'AGPL-3',
+ 'installable': True,
+ 'auto_install': False,
+ 'application': False,
+}
diff --git a/theme_eco_refine/controllers/__init__.py b/theme_eco_refine/controllers/__init__.py
new file mode 100755
index 0000000000..11e26cbe21
--- /dev/null
+++ b/theme_eco_refine/controllers/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from . import about_us
+from . import dynamic_snippets
+from . import theme_eco_refine
diff --git a/theme_eco_refine/controllers/about_us.py b/theme_eco_refine/controllers/about_us.py
new file mode 100755
index 0000000000..ca16de0b16
--- /dev/null
+++ b/theme_eco_refine/controllers/about_us.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from odoo import http
+
+
+class EcoRefine(http.Controller):
+ """Class used to define function which renders appropriate template."""
+ @http.route('/about_us', type='http', website=True, auth='public')
+ def eco_refine_about_us(self):
+ """Renders template about_us page."""
+ return http.request.render('theme_eco_refine.about_us', {})
diff --git a/theme_eco_refine/controllers/dynamic_snippets.py b/theme_eco_refine/controllers/dynamic_snippets.py
new file mode 100755
index 0000000000..49d2f8dfb2
--- /dev/null
+++ b/theme_eco_refine/controllers/dynamic_snippets.py
@@ -0,0 +1,138 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+import time
+from odoo import http
+from odoo.http import request
+
+
+class DynamicSnippets(http.Controller):
+ """This class is for the getting values for dynamic product snippets
+ """
+
+ @http.route('/top_selling_products', type='json', auth='public')
+ def top_selling(self):
+ """Function for getting the current website,top sold products and
+ its categories.
+ Return
+ products-most sold products
+ unique_categories-categories of all products
+ current_website-the current website for checking products or
+ """
+ current_website = request.env[
+ 'website'].sudo().get_current_website().id
+ public_categ_id = request.env[
+ 'product.public.category'].sudo().search_read([], ['name',
+ 'website_id'])
+ products = []
+ public_categories = []
+ for category in public_categ_id:
+ products_search_read = request.env['product.template'].with_user(
+ 1).search_read(
+ [('is_published', '=', True),
+ ('public_categ_ids.id', '=', category['id'])],
+ ['name', 'image_1920', 'public_categ_ids', 'website_id',
+ 'sales_count', 'list_price']
+ )
+
+ products_search_read.sort(key=lambda p: p.get('sales_count', 0),
+ reverse=True)
+ for product in products_search_read:
+ if product['sales_count'] != 0:
+ products.append(product)
+ public_categories.append(category)
+ unique_categories = [dict(categories) for categories in
+ {tuple(sorted(record.items())) for record in
+ public_categories}]
+ products = sorted(products, key=lambda i: i['sales_count'],
+ reverse=True)
+ unique_id = "pc-%d" % int(time.time() * 1000)
+ return products, unique_categories, current_website, unique_id
+
+ @http.route('/new_arrival_products', type='json', auth='public')
+ def products_new_arrivals(self):
+ """Function for getting the current website,new arrival products and
+ its categories.
+ Return
+ products-most sold products
+ unique_categories-categories of all products
+ current_website-the current website for checking products or
+ """
+ current_website = request.env[
+ 'website'].sudo().get_current_website().id
+ public_categ_id = request.env[
+ 'product.public.category'].sudo().search_read([], ['name',
+ 'website_id'])
+ products = []
+ public_categories = []
+ for category in public_categ_id:
+ products_search_read = request.env['product.template'].with_user(
+ 1).search_read(
+ [('is_published', '=', True),
+ ('public_categ_ids.id', '=', category['id'])],
+ ['name', 'public_categ_ids', 'website_id',
+ 'sales_count', 'image_1920', 'list_price', 'create_date'],
+ order='create_date desc')
+ for product in products_search_read:
+ products.append(product)
+ public_categories.append(category)
+ unique_id = "uc-%d" % int(time.time() * 1000)
+ unique_categories = [dict(categories) for categories in
+ {tuple(sorted(record.items())) for record in
+ public_categories}]
+ products = sorted(products, key=lambda i: i['create_date'],
+ reverse=True)
+ return products, unique_categories, current_website, unique_id
+
+ @http.route('/top_rated_products', type='json', auth='public')
+ def top_rated_products(self):
+ """Function for getting the current website,rated products and
+ its categories.
+ Return
+ products-most sold products
+ unique_categories-categories of all products
+ current_website-the current website for checking products or
+ """
+ current_website = request.env[
+ 'website'].sudo().get_current_website().id
+ public_categ_id = request.env[
+ 'product.public.category'].sudo().search_read([], ['name',
+ 'website_id'])
+ rated_products = request.env['rating.rating'].sudo().search_read(
+ [('res_model', '=', 'product.template')],
+ ['res_id', 'res_name', ], order='rating desc')
+ products = []
+ public_categories = []
+ for category in rated_products:
+ products_search_read = request.env['product.template'].with_user(
+ 1).search_read(
+ [('is_published', '=', True),
+ ('id', '=', category['res_id'])],
+ ['name', 'public_categ_ids', 'website_id',
+ 'sales_count', 'image_1920', 'list_price', 'create_date'], )
+ for product in products_search_read:
+ if product not in products:
+ products.append(product)
+ public_categories.append(category)
+ unique_categories = [dict(categories) for categories in
+ {tuple(sorted(record.items())) for record in
+ public_categories}]
+ return products, unique_categories, current_website, public_categ_id
diff --git a/theme_eco_refine/controllers/theme_eco_refine.py b/theme_eco_refine/controllers/theme_eco_refine.py
new file mode 100755
index 0000000000..6ef884782d
--- /dev/null
+++ b/theme_eco_refine/controllers/theme_eco_refine.py
@@ -0,0 +1,202 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+import babel.dates
+import itertools
+import pytz
+from odoo.http import request
+from odoo.tools import lazy
+from odoo import http, fields
+from werkzeug.exceptions import NotFound
+from collections import OrderedDict
+from odoo.tools import sql
+from odoo.tools.misc import get_lang
+from odoo.addons.website.controllers.main import QueryURL
+from odoo.addons.website_sale.controllers.main import TableCompute, WebsiteSale
+
+
+class WebsiteShop(WebsiteSale):
+ """Shop Controller
+ super the controller to set 3 columns of products in
+ website shop instead of 4 """
+ @http.route(['/shop/config/website'], type='json', auth='user')
+ def _change_website_config(self, **options):
+ """ Function for shop configuration """
+ if not request.env.user.has_group(
+ 'website.group_website_restricted_editor'):
+ raise NotFound()
+ current_website = request.env['website'].get_current_website()
+ # Restrict options we can write to.
+ writable_fields = {
+ 'shop_ppg', 'shop_ppr', 'shop_default_sort',
+ 'product_page_image_layout', 'product_page_image_width',
+ 'product_page_grid_columns', 'product_page_image_spacing'
+ }
+ # Default ppg to 1.
+ if 'ppg' in options and not options['ppg']:
+ options['ppg'] = 1
+ if 'product_page_grid_columns' in options:
+ options['product_page_grid_columns'] = int(
+ options['product_page_grid_columns'])
+ write_vals = {k: v for k, v in options.items() if k in writable_fields}
+ if write_vals:
+ current_website.write(write_vals)
+ current_website.select = True
+
+ @http.route()
+ def shop(self, page=0, category=None, search='', min_price=0.0,
+ max_price=0.0, ppg=False, **post):
+ """Function for website shop"""
+ current_website = request.env['website'].get_current_website()
+ if not current_website.select:
+ ppg = 12
+ ppr = 3
+ res = super(WebsiteShop, self).shop(page=page, category=category,
+ search=search,
+ min_price=min_price,
+ max_price=max_price, ppg=ppg,
+ **post)
+ products = res.qcontext['products']
+ res.qcontext.update({
+ 'bins': lazy(
+ lambda: TableCompute().process(products, ppg, ppr)),
+ 'ppr': ppr,
+ })
+ return res
+ else:
+ ppg = current_website.shop_ppg
+ ppr = current_website.shop_ppr
+ res = super(WebsiteShop, self).shop(page=page, category=category,
+ search=search,
+ min_price=min_price,
+ max_price=max_price, ppg=ppg,
+ **post)
+ products = res.qcontext['products']
+ res.qcontext.update({
+ 'bins': lazy(
+ lambda: TableCompute().process(products, ppg, ppr)),
+ 'ppr': ppr,
+ })
+ current_website.select = True
+ return res
+
+
+class WebsiteBlog(http.Controller):
+ """
+ Class for Website blog, super the controller to get the previous blog id
+ """
+ def nav_list(self, blog=None):
+ dom = blog and [('blog_id', '=', blog.id)] or []
+ if not request.env.user.has_group('website.group_website_designer'):
+ dom += [('post_date', '<=', fields.Datetime.now())]
+ groups = request.env['blog.post']._read_group_raw(
+ dom,
+ ['name', 'post_date'],
+ groupby=["post_date"], orderby="post_date desc")
+ for group in groups:
+ (r, label) = group['post_date']
+ start, end = r.split('/')
+ group['post_date'] = label
+ group['date_begin'] = start
+ group['date_end'] = end
+ locale = get_lang(request.env).code
+ start = pytz.UTC.localize(fields.Datetime.from_string(start))
+ tzinfo = pytz.timezone(request.context.get('tz', 'utc') or 'utc')
+ group['month'] = babel.dates.format_datetime(start, format='MMMM',
+ tzinfo=tzinfo,
+ locale=locale)
+ group['year'] = babel.dates.format_datetime(start, format='yyyy',
+ tzinfo=tzinfo,
+ locale=locale)
+ return OrderedDict((year, [m for m in months]) for year, months in
+ itertools.groupby(groups, lambda g: g['year']))
+
+ @http.route([
+ '''/blog//
+ ''',
+ ], type='http', auth="public", website=True, sitemap=True)
+ def blog_post(self, blog, blog_post, tag_id=None, page=1,
+ enable_editor=None, **post):
+ """ Prepare all values to display the blog.
+ :return dict values: values for the templates, containing
+ - 'blog_post': browse of the current post
+ - 'blog': browse of the current blog
+ - 'blogs': list of browse records of blogs
+ - 'tag': current tag, if tag_id in parameters
+ - 'tags': all tags, for tag-based navigation
+ - 'pager': a pager on the comments
+ - 'nav_list': a dict [year][month] for archives navigation
+ - 'next_post': next blog post, to direct the user towards the next
+ interesting post
+ """
+ BlogPost = request.env['blog.post']
+ date_begin, date_end = post.get('date_begin'), post.get('date_end')
+ domain = request.website.website_domain()
+ blogs = blog.search(domain, order="create_date, id asc")
+ slug = request.env['ir.http']._slug
+ tag = None
+ if tag_id:
+ tag = request.env['blog.tag'].browse(int(tag_id))
+ blog_url = QueryURL('', ['blog', 'tag'], blog=blog_post.blog_id,
+ tag=tag, date_begin=date_begin, date_end=date_end)
+ if not blog_post.blog_id.id == blog.id:
+ return request.redirect(
+ "/blog/%s/%s" % (slug(blog_post.blog_id), slug(blog_post)),
+ code=301)
+ tags = request.env['blog.tag'].search([])
+ # Find next Post
+ blog_post_domain = [('blog_id', '=', blog.id)]
+ if not request.env.user.has_group('website.group_website_designer'):
+ blog_post_domain += [('post_date', '<=', fields.Datetime.now())]
+ all_post = BlogPost.search(blog_post_domain)
+ if blog_post not in all_post:
+ return request.redirect("/blog/%s" % (slug(blog_post.blog_id)))
+ # should always return at least the current post
+ all_post_ids = all_post.ids
+ current_blog_post_index = all_post_ids.index(blog_post.id)
+ nb_posts = len(all_post_ids)
+ next_post_id = all_post_ids[
+ (current_blog_post_index + 1) % nb_posts] if nb_posts > 1 else None
+ next_post = next_post_id and BlogPost.browse(next_post_id) or False
+ prev_post_id = all_post_ids[
+ (current_blog_post_index - 1) % nb_posts] if nb_posts > 1 else None
+ prev_post = next_post_id and BlogPost.browse(prev_post_id) or False
+ values = {
+ 'tags': tags,
+ 'tag': tag,
+ 'blog': blog,
+ 'blog_post': blog_post,
+ 'blogs': blogs,
+ 'main_object': blog_post,
+ 'enable_editor': enable_editor,
+ 'next_post': next_post,
+ 'date': date_begin,
+ 'blog_url': blog_url,
+ 'prev_post': prev_post,
+ }
+ response = request.render("website_blog.blog_post_complete", values)
+ if blog_post.id not in request.session.get('posts_viewed', []):
+ if sql.increment_fields_skiplock(blog_post, 'visits'):
+ if not request.session.get('posts_viewed'):
+ request.session['posts_viewed'] = []
+ request.session['posts_viewed'].append(blog_post.id)
+ request.session.modified = True
+ return response
diff --git a/theme_eco_refine/data/theme_eco_refine_menus.xml b/theme_eco_refine/data/theme_eco_refine_menus.xml
new file mode 100755
index 0000000000..1106f72a0b
--- /dev/null
+++ b/theme_eco_refine/data/theme_eco_refine_menus.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/theme_eco_refine/doc/RELEASE_NOTES.md b/theme_eco_refine/doc/RELEASE_NOTES.md
new file mode 100755
index 0000000000..6d3be098d9
--- /dev/null
+++ b/theme_eco_refine/doc/RELEASE_NOTES.md
@@ -0,0 +1,6 @@
+## Module
+
+#### 20.09.2025
+#### Version 18.0.1.0.0
+#### ADD
+- Initial commit for Theme Eco Refine
diff --git a/theme_eco_refine/models/__init__.py b/theme_eco_refine/models/__init__.py
new file mode 100755
index 0000000000..cf39c5574e
--- /dev/null
+++ b/theme_eco_refine/models/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from . import product_template
+from . import website
diff --git a/theme_eco_refine/models/product_template.py b/theme_eco_refine/models/product_template.py
new file mode 100755
index 0000000000..11843103d0
--- /dev/null
+++ b/theme_eco_refine/models/product_template.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from odoo import fields, models
+
+
+class ProductTemplate(models.Model):
+ """Inherit model product template and fields for
+ product specification and product details"""
+ _inherit = 'product.template'
+
+ product_spec = fields.Text(
+ string='Product Specification', translate=True,
+ help="The Specification of the Product.")
+ product_detail = fields.Text(
+ string='Product Detail', translate=True,
+ help="The Details of the Product ")
diff --git a/theme_eco_refine/models/website.py b/theme_eco_refine/models/website.py
new file mode 100755
index 0000000000..59562eb812
--- /dev/null
+++ b/theme_eco_refine/models/website.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from odoo import fields, models
+
+
+class Website(models.Model):
+ """ Inherit website to add boolean field to set
+ 3 product columns in shop instead of 4 """
+ _inherit = 'website'
+
+ select = fields.Boolean(default=False, string='Select',
+ help='Set default 3 columns of products in shop')
diff --git a/theme_eco_refine/static/description/banner.jpg b/theme_eco_refine/static/description/banner.jpg
new file mode 100644
index 0000000000..701aac48e0
Binary files /dev/null and b/theme_eco_refine/static/description/banner.jpg differ
diff --git a/theme_eco_refine/static/description/icon.png b/theme_eco_refine/static/description/icon.png
new file mode 100644
index 0000000000..b89a7d7318
Binary files /dev/null and b/theme_eco_refine/static/description/icon.png differ
diff --git a/theme_eco_refine/static/description/img/About-us-mobile-temp.png b/theme_eco_refine/static/description/img/About-us-mobile-temp.png
new file mode 100644
index 0000000000..24da73800e
Binary files /dev/null and b/theme_eco_refine/static/description/img/About-us-mobile-temp.png differ
diff --git a/theme_eco_refine/static/description/img/Edu.png b/theme_eco_refine/static/description/img/Edu.png
new file mode 100644
index 0000000000..158b36a162
Binary files /dev/null and b/theme_eco_refine/static/description/img/Edu.png differ
diff --git a/theme_eco_refine/static/description/img/FAQ.png b/theme_eco_refine/static/description/img/FAQ.png
new file mode 100644
index 0000000000..547db3e04c
Binary files /dev/null and b/theme_eco_refine/static/description/img/FAQ.png differ
diff --git a/theme_eco_refine/static/description/img/POS.png b/theme_eco_refine/static/description/img/POS.png
new file mode 100644
index 0000000000..3c7f1cfe9c
Binary files /dev/null and b/theme_eco_refine/static/description/img/POS.png differ
diff --git a/theme_eco_refine/static/description/img/Production.png b/theme_eco_refine/static/description/img/Production.png
new file mode 100644
index 0000000000..e88dcd0d6c
Binary files /dev/null and b/theme_eco_refine/static/description/img/Production.png differ
diff --git a/theme_eco_refine/static/description/img/Shop-responsive.png b/theme_eco_refine/static/description/img/Shop-responsive.png
new file mode 100644
index 0000000000..6fa44537a3
Binary files /dev/null and b/theme_eco_refine/static/description/img/Shop-responsive.png differ
diff --git a/theme_eco_refine/static/description/img/Top_rated_products.png b/theme_eco_refine/static/description/img/Top_rated_products.png
new file mode 100644
index 0000000000..6820df620c
Binary files /dev/null and b/theme_eco_refine/static/description/img/Top_rated_products.png differ
diff --git a/theme_eco_refine/static/description/img/about_us_1.png b/theme_eco_refine/static/description/img/about_us_1.png
new file mode 100644
index 0000000000..018fb3e877
Binary files /dev/null and b/theme_eco_refine/static/description/img/about_us_1.png differ
diff --git a/theme_eco_refine/static/description/img/about_us_2.png b/theme_eco_refine/static/description/img/about_us_2.png
new file mode 100644
index 0000000000..c6691e6aaf
Binary files /dev/null and b/theme_eco_refine/static/description/img/about_us_2.png differ
diff --git a/theme_eco_refine/static/description/img/arrow-black.png b/theme_eco_refine/static/description/img/arrow-black.png
new file mode 100644
index 0000000000..3fd6da801a
Binary files /dev/null and b/theme_eco_refine/static/description/img/arrow-black.png differ
diff --git a/theme_eco_refine/static/description/img/arrows-repeat.svg b/theme_eco_refine/static/description/img/arrows-repeat.svg
new file mode 100644
index 0000000000..94fb8f7f90
--- /dev/null
+++ b/theme_eco_refine/static/description/img/arrows-repeat.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/banner-bg-1.svg b/theme_eco_refine/static/description/img/banner-bg-1.svg
new file mode 100644
index 0000000000..7af9bab87d
--- /dev/null
+++ b/theme_eco_refine/static/description/img/banner-bg-1.svg
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/banner-img.png b/theme_eco_refine/static/description/img/banner-img.png
new file mode 100644
index 0000000000..7a3cdf8508
Binary files /dev/null and b/theme_eco_refine/static/description/img/banner-img.png differ
diff --git a/theme_eco_refine/static/description/img/banner.jpg b/theme_eco_refine/static/description/img/banner.jpg
new file mode 100644
index 0000000000..701aac48e0
Binary files /dev/null and b/theme_eco_refine/static/description/img/banner.jpg differ
diff --git a/theme_eco_refine/static/description/img/banner.svg b/theme_eco_refine/static/description/img/banner.svg
new file mode 100644
index 0000000000..3d4ed7a4ab
--- /dev/null
+++ b/theme_eco_refine/static/description/img/banner.svg
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/banner_1.png b/theme_eco_refine/static/description/img/banner_1.png
new file mode 100644
index 0000000000..176ce66281
Binary files /dev/null and b/theme_eco_refine/static/description/img/banner_1.png differ
diff --git a/theme_eco_refine/static/description/img/banner_2.png b/theme_eco_refine/static/description/img/banner_2.png
new file mode 100644
index 0000000000..0ee9609d06
Binary files /dev/null and b/theme_eco_refine/static/description/img/banner_2.png differ
diff --git a/theme_eco_refine/static/description/img/banner_template.jpg b/theme_eco_refine/static/description/img/banner_template.jpg
new file mode 100644
index 0000000000..9daef7ccfc
Binary files /dev/null and b/theme_eco_refine/static/description/img/banner_template.jpg differ
diff --git a/theme_eco_refine/static/description/img/best_seller.png b/theme_eco_refine/static/description/img/best_seller.png
new file mode 100644
index 0000000000..0cce724206
Binary files /dev/null and b/theme_eco_refine/static/description/img/best_seller.png differ
diff --git a/theme_eco_refine/static/description/img/blog-responsive-design.png b/theme_eco_refine/static/description/img/blog-responsive-design.png
new file mode 100644
index 0000000000..ba13a6590a
Binary files /dev/null and b/theme_eco_refine/static/description/img/blog-responsive-design.png differ
diff --git a/theme_eco_refine/static/description/img/blog.png b/theme_eco_refine/static/description/img/blog.png
new file mode 100644
index 0000000000..56e6700af5
Binary files /dev/null and b/theme_eco_refine/static/description/img/blog.png differ
diff --git a/theme_eco_refine/static/description/img/check.svg b/theme_eco_refine/static/description/img/check.svg
new file mode 100644
index 0000000000..8bc79333dc
--- /dev/null
+++ b/theme_eco_refine/static/description/img/check.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/collections.png b/theme_eco_refine/static/description/img/collections.png
new file mode 100644
index 0000000000..466109ad67
Binary files /dev/null and b/theme_eco_refine/static/description/img/collections.png differ
diff --git a/theme_eco_refine/static/description/img/contact_us.png b/theme_eco_refine/static/description/img/contact_us.png
new file mode 100644
index 0000000000..af7294860a
Binary files /dev/null and b/theme_eco_refine/static/description/img/contact_us.png differ
diff --git a/theme_eco_refine/static/description/img/customer_response.png b/theme_eco_refine/static/description/img/customer_response.png
new file mode 100644
index 0000000000..7404dbd64f
Binary files /dev/null and b/theme_eco_refine/static/description/img/customer_response.png differ
diff --git a/theme_eco_refine/static/description/img/feature-star.svg b/theme_eco_refine/static/description/img/feature-star.svg
new file mode 100644
index 0000000000..a913270e8e
--- /dev/null
+++ b/theme_eco_refine/static/description/img/feature-star.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/gear.svg b/theme_eco_refine/static/description/img/gear.svg
new file mode 100644
index 0000000000..ce383059da
--- /dev/null
+++ b/theme_eco_refine/static/description/img/gear.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/hire-odoo.svg b/theme_eco_refine/static/description/img/hire-odoo.svg
new file mode 100644
index 0000000000..9cfec4e447
--- /dev/null
+++ b/theme_eco_refine/static/description/img/hire-odoo.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/home-mobile.png b/theme_eco_refine/static/description/img/home-mobile.png
new file mode 100644
index 0000000000..d66ac582d2
Binary files /dev/null and b/theme_eco_refine/static/description/img/home-mobile.png differ
diff --git a/theme_eco_refine/static/description/img/home_2.png b/theme_eco_refine/static/description/img/home_2.png
new file mode 100644
index 0000000000..223afa14d9
Binary files /dev/null and b/theme_eco_refine/static/description/img/home_2.png differ
diff --git a/theme_eco_refine/static/description/img/icon-Compatibility-with-plugins.png b/theme_eco_refine/static/description/img/icon-Compatibility-with-plugins.png
new file mode 100644
index 0000000000..2c0c4015ef
Binary files /dev/null and b/theme_eco_refine/static/description/img/icon-Compatibility-with-plugins.png differ
diff --git a/theme_eco_refine/static/description/img/icon-Fast-loading-times.png b/theme_eco_refine/static/description/img/icon-Fast-loading-times.png
new file mode 100644
index 0000000000..d758dea65f
Binary files /dev/null and b/theme_eco_refine/static/description/img/icon-Fast-loading-times.png differ
diff --git a/theme_eco_refine/static/description/img/icon-One-Click-Installation.png b/theme_eco_refine/static/description/img/icon-One-Click-Installation.png
new file mode 100644
index 0000000000..189cc7cbb2
Binary files /dev/null and b/theme_eco_refine/static/description/img/icon-One-Click-Installation.png differ
diff --git a/theme_eco_refine/static/description/img/icon-Responsive-design.png b/theme_eco_refine/static/description/img/icon-Responsive-design.png
new file mode 100644
index 0000000000..963329a0a1
Binary files /dev/null and b/theme_eco_refine/static/description/img/icon-Responsive-design.png differ
diff --git a/theme_eco_refine/static/description/img/icon-Up-to-date-development.png b/theme_eco_refine/static/description/img/icon-Up-to-date-development.png
new file mode 100644
index 0000000000..892a490e85
Binary files /dev/null and b/theme_eco_refine/static/description/img/icon-Up-to-date-development.png differ
diff --git a/theme_eco_refine/static/description/img/icon-design.png b/theme_eco_refine/static/description/img/icon-design.png
new file mode 100644
index 0000000000..bd578f6d19
Binary files /dev/null and b/theme_eco_refine/static/description/img/icon-design.png differ
diff --git a/theme_eco_refine/static/description/img/life-ring-icon.svg b/theme_eco_refine/static/description/img/life-ring-icon.svg
new file mode 100644
index 0000000000..b6c797ba14
--- /dev/null
+++ b/theme_eco_refine/static/description/img/life-ring-icon.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/logo-cybro.png b/theme_eco_refine/static/description/img/logo-cybro.png
new file mode 100644
index 0000000000..ecf9b01340
Binary files /dev/null and b/theme_eco_refine/static/description/img/logo-cybro.png differ
diff --git a/theme_eco_refine/static/description/img/new_arrival.png b/theme_eco_refine/static/description/img/new_arrival.png
new file mode 100644
index 0000000000..2c619c5b18
Binary files /dev/null and b/theme_eco_refine/static/description/img/new_arrival.png differ
diff --git a/theme_eco_refine/static/description/img/odoo-consultancy.svg b/theme_eco_refine/static/description/img/odoo-consultancy.svg
new file mode 100644
index 0000000000..c2c27e6083
--- /dev/null
+++ b/theme_eco_refine/static/description/img/odoo-consultancy.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/odoo-consultency.png b/theme_eco_refine/static/description/img/odoo-consultency.png
new file mode 100644
index 0000000000..bf2d21531c
Binary files /dev/null and b/theme_eco_refine/static/description/img/odoo-consultency.png differ
diff --git a/theme_eco_refine/static/description/img/odoo-customization.png b/theme_eco_refine/static/description/img/odoo-customization.png
new file mode 100644
index 0000000000..a51a84de40
Binary files /dev/null and b/theme_eco_refine/static/description/img/odoo-customization.png differ
diff --git a/theme_eco_refine/static/description/img/odoo-developer.png b/theme_eco_refine/static/description/img/odoo-developer.png
new file mode 100644
index 0000000000..b2272be9ec
Binary files /dev/null and b/theme_eco_refine/static/description/img/odoo-developer.png differ
diff --git a/theme_eco_refine/static/description/img/odoo-implement.png b/theme_eco_refine/static/description/img/odoo-implement.png
new file mode 100644
index 0000000000..ab975c139c
Binary files /dev/null and b/theme_eco_refine/static/description/img/odoo-implement.png differ
diff --git a/theme_eco_refine/static/description/img/odoo-intergration.png b/theme_eco_refine/static/description/img/odoo-intergration.png
new file mode 100644
index 0000000000..82b73a193c
Binary files /dev/null and b/theme_eco_refine/static/description/img/odoo-intergration.png differ
diff --git a/theme_eco_refine/static/description/img/odoo-licencing.png b/theme_eco_refine/static/description/img/odoo-licencing.png
new file mode 100644
index 0000000000..fe24f14c4e
Binary files /dev/null and b/theme_eco_refine/static/description/img/odoo-licencing.png differ
diff --git a/theme_eco_refine/static/description/img/odoo-licencing.svg b/theme_eco_refine/static/description/img/odoo-licencing.svg
new file mode 100644
index 0000000000..8a520b40f1
--- /dev/null
+++ b/theme_eco_refine/static/description/img/odoo-licencing.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/description/img/odoo-logo.png b/theme_eco_refine/static/description/img/odoo-logo.png
new file mode 100644
index 0000000000..36960c38ba
Binary files /dev/null and b/theme_eco_refine/static/description/img/odoo-logo.png differ
diff --git a/theme_eco_refine/static/description/img/odoo-migration.png b/theme_eco_refine/static/description/img/odoo-migration.png
new file mode 100644
index 0000000000..03ac43d053
Binary files /dev/null and b/theme_eco_refine/static/description/img/odoo-migration.png differ
diff --git a/theme_eco_refine/static/description/img/odoo-support.png b/theme_eco_refine/static/description/img/odoo-support.png
new file mode 100644
index 0000000000..6d481032cd
Binary files /dev/null and b/theme_eco_refine/static/description/img/odoo-support.png differ
diff --git a/theme_eco_refine/static/description/img/patter.svg b/theme_eco_refine/static/description/img/patter.svg
new file mode 100644
index 0000000000..9b7b0d7cda
--- /dev/null
+++ b/theme_eco_refine/static/description/img/patter.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/puzzle-piece-icon.svg b/theme_eco_refine/static/description/img/puzzle-piece-icon.svg
new file mode 100644
index 0000000000..ab5e56fa7b
--- /dev/null
+++ b/theme_eco_refine/static/description/img/puzzle-piece-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/screen-shot-01.png b/theme_eco_refine/static/description/img/screen-shot-01.png
new file mode 100644
index 0000000000..b08ce40696
Binary files /dev/null and b/theme_eco_refine/static/description/img/screen-shot-01.png differ
diff --git a/theme_eco_refine/static/description/img/screenshot-1.svg b/theme_eco_refine/static/description/img/screenshot-1.svg
new file mode 100644
index 0000000000..72eeb921b4
--- /dev/null
+++ b/theme_eco_refine/static/description/img/screenshot-1.svg
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/screenshot-2.png b/theme_eco_refine/static/description/img/screenshot-2.png
new file mode 100644
index 0000000000..e13b876da6
Binary files /dev/null and b/theme_eco_refine/static/description/img/screenshot-2.png differ
diff --git a/theme_eco_refine/static/description/img/screenshot-3.png b/theme_eco_refine/static/description/img/screenshot-3.png
new file mode 100644
index 0000000000..be1acdfd51
Binary files /dev/null and b/theme_eco_refine/static/description/img/screenshot-3.png differ
diff --git a/theme_eco_refine/static/description/img/screenshot-4.png b/theme_eco_refine/static/description/img/screenshot-4.png
new file mode 100644
index 0000000000..1d01e11fc7
Binary files /dev/null and b/theme_eco_refine/static/description/img/screenshot-4.png differ
diff --git a/theme_eco_refine/static/description/img/screenshot-5.svg b/theme_eco_refine/static/description/img/screenshot-5.svg
new file mode 100644
index 0000000000..923e355bf9
--- /dev/null
+++ b/theme_eco_refine/static/description/img/screenshot-5.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/screenshot-img.png b/theme_eco_refine/static/description/img/screenshot-img.png
new file mode 100644
index 0000000000..a425d9ede9
Binary files /dev/null and b/theme_eco_refine/static/description/img/screenshot-img.png differ
diff --git a/theme_eco_refine/static/description/img/screenshot-main.png b/theme_eco_refine/static/description/img/screenshot-main.png
new file mode 100644
index 0000000000..575f8e676b
Binary files /dev/null and b/theme_eco_refine/static/description/img/screenshot-main.png differ
diff --git a/theme_eco_refine/static/description/img/shop.png b/theme_eco_refine/static/description/img/shop.png
new file mode 100644
index 0000000000..fe85dbdfdf
Binary files /dev/null and b/theme_eco_refine/static/description/img/shop.png differ
diff --git a/theme_eco_refine/static/description/img/single_product.png b/theme_eco_refine/static/description/img/single_product.png
new file mode 100644
index 0000000000..903672d2dc
Binary files /dev/null and b/theme_eco_refine/static/description/img/single_product.png differ
diff --git a/theme_eco_refine/static/description/img/trading.png b/theme_eco_refine/static/description/img/trading.png
new file mode 100644
index 0000000000..9d99bc55bd
Binary files /dev/null and b/theme_eco_refine/static/description/img/trading.png differ
diff --git a/theme_eco_refine/static/description/img/translate.svg b/theme_eco_refine/static/description/img/translate.svg
new file mode 100644
index 0000000000..eea7295427
--- /dev/null
+++ b/theme_eco_refine/static/description/img/translate.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/img/wrench-icon.svg b/theme_eco_refine/static/description/img/wrench-icon.svg
new file mode 100644
index 0000000000..4e0ce1d016
--- /dev/null
+++ b/theme_eco_refine/static/description/img/wrench-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/description/index.html b/theme_eco_refine/static/description/index.html
new file mode 100644
index 0000000000..5cc54062f8
--- /dev/null
+++ b/theme_eco_refine/static/description/index.html
@@ -0,0 +1,614 @@
+
+
+
+
+
+
+ app index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Supports:
+
+ Community
+
+
+ Enterprise
+
+
+
+
+
+
Availability:
+
+ Odoo Online
+
+
+ Odoo.sh
+
+
+ On Premise
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ECO REFINE
+
+
Theme Eco Refine was created by Cybrosys Technology
+ Solutions. This theme makes the website more unique and attractive through its style and
+ custom-designed snippets, mainly suitable for eCommerce websites.
+
+
+
+
+
+
+
Design
+
+
+
+
Fast loading times
+
+
+
+
Responsive design
+
+
+
+
One Click Installation
+
+
+
+
+
+
+
+
+
+
+
+
+
Our Features
+
+
info includes 300+ elements that you may need to create website without
+ external plugins.
+
+
+
+
+
+
+
+
+
+
+
Unique and Attractive custom-designed
+ snippets.
+
+
+
+
+
+
+
+
+
+
+
This theme loads all of its features
+ more quickly than other designs.
+
+
+
+
+
+
+
+
+
+
+
Different resolution devices can be
+ used by users to watch websites.
+
+
+
+
+
+
+
+
+
+
+
+
This mode is significantly easier than
+ others because Odoo makes One Click Installation feasible.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Theme Features
+
+
+
+
+ HIGHLIGHT
+
Mobile Responsive Design
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HIGHLIGHT
+
Shop
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HIGHLIGHT
+
Mobile Responsive Design
+
+
+
+
+
+
+
+
+
+
+
+
+ HIGHLIGHT
+
Blog Page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HIGHLIGHT
+
Mobile Responsive Design
+
+
+
+
+
+
+
+
+
+
+
+
+ HIGHLIGHT
+
Contact us Page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/theme_eco_refine/static/description/theme_screenshot.jpg b/theme_eco_refine/static/description/theme_screenshot.jpg
new file mode 100644
index 0000000000..9daef7ccfc
Binary files /dev/null and b/theme_eco_refine/static/description/theme_screenshot.jpg differ
diff --git a/theme_eco_refine/static/src/css/about_us.css b/theme_eco_refine/static/src/css/about_us.css
new file mode 100755
index 0000000000..4f227de8b2
--- /dev/null
+++ b/theme_eco_refine/static/src/css/about_us.css
@@ -0,0 +1,737 @@
+.ref-abt-bg {
+ background: (linear-gradient(180deg, rgba(20, 108, 148, 0.6) 0%, #FFFFFF 100%), url('../images/about-hero-banner.png'));
+ background-size: cover;
+}
+.ref-about-container {
+ display: flex;
+ align-items: center;
+}
+.ref-about-container:last-child {
+ margin-bottom: 5rem;
+}
+.ref-about-content {
+ padding: 10px;
+ align-items: center;
+}
+.rf-about-img {
+ width: 450px;
+}
+.ref-about-content img {
+ width: 100%;
+ height: auto;
+}
+.ref-about-content_txt {
+ color: $dark-grey;
+ font-weight: 500;
+ font-size: 18px;
+ margin-top: 2rem;
+ line-height: 32px;
+}
+.ref-about-content {
+ h2 {
+ font-weight: 600;
+ line-height: 2.2rem;
+ }
+}
+.ref-feature__container {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ grid-gap: 30px;
+ padding: 50px 0px;
+}
+.ref-feature__container-box {
+ padding: 30px;
+ border-radius: 4px;
+ cursor: pointer;
+}
+.ref-feature__container-box:hover {
+ background: $primary-color;
+}
+.ref-feature__container-box:hover span {
+ color: #fff;
+}
+.ref-feature__container-box:hover .ref-feature-box_img img {
+ filter: invert(100%);
+}
+.ref-feature__container-box:hover p {
+ color: #A9A9A9;
+}
+.ref-feature__container-box span {
+ font-weight: 600;
+ display: block;
+}
+.ref-feature-box_img {
+ width: 36px;
+ height: 36px;
+ margin-bottom: 0.6rem;
+}
+.ref-feature-box_img img {
+ width: 100%;
+ height: auto;
+}
+.ref-feature__container-box p {
+ color: $dark-grey;
+ line-height: 32px;
+ margin-top: 0.8rem;
+}
+#ref-about-history {
+ padding: 50px 0;
+}
+.ref-abt-button {
+ width: 20px;
+ height: 20px;
+ background-color: $primary-color;
+ border-radius: 50%;
+ margin: 30px;
+ border: 3px solid #fff;
+ box-shadow: (0px 0px 9px rgba(0, 0, 0, 0.25));
+}
+.button-text {
+ display: block;
+ text-align: center;
+ /*position: absolute;*/
+ left: 0;
+ width: 100%;
+ padding: 5px 0;
+ color: $dark-grey;
+ font-size: 12px;
+}
+.ref-abt_container .owl-carousel-abt .owl-item{
+ position: relative;
+ margin-right: 0px !important;
+}
+.ref-abt_container .owl-nav {
+ display: none;
+}
+
+.owl-carousel-abt .owl-item {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ margin-bottom: 200px;
+}
+.ref-abt-button:before {
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 50%;
+ width: 100%;
+ height: 6px;
+ background-color: #0D5272;
+ -webkit-transform: translateY(-50%);
+ transform: translateY(-50%);
+
+}
+.button-text {
+ display: block;
+ text-align: center;
+ margin-top: 15px;
+ color: $dark-grey;
+ font-weight: 600;
+ font-size: 16px;
+}
+.ref-abt-button:hover .ref-abt-button__content {
+ display: block;
+ opacity: 1;
+}
+.ref-abt-button.active .ref-abt-button__content {
+ display: block;
+ opacity: 1;
+}
+.ref-abt_container {
+ position: relative;
+}
+.custom-nav-owl {
+ position: absolute;
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ top: 28px;
+}
+.re-abt-nav i {
+ font-size: 12px;
+}
+.ref-abt-button__content {
+ p {
+ color: $dark-grey;
+ font-size: 1rem;
+ }
+}
+
+.ref-abt_mob {
+ display: none;
+ flex-direction: column;
+ justify-content: space-between;
+ height: 600px;
+ margin: 50px 0;
+}
+.ref-abt_mob .ref-mob-btn:before {
+ content: '';
+ width: 50%;
+ background-color: $primary-color;
+ height: 150px;
+ position: absolute;
+ left: 4px;
+ border-radius: 50px;
+
+}
+.ref-mob-btn:hover .ref-abt-button__mobcontent{
+ display: block;
+ opacity: 1;
+}
+.ref-mob-btn:hover .button-mob-text {
+ display: none;
+}
+.ref-abt-button__mobcontent {
+ width: 500px;
+ margin-left: 24px;
+ display: none;
+ opacity: 0;
+ transition: opacity 0.3s ease-in-out;
+}
+.ref-abt-button__mobcontent.show {
+ display: block;
+ opacity: 1;
+}
+.button-mob-text {
+ display: block;
+ width: max-content;
+ color: $dark-grey;
+ font-weight: 500;
+ font-size: 1rem;
+ margin-left: 24px;
+}
+.hidden {
+ display: none;
+}
+
+//media@query.....
+@media(max-width:$breakpoint-lg) {
+ .owl-carousel-abt .owl-item {
+ margin-bottom: 240px;
+ }
+}
+@media(max-width:$breakpoint-md) {
+ .rf-about-img {
+ width: 360px;
+ }
+ .owl-carousel-abt .owl-item {
+ margin-bottom: 260px;
+ }
+ .ref-abt-button__content {
+ p {
+ color: $dark-grey;
+ font-size: 0.9rem;
+
+ }
+ }
+}
+@media(max-width:$breakpoint-sm) {
+ #ref-about-history {
+ padding-bottom: 100px;
+ }
+ .ref-about-container {
+ flex-direction: column;
+ }
+ .ref-about-container:last-child {
+ flex-direction: column-reverse;
+ }
+ .ref-about-content {
+ flex-basis: 100%;
+ }
+ .ref-feature__container {
+ grid-template-columns: repeat(2, 1fr);
+ }
+ .ref-abt_mob {
+ height: 525px;
+ }
+ .ref-abt_mob {
+ display: flex;
+ }
+ .ref-abt_container {
+ display: none;
+ }
+}
+@media(max-width:$breakpoint-xs) {
+ .ref-about-content h2 {
+ font-size: 1.3rem;
+ }
+ .ref-about-content_txt {
+ font-size: 16px;
+ margin-top: 0rem;
+ line-height: 30px;
+ }
+ .ref-about-content img {
+ width: 100%;
+ height: 180px;
+}
+ .ref-feature__container {
+ -ms-grid-columns: 1fr 30px 1fr;
+ grid-template-columns: repeat(1, 1fr);
+ }
+ .ref-abt-button__mobcontent {
+ width: 300px;
+ font-size: 12px;
+ }
+ .ref-feature__container {
+ grid-gap: 0px;
+ }
+ .ref-abt_mob {
+ height: 500px;
+ margin-bottom: 100px;
+ }
+}.ref-arrival-content {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+}
+.ref-centerhead__underline {
+ position: relative;
+ padding: 0px;
+ margin: 1rem 0;
+}
+.ref-centerhead__underline::after {
+ content: "";
+ position: absolute;
+ width: 80%;
+ height: 3px;
+ background-color: #000;
+ left: 10%;
+ bottom: 0;
+ border-radius: 50px;
+}
+.ref-abt-button {
+ width: 20px;
+ height: 20px;
+ background-color: $primary-color;
+ border-radius: 50%;
+ margin: 30px;
+ border: 3px solid #fff;
+ box-shadow: (0px 0px 9px rgba(0, 0, 0, 0.25));
+}
+.ref-abt-button {
+ width: 20px;
+ height: 20px;
+ background-color: #0D5272;
+ border-radius: 50%;
+ margin: 30px;
+ border: 3px solid #fff;
+ -webkit-box-shadow: 0px 0px 9px rgb(0 0 0 / 25%);
+ box-shadow: 0px 0px 9px rgb(0 0 0 / 25%);
+}
+.re-abt-nav {
+ width: 22px;
+ height: 22px;
+ border-radius: 50px;
+ background: #0D5272;
+ border: none;
+ outline: none;
+ color: #fff;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ cursor: pointer;
+ z-index: 888;
+}
+.ref-abt_mob .ref-mob-btn {
+ position: relative;
+ width: 20px;
+ height: 20px;
+ background-color: #0D5272;
+ border-radius: 50%;
+ cursor: pointer;
+ border: 3px solid #fff;
+ -webkit-box-shadow: 0px 0px 9px rgb(0 0 0 / 25%);
+ box-shadow: 0px 0px 9px rgb(0 0 0 / 25%);
+}
+.ref-abt-button__content {
+ display: none;
+ position: absolute;
+ top: 57px;
+ left: 50%;
+ -webkit-transform: translateX(-50%);
+ transform: translateX(-50%);
+ background-color: #EAF8FF;
+ padding: 20px;
+ width: 100%;
+ text-align: center;
+ opacity: 0;
+ -webkit-transition: opacity 0.3s ease-in-out;
+ transition: opacity 0.3s ease-in-out;
+}
+.ref-abt-button.active .ref-abt-button__content {
+ display: block;
+ opacity: 1;
+}
+.re-abt-nav i {
+ font-size: 12px;
+}
+.fa-solid, .fas {
+ font-weight: 900;
+}
+.ref-about-container {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+}
+.ref-about-container:last-child {
+ margin-bottom: 5rem;
+}
+.ref-about-content {
+ padding: 10px;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+}
+.rf-about-img {
+ width: 450px;
+}
+.ref-about-content img {
+ width: 100%;
+ height: auto;
+}
+.ref-about-content_txt {
+ color: #6F6969;
+ font-weight: 500;
+ font-size: 18px;
+ margin-top: 2rem;
+ line-height: 32px;
+}
+.ref-about-content h2 {
+ font-weight: 600;
+ line-height: 2.2rem;
+}
+.ref-feature__container {
+ display: -ms-grid;
+ display: grid;
+ -ms-grid-columns: 1fr 30px 1fr 30px 1fr;
+ grid-template-columns: repeat(3, 1fr);
+ grid-gap: 30px;
+ padding: 50px 0px;
+}
+.ref-feature__container-box {
+ padding: 30px;
+ border-radius: 4px;
+ cursor: pointer;
+}
+.ref-feature__container-box:hover {
+ background: #0D5272;
+}
+.ref-feature__container-box:hover span {
+ color: #fff;
+}
+.ref-feature__container-box:hover .ref-feature-box_img img {
+ -webkit-filter: invert(100%);
+ filter: invert(100%);
+}
+.ref-feature__container-box:hover p {
+ color: #A9A9A9;
+}
+.ref-feature__container-box span {
+ font-weight: 600;
+ display: block;
+}
+.ref-feature-box_img {
+ width: 36px;
+ height: 36px;
+ margin-bottom: 0.6rem;
+}
+.ref-feature-box_img img {
+ width: 100%;
+ height: auto;
+}
+.ref-feature__container-box p {
+ color: #6F6969;
+ line-height: 32px;
+ margin-top: 0.8rem;
+}
+#ref-about-history {
+ padding: 50px 0;
+}
+.ref-abt-button {
+ width: 20px;
+ height: 20px;
+ background-color: #0D5272;
+ border-radius: 50%;
+ margin: 30px;
+ border: 3px solid #fff;
+ -webkit-box-shadow: 0px 0px 9px rgba(0, 0, 0, 0.25);
+ box-shadow: 0px 0px 9px rgba(0, 0, 0, 0.25);
+}
+.button-text {
+ display: block;
+ text-align: center;
+ position: absolute;
+ left: 0;
+ width: 100%;
+ padding: 5px 0;
+ color: #6F6969;
+ font-size: 12px;
+}
+.owl-carousel-abt .owl-item {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ cursor: pointer;
+ margin-bottom: 200px;
+}
+
+.ref-abt-button:before {
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 50%;
+ width: 100%;
+ height: 6px;
+ background-color: #0D5272;
+ -webkit-transform: translateY(-50%);
+ transform: translateY(-50%);
+ z-index: -1;
+}
+.button-text {
+ display: block;
+ text-align: center;
+ margin-top: 15px;
+ color: #6F6969;
+ font-weight: 600;
+ font-size: 16px;
+}
+.ref-abt-button__content {
+ display: none;
+ position: absolute;
+ top: 57px;
+ left: 50%;
+ -webkit-transform: translateX(-50%);
+ transform: translateX(-50%);
+ background-color: #EAF8FF;
+ padding: 20px;
+ width: 100%;
+ text-align: center;
+ opacity: 0;
+ -webkit-transition: opacity 0.3s ease-in-out;
+ transition: opacity 0.3s ease-in-out;
+}
+.ref-abt-button:hover .ref-abt-button__content {
+ display: block;
+ opacity: 1;
+}
+.ref-abt-button.active .ref-abt-button__content {
+ display: block;
+ opacity: 1;
+}
+.ref-abt_container {
+ position: relative;
+}
+.custom-nav-owl {
+ position: absolute;
+ width: 100%;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ top: 28px;
+}
+.re-abt-nav {
+ width: 22px;
+ height: 22px;
+ border-radius: 50px;
+ background: #0D5272;
+ border: none;
+ outline: none;
+ color: #fff;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ cursor: pointer;
+ z-index: 888;
+}
+.re-abt-nav i {
+ font-size: 12px;
+}
+.ref-abt-button__content p {
+ color: #6F6969;
+ font-size: 1rem;
+}
+.ref-abt_mob {
+ display: none;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ height: 600px;
+ margin: 50px 0;
+}
+.ref-abt_mob .ref-mob-btn {
+ position: relative;
+ width: 20px;
+ height: 20px;
+ background-color: #0D5272;
+ border-radius: 50%;
+ cursor: pointer;
+ border: 3px solid #fff;
+ -webkit-box-shadow: 0px 0px 9px rgba(0, 0, 0, 0.25);
+ box-shadow: 0px 0px 9px rgba(0, 0, 0, 0.25);
+}
+.ref-light-section {
+ background-color: #EAF8FF;
+ padding: 50px 0px;
+}
+.ref-abt_mob .ref-mob-btn:before {
+ content: "";
+ width: 50%;
+ background-color: #0D5272;
+ height: 150px;
+ position: absolute;
+ left: 4px;
+ border-radius: 50px;
+
+}
+.ref-mob-btn:hover .ref-abt-button__mobcontent {
+ display: block;
+ opacity: 1;
+}
+.ref-mob-btn:hover .button-mob-text {
+ display: none;
+}
+.ref-abt-button__mobcontent {
+ width: 500px;
+ margin-left: 24px;
+ display: none;
+ opacity: 0;
+ -webkit-transition: opacity 0.3s ease-in-out;
+ transition: opacity 0.3s ease-in-out;
+}
+.ref-abt-button__mobcontent.show {
+ display: block;
+ opacity: 1;
+}
+.button-mob-text {
+ display: block;
+ width: -webkit-max-content;
+ width: -moz-max-content;
+ width: max-content;
+ color: #6F6969;
+ font-weight: 500;
+ font-size: 1rem;
+ margin-left: 24px;
+}
+.hidden {
+ display: none;
+}
+@media (max-width: 1199.98px) {
+ .owl-carousel-abt .owl-item {
+ margin-bottom: 240px;
+ float: left;
+ }
+}
+@media (max-width: 991.98px) {
+ .rf-about-img {
+ width: 360px;
+ }
+ .owl-carousel-abt .owl-item {
+ margin-bottom: 260px;
+ }
+ .ref-abt-button__content p {
+ color: #6F6969;
+ font-size: 0.9rem;
+ }
+}
+@media (max-width: 767.98px) {
+ #ref-about-history {
+ padding-bottom: 100px;
+ }
+ .ref-about-container {
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ }
+ .ref-about-container:last-child {
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: reverse;
+ -ms-flex-direction: column-reverse;
+ flex-direction: column-reverse;
+ }
+ .ref-about-content {
+ -ms-flex-preferred-size: 100%;
+ flex-basis: 100%;
+ }
+ .ref-feature__container {
+ -ms-grid-columns: 1fr 30px 1fr;
+ grid-template-columns: repeat(2, 1fr);
+ }
+ .ref-abt_mob {
+ height: 525px;
+ }
+ .ref-abt_mob {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ }
+ .ref-abt_container {
+ display: none;
+ }
+}
+.nav-link active{
+ content: "";
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 40%;
+ height: 3px;
+ font-weight: 600;
+ background-color: #0D5272;
+ -webkit-transition: width 0.3s ease-in-out;
+ transition: width 0.3s ease-in-out;
+ border-radius: 50px;
+}
+.ref-feature__container-box:hover span {
+ color: #fff !important;
+}
+@media(min-width: 768px) {
+ .ref-abt_container .owl-stage{
+ display: flex;
+ }
+ .ref-abt_container .owl-dots{
+ display:none;
+ }
+}
+#about_history_snippet_carousel {
+ overflow: hidden;
+}
+@media (max-width: 767.98px) {
+ .ref-abt_mob {
+ overflow-y: auto;
+
+ }
+}
\ No newline at end of file
diff --git a/theme_eco_refine/static/src/css/blog.css b/theme_eco_refine/static/src/css/blog.css
new file mode 100755
index 0000000000..c20e235a8c
--- /dev/null
+++ b/theme_eco_refine/static/src/css/blog.css
@@ -0,0 +1,283 @@
+.ref-blog-bg {
+ background: -webkit-gradient(linear, left top, left bottom, from(rgba(20, 108, 148, 0.6)), to(#FFFFFF)), url('/theme_eco_refine/static/src/img/blog-bg.png');
+ background: linear-gradient(180deg, rgba(20, 108, 148, 0.6) 0%, #FFFFFF 100%), url('/theme_eco_refine/static/src/img/blog-bg.png');
+ background-size: cover;
+}
+#o_wblog_blog_top .o_wblog_post_page_cover .o_record_cover_component{
+ display:none;
+}
+#o_wblog_blog_top{
+ margin-top: -100px;
+}
+#o_wblog_blog_top .o_wblog_post_title{
+ display: none;
+}
+.navbar-light .navbar-nav .nav-link.disabled {
+ color: rgb(33 77 93);
+}
+.input-group .oe_search_button{
+ background: #0d5272;
+ width: 60px;
+}
+.navbar-light .navbar-nav .show > .nav-link, .navbar-light .navbar-nav .nav-link.active {
+ color: rgb(27 80 97 / 90%);
+}
+.o_blog_post_title{
+ font-weight: 600;
+}
+.text-reset .mt-2 {
+ color: #0d5272;
+}
+.o_wblog_post_short_tag_section .badge{
+ border: 1px solid #0d5272 !important;
+}
+.table{
+ color: black;
+}
+.text-start{
+ color: black;
+}
+.row .col-md-6{
+ padding-bottom: 3rem !important;
+}
+.pb-4 {
+ padding-bottom: 3.5rem !important;
+}
+.px-2 {
+ padding-right: 0.5rem !important;
+ padding-left: 1.5rem !important;
+}
+.ref-wrapper {
+ max-width: 1200px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 20px;
+ padding-right: 20px;
+ width: 100%;
+}
+.ref-blog-container {
+ padding: 0px 0px;
+}
+.ref-blog-contain {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ margin-bottom: 60px;
+ gap: 15px;
+}
+.ref-blog-img_container {
+ overflow: hidden;
+ position: relative;
+ display: inline-block;
+ -webkit-transition: all 0.3s ease;
+ transition: all 0.3s ease;
+ cursor: pointer;
+}
+.ref-blog-detail {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+}
+.ref-blog--sub-head {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ margin-bottom: 0.5rem;
+}
+.ref-date-single_blog {
+ padding-right: 1rem;
+ border-right: 1px solid #0D5272;
+}
+.ref-date {
+ margin: 0px 0px 16px 0px;
+ color: #0D5272;
+ font-weight: 500;
+}
+.ref-author {
+ padding-left: 1rem;
+ font-weight: 500;
+ color: #0D5272;
+}
+.ref-section_head {
+ font-size: 28px;
+ color: black;
+ font-weight: 600;
+ padding: 1rem 0;
+}
+.ref-section_head {
+ font-size: 28px;
+ color: black;
+ font-weight: 600;
+ padding: 1rem 0;
+}
+.ref-blog-detail a {
+ -0.7rem 1.5rem;
+}
+.ref-blog-img_container img {
+ width: 100%;
+ -o-object-fit: cover;
+ object-fit: cover;
+ height: -webkit-fill-available;
+}
+.text-nowrap{
+ font-size: 1.3em;
+ color: #0d5272;
+}
+.o_wblog_post_cover_nocard .o_record_cover_component {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+ height: 452px;
+ width: 453px;
+}
+.website_blog #o_wblog_posts_loop.o_wblog_list_view .o_wblog_post_cover_nocard .o_record_cover_container {
+ padding-top: 65% !important;
+}
+#o_wblog_posts_loop{
+ margin-left: -140px;
+}
+.o_wblog_post_cover_nocard{
+ width: 452px;
+}
+.website_blog .o_wblog_read_text {
+ font-size: 20px !important;
+ line-height: 45px !important;
+ font-weight: 300 !important;
+ width: 680px !important;
+}
+.mx-n2 {
+ margin-right: -0.5rem !important;
+ margin-left: -1.5rem !important;
+}
+.pt-2 {
+ padding-top: 1.5rem !important;
+}
+.o_wblog_post_short_tag_section .badge {
+ border: 1px solid #0d5272 !important;
+ height: 25px;
+ width: 115px;
+ font-size: 15px;
+}
+.ref-blog-detail .btn-primary{
+ margin-bottom: 18px;
+ padding: 0.5rem 1.5rem;
+ background-color: #ffff;
+ color: #0d5272;
+ border-radius: 0px;
+ border-width: 3px;
+}
+.pb-4 {
+ padding-bottom: 0rem !important;
+}
+#o_wblog_posts_loop .row .mb-5{
+ display:none;
+}
+.rounded {
+ border-radius: 0rem !important;
+ border-top-left-radius: 0rem;
+ border-top-right-radius: 0rem;
+ border-bottom-right-radius: 0rem;
+ border-bottom-left-radius: 0rem;
+}
+.website_blog .o_wblog_post_page_cover.o_record_has_cover .o_wblog_post_title {
+ color: #733636!important;
+}
+#o_wblog_post_top .blog_header {
+ display: none;
+}
+#o_wblog_post_name{
+ font-size: 50px!important;
+ font-weight: 500!important;
+ line-height: 65px!important;
+ color:#0d5272!important;
+}
+#o_wblog_post_content .text-decoration-none .o_record_cover_container{
+ padding-top: 90%;
+ width: 850px;
+}
+#o_wblog_post_content .o_record_cover_component{
+ height: 700px;
+ width: 850px;
+}
+.website_blog .o_wblog_read_text .lead {
+ font-size: 28px;
+ line-height: 34px;
+ margin-bottom: 40px;
+ width: 900PX;
+}
+.website_blog .o_wblog_read_text p, .website_blog .o_wblog_read_text ul, .website_blog .o_wblog_read_text ol {
+ margin-bottom: 1.55em;
+ font-size: 20px;
+ margin-top: 1rem;
+ line-height: 38px;
+ width: 880px;
+}
+.website_blog .o_wblog_post_title #o_wblog_post_subtitle {
+ font-weight: 300!important;
+ font-size: 1.5rem!important;
+}
+.o_wblog_post_content_field .mt-2{
+ width: 860px;
+}
+#o_wblog_next_container .o_record_cover_container .o_record_cover_component{
+ width: 100%;
+ height: 350px;
+ margin-top: -62px;
+
+}
+#o_wblog_next_container .o_record_cover_container .o_record_cover_filter{
+ width: 100%;
+ margin-top: -61px;
+ height: 350px;
+}
+.website_blog #o_wblog_next_container .o_wblog_next_loader {
+ transform: translateZ(-5px)!important;
+}
+.ref-single-blog-navigation {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ margin-top: 20px;
+ margin-bottom: 50px;
+ width: 900px;
+ color:black;
+}
+#rf-blog-prev-btn, #rf-blog-next-btn {
+ padding: 0.8rem 0;
+ cursor: pointer;
+ background: none;
+ border: none;
+ font-weight: 600;
+ font-size: 18px;
+ color:black;
+}
+#o_wblog_posts_loop .blog_post .o_record_cover_component{
+ height: 200px;
+}
+#o_wblog_post_content .o_wblog_post_title{
+ margin-top: 125px;
+}
+#o_wblog_index_content{
+ margin-left: 230px;
+}
+.oe_search_button .oe_search_found{
+ display:none !important;
+}
diff --git a/theme_eco_refine/static/src/css/contact_us.css b/theme_eco_refine/static/src/css/contact_us.css
new file mode 100755
index 0000000000..2d33d26dd5
--- /dev/null
+++ b/theme_eco_refine/static/src/css/contact_us.css
@@ -0,0 +1,597 @@
+.ref-hero-sub-bg {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ width: 100%;
+ height: 350px;
+ background: -webkit-gradient(linear, left top, left bottom, from(rgba(20, 108, 148, 0.6)), to(#FFFFFF)), url("/theme_eco_refine/static/src/img/contact-hero.png");
+ background: linear-gradient(180deg, rgba(20, 108, 148, 0.6) 0%, #FFFFFF 100%), url("/theme_eco_refine/static/src/img/contact-hero.png");
+ background-position: center;
+ background-size: cover;
+ background-repeat: no-repeat;
+}
+.ref-contact_container {
+ text-align: center;
+}
+.ref-contact-info {
+ display: flex;
+ justify-content: center;
+ gap: 20px;
+ align-items: center;
+}
+.ref-contact_container img {
+ padding: 30px;
+}
+.ref-contact-msg {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ margin: 50px 0px;
+ -webkit-box-orient: vertical;
+ webkit-box-direction: normal;
+ -webkit-box-direction: normal;
+ -webkit-box-align: center;
+}
+.ref-contact-form {
+ display: flex;
+ flex-direction: column;
+ text-align: center;
+ justify-content: center;
+}
+.ref-contant-form_input {
+ background: #FFFFFF;
+ border: 2px solid #0d5272;
+ border-radius: 4px;
+ padding: 0.8rem 0.6rem;
+ margin-bottom: 1.5rem;
+ width: 450px;
+}
+.form-control {
+ background: #FFFFFF;
+ border: 2px solid #0d5272;
+ border-radius: 4px;
+ padding: 0.8rem 0.6rem;
+ margin-bottom: 1.5rem;
+ width: 410px;
+ margin-left: 0px;
+}
+@media(max-width:1399px) {
+ .form-control {
+ background: #FFFFFF;
+ border: 1px solid #000000;
+ border-radius: 4px;
+ padding: 1.8rem 0.6rem;
+ margin-bottom: 1.5rem;
+ width: 450px;
+ margin-left: 330px;
+}
+ }
+@media(max-width:1200px) {
+ .form-control {
+ background: #FFFFFF;
+ border: 1px solid #000000;
+ border-radius: 4px;
+ padding: 1.8rem 0.6rem;
+ margin-bottom: 1.5rem;
+ width: 450px;
+ margin-left: 240px;
+}
+ }
+@media(max-width:992px) {
+ .form-control {
+ background: #FFFFFF;
+ border: 1px solid #000000;
+ border-radius: 4px;
+ padding: 1.8rem 0.6rem;
+ margin-bottom: 1.5rem;
+ width: 450px;
+ margin-left: 120px;
+}
+ }
+@media(max-width:768px) {
+
+.s_newsletter_subscribe_form .input-group > .form-control, .input-group > .form-select {
+ position: relative !important;
+ -webkit-box-flex: 1 !important;
+ -webkit-flex: 1 1 auto !important;
+ flex: 1 1 auto !important;
+ width: 1% !important;
+ min-width: 230px !important;
+ margin-left: 262px !important;
+ height: 40px !important;
+ border-width: 2px !important;
+ border-color: #0d5272 !important;
+}
+ .form-control {
+ background: #FFFFFF;
+ border: 1px solid #000000;
+ border-radius: 4px;
+ padding: 1.8rem 0.6rem;
+ margin-bottom: 1.5rem;
+ width: 450px;
+ margin-left: 20px;
+}
+ }
+@media(max-width:$breakpoint-sm) {
+ .ref-hero-sub-bg {
+ height: 280px;
+ }
+ .ref-contact-info {
+ gap: 60px;
+ flex-wrap: wrap;
+ }
+}
+@media(max-width:$breakpoint-xs) {
+ .ref-contact_container {
+ h4 {
+ font-size: 1rem;
+ }
+ }
+ .ref-contact_container {
+ p {
+ font-size: 12px;
+ }
+ }
+ .ref-contact-info {
+ gap: 24px;
+ }
+ .ref-contant-form_input {
+ width:100%;
+ }
+ .ref-contact-form {
+ width: 90%;
+ }
+ .ref-contact_container img {
+ padding: 20px;
+ width: 70px;
+ }
+}
+element.style {
+}
+.ref-head--primary {
+ color: #0D5272;
+}
+.ref-section_head {
+ font-size: 28px;
+ color: black;
+ font-weight: 600;
+ padding: 1rem 0;
+}
+element.style {
+}
+@media (max-width: 991.98px)
+.ref-hero-sub-bg_heading {
+ font-size: 42px;
+ width: 60%;
+}
+.ref-hero-sub-bg_heading {
+ font-weight: 600;
+ font-size: 42px;
+ width: 50%;
+ text-align: center;
+ line-height: 72px;
+}
+.btn-primary:hover {
+ color: #000;
+ background-color: #0D5272;
+ text-decoration: underline;
+}
+.btn-primary:active {
+ color: #fcffff;;
+ background-color: #0D5272;
+}
+.btn-primary:focus {
+ color: #fcffff;;
+ background-color: #0D5272;
+ box-shadow:none;
+ outline:none;
+}
+.btn-primary {
+ padding: 0.5rem 1.5rem;
+ width: -webkit-fit-content;
+ width: -moz-fit-content;
+ width: fit-content;
+ color: #fff;
+ background-color: #0D5272 !important;
+ border-radius: 4px;
+}
+.text-bg-primary{
+ background-color: #0D5272 !important;
+}
+.ref-head--primary {
+ color: #0D5272;
+}
+#ref-footer {
+ background-color: #000;
+ padding: 100px 0px 50px 0px;
+}
+.ref-foot-row {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ width: 100%;
+}
+@media (max-width: 1199.98px)
+.ref-wrapper {
+ max-width: 999px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 20px;
+ padding-right: 20px;
+ width: 100%;
+}
+
+element.style {
+}
+@media (max-width: 1199.98px)
+.ref-wrapper {
+ max-width: 999px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 20px;
+ padding-right: 20px;
+ width: 100%;
+}
+.ref-wrapper {
+ max-width: 1200px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 20px;
+ padding-right: 20px;
+ width: 100%;
+}
+#ref-footer .ref-logo {
+ color: #fff;
+}
+.ref-foot-para {
+ color: #A9A9A9;
+ line-height: 36px;
+}
+.column {
+ -ms-flex-preferred-size: 20%;
+ flex-basis: 22%!important;
+}
+.ref-footer-section {
+ margin-bottom: 50px;
+}
+.ref-logo {
+ font-weight: 700;
+ font-size: 36px;
+ color: #000000;
+}
+.ref-foot_head {
+ color: #fff;
+ font-size: 22px;
+ line-height: 36px;
+}
+#ref-footer ul {
+ list-style: none;
+}
+#ref-footer li {
+ margin-right: 1rem;
+}
+a:not([href]):not([tabindex]) {
+ color: inherit;
+ text-decoration: none;
+}
+element.style {
+}
+.subscription-form {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: wrap;
+ flex-wrap: wrap;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ margin-top: 20px;
+ position: relative;
+}
+.subscription-form input[type=email] {
+ width: 450px;
+ border-radius: 6px;
+ padding: 12px;
+ margin: 50px 0px 0px 0px;
+}
+.subscription-form button {
+ background-color: #0D5272;
+ color: #fff;
+ border: none;
+ position: absolute;
+ right: 0;
+ margin: 6px;
+ top: 50px;
+ cursor: pointer;
+}
+.ref-button {
+ padding: 0.5rem 1.5rem;
+ width: -webkit-fit-content;
+ width: -moz-fit-content;
+ width: fit-content;
+ color: #fff;
+ background-color: #0D5272;
+ border-radius: 4px;
+}
+[type=reset], [type=submit], button, html [type=button] {
+ -webkit-appearance: button;
+}
+@media (max-width: 1199.98px)
+.ref-wrapper {
+ max-width: 999px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 20px;
+ padding-right: 20px;
+ width: 100%;
+}
+.ref-wrapper {
+ max-width: 1200px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 20px;
+ padding-right: 20px;
+ width: 100%;
+}
+.ref-foot-cpy-rt {
+ width: 100%;
+ text-align: center;
+ color: #6F6969;
+ font-size: 12px;
+ border-top: 1px solid rgba(255, 255, 255, 0.3);
+ padding-top: 2rem;
+}
+.o_footer_copyright{
+ display:none;
+}
+@media (max-width: 1199.98px)
+.ref-wrapper {
+ max-width: 999px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 20px;
+ padding-right: 20px;
+ width: 100%;
+}
+.ref-searchbox {
+ position: relative;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ WIDTH: 10px;
+}
+.ref-searchbox input {
+ padding: 6px 40px 6px 6px;
+ border-radius: 4px;
+ width: 400px;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+}
+.ref-searchbox button {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 35px;
+ height: 100%;
+ background-color: #0D5272;
+ color: #fff;
+ border: none;
+ border-radius: 0 4px 4px 0;
+ cursor: pointer;
+}
+.ref-searchbox input {
+ padding: 6px 40px 6px 6px;
+ border-radius: 4px;
+ width: 420px;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ margin-left: 290px;
+}
+@media (max-width: 1199.98px)
+.ref-wrapper {
+ max-width: 999px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 20px;
+ padding-right: 20px;
+ width: 100%;
+}
+.ref-head {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ padding: 1rem 0px;
+}
+.ref-header__icons {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ margin-left: 410px;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ gap: 1rem;
+}
+.ref-header--icon img {
+ width: 22px;
+ height: 22px;
+}
+@media(max-width:1500px) {
+ .ref-header__icons {
+ margin-left: 350px;
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ justify-content: center;
+ gap: 1rem;
+}
+ }
+ @media(max-width:1400px) {
+ .ref-header__icons {
+ margin-left: 211px;
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ justify-content: center;
+ gap: 1rem;
+ margin-right: 90px;
+}
+ }
+ @media(max-width:1284px) {
+ .ref-header__icons {
+ margin-left: 180px;
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ justify-content: center;
+ gap: 1rem;
+}
+.ref-logo {
+ font-weight: 700;
+ font-size: 36px;
+ color: #000000;
+ margin-left: 50px;
+}
+ }
+@media(max-width:1170px) {
+ .ref-header__icons {
+ margin-left: 200px;
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ justify-content: center;
+ gap: 1rem;
+}
+ }
+@media(max-width:1100px) {
+ .ref-header__icons {
+ margin-left: 250px;
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ justify-content: center;
+ gap: 1rem;
+}
+ }
+ @media(max-width:1000px) {
+ .ref-searchbox input {
+ padding: 6px 40px 6px 6px;
+ border-radius: 4px;
+ width: 420px;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ margin-left: 132px;
+}
+ }
+ @media(max-width:920px) {
+ .ref-searchbox input {
+ padding: 6px 40px 6px 6px;
+ border-radius: 4px;
+ width: 420px;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ margin-left: 82px;
+}
+ }
+ @media(max-width:780px) {
+ .ref-logo {
+ font-weight: 700;
+ font-size: 36px;
+ color: #000000;
+ margin-left: 16px;
+}
+.ref-searchbox input {
+ padding: 6px 40px 6px 6px;
+ border-radius: 4px;
+ width: 420px;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ margin-left: 15px;
+}
+.ref-header__icons {
+ margin-left: 50px;
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ justify-content: center;
+ gap: 1rem;
+}
+ }
+.navbar-nav {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ gap: 38px;
+ padding: 24px 0px;
+ margin-bottom: 0px;
+ flex-direction: row-reverse;
+}
+.navbar-nav .nav-link {
+ padding-right: 0;
+ padding-left: 0;
+ margin-right: -25px;
+ color: #0d5272;
+}
+.oe_website_login_container .input-group {
+ margin-left: -5px;
+ margin-top: 25px;
+}
+.o_cart_product .input-group > :not(:first-child):not(.dropdown-menu):not(.o_dropdown_menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {
+ margin-left: unset;
+}
+.o_cart_product .js_add_cart_json:focus{
+box-shadow:none;
+}
+.oe_website_login_container .input-group{
+ width: 410px;
+}
+.oe_website_login_container a{
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+.oe_website_login_container .input-group > :not(:first-child):not(.dropdown-menu):not(.o_dropdown_menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {
+ margin-left: unset;
+}
+#contact6 {
+ width: 445px;
+ margin-left: 415px
+}
+#contact5 {
+ width: 445px;
+ margin-left: 415px
+}
diff --git a/theme_eco_refine/static/src/css/home.css b/theme_eco_refine/static/src/css/home.css
new file mode 100755
index 0000000000..c7a5e64525
--- /dev/null
+++ b/theme_eco_refine/static/src/css/home.css
@@ -0,0 +1,1392 @@
+.ref-hero-bg {
+ background-color: #f0f0f0;
+ background-image: url("/theme_eco_refine/static/src/img/refurbished-img.jpg");
+ background-position: center;
+ background-size: cover;
+ height: 590px;
+ width: 100%;
+}
+.oe_login_form, .oe_signup_form, .oe_reset_password_form {
+ max-width: 435px;
+ position: relative;
+ margin: 50px auto;
+}
+
+element.style {
+}
+.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.o_dropdown_menu), .input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n + 3) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.input-group > .form-control:focus, .input-group > .form-select:focus {
+ z-index: 3;
+}
+.form-control:focus {
+ background-color: #FFFFFF;
+}
+.input-group .form-control {
+ height: 64px;
+}
+#o_wsale_cta_wrapper .js_add_cart_json{
+ margin-left: 0px;
+}
+#o_wsale_cta_wrapper .input-group > :not(:first-child):not(.dropdown-menu):not(.o_dropdown_menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){
+ margin-left: unset;
+}
+.coupon_form .input-group > :not(:first-child):not(.dropdown-menu):not(.o_dropdown_menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){
+ margin-left: unset;
+ height: 64px !important;
+ display: flex;
+ align-items: center;
+}
+}
+.input-group > .form-control, .input-group > .form-select {
+ position: relative;
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 auto;
+ flex: 1 1 auto;
+ width: 1%;
+ min-width: 350px;
+
+ /* height: 40px; */
+ /* border-width: 2px; */
+ /* border-color: #0d5272; */
+}
+.input-group > .form-control, .input-group > .form-select {
+ position: relative;
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 auto;
+ flex: 1 1 auto;
+ width: 1%;
+ min-width: 0;
+}
+
+.text-center{
+ color: #0D5272;
+}
+.ref-hero-carousel {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ height: 100%;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+}
+.ref-hero__mainhead {
+ font-size: 48px;
+ font-weight: 700;
+ width: 58%;
+ color: black;
+}
+.ref-hero__mainhead .tech {
+ color: #0D5272 !important;
+}
+.carousel-indicators .active {
+ background-color: #0D5272;
+}
+.carousel-indicators li {
+ position: relative;
+ -webkit-box-flex: 0;
+ -ms-flex: 0 1 auto;
+ flex: 0 1 auto;
+ width: 0.8rem;
+ height: 0.8rem;
+ border-radius: 50px;
+ margin-right: 3px;
+ margin-left: 3px;
+ text-indent: -999px;
+ background-color: #6F6969;
+ cursor: pointer;
+}
+.ref-search-input-box input:focus {
+ outline: none;
+}
+.ref-hero__subhead {
+ font-weight: 500;
+ font-size: 26px;
+ color: #6F6969;
+}
+.o_homepage_editor_welcome_message {
+ padding-top: 0px;
+ padding-bottom: 128px;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Ubuntu, "Liberation Sans", Arial, "Odoo Unicode Support Noto", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ max-width: 100%;
+}
+.ref-hero-section{
+ margin-top: -126px;
+ width: 102%;
+ margin-left: -14px;
+}
+.ref-logo {
+ font-weight: 700;
+ font-size: 36px;
+ color: #000000;
+}
+.ref-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 1rem 0px;
+}
+.ref-searchbox {
+ position: relative;
+ display: flex;
+ align-items: center;
+}
+.ref-searchbox {
+ input {
+ padding: 6px 40px 6px 6px;
+ border-radius: 4px;
+ width: 400px;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ }
+}
+.ref-searchbox {
+ button {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 35px;
+ height: 100%;
+ background-color: $primary-color;
+ color: #fff;
+ border: none;
+ border-radius: 0 4px 4px 0;
+ cursor: pointer;
+ }
+}
+.ref-searchbox {
+ button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
+.ref-header__icons {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 1rem;
+}
+.ref-header--icon {
+ width: 22px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+}
+.ref-header--icon img {
+ width: 100%;
+ height: auto;
+}
+.ref-border {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.3);
+}
+.ref-nav-menu {
+ list-style: none;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 38px;
+ padding: 54px 0px;
+ margin-bottom: 0px;
+}
+.ref-nav-menu {
+ li {
+ a {
+ font-weight: 500;
+ font-size: 18px;
+ line-height: 24px;
+ color: #000000;
+ text-decoration: none;
+ position: relative;
+ }
+ }
+}
+.ref-nav-menu {
+ li {
+ a.active {
+ font-weight: 600;
+ }
+ }
+}
+.ref-nav-menu {
+ li {
+ a.active::after {
+ content: "";
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 40%;
+ height: 3px;
+ font-weight: 600;
+ background-color: $primary-color;
+ transition: width 0.3s ease-in-out;
+ border-radius: 50px;
+ }
+ }
+}
+.ref-nav-menu {
+ li {
+ a:after {
+ content: "";
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 0;
+ height: 3px;
+ font-weight: 600;
+ background-color: $primary-color;
+ transition: width 0.8s cubic-bezier(0.5, 0, 0.75, 0.9);
+ border-radius: 50px;
+ }
+ }
+}
+.ref-nav-menu {
+ li {
+ a:hover::after {
+ width: 40%;
+ }
+ }
+}
+.ref-hero-carousel {
+ display: flex;
+ height: 100%;
+ justify-content: center;
+ flex-direction: column;
+}
+.ref-hero__mainhead {
+ font-size: 48px;
+ font-weight: 700;
+ width: 58%;
+ color: black;
+}
+.ref-hero__mainhead .tech {
+ color: $primary-color !important;
+}
+.carousel-indicators .active {
+ background-color: $primary-color;
+}
+.carousel-indicators li {
+ position: relative;
+ -webkit-box-flex: 0;
+ -ms-flex: 0 1 auto;
+ flex: 0 1 auto;
+ width: 0.8rem;
+ height: 0.8rem;
+ border-radius: 50px;
+ margin-right: 3px;
+ margin-left: 3px;
+ text-indent: -999px;
+ background-color: $dark-grey;
+ cursor: pointer;
+}
+.ref-search-input-box input:focus {
+ outline: none;
+}
+.ref-hero__subhead {
+ font-weight: 500;
+ font-size: 26px;
+ color: $dark-grey;
+}
+.ref-collection--container {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: space-between;
+ gap: 20px;
+}
+.ref-collection__item {
+ flex-basis: calc(20% - 20px);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+}
+.ref-collection__item--box {
+ width: 120px;
+ height: 120px;
+ background-color: #0d5272;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+}
+.ref-collection__item--box img {
+ filter: invert(0%);
+ transition: filter 0.3s ease;
+}
+.ref-collection__item:hover .ref-collection__item--box,
+.ref-collection__item.selected .ref-collection__item--box {
+ box-shadow: 0px 0px 9px $primary-color;
+ background-color: $primary-color;
+ color: white;
+}
+.ref-collection__item:hover .ref-collection__item--box img,
+.ref-collection__item.selected .ref-collection__item--box img {
+ filter: invert(100%);
+}
+.ref-product--container {
+ display: flex;
+ justify-content: space-between;
+}
+.ref-product-detail-box {
+ flex-basis: 20%;
+}
+.ref-product__box {
+ position: relative;
+}
+.ref-product__box img {
+ height: auto;
+ transition: filter 0.3s ease;
+}
+.product-box-overlay_container {
+ background-color: rgba(20, 108, 148, 0.16);
+ opacity: 0;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 0;
+ top: 0;
+}
+.ref-product__box:hover .product-box-overlay_container {
+ opacity: 1;
+}
+.ref-product__box {
+ .overlay {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ padding: 10px;
+ opacity: 0;
+ transition: opacity 0.3s ease;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 1rem;
+ }
+}
+.product-box:hover img {
+ filter: brightness(70%);
+}
+.ref-product__box:hover .overlay {
+ opacity: 1;
+}
+.overlay-icon-container {
+ width: 32px;
+ height: 32px;
+ background-color: $primary-color;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+}
+.product-detail {
+ text-align: center;
+}
+.ref-banner-section {
+ background-image: linear-gradient(85.66deg, rgba(13, 82, 114, 0.46) 10.47%, rgba(42, 203, 225, 0.0552) 46.94%, rgba(224, 34, 34, 0.4554) 94.18%), url("/theme_eco_refine/static/src/img/shopping-banner-img.png");
+ background-position: center;
+ background-size: cover;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ height: 460px;
+}
+.ref-border_btn {
+ text-decoration: none;
+ color: #000;
+ padding: 0.5rem 1.5rem;
+ border: 2px solid #000;
+ width: -webkit-fit-content;
+ width: -moz-fit-content;
+ width: fit-content;
+}
+.ref-banner-section {
+ padding: 100px 0px;
+ width: 142%;
+ margin-left: -270px;
+}
+.ref-banner-section span {
+ text-align: center;
+ width: 50%;
+ font-size: 45px;
+ margin-bottom: 0.5rem;
+ font-weight: 600;
+}
+.ref-banner-section p {
+ width: 48%;
+ text-align: center;
+ line-height: 28px;
+}
+.ref-banner-section a {
+ font-weight: 500;
+ -webkit-transition: 0.3s ease-in-out;
+ transition: 0.3s ease-in-out;
+}
+.ref-arrival-section {
+ text-align: center;
+}
+.ref-banner-section a:hover {
+ font-size: 18px;
+}
+.ref-arrival-content {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+}
+.ref-banner_sm--container {
+ flex-basis: 48%;
+ background-image: url('/theme_eco_refine/static/src/img/shopping-banner2.png');
+ background-position: center;
+ background-size: cover;
+ padding: 50px;
+ display: flex;
+ align-items: flex-end;
+ flex-direction: column;
+}
+.banner-box {
+ /* display: flex;
+ justify-content: space-between;
+ align-items: center;*/
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+}
+.banner-lft {
+ width: 73%;
+}
+.banner-bg-sm {
+ background-image: url('/theme_eco_refine/static/src/img/shopping-cart-fil.png');
+ align-items: flex-start;
+}
+.ref-banner_text {
+ color: #fff;
+ padding-bottom: 1rem;
+ font-weight: 500;
+}
+.overlay img {
+ width: 16px !important;
+}
+.owl-theme .owl-dots {
+ display: none;
+}
+.ref-testimonial-section {
+ margin: 100px 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+}
+.ref-testimonial__head {
+ text-align: center;
+ color: #6F6969;
+ font-weight: 600;
+}
+.ref-testimonial__content {
+ background: #0d5272;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 50px;
+ padding-top: 105px;
+ gap: 100px;
+ position: relative;
+}
+.ref-testimonial-text {
+ p {
+ font-weight: 600;
+ font-size: 24px;
+ line-height: 42px;
+ color: #A9A9A9;
+ position: relative;
+ }
+}
+.ref-testimonial-text p::before {
+ content: "";
+ position: absolute;
+ background: url('/theme_eco_refine/static/src/img/quotes-before.svg');
+ top: -84px;
+ left: 0;
+ width: 69px;
+ height: 54px;
+}
+.ref-testimonial-text p::after {
+ content: "";
+ position: absolute;
+ background: url(../images/quotes-after.svg);
+ bottom: -84px;
+ right: 0;
+ width: 69px;
+ height: 54px;
+}
+.ref-testimonial-text {
+ span {
+ font-weight: 600;
+ font-size: 30px;
+ line-height: 45px;
+ color: #FFFFFF;
+ position: relative;
+ }
+}
+.ref-testimonial__content img {
+ width: fit-content !important;
+}
+.panel-default>.panel-heading a[aria-expanded="true"]:after {
+ content: url("/theme_eco_refine/static/src/img/cross.svg");
+ float: right;
+ transform: rotate(180deg);
+}
+.panel-default>.panel-heading a[aria-expanded="false"]:after {
+ content: url("/theme_eco_refine/static/src/img/plus.svg");
+ float: right;
+ transform: rotate(90deg);
+}
+.custom-nav,
+.custom-nav img {
+ display: flex;
+}
+.owl-carousel .owl-item img {
+ display: flex;
+}
+.custom-nav {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ margin: 0 50px 50px;
+}
+.custom-nav {
+ .custom-nav__prev,
+ .custom-nav__next {
+ cursor: pointer;
+ margin: 2px;
+ }
+}
+.ref-faq-section__content {
+ margin: 30px 0px 0px 0px;
+}
+.custom-nav__prev,
+.custom-nav__next {
+ filter: invert(100%);
+ color: white;
+}
+.ref-faq-question {
+ font-weight: 500;
+ font-size: 22px;
+ line-height: 48px;
+}
+.ref-header-menubar {
+ cursor: pointer;
+}
+.ref-fag-index {
+ color: rgba(0, 51, 102, 0.16);
+ font-weight: 700;
+ padding-right: 2px;
+ font-size: 22px;
+}
+.ref-faq-question:hover {
+ color: $primary-color;
+}
+.ref-faq-panel {
+ font-weight: 400;
+ font-size: 18px;
+ line-height: 36px;
+ width: 90%;
+ color: $dark-grey;
+ margin-bottom: 20px;
+ margin-left: 32px;
+}
+#ref-footer {
+ background-color: #000;
+ padding: 100px 0px 50px 0px;
+}
+#ref-footer {
+ .ref-logo {
+ color: #fff;
+ }
+}
+.ref-foot_head {
+ color: #fff;
+ font-size: 22px;
+ line-height: 36px;
+}
+#ref-footer {
+ ul {
+ list-style: none;
+ }
+}
+#ref-footer {
+ li {
+ margin-right: 1rem;
+ }
+}
+.ref-footer-section {
+ margin-bottom: 50px;
+}
+.subscription-form {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ align-items: center;
+ margin-top: 20px;
+ position: relative;
+}
+.subscription-form input[type="email"] {
+ width: 450px;
+ border-radius: 6px;
+ padding: 12px;
+ margin: 50px 0px 0px 0px;
+}
+.ref-foot-row {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ width: 100%;
+}
+.subscription-form button {
+ background-color: $primary-color;
+ color: #fff;
+ border: none;
+ position: absolute;
+ right: 0;
+ margin: 6px;
+ top: 50px;
+ cursor: pointer;
+}
+.column {
+ flex-basis: 20%;
+}
+.subscription-form button a {
+ color: #fff;
+}
+.ref-foot-para {
+ color: #A9A9A9;
+ line-height: 36px;
+}
+.ref-foot-cpy-rt {
+ width: 100%;
+ text-align: center;
+ color: $dark-grey;
+ font-size: 12px;
+ border-top: 1px solid rgba(255, 255, 255, 0.3);
+ padding-top: 2rem;
+}
+.ref-menubar-header {
+ display: none;
+}
+.menu-list {
+ display: none;
+}
+button:focus {
+ outline: none;
+}
+.ref-login-container .ref-signup-btn:hover{
+ color: #fff;
+}
+@media(max-width:$breakpoint-lg) {
+ .ref-wrapper {
+ max-width: 999px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 20px;
+ padding-right: 20px;
+ width: 100%;
+ }
+ .ref-hero__mainhead {
+ width: 70%;
+ }
+}
+@media(max-width:$breakpoint-md) {
+ .ref-collection--container {
+ justify-content: center;
+ }
+ .ref-collection__item {
+ flex-basis: calc(30% - 20px);
+ }
+ .ref-testimonial-text p {
+ font-size: 18px;
+ line-height: 36px;
+ }
+ .ref-testimonial-text span {
+ font-size: 26px;
+ line-height: 40px;
+ }
+ .ref-testimonial__content {
+ gap: 30px;
+ }
+ .ref-banner-section span {
+ width: 78%;
+ font-size: 40px;
+ }
+ .ref-banner-section p {
+ width: 60%;
+ line-height: 28px;
+ }
+ .ref-banner_sm--containner {
+ padding: 30px;
+ }
+ .ref-banner_text {
+ font-size: 1.6rem;
+ line-height: 42px;
+ }
+}
+@media(max-width:$breakpoint-sm) {
+ .ref-hero__mainhead {
+ font-size: 38px;
+ width: 71%;
+ }
+ .ref-collection__item--box {
+ width: 100px;
+ height: 100px;
+ }
+ .ref-collection__item--box img {
+ width: 50px;
+ height: auto;
+ }
+ .ref-header {
+ display: none;
+ }
+ .ref-menubar-header {
+ display: block;
+ position: relative;
+ }
+ .ref-logo {
+ font-size: 22px;
+ }
+ .ref-header__logo {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ }
+ .ref-menubar-nav {
+ background: #FFFFFF;
+ width: 100%;
+ height: 100%;
+ }
+ .menu-list {
+ display: block;
+ position: fixed;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background-color: $secondary-color;
+ z-index: 9999;
+ transition: left 0.3s ease-in-out;
+ }
+ .menu-list.open {
+ left: 0;
+ }
+ .menu-list ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ }
+ .menu-list ul li {
+ padding: 10px;
+ color: $primary-color;
+ font-size: 18px;
+ font-weight: 500;
+ }
+ .close-icon {
+ margin: 1rem 0;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ cursor: pointer;
+ }
+ .ref-search-input-box {
+ position: absolute;
+ top: 82px;
+ z-index: 2000;
+ right: 16%;
+ padding: 1rem;
+ background: #fff;
+ border-radius: 4px;
+ display: none;
+ box-shadow: 0 4px 9px rgba(0, 0, 0, 0.2);
+ }
+ .ref-search-input-box input {
+ border: none;
+ border-bottom: 1px solid black;
+ }
+ .ref-head {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.3);
+ }
+ .ref-search:hover .ref-search-input-box {
+ display: flex;
+ }
+ .banner-box {
+ flex-wrap: wrap;
+ gap: 30px;
+ }
+ .ref-banner_sm--containner {
+ flex-basis: 100%;
+ }
+ .ref-product--container {
+ flex-wrap: wrap;
+ }
+ .ref-product-detail-box {
+ flex-basis: 48%;
+ }
+ .column {
+ flex-basis: 48%;
+ }
+ .ref-faq-question {
+ font-size: 18px;
+ line-height: 42px;
+ }
+ .ref-testimonial__content img {
+ width: 100% !important;
+ }
+ .ref-testimonial-text p {
+ font-size: 16px;
+ line-height: 32px;
+ }
+ .ref-testimonial-text span {
+ font-size: 22px;
+ line-height: 20px;
+ }
+ .ref-testimonial__content {
+ gap: 24px;
+ }
+ .ref-testimonial__content {
+ padding: 30px;
+ }
+ .ref-testimonial-text p::before {
+ display: none;
+ }
+ .ref-testimonial-text p::after {
+ display: none;
+ }
+ .custom-nav {
+ margin: 27px;
+ }
+ .product-detail {
+
+ margin-top: 12px;
+ }
+ .custom-nav img {
+ width: 50px !important;
+ }
+}
+@media(max-width:768px) {
+ .modal-dialog-centered{
+
+ }
+ .ref-hero-bg {
+ height: 40vh;
+ }
+.o_header_mobile_buttons_wrap .o_wsale_my_cart{
+ display:none !important;
+ background-color:red;
+}
+
+ .subscription-form button {
+ font-size: 12px;
+ }
+ .subscription-form input[type=email] {
+ width: 300px;
+ font-size: 12px;
+ }
+ .ref-banner-section span {
+ width: 95%;
+ font-size: 24px;
+ }
+ .ref-banner-section p {
+ width: 95%;
+ }
+ .ref-banner-section {
+ padding: 60px 0px;
+ }
+ .ref-collection__item {
+ flex-basis: calc(50% - 20px);
+ }
+ .ref-hero__mainhead {
+ font-size: 24px;
+ width: 100%;
+ }
+ .ref-hero__subhead {
+ font-size: 14px;
+ }
+ .ref-banner_text {
+ font-size: 1.2rem;
+ line-height: 24px;
+ }
+ .ref-faq-panel {
+ font-size: 12px;
+ line-height: 32px;
+ }
+ .ref-faq-question {
+ font-size: 14px;
+ line-height: 32px;
+ }
+ .ref-fag-index {
+ font-size: 18px;
+ }
+ .ref-testimonial__content {
+ padding: 20px;
+ }
+ .ref-testimonial-text p {
+ font-size: 14px;
+ line-height: 26px;
+ }
+ .ref-testimonial-text span {
+ font-size: 18px;
+ line-height: 15px;
+ }
+ .custom-nav {
+ margin: 16px;
+ }
+ .ref-testimonial__content {
+ flex-direction: column;
+ }
+ .ref-testimonial__content img {
+ width: 140px !important;
+ }
+ .custom-nav img {
+ width: 50px !important;
+ }
+ .ref-testimonial-section {
+ margin: 50px 0;
+ }
+ .ref-search-input-box input {
+ font-size: 14px;
+ }
+}
+#top_products_carousel {
+ margin-top: 30px;
+}
+#new_arrival_carousel {
+ margin-top: 30px;
+}
+.sign_and_buy_snippet{
+ margin-top: 15px;
+}
+.ref-head--primary {
+ color: #0D5272!important;
+ text-decoration:none!important
+}
+.ref-testimonial-text p {
+ font-weight: 600;
+ font-size: 24px;
+ line-height: 42px;
+ color: #A9A9A9;
+ position: relative;
+}
+.ref-testimonial-text span {
+ font-weight: 600;
+ font-size: 30px;
+ line-height: 45px;
+ color: #FFFFFF;
+ position: relative;
+}
+.ref-testimonial-text p::after {
+ content: "";
+ position: absolute;
+ background: url('/theme_eco_refine/static/src/img/quotes-after.svg');
+ bottom: -84px;
+ right: 0;
+ width: 69px;
+ height: 54px;
+}
+.custom-nav {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ margin: 0 50px 20px;
+}
+.ref-light-section {
+ background-color: #EAF8FF;
+ padding: 50px 0px;
+ width: 100%;
+
+}
+#top_menu_collapse .o_wsale_my_wish{
+ display:none;
+}
+#top_menu_collapse .o_wsale_my_cart{
+ display:none;
+}
+#top_menu_collapse .o_no_autohide_item{
+ display:none;
+}
+.ref-header{
+ background-color:#fff;
+}
+.multirange-wrapper small span{ color:#000 !important; }
+@media only screen and (max-width: 574px) and (min-width: 515px) {.subscription-form button{ right:62px !important; }}
+@media (max-width: 576px) {
+
+ .carousel-control-next{ right: -10px !important;
+ top: -89px; }
+
+.carousel .carousel-control-prev{ left: 130px !important;
+ top: -89px; }
+
+ .o_carousel_product_card{ margin-left:12px; }
+
+.css_quantity .quantity{ min-width:100% !important; }
+
+#product_option_block{
+ display: inline-block !important;
+ height: auto;
+ grid-area: c;
+}
+/*#add_to_cart_wrap{
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ padding-bottom: 12px;
+}
+
+
+#add_to_cart_wrap {
+
+ grid-area: b;
+ }
+#o_wsale_cta_wrapper {
+ display: grid !IMPORTANT;
+ grid-template-areas:
+ "a a a a"
+ "b b c c";
+ gap: 10px;
+}*/
+.css_quantity .js_add_cart_json {
+ width: 100%;
+ max-width: unset;
+}
+#add_to_cart_wrap{
+width:100%;
+}
+#add_to_cart,
+.o_add_wishlist_dyn{
+margin-top:0px;
+margin-left:0px;
+width:100%;
+}
+.css_quantity {
+ width: 100%;
+ display: grid !important;
+ grid-template-columns: 56px 1fr 56px;
+ border-radius: 5px;
+}
+.ref-contant-form_input{ width:auto !important; }
+.s_col_no_resize div{ display:flex; justify-content:center; }
+.s_col_no_resize #contact6{
+ margin-left: 0px !important;
+ width: 229px !important;
+}
+.tab-container{
+ margin-top: 40px;
+}
+.s_col_no_resize #contact5 {
+ margin-left: 0px !important;
+ width: 229px !important;
+}
+.ref-contact-info{ display:block !important; }
+.ref-abt-button__mobcontent{ width:320px !important; font-size:13px; }
+.website_blog nav ul{
+ display: block !important;
+ float: left;
+ width: 100%;
+ padding-bottom:0px;
+
+ }
+ .website_blog nav ul li:nth-child(1) {
+ margin-left:0px;
+}
+ .website_blog nav ul li{ float:left; margin-left:35px; }
+#wrapwrap .website_blog .search-query {
+ min-width:83% !important;
+ margin-left:312px !important;
+}
+.ref-wrapper{
+ padding-left:0px !important;
+ padding-right:0px !important;
+}
+#ref-footer .ref-header__logo .ref-logo {
+ margin-left: 18px !important;
+}
+.ref-wrapper .ref-searchbox{
+ left: -89px !important;
+}
+.ref-banner-section span{
+ width:90% !important;
+}
+.ref-banner-section p{
+ width:90% !important;
+}
+.ref-wrapper .ref-searchbox .search-query {
+ min-width: 170px !important;
+ margin-left: 274px !important;
+}
+.banner-box{
+ display:block !important;
+}
+.banner-bg-sm{
+ margin-top:10px;
+}
+.ref-testimonial-photo{
+ display:none;
+}
+.ref-light-section{
+ padding: 50px 25px !important;
+}
+.ref-foot-row{
+ display:block !important;
+}
+.ref-foot-para {
+ width: 70%;
+ padding-left: 18px;
+}
+.subscription-form button{
+ right:0px;
+}
+.navbar-light .navbar-nav .nav-link{
+ font-size:15px;
+}
+}
+@media (max-width: 768px) {
+.o_container_small{ max-width:100% !important; }
+.o_container_small{ max-width:100% !important; }
+#o_wblog_post_content .text-decoration-none .o_record_cover_container{ width:100% !important; }
+#o_wblog_post_content .o_record_cover_component{ width:100% !important; }
+.o_wblog_post_content_field .mt-2{ width:100% !important; }
+.website_blog .o_wblog_read_text .lead{ width:100% !important; }
+.website_blog .o_wblog_read_text p{ width:100% !important; }
+.website_blog .o_wblog_read_text ol{ width:100% !important; }
+ .website_blog #o_wblog_post_main .o_wblog_read_text{ width:100% !important; }
+.s_col_no_resize div{ display:flex; justify-content:center; }
+.s_col_no_resize #contact6{
+ margin-left: 0px !important;
+ width:450px;
+}
+.s_col_no_resize #contact5 {
+ margin-left: 0px !important;
+ width:450px;
+}
+.ref-contact-info{ display:block !important; }
+.website_blog nav ul{
+ display:block !important;
+ float: left;
+ width: 100%;
+ padding-bottom:0px;
+
+ }
+ .website_blog nav ul li:nth-child(1) {
+ margin-left:0px;
+}
+ .website_blog nav ul li{ float:left; margin-left:35px; }
+.website_blog .container { max-width:100% !important; }
+ .ref-searchbox{
+ position: relative;
+ top: 67px;
+ left: -178px !important;
+ z-index: 9;
+ }
+ .ref-searchbox .search-query{
+ min-width: 170px;
+ margin-left: 193px;
+ }
+ .ref-logo{
+ margin-left:16px !important;
+ }
+#o_wblog_index_content {
+ margin-left: 140px !important;
+}
+}
+@media (max-width: 992px) {
+
+
+.s_col_no_resize div{ display:flex; justify-content:center; }
+.s_col_no_resize #contact6{
+ margin-left: 0px !important;
+ width:450px;
+}
+.s_col_no_resize #contact5 {
+ margin-left: 0px !important;
+ width:450px;
+}
+.ref-contact-info{ display:block !important; }
+.website_blog .o_searchbar_form .search-query{ min-width: 239px !important;
+ margin-left:378px !important; }
+.multirange-wrapper small span{ color:#000 !important; }
+.ref-banner-section{
+ width:auto !important;
+ margin-left:0px !important;
+ height:auto !important;
+}
+.ref-testimonial-photo{
+ display:none;
+}
+.home_sign_up_snippet{
+ max-width:100% !important;
+ }
+ .sign_and_buy_snippet{
+ max-width:100% !important;
+ }
+ .ref-searchbox{
+ position: relative;
+ top: 67px;
+ left: -228px;
+ z-index: 9;
+ }
+ .ref-searchbox .search-query{
+ min-width: 170px;
+ margin-left: 193px;
+ }
+ .navbar-nav {
+ flex-direction: column !important;
+
+ }
+ .ref-logo{
+ margin-left:0px;
+ }
+ .accordion-item{
+ padding:0px !important;
+ }
+ .o_searchbar_form .oe_search_box{
+ min-width: 292px !important;
+ margin-left: 314px !important;
+ }
+ }
+@media (max-width: 1200px) {
+.s_col_no_resize div{ display:flex; justify-content:center; }
+.s_col_no_resize #contact6{
+ margin-left: 0px !important;
+ width:450px;
+}
+.s_col_no_resize #contact5 {
+ margin-left: 0px !important;
+ width:450px;
+}
+.ref-contact-info{ display:block !important; }
+ .multirange-wrapper small span{ color:#000 !important; }
+ .js_attributes a small b{ color:#000 !important; }
+ #ref-footer .ref-logo{ margin-left:0px !important; }
+ }
+ .js_attributes a small b{ color:#000 !important; }
+ #contact6, #contact5{ margin-left:330px !important; }
+.s_col_no_resize div{ display:flex; justify-content:center; }
+.s_col_no_resize #contact6{
+ margin-left: 0px !important;
+ width:450px;
+}
+.s_col_no_resize #contact5 {
+ margin-left: 0px !important;
+ width:450px;
+}
+.ref-contact-info{ display:block !important; }
+.s_newsletter_subscribe_form .input-group{
+ margin-left: 0px;
+ margin-top: 25px;
+}
+.js_subscribed_btn{
+ padding-top:20px;
+}
+.js_subscribe_btn{
+ padding-top:18px;
+ box-shadow: 0 0 0 0.25rem #0d5272;
+ margin-left: 0px !important;
+}
+.o_header_affixed {
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: auto;
+ right: 0;
+ /* position: fixed; */
+}
+.product_list .top_rate_product{
+ float: left;
+ margin-left: 27px;
+ width: 295px;
+ margin-top: 39px;
+}
+.carousel-item{
+ min-height :500px !important;
+}
+.dropdown-user li a div{
+display:contents;
+}
+.modal-open #wrapwrap {
+ overflow: auto;
+}
+#o_main_nav {
+ padding-left: 430px;
+}
+.oe_search_box{
+ box-shadow: none !important;
+}
+.o_wsale_apply_grid {
+ padding: 0.7rem 1rem !important;
+}
+.btn-group .btn-light.active {
+ box-shadow: inset 0 0 0 1px #0d5272;
+ border-color: transparent;
+ background-color: #f3f2f2;
+}
+.o_wsale_apply_list {
+ padding: 0.7rem 1rem !important;
+}
+.o_footer .btn-primary{
+border-radius:0px 0.2rem 0.2rem 0px;
+box-shadow:none !important;
+border-color: #0d5272 !important;
+}
+.o_footer .btn-primary:focus,
+.o_footer .btn-primary:active{
+ background-color: #0d5272 !important;
+ border-color: #0d5272 !important;
+ box-shadow:none !important;
+}
+.o_we_buy_now:focus{
+ background-color: #0d5272 !important;
+ border-color: #0d5272 !important;
+ box-shadow: none;
+}
+
+/*.main_body_refurbished_carousel .carousel-indicators [data-bs-target]{
+ width: 16px;
+ background-color: #dfdfdf;
+}
+.main_body_refurbished_carousel .carousel-indicators [data-bs-target].active{
+
+ background-color: #0d5272 !important;
+}*/
diff --git a/theme_eco_refine/static/src/css/owl.carousel.css b/theme_eco_refine/static/src/css/owl.carousel.css
new file mode 100755
index 0000000000..7c2817d37f
--- /dev/null
+++ b/theme_eco_refine/static/src/css/owl.carousel.css
@@ -0,0 +1,211 @@
+/**
+ * Owl Carousel v2.3.4
+ * Copyright 2013-2018 David Deutsch
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
+ */
+/*
+ * Owl Carousel - Core
+ */
+.owl-carousel {
+ display: none;
+ width: 100%;
+ -webkit-tap-highlight-color: transparent;
+ /* position relative and z-index fix webkit rendering fonts issue */
+ position: relative;
+ z-index: 1; }
+ .owl-carousel .owl-stage {
+ position: relative;
+ -ms-touch-action: pan-Y;
+ touch-action: manipulation;
+ -moz-backface-visibility: hidden;
+ /* fix firefox animation glitch */ }
+ .owl-carousel .owl-stage:after {
+ content: ".";
+ display: block;
+ clear: both;
+ visibility: hidden;
+ line-height: 0;
+ height: 0; }
+ .owl-carousel .owl-stage-outer {
+ position: relative;
+ overflow: hidden;
+ /* fix for flashing background */
+ -webkit-transform: translate3d(0px, 0px, 0px); }
+ .owl-carousel .owl-wrapper,
+ .owl-carousel .owl-item {
+ -webkit-backface-visibility: hidden;
+ -moz-backface-visibility: hidden;
+ -ms-backface-visibility: hidden;
+ -webkit-transform: translate3d(0, 0, 0);
+ -moz-transform: translate3d(0, 0, 0);
+ -ms-transform: translate3d(0, 0, 0); }
+ .owl-carousel .owl-item {
+ position: relative;
+ min-height: 1px;
+ float: left;
+ -webkit-backface-visibility: hidden;
+ -webkit-tap-highlight-color: transparent;
+ -webkit-touch-callout: none; }
+ .owl-carousel .owl-item img {
+ display: block;
+ width: 100%; }
+ .owl-carousel .owl-nav.disabled,
+ .owl-carousel .owl-dots.disabled {
+ display: none; }
+ .owl-carousel .owl-nav .owl-prev,
+ .owl-carousel .owl-nav .owl-next,
+ .owl-carousel .owl-dot {
+ cursor: pointer;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none; }
+ .owl-carousel .owl-nav button.owl-prev,
+ .owl-carousel .owl-nav button.owl-next,
+ .owl-carousel button.owl-dot {
+ background: none;
+ color: inherit;
+ border: none;
+ padding: 0 !important;
+ font: inherit; }
+ .owl-carousel.owl-loaded {
+ display: block; }
+ .owl-carousel.owl-loading {
+ opacity: 0;
+ display: block; }
+ .owl-carousel.owl-hidden {
+ opacity: 0; }
+ .owl-carousel.owl-refresh .owl-item {
+ visibility: hidden; }
+ .owl-carousel.owl-drag .owl-item {
+ -ms-touch-action: pan-y;
+ touch-action: pan-y;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none; }
+ .owl-carousel.owl-grab {
+ cursor: move;
+ cursor: grab; }
+ .owl-carousel.owl-rtl {
+ direction: rtl; }
+ .owl-carousel.owl-rtl .owl-item {
+ float: right; }
+
+/* No Js */
+.no-js .owl-carousel {
+ display: block; }
+
+/*
+ * Owl Carousel - Animate Plugin
+ */
+.owl-carousel .animated {
+ animation-duration: 1000ms;
+ animation-fill-mode: both; }
+
+.owl-carousel .owl-animated-in {
+ z-index: 0; }
+
+.owl-carousel .owl-animated-out {
+ z-index: 1; }
+
+.owl-carousel .fadeOut {
+ animation-name: fadeOut; }
+
+@keyframes fadeOut {
+ 0% {
+ opacity: 1; }
+ 100% {
+ opacity: 0; } }
+
+/*
+ * Owl Carousel - Auto Height Plugin
+ */
+.owl-height {
+ transition: height 500ms ease-in-out; }
+
+/*
+ * Owl Carousel - Lazy Load Plugin
+ */
+.owl-carousel .owl-item {
+ /**
+ This is introduced due to a bug in IE11 where lazy loading combined with autoheight plugin causes a wrong
+ calculation of the height of the owl-item that breaks page layouts
+ */ }
+ .owl-carousel .owl-item .owl-lazy {
+ opacity: 0;
+ transition: opacity 400ms ease; }
+ .owl-carousel .owl-item .owl-lazy[src^=""], .owl-carousel .owl-item .owl-lazy:not([src]) {
+ max-height: 0; }
+ .owl-carousel .owl-item img.owl-lazy {
+ transform-style: preserve-3d; }
+
+/*
+ * Owl Carousel - Video Plugin
+ */
+.owl-carousel .owl-video-wrapper {
+ position: relative;
+ height: 100%;
+ background: #000; }
+
+.owl-carousel .owl-video-play-icon {
+ position: absolute;
+ height: 80px;
+ width: 80px;
+ left: 50%;
+ top: 50%;
+ margin-left: -40px;
+ margin-top: -40px;
+ background: url("owl.video.play.png") no-repeat;
+ cursor: pointer;
+ z-index: 1;
+ -webkit-backface-visibility: hidden;
+ transition: transform 100ms ease; }
+
+.owl-carousel .owl-video-play-icon:hover {
+ -ms-transform: scale(1.3, 1.3);
+ transform: scale(1.3, 1.3); }
+
+.owl-carousel .owl-video-playing .owl-video-tn,
+.owl-carousel .owl-video-playing .owl-video-play-icon {
+ display: none; }
+
+.owl-carousel .owl-video-tn {
+ opacity: 0;
+ height: 100%;
+ background-position: center center;
+ background-repeat: no-repeat;
+ background-size: contain;
+ transition: opacity 400ms ease; }
+
+.owl-carousel .owl-video-frame {
+ position: relative;
+ z-index: 1;
+ height: 100%;
+ width: 100%; }
+.owl-carousel .owl-nav button.owl-prev{
+ font-size: 3rem;
+ padding: 0.6rem;
+ border-radius: 50px;
+ padding: 0rem 1rem;
+ background-color: aliceblue;
+ padding-left: 37px;
+}
+.owl-carousel .owl-nav button.owl-next{
+ font-size: 3rem;
+ padding: 0.6rem;
+ border-radius: 50px;
+ padding: 0rem 1rem;
+ background-color: aliceblue;
+ padding-right: 57px;
+}
+.owl-nav{
+
+ display: flex;
+ justify-content: space-between;
+ position: absolute;
+ width: 100%;
+ top: 32%;
+}
+}
\ No newline at end of file
diff --git a/theme_eco_refine/static/src/css/product.css b/theme_eco_refine/static/src/css/product.css
new file mode 100755
index 0000000000..f3ef816d07
--- /dev/null
+++ b/theme_eco_refine/static/src/css/product.css
@@ -0,0 +1,665 @@
+.ref-prdt-bg {
+ background: -webkit-gradient(linear, left top, left bottom, from(rgba(20, 108, 148, 0.6)), to(#FFFFFF)), url(/theme_eco_refine/static/src/img/product-page-herobanner.png);
+ background: linear-gradient(180deg, rgba(20, 108, 148, 0.6) 0%, #FFFFFF 100%), url(/theme_eco_refine/static/src/img/product-page-herobanner.png);
+ background-size: cover;
+}
+.oi oi-search{
+ margin-left: -7px;
+}
+.input-group > .form-control, .input-group > .form-select {
+ position: relative;
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 auto;
+ flex: 1 1 auto;
+ width: 1%;
+ min-width: 350px;
+ margin-left: 250px;
+ height: 40px;
+ border-width: 2px;
+ border-color: #0d5272;
+}
+.input-group > .form-control{
+margin-left:0px;
+}
+.oe_search_button{
+ height: 40px;
+}
+ @media(max-width:1399px) {
+ .oe_search_button{
+ height: 59px;
+}
+}
+.input-group {
+ margin-left: 0px;
+ margin-top: 25px;
+}
+ @media(max-width:1254px) {
+ .input-group {
+ margin-left: -300px;
+ margin-top: 25px;
+}
+ }
+ @media(max-width:1100px) {
+ .input-group {
+ margin-left: -360px;
+ margin-top: 25px;
+}
+ }
+ @media(max-width:991px) {
+ .my_wish_quantity{
+ position:static !important;
+ }
+ .oe_cart{
+ margin-top: 2rem;
+ }
+ .o_wsale_my_wish{
+ display: none;
+ }
+ #customer_input{
+ width: 100% !important;
+ margin-left: 0px;
+ }
+.ref-abt_container{
+ display: none;
+ }
+
+ #add_to_cart {
+ margin-top: 10px;
+ margin-left: 28px;
+ font-size: 21px !important;
+ font-weight: 500 !important;
+ width: -moz-fit-content;
+ color: #fcffff;
+ background-color: #0d5272;
+ border-radius: 4px;
+ margin-bottom: 10px;
+},
+ }
+ @media(max-width:780px) {
+ .input-group {
+ margin-left: -410px;
+ margin-top: 25px;
+}
+ }
+ .ref-product-main-header__section {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+}
+.ref-section_head {
+ font-size: 28px;
+ color: black;
+ font-weight: 600;
+ padding: 1rem 0;
+}
+.o_wsale_products_grid_before_rail {
+ width: 85%;
+ padding: 0.7rem 0;
+}
+.ref-filter__settings-row {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ border-bottom: 1.2px solid #0D5272;
+}
+.ref-filter-head {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ gap: 8px;
+}
+.ref-sm-head {
+ font-weight: 500;
+ font-size: 20px;
+ line-height: 32px;
+
+}
+@media (max-width: 991.98px)
+.ref-sm-head {
+ font-size: 18px;
+ line-height: 38px;
+}
+.ref-filter_rest-btn {
+ background: none;
+ border: none;
+ color: #0D5272;
+ font-weight: 500;
+ font-size: 1rem;
+ cursor: pointer;
+}
+.accordion-item {
+ border-bottom: 1.2px solid #0D5272;
+ padding: 0.8rem 0;
+}
+.accordion-item {
+ border-bottom: 1.2px solid #0D5272;
+ padding: 0.8rem 0;
+}
+.mb-3{
+ line-height: 20px;
+ font-weight: 600;
+ padding: 0.5rem 0;
+}
+.form-check-input:checked {
+ background-color: #0d5272;
+ border-color: #0d5272;
+}
+.oe_search_button {
+ background-color: #0d5272;
+}
+.oi-search{
+ color:white;
+}
+.dropdown-toggle{
+ color:#0d5272;
+}
+
+@media (min-width: 600px)
+#products_grid:not(.o_wsale_layout_list) td.oe_product {
+ padding-bottom: 23.5px;
+ padding-left: 20px;
+ width: 10px;
+}
+.text-primary {
+ color: #121313 !important;
+}
+.h6 {
+ font-size: 1rem;
+ color: #195c79;
+}
+.o_wsale_products_item_title{
+ font-size: 20px;
+}
+.page-item.active .page-link {
+ z-index: 3;
+ color: #FFF;
+ background-color: #181818;
+ border-color: #35979c;
+}
+.o_wsale_products_grid_before_rail {
+ width: 85%;
+ padding: 0.7rem 0;
+ OVERFLOW: hidden;
+}
+.js_quantity{
+ max-width: 4rem;
+ margin-bottom: 0px;
+}
+.css_quantity{
+ margin-left: 0;
+ background: whitesmoke;
+}
+.oe_website_sale h1[itemprop="name"], .oe_website_sale .h1[itemprop="name"] {
+ font-size: 2rem;
+ font-weight: 700;
+}
+.oe_price{
+ white-space: nowrap;
+ color: #0d5272;
+ font-size: 40px;
+ font-weight: 600;
+}
+.text-danger {
+ color: #6f6969 !important;
+ font-size: unset;
+ font-weight: 600;
+}
+.list-inline-item{
+ margin: 0;
+ border-radius: 36px;
+ width: auto ;
+ border: 2px solid #0D5272;
+}
+.list-inline-item:active{
+ margin: 0;
+ background: #0d5272;
+ color: white;
+ border-radius: 36px;
+ width: auto ;
+}
+.col-form-label{
+ margin-left:7px;
+}
+.variant_custom_value{
+ margin-left:0px;
+ border-color: #0d5272;
+ border-block-width: 2px;
+}
+.quantity{
+ margin-bottom: 0;
+}
+.js_check_product{
+ padding: 0.5rem 1.5rem;
+ width: 223px;
+ font-size: 20px;
+ font-weight: 500;
+ color: #fcffff;
+ background-color: #0d5272;
+ border-radius: 8px;
+ display: block;
+}
+.list-group{
+ overflow: hidden;
+ border-width: 2px;
+ border-color: #0d5272;
+}
+.fa-minus {
+ color: #0d5272;
+ margin-top: 15px;
+}
+.fa-plus{
+ color: #0d5272;
+ margin-top: 15px;
+}
+.o_add_wishlist_dyn{
+ padding: 0.4rem 1.5rem;
+ width: 223px;
+ color: #fcffff;
+ background-color: #0d5272;
+ border-radius: 4px;
+ font-size: 21px;
+ font-weight: 500;
+ margin-bottom: 10px;
+}
+.btn-secondary {
+ color: #FFFFFF;
+ background-color: #0d5272;
+ border-color: #030303;
+}
+#login,#password,#confirm_password,#name{
+ margin-left:0px;
+ width: 410px;
+ border-width: 2px;
+ border-color: #0d5272;
+}
+
+#db{
+ height: 65px;
+ border-width: 2px;
+ border-color: #0d5272;
+}
+.input-group .btn-secondary {
+ height: 65px;
+}
+.oe_login_buttons .btn-primary{
+ width: 415px;
+ border-width: 2px;
+ background: #0d5272;
+}
+.btn-primary {
+ padding: 0.5rem 1.5rem;
+ width: -moz-fit-content;
+ color: #ffffff;
+
+ border-radius: 4px;
+}
+.btn-outline-primary {
+ color: #0d5272;
+ border-color: #0d5272;
+}
+.btn-outline-primary:disabled{
+color: #0d5272;
+}
+
+
+.float-end{
+ color: #ffffff !important;
+}
+
+.justify-content-between .btn-link{
+ color: #0d5272;
+}
+.me-sm-2{
+ display:none;
+}
+.justify-content-between a {
+ color: black;
+}
+.o_portal .justify-content-between a {
+ color: black;
+}
+.navbar-light .navbar-nav .nav-link {
+ color: rgb(25 70 76);
+}
+.o_pricelist_dropdown .dropdown-toggle{
+ padding: 0.6rem 1rem;
+ color: #0d5272;
+}
+.o_sortby_dropdown .dropdown-toggle{
+ color:#0d5272;
+ padding: 0.6rem 1rem;
+}
+.d-flex .btn-light {
+ color: #0d5272;
+ background-color: #f7f7f7;
+ border-color: #f7f7f7;
+}
+small, .small {
+ font-size: 0.875em;
+ color: white;
+}
+.input-group .oe_search_button{
+ width:100px;
+}
+.input-group .form-control{
+ height: 64px;
+}
+.input-group > :not(:first-child):not(.dropdown-menu):not(.o_dropdown_menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {
+ margin-left: 25px;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ height: 64px;
+}
+.o_header_standard .o_dropdown_menu{
+ display:none;
+}
+.modal-header{
+ color:#0d5275;
+}
+.css_attribute_select{
+ border-width: 2px;
+ border-color: #0d5272;
+}
+.navbar-light .navbar-nav .nav-link {
+ color: rgb(34 36 36 / 87%);
+ font-size: large;
+ font-weight: 600;
+}
+.progress-wizard .progress-wizard-step.active .progress-wizard-steplabel {
+ color: #0d5272;
+ font-weight: bolder;
+}
+.progress-wizard-step.active .progress-wizard-dot {
+ animation: fadeIn 1s ease 0s 1 normal none running;
+ background: #0d5272;
+ box-shadow: 0 0 0 0.1875rem white, 0 0 0 0.25rem rgb(53 151 156 / 50%);
+}
+.progress-wizard .progress-wizard-step.active .progress-wizard-dot {
+ animation: fadeIn 1s ease 0s 1 normal none running;
+ background: #0d5272;
+ box-shadow: 0 0 0 0.1875rem white, 0 0 0 0.25rem rgb(53 151 156 / 50%);
+}
+.td-product_name a {
+ color: #0d5272;
+}
+.o_legacy_dialog .fa {
+ color:#fcfeff;
+}
+
+.js_cart_summary{
+ border-width: 2px;
+ border-color: #0d5272;
+ width: 460px;
+}
+.card-body .d-xl-block, .show_coupon, .fa-trash-o{
+ color: #0d5272;
+}
+.alert-info .alert-link{
+ color:white;
+}
+.alert-info {
+ color: #ffffff;
+ background-color: #0d5272;
+ border-color: #030303;
+}
+.table-bordered > :not(caption) > * {
+ border-width: 2px 2px;
+ border-color: #0d5272;
+}
+.text-start a{
+ color:#0d5272;
+}
+.tab-container {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+}
+.tab {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+}
+.tab-content.active {
+ display: block;
+}
+.tab-content {
+ display: none;
+ padding: 1rem 0;
+ font-weight: 400;
+ font-size: 18px;
+ line-height: 33px;
+ color: #6F6969;
+}
+.tab-content {
+ display: none;
+ padding: 1rem 0;
+ font-weight: 400;
+ font-size: 18px;
+ line-height: 33px;
+ color: #6F6969;
+}
+.tab-link .active {
+ border-bottom: 3px solid #0D5272;
+}
+.tab-container button {
+ background: none;
+ border: none;
+ border-bottom: 1px solid #6F6969;
+ outline: none;
+}
+.tab-link {
+ -webkit-box-flex: 1;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+ padding: 10px;
+ background-color: transparent;
+ cursor: pointer;
+ font-weight: 600;
+ font-size: 20px;
+}
+.tab-content {
+ display: none;
+ padding: 1rem 0;
+ font-weight: 400;
+ font-size: 18px;
+ line-height: 33px;
+ color: #6F6969;
+}
+.tab-link.active {
+ border-bottom: 3px solid #0D5272;
+}
+@media (max-width: 991.98px)
+.tab-content p {
+ font-size: 14px;
+ line-height: 28px;
+}
+
+
+.s_searchbar_input .input-group {
+ margin-top: 25px;
+ padding-right: 21px;
+ padding-left: -3px;
+}
+.search-query{
+ margin-left:0px !important;
+}
+@media (max-width: 1299px)
+{
+ .s_searchbar_input .input-group {
+ margin-left: -315px;
+ margin-top: 25px;
+}
+.js_quantity{
+ width: 38px !important;
+
+}
+
+
+}
+.my_cart_quantity {
+ position: relative;
+ left: -15px;
+}
+.my_wish_quantity {
+ position: relative;
+ left: -15px;
+}
+.card {
+ overflow: hidden;
+ border-width: 2px;
+ border-color: #0d5272;
+}
+.coupon_form .form-control{
+ position: relative;
+ -webkit-box-flex: 1;
+ -webkit-flex: 1 1 auto;
+ flex: 1 1 auto;
+ width: 1%;
+ min-width: 311px;
+ margin-left: 0;
+ height: 40px;
+ border-width: 2px;
+ border-color: #0d5272;
+}
+.coupon_form .input-group{
+ margin-left: -1px;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ height: 40px;
+}
+.o_image_64_cover {
+ width: 80px;
+ height: 130px;
+ object-fit: cover;
+}
+#o-carousel-product .o_carousel_product_indicators .carousel-indicators li {
+ width: 64px;
+ height: 64px;
+ text-indent: unset;
+ transition: none;
+ border: 0px solid #CED4DA;
+ height: 130px;
+ width: 80px;
+}
+.o_carousel_product_indicators .carousel{
+ justify-content: center;
+}
+.ref-head__underline {
+ position: relative;
+ padding: 0px;
+ margin: 1rem 0;
+}
+.ref-head__underline::after {
+ content: "";
+ position: absolute;
+ width: 80%;
+ height: 3px;
+ background-color: #0D5272;
+ left: 0;
+ bottom: 0;
+ border-radius: 50px;
+}
+.product_price .small{
+ font-size: 0.875em;
+ color: rgb(13, 82, 114);
+}
+.dropdown-item:not(.disabled):not(:disabled):not(.o_wysiwyg_loader), .dropdown-item:not(.disabled):not(:disabled):not(.o_wysiwyg_loader) label {
+ cursor: pointer;
+ COLOR: #0d5272;
+}
+.o_carousel_product_card_body .h6 {
+ font-size: 20px;
+ color: #000000;
+ font-weight: 600;
+}
+.o_carousel_product_card_body .mt-2 {
+ color: #0d5272;
+ font-size: 25px;
+}
+.coupon_form .a-submit {
+ height: 40px !important;
+}
+
+small, .small {
+ font-size: 0.875em;
+ color: #0d5272;
+}
+.o-livechat-root .o-livechat-LivechatButton{
+
+ background-color: #0d5272 !important;
+}
+.o-livechat-LivechatButton {
+background-color: #0d5272 !important;
+}
+/*#product_option_block{
+ bottom: 51px;
+ position: absolute;
+}
+*/
+
+@media (max-width: 576px){
+#uniqueId, #TopuniqueId{
+ margin: 0px 0px !important;
+}
+#product_option_block{
+ position: unset;
+}
+}
+#o_wsale_cta_wrapper{
+ position: relative;
+}
+.o_we_buy_now{
+ display: block;
+ position: relative !important;
+ margin: 0 !important;
+ display: block;
+ border-radius: 3px;
+ width: 227px;
+ padding: 8px 15px;
+ color: #FFFFFF;
+ background-color: #0d5272 !important;
+ border-color: #0d5272 !important;
+ font-size: 20px;
+ font-weight: 500;
+}
+.o_we_buy_now:focus {
+ box-shadow: none !important;
+}
+#add_to_cart_wrap{
+ display: grid !important;
+ grid-template-columns: 1fr 1fr;
+ gap: 10px;
+}
+#o_wsale_cta_wrapper .form-control {
+ width: 100%;
+ min-width:370px !important;
+ height: 64px;
+}
+@media (max-width: 576px){
+#add_to_cart_wrap{
+ display: block !important;
+ gap: 0px;
+}
+#o_wsale_cta_wrapper .form-control {
+ min-width:100% !important;
+}
+.o_we_buy_now{
+ width:100%
+}
+}
\ No newline at end of file
diff --git a/theme_eco_refine/static/src/img/Arrow 1.svg b/theme_eco_refine/static/src/img/Arrow 1.svg
new file mode 100755
index 0000000000..29b1829c3e
--- /dev/null
+++ b/theme_eco_refine/static/src/img/Arrow 1.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/Arrow 2.svg b/theme_eco_refine/static/src/img/Arrow 2.svg
new file mode 100755
index 0000000000..7f5df273a2
--- /dev/null
+++ b/theme_eco_refine/static/src/img/Arrow 2.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/Iphone 1.png b/theme_eco_refine/static/src/img/Iphone 1.png
new file mode 100755
index 0000000000..b0c1d94cf3
Binary files /dev/null and b/theme_eco_refine/static/src/img/Iphone 1.png differ
diff --git a/theme_eco_refine/static/src/img/Laptop.svg b/theme_eco_refine/static/src/img/Laptop.svg
new file mode 100755
index 0000000000..46aa931298
--- /dev/null
+++ b/theme_eco_refine/static/src/img/Laptop.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/Quality Product.svg b/theme_eco_refine/static/src/img/Quality Product.svg
new file mode 100755
index 0000000000..c554dd41fd
--- /dev/null
+++ b/theme_eco_refine/static/src/img/Quality Product.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/Vector (3).svg b/theme_eco_refine/static/src/img/Vector (3).svg
new file mode 100755
index 0000000000..25c19d1a92
--- /dev/null
+++ b/theme_eco_refine/static/src/img/Vector (3).svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/about-hero-banner.png b/theme_eco_refine/static/src/img/about-hero-banner.png
new file mode 100755
index 0000000000..cc82d09210
Binary files /dev/null and b/theme_eco_refine/static/src/img/about-hero-banner.png differ
diff --git a/theme_eco_refine/static/src/img/blog-bg.png b/theme_eco_refine/static/src/img/blog-bg.png
new file mode 100755
index 0000000000..7b143bc054
Binary files /dev/null and b/theme_eco_refine/static/src/img/blog-bg.png differ
diff --git a/theme_eco_refine/static/src/img/camera 1.svg b/theme_eco_refine/static/src/img/camera 1.svg
new file mode 100755
index 0000000000..4dc26e34c6
--- /dev/null
+++ b/theme_eco_refine/static/src/img/camera 1.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/cart-icon.svg b/theme_eco_refine/static/src/img/cart-icon.svg
new file mode 100755
index 0000000000..8c30309d48
--- /dev/null
+++ b/theme_eco_refine/static/src/img/cart-icon.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/community.svg b/theme_eco_refine/static/src/img/community.svg
new file mode 100755
index 0000000000..9809db1419
--- /dev/null
+++ b/theme_eco_refine/static/src/img/community.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/theme_eco_refine/static/src/img/contact-hero.png b/theme_eco_refine/static/src/img/contact-hero.png
new file mode 100755
index 0000000000..67a3a1d2b2
Binary files /dev/null and b/theme_eco_refine/static/src/img/contact-hero.png differ
diff --git a/theme_eco_refine/static/src/img/cross.svg b/theme_eco_refine/static/src/img/cross.svg
new file mode 100755
index 0000000000..5b0b8c9253
--- /dev/null
+++ b/theme_eco_refine/static/src/img/cross.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/email.svg b/theme_eco_refine/static/src/img/email.svg
new file mode 100755
index 0000000000..3ce9dd4233
--- /dev/null
+++ b/theme_eco_refine/static/src/img/email.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/exchange.svg b/theme_eco_refine/static/src/img/exchange.svg
new file mode 100755
index 0000000000..187d1a3431
--- /dev/null
+++ b/theme_eco_refine/static/src/img/exchange.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/facebook.svg b/theme_eco_refine/static/src/img/facebook.svg
new file mode 100755
index 0000000000..2dd6ce0595
--- /dev/null
+++ b/theme_eco_refine/static/src/img/facebook.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/filter.svg b/theme_eco_refine/static/src/img/filter.svg
new file mode 100755
index 0000000000..fb015ae818
--- /dev/null
+++ b/theme_eco_refine/static/src/img/filter.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/goal-gd9f02c7b0_1920 1.png b/theme_eco_refine/static/src/img/goal-gd9f02c7b0_1920 1.png
new file mode 100755
index 0000000000..5fc860884b
Binary files /dev/null and b/theme_eco_refine/static/src/img/goal-gd9f02c7b0_1920 1.png differ
diff --git a/theme_eco_refine/static/src/img/guarantee (3) 1.svg b/theme_eco_refine/static/src/img/guarantee (3) 1.svg
new file mode 100755
index 0000000000..97f2402a8c
--- /dev/null
+++ b/theme_eco_refine/static/src/img/guarantee (3) 1.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/headphone 1.svg b/theme_eco_refine/static/src/img/headphone 1.svg
new file mode 100755
index 0000000000..869e13d12e
--- /dev/null
+++ b/theme_eco_refine/static/src/img/headphone 1.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/instagram.svg b/theme_eco_refine/static/src/img/instagram.svg
new file mode 100755
index 0000000000..606c79b412
--- /dev/null
+++ b/theme_eco_refine/static/src/img/instagram.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/levitating-music-headphones-display 1.png b/theme_eco_refine/static/src/img/levitating-music-headphones-display 1.png
new file mode 100755
index 0000000000..cef2c768cb
Binary files /dev/null and b/theme_eco_refine/static/src/img/levitating-music-headphones-display 1.png differ
diff --git a/theme_eco_refine/static/src/img/like.svg b/theme_eco_refine/static/src/img/like.svg
new file mode 100755
index 0000000000..6305f40b64
--- /dev/null
+++ b/theme_eco_refine/static/src/img/like.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/location.svg b/theme_eco_refine/static/src/img/location.svg
new file mode 100755
index 0000000000..8140e31911
--- /dev/null
+++ b/theme_eco_refine/static/src/img/location.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/login.svg b/theme_eco_refine/static/src/img/login.svg
new file mode 100755
index 0000000000..2293e0609b
--- /dev/null
+++ b/theme_eco_refine/static/src/img/login.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/phone.svg b/theme_eco_refine/static/src/img/phone.svg
new file mode 100755
index 0000000000..b6943d93d0
--- /dev/null
+++ b/theme_eco_refine/static/src/img/phone.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/plus.svg b/theme_eco_refine/static/src/img/plus.svg
new file mode 100755
index 0000000000..83c3b059c0
--- /dev/null
+++ b/theme_eco_refine/static/src/img/plus.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/pricing.svg b/theme_eco_refine/static/src/img/pricing.svg
new file mode 100755
index 0000000000..9f5175118d
--- /dev/null
+++ b/theme_eco_refine/static/src/img/pricing.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/product-cart.svg b/theme_eco_refine/static/src/img/product-cart.svg
new file mode 100755
index 0000000000..1b8941d649
--- /dev/null
+++ b/theme_eco_refine/static/src/img/product-cart.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/product-like.svg b/theme_eco_refine/static/src/img/product-like.svg
new file mode 100755
index 0000000000..29ce9e4b76
--- /dev/null
+++ b/theme_eco_refine/static/src/img/product-like.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/product-page-herobanner.png b/theme_eco_refine/static/src/img/product-page-herobanner.png
new file mode 100755
index 0000000000..dba6a95a7e
Binary files /dev/null and b/theme_eco_refine/static/src/img/product-page-herobanner.png differ
diff --git a/theme_eco_refine/static/src/img/product-view.svg b/theme_eco_refine/static/src/img/product-view.svg
new file mode 100755
index 0000000000..a261e8cb8b
--- /dev/null
+++ b/theme_eco_refine/static/src/img/product-view.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/quotes-after.svg b/theme_eco_refine/static/src/img/quotes-after.svg
new file mode 100755
index 0000000000..cb96c1c6f1
--- /dev/null
+++ b/theme_eco_refine/static/src/img/quotes-after.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/quotes-before.svg b/theme_eco_refine/static/src/img/quotes-before.svg
new file mode 100755
index 0000000000..892d194121
--- /dev/null
+++ b/theme_eco_refine/static/src/img/quotes-before.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/refurbished-img.jpg b/theme_eco_refine/static/src/img/refurbished-img.jpg
new file mode 100755
index 0000000000..34379e7c0d
Binary files /dev/null and b/theme_eco_refine/static/src/img/refurbished-img.jpg differ
diff --git a/theme_eco_refine/static/src/img/return.svg b/theme_eco_refine/static/src/img/return.svg
new file mode 100755
index 0000000000..55d669353c
--- /dev/null
+++ b/theme_eco_refine/static/src/img/return.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/shopping-banner-img.png b/theme_eco_refine/static/src/img/shopping-banner-img.png
new file mode 100755
index 0000000000..fc1b4da1e4
Binary files /dev/null and b/theme_eco_refine/static/src/img/shopping-banner-img.png differ
diff --git a/theme_eco_refine/static/src/img/shopping-banner2.png b/theme_eco_refine/static/src/img/shopping-banner2.png
new file mode 100755
index 0000000000..182d06ad01
Binary files /dev/null and b/theme_eco_refine/static/src/img/shopping-banner2.png differ
diff --git a/theme_eco_refine/static/src/img/shopping-cart-fil.png b/theme_eco_refine/static/src/img/shopping-cart-fil.png
new file mode 100755
index 0000000000..a1f888a59d
Binary files /dev/null and b/theme_eco_refine/static/src/img/shopping-cart-fil.png differ
diff --git a/theme_eco_refine/static/src/img/smart-watch 1.svg b/theme_eco_refine/static/src/img/smart-watch 1.svg
new file mode 100755
index 0000000000..05301656f9
--- /dev/null
+++ b/theme_eco_refine/static/src/img/smart-watch 1.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/smartphone 1.svg b/theme_eco_refine/static/src/img/smartphone 1.svg
new file mode 100755
index 0000000000..1409448385
--- /dev/null
+++ b/theme_eco_refine/static/src/img/smartphone 1.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/img/smartwatch-screen-digital-device (1) 1.png b/theme_eco_refine/static/src/img/smartwatch-screen-digital-device (1) 1.png
new file mode 100755
index 0000000000..014018d660
Binary files /dev/null and b/theme_eco_refine/static/src/img/smartwatch-screen-digital-device (1) 1.png differ
diff --git a/theme_eco_refine/static/src/img/snippet/Best-Seller.jpg b/theme_eco_refine/static/src/img/snippet/Best-Seller.jpg
new file mode 100644
index 0000000000..4cead665fd
Binary files /dev/null and b/theme_eco_refine/static/src/img/snippet/Best-Seller.jpg differ
diff --git a/theme_eco_refine/static/src/img/snippet/Customer-Response.jpg b/theme_eco_refine/static/src/img/snippet/Customer-Response.jpg
new file mode 100644
index 0000000000..a5db134f65
Binary files /dev/null and b/theme_eco_refine/static/src/img/snippet/Customer-Response.jpg differ
diff --git a/theme_eco_refine/static/src/img/snippet/FAQ.jpg b/theme_eco_refine/static/src/img/snippet/FAQ.jpg
new file mode 100644
index 0000000000..d50d6e7f6b
Binary files /dev/null and b/theme_eco_refine/static/src/img/snippet/FAQ.jpg differ
diff --git a/theme_eco_refine/static/src/img/snippet/New-Arrival.jpg b/theme_eco_refine/static/src/img/snippet/New-Arrival.jpg
new file mode 100644
index 0000000000..52d8a6eb48
Binary files /dev/null and b/theme_eco_refine/static/src/img/snippet/New-Arrival.jpg differ
diff --git a/theme_eco_refine/static/src/img/snippet/Our-collection.jpg b/theme_eco_refine/static/src/img/snippet/Our-collection.jpg
new file mode 100644
index 0000000000..0347c9feb1
Binary files /dev/null and b/theme_eco_refine/static/src/img/snippet/Our-collection.jpg differ
diff --git a/theme_eco_refine/static/src/img/snippet/Refurbished-Carousel.jpg b/theme_eco_refine/static/src/img/snippet/Refurbished-Carousel.jpg
new file mode 100644
index 0000000000..96ef31f417
Binary files /dev/null and b/theme_eco_refine/static/src/img/snippet/Refurbished-Carousel.jpg differ
diff --git a/theme_eco_refine/static/src/img/snippet/Sign-up-snippet.jpg b/theme_eco_refine/static/src/img/snippet/Sign-up-snippet.jpg
new file mode 100644
index 0000000000..668df91532
Binary files /dev/null and b/theme_eco_refine/static/src/img/snippet/Sign-up-snippet.jpg differ
diff --git a/theme_eco_refine/static/src/img/snippet/Sign_up_and_Buy.jpg b/theme_eco_refine/static/src/img/snippet/Sign_up_and_Buy.jpg
new file mode 100644
index 0000000000..bf1bd51fc6
Binary files /dev/null and b/theme_eco_refine/static/src/img/snippet/Sign_up_and_Buy.jpg differ
diff --git a/theme_eco_refine/static/src/img/snippet/Top-Rated-Product.jpg b/theme_eco_refine/static/src/img/snippet/Top-Rated-Product.jpg
new file mode 100644
index 0000000000..122cd4e458
Binary files /dev/null and b/theme_eco_refine/static/src/img/snippet/Top-Rated-Product.jpg differ
diff --git a/theme_eco_refine/static/src/img/testimonial-person-1.png b/theme_eco_refine/static/src/img/testimonial-person-1.png
new file mode 100755
index 0000000000..9621f64a09
Binary files /dev/null and b/theme_eco_refine/static/src/img/testimonial-person-1.png differ
diff --git a/theme_eco_refine/static/src/img/twitter.svg b/theme_eco_refine/static/src/img/twitter.svg
new file mode 100755
index 0000000000..7eaccfe43c
--- /dev/null
+++ b/theme_eco_refine/static/src/img/twitter.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_eco_refine/static/src/img/workplace-business-modern-male-accessories-laptop-white 1 (1).png b/theme_eco_refine/static/src/img/workplace-business-modern-male-accessories-laptop-white 1 (1).png
new file mode 100755
index 0000000000..0ef339609a
Binary files /dev/null and b/theme_eco_refine/static/src/img/workplace-business-modern-male-accessories-laptop-white 1 (1).png differ
diff --git a/theme_eco_refine/static/src/js/about_us.js b/theme_eco_refine/static/src/js/about_us.js
new file mode 100755
index 0000000000..05006a2fb6
--- /dev/null
+++ b/theme_eco_refine/static/src/js/about_us.js
@@ -0,0 +1,81 @@
+/** @odoo-module */
+ import publicWidget from '@web/legacy/js/public/public_widget';
+ import { renderToElement } from "@web/core/utils/render";
+ publicWidget.registry.refurb_theme_about_us = publicWidget.Widget.extend({
+ templates: 'theme_eco_refine.about_us',
+ selector: '.ref-wrapper',
+ events: {
+ 'click .ref-abt-button': 'toggleDiv',
+ 'click .ref-mob-btn': 'toggleContent',
+ 'click .custom-nav_prev': 'togglePrevious',
+ 'click .custom-nav_next': 'toggleNext',
+ },
+ start: function() {
+ var self = this;
+ return this._super.apply(this, arguments).then(function() {
+ var defaultIndex = 2;
+ var defaultContentElement = self.$('.ref-abt_mob .ref-mob-btn:nth-child(' + (defaultIndex + 1) + ') .ref-abt-button__mobcontent');
+ if (defaultContentElement.length) {
+ defaultContentElement.addClass('show');
+ }
+ var buttons = self.$el.find('.ref-abt-button');
+ if (buttons.length > 0) {
+ self.$(buttons[1]).addClass('active');
+ self.$(buttons[3]).addClass('active');
+ }
+ self.$(".owl-carousel-abt").owlCarousel();
+ });
+ },
+ toggleDiv: function (ev) {
+ if (ev.target.classList.contains('ref-abt-button')){
+ // function for show and hide corresponding div according to click on Our Journy
+ const buttons = this.$el[0].querySelectorAll('.ref-abt-button');
+ const about = ev.target.querySelector('.ref-abt-button__content');
+ buttons.forEach((btn) => {
+ btn.classList.remove('active');
+ btn.querySelector('.ref-abt-button__content').style.display = 'none';
+ });
+ ev.target.classList.add('active');
+ about.style.display = 'block';
+ }
+ },
+ toggleContent: function (ev){
+ let index;
+ if(this.$(ev.target).hasClass('div0')){
+ index = 0
+ }else if(this.$(ev.target).hasClass('div1')){
+ index = 1
+ }else if(this.$(ev.target).hasClass('div2')){
+ index = 2
+ }else if(this.$(ev.target).hasClass('div3')){
+ index = 3
+ }else {
+ index = 4
+ }
+ const contentElements = this.$el[0].querySelectorAll('.ref-abt-button__mobcontent');
+ contentElements.forEach(function (contentElement, i) {
+ if (i === index) {
+ contentElement.classList.add('show');
+ } else {
+ contentElement.classList.remove('show');
+ }
+ });
+ const buttonTextElements = this.$el[0].querySelectorAll('.button-mob-text');
+ buttonTextElements.forEach(function (buttonTextElement, i) {
+ if (i === index) {
+ buttonTextElement.classList.toggle('hidden');
+ } else {
+ buttonTextElement.classList.remove('hidden');
+ }
+ });
+ },
+ togglePrevious:function(){
+ // Function for Previous button of Our Journey
+ self.$(".owl-carousel-abt").trigger("prev.owl.carousel");
+ },
+ toggleNext:function(){
+ // Function for Next button of Our Journey
+ self.$(".owl-carousel-abt").trigger("next.owl.carousel");
+ },
+ });
+ return publicWidget.registry.refurb_theme_about_us;
diff --git a/theme_eco_refine/static/src/js/best_seller_snippet.js b/theme_eco_refine/static/src/js/best_seller_snippet.js
new file mode 100755
index 0000000000..d1bbc95a1d
--- /dev/null
+++ b/theme_eco_refine/static/src/js/best_seller_snippet.js
@@ -0,0 +1,64 @@
+/** @odoo-module */
+import PublicWidget from "@web/legacy/js/public/public_widget";
+import { rpc } from "@web/core/network/rpc";
+import { renderToElement } from "@web/core/utils/render";
+export function _chunk(array, size) {
+ const result = [];
+ for (let i = 0; i < array.length; i += size) {
+ result.push(array.slice(i, i + size));
+ }
+ return result;
+}
+// Function for best seller snippet
+var TopSellingProducts = PublicWidget.Widget.extend({
+ selector: '.best_seller_product_snippet',
+ willStart: async function () {
+ const data = await rpc('/top_selling_products', {})
+ const [products, categories, website_id, unique_id] = data
+ Object.assign(this, {
+ products, categories, website_id, unique_id
+ })
+ },
+ start: function () {
+ const refEl = this.$el.find("#top_products_carousel")
+ const { products, categories, current_website_id, products_list} = this
+ const chunkData = _chunk(products, 4)
+ refEl.html(renderToElement('theme_eco_refine.products_category_wise', {
+ products,
+ categories,
+ current_website_id,
+ products_list,
+ chunkData
+ }))
+ const element = document.body.querySelector("#bestSellCarousel")
+ self.$('.owl-carousel').owlCarousel({
+ loop: true,
+ margin: 10,
+ autoplay: true,
+ nav: true,
+ responsiveClass:true,
+ responsive: {
+ 0: {
+ items: 1,
+ nav:true
+ },
+ 600: {
+ items: 3,
+ nav:true
+ },
+ 1000: {
+ items: 4,
+ nav:true
+ }
+ },
+ });
+ self.$(".owl-prev").click(function () {
+ $(".owl-carousel").trigger("prev.owl.carousel");
+ });
+ self.$("owl-next").click(function () {
+ $(".owl-carousel").trigger("next.owl.carousel");
+ });
+ }
+ });
+PublicWidget.registry.products_category_wise_snippet = TopSellingProducts;
+return TopSellingProducts;
diff --git a/theme_eco_refine/static/src/js/collection_snippet.js b/theme_eco_refine/static/src/js/collection_snippet.js
new file mode 100755
index 0000000000..27b6dcf5d7
--- /dev/null
+++ b/theme_eco_refine/static/src/js/collection_snippet.js
@@ -0,0 +1,20 @@
+/** @odoo-module */
+ import publicWidget from '@web/legacy/js/public/public_widget';
+ publicWidget.registry.collection_snippet = publicWidget.Widget.extend({
+ selector: '.ref-collection--container',
+ start: function () {
+ var self = this;
+ return this._super.apply(this, arguments).then(function () {
+ self.$('.ref-collection__item').each(function (index) {
+ if (index === 0) {
+ self.$(this).addClass('selected');
+ }
+ self.$(this).on('click', function () {
+ self.$('.ref-collection__item').removeClass('selected');
+ self.$(this).addClass('selected');
+ });
+ });
+ });
+ },
+ });
+ return publicWidget.registry.collection_snippet;
diff --git a/theme_eco_refine/static/src/js/customer_response.js b/theme_eco_refine/static/src/js/customer_response.js
new file mode 100644
index 0000000000..f4af8181be
--- /dev/null
+++ b/theme_eco_refine/static/src/js/customer_response.js
@@ -0,0 +1,34 @@
+/** @odoo-module */
+ // Function for customer response snippet
+ self.$('.owl-carousel1').owlCarousel({
+ loop: true,
+ margin: 10,
+ navText: ["Prev", "Next"],
+ nav: false,
+ autoplay:true,
+ responsive: {
+ 0: {
+ items: 2
+ },
+ 600: {
+ items: 3
+ },
+ 1000: {
+ items: 5
+ }
+ }
+ });
+ self.$(".owl-carousel2").owlCarousel({
+ items: 1,
+ loop: true,
+ nav: false,
+ autoplay:true,
+ dots: false,
+ });
+ // Custom navigation
+ self.$(".custom-nav__prev").click(function () {
+ $(".owl-carousel2").trigger("prev.owl.carousel");
+ });
+ self.$(".custom-nav__next").click(function () {
+ $(".owl-carousel2").trigger("next.owl.carousel");
+ });
diff --git a/theme_eco_refine/static/src/js/new_arrival_snippet.js b/theme_eco_refine/static/src/js/new_arrival_snippet.js
new file mode 100755
index 0000000000..f0a243dbf0
--- /dev/null
+++ b/theme_eco_refine/static/src/js/new_arrival_snippet.js
@@ -0,0 +1,60 @@
+/** @odoo-module */
+import PublicWidget from "@web/legacy/js/public/public_widget";
+import { rpc } from "@web/core/network/rpc";
+export function _chunk(array, size) {
+ const result = [];
+ for (let i = 0; i < array.length; i += size) {
+ result.push(array.slice(i, i + size));
+ }
+ return result;
+}
+import { renderToElement } from "@web/core/utils/render";
+ var NewArrivalProducts = PublicWidget.Widget.extend({
+ selector: '.product_new_arrival_snippet',
+ willStart: async function() {
+ const data = await rpc('/new_arrival_products', {})
+ const [products, categories, website_id, unique_id] = data
+ Object.assign(this, {
+ products, categories, website_id, unique_id
+ })
+ },
+ /**
+ * Render the widget with the fetched data.
+ */
+ start: function () {
+ const refEl = this.$el.find("#new_arrival_carousel")
+ const { products, categories, current_website_id, products_list} = this
+ const chunkData = _chunk(products, 4)
+ refEl.html(renderToElement('theme_eco_refine.new_product_arrival', {
+ products,
+ categories,
+ current_website_id,
+ products_list,
+ chunkData
+ }))
+ const element = document.body.querySelector("#myCarousel")
+ self.$('.owl-carousel').owlCarousel({
+ loop: true,
+ margin: 10,
+ autoplay: true,
+ nav: true,
+ responsiveClass:true,
+ responsive: {
+ 0: {
+ items: 1,
+ nav:true
+ },
+ 600: {
+ items: 3,
+ nav:true
+ },
+ 1000: {
+ items: 4,
+ nav:true
+ }
+ },
+ });
+ }
+ });
+ PublicWidget.registry.product_new_arrival_snippet = NewArrivalProducts;
+ return NewArrivalProducts;
diff --git a/theme_eco_refine/static/src/js/owl.carousel.js b/theme_eco_refine/static/src/js/owl.carousel.js
new file mode 100755
index 0000000000..025c77965a
--- /dev/null
+++ b/theme_eco_refine/static/src/js/owl.carousel.js
@@ -0,0 +1,3010 @@
+/**
+ * Owl Carousel v2.3.4
+ * Copyright 2013-2018 David Deutsch
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
+ */
+/**
+ * Owl carousel
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ * @todo Lazy Load Icon
+ * @todo prevent animationend bubling
+ * @todo itemsScaleUp
+ * @todo Test Zepto
+ * @todo stagePadding calculate wrong active classes
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates a carousel.
+ * @class The Owl Carousel.
+ * @public
+ * @param {HTMLElement|jQuery} element - The element to create the carousel for.
+ * @param {Object} [options] - The options
+ */
+ function Owl(element, options) {
+ /**
+ * Current settings for the carousel.
+ * @public
+ */
+ this.settings = null;
+ /**
+ * Current options set by the caller including defaults.
+ * @public
+ */
+ this.options = $.extend({}, Owl.Defaults, options);
+ /**
+ * Plugin element.
+ * @public
+ */
+ this.$element = $(element);
+ /**
+ * Proxied event handlers.
+ * @protected
+ */
+ this._handlers = {};
+ /**
+ * References to the running plugins of this carousel.
+ * @protected
+ */
+ this._plugins = {};
+ /**
+ * Currently suppressed events to prevent them from being retriggered.
+ * @protected
+ */
+ this._supress = {};
+ /**
+ * Absolute current position.
+ * @protected
+ */
+ this._current = null;
+ /**
+ * Animation speed in milliseconds.
+ * @protected
+ */
+ this._speed = null;
+ /**
+ * Coordinates of all items in pixel.
+ * @todo The name of this member is missleading.
+ * @protected
+ */
+ this._coordinates = [];
+ /**
+ * Current breakpoint.
+ * @todo Real media queries would be nice.
+ * @protected
+ */
+ this._breakpoint = null;
+ /**
+ * Current width of the plugin element.
+ */
+ this._width = null;
+ /**
+ * All real items.
+ * @protected
+ */
+ this._items = [];
+ /**
+ * All cloned items.
+ * @protected
+ */
+ this._clones = [];
+ /**
+ * Merge values of all items.
+ * @todo Maybe this could be part of a plugin.
+ * @protected
+ */
+ this._mergers = [];
+ /**
+ * Widths of all items.
+ */
+ this._widths = [];
+ /**
+ * Invalidated parts within the update process.
+ * @protected
+ */
+ this._invalidated = {};
+ /**
+ * Ordered list of workers for the update process.
+ * @protected
+ */
+ this._pipe = [];
+ /**
+ * Current state information for the drag operation.
+ * @todo #261
+ * @protected
+ */
+ this._drag = {
+ time: null,
+ target: null,
+ pointer: null,
+ stage: {
+ start: null,
+ current: null
+ },
+ direction: null
+ };
+ /**
+ * Current state information and their tags.
+ * @type {Object}
+ * @protected
+ */
+ this._states = {
+ current: {},
+ tags: {
+ 'initializing': [ 'busy' ],
+ 'animating': [ 'busy' ],
+ 'dragging': [ 'interacting' ]
+ }
+ };
+ $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
+ this._handlers[handler] = $.proxy(this[handler], this);
+ }, this));
+ $.each(Owl.Plugins, $.proxy(function(key, plugin) {
+ this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
+ = new plugin(this);
+ }, this));
+ $.each(Owl.Workers, $.proxy(function(priority, worker) {
+ this._pipe.push({
+ 'filter': worker.filter,
+ 'run': $.proxy(worker.run, this)
+ });
+ }, this));
+ this.setup();
+ this.initialize();
+ }
+ /**
+ * Default options for the carousel.
+ * @public
+ */
+ Owl.Defaults = {
+ items: 3,
+ loop: false,
+ center: false,
+ rewind: false,
+ checkVisibility: true,
+ mouseDrag: true,
+ touchDrag: true,
+ pullDrag: true,
+ freeDrag: false,
+ margin: 0,
+ stagePadding: 0,
+ merge: false,
+ mergeFit: true,
+ autoWidth: false,
+ startPosition: 0,
+ rtl: false,
+ smartSpeed: 250,
+ fluidSpeed: false,
+ dragEndSpeed: false,
+ responsive: {},
+ responsiveRefreshRate: 200,
+ responsiveBaseElement: window,
+ fallbackEasing: 'swing',
+ slideTransition: '',
+ info: false,
+ nestedItemSelector: false,
+ itemElement: 'div',
+ stageElement: 'div',
+ refreshClass: 'owl-refresh',
+ loadedClass: 'owl-loaded',
+ loadingClass: 'owl-loading',
+ rtlClass: 'owl-rtl',
+ responsiveClass: 'owl-responsive',
+ dragClass: 'owl-drag',
+ itemClass: 'owl-item',
+ stageClass: 'owl-stage',
+ stageOuterClass: 'owl-stage-outer',
+ grabClass: 'owl-grab'
+ };
+ /**
+ * Enumeration for width.
+ * @public
+ * @readonly
+ * @enum {String}
+ */
+ Owl.Width = {
+ Default: 'default',
+ Inner: 'inner',
+ Outer: 'outer'
+ };
+ /**
+ * Enumeration for types.
+ * @public
+ * @readonly
+ * @enum {String}
+ */
+ Owl.Type = {
+ Event: 'event',
+ State: 'state'
+ };
+ /**
+ * Contains all registered plugins.
+ * @public
+ */
+ Owl.Plugins = {};
+ /**
+ * List of workers involved in the update process.
+ */
+ Owl.Workers = [ {
+ filter: [ 'width', 'settings' ],
+ run: function() {
+ this._width = this.$element.width();
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ cache.current = this._items && this._items[this.relative(this._current)];
+ }
+ }, {
+ filter: [ 'items', 'settings' ],
+ run: function() {
+ this.$stage.children('.cloned').remove();
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ var margin = this.settings.margin || '',
+ grid = !this.settings.autoWidth,
+ rtl = this.settings.rtl,
+ css = {
+ 'width': 'auto',
+ 'margin-left': rtl ? margin : '',
+ 'margin-right': rtl ? '' : margin
+ };
+
+ !grid && this.$stage.children().css(css);
+
+ cache.css = css;
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
+ merge = null,
+ iterator = this._items.length,
+ grid = !this.settings.autoWidth,
+ widths = [];
+ cache.items = {
+ merge: false,
+ width: width
+ };
+ while (iterator--) {
+ merge = this._mergers[iterator];
+ merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
+ cache.items.merge = merge > 1 || cache.items.merge;
+ widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
+ }
+ this._widths = widths;
+ }
+ }, {
+ filter: [ 'items', 'settings' ],
+ run: function() {
+ var clones = [],
+ items = this._items,
+ settings = this.settings,
+ // TODO: Should be computed from number of min width items in stage
+ view = Math.max(settings.items * 2, 4),
+ size = Math.ceil(items.length / 2) * 2,
+ repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
+ append = '',
+ prepend = '';
+ repeat /= 2;
+ while (repeat > 0) {
+ // Switch to only using appended clones
+ clones.push(this.normalize(clones.length / 2, true));
+ append = append + items[clones[clones.length - 1]][0].outerHTML;
+ clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
+ prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
+ repeat -= 1;
+ }
+ this._clones = clones;
+ $(append).addClass('cloned').appendTo(this.$stage);
+ $(prepend).addClass('cloned').prependTo(this.$stage);
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function() {
+ var rtl = this.settings.rtl ? 1 : -1,
+ size = this._clones.length + this._items.length,
+ iterator = -1,
+ previous = 0,
+ current = 0,
+ coordinates = [];
+ while (++iterator < size) {
+ previous = coordinates[iterator - 1] || 0;
+ current = this._widths[this.relative(iterator)] + this.settings.margin;
+ coordinates.push(previous + current * rtl);
+ }
+ this._coordinates = coordinates;
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function() {
+ var padding = this.settings.stagePadding,
+ coordinates = this._coordinates,
+ css = {
+ 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
+ 'padding-left': padding || '',
+ 'padding-right': padding || ''
+ };
+ this.$stage.css(css);
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ var iterator = this._coordinates.length,
+ grid = !this.settings.autoWidth,
+ items = this.$stage.children();
+ if (grid && cache.items.merge) {
+ while (iterator--) {
+ cache.css.width = this._widths[this.relative(iterator)];
+ items.eq(iterator).css(cache.css);
+ }
+ } else if (grid) {
+ cache.css.width = cache.items.width;
+ items.css(cache.css);
+ }
+ }
+ }, {
+ filter: [ 'items' ],
+ run: function() {
+ this._coordinates.length < 1 && this.$stage.removeAttr('style');
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
+ cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
+ this.reset(cache.current);
+ }
+ }, {
+ filter: [ 'position' ],
+ run: function() {
+ this.animate(this.coordinates(this._current));
+ }
+ }, {
+ filter: [ 'width', 'position', 'items', 'settings' ],
+ run: function() {
+ var rtl = this.settings.rtl ? 1 : -1,
+ padding = this.settings.stagePadding * 2,
+ begin = this.coordinates(this.current()) + padding,
+ end = begin + this.width() * rtl,
+ inner, outer, matches = [], i, n;
+ for (i = 0, n = this._coordinates.length; i < n; i++) {
+ inner = this._coordinates[i - 1] || 0;
+ outer = Math.abs(this._coordinates[i]) + padding * rtl;
+ if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
+ || (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
+ matches.push(i);
+ }
+ }
+ this.$stage.children('.active').removeClass('active');
+ this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
+ this.$stage.children('.center').removeClass('center');
+ if (this.settings.center) {
+ this.$stage.children().eq(this.current()).addClass('center');
+ }
+ }
+ } ];
+ /**
+ * Create the stage DOM element
+ */
+ Owl.prototype.initializeStage = function() {
+ this.$stage = this.$element.find('.' + this.settings.stageClass);
+ // if the stage is already in the DOM, grab it and skip stage initialization
+ if (this.$stage.length) {
+ return;
+ }
+ this.$element.addClass(this.options.loadingClass);
+ // create stage
+ this.$stage = $('<' + this.settings.stageElement + '>', {
+ "class": this.settings.stageClass
+ }).wrap( $( '
', {
+ "class": this.settings.stageOuterClass
+ }));
+ // append stage
+ this.$element.append(this.$stage.parent());
+ };
+ /**
+ * Create item DOM elements
+ */
+ Owl.prototype.initializeItems = function() {
+ var $items = this.$element.find('.owl-item');
+ // if the items are already in the DOM, grab them and skip item initialization
+ if ($items.length) {
+ this._items = $items.get().map(function(item) {
+ return $(item);
+ });
+ this._mergers = this._items.map(function() {
+ return 1;
+ });
+ this.refresh();
+ return;
+ }
+ // append content
+ this.replace(this.$element.children().not(this.$stage.parent()));
+ // check visibility
+ if (this.isVisible()) {
+ // update view
+ this.refresh();
+ } else {
+ // invalidate width
+ this.invalidate('width');
+ }
+ this.$element
+ .removeClass(this.options.loadingClass)
+ .addClass(this.options.loadedClass);
+ };
+ /**
+ * Initializes the carousel.
+ * @protected
+ */
+ Owl.prototype.initialize = function() {
+ this.enter('initializing');
+ this.trigger('initialize');
+ this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
+ if (this.settings.autoWidth && !this.is('pre-loading')) {
+ var imgs, nestedSelector, width;
+ imgs = this.$element.find('img');
+ nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
+ width = this.$element.children(nestedSelector).width();
+ if (imgs.length && width <= 0) {
+ this.preloadAutoWidthImages(imgs);
+ }
+ }
+ this.initializeStage();
+ this.initializeItems();
+ // register event handlers
+ this.registerEventHandlers();
+ this.leave('initializing');
+ this.trigger('initialized');
+ };
+ /**
+ * @returns {Boolean} visibility of $element
+ * if you know the carousel will always be visible you can set `checkVisibility` to `false` to
+ * prevent the expensive browser layout forced reflow the $element.is(':visible') does
+ */
+ Owl.prototype.isVisible = function() {
+ return this.settings.checkVisibility
+ ? this.$element.is(':visible')
+ : true;
+ };
+ /**
+ * Setups the current settings.
+ * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
+ * @todo Support for media queries by using `matchMedia` would be nice.
+ * @public
+ */
+ Owl.prototype.setup = function() {
+ var viewport = this.viewport(),
+ overwrites = this.options.responsive,
+ match = -1,
+ settings = null;
+ if (!overwrites) {
+ settings = $.extend({}, this.options);
+ } else {
+ $.each(overwrites, function(breakpoint) {
+ if (breakpoint <= viewport && breakpoint > match) {
+ match = Number(breakpoint);
+ }
+ });
+ settings = $.extend({}, this.options, overwrites[match]);
+ if (typeof settings.stagePadding === 'function') {
+ settings.stagePadding = settings.stagePadding();
+ }
+ delete settings.responsive;
+ // responsive class
+ if (settings.responsiveClass) {
+ this.$element.attr('class',
+ this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
+ );
+ }
+ }
+ this.trigger('change', { property: { name: 'settings', value: settings } });
+ this._breakpoint = match;
+ this.settings = settings;
+ this.invalidate('settings');
+ this.trigger('changed', { property: { name: 'settings', value: this.settings } });
+ };
+ /**
+ * Updates option logic if necessery.
+ * @protected
+ */
+ Owl.prototype.optionsLogic = function() {
+ if (this.settings.autoWidth) {
+ this.settings.stagePadding = false;
+ this.settings.merge = false;
+ }
+ };
+ /**
+ * Prepares an item before add.
+ * @todo Rename event parameter `content` to `item`.
+ * @protected
+ * @returns {jQuery|HTMLElement} - The item container.
+ */
+ Owl.prototype.prepare = function(item) {
+ var event = this.trigger('prepare', { content: item });
+
+ if (!event.data) {
+ event.data = $('<' + this.settings.itemElement + '/>')
+ .addClass(this.options.itemClass).append(item)
+ }
+ this.trigger('prepared', { content: event.data });
+ return event.data;
+ };
+ /**
+ * Updates the view.
+ * @public
+ */
+ Owl.prototype.update = function() {
+ var i = 0,
+ n = this._pipe.length,
+ filter = $.proxy(function(p) { return this[p] }, this._invalidated),
+ cache = {};
+ while (i < n) {
+ if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
+ this._pipe[i].run(cache);
+ }
+ i++;
+ }
+ this._invalidated = {};
+ !this.is('valid') && this.enter('valid');
+ };
+ /**
+ * Gets the width of the view.
+ * @public
+ * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
+ * @returns {Number} - The width of the view in pixel.
+ */
+ Owl.prototype.width = function(dimension) {
+ dimension = dimension || Owl.Width.Default;
+ switch (dimension) {
+ case Owl.Width.Inner:
+ case Owl.Width.Outer:
+ return this._width;
+ default:
+ return this._width - this.settings.stagePadding * 2 + this.settings.margin;
+ }
+ };
+ /**
+ * Refreshes the carousel primarily for adaptive purposes.
+ * @public
+ */
+ Owl.prototype.refresh = function() {
+ this.enter('refreshing');
+ this.trigger('refresh');
+ this.setup();
+ this.optionsLogic();
+ this.$element.addClass(this.options.refreshClass);
+ this.update();
+ this.$element.removeClass(this.options.refreshClass);
+ this.leave('refreshing');
+ this.trigger('refreshed');
+ };
+ /**
+ * Checks window `resize` event.
+ * @protected
+ */
+ Owl.prototype.onThrottledResize = function() {
+ window.clearTimeout(this.resizeTimer);
+ this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
+ };
+ /**
+ * Checks window `resize` event.
+ * @protected
+ */
+ Owl.prototype.onResize = function() {
+ if (!this._items.length) {
+ return false;
+ }
+ if (this._width === this.$element.width()) {
+ return false;
+ }
+ if (!this.isVisible()) {
+ return false;
+ }
+ this.enter('resizing');
+ if (this.trigger('resize').isDefaultPrevented()) {
+ this.leave('resizing');
+ return false;
+ }
+ this.invalidate('width');
+ this.refresh();
+ this.leave('resizing');
+ this.trigger('resized');
+ };
+ /**
+ * Registers event handlers.
+ * @todo Check `msPointerEnabled`
+ * @todo #261
+ * @protected
+ */
+ Owl.prototype.registerEventHandlers = function() {
+ if ($.support.transition) {
+ this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
+ }
+ if (this.settings.responsive !== false) {
+ this.on(window, 'resize', this._handlers.onThrottledResize);
+ }
+ if (this.settings.mouseDrag) {
+ this.$element.addClass(this.options.dragClass);
+ this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
+ this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
+ }
+ if (this.settings.touchDrag){
+ this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
+ this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
+ }
+ };
+ /**
+ * Handles `touchstart` and `mousedown` events.
+ * @todo Horizontal swipe threshold as option
+ * @todo #261
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onDragStart = function(event) {
+ var stage = null;
+ if (event.which === 3) {
+ return;
+ }
+ if ($.support.transform) {
+ stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
+ stage = {
+ x: stage[stage.length === 16 ? 12 : 4],
+ y: stage[stage.length === 16 ? 13 : 5]
+ };
+ } else {
+ stage = this.$stage.position();
+ stage = {
+ x: this.settings.rtl ?
+ stage.left + this.$stage.width() - this.width() + this.settings.margin :
+ stage.left,
+ y: stage.top
+ };
+ }
+ if (this.is('animating')) {
+ $.support.transform ? this.animate(stage.x) : this.$stage.stop()
+ this.invalidate('position');
+ }
+ this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
+ this.speed(0);
+ this._drag.time = new Date().getTime();
+ this._drag.target = $(event.target);
+ this._drag.stage.start = stage;
+ this._drag.stage.current = stage;
+ this._drag.pointer = this.pointer(event);
+ $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
+ $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
+ var delta = this.difference(this._drag.pointer, this.pointer(event));
+ $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
+ if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
+ return;
+ }
+ event.preventDefault();
+ this.enter('dragging');
+ this.trigger('drag');
+ }, this));
+ };
+ /**
+ * Handles the `touchmove` and `mousemove` events.
+ * @todo #261
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onDragMove = function(event) {
+ var minimum = null,
+ maximum = null,
+ pull = null,
+ delta = this.difference(this._drag.pointer, this.pointer(event)),
+ stage = this.difference(this._drag.stage.start, delta);
+ if (!this.is('dragging')) {
+ return;
+ }
+ event.preventDefault();
+ if (this.settings.loop) {
+ minimum = this.coordinates(this.minimum());
+ maximum = this.coordinates(this.maximum() + 1) - minimum;
+ stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
+ } else {
+ minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
+ maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
+ pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
+ stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
+ }
+ this._drag.stage.current = stage;
+ this.animate(stage.x);
+ };
+ /**
+ * Handles the `touchend` and `mouseup` events.
+ * @todo #261
+ * @todo Threshold for click event
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onDragEnd = function(event) {
+ var delta = this.difference(this._drag.pointer, this.pointer(event)),
+ stage = this._drag.stage.current,
+ direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
+ $(document).off('.owl.core');
+ this.$element.removeClass(this.options.grabClass);
+ if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
+ this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
+ this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
+ this.invalidate('position');
+ this.update();
+ this._drag.direction = direction;
+ if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
+ this._drag.target.one('click.owl.core', function() { return false; });
+ }
+ }
+ if (!this.is('dragging')) {
+ return;
+ }
+ this.leave('dragging');
+ this.trigger('dragged');
+ };
+ /**
+ * Gets absolute position of the closest item for a coordinate.
+ * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
+ * @protected
+ * @param {Number} coordinate - The coordinate in pixel.
+ * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
+ * @return {Number} - The absolute position of the closest item.
+ */
+ Owl.prototype.closest = function(coordinate, direction) {
+ var position = -1,
+ pull = 30,
+ width = this.width(),
+ coordinates = this.coordinates();
+ if (!this.settings.freeDrag) {
+ // check closest item
+ $.each(coordinates, $.proxy(function(index, value) {
+ // on a left pull, check on current index
+ if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
+ position = index;
+ // on a right pull, check on previous index
+ // to do so, subtract width from value and set position = index + 1
+ } else if (direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull) {
+ position = index + 1;
+ } else if (this.op(coordinate, '<', value)
+ && this.op(coordinate, '>', coordinates[index + 1] !== undefined ? coordinates[index + 1] : value - width)) {
+ position = direction === 'left' ? index + 1 : index;
+ }
+ return position === -1;
+ }, this));
+ }
+ if (!this.settings.loop) {
+ // non loop boundries
+ if (this.op(coordinate, '>', coordinates[this.minimum()])) {
+ position = coordinate = this.minimum();
+ } else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
+ position = coordinate = this.maximum();
+ }
+ }
+ return position;
+ };
+ /**
+ * Animates the stage.
+ * @todo #270
+ * @public
+ * @param {Number} coordinate - The coordinate in pixels.
+ */
+ Owl.prototype.animate = function(coordinate) {
+ var animate = this.speed() > 0;
+ this.is('animating') && this.onTransitionEnd();
+ if (animate) {
+ this.enter('animating');
+ this.trigger('translate');
+ }
+ if ($.support.transform3d && $.support.transition) {
+ this.$stage.css({
+ transform: 'translate3d(' + coordinate + 'px,0px,0px)',
+ transition: (this.speed() / 1000) + 's' + (
+ this.settings.slideTransition ? ' ' + this.settings.slideTransition : ''
+ )
+ });
+ } else if (animate) {
+ this.$stage.animate({
+ left: coordinate + 'px'
+ }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
+ } else {
+ this.$stage.css({
+ left: coordinate + 'px'
+ });
+ }
+ };
+ /**
+ * Checks whether the carousel is in a specific state or not.
+ * @param {String} state - The state to check.
+ * @returns {Boolean} - The flag which indicates if the carousel is busy.
+ */
+ Owl.prototype.is = function(state) {
+ return this._states.current[state] && this._states.current[state] > 0;
+ };
+ /**
+ * Sets the absolute position of the current item.
+ * @public
+ * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
+ * @returns {Number} - The absolute position of the current item.
+ */
+ Owl.prototype.current = function(position) {
+ if (position === undefined) {
+ return this._current;
+ }
+ if (this._items.length === 0) {
+ return undefined;
+ }
+ position = this.normalize(position);
+ if (this._current !== position) {
+ var event = this.trigger('change', { property: { name: 'position', value: position } });
+ if (event.data !== undefined) {
+ position = this.normalize(event.data);
+ }
+ this._current = position;
+ this.invalidate('position');
+ this.trigger('changed', { property: { name: 'position', value: this._current } });
+ }
+ return this._current;
+ };
+ /**
+ * Invalidates the given part of the update routine.
+ * @param {String} [part] - The part to invalidate.
+ * @returns {Array.} - The invalidated parts.
+ */
+ Owl.prototype.invalidate = function(part) {
+ if ($.type(part) === 'string') {
+ this._invalidated[part] = true;
+ this.is('valid') && this.leave('valid');
+ }
+ return $.map(this._invalidated, function(v, i) { return i });
+ };
+ /**
+ * Resets the absolute position of the current item.
+ * @public
+ * @param {Number} position - The absolute position of the new item.
+ */
+ Owl.prototype.reset = function(position) {
+ position = this.normalize(position);
+ if (position === undefined) {
+ return;
+ }
+ this._speed = 0;
+ this._current = position;
+ this.suppress([ 'translate', 'translated' ]);
+ this.animate(this.coordinates(position));
+ this.release([ 'translate', 'translated' ]);
+ };
+ /**
+ * Normalizes an absolute or a relative position of an item.
+ * @public
+ * @param {Number} position - The absolute or relative position to normalize.
+ * @param {Boolean} [relative=false] - Whether the given position is relative or not.
+ * @returns {Number} - The normalized position.
+ */
+ Owl.prototype.normalize = function(position, relative) {
+ var n = this._items.length,
+ m = relative ? 0 : this._clones.length;
+ if (!this.isNumeric(position) || n < 1) {
+ position = undefined;
+ } else if (position < 0 || position >= n + m) {
+ position = ((position - m / 2) % n + n) % n + m / 2;
+ }
+ return position;
+ };
+ /**
+ * Converts an absolute position of an item into a relative one.
+ * @public
+ * @param {Number} position - The absolute position to convert.
+ * @returns {Number} - The converted position.
+ */
+ Owl.prototype.relative = function(position) {
+ position -= this._clones.length / 2;
+ return this.normalize(position, true);
+ };
+ /**
+ * Gets the maximum position for the current item.
+ * @public
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
+ * @returns {Number}
+ */
+ Owl.prototype.maximum = function(relative) {
+ var settings = this.settings,
+ maximum = this._coordinates.length,
+ iterator,
+ reciprocalItemsWidth,
+ elementWidth;
+ if (settings.loop) {
+ maximum = this._clones.length / 2 + this._items.length - 1;
+ } else if (settings.autoWidth || settings.merge) {
+ iterator = this._items.length;
+ if (iterator) {
+ reciprocalItemsWidth = this._items[--iterator].width();
+ elementWidth = this.$element.width();
+ while (iterator--) {
+ reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
+ if (reciprocalItemsWidth > elementWidth) {
+ break;
+ }
+ }
+ }
+ maximum = iterator + 1;
+ } else if (settings.center) {
+ maximum = this._items.length - 1;
+ } else {
+ maximum = this._items.length - settings.items;
+ }
+ if (relative) {
+ maximum -= this._clones.length / 2;
+ }
+ return Math.max(maximum, 0);
+ };
+ /**
+ * Gets the minimum position for the current item.
+ * @public
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
+ * @returns {Number}
+ */
+ Owl.prototype.minimum = function(relative) {
+ return relative ? 0 : this._clones.length / 2;
+ };
+ /**
+ * Gets an item at the specified relative position.
+ * @public
+ * @param {Number} [position] - The relative position of the item.
+ * @return {jQuery|Array.} - The item at the given position or all items if no position was given.
+ */
+ Owl.prototype.items = function(position) {
+ if (position === undefined) {
+ return this._items.slice();
+ }
+ position = this.normalize(position, true);
+ return this._items[position];
+ };
+ /**
+ * Gets an item at the specified relative position.
+ * @public
+ * @param {Number} [position] - The relative position of the item.
+ * @return {jQuery|Array.} - The item at the given position or all items if no position was given.
+ */
+ Owl.prototype.mergers = function(position) {
+ if (position === undefined) {
+ return this._mergers.slice();
+ }
+ position = this.normalize(position, true);
+ return this._mergers[position];
+ };
+ /**
+ * Gets the absolute positions of clones for an item.
+ * @public
+ * @param {Number} [position] - The relative position of the item.
+ * @returns {Array.} - The absolute positions of clones for the item or all if no position was given.
+ */
+ Owl.prototype.clones = function(position) {
+ var odd = this._clones.length / 2,
+ even = odd + this._items.length,
+ map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
+ if (position === undefined) {
+ return $.map(this._clones, function(v, i) { return map(i) });
+ }
+ return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
+ };
+ /**
+ * Sets the current animation speed.
+ * @public
+ * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
+ * @returns {Number} - The current animation speed in milliseconds.
+ */
+ Owl.prototype.speed = function(speed) {
+ if (speed !== undefined) {
+ this._speed = speed;
+ }
+ return this._speed;
+ };
+ /**
+ * Gets the coordinate of an item.
+ * @todo The name of this method is missleanding.
+ * @public
+ * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
+ * @returns {Number|Array.} - The coordinate of the item in pixel or all coordinates.
+ */
+ Owl.prototype.coordinates = function(position) {
+ var multiplier = 1,
+ newPosition = position - 1,
+ coordinate;
+ if (position === undefined) {
+ return $.map(this._coordinates, $.proxy(function(coordinate, index) {
+ return this.coordinates(index);
+ }, this));
+ }
+ if (this.settings.center) {
+ if (this.settings.rtl) {
+ multiplier = -1;
+ newPosition = position + 1;
+ }
+ coordinate = this._coordinates[position];
+ coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
+ } else {
+ coordinate = this._coordinates[newPosition] || 0;
+ }
+ coordinate = Math.ceil(coordinate);
+ return coordinate;
+ };
+ /**
+ * Calculates the speed for a translation.
+ * @protected
+ * @param {Number} from - The absolute position of the start item.
+ * @param {Number} to - The absolute position of the target item.
+ * @param {Number} [factor=undefined] - The time factor in milliseconds.
+ * @returns {Number} - The time in milliseconds for the translation.
+ */
+ Owl.prototype.duration = function(from, to, factor) {
+ if (factor === 0) {
+ return 0;
+ }
+ return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
+ };
+ /**
+ * Slides to the specified item.
+ * @public
+ * @param {Number} position - The position of the item.
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ */
+ Owl.prototype.to = function(position, speed) {
+ var current = this.current(),
+ revert = null,
+ distance = position - this.relative(current),
+ direction = (distance > 0) - (distance < 0),
+ items = this._items.length,
+ minimum = this.minimum(),
+ maximum = this.maximum();
+ if (this.settings.loop) {
+ if (!this.settings.rewind && Math.abs(distance) > items / 2) {
+ distance += direction * -1 * items;
+ }
+ position = current + distance;
+ revert = ((position - minimum) % items + items) % items + minimum;
+ if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
+ current = revert - distance;
+ position = revert;
+ this.reset(current);
+ }
+ } else if (this.settings.rewind) {
+ maximum += 1;
+ position = (position % maximum + maximum) % maximum;
+ } else {
+ position = Math.max(minimum, Math.min(maximum, position));
+ }
+ this.speed(this.duration(current, position, speed));
+ this.current(position);
+ if (this.isVisible()) {
+ this.update();
+ }
+ };
+ /**
+ * Slides to the next item.
+ * @public
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ */
+ Owl.prototype.next = function(speed) {
+ speed = speed || false;
+ this.to(this.relative(this.current()) + 1, speed);
+ };
+ /**
+ * Slides to the previous item.
+ * @public
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ */
+ Owl.prototype.prev = function(speed) {
+ speed = speed || false;
+ this.to(this.relative(this.current()) - 1, speed);
+ };
+ /**
+ * Handles the end of an animation.
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onTransitionEnd = function(event) {
+ // if css2 animation then event object is undefined
+ if (event !== undefined) {
+ event.stopPropagation();
+
+ // Catch only owl-stage transitionEnd event
+ if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
+ return false;
+ }
+ }
+ this.leave('animating');
+ this.trigger('translated');
+ };
+ /**
+ * Gets viewport width.
+ * @protected
+ * @return {Number} - The width in pixel.
+ */
+ Owl.prototype.viewport = function() {
+ var width;
+ if (this.options.responsiveBaseElement !== window) {
+ width = $(this.options.responsiveBaseElement).width();
+ } else if (window.innerWidth) {
+ width = window.innerWidth;
+ } else if (document.documentElement && document.documentElement.clientWidth) {
+ width = document.documentElement.clientWidth;
+ } else {
+ console.warn('Can not detect viewport width.');
+ }
+ return width;
+ };
+ /**
+ * Replaces the current content.
+ * @public
+ * @param {HTMLElement|jQuery|String} content - The new content.
+ */
+ Owl.prototype.replace = function(content) {
+ this.$stage.empty();
+ this._items = [];
+ if (content) {
+ content = (content instanceof jQuery) ? content : $(content);
+ }
+
+ if (this.settings.nestedItemSelector) {
+ content = content.find('.' + this.settings.nestedItemSelector);
+ }
+
+ content.filter(function() {
+ return this.nodeType === 1;
+ }).each($.proxy(function(index, item) {
+ item = this.prepare(item);
+ this.$stage.append(item);
+ this._items.push(item);
+ this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
+ }, this));
+ this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
+ this.invalidate('items');
+ };
+ /**
+ * Adds an item.
+ * @todo Use `item` instead of `content` for the event arguments.
+ * @public
+ * @param {HTMLElement|jQuery|String} content - The item content to add.
+ * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
+ */
+ Owl.prototype.add = function(content, position) {
+ var current = this.relative(this._current);
+ position = position === undefined ? this._items.length : this.normalize(position, true);
+ content = content instanceof jQuery ? content : $(content);
+ this.trigger('add', { content: content, position: position });
+ content = this.prepare(content);
+ if (this._items.length === 0 || position === this._items.length) {
+ this._items.length === 0 && this.$stage.append(content);
+ this._items.length !== 0 && this._items[position - 1].after(content);
+ this._items.push(content);
+ this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
+ } else {
+ this._items[position].before(content);
+ this._items.splice(position, 0, content);
+ this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
+ }
+ this._items[current] && this.reset(this._items[current].index());
+ this.invalidate('items');
+ this.trigger('added', { content: content, position: position });
+ };
+ /**
+ * Removes an item by its position.
+ * @todo Use `item` instead of `content` for the event arguments.
+ * @public
+ * @param {Number} position - The relative position of the item to remove.
+ */
+ Owl.prototype.remove = function(position) {
+ position = this.normalize(position, true);
+ if (position === undefined) {
+ return;
+ }
+ this.trigger('remove', { content: this._items[position], position: position });
+ this._items[position].remove();
+ this._items.splice(position, 1);
+ this._mergers.splice(position, 1);
+ this.invalidate('items');
+ this.trigger('removed', { content: null, position: position });
+ };
+ /**
+ * Preloads images with auto width.
+ * @todo Replace by a more generic approach
+ * @protected
+ */
+ Owl.prototype.preloadAutoWidthImages = function(images) {
+ images.each($.proxy(function(i, element) {
+ this.enter('pre-loading');
+ element = $(element);
+ $(new Image()).one('load', $.proxy(function(e) {
+ element.attr('src', e.target.src);
+ element.css('opacity', 1);
+ this.leave('pre-loading');
+ !this.is('pre-loading') && !this.is('initializing') && this.refresh();
+ }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
+ }, this));
+ };
+ /**
+ * Destroys the carousel.
+ * @public
+ */
+ Owl.prototype.destroy = function() {
+ this.$element.off('.owl.core');
+ this.$stage.off('.owl.core');
+ $(document).off('.owl.core');
+ if (this.settings.responsive !== false) {
+ window.clearTimeout(this.resizeTimer);
+ this.off(window, 'resize', this._handlers.onThrottledResize);
+ }
+ for (var i in this._plugins) {
+ this._plugins[i].destroy();
+ }
+ this.$stage.children('.cloned').remove();
+ this.$stage.unwrap();
+ this.$stage.children().contents().unwrap();
+ this.$stage.children().unwrap();
+ this.$stage.remove();
+ this.$element
+ .removeClass(this.options.refreshClass)
+ .removeClass(this.options.loadingClass)
+ .removeClass(this.options.loadedClass)
+ .removeClass(this.options.rtlClass)
+ .removeClass(this.options.dragClass)
+ .removeClass(this.options.grabClass)
+ .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
+ .removeData('owl.carousel');
+ };
+
+ /**
+ * Operators to calculate right-to-left and left-to-right.
+ * @protected
+ * @param {Number} [a] - The left side operand.
+ * @param {String} [o] - The operator.
+ * @param {Number} [b] - The right side operand.
+ */
+ Owl.prototype.op = function(a, o, b) {
+ var rtl = this.settings.rtl;
+ switch (o) {
+ case '<':
+ return rtl ? a > b : a < b;
+ case '>':
+ return rtl ? a < b : a > b;
+ case '>=':
+ return rtl ? a <= b : a >= b;
+ case '<=':
+ return rtl ? a >= b : a <= b;
+ default:
+ break;
+ }
+ };
+
+ /**
+ * Attaches to an internal event.
+ * @protected
+ * @param {HTMLElement} element - The event source.
+ * @param {String} event - The event name.
+ * @param {Function} listener - The event handler to attach.
+ * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
+ */
+ Owl.prototype.on = function(element, event, listener, capture) {
+ if (element.addEventListener) {
+ element.addEventListener(event, listener, capture);
+ } else if (element.attachEvent) {
+ element.attachEvent('on' + event, listener);
+ }
+ };
+ /**
+ * Detaches from an internal event.
+ * @protected
+ * @param {HTMLElement} element - The event source.
+ * @param {String} event - The event name.
+ * @param {Function} listener - The attached event handler to detach.
+ * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
+ */
+ Owl.prototype.off = function(element, event, listener, capture) {
+ if (element.removeEventListener) {
+ element.removeEventListener(event, listener, capture);
+ } else if (element.detachEvent) {
+ element.detachEvent('on' + event, listener);
+ }
+ };
+ /**
+ * Triggers a public event.
+ * @todo Remove `status`, `relatedTarget` should be used instead.
+ * @protected
+ * @param {String} name - The event name.
+ * @param {*} [data=null] - The event data.
+ * @param {String} [namespace=carousel] - The event namespace.
+ * @param {String} [state] - The state which is associated with the event.
+ * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
+ * @returns {Event} - The event arguments.
+ */
+ Owl.prototype.trigger = function(name, data, namespace, state, enter) {
+ var status = {
+ item: { count: this._items.length, index: this.current() }
+ }, handler = $.camelCase(
+ $.grep([ 'on', name, namespace ], function(v) { return v })
+ .join('-').toLowerCase()
+ ), event = $.Event(
+ [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
+ $.extend({ relatedTarget: this }, status, data)
+ );
+ if (!this._supress[name]) {
+ $.each(this._plugins, function(name, plugin) {
+ if (plugin.onTrigger) {
+ plugin.onTrigger(event);
+ }
+ });
+ this.register({ type: Owl.Type.Event, name: name });
+ this.$element.trigger(event);
+
+ if (this.settings && typeof this.settings[handler] === 'function') {
+ this.settings[handler].call(this, event);
+ }
+ }
+ return event;
+ };
+
+ /**
+ * Enters a state.
+ * @param name - The state name.
+ */
+ Owl.prototype.enter = function(name) {
+ $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
+ if (this._states.current[name] === undefined) {
+ this._states.current[name] = 0;
+ }
+
+ this._states.current[name]++;
+ }, this));
+ };
+
+ /**
+ * Leaves a state.
+ * @param name - The state name.
+ */
+ Owl.prototype.leave = function(name) {
+ $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
+ this._states.current[name]--;
+ }, this));
+ };
+ /**
+ * Registers an event or state.
+ * @public
+ * @param {Object} object - The event or state to register.
+ */
+ Owl.prototype.register = function(object) {
+ if (object.type === Owl.Type.Event) {
+ if (!$.event.special[object.name]) {
+ $.event.special[object.name] = {};
+ }
+ if (!$.event.special[object.name].owl) {
+ var _default = $.event.special[object.name]._default;
+ $.event.special[object.name]._default = function(e) {
+ if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
+ return _default.apply(this, arguments);
+ }
+ return e.namespace && e.namespace.indexOf('owl') > -1;
+ };
+ $.event.special[object.name].owl = true;
+ }
+ } else if (object.type === Owl.Type.State) {
+ if (!this._states.tags[object.name]) {
+ this._states.tags[object.name] = object.tags;
+ } else {
+ this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
+ }
+
+ this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
+ return $.inArray(tag, this._states.tags[object.name]) === i;
+ }, this));
+ }
+ };
+ /**
+ * Suppresses events.
+ * @protected
+ * @param {Array.} events - The events to suppress.
+ */
+ Owl.prototype.suppress = function(events) {
+ $.each(events, $.proxy(function(index, event) {
+ this._supress[event] = true;
+ }, this));
+ };
+ /**
+ * Releases suppressed events.
+ * @protected
+ * @param {Array.} events - The events to release.
+ */
+ Owl.prototype.release = function(events) {
+ $.each(events, $.proxy(function(index, event) {
+ delete this._supress[event];
+ }, this));
+ };
+ /**
+ * Gets unified pointer coordinates from event.
+ * @todo #261
+ * @protected
+ * @param {Event} - The `mousedown` or `touchstart` event.
+ * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
+ */
+ Owl.prototype.pointer = function(event) {
+ var result = { x: null, y: null };
+ event = event.originalEvent || event || window.event;
+ event = event.touches && event.touches.length ?
+ event.touches[0] : event.changedTouches && event.changedTouches.length ?
+ event.changedTouches[0] : event;
+ if (event.pageX) {
+ result.x = event.pageX;
+ result.y = event.pageY;
+ } else {
+ result.x = event.clientX;
+ result.y = event.clientY;
+ }
+ return result;
+ };
+ /**
+ * Determines if the input is a Number or something that can be coerced to a Number
+ * @protected
+ * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
+ * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
+ */
+ Owl.prototype.isNumeric = function(number) {
+ return !isNaN(parseFloat(number));
+ };
+ /**
+ * Gets the difference of two vectors.
+ * @todo #261
+ * @protected
+ * @param {Object} - The first vector.
+ * @param {Object} - The second vector.
+ * @returns {Object} - The difference.
+ */
+ Owl.prototype.difference = function(first, second) {
+ return {
+ x: first.x - second.x,
+ y: first.y - second.y
+ };
+ };
+ /**
+ * The jQuery Plugin for the Owl Carousel
+ * @todo Navigation plugin `next` and `prev`
+ * @public
+ */
+ $.fn.owlCarousel = function(option) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return this.each(function() {
+ var $this = $(this),
+ data = $this.data('owl.carousel');
+ if (!data) {
+ data = new Owl(this, typeof option == 'object' && option);
+ $this.data('owl.carousel', data);
+ $.each([
+ 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
+ ], function(i, event) {
+ data.register({ type: Owl.Type.Event, name: event });
+ data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
+ if (e.namespace && e.relatedTarget !== this) {
+ this.suppress([ event ]);
+ data[event].apply(this, [].slice.call(arguments, 1));
+ this.release([ event ]);
+ }
+ }, data));
+ });
+ }
+ if (typeof option == 'string' && option.charAt(0) !== '_') {
+ data[option].apply(data, args);
+ }
+ });
+ };
+ /**
+ * The constructor for the jQuery Plugin
+ * @public
+ */
+ $.fn.owlCarousel.Constructor = Owl;
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * AutoRefresh Plugin
+ * @version 2.3.4
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the auto refresh plugin.
+ * @class The Auto Refresh Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var AutoRefresh = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ /**
+ * Refresh interval.
+ * @protected
+ * @type {number}
+ */
+ this._interval = null;
+ /**
+ * Whether the element is currently visible or not.
+ * @protected
+ * @type {Boolean}
+ */
+ this._visible = null;
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoRefresh) {
+ this.watch();
+ }
+ }, this)
+ };
+ // set default options
+ this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
+
+ // register event handlers
+ this._core.$element.on(this._handlers);
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ AutoRefresh.Defaults = {
+ autoRefresh: true,
+ autoRefreshInterval: 500
+ };
+ /**
+ * Watches the element.
+ */
+ AutoRefresh.prototype.watch = function() {
+ if (this._interval) {
+ return;
+ }
+
+ this._visible = this._core.isVisible();
+ this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
+ };
+ /**
+ * Refreshes the element.
+ */
+ AutoRefresh.prototype.refresh = function() {
+ if (this._core.isVisible() === this._visible) {
+ return;
+ }
+ this._visible = !this._visible;
+ this._core.$element.toggleClass('owl-hidden', !this._visible);
+ this._visible && (this._core.invalidate('width') && this._core.refresh());
+ };
+ /**
+ * Destroys the plugin.
+ */
+ AutoRefresh.prototype.destroy = function() {
+ var handler, property;
+ window.clearInterval(this._interval);
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * Lazy Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the lazy plugin.
+ * @class The Lazy Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var Lazy = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ /**
+ * Already loaded items.
+ * @protected
+ * @type {Array.}
+ */
+ this._loaded = [];
+ /**
+ * Event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function(e) {
+ if (!e.namespace) {
+ return;
+ }
+ if (!this._core.settings || !this._core.settings.lazyLoad) {
+ return;
+ }
+ if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
+ var settings = this._core.settings,
+ n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
+ i = ((settings.center && n * -1) || 0),
+ position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i,
+ clones = this._core.clones().length,
+ load = $.proxy(function(i, v) { this.load(v) }, this);
+ //TODO: Need documentation for this new option
+ if (settings.lazyLoadEager > 0) {
+ n += settings.lazyLoadEager;
+ // If the carousel is looping also preload images that are to the "left"
+ if (settings.loop) {
+ position -= settings.lazyLoadEager;
+ n++;
+ }
+ }
+
+ while (i++ < n) {
+ this.load(clones / 2 + this._core.relative(position));
+ clones && $.each(this._core.clones(this._core.relative(position)), load);
+ position++;
+ }
+ }
+ }, this)
+ };
+ // set the default options
+ this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
+ // register event handler
+ this._core.$element.on(this._handlers);
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ Lazy.Defaults = {
+ lazyLoad: false,
+ lazyLoadEager: 0
+ };
+ /**
+ * Loads all resources of an item at the specified position.
+ * @param {Number} position - The absolute position of the item.
+ * @protected
+ */
+ Lazy.prototype.load = function(position) {
+ var $item = this._core.$stage.children().eq(position),
+ $elements = $item && $item.find('.owl-lazy');
+
+ if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
+ return;
+ }
+ $elements.each($.proxy(function(index, element) {
+ var $element = $(element), image,
+ url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src') || $element.attr('data-srcset');
+ this._core.trigger('load', { element: $element, url: url }, 'lazy');
+ if ($element.is('img')) {
+ $element.one('load.owl.lazy', $.proxy(function() {
+ $element.css('opacity', 1);
+ this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
+ }, this)).attr('src', url);
+ } else if ($element.is('source')) {
+ $element.one('load.owl.lazy', $.proxy(function() {
+ this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
+ }, this)).attr('srcset', url);
+ } else {
+ image = new Image();
+ image.onload = $.proxy(function() {
+ $element.css({
+ 'background-image': 'url("' + url + '")',
+ 'opacity': '1'
+ });
+ this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
+ }, this);
+ image.src = url;
+ }
+ }, this));
+ this._loaded.push($item.get(0));
+ };
+
+ /**
+ * Destroys the plugin.
+ * @public
+ */
+ Lazy.prototype.destroy = function() {
+ var handler, property;
+ for (handler in this.handlers) {
+ this._core.$element.off(handler, this.handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * AutoHeight Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the auto height plugin.
+ * @class The Auto Height Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var AutoHeight = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ this._previousHeight = null;
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoHeight) {
+ this.update();
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoHeight && e.property.name === 'position'){
+ this.update();
+ }
+ }, this),
+ 'loaded.owl.lazy': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoHeight
+ && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
+ this.update();
+ }
+ }, this)
+ };
+ // set default options
+ this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
+ // register event handlers
+ this._core.$element.on(this._handlers);
+ this._intervalId = null;
+ var refThis = this;
+ // These changes have been taken from a PR by gavrochelegnou proposed in #1575
+ // and have been made compatible with the latest jQuery version
+ $(window).on('load', function() {
+ if (refThis._core.settings.autoHeight) {
+ refThis.update();
+ }
+ });
+ // Autoresize the height of the carousel when window is resized
+ // When carousel has images, the height is dependent on the width
+ // and should also change on resize
+ $(window).resize(function() {
+ if (refThis._core.settings.autoHeight) {
+ if (refThis._intervalId != null) {
+ clearTimeout(refThis._intervalId);
+ }
+
+ refThis._intervalId = setTimeout(function() {
+ refThis.update();
+ }, 250);
+ }
+ });
+ };
+
+ /**
+ * Default options.
+ * @public
+ */
+ AutoHeight.Defaults = {
+ autoHeight: false,
+ autoHeightClass: 'owl-height'
+ };
+
+ /**
+ * Updates the view.
+ */
+ AutoHeight.prototype.update = function() {
+ var start = this._core._current,
+ end = start + this._core.settings.items,
+ lazyLoadEnabled = this._core.settings.lazyLoad,
+ visible = this._core.$stage.children().toArray().slice(start, end),
+ heights = [],
+ maxheight = 0;
+ $.each(visible, function(index, item) {
+ heights.push($(item).height());
+ });
+ maxheight = Math.max.apply(null, heights);
+ if (maxheight <= 1 && lazyLoadEnabled && this._previousHeight) {
+ maxheight = this._previousHeight;
+ }
+ this._previousHeight = maxheight;
+
+ this._core.$stage.parent()
+ .height(maxheight)
+ .addClass(this._core.settings.autoHeightClass);
+ };
+ AutoHeight.prototype.destroy = function() {
+ var handler, property;
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] !== 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * Video Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the video plugin.
+ * @class The Video Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var Video = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ /**
+ * Cache all video URLs.
+ * @protected
+ * @type {Object}
+ */
+ this._videos = {};
+ /**
+ * Current playing item.
+ * @protected
+ * @type {jQuery}
+ */
+ this._playing = null;
+ /**
+ * All event handlers.
+ * @todo The cloned content removale is too late
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace) {
+ this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
+ }
+ }, this),
+ 'resize.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
+ e.preventDefault();
+ }
+ }, this),
+ 'refreshed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.is('resizing')) {
+ this._core.$stage.find('.cloned .owl-video-frame').remove();
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name === 'position' && this._playing) {
+ this.stop();
+ }
+ }, this),
+ 'prepared.owl.carousel': $.proxy(function(e) {
+ if (!e.namespace) {
+ return;
+ }
+ var $element = $(e.content).find('.owl-video');
+
+ if ($element.length) {
+ $element.css('display', 'none');
+ this.fetch($element, $(e.content));
+ }
+ }, this)
+ };
+ // set default options
+ this._core.options = $.extend({}, Video.Defaults, this._core.options);
+
+ // register event handlers
+ this._core.$element.on(this._handlers);
+
+ this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
+ this.play(e);
+ }, this));
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ Video.Defaults = {
+ video: false,
+ videoHeight: false,
+ videoWidth: false
+ };
+ /**
+ * Gets the video ID and the type (YouTube/Vimeo/vzaar only).
+ * @protected
+ * @param {jQuery} target - The target containing the video data.
+ * @param {jQuery} item - The item containing the video.
+ */
+ Video.prototype.fetch = function(target, item) {
+ var type = (function() {
+ if (target.attr('data-vimeo-id')) {
+ return 'vimeo';
+ } else if (target.attr('data-vzaar-id')) {
+ return 'vzaar'
+ } else {
+ return 'youtube';
+ }
+ })(),
+ id = target.attr('data-vimeo-id') || target.attr('data-youtube-id') || target.attr('data-vzaar-id'),
+ width = target.attr('data-width') || this._core.settings.videoWidth,
+ height = target.attr('data-height') || this._core.settings.videoHeight,
+ url = target.attr('href');
+
+ if (url) {
+ /*
+ Parses the id's out of the following urls (and probably more):
+ https://www.youtube.com/watch?v=:id
+ https://youtu.be/:id
+ https://vimeo.com/:id
+ https://vimeo.com/channels/:channel/:id
+ https://vimeo.com/groups/:group/videos/:id
+ https://app.vzaar.com/videos/:id
+
+ Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F
+ */
+ id = url.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com|be\-nocookie\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
+
+ if (id[3].indexOf('youtu') > -1) {
+ type = 'youtube';
+ } else if (id[3].indexOf('vimeo') > -1) {
+ type = 'vimeo';
+ } else if (id[3].indexOf('vzaar') > -1) {
+ type = 'vzaar';
+ } else {
+ throw new Error('Video URL not supported.');
+ }
+ id = id[6];
+ } else {
+ throw new Error('Missing video URL.');
+ }
+
+ this._videos[url] = {
+ type: type,
+ id: id,
+ width: width,
+ height: height
+ };
+ item.attr('data-video', url);
+ this.thumbnail(target, this._videos[url]);
+ };
+ /**
+ * Creates video thumbnail.
+ * @protected
+ * @param {jQuery} target - The target containing the video data.
+ * @param {Object} info - The video info object.
+ * @see `fetch`
+ */
+ Video.prototype.thumbnail = function(target, video) {
+ var tnLink,
+ icon,
+ path,
+ dimensions = video.width && video.height ? 'width:' + video.width + 'px;height:' + video.height + 'px;' : '',
+ customTn = target.find('img'),
+ srcType = 'src',
+ lazyClass = '',
+ settings = this._core.settings,
+ create = function(path) {
+ icon = '
';
+ if (settings.lazyLoad) {
+ tnLink = $('
',{
+ "class": 'owl-video-tn ' + lazyClass,
+ "srcType": path
+ });
+ } else {
+ tnLink = $( '
', {
+ "class": "owl-video-tn",
+ "style": 'opacity:1;background-image:url(' + path + ')'
+ });
+ }
+ target.after(tnLink);
+ target.after(icon);
+ };
+ // wrap video content into owl-video-wrapper div
+ target.wrap( $( '
', {
+ "class": "owl-video-wrapper",
+ "style": dimensions
+ }));
+ if (this._core.settings.lazyLoad) {
+ srcType = 'data-src';
+ lazyClass = 'owl-lazy';
+ }
+ // custom thumbnail
+ if (customTn.length) {
+ create(customTn.attr(srcType));
+ customTn.remove();
+ return false;
+ }
+ if (video.type === 'youtube') {
+ path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
+ create(path);
+ } else if (video.type === 'vimeo') {
+ $.ajax({
+ type: 'GET',
+ url: '//vimeo.com/api/v2/video/' + video.id + '.json',
+ jsonp: 'callback',
+ dataType: 'jsonp',
+ success: function(data) {
+ path = data[0].thumbnail_large;
+ create(path);
+ }
+ });
+ } else if (video.type === 'vzaar') {
+ $.ajax({
+ type: 'GET',
+ url: '//vzaar.com/api/videos/' + video.id + '.json',
+ jsonp: 'callback',
+ dataType: 'jsonp',
+ success: function(data) {
+ path = data.framegrab_url;
+ create(path);
+ }
+ });
+ }
+ };
+ /**
+ * Stops the current video.
+ * @public
+ */
+ Video.prototype.stop = function() {
+ this._core.trigger('stop', null, 'video');
+ this._playing.find('.owl-video-frame').remove();
+ this._playing.removeClass('owl-video-playing');
+ this._playing = null;
+ this._core.leave('playing');
+ this._core.trigger('stopped', null, 'video');
+ };
+ /**
+ * Starts the current video.
+ * @public
+ * @param {Event} event - The event arguments.
+ */
+ Video.prototype.play = function(event) {
+ var target = $(event.target),
+ item = target.closest('.' + this._core.settings.itemClass),
+ video = this._videos[item.attr('data-video')],
+ width = video.width || '100%',
+ height = video.height || this._core.$stage.height(),
+ html,
+ iframe;
+
+ if (this._playing) {
+ return;
+ }
+ this._core.enter('playing');
+ this._core.trigger('play', null, 'video');
+ item = this._core.items(this._core.relative(item.index()));
+ this._core.reset(item.index());
+ html = $( '' );
+ html.attr( 'height', height );
+ html.attr( 'width', width );
+ if (video.type === 'youtube') {
+ html.attr( 'src', '//www.youtube.com/embed/' + video.id + '?autoplay=1&rel=0&v=' + video.id );
+ } else if (video.type === 'vimeo') {
+ html.attr( 'src', '//player.vimeo.com/video/' + video.id + '?autoplay=1' );
+ } else if (video.type === 'vzaar') {
+ html.attr( 'src', '//view.vzaar.com/' + video.id + '/player?autoplay=true' );
+ }
+ iframe = $(html).wrap( '
' ).insertAfter(item.find('.owl-video'));
+ this._playing = item.addClass('owl-video-playing');
+ };
+ /**
+ * Checks whether an video is currently in full screen mode or not.
+ * @todo Bad style because looks like a readonly method but changes members.
+ * @protected
+ * @returns {Boolean}
+ */
+ Video.prototype.isInFullScreen = function() {
+ var element = document.fullscreenElement || document.mozFullScreenElement ||
+ document.webkitFullscreenElement;
+
+ return element && $(element).parent().hasClass('owl-video-frame');
+ };
+ /**
+ * Destroys the plugin.
+ */
+ Video.prototype.destroy = function() {
+ var handler, property;
+ this._core.$element.off('click.owl.video');
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.Video = Video;
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * Animate Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the animate plugin.
+ * @class The Navigation Plugin
+ * @param {Owl} scope - The Owl Carousel
+ */
+ var Animate = function(scope) {
+ this.core = scope;
+ this.core.options = $.extend({}, Animate.Defaults, this.core.options);
+ this.swapping = true;
+ this.previous = undefined;
+ this.next = undefined;
+ this.handlers = {
+ 'change.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name == 'position') {
+ this.previous = this.core.current();
+ this.next = e.property.value;
+ }
+ }, this),
+ 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
+ if (e.namespace) {
+ this.swapping = e.type == 'translated';
+ }
+ }, this),
+ 'translate.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
+ this.swap();
+ }
+ }, this)
+ };
+ this.core.$element.on(this.handlers);
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ Animate.Defaults = {
+ animateOut: false,
+ animateIn: false
+ };
+ /**
+ * Toggles the animation classes whenever an translations starts.
+ * @protected
+ * @returns {Boolean|undefined}
+ */
+ Animate.prototype.swap = function() {
+ if (this.core.settings.items !== 1) {
+ return;
+ }
+ if (!$.support.animation || !$.support.transition) {
+ return;
+ }
+ this.core.speed(0);
+ var left,
+ clear = $.proxy(this.clear, this),
+ previous = this.core.$stage.children().eq(this.previous),
+ next = this.core.$stage.children().eq(this.next),
+ incoming = this.core.settings.animateIn,
+ outgoing = this.core.settings.animateOut;
+
+ if (this.core.current() === this.previous) {
+ return;
+ }
+ if (outgoing) {
+ left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
+ previous.one($.support.animation.end, clear)
+ .css( { 'left': left + 'px' } )
+ .addClass('animated owl-animated-out')
+ .addClass(outgoing);
+ }
+ if (incoming) {
+ next.one($.support.animation.end, clear)
+ .addClass('animated owl-animated-in')
+ .addClass(incoming);
+ }
+ };
+ Animate.prototype.clear = function(e) {
+ $(e.target).css( { 'left': '' } )
+ .removeClass('animated owl-animated-out owl-animated-in')
+ .removeClass(this.core.settings.animateIn)
+ .removeClass(this.core.settings.animateOut);
+ this.core.onTransitionEnd();
+ };
+ /**
+ * Destroys the plugin.
+ * @public
+ */
+ Animate.prototype.destroy = function() {
+ var handler, property;
+ for (handler in this.handlers) {
+ this.core.$element.off(handler, this.handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * Autoplay Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @author Tom De Caluwé
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the autoplay plugin.
+ * @class The Autoplay Plugin
+ * @param {Owl} scope - The Owl Carousel
+ */
+ var Autoplay = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ /**
+ * The autoplay timeout id.
+ * @type {Number}
+ */
+ this._call = null;
+ /**
+ * Depending on the state of the plugin, this variable contains either
+ * the start time of the timer or the current timer value if it's
+ * paused. Since we start in a paused state we initialize the timer
+ * value.
+ * @type {Number}
+ */
+ this._time = 0;
+ /**
+ * Stores the timeout currently used.
+ * @type {Number}
+ */
+ this._timeout = 0;
+ /**
+ * Indicates whenever the autoplay is paused.
+ * @type {Boolean}
+ */
+ this._paused = true;
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name === 'settings') {
+ if (this._core.settings.autoplay) {
+ this.play();
+ } else {
+ this.stop();
+ }
+ } else if (e.namespace && e.property.name === 'position' && this._paused) {
+ // Reset the timer. This code is triggered when the position
+ // of the carousel was changed through user interaction.
+ this._time = 0;
+ }
+ }, this),
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoplay) {
+ this.play();
+ }
+ }, this),
+ 'play.owl.autoplay': $.proxy(function(e, t, s) {
+ if (e.namespace) {
+ this.play(t, s);
+ }
+ }, this),
+ 'stop.owl.autoplay': $.proxy(function(e) {
+ if (e.namespace) {
+ this.stop();
+ }
+ }, this),
+ 'mouseover.owl.autoplay': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
+ this.pause();
+ }
+ }, this),
+ 'mouseleave.owl.autoplay': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
+ this.play();
+ }
+ }, this),
+ 'touchstart.owl.core': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
+ this.pause();
+ }
+ }, this),
+ 'touchend.owl.core': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause) {
+ this.play();
+ }
+ }, this)
+ };
+ // register event handlers
+ this._core.$element.on(this._handlers);
+
+ // set default options
+ this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ Autoplay.Defaults = {
+ autoplay: false,
+ autoplayTimeout: 5000,
+ autoplayHoverPause: false,
+ autoplaySpeed: false
+ };
+ /**
+ * Transition to the next slide and set a timeout for the next transition.
+ * @private
+ * @param {Number} [speed] - The animation speed for the animations.
+ */
+ Autoplay.prototype._next = function(speed) {
+ this._call = window.setTimeout(
+ $.proxy(this._next, this, speed),
+ this._timeout * (Math.round(this.read() / this._timeout) + 1) - this.read()
+ );
+
+ if (this._core.is('interacting') || document.hidden) {
+ return;
+ }
+ this._core.next(speed || this._core.settings.autoplaySpeed);
+ }
+ /**
+ * Reads the current timer value when the timer is playing.
+ * @public
+ */
+ Autoplay.prototype.read = function() {
+ return new Date().getTime() - this._time;
+ };
+ /**
+ * Starts the autoplay.
+ * @public
+ * @param {Number} [timeout] - The interval before the next animation starts.
+ * @param {Number} [speed] - The animation speed for the animations.
+ */
+ Autoplay.prototype.play = function(timeout, speed) {
+ var elapsed;
+
+ if (!this._core.is('rotating')) {
+ this._core.enter('rotating');
+ }
+ timeout = timeout || this._core.settings.autoplayTimeout;
+ // Calculate the elapsed time since the last transition. If the carousel
+ // wasn't playing this calculation will yield zero.
+ elapsed = Math.min(this._time % (this._timeout || timeout), timeout);
+ if (this._paused) {
+ // Start the clock.
+ this._time = this.read();
+ this._paused = false;
+ } else {
+ // Clear the active timeout to allow replacement.
+ window.clearTimeout(this._call);
+ }
+ // Adjust the origin of the timer to match the new timeout value.
+ this._time += this.read() % timeout - elapsed;
+ this._timeout = timeout;
+ this._call = window.setTimeout($.proxy(this._next, this, speed), timeout - elapsed);
+ };
+ /**
+ * Stops the autoplay.
+ * @public
+ */
+ Autoplay.prototype.stop = function() {
+ if (this._core.is('rotating')) {
+ // Reset the clock.
+ this._time = 0;
+ this._paused = true;
+ window.clearTimeout(this._call);
+ this._core.leave('rotating');
+ }
+ };
+ /**
+ * Pauses the autoplay.
+ * @public
+ */
+ Autoplay.prototype.pause = function() {
+ if (this._core.is('rotating') && !this._paused) {
+ // Pause the clock.
+ this._time = this.read();
+ this._paused = true;
+ window.clearTimeout(this._call);
+ }
+ };
+ /**
+ * Destroys the plugin.
+ */
+ Autoplay.prototype.destroy = function() {
+ var handler, property;
+ this.stop();
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * Navigation Plugin
+ * @version 2.3.4
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ 'use strict';
+ /**
+ * Creates the navigation plugin.
+ * @class The Navigation Plugin
+ * @param {Owl} carousel - The Owl Carousel.
+ */
+ var Navigation = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+
+ /**
+ * Indicates whether the plugin is initialized or not.
+ * @protected
+ * @type {Boolean}
+ */
+ this._initialized = false;
+ /**
+ * The current paging indexes.
+ * @protected
+ * @type {Array}
+ */
+ this._pages = [];
+ /**
+ * All DOM elements of the user interface.
+ * @protected
+ * @type {Object}
+ */
+ this._controls = {};
+ /**
+ * Markup for an indicator.
+ * @protected
+ * @type {Array.}
+ */
+ this._templates = [];
+ /**
+ * The carousel element.
+ * @type {jQuery}
+ */
+ this.$element = this._core.$element;
+ /**
+ * Overridden methods of the carousel.
+ * @protected
+ * @type {Object}
+ */
+ this._overrides = {
+ next: this._core.next,
+ prev: this._core.prev,
+ to: this._core.to
+ };
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'prepared.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.dotsData) {
+ this._templates.push('' +
+ $(e.content).find('[data-dot]').addBack('[data-dot]').attr('data-dot') + '
');
+ }
+ }, this),
+ 'added.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.dotsData) {
+ this._templates.splice(e.position, 0, this._templates.pop());
+ }
+ }, this),
+ 'remove.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.dotsData) {
+ this._templates.splice(e.position, 1);
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name == 'position') {
+ this.draw();
+ }
+ }, this),
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && !this._initialized) {
+ this._core.trigger('initialize', null, 'navigation');
+ this.initialize();
+ this.update();
+ this.draw();
+ this._initialized = true;
+ this._core.trigger('initialized', null, 'navigation');
+ }
+ }, this),
+ 'refreshed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._initialized) {
+ this._core.trigger('refresh', null, 'navigation');
+ this.update();
+ this.draw();
+ this._core.trigger('refreshed', null, 'navigation');
+ }
+ }, this)
+ };
+ // set default options
+ this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
+
+ // register event handlers
+ this.$element.on(this._handlers);
+ };
+ /**
+ * Default options.
+ * @public
+ * @todo Rename `slideBy` to `navBy`
+ */
+ Navigation.Defaults = {
+ nav: false,
+ navText: [
+ '‹ ',
+ '› '
+ ],
+ navSpeed: false,
+ navElement: 'button type="button" role="presentation"',
+ navContainer: false,
+ navContainerClass: 'owl-nav',
+ navClass: [
+ 'owl-prev',
+ 'owl-next'
+ ],
+ slideBy: 1,
+ dotClass: 'owl-dot',
+ dotsClass: 'owl-dots',
+ dots: true,
+ dotsEach: false,
+ dotsData: false,
+ dotsSpeed: false,
+ dotsContainer: false
+ };
+ /**
+ * Initializes the layout of the plugin and extends the carousel.
+ * @protected
+ */
+ Navigation.prototype.initialize = function() {
+ var override,
+ settings = this._core.settings;
+ // create DOM structure for relative navigation
+ this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
+ : $('').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
+
+ this._controls.$previous = $('<' + settings.navElement + '>')
+ .addClass(settings.navClass[0])
+ .html(settings.navText[0])
+ .prependTo(this._controls.$relative)
+ .on('click', $.proxy(function(e) {
+ this.prev(settings.navSpeed);
+ }, this));
+ this._controls.$next = $('<' + settings.navElement + '>')
+ .addClass(settings.navClass[1])
+ .html(settings.navText[1])
+ .appendTo(this._controls.$relative)
+ .on('click', $.proxy(function(e) {
+ this.next(settings.navSpeed);
+ }, this));
+ // create DOM structure for absolute navigation
+ if (!settings.dotsData) {
+ this._templates = [ $('
')
+ .addClass(settings.dotClass)
+ .append($(''))
+ .prop('outerHTML') ];
+ }
+ this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
+ : $('').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
+ this._controls.$absolute.on('click', 'button', $.proxy(function(e) {
+ var index = $(e.target).parent().is(this._controls.$absolute)
+ ? $(e.target).index() : $(e.target).parent().index();
+ e.preventDefault();
+ this.to(index, settings.dotsSpeed);
+ }, this));
+ /*$el.on('focusin', function() {
+ $(document).off(".carousel");
+
+ $(document).on('keydown.carousel', function(e) {
+ if(e.keyCode == 37) {
+ $el.trigger('prev.owl')
+ }
+ if(e.keyCode == 39) {
+ $el.trigger('next.owl')
+ }
+ });
+ });*/
+
+ // override public methods of the carousel
+ for (override in this._overrides) {
+ this._core[override] = $.proxy(this[override], this);
+ }
+ };
+ /**
+ * Destroys the plugin.
+ * @protected
+ */
+ Navigation.prototype.destroy = function() {
+ var handler, control, property, override, settings;
+ settings = this._core.settings;
+
+ for (handler in this._handlers) {
+ this.$element.off(handler, this._handlers[handler]);
+ }
+ for (control in this._controls) {
+ if (control === '$relative' && settings.navContainer) {
+ this._controls[control].html('');
+ } else {
+ this._controls[control].remove();
+ }
+ }
+ for (override in this.overides) {
+ this._core[override] = this._overrides[override];
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ /**
+ * Updates the internal state.
+ * @protected
+ */
+ Navigation.prototype.update = function() {
+ var i, j, k,
+ lower = this._core.clones().length / 2,
+ upper = lower + this._core.items().length,
+ maximum = this._core.maximum(true),
+ settings = this._core.settings,
+ size = settings.center || settings.autoWidth || settings.dotsData
+ ? 1 : settings.dotsEach || settings.items;
+ if (settings.slideBy !== 'page') {
+ settings.slideBy = Math.min(settings.slideBy, settings.items);
+ }
+ if (settings.dots || settings.slideBy == 'page') {
+ this._pages = [];
+ for (i = lower, j = 0, k = 0; i < upper; i++) {
+ if (j >= size || j === 0) {
+ this._pages.push({
+ start: Math.min(maximum, i - lower),
+ end: i - lower + size - 1
+ });
+ if (Math.min(maximum, i - lower) === maximum) {
+ break;
+ }
+ j = 0, ++k;
+ }
+ j += this._core.mergers(this._core.relative(i));
+ }
+ }
+ };
+ /**
+ * Draws the user interface.
+ * @todo The option `dotsData` wont work.
+ * @protected
+ */
+ Navigation.prototype.draw = function() {
+ var difference,
+ settings = this._core.settings,
+ disabled = this._core.items().length <= settings.items,
+ index = this._core.relative(this._core.current()),
+ loop = settings.loop || settings.rewind;
+ this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
+ if (settings.nav) {
+ this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
+ this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
+ }
+ this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
+ if (settings.dots) {
+ difference = this._pages.length - this._controls.$absolute.children().length;
+ if (settings.dotsData && difference !== 0) {
+ this._controls.$absolute.html(this._templates.join(''));
+ } else if (difference > 0) {
+ this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
+ } else if (difference < 0) {
+ this._controls.$absolute.children().slice(difference).remove();
+ }
+ this._controls.$absolute.find('.active').removeClass('active');
+ this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
+ }
+ };
+ /**
+ * Extends event data.
+ * @protected
+ * @param {Event} event - The event object which gets thrown.
+ */
+ Navigation.prototype.onTrigger = function(event) {
+ var settings = this._core.settings;
+ event.page = {
+ index: $.inArray(this.current(), this._pages),
+ count: this._pages.length,
+ size: settings && (settings.center || settings.autoWidth || settings.dotsData
+ ? 1 : settings.dotsEach || settings.items)
+ };
+ };
+ /**
+ * Gets the current page position of the carousel.
+ * @protected
+ * @returns {Number}
+ */
+ Navigation.prototype.current = function() {
+ var current = this._core.relative(this._core.current());
+ return $.grep(this._pages, $.proxy(function(page, index) {
+ return page.start <= current && page.end >= current;
+ }, this)).pop();
+ };
+ /**
+ * Gets the current succesor/predecessor position.
+ * @protected
+ * @returns {Number}
+ */
+ Navigation.prototype.getPosition = function(successor) {
+ var position, length,
+ settings = this._core.settings;
+ if (settings.slideBy == 'page') {
+ position = $.inArray(this.current(), this._pages);
+ length = this._pages.length;
+ successor ? ++position : --position;
+ position = this._pages[((position % length) + length) % length].start;
+ } else {
+ position = this._core.relative(this._core.current());
+ length = this._core.items().length;
+ successor ? position += settings.slideBy : position -= settings.slideBy;
+ }
+ return position;
+ };
+ /**
+ * Slides to the next item or page.
+ * @public
+ * @param {Number} [speed=false] - The time in milliseconds for the transition.
+ */
+ Navigation.prototype.next = function(speed) {
+ $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
+ };
+ /**
+ * Slides to the previous item or page.
+ * @public
+ * @param {Number} [speed=false] - The time in milliseconds for the transition.
+ */
+ Navigation.prototype.prev = function(speed) {
+ $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
+ };
+ /**
+ * Slides to the specified item or page.
+ * @public
+ * @param {Number} position - The position of the item or page.
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
+ */
+ Navigation.prototype.to = function(position, speed, standard) {
+ var length;
+
+ if (!standard && this._pages.length) {
+ length = this._pages.length;
+ $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
+ } else {
+ $.proxy(this._overrides.to, this._core)(position, speed);
+ }
+ };
+
+ $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * Hash Plugin
+ * @version 2.3.4
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ 'use strict';
+ /**
+ * Creates the hash plugin.
+ * @class The Hash Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var Hash = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ /**
+ * Hash index for the items.
+ * @protected
+ * @type {Object}
+ */
+ this._hashes = {};
+ /**
+ * The carousel element.
+ * @type {jQuery}
+ */
+ this.$element = this._core.$element;
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.startPosition === 'URLHash') {
+ $(window).trigger('hashchange.owl.navigation');
+ }
+ }, this),
+ 'prepared.owl.carousel': $.proxy(function(e) {
+ if (e.namespace) {
+ var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
+
+ if (!hash) {
+ return;
+ }
+ this._hashes[hash] = e.content;
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name === 'position') {
+ var current = this._core.items(this._core.relative(this._core.current())),
+ hash = $.map(this._hashes, function(item, hash) {
+ return item === current ? hash : null;
+ }).join();
+ if (!hash || window.location.hash.slice(1) === hash) {
+ return;
+ }
+
+ window.location.hash = hash;
+ }
+ }, this)
+ };
+ // set default options
+ this._core.options = $.extend({}, Hash.Defaults, this._core.options);
+
+ // register the event handlers
+ this.$element.on(this._handlers);
+
+ // register event listener for hash navigation
+ $(window).on('hashchange.owl.navigation', $.proxy(function(e) {
+ var hash = window.location.hash.substring(1),
+ items = this._core.$stage.children(),
+ position = this._hashes[hash] && items.index(this._hashes[hash]);
+
+ if (position === undefined || position === this._core.current()) {
+ return;
+ }
+ this._core.to(this._core.relative(position), false, true);
+ }, this));
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ Hash.Defaults = {
+ URLhashListener: false
+ };
+ /**
+ * Destroys the plugin.
+ * @public
+ */
+ Hash.prototype.destroy = function() {
+ var handler, property;
+ $(window).off('hashchange.owl.navigation');
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * Support Plugin
+ *
+ * @version 2.3.4
+ * @author Vivid Planet Software GmbH
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ var style = $('
').get(0).style,
+ prefixes = 'Webkit Moz O ms'.split(' '),
+ events = {
+ transition: {
+ end: {
+ WebkitTransition: 'webkitTransitionEnd',
+ MozTransition: 'transitionend',
+ OTransition: 'oTransitionEnd',
+ transition: 'transitionend'
+ }
+ },
+ animation: {
+ end: {
+ WebkitAnimation: 'webkitAnimationEnd',
+ MozAnimation: 'animationend',
+ OAnimation: 'oAnimationEnd',
+ animation: 'animationend'
+ }
+ }
+ },
+ tests = {
+ csstransforms: function() {
+ return !!test('transform');
+ },
+ csstransforms3d: function() {
+ return !!test('perspective');
+ },
+ csstransitions: function() {
+ return !!test('transition');
+ },
+ cssanimations: function() {
+ return !!test('animation');
+ }
+ };
+ function test(property, prefixed) {
+ var result = false,
+ upper = property.charAt(0).toUpperCase() + property.slice(1);
+ $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
+ if (style[property] !== undefined) {
+ result = prefixed ? property : true;
+ return false;
+ }
+ });
+ return result;
+ }
+ function prefixed(property) {
+ return test(property, true);
+ }
+ if (tests.csstransitions()) {
+ /* jshint -W053 */
+ $.support.transition = new String(prefixed('transition'))
+ $.support.transition.end = events.transition.end[ $.support.transition ];
+ }
+ if (tests.cssanimations()) {
+ /* jshint -W053 */
+ $.support.animation = new String(prefixed('animation'))
+ $.support.animation.end = events.animation.end[ $.support.animation ];
+ }
+ if (tests.csstransforms()) {
+ /* jshint -W053 */
+ $.support.transform = new String(prefixed('transform'));
+ $.support.transform3d = tests.csstransforms3d();
+ }
+})(window.Zepto || window.jQuery, window, document);
diff --git a/theme_eco_refine/static/src/js/owl.carousel.min.js b/theme_eco_refine/static/src/js/owl.carousel.min.js
new file mode 100755
index 0000000000..241d0a97a6
--- /dev/null
+++ b/theme_eco_refine/static/src/js/owl.carousel.min.js
@@ -0,0 +1,7 @@
+/**
+ * Owl Carousel v2.3.4
+ * Copyright 2013-2018 David Deutsch
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
+ */
+!function(a,b,c,d){function e(b,c){this.settings=null,this.options=a.extend({},e.Defaults,c),this.$element=a(b),this._handlers={},this._plugins={},this._supress={},this._current=null,this._speed=null,this._coordinates=[],this._breakpoint=null,this._width=null,this._items=[],this._clones=[],this._mergers=[],this._widths=[],this._invalidated={},this._pipe=[],this._drag={time:null,target:null,pointer:null,stage:{start:null,current:null},direction:null},this._states={current:{},tags:{initializing:["busy"],animating:["busy"],dragging:["interacting"]}},a.each(["onResize","onThrottledResize"],a.proxy(function(b,c){this._handlers[c]=a.proxy(this[c],this)},this)),a.each(e.Plugins,a.proxy(function(a,b){this._plugins[a.charAt(0).toLowerCase()+a.slice(1)]=new b(this)},this)),a.each(e.Workers,a.proxy(function(b,c){this._pipe.push({filter:c.filter,run:a.proxy(c.run,this)})},this)),this.setup(),this.initialize()}e.Defaults={items:3,loop:!1,center:!1,rewind:!1,checkVisibility:!0,mouseDrag:!0,touchDrag:!0,pullDrag:!0,freeDrag:!1,margin:0,stagePadding:0,merge:!1,mergeFit:!0,autoWidth:!1,startPosition:0,rtl:!1,smartSpeed:250,fluidSpeed:!1,dragEndSpeed:!1,responsive:{},responsiveRefreshRate:200,responsiveBaseElement:b,fallbackEasing:"swing",slideTransition:"",info:!1,nestedItemSelector:!1,itemElement:"div",stageElement:"div",refreshClass:"owl-refresh",loadedClass:"owl-loaded",loadingClass:"owl-loading",rtlClass:"owl-rtl",responsiveClass:"owl-responsive",dragClass:"owl-drag",itemClass:"owl-item",stageClass:"owl-stage",stageOuterClass:"owl-stage-outer",grabClass:"owl-grab"},e.Width={Default:"default",Inner:"inner",Outer:"outer"},e.Type={Event:"event",State:"state"},e.Plugins={},e.Workers=[{filter:["width","settings"],run:function(){this._width=this.$element.width()}},{filter:["width","items","settings"],run:function(a){a.current=this._items&&this._items[this.relative(this._current)]}},{filter:["items","settings"],run:function(){this.$stage.children(".cloned").remove()}},{filter:["width","items","settings"],run:function(a){var b=this.settings.margin||"",c=!this.settings.autoWidth,d=this.settings.rtl,e={width:"auto","margin-left":d?b:"","margin-right":d?"":b};!c&&this.$stage.children().css(e),a.css=e}},{filter:["width","items","settings"],run:function(a){var b=(this.width()/this.settings.items).toFixed(3)-this.settings.margin,c=null,d=this._items.length,e=!this.settings.autoWidth,f=[];for(a.items={merge:!1,width:b};d--;)c=this._mergers[d],c=this.settings.mergeFit&&Math.min(c,this.settings.items)||c,a.items.merge=c>1||a.items.merge,f[d]=e?b*c:this._items[d].width();this._widths=f}},{filter:["items","settings"],run:function(){var b=[],c=this._items,d=this.settings,e=Math.max(2*d.items,4),f=2*Math.ceil(c.length/2),g=d.loop&&c.length?d.rewind?e:Math.max(e,f):0,h="",i="";for(g/=2;g>0;)b.push(this.normalize(b.length/2,!0)),h+=c[b[b.length-1]][0].outerHTML,b.push(this.normalize(c.length-1-(b.length-1)/2,!0)),i=c[b[b.length-1]][0].outerHTML+i,g-=1;this._clones=b,a(h).addClass("cloned").appendTo(this.$stage),a(i).addClass("cloned").prependTo(this.$stage)}},{filter:["width","items","settings"],run:function(){for(var a=this.settings.rtl?1:-1,b=this._clones.length+this._items.length,c=-1,d=0,e=0,f=[];++c",h)||this.op(b,"<",g)&&this.op(b,">",h))&&i.push(c);this.$stage.children(".active").removeClass("active"),this.$stage.children(":eq("+i.join("), :eq(")+")").addClass("active"),this.$stage.children(".center").removeClass("center"),this.settings.center&&this.$stage.children().eq(this.current()).addClass("center")}}],e.prototype.initializeStage=function(){this.$stage=this.$element.find("."+this.settings.stageClass),this.$stage.length||(this.$element.addClass(this.options.loadingClass),this.$stage=a("<"+this.settings.stageElement+">",{class:this.settings.stageClass}).wrap(a("
",{class:this.settings.stageOuterClass})),this.$element.append(this.$stage.parent()))},e.prototype.initializeItems=function(){var b=this.$element.find(".owl-item");if(b.length)return this._items=b.get().map(function(b){return a(b)}),this._mergers=this._items.map(function(){return 1}),void this.refresh();this.replace(this.$element.children().not(this.$stage.parent())),this.isVisible()?this.refresh():this.invalidate("width"),this.$element.removeClass(this.options.loadingClass).addClass(this.options.loadedClass)},e.prototype.initialize=function(){if(this.enter("initializing"),this.trigger("initialize"),this.$element.toggleClass(this.settings.rtlClass,this.settings.rtl),this.settings.autoWidth&&!this.is("pre-loading")){var a,b,c;a=this.$element.find("img"),b=this.settings.nestedItemSelector?"."+this.settings.nestedItemSelector:d,c=this.$element.children(b).width(),a.length&&c<=0&&this.preloadAutoWidthImages(a)}this.initializeStage(),this.initializeItems(),this.registerEventHandlers(),this.leave("initializing"),this.trigger("initialized")},e.prototype.isVisible=function(){return!this.settings.checkVisibility||this.$element.is(":visible")},e.prototype.setup=function(){var b=this.viewport(),c=this.options.responsive,d=-1,e=null;c?(a.each(c,function(a){a<=b&&a>d&&(d=Number(a))}),e=a.extend({},this.options,c[d]),"function"==typeof e.stagePadding&&(e.stagePadding=e.stagePadding()),delete e.responsive,e.responsiveClass&&this.$element.attr("class",this.$element.attr("class").replace(new RegExp("("+this.options.responsiveClass+"-)\\S+\\s","g"),"$1"+d))):e=a.extend({},this.options),this.trigger("change",{property:{name:"settings",value:e}}),this._breakpoint=d,this.settings=e,this.invalidate("settings"),this.trigger("changed",{property:{name:"settings",value:this.settings}})},e.prototype.optionsLogic=function(){this.settings.autoWidth&&(this.settings.stagePadding=!1,this.settings.merge=!1)},e.prototype.prepare=function(b){var c=this.trigger("prepare",{content:b});return c.data||(c.data=a("<"+this.settings.itemElement+"/>").addClass(this.options.itemClass).append(b)),this.trigger("prepared",{content:c.data}),c.data},e.prototype.update=function(){for(var b=0,c=this._pipe.length,d=a.proxy(function(a){return this[a]},this._invalidated),e={};b0)&&this._pipe[b].run(e),b++;this._invalidated={},!this.is("valid")&&this.enter("valid")},e.prototype.width=function(a){switch(a=a||e.Width.Default){case e.Width.Inner:case e.Width.Outer:return this._width;default:return this._width-2*this.settings.stagePadding+this.settings.margin}},e.prototype.refresh=function(){this.enter("refreshing"),this.trigger("refresh"),this.setup(),this.optionsLogic(),this.$element.addClass(this.options.refreshClass),this.update(),this.$element.removeClass(this.options.refreshClass),this.leave("refreshing"),this.trigger("refreshed")},e.prototype.onThrottledResize=function(){b.clearTimeout(this.resizeTimer),this.resizeTimer=b.setTimeout(this._handlers.onResize,this.settings.responsiveRefreshRate)},e.prototype.onResize=function(){return!!this._items.length&&(this._width!==this.$element.width()&&(!!this.isVisible()&&(this.enter("resizing"),this.trigger("resize").isDefaultPrevented()?(this.leave("resizing"),!1):(this.invalidate("width"),this.refresh(),this.leave("resizing"),void this.trigger("resized")))))},e.prototype.registerEventHandlers=function(){a.support.transition&&this.$stage.on(a.support.transition.end+".owl.core",a.proxy(this.onTransitionEnd,this)),!1!==this.settings.responsive&&this.on(b,"resize",this._handlers.onThrottledResize),this.settings.mouseDrag&&(this.$element.addClass(this.options.dragClass),this.$stage.on("mousedown.owl.core",a.proxy(this.onDragStart,this)),this.$stage.on("dragstart.owl.core selectstart.owl.core",function(){return!1})),this.settings.touchDrag&&(this.$stage.on("touchstart.owl.core",a.proxy(this.onDragStart,this)),this.$stage.on("touchcancel.owl.core",a.proxy(this.onDragEnd,this)))},e.prototype.onDragStart=function(b){var d=null;3!==b.which&&(a.support.transform?(d=this.$stage.css("transform").replace(/.*\(|\)| /g,"").split(","),d={x:d[16===d.length?12:4],y:d[16===d.length?13:5]}):(d=this.$stage.position(),d={x:this.settings.rtl?d.left+this.$stage.width()-this.width()+this.settings.margin:d.left,y:d.top}),this.is("animating")&&(a.support.transform?this.animate(d.x):this.$stage.stop(),this.invalidate("position")),this.$element.toggleClass(this.options.grabClass,"mousedown"===b.type),this.speed(0),this._drag.time=(new Date).getTime(),this._drag.target=a(b.target),this._drag.stage.start=d,this._drag.stage.current=d,this._drag.pointer=this.pointer(b),a(c).on("mouseup.owl.core touchend.owl.core",a.proxy(this.onDragEnd,this)),a(c).one("mousemove.owl.core touchmove.owl.core",a.proxy(function(b){var d=this.difference(this._drag.pointer,this.pointer(b));a(c).on("mousemove.owl.core touchmove.owl.core",a.proxy(this.onDragMove,this)),Math.abs(d.x)0^this.settings.rtl?"left":"right";a(c).off(".owl.core"),this.$element.removeClass(this.options.grabClass),(0!==d.x&&this.is("dragging")||!this.is("valid"))&&(this.speed(this.settings.dragEndSpeed||this.settings.smartSpeed),this.current(this.closest(e.x,0!==d.x?f:this._drag.direction)),this.invalidate("position"),this.update(),this._drag.direction=f,(Math.abs(d.x)>3||(new Date).getTime()-this._drag.time>300)&&this._drag.target.one("click.owl.core",function(){return!1})),this.is("dragging")&&(this.leave("dragging"),this.trigger("dragged"))},e.prototype.closest=function(b,c){var e=-1,f=30,g=this.width(),h=this.coordinates();return this.settings.freeDrag||a.each(h,a.proxy(function(a,i){return"left"===c&&b>i-f&&bi-g-f&&b",h[a+1]!==d?h[a+1]:i-g)&&(e="left"===c?a+1:a),-1===e},this)),this.settings.loop||(this.op(b,">",h[this.minimum()])?e=b=this.minimum():this.op(b,"<",h[this.maximum()])&&(e=b=this.maximum())),e},e.prototype.animate=function(b){var c=this.speed()>0;this.is("animating")&&this.onTransitionEnd(),c&&(this.enter("animating"),this.trigger("translate")),a.support.transform3d&&a.support.transition?this.$stage.css({transform:"translate3d("+b+"px,0px,0px)",transition:this.speed()/1e3+"s"+(this.settings.slideTransition?" "+this.settings.slideTransition:"")}):c?this.$stage.animate({left:b+"px"},this.speed(),this.settings.fallbackEasing,a.proxy(this.onTransitionEnd,this)):this.$stage.css({left:b+"px"})},e.prototype.is=function(a){return this._states.current[a]&&this._states.current[a]>0},e.prototype.current=function(a){if(a===d)return this._current;if(0===this._items.length)return d;if(a=this.normalize(a),this._current!==a){var b=this.trigger("change",{property:{name:"position",value:a}});b.data!==d&&(a=this.normalize(b.data)),this._current=a,this.invalidate("position"),this.trigger("changed",{property:{name:"position",value:this._current}})}return this._current},e.prototype.invalidate=function(b){return"string"===a.type(b)&&(this._invalidated[b]=!0,this.is("valid")&&this.leave("valid")),a.map(this._invalidated,function(a,b){return b})},e.prototype.reset=function(a){(a=this.normalize(a))!==d&&(this._speed=0,this._current=a,this.suppress(["translate","translated"]),this.animate(this.coordinates(a)),this.release(["translate","translated"]))},e.prototype.normalize=function(a,b){var c=this._items.length,e=b?0:this._clones.length;return!this.isNumeric(a)||c<1?a=d:(a<0||a>=c+e)&&(a=((a-e/2)%c+c)%c+e/2),a},e.prototype.relative=function(a){return a-=this._clones.length/2,this.normalize(a,!0)},e.prototype.maximum=function(a){var b,c,d,e=this.settings,f=this._coordinates.length;if(e.loop)f=this._clones.length/2+this._items.length-1;else if(e.autoWidth||e.merge){if(b=this._items.length)for(c=this._items[--b].width(),d=this.$element.width();b--&&!((c+=this._items[b].width()+this.settings.margin)>d););f=b+1}else f=e.center?this._items.length-1:this._items.length-e.items;return a&&(f-=this._clones.length/2),Math.max(f,0)},e.prototype.minimum=function(a){return a?0:this._clones.length/2},e.prototype.items=function(a){return a===d?this._items.slice():(a=this.normalize(a,!0),this._items[a])},e.prototype.mergers=function(a){return a===d?this._mergers.slice():(a=this.normalize(a,!0),this._mergers[a])},e.prototype.clones=function(b){var c=this._clones.length/2,e=c+this._items.length,f=function(a){return a%2==0?e+a/2:c-(a+1)/2};return b===d?a.map(this._clones,function(a,b){return f(b)}):a.map(this._clones,function(a,c){return a===b?f(c):null})},e.prototype.speed=function(a){return a!==d&&(this._speed=a),this._speed},e.prototype.coordinates=function(b){var c,e=1,f=b-1;return b===d?a.map(this._coordinates,a.proxy(function(a,b){return this.coordinates(b)},this)):(this.settings.center?(this.settings.rtl&&(e=-1,f=b+1),c=this._coordinates[b],c+=(this.width()-c+(this._coordinates[f]||0))/2*e):c=this._coordinates[f]||0,c=Math.ceil(c))},e.prototype.duration=function(a,b,c){return 0===c?0:Math.min(Math.max(Math.abs(b-a),1),6)*Math.abs(c||this.settings.smartSpeed)},e.prototype.to=function(a,b){var c=this.current(),d=null,e=a-this.relative(c),f=(e>0)-(e<0),g=this._items.length,h=this.minimum(),i=this.maximum();this.settings.loop?(!this.settings.rewind&&Math.abs(e)>g/2&&(e+=-1*f*g),a=c+e,(d=((a-h)%g+g)%g+h)!==a&&d-e<=i&&d-e>0&&(c=d-e,a=d,this.reset(c))):this.settings.rewind?(i+=1,a=(a%i+i)%i):a=Math.max(h,Math.min(i,a)),this.speed(this.duration(c,a,b)),this.current(a),this.isVisible()&&this.update()},e.prototype.next=function(a){a=a||!1,this.to(this.relative(this.current())+1,a)},e.prototype.prev=function(a){a=a||!1,this.to(this.relative(this.current())-1,a)},e.prototype.onTransitionEnd=function(a){if(a!==d&&(a.stopPropagation(),(a.target||a.srcElement||a.originalTarget)!==this.$stage.get(0)))return!1;this.leave("animating"),this.trigger("translated")},e.prototype.viewport=function(){var d;return this.options.responsiveBaseElement!==b?d=a(this.options.responsiveBaseElement).width():b.innerWidth?d=b.innerWidth:c.documentElement&&c.documentElement.clientWidth?d=c.documentElement.clientWidth:console.warn("Can not detect viewport width."),d},e.prototype.replace=function(b){this.$stage.empty(),this._items=[],b&&(b=b instanceof jQuery?b:a(b)),this.settings.nestedItemSelector&&(b=b.find("."+this.settings.nestedItemSelector)),b.filter(function(){return 1===this.nodeType}).each(a.proxy(function(a,b){b=this.prepare(b),this.$stage.append(b),this._items.push(b),this._mergers.push(1*b.find("[data-merge]").addBack("[data-merge]").attr("data-merge")||1)},this)),this.reset(this.isNumeric(this.settings.startPosition)?this.settings.startPosition:0),this.invalidate("items")},e.prototype.add=function(b,c){var e=this.relative(this._current);c=c===d?this._items.length:this.normalize(c,!0),b=b instanceof jQuery?b:a(b),this.trigger("add",{content:b,position:c}),b=this.prepare(b),0===this._items.length||c===this._items.length?(0===this._items.length&&this.$stage.append(b),0!==this._items.length&&this._items[c-1].after(b),this._items.push(b),this._mergers.push(1*b.find("[data-merge]").addBack("[data-merge]").attr("data-merge")||1)):(this._items[c].before(b),this._items.splice(c,0,b),this._mergers.splice(c,0,1*b.find("[data-merge]").addBack("[data-merge]").attr("data-merge")||1)),this._items[e]&&this.reset(this._items[e].index()),this.invalidate("items"),this.trigger("added",{content:b,position:c})},e.prototype.remove=function(a){(a=this.normalize(a,!0))!==d&&(this.trigger("remove",{content:this._items[a],position:a}),this._items[a].remove(),this._items.splice(a,1),this._mergers.splice(a,1),this.invalidate("items"),this.trigger("removed",{content:null,position:a}))},e.prototype.preloadAutoWidthImages=function(b){b.each(a.proxy(function(b,c){this.enter("pre-loading"),c=a(c),a(new Image).one("load",a.proxy(function(a){c.attr("src",a.target.src),c.css("opacity",1),this.leave("pre-loading"),!this.is("pre-loading")&&!this.is("initializing")&&this.refresh()},this)).attr("src",c.attr("src")||c.attr("data-src")||c.attr("data-src-retina"))},this))},e.prototype.destroy=function(){this.$element.off(".owl.core"),this.$stage.off(".owl.core"),a(c).off(".owl.core"),!1!==this.settings.responsive&&(b.clearTimeout(this.resizeTimer),this.off(b,"resize",this._handlers.onThrottledResize));for(var d in this._plugins)this._plugins[d].destroy();this.$stage.children(".cloned").remove(),this.$stage.unwrap(),this.$stage.children().contents().unwrap(),this.$stage.children().unwrap(),this.$stage.remove(),this.$element.removeClass(this.options.refreshClass).removeClass(this.options.loadingClass).removeClass(this.options.loadedClass).removeClass(this.options.rtlClass).removeClass(this.options.dragClass).removeClass(this.options.grabClass).attr("class",this.$element.attr("class").replace(new RegExp(this.options.responsiveClass+"-\\S+\\s","g"),"")).removeData("owl.carousel")},e.prototype.op=function(a,b,c){var d=this.settings.rtl;switch(b){case"<":return d?a>c:a":return d?ac;case">=":return d?a<=c:a>=c;case"<=":return d?a>=c:a<=c}},e.prototype.on=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,d):a.attachEvent&&a.attachEvent("on"+b,c)},e.prototype.off=function(a,b,c,d){a.removeEventListener?a.removeEventListener(b,c,d):a.detachEvent&&a.detachEvent("on"+b,c)},e.prototype.trigger=function(b,c,d,f,g){var h={item:{count:this._items.length,index:this.current()}},i=a.camelCase(a.grep(["on",b,d],function(a){return a}).join("-").toLowerCase()),j=a.Event([b,"owl",d||"carousel"].join(".").toLowerCase(),a.extend({relatedTarget:this},h,c));return this._supress[b]||(a.each(this._plugins,function(a,b){b.onTrigger&&b.onTrigger(j)}),this.register({type:e.Type.Event,name:b}),this.$element.trigger(j),this.settings&&"function"==typeof this.settings[i]&&this.settings[i].call(this,j)),j},e.prototype.enter=function(b){a.each([b].concat(this._states.tags[b]||[]),a.proxy(function(a,b){this._states.current[b]===d&&(this._states.current[b]=0),this._states.current[b]++},this))},e.prototype.leave=function(b){a.each([b].concat(this._states.tags[b]||[]),a.proxy(function(a,b){this._states.current[b]--},this))},e.prototype.register=function(b){if(b.type===e.Type.Event){if(a.event.special[b.name]||(a.event.special[b.name]={}),!a.event.special[b.name].owl){var c=a.event.special[b.name]._default;a.event.special[b.name]._default=function(a){return!c||!c.apply||a.namespace&&-1!==a.namespace.indexOf("owl")?a.namespace&&a.namespace.indexOf("owl")>-1:c.apply(this,arguments)},a.event.special[b.name].owl=!0}}else b.type===e.Type.State&&(this._states.tags[b.name]?this._states.tags[b.name]=this._states.tags[b.name].concat(b.tags):this._states.tags[b.name]=b.tags,this._states.tags[b.name]=a.grep(this._states.tags[b.name],a.proxy(function(c,d){return a.inArray(c,this._states.tags[b.name])===d},this)))},e.prototype.suppress=function(b){a.each(b,a.proxy(function(a,b){this._supress[b]=!0},this))},e.prototype.release=function(b){a.each(b,a.proxy(function(a,b){delete this._supress[b]},this))},e.prototype.pointer=function(a){var c={x:null,y:null};return a=a.originalEvent||a||b.event,a=a.touches&&a.touches.length?a.touches[0]:a.changedTouches&&a.changedTouches.length?a.changedTouches[0]:a,a.pageX?(c.x=a.pageX,c.y=a.pageY):(c.x=a.clientX,c.y=a.clientY),c},e.prototype.isNumeric=function(a){return!isNaN(parseFloat(a))},e.prototype.difference=function(a,b){return{x:a.x-b.x,y:a.y-b.y}},a.fn.owlCarousel=function(b){var c=Array.prototype.slice.call(arguments,1);return this.each(function(){var d=a(this),f=d.data("owl.carousel");f||(f=new e(this,"object"==typeof b&&b),d.data("owl.carousel",f),a.each(["next","prev","to","destroy","refresh","replace","add","remove"],function(b,c){f.register({type:e.Type.Event,name:c}),f.$element.on(c+".owl.carousel.core",a.proxy(function(a){a.namespace&&a.relatedTarget!==this&&(this.suppress([c]),f[c].apply(this,[].slice.call(arguments,1)),this.release([c]))},f))})),"string"==typeof b&&"_"!==b.charAt(0)&&f[b].apply(f,c)})},a.fn.owlCarousel.Constructor=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._interval=null,this._visible=null,this._handlers={"initialized.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoRefresh&&this.watch()},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers)};e.Defaults={autoRefresh:!0,autoRefreshInterval:500},e.prototype.watch=function(){this._interval||(this._visible=this._core.isVisible(),this._interval=b.setInterval(a.proxy(this.refresh,this),this._core.settings.autoRefreshInterval))},e.prototype.refresh=function(){this._core.isVisible()!==this._visible&&(this._visible=!this._visible,this._core.$element.toggleClass("owl-hidden",!this._visible),this._visible&&this._core.invalidate("width")&&this._core.refresh())},e.prototype.destroy=function(){var a,c;b.clearInterval(this._interval);for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(c in Object.getOwnPropertyNames(this))"function"!=typeof this[c]&&(this[c]=null)},a.fn.owlCarousel.Constructor.Plugins.AutoRefresh=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._loaded=[],this._handlers={"initialized.owl.carousel change.owl.carousel resized.owl.carousel":a.proxy(function(b){if(b.namespace&&this._core.settings&&this._core.settings.lazyLoad&&(b.property&&"position"==b.property.name||"initialized"==b.type)){var c=this._core.settings,e=c.center&&Math.ceil(c.items/2)||c.items,f=c.center&&-1*e||0,g=(b.property&&b.property.value!==d?b.property.value:this._core.current())+f,h=this._core.clones().length,i=a.proxy(function(a,b){this.load(b)},this);for(c.lazyLoadEager>0&&(e+=c.lazyLoadEager,c.loop&&(g-=c.lazyLoadEager,e++));f++-1||(e.each(a.proxy(function(c,d){var e,f=a(d),g=b.devicePixelRatio>1&&f.attr("data-src-retina")||f.attr("data-src")||f.attr("data-srcset");this._core.trigger("load",{element:f,url:g},"lazy"),f.is("img")?f.one("load.owl.lazy",a.proxy(function(){f.css("opacity",1),this._core.trigger("loaded",{element:f,url:g},"lazy")},this)).attr("src",g):f.is("source")?f.one("load.owl.lazy",a.proxy(function(){this._core.trigger("loaded",{element:f,url:g},"lazy")},this)).attr("srcset",g):(e=new Image,e.onload=a.proxy(function(){f.css({"background-image":'url("'+g+'")',opacity:"1"}),this._core.trigger("loaded",{element:f,url:g},"lazy")},this),e.src=g)},this)),this._loaded.push(d.get(0)))},e.prototype.destroy=function(){var a,b;for(a in this.handlers)this._core.$element.off(a,this.handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Lazy=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(c){this._core=c,this._previousHeight=null,this._handlers={"initialized.owl.carousel refreshed.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&this.update()},this),"changed.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&"position"===a.property.name&&this.update()},this),"loaded.owl.lazy":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&a.element.closest("."+this._core.settings.itemClass).index()===this._core.current()&&this.update()},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers),this._intervalId=null;var d=this;a(b).on("load",function(){d._core.settings.autoHeight&&d.update()}),a(b).resize(function(){d._core.settings.autoHeight&&(null!=d._intervalId&&clearTimeout(d._intervalId),d._intervalId=setTimeout(function(){d.update()},250))})};e.Defaults={autoHeight:!1,autoHeightClass:"owl-height"},e.prototype.update=function(){var b=this._core._current,c=b+this._core.settings.items,d=this._core.settings.lazyLoad,e=this._core.$stage.children().toArray().slice(b,c),f=[],g=0;a.each(e,function(b,c){f.push(a(c).height())}),g=Math.max.apply(null,f),g<=1&&d&&this._previousHeight&&(g=this._previousHeight),this._previousHeight=g,this._core.$stage.parent().height(g).addClass(this._core.settings.autoHeightClass)},e.prototype.destroy=function(){var a,b;for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.AutoHeight=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._videos={},this._playing=null,this._handlers={"initialized.owl.carousel":a.proxy(function(a){a.namespace&&this._core.register({type:"state",name:"playing",tags:["interacting"]})},this),"resize.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.video&&this.isInFullScreen()&&a.preventDefault()},this),"refreshed.owl.carousel":a.proxy(function(a){a.namespace&&this._core.is("resizing")&&this._core.$stage.find(".cloned .owl-video-frame").remove()},this),"changed.owl.carousel":a.proxy(function(a){a.namespace&&"position"===a.property.name&&this._playing&&this.stop()},this),"prepared.owl.carousel":a.proxy(function(b){if(b.namespace){var c=a(b.content).find(".owl-video");c.length&&(c.css("display","none"),this.fetch(c,a(b.content)))}},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers),this._core.$element.on("click.owl.video",".owl-video-play-icon",a.proxy(function(a){this.play(a)},this))};e.Defaults={video:!1,videoHeight:!1,videoWidth:!1},e.prototype.fetch=function(a,b){var c=function(){return a.attr("data-vimeo-id")?"vimeo":a.attr("data-vzaar-id")?"vzaar":"youtube"}(),d=a.attr("data-vimeo-id")||a.attr("data-youtube-id")||a.attr("data-vzaar-id"),e=a.attr("data-width")||this._core.settings.videoWidth,f=a.attr("data-height")||this._core.settings.videoHeight,g=a.attr("href");if(!g)throw new Error("Missing video URL.");if(d=g.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com|be\-nocookie\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/),d[3].indexOf("youtu")>-1)c="youtube";else if(d[3].indexOf("vimeo")>-1)c="vimeo";else{if(!(d[3].indexOf("vzaar")>-1))throw new Error("Video URL not supported.");c="vzaar"}d=d[6],this._videos[g]={type:c,id:d,width:e,height:f},b.attr("data-video",g),this.thumbnail(a,this._videos[g])},e.prototype.thumbnail=function(b,c){var d,e,f,g=c.width&&c.height?"width:"+c.width+"px;height:"+c.height+"px;":"",h=b.find("img"),i="src",j="",k=this._core.settings,l=function(c){e='
',d=k.lazyLoad?a("
",{class:"owl-video-tn "+j,srcType:c}):a("
",{class:"owl-video-tn",style:"opacity:1;background-image:url("+c+")"}),b.after(d),b.after(e)};if(b.wrap(a("
",{class:"owl-video-wrapper",style:g})),this._core.settings.lazyLoad&&(i="data-src",j="owl-lazy"),h.length)return l(h.attr(i)),h.remove(),!1;"youtube"===c.type?(f="//img.youtube.com/vi/"+c.id+"/hqdefault.jpg",l(f)):"vimeo"===c.type?a.ajax({type:"GET",url:"//vimeo.com/api/v2/video/"+c.id+".json",jsonp:"callback",dataType:"jsonp",success:function(a){f=a[0].thumbnail_large,l(f)}}):"vzaar"===c.type&&a.ajax({type:"GET",url:"//vzaar.com/api/videos/"+c.id+".json",jsonp:"callback",dataType:"jsonp",success:function(a){f=a.framegrab_url,l(f)}})},e.prototype.stop=function(){this._core.trigger("stop",null,"video"),this._playing.find(".owl-video-frame").remove(),this._playing.removeClass("owl-video-playing"),this._playing=null,this._core.leave("playing"),this._core.trigger("stopped",null,"video")},e.prototype.play=function(b){var c,d=a(b.target),e=d.closest("."+this._core.settings.itemClass),f=this._videos[e.attr("data-video")],g=f.width||"100%",h=f.height||this._core.$stage.height();this._playing||(this._core.enter("playing"),this._core.trigger("play",null,"video"),e=this._core.items(this._core.relative(e.index())),this._core.reset(e.index()),c=a(''),c.attr("height",h),c.attr("width",g),"youtube"===f.type?c.attr("src","//www.youtube.com/embed/"+f.id+"?autoplay=1&rel=0&v="+f.id):"vimeo"===f.type?c.attr("src","//player.vimeo.com/video/"+f.id+"?autoplay=1"):"vzaar"===f.type&&c.attr("src","//view.vzaar.com/"+f.id+"/player?autoplay=true"),a(c).wrap('
').insertAfter(e.find(".owl-video")),this._playing=e.addClass("owl-video-playing"))},e.prototype.isInFullScreen=function(){var b=c.fullscreenElement||c.mozFullScreenElement||c.webkitFullscreenElement;return b&&a(b).parent().hasClass("owl-video-frame")},e.prototype.destroy=function(){var a,b;this._core.$element.off("click.owl.video");for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Video=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this.core=b,this.core.options=a.extend({},e.Defaults,this.core.options),this.swapping=!0,this.previous=d,this.next=d,this.handlers={"change.owl.carousel":a.proxy(function(a){a.namespace&&"position"==a.property.name&&(this.previous=this.core.current(),this.next=a.property.value)},this),"drag.owl.carousel dragged.owl.carousel translated.owl.carousel":a.proxy(function(a){a.namespace&&(this.swapping="translated"==a.type)},this),"translate.owl.carousel":a.proxy(function(a){a.namespace&&this.swapping&&(this.core.options.animateOut||this.core.options.animateIn)&&this.swap()},this)},this.core.$element.on(this.handlers)};e.Defaults={animateOut:!1,
+animateIn:!1},e.prototype.swap=function(){if(1===this.core.settings.items&&a.support.animation&&a.support.transition){this.core.speed(0);var b,c=a.proxy(this.clear,this),d=this.core.$stage.children().eq(this.previous),e=this.core.$stage.children().eq(this.next),f=this.core.settings.animateIn,g=this.core.settings.animateOut;this.core.current()!==this.previous&&(g&&(b=this.core.coordinates(this.previous)-this.core.coordinates(this.next),d.one(a.support.animation.end,c).css({left:b+"px"}).addClass("animated owl-animated-out").addClass(g)),f&&e.one(a.support.animation.end,c).addClass("animated owl-animated-in").addClass(f))}},e.prototype.clear=function(b){a(b.target).css({left:""}).removeClass("animated owl-animated-out owl-animated-in").removeClass(this.core.settings.animateIn).removeClass(this.core.settings.animateOut),this.core.onTransitionEnd()},e.prototype.destroy=function(){var a,b;for(a in this.handlers)this.core.$element.off(a,this.handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Animate=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._call=null,this._time=0,this._timeout=0,this._paused=!0,this._handlers={"changed.owl.carousel":a.proxy(function(a){a.namespace&&"settings"===a.property.name?this._core.settings.autoplay?this.play():this.stop():a.namespace&&"position"===a.property.name&&this._paused&&(this._time=0)},this),"initialized.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoplay&&this.play()},this),"play.owl.autoplay":a.proxy(function(a,b,c){a.namespace&&this.play(b,c)},this),"stop.owl.autoplay":a.proxy(function(a){a.namespace&&this.stop()},this),"mouseover.owl.autoplay":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is("rotating")&&this.pause()},this),"mouseleave.owl.autoplay":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is("rotating")&&this.play()},this),"touchstart.owl.core":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is("rotating")&&this.pause()},this),"touchend.owl.core":a.proxy(function(){this._core.settings.autoplayHoverPause&&this.play()},this)},this._core.$element.on(this._handlers),this._core.options=a.extend({},e.Defaults,this._core.options)};e.Defaults={autoplay:!1,autoplayTimeout:5e3,autoplayHoverPause:!1,autoplaySpeed:!1},e.prototype._next=function(d){this._call=b.setTimeout(a.proxy(this._next,this,d),this._timeout*(Math.round(this.read()/this._timeout)+1)-this.read()),this._core.is("interacting")||c.hidden||this._core.next(d||this._core.settings.autoplaySpeed)},e.prototype.read=function(){return(new Date).getTime()-this._time},e.prototype.play=function(c,d){var e;this._core.is("rotating")||this._core.enter("rotating"),c=c||this._core.settings.autoplayTimeout,e=Math.min(this._time%(this._timeout||c),c),this._paused?(this._time=this.read(),this._paused=!1):b.clearTimeout(this._call),this._time+=this.read()%c-e,this._timeout=c,this._call=b.setTimeout(a.proxy(this._next,this,d),c-e)},e.prototype.stop=function(){this._core.is("rotating")&&(this._time=0,this._paused=!0,b.clearTimeout(this._call),this._core.leave("rotating"))},e.prototype.pause=function(){this._core.is("rotating")&&!this._paused&&(this._time=this.read(),this._paused=!0,b.clearTimeout(this._call))},e.prototype.destroy=function(){var a,b;this.stop();for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.autoplay=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){"use strict";var e=function(b){this._core=b,this._initialized=!1,this._pages=[],this._controls={},this._templates=[],this.$element=this._core.$element,this._overrides={next:this._core.next,prev:this._core.prev,to:this._core.to},this._handlers={"prepared.owl.carousel":a.proxy(function(b){b.namespace&&this._core.settings.dotsData&&this._templates.push(''+a(b.content).find("[data-dot]").addBack("[data-dot]").attr("data-dot")+"
")},this),"added.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.dotsData&&this._templates.splice(a.position,0,this._templates.pop())},this),"remove.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.dotsData&&this._templates.splice(a.position,1)},this),"changed.owl.carousel":a.proxy(function(a){a.namespace&&"position"==a.property.name&&this.draw()},this),"initialized.owl.carousel":a.proxy(function(a){a.namespace&&!this._initialized&&(this._core.trigger("initialize",null,"navigation"),this.initialize(),this.update(),this.draw(),this._initialized=!0,this._core.trigger("initialized",null,"navigation"))},this),"refreshed.owl.carousel":a.proxy(function(a){a.namespace&&this._initialized&&(this._core.trigger("refresh",null,"navigation"),this.update(),this.draw(),this._core.trigger("refreshed",null,"navigation"))},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this.$element.on(this._handlers)};e.Defaults={nav:!1,navText:['‹ ','› '],navSpeed:!1,navElement:'button type="button" role="presentation"',navContainer:!1,navContainerClass:"owl-nav",navClass:["owl-prev","owl-next"],slideBy:1,dotClass:"owl-dot",dotsClass:"owl-dots",dots:!0,dotsEach:!1,dotsData:!1,dotsSpeed:!1,dotsContainer:!1},e.prototype.initialize=function(){var b,c=this._core.settings;this._controls.$relative=(c.navContainer?a(c.navContainer):a("").addClass(c.navContainerClass).appendTo(this.$element)).addClass("disabled"),this._controls.$previous=a("<"+c.navElement+">").addClass(c.navClass[0]).html(c.navText[0]).prependTo(this._controls.$relative).on("click",a.proxy(function(a){this.prev(c.navSpeed)},this)),this._controls.$next=a("<"+c.navElement+">").addClass(c.navClass[1]).html(c.navText[1]).appendTo(this._controls.$relative).on("click",a.proxy(function(a){this.next(c.navSpeed)},this)),c.dotsData||(this._templates=[a('
').addClass(c.dotClass).append(a("")).prop("outerHTML")]),this._controls.$absolute=(c.dotsContainer?a(c.dotsContainer):a("").addClass(c.dotsClass).appendTo(this.$element)).addClass("disabled"),this._controls.$absolute.on("click","button",a.proxy(function(b){var d=a(b.target).parent().is(this._controls.$absolute)?a(b.target).index():a(b.target).parent().index();b.preventDefault(),this.to(d,c.dotsSpeed)},this));for(b in this._overrides)this._core[b]=a.proxy(this[b],this)},e.prototype.destroy=function(){var a,b,c,d,e;e=this._core.settings;for(a in this._handlers)this.$element.off(a,this._handlers[a]);for(b in this._controls)"$relative"===b&&e.navContainer?this._controls[b].html(""):this._controls[b].remove();for(d in this.overides)this._core[d]=this._overrides[d];for(c in Object.getOwnPropertyNames(this))"function"!=typeof this[c]&&(this[c]=null)},e.prototype.update=function(){var a,b,c,d=this._core.clones().length/2,e=d+this._core.items().length,f=this._core.maximum(!0),g=this._core.settings,h=g.center||g.autoWidth||g.dotsData?1:g.dotsEach||g.items;if("page"!==g.slideBy&&(g.slideBy=Math.min(g.slideBy,g.items)),g.dots||"page"==g.slideBy)for(this._pages=[],a=d,b=0,c=0;a
=h||0===b){if(this._pages.push({start:Math.min(f,a-d),end:a-d+h-1}),Math.min(f,a-d)===f)break;b=0,++c}b+=this._core.mergers(this._core.relative(a))}},e.prototype.draw=function(){var b,c=this._core.settings,d=this._core.items().length<=c.items,e=this._core.relative(this._core.current()),f=c.loop||c.rewind;this._controls.$relative.toggleClass("disabled",!c.nav||d),c.nav&&(this._controls.$previous.toggleClass("disabled",!f&&e<=this._core.minimum(!0)),this._controls.$next.toggleClass("disabled",!f&&e>=this._core.maximum(!0))),this._controls.$absolute.toggleClass("disabled",!c.dots||d),c.dots&&(b=this._pages.length-this._controls.$absolute.children().length,c.dotsData&&0!==b?this._controls.$absolute.html(this._templates.join("")):b>0?this._controls.$absolute.append(new Array(b+1).join(this._templates[0])):b<0&&this._controls.$absolute.children().slice(b).remove(),this._controls.$absolute.find(".active").removeClass("active"),this._controls.$absolute.children().eq(a.inArray(this.current(),this._pages)).addClass("active"))},e.prototype.onTrigger=function(b){var c=this._core.settings;b.page={index:a.inArray(this.current(),this._pages),count:this._pages.length,size:c&&(c.center||c.autoWidth||c.dotsData?1:c.dotsEach||c.items)}},e.prototype.current=function(){var b=this._core.relative(this._core.current());return a.grep(this._pages,a.proxy(function(a,c){return a.start<=b&&a.end>=b},this)).pop()},e.prototype.getPosition=function(b){var c,d,e=this._core.settings;return"page"==e.slideBy?(c=a.inArray(this.current(),this._pages),d=this._pages.length,b?++c:--c,c=this._pages[(c%d+d)%d].start):(c=this._core.relative(this._core.current()),d=this._core.items().length,b?c+=e.slideBy:c-=e.slideBy),c},e.prototype.next=function(b){a.proxy(this._overrides.to,this._core)(this.getPosition(!0),b)},e.prototype.prev=function(b){a.proxy(this._overrides.to,this._core)(this.getPosition(!1),b)},e.prototype.to=function(b,c,d){var e;!d&&this._pages.length?(e=this._pages.length,a.proxy(this._overrides.to,this._core)(this._pages[(b%e+e)%e].start,c)):a.proxy(this._overrides.to,this._core)(b,c)},a.fn.owlCarousel.Constructor.Plugins.Navigation=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){"use strict";var e=function(c){this._core=c,this._hashes={},this.$element=this._core.$element,this._handlers={"initialized.owl.carousel":a.proxy(function(c){c.namespace&&"URLHash"===this._core.settings.startPosition&&a(b).trigger("hashchange.owl.navigation")},this),"prepared.owl.carousel":a.proxy(function(b){if(b.namespace){var c=a(b.content).find("[data-hash]").addBack("[data-hash]").attr("data-hash");if(!c)return;this._hashes[c]=b.content}},this),"changed.owl.carousel":a.proxy(function(c){if(c.namespace&&"position"===c.property.name){var d=this._core.items(this._core.relative(this._core.current())),e=a.map(this._hashes,function(a,b){return a===d?b:null}).join();if(!e||b.location.hash.slice(1)===e)return;b.location.hash=e}},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this.$element.on(this._handlers),a(b).on("hashchange.owl.navigation",a.proxy(function(a){var c=b.location.hash.substring(1),e=this._core.$stage.children(),f=this._hashes[c]&&e.index(this._hashes[c]);f!==d&&f!==this._core.current()&&this._core.to(this._core.relative(f),!1,!0)},this))};e.Defaults={URLhashListener:!1},e.prototype.destroy=function(){var c,d;a(b).off("hashchange.owl.navigation");for(c in this._handlers)this._core.$element.off(c,this._handlers[c]);for(d in Object.getOwnPropertyNames(this))"function"!=typeof this[d]&&(this[d]=null)},a.fn.owlCarousel.Constructor.Plugins.Hash=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){function e(b,c){var e=!1,f=b.charAt(0).toUpperCase()+b.slice(1);return a.each((b+" "+h.join(f+" ")+f).split(" "),function(a,b){if(g[b]!==d)return e=!c||b,!1}),e}function f(a){return e(a,!0)}var g=a("").get(0).style,h="Webkit Moz O ms".split(" "),i={transition:{end:{WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",transition:"transitionend"}},animation:{end:{WebkitAnimation:"webkitAnimationEnd",MozAnimation:"animationend",OAnimation:"oAnimationEnd",animation:"animationend"}}},j={csstransforms:function(){return!!e("transform")},csstransforms3d:function(){return!!e("perspective")},csstransitions:function(){return!!e("transition")},cssanimations:function(){return!!e("animation")}};j.csstransitions()&&(a.support.transition=new String(f("transition")),a.support.transition.end=i.transition.end[a.support.transition]),j.cssanimations()&&(a.support.animation=new String(f("animation")),a.support.animation.end=i.animation.end[a.support.animation]),j.csstransforms()&&(a.support.transform=new String(f("transform")),a.support.transform3d=j.csstransforms3d())}(window.Zepto||window.jQuery,window,document);
diff --git a/theme_eco_refine/static/src/js/product_specification.js b/theme_eco_refine/static/src/js/product_specification.js
new file mode 100755
index 0000000000..3b0412276a
--- /dev/null
+++ b/theme_eco_refine/static/src/js/product_specification.js
@@ -0,0 +1,30 @@
+/** @odoo-module */
+ import publicWidget from '@web/legacy/js/public/public_widget';
+ publicWidget.registry.refurb_theme_product = publicWidget.Widget.extend({
+ templates: 'website_sale.product',
+ selector: '.tab',
+ events: {
+ 'click .tab-link': 'openTab',
+ },
+ openTab: function (ev) {
+ let tabId;
+ if(this.$(ev.target).hasClass('tab1')){
+ tabId = "tab1"
+ }else{
+ tabId = "tab2"
+ }
+ var tabContent = $(this.$el[0].parentNode.querySelectorAll(".tab-content"))
+ var tabLinks = this.$el.find(".tab-link")
+ for (var i = 0; i < tabContent.length; i++) {
+ tabContent[i].style.display = "none";
+ }
+ for (var i = 0; i < tabLinks.length; i++) {
+ tabLinks[i].classList.remove("active");
+ }
+ if(tabId){
+ this.$el[0].parentNode.querySelectorAll("#"+tabId)[0].style.display = "block";
+ }
+ ev.target.classList.add("active");
+ }
+ });
+ return publicWidget.registry.refurb_theme_product;
diff --git a/theme_eco_refine/static/src/js/top_rated_products_snippet.js b/theme_eco_refine/static/src/js/top_rated_products_snippet.js
new file mode 100755
index 0000000000..f72a8e22d1
--- /dev/null
+++ b/theme_eco_refine/static/src/js/top_rated_products_snippet.js
@@ -0,0 +1,58 @@
+/** @odoo-module */
+import PublicWidget from "@web/legacy/js/public/public_widget";
+import { rpc } from "@web/core/network/rpc";
+import { renderToElement } from "@web/core/utils/render";
+export function _chunk(array, size) {
+ const result = [];
+ for (let i = 0; i < array.length; i += size) {
+ result.push(array.slice(i, i + size));
+ }
+ return result;
+}
+ var RatedProducts = PublicWidget.Widget.extend({
+ selector: '.top_rated_product_snippet',
+ willStart: async function() {
+ var self = this;
+ const data = await rpc('/top_rated_products', {})
+ const [products, categories, website_id, unique_id] = data
+ Object.assign(this, {
+ products, categories, website_id
+ })
+ },
+ start: function () {
+ const refEl = this.$el.find("#top_rated_carousel")
+ const { products, categories, current_website_id, products_list} = this
+ const chunkData = _chunk(products, 4)
+ refEl.html(renderToElement('theme_eco_refine.top_rated_products', {
+ products,
+ categories,
+ current_website_id,
+ products_list,
+ chunkData
+ }))
+ const element = document.body.querySelector("#topRatedCarousel")
+ self.$('.owl-carousel').owlCarousel({
+ loop: true,
+ margin: 10,
+ autoplay: true,
+ nav: true,
+ responsiveClass:true,
+ responsive: {
+ 0: {
+ items: 1,
+ nav:true
+ },
+ 600: {
+ items: 3,
+ nav:true
+ },
+ 1000: {
+ items: 4,
+ nav:true
+ }
+ },
+ });
+ }
+ });
+ PublicWidget.registry.top_rated_product_snippet = RatedProducts;
+ return RatedProducts;
diff --git a/theme_eco_refine/static/src/xml/best_seller_snippet_templates.xml b/theme_eco_refine/static/src/xml/best_seller_snippet_templates.xml
new file mode 100644
index 0000000000..3b2f847190
--- /dev/null
+++ b/theme_eco_refine/static/src/xml/best_seller_snippet_templates.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/xml/new_arrival_snippet_templates.xml b/theme_eco_refine/static/src/xml/new_arrival_snippet_templates.xml
new file mode 100644
index 0000000000..ad3d8551f9
--- /dev/null
+++ b/theme_eco_refine/static/src/xml/new_arrival_snippet_templates.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/static/src/xml/top_rated_product_snippet_templates.xml b/theme_eco_refine/static/src/xml/top_rated_product_snippet_templates.xml
new file mode 100644
index 0000000000..484aead2fc
--- /dev/null
+++ b/theme_eco_refine/static/src/xml/top_rated_product_snippet_templates.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/views/about_us_templates.xml b/theme_eco_refine/views/about_us_templates.xml
new file mode 100755
index 0000000000..fdf64d6733
--- /dev/null
+++ b/theme_eco_refine/views/about_us_templates.xml
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
About ReTech
+
+
+
+
+
+
+
+
Our Mission
+
At Retech, our
+ mission is to provide high-quality
+ refurbished electronics
+ to our customers while
+ promoting sustainability and reducing
+ e-waste. We believe that everyone should
+ have access to affordable
+ technology, and that it shouldn't come at
+ the expense of our environment.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Our Vision
+
We take
+ pre-owned electronic devices and give them
+ new life by restoring
+ them to like-new condition. Our team of
+ expert technicians carefully inspects,
+ cleans, and tests each
+ device to ensure that it meets our strict
+ quality standards. We then offer these
+ devices at a fraction of
+ the cost of new ones, giving our customers
+ a budget-friendly option without
+ compromising on quality.
+
+
+
+
+
+
+
+
+
+
Why Choose Us ?
+
+
+
+
+
+
+ Quality Products
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+ Competitive Pricing
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+ Warranty
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+ Easy Returns
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+ Exchange Policy
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+ Wide Range of Products
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/views/homepage_templates.xml b/theme_eco_refine/views/homepage_templates.xml
new file mode 100755
index 0000000000..2f836ae4a6
--- /dev/null
+++ b/theme_eco_refine/views/homepage_templates.xml
@@ -0,0 +1,704 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Our Mission
+
At Retech, our
+ mission is to provide high-quality
+ refurbished electronics
+ to our customers while
+ promoting sustainability and reducing
+ e-waste. We believe that everyone should
+ have access to affordable
+ technology, and that it shouldn't come at
+ the expense of our environment.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Our Vision
+
We take
+ pre-owned electronic devices and give them
+ new life by restoring
+ them to like-new condition. Our team of
+ expert technicians carefully inspects,
+ cleans, and tests each
+ device to ensure that it meets our strict
+ quality standards. We then offer these
+ devices at a fraction of
+ the cost of new ones, giving our customers
+ a budget-friendly option without
+ compromising on quality.
+
+
+
+
+
+
+
+
+
+
+
+
+
Why Choose Us ?
+
+
+
+
+
+
+ Quality Products
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+ Competitive Pricing
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+ Warranty
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+ Easy Returns
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+ Exchange Policy
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+ Wide Range of Products
+
+
Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry. .
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Our Journey So Far
+
+
+
+
+
+
+
September 07,
+ 2019
+
+
+
+ September 07, 2019
+
+
Over the years, we've grown from a small
+ operation to a company with a global
+ presence. In 2010, we
+ opened our first retail store, and by
+ 2015, we had expanded to four different
+ countries.
+
+
+
+
+
September 07,
+ 2019
+
+
+
+ September 07, 2019
+
+
Over the years, we've grown from a small
+ operation to a company with a global
+ presence. In 2010, we
+ opened our first retail store, and by
+ 2015, we had expanded to four different
+ countries.
+
+
+
+
+
September
+ 07, 2019
+
+
+
+ September 07, 2019
+
+
Over the years, we've grown from a small
+ operation to a company with a global
+ presence. In 2010, we
+ opened our first retail store, and by
+ 2015, we had expanded to four different
+ countries.
+
+
+
+
+
September 07,
+ 2019
+
+
+
+ September 07, 2019
+
+
Over the years, we've grown from a small
+ operation to a company with a global
+ presence. In 2010, we
+ opened our first retail store, and by
+ 2015, we had expanded to four different
+ countries.
+
+
+
+
+
September 08,
+ 2019
+
+
+
+ September 08, 2019
+
+
Over the years, we've grown from a small
+ operation to a company with a global
+ presence. In 2010, we
+ opened our first retail store, and by
+ 2015, we had expanded to four different
+ countries.
+
+
+
+
+
+
+
+
+
+
+
+
+
Join Our Newsletter for Exclusive Deals and
+ Updates
+
+
Stay up-to-date with the latest product
+ releases and exclusive deals by signing up for
+ our
+ newsletter today.
+
+
Sign Up Now
+
+
+
+
+
+
+
+
+
+
+
Shop now and
+ save with our limited time offer prices!
+
+
Sign
+ Now
+
+
+
+
Get your hands on
+ premium gadgets at unbeatable prices today!
+
+
Buy Now
+
+
+
+
+
+
+
+
+
+
+
+
+
+ What Our Customers Say
+
+
+
We take pride
+ in our customer service and here's why
+
+
+
+
+
+
+
+
I was hesitant to buy a refurbished phone,
+ but the quality and customer service
+ exceeded my
+ expectations.
+ I'm so glad I chose this company for my
+ purchase.
+
+
-Tom
+
+
+
+
+
+
+
+
I was hesitant to buy a refurbished phone,
+ but the quality and customer service
+ exceeded my
+ expectations.
+ I'm so glad I chose this company for my
+ purchase.
+
+
-Tom
+
+
+
+
+
+
+
+
+
+
+
+
+ Frequently Asked Questions
+
+
+
+
+
+
+
+ Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry.
+ Lorem Ipsum has been the
+ industry's standard dummy text ever
+ since the 1500s, when an unknown
+ printer took a galley of type
+ and
+ scrambled it to make a type specimen
+ book.Lorem Ipsum is simply dummy text
+ of the printing and
+ typesetting industry. Lorem Ipsum has
+ been the
+ industry's standard dummy text ever
+ since the 1500s, when an unknown
+ printer took a galley of type
+ and
+ scrambled it to make a type specimen
+ book.
+
+
+
+
+
+
+
+ Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry.
+ Lorem Ipsum has been the
+ industry's standard dummy text ever
+ since the 1500s, when an unknown
+ printer took a galley of type
+ and
+ scrambled it to make a type specimen
+ book.
+
+
+
+
+
+
+
+ Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry.
+ Lorem Ipsum has been the
+ industry's standard dummy text ever
+ since the 1500s, when an unknown
+ printer took a galley of type
+ and
+ scrambled it to make a type specimen
+ book.
+
+
+
+
+
+
+
+ Lorem Ipsum is simply dummy text of the
+ printing and typesetting industry.
+ Lorem Ipsum has been the
+ industry's standard dummy text ever
+ since the 1500s, when an unknown
+ printer took a galley of type
+ and
+ scrambled it to make a type specimen
+ book.
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/views/product_template_views.xml b/theme_eco_refine/views/product_template_views.xml
new file mode 100755
index 0000000000..a43c188907
--- /dev/null
+++ b/theme_eco_refine/views/product_template_views.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ product.template.view.form.inherit.theme.refurbished
+
+ product.template
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/views/snippets.xml b/theme_eco_refine/views/snippets.xml
new file mode 100755
index 0000000000..138846978a
--- /dev/null
+++ b/theme_eco_refine/views/snippets.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_eco_refine/views/templates.xml b/theme_eco_refine/views/templates.xml
new file mode 100755
index 0000000000..04fd615c02
--- /dev/null
+++ b/theme_eco_refine/views/templates.xml
@@ -0,0 +1,387 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Get in Touch with Us
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Discover Our Latest
+ Refurbished Products
+
+
+
+
+
+
Product
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Specification
+
+
+ Product detail
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Related
+ Product
+
+
+
+
diff --git a/theme_eco_refine/views/website_blog_templates.xml b/theme_eco_refine/views/website_blog_templates.xml
new file mode 100755
index 0000000000..d748705588
--- /dev/null
+++ b/theme_eco_refine/views/website_blog_templates.xml
@@ -0,0 +1,188 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Blog
+
+
+
+
diff --git a/theme_lego/README.rst b/theme_lego/README.rst
new file mode 100644
index 0000000000..1c21dfbbae
--- /dev/null
+++ b/theme_lego/README.rst
@@ -0,0 +1,49 @@
+.. image:: https://img.shields.io/badge/licence-LGPL--3-blue.svg
+ :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html
+ :alt: License: LGPL-3
+
+Theme Lego
+==========
+* Design Web Pages with Theme Lego
+
+Installation
+============
+ - www.odoo.com/documentation/18.0/setup/install.html
+ - Install our custom addon
+
+License
+-------
+General Public License, Version 3 (LGPL v3).
+(https://www.gnu.org/licenses/lgpl-3.0-standalone.html)
+
+Company
+-------
+* `Cybrosys Techno Solutions `__
+
+Credits
+-------
+* Developer: (V18) Anfas Faisal K
+ (V17) Fouzan M
+ (V16) Sigha CK
+* Contact: odoo@cybrosys.com
+
+Contacts
+--------
+* Mail Contact : odoo@cybrosys.com
+* Website : https://cybrosys.com
+
+Bug Tracker
+-----------
+Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
+
+Maintainer
+==========
+.. image:: https://cybrosys.com/images/logo.png
+ :target: https://cybrosys.com
+This module is maintained by Cybrosys Technologies.
+
+For support and more information, please visit https://www.cybrosys.com
+
+Further information
+===================
+HTML Description: ``__
diff --git a/theme_lego/__init__.py b/theme_lego/__init__.py
new file mode 100644
index 0000000000..5466591d1f
--- /dev/null
+++ b/theme_lego/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys (
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+from . import controllers
+from . import models
diff --git a/theme_lego/__manifest__.py b/theme_lego/__manifest__.py
new file mode 100644
index 0000000000..1be4476bbf
--- /dev/null
+++ b/theme_lego/__manifest__.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys (
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+{
+ 'name': 'Theme Lego',
+ 'version': '18.0.1.0.0',
+ 'category': 'Theme',
+ 'summary': 'Design Web Pages with Theme Lego',
+ 'description': 'Theme Lego is an ideal choice for your Odoo 18.'
+ 'This theme promises to offer a refreshing experience with Odoo,'
+ 'enhancing its functionality and aesthetics."',
+ 'author': 'Cybrosys Techno Solutions',
+ 'company': 'Cybrosys Techno Solutions',
+ 'maintainer': 'Cybrosys Techno Solutions',
+ 'website': "https://www.cybrosys.com",
+ 'depends': ['website_sale_wishlist',
+ 'website_sale_comparison',
+ 'website',
+ 'website_mass_mailing'],
+ 'data': [
+ 'views/footer_templates.xml',
+ 'views/shop_templates.xml',
+ 'views/add_to_cart_templates.xml',
+ 'views/payment_templates.xml',
+ 'views/login_templates.xml',
+ 'views/header_templates.xml',
+ 'views/product_template_views.xml',
+ 'views/snippets/snippet_templates.xml'
+ ],
+ 'assets': {
+ 'web.assets_frontend': [
+ "/theme_lego/static/src/css/owl.carousel.min.css",
+ "/theme_lego/static/src/css/owl.theme.default.min.css",
+ "/theme_lego/static/src/css/style.css",
+ "/theme_lego/static/src/js/owl.carousel.js",
+ "/theme_lego/static/src/js/owl.carousel.min.js",
+ "/theme_lego/static/src/js/index.js",
+ "/theme_lego/static/src/js/deal.js",
+ "/theme_lego/static/src/js/subscription.js",
+ ],
+ 'website.assets_editor': [
+ "/theme_lego/static/src/views/website_preview.xml"
+ ],
+ },
+ 'images': [
+ 'static/description/banner.jpg',
+ 'static/description/theme_screenshot.jpg'
+ ],
+ 'license': 'LGPL-3',
+ 'installable': True,
+ 'auto_install': False,
+ 'application': False,
+}
diff --git a/theme_lego/controllers/__init__.py b/theme_lego/controllers/__init__.py
new file mode 100644
index 0000000000..a58fee32be
--- /dev/null
+++ b/theme_lego/controllers/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys ()
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+from . import theme_lego
+from . import website_sale
diff --git a/theme_lego/controllers/theme_lego.py b/theme_lego/controllers/theme_lego.py
new file mode 100644
index 0000000000..70d1ea2951
--- /dev/null
+++ b/theme_lego/controllers/theme_lego.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys ()
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+from odoo import http
+from odoo.http import request
+
+
+class WebsiteProduct(http.Controller):
+ """
+ HTTP Controller class for handling requests related to the website products.
+ """
+ @http.route('/get_deal_of_the_week', auth="public", type='json')
+ def get_deal_of_the_week(self):
+ """JSON endpoint that fetches the products from the backend marked
+ as 'Deal of the Week'.Returns a rendered HTTP response with the
+ fetched product information."""
+ product_ids = request.env['product.template'].sudo().search([
+ ('deal_check', '=', True)], limit=9)
+ response = http.Response(template='theme_lego.deal_week',
+ qcontext={'product_ids': product_ids})
+ return response.render()
+
+ @http.route('/newsletter_subscription', auth='public', type='json')
+ def newsletter_subscription(self, **kw):
+ """ To save email to a newsletter mail list"""
+ if request.env['mailing.contact'].sudo().search([
+ ("email", "=", kw.get("email")),
+ ("list_ids", "in",
+ [request.env.ref('mass_mailing.mailing_list_data').id])]):
+ return False
+ elif request.env.user._is_public():
+ visitor_sudo = (request.env['website.visitor'].sudo()
+ ._get_visitor_from_request())
+ name = visitor_sudo.display_name if visitor_sudo else \
+ "Website Visitor"
+ else:
+ name = request.env.user.partner_id.name
+ request.env['mailing.contact'].sudo().create({
+ "name": name,
+ "email": kw.get('email'),
+ "list_ids": [request.env.ref(
+ 'mass_mailing.mailing_list_data').id]
+ })
+ return True
diff --git a/theme_lego/controllers/website_sale.py b/theme_lego/controllers/website_sale.py
new file mode 100644
index 0000000000..c6629f534a
--- /dev/null
+++ b/theme_lego/controllers/website_sale.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys ()
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+from odoo import http
+from odoo.addons.payment.controllers import portal as payment_portal
+
+
+class WebsiteSale(payment_portal.PaymentPortal):
+ """
+ HTTP Controller class for handling requests related to the website sale.
+ """
+
+ @http.route(['/shop/cart'], type='http', auth="public", website=True,
+ sitemap=False)
+ def cart(self, **post):
+ """
+ Render the shopping cart page with title 'CHECKOUT' on the banner.
+ """
+ result = super().cart(**post)
+ result.qcontext['title'] = 'CHECKOUT'
+ return result
+
+ @http.route(['/shop/payment'], type='http', auth='public',
+ website=True, sitemap=False)
+ def shop_payment(self, **post):
+ """
+ Render the shopping cart page with title 'CONFIRMATION' on the banner.
+ """
+ result = super().shop_payment(**post)
+ result.qcontext['title'] = 'CONFIRMATION'
+ return result
+
+ @http.route(['/shop/checkout'], type='http', auth="public",
+ website=True, sitemap=False)
+ def shop_checkout(self, **post):
+ """
+ Render the address page with title 'SHIPPING' on the banner.
+ """
+ result = super().shop_checkout(**post)
+ result.qcontext['title'] = 'SHIPPING'
+ return result
diff --git a/theme_lego/doc/RELEASE_NOTES.md b/theme_lego/doc/RELEASE_NOTES.md
new file mode 100644
index 0000000000..586f179de1
--- /dev/null
+++ b/theme_lego/doc/RELEASE_NOTES.md
@@ -0,0 +1,6 @@
+## Module
+
+#### 11.09.2025
+#### Version 18.0.1.0.0
+#### ADD
+- Initial commit for Theme Lego
diff --git a/theme_lego/models/__init__.py b/theme_lego/models/__init__.py
new file mode 100644
index 0000000000..931224e085
--- /dev/null
+++ b/theme_lego/models/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys (
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+from . import product_template
+from . import theme_utils
diff --git a/theme_lego/models/product_template.py b/theme_lego/models/product_template.py
new file mode 100644
index 0000000000..d290df6a69
--- /dev/null
+++ b/theme_lego/models/product_template.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys (
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+from odoo import fields, models
+
+
+class ProductTemplate(models.Model):
+ """
+ Inherited model for the 'product.template' class. Adds a new boolean
+ field named 'deal_check', which enables the 'Deal of the Week' feature.
+ """
+ _inherit = "product.template"
+
+ deal_check = fields.Boolean(string="Deal of the Week",
+ help="Enable the deal of the week")
diff --git a/theme_lego/models/theme_utils.py b/theme_lego/models/theme_utils.py
new file mode 100644
index 0000000000..bac58fdef0
--- /dev/null
+++ b/theme_lego/models/theme_utils.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys (
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+from odoo import models
+
+
+class ThemeLego(models.AbstractModel):
+ """ Abstract model that serves as the base class for the website header.
+ It inherits from the 'theme.utils' class."""
+ _inherit = 'theme.utils'
+
+ def _theme_lego_post_copy(self, mod):
+ """ It enables the default website header view,
+ which is responsible for showing the header of the website """
+ self.enable_view('theme_lego.template_header_default_inherited')
diff --git a/theme_lego/static/description/banner.jpg b/theme_lego/static/description/banner.jpg
new file mode 100644
index 0000000000..4ed0306134
Binary files /dev/null and b/theme_lego/static/description/banner.jpg differ
diff --git a/theme_lego/static/description/icon.png b/theme_lego/static/description/icon.png
new file mode 100644
index 0000000000..59528f918e
Binary files /dev/null and b/theme_lego/static/description/icon.png differ
diff --git a/theme_lego/static/description/img/1.jpg b/theme_lego/static/description/img/1.jpg
new file mode 100644
index 0000000000..0a1258e2f6
Binary files /dev/null and b/theme_lego/static/description/img/1.jpg differ
diff --git a/theme_lego/static/description/img/2.jpg b/theme_lego/static/description/img/2.jpg
new file mode 100644
index 0000000000..2710682089
Binary files /dev/null and b/theme_lego/static/description/img/2.jpg differ
diff --git a/theme_lego/static/description/img/3.jpg b/theme_lego/static/description/img/3.jpg
new file mode 100644
index 0000000000..ce0890b2f3
Binary files /dev/null and b/theme_lego/static/description/img/3.jpg differ
diff --git a/theme_lego/static/description/img/4.jpg b/theme_lego/static/description/img/4.jpg
new file mode 100644
index 0000000000..54fca9f376
Binary files /dev/null and b/theme_lego/static/description/img/4.jpg differ
diff --git a/theme_lego/static/description/img/5.png b/theme_lego/static/description/img/5.png
new file mode 100644
index 0000000000..571320a1e1
Binary files /dev/null and b/theme_lego/static/description/img/5.png differ
diff --git a/theme_lego/static/description/img/6.png b/theme_lego/static/description/img/6.png
new file mode 100644
index 0000000000..d350a8a29c
Binary files /dev/null and b/theme_lego/static/description/img/6.png differ
diff --git a/theme_lego/static/description/img/Cart.png b/theme_lego/static/description/img/Cart.png
new file mode 100644
index 0000000000..33100ea569
Binary files /dev/null and b/theme_lego/static/description/img/Cart.png differ
diff --git a/theme_lego/static/description/img/arrows-repeat.svg b/theme_lego/static/description/img/arrows-repeat.svg
new file mode 100644
index 0000000000..94fb8f7f90
--- /dev/null
+++ b/theme_lego/static/description/img/arrows-repeat.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/banner-bg-1.svg b/theme_lego/static/description/img/banner-bg-1.svg
new file mode 100644
index 0000000000..7af9bab87d
--- /dev/null
+++ b/theme_lego/static/description/img/banner-bg-1.svg
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/banner.jpg b/theme_lego/static/description/img/banner.jpg
new file mode 100644
index 0000000000..4ed0306134
Binary files /dev/null and b/theme_lego/static/description/img/banner.jpg differ
diff --git a/theme_lego/static/description/img/banner.svg b/theme_lego/static/description/img/banner.svg
new file mode 100644
index 0000000000..3d4ed7a4ab
--- /dev/null
+++ b/theme_lego/static/description/img/banner.svg
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/check.svg b/theme_lego/static/description/img/check.svg
new file mode 100644
index 0000000000..8bc79333dc
--- /dev/null
+++ b/theme_lego/static/description/img/check.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/confirmation.png b/theme_lego/static/description/img/confirmation.png
new file mode 100644
index 0000000000..af0752e2cf
Binary files /dev/null and b/theme_lego/static/description/img/confirmation.png differ
diff --git a/theme_lego/static/description/img/contact.png b/theme_lego/static/description/img/contact.png
new file mode 100644
index 0000000000..19839ee1e9
Binary files /dev/null and b/theme_lego/static/description/img/contact.png differ
diff --git a/theme_lego/static/description/img/demo-1.jpg b/theme_lego/static/description/img/demo-1.jpg
new file mode 100644
index 0000000000..f86f96819e
Binary files /dev/null and b/theme_lego/static/description/img/demo-1.jpg differ
diff --git a/theme_lego/static/description/img/demo-2.jpg b/theme_lego/static/description/img/demo-2.jpg
new file mode 100644
index 0000000000..7cb4db3ede
Binary files /dev/null and b/theme_lego/static/description/img/demo-2.jpg differ
diff --git a/theme_lego/static/description/img/demo-3.jpg b/theme_lego/static/description/img/demo-3.jpg
new file mode 100644
index 0000000000..1ac61ab441
Binary files /dev/null and b/theme_lego/static/description/img/demo-3.jpg differ
diff --git a/theme_lego/static/description/img/feature-star.svg b/theme_lego/static/description/img/feature-star.svg
new file mode 100644
index 0000000000..a913270e8e
--- /dev/null
+++ b/theme_lego/static/description/img/feature-star.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/gear.svg b/theme_lego/static/description/img/gear.svg
new file mode 100644
index 0000000000..ce383059da
--- /dev/null
+++ b/theme_lego/static/description/img/gear.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/hero.gif b/theme_lego/static/description/img/hero.gif
new file mode 100644
index 0000000000..ebdacb8d96
Binary files /dev/null and b/theme_lego/static/description/img/hero.gif differ
diff --git a/theme_lego/static/description/img/hire-odoo.svg b/theme_lego/static/description/img/hire-odoo.svg
new file mode 100644
index 0000000000..9cfec4e447
--- /dev/null
+++ b/theme_lego/static/description/img/hire-odoo.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/img_shop.png b/theme_lego/static/description/img/img_shop.png
new file mode 100644
index 0000000000..ecf12a9605
Binary files /dev/null and b/theme_lego/static/description/img/img_shop.png differ
diff --git a/theme_lego/static/description/img/laptop-screenshots.jpg b/theme_lego/static/description/img/laptop-screenshots.jpg
new file mode 100644
index 0000000000..a40a6d9616
Binary files /dev/null and b/theme_lego/static/description/img/laptop-screenshots.jpg differ
diff --git a/theme_lego/static/description/img/lego_1.png b/theme_lego/static/description/img/lego_1.png
new file mode 100644
index 0000000000..4e2397d437
Binary files /dev/null and b/theme_lego/static/description/img/lego_1.png differ
diff --git a/theme_lego/static/description/img/life-ring-icon.svg b/theme_lego/static/description/img/life-ring-icon.svg
new file mode 100644
index 0000000000..b6c797ba14
--- /dev/null
+++ b/theme_lego/static/description/img/life-ring-icon.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/odoo-consultancy.svg b/theme_lego/static/description/img/odoo-consultancy.svg
new file mode 100644
index 0000000000..c2c27e6083
--- /dev/null
+++ b/theme_lego/static/description/img/odoo-consultancy.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/theme_lego/static/description/img/odoo-licencing.svg b/theme_lego/static/description/img/odoo-licencing.svg
new file mode 100644
index 0000000000..8a520b40f1
--- /dev/null
+++ b/theme_lego/static/description/img/odoo-licencing.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_lego/static/description/img/patter.svg b/theme_lego/static/description/img/patter.svg
new file mode 100644
index 0000000000..9b7b0d7cda
--- /dev/null
+++ b/theme_lego/static/description/img/patter.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/phone-screenshots.jpg b/theme_lego/static/description/img/phone-screenshots.jpg
new file mode 100644
index 0000000000..9250d77bf9
Binary files /dev/null and b/theme_lego/static/description/img/phone-screenshots.jpg differ
diff --git a/theme_lego/static/description/img/product_preview.png b/theme_lego/static/description/img/product_preview.png
new file mode 100644
index 0000000000..4b338ac282
Binary files /dev/null and b/theme_lego/static/description/img/product_preview.png differ
diff --git a/theme_lego/static/description/img/puzzle-piece-icon.svg b/theme_lego/static/description/img/puzzle-piece-icon.svg
new file mode 100644
index 0000000000..ab5e56fa7b
--- /dev/null
+++ b/theme_lego/static/description/img/puzzle-piece-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/screenshot-1.svg b/theme_lego/static/description/img/screenshot-1.svg
new file mode 100644
index 0000000000..72eeb921b4
--- /dev/null
+++ b/theme_lego/static/description/img/screenshot-1.svg
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/screenshot-2.png b/theme_lego/static/description/img/screenshot-2.png
new file mode 100644
index 0000000000..e13b876da6
Binary files /dev/null and b/theme_lego/static/description/img/screenshot-2.png differ
diff --git a/theme_lego/static/description/img/screenshot-3.png b/theme_lego/static/description/img/screenshot-3.png
new file mode 100644
index 0000000000..be1acdfd51
Binary files /dev/null and b/theme_lego/static/description/img/screenshot-3.png differ
diff --git a/theme_lego/static/description/img/screenshot-4.png b/theme_lego/static/description/img/screenshot-4.png
new file mode 100644
index 0000000000..1d01e11fc7
Binary files /dev/null and b/theme_lego/static/description/img/screenshot-4.png differ
diff --git a/theme_lego/static/description/img/screenshot-5.svg b/theme_lego/static/description/img/screenshot-5.svg
new file mode 100644
index 0000000000..923e355bf9
--- /dev/null
+++ b/theme_lego/static/description/img/screenshot-5.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/screenshot-img.png b/theme_lego/static/description/img/screenshot-img.png
new file mode 100644
index 0000000000..a425d9ede9
Binary files /dev/null and b/theme_lego/static/description/img/screenshot-img.png differ
diff --git a/theme_lego/static/description/img/screenshot-main.png b/theme_lego/static/description/img/screenshot-main.png
new file mode 100644
index 0000000000..575f8e676b
Binary files /dev/null and b/theme_lego/static/description/img/screenshot-main.png differ
diff --git a/theme_lego/static/description/img/shop.png b/theme_lego/static/description/img/shop.png
new file mode 100644
index 0000000000..db0f9e2eb0
Binary files /dev/null and b/theme_lego/static/description/img/shop.png differ
diff --git a/theme_lego/static/description/img/translate.svg b/theme_lego/static/description/img/translate.svg
new file mode 100644
index 0000000000..eea7295427
--- /dev/null
+++ b/theme_lego/static/description/img/translate.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/img/wrench-icon.svg b/theme_lego/static/description/img/wrench-icon.svg
new file mode 100644
index 0000000000..4e0ce1d016
--- /dev/null
+++ b/theme_lego/static/description/img/wrench-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/static/description/index.html b/theme_lego/static/description/index.html
new file mode 100644
index 0000000000..c9fc0bc376
--- /dev/null
+++ b/theme_lego/static/description/index.html
@@ -0,0 +1,662 @@
+
+
+
+
+
+
+ app index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Supports:
+
+ Community
+
+
+ Enterprise
+
+
+
+
+
+
Availability:
+
+ Odoo Online
+
+
+ Odoo.sh
+
+
+ On Premise
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Theme Features
+
+
+
+
+
HIGHLIGHT
+
Mobile View
+
User-friendly and modern looking theme makes your page more Stylish And
+ Beautiful
+
+
+
+
+
+
+
+
+
+
+
+
+
+
HIGHLIGHT
+
Desktop View
+
It is easy to customize and use. Just drag and drop the building blocks to
+ make attractive webpages. webpages.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
HIGHLIGHT
+
Home Page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
HIGHLIGHT
+
Product View
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
HIGHLIGHT
+
Confirmation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fully Responsive
+ Layout.
+
+
+
+
Our design are now fully responsive, enabling you to view and manage everything from
+ the comfort of your mobile device. Everything has been designed in a meticulous
+ fashion so that
+ every view snaps itself to fit the size of the device you are using, be it
+ smartphones, tablet
+ or any other portables, our theme adjusts itself to fit the screen size.
+
+ .
+
+ Fully responsive
+ Fits perfectly to all screen sizes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/theme_lego/static/description/theme_screenshot.jpg b/theme_lego/static/description/theme_screenshot.jpg
new file mode 100644
index 0000000000..bde56fed86
Binary files /dev/null and b/theme_lego/static/description/theme_screenshot.jpg differ
diff --git a/theme_lego/static/src/css/owl.carousel.min.css b/theme_lego/static/src/css/owl.carousel.min.css
new file mode 100644
index 0000000000..0b2a5f38bc
--- /dev/null
+++ b/theme_lego/static/src/css/owl.carousel.min.css
@@ -0,0 +1,6 @@
+/**
+ * Owl Carousel v2.3.4
+ * Copyright 2013-2018 David Deutsch
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
+ */
+.owl-carousel,.owl-carousel .owl-item{-webkit-tap-highlight-color:transparent;position:relative}.owl-carousel{display:none;width:100%;z-index:1}.owl-carousel .owl-stage{position:relative;-ms-touch-action:pan-Y;touch-action:manipulation;-moz-backface-visibility:hidden}.owl-carousel .owl-stage:after{content:".";display:block;clear:both;visibility:hidden;line-height:0;height:0}.owl-carousel .owl-stage-outer{position:relative;overflow:hidden;-webkit-transform:translate3d(0,0,0)}.owl-carousel .owl-item,.owl-carousel .owl-wrapper{-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0)}.owl-carousel .owl-item{min-height:1px;float:left;-webkit-backface-visibility:hidden;-webkit-touch-callout:none}.owl-carousel .owl-item img{display:block;width:100%}.owl-carousel .owl-dots,.owl-carousel .owl-nav.disabled{display:none}.no-js .owl-carousel,.owl-carousel.owl-loaded{display:block}.owl-carousel .owl-dot,.owl-carousel .owl-nav .owl-next,.owl-carousel .owl-nav .owl-prev{cursor:pointer;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.owl-carousel .owl-nav button.owl-next,.owl-carousel .owl-nav button.owl-prev,.owl-carousel button.owl-dot{background:0 0;color:inherit;border:none;padding:0!important;font:inherit}.owl-carousel.owl-loading{opacity:0;display:block}.owl-carousel.owl-hidden{opacity:0}.owl-carousel.owl-refresh .owl-item{visibility:hidden}.owl-carousel.owl-drag .owl-item{-ms-touch-action:pan-y;touch-action:pan-y;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.owl-carousel.owl-grab{cursor:move;cursor:grab}.owl-carousel.owl-rtl{direction:rtl}.owl-carousel.owl-rtl .owl-item{float:right}.owl-carousel .animated{animation-duration:1s;animation-fill-mode:both}.owl-carousel .owl-animated-in{z-index:0}.owl-carousel .owl-animated-out{z-index:1}.owl-carousel .fadeOut{animation-name:fadeOut}@keyframes fadeOut{0%{opacity:1}100%{opacity:0}}.owl-height{transition:height .5s ease-in-out}.owl-carousel .owl-item .owl-lazy{opacity:0;transition:opacity .4s ease}.owl-carousel .owl-item .owl-lazy:not([src]),.owl-carousel .owl-item .owl-lazy[src^=""]{max-height:0}.owl-carousel .owl-item img.owl-lazy{transform-style:preserve-3d}.owl-carousel .owl-video-wrapper{position:relative;height:100%;background:#000}.owl-carousel .owl-video-play-icon{position:absolute;height:80px;width:80px;left:50%;top:50%;margin-left:-40px;margin-top:-40px;background:url(owl.video.play.png) no-repeat;cursor:pointer;z-index:1;-webkit-backface-visibility:hidden;transition:transform .1s ease}.owl-carousel .owl-video-play-icon:hover{-ms-transform:scale(1.3,1.3);transform:scale(1.3,1.3)}.owl-carousel .owl-video-playing .owl-video-play-icon,.owl-carousel .owl-video-playing .owl-video-tn{display:none}.owl-carousel .owl-video-tn{opacity:0;height:100%;background-position:center center;background-repeat:no-repeat;background-size:contain;transition:opacity .4s ease}.owl-carousel .owl-video-frame{position:relative;z-index:1;height:100%;width:100%}
\ No newline at end of file
diff --git a/theme_lego/static/src/css/owl.theme.default.min.css b/theme_lego/static/src/css/owl.theme.default.min.css
new file mode 100644
index 0000000000..487088d2e3
--- /dev/null
+++ b/theme_lego/static/src/css/owl.theme.default.min.css
@@ -0,0 +1,6 @@
+/**
+ * Owl Carousel v2.3.4
+ * Copyright 2013-2018 David Deutsch
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
+ */
+.owl-theme .owl-dots,.owl-theme .owl-nav{text-align:center;-webkit-tap-highlight-color:transparent}.owl-theme .owl-nav{margin-top:10px}.owl-theme .owl-nav [class*=owl-]{color:#FFF;font-size:14px;margin:5px;padding:4px 7px;background:#D6D6D6;display:inline-block;cursor:pointer;border-radius:3px}.owl-theme .owl-nav [class*=owl-]:hover{background:#869791;color:#FFF;text-decoration:none}.owl-theme .owl-nav .disabled{opacity:.5;cursor:default}.owl-theme .owl-nav.disabled+.owl-dots{margin-top:10px}.owl-theme .owl-dots .owl-dot{display:inline-block;zoom:1}.owl-theme .owl-dots .owl-dot span{width:10px;height:10px;margin:5px 7px;background:#D6D6D6;display:block;-webkit-backface-visibility:visible;transition:opacity .2s ease;border-radius:30px}.owl-theme .owl-dots .owl-dot.active span,.owl-theme .owl-dots .owl-dot:hover span{background:#869791}
\ No newline at end of file
diff --git a/theme_lego/static/src/css/style.css b/theme_lego/static/src/css/style.css
new file mode 100644
index 0000000000..7b6f3031ec
--- /dev/null
+++ b/theme_lego/static/src/css/style.css
@@ -0,0 +1,3545 @@
+
+
+/*@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800&family=Roboto&display=swap");
+*/
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+/* Document
+ ========================================================================== */
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+html {
+ line-height: 1.15;
+ /* 1 */
+ -webkit-text-size-adjust: 100%;
+ /* 2 */
+}
+
+/* Sections
+ ========================================================================== */
+/**
+ * Remove the margin in all browsers.
+ */
+body {
+ margin: 0;
+}
+
+/**
+ * Render the `main` element consistently in IE.
+ */
+main {
+ display: block;
+}
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/* Grouping content
+ ========================================================================== */
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+hr {
+ box-sizing: content-box;
+ /* 1 */
+ height: 0;
+ /* 1 */
+ overflow: visible;
+ /* 2 */
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+pre {
+ font-family: monospace, monospace;
+ /* 1 */
+ font-size: 1em;
+ /* 2 */
+}
+
+
+
+/* Text-level semantics
+ ========================================================================== */
+/**
+ * Remove the gray background on active links in IE 10.
+ */
+a {
+ background-color: transparent;
+}
+
+/**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+abbr[title] {
+ border-bottom: none;
+ /* 1 */
+ text-decoration: underline;
+ /* 2 */
+ text-decoration: underline dotted;
+ /* 2 */
+}
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+b,
+strong {
+ font-weight: bolder;
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+code,
+kbd,
+samp {
+ font-family: monospace, monospace;
+ /* 1 */
+ font-size: 1em;
+ /* 2 */
+}
+
+/**
+ * Add the correct font size in all browsers.
+ */
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/* Embedded content
+ ========================================================================== */
+/**
+ * Remove the border on images inside links in IE 10.
+ */
+img {
+ border-style: none;
+}
+
+/* Forms
+ ========================================================================== */
+/**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit;
+ /* 1 */
+ font-size: 100%;
+ /* 1 */
+ line-height: 1.15;
+ /* 1 */
+ margin: 0;
+ /* 2 */
+}
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+button,
+input {
+ /* 1 */
+ overflow: visible;
+}
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+button,
+select {
+ /* 1 */
+ text-transform: none;
+}
+
+/**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button;
+}
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+}
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+ outline: 1px dotted ButtonText;
+}
+
+/**
+ * Correct the padding in Firefox.
+ */
+fieldset {
+ padding: 0.35em 0.75em 0.625em;
+}
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ * `fieldset` elements in all browsers.
+ */
+legend {
+ box-sizing: border-box;
+ /* 1 */
+ color: inherit;
+ /* 2 */
+ display: table;
+ /* 1 */
+ max-width: 100%;
+ /* 1 */
+ padding: 0;
+ /* 3 */
+ white-space: normal;
+ /* 1 */
+}
+
+/**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+progress {
+ vertical-align: baseline;
+}
+
+/**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+textarea {
+ overflow: auto;
+}
+
+/**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+[type="checkbox"],
+[type="radio"] {
+ box-sizing: border-box;
+ /* 1 */
+ padding: 0;
+ /* 2 */
+}
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+[type="search"] {
+ -webkit-appearance: textfield;
+ /* 1 */
+ outline-offset: -2px;
+ /* 2 */
+}
+
+/**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+::-webkit-file-upload-button {
+ -webkit-appearance: button;
+ /* 1 */
+ font: inherit;
+ /* 2 */
+}
+
+/* Interactive
+ ========================================================================== */
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+details {
+ display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+summary {
+ display: list-item;
+}
+
+/* Misc
+ ========================================================================== */
+/**
+ * Add the correct display in IE 10+.
+ */
+template {
+ display: none;
+}
+
+/**
+ * Add the correct display in IE 10.
+ */
+[hidden] {
+ display: none;
+}
+
+*body {
+ line-height: 24px;
+ font-size: 14px;
+ font-weight: 400;
+ color: #777777;
+ background: #fff;
+}
+
+html,
+body {
+ height: 100%;
+}
+
+ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+*h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: "Poppins", sans-serif;
+ color: #222222;
+ font-weight: 500;
+ line-height: 1.2 !important;
+}
+
+.list {
+ list-style: none;
+ margin: 0px;
+ padding: 0px;
+}
+
+*a {
+ text-decoration: none;
+ transition: all 0.3s ease-in-out;
+}
+
+*a:hover, *a:focus {
+ text-decoration: none;
+ outline: none;
+}
+
+*button:focus {
+ outline: none;
+ box-shadow: none;
+}
+
+.overflow-hidden {
+ overflow: hidden;
+}
+
+*:focus {
+ outline: 0 !important;
+}
+
+*button:focus {
+ border: none;
+ outline: none;
+}
+
+* {
+ list-style-type: none;
+ font-family: "Poppins", sans-serif;
+ font-size: 14px;
+}
+
+*:focus, *:active {
+ outline: none !important;
+}
+
+*:hover {
+ transition: 0.5s;
+}
+
+.banner {
+ background-image: url(./../img/banner/banner-bg.jpg);
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: cover;
+ position: relative;
+}
+
+.banner .banner_content {
+ position: relative;
+ padding-top: 250px;
+ padding-bottom: 150px;
+}
+
+@media screen and (max-width: 996px) {
+ .banner .banner_content {
+ padding-top: 220px;
+ padding-bottom: 75px;
+ }
+}
+
+.banner .banner_content .banner_left h1 {
+ font-size: 50px;
+ font-weight: 700;
+ text-transform: uppercase;
+ color: #fff;
+}
+
+@media screen and (max-width: 1100px) {
+ .banner .banner_content .banner_left h1 {
+ font-size: 40px;
+ }
+}
+
+@media screen and (max-width: 996px) {
+ .banner .banner_content .banner_left h1 {
+ font-size: 30px;
+ }
+}
+
+.banner .banner_content .banner_left p {
+ color: #fff;
+ line-height: 24px;
+ margin-bottom: 33px;
+}
+
+@media screen and (max-width: 786px) {
+ .banner .banner_content .banner_img {
+ display: none;
+ }
+}
+
+.banner .banner_content .banner_img img {
+ width: 100%;
+}
+
+.banner .banner_content .owl-carousel {
+ position: relative;
+}
+
+.banner .banner_content .owl-carousel .owl-nav {
+ position: absolute;
+ right: 50px;
+ bottom: 12px;
+}
+
+.banner .banner_content .owl-carousel .owl-nav .owl-prev {
+ color: #fff;
+}
+
+.banner .banner_content .owl-carousel .owl-nav .owl-prev:hover {
+ color: #000;
+}
+
+.banner .banner_content .owl-carousel .owl-nav .owl-prev i {
+ font-size: 27px;
+ padding: 10px;
+}
+
+.banner .banner_content .owl-carousel .owl-nav .owl-next {
+ color: #fff;
+}
+
+.banner .banner_content .owl-carousel .owl-nav .owl-next:hover {
+ color: #000;
+}
+
+.banner .banner_content .owl-carousel .owl-nav .owl-next i {
+ font-size: 27px;
+}
+
+.banner_product {
+ background-image: url(./../img/banner/banner-bg.jpg);
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: cover;
+ position: relative;
+}
+
+.banner_product .banner_content {
+ text-align: end;
+ padding-top: 180px;
+}
+
+.banner_product .banner_content .product_heading h1 {
+ color: #000;
+ text-transform: uppercase;
+ font-size: 50px;
+ font-weight: 700;
+ color: #fff;
+}
+
+@media screen and (max-width: 768px) {
+ .banner_product .banner_content .product_heading h1 {
+ font-size: 40px;
+ }
+}
+
+@media screen and (max-width: 600px) {
+ .banner_product .banner_content .product_heading h1 {
+ font-size: 25px;
+ text-align: left;
+ }
+}
+
+.banner_product .banner_content .product_heading .breadcrumb {
+ background-color: transparent;
+ justify-content: end;
+}
+
+@media screen and (max-width: 600px) {
+ .banner_product .banner_content .product_heading .breadcrumb {
+ justify-content: left;
+ padding-left: 0;
+ }
+}
+
+.banner_product .banner_content .product_heading .breadcrumb .active {
+ color: #000;
+}
+
+.banner_product .banner_content .product_heading .breadcrumb .breadcrumb-item a {
+ color: #fff;
+ text-decoration: none;
+}
+
+.banner_product .banner_content .product_heading .breadcrumb .breadcrumb-item:before {
+ display: inline-block;
+ padding-right: 0.5rem;
+ color: #1b80da;
+ content: "";
+}
+
+.banner_product .banner_content .product_heading .breadcrumb .breadcrumb-item .material-icons {
+ padding-top: 6px;
+ padding-left: 3px;
+}
+
+.btn {
+ border: none !important;
+ outline: 0 !important;
+ transition: 0.5s;
+ box-shadow: none !important;
+}
+
+.btn-primary {
+ background-color: transparent !important;
+ border-color: #fff;
+ padding: 12px 36px;
+ color: #000 !important;
+ font-size: 16px;
+ font-weight: 600;
+ border-radius: 0;
+ border: 1px solid !important;
+}
+
+.btn-primary:hover {
+ border: none !important;
+ color: #000 !important;
+ background: #fff !important;
+}
+
+.btn-add {
+ text-transform: uppercase !important;
+ font-size: 14px;
+ font-weight: 600;
+ color: #222222;
+ display: flex;
+ color: #fff;
+ align-items: center;
+ text-decoration: none !important;
+}
+
+.btn-add:hover {
+ color: #ff6c00;
+}
+
+.btn-add i {
+ height: 45px;
+ width: 45px;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ color: white !important;
+ border-radius: 50%;
+ padding: 12px;
+ margin-right: 13px;
+}
+
+.btn-add2 {
+ text-transform: uppercase !important;
+ font-size: 14px;
+ font-weight: 600;
+ color: #222222;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ text-decoration: none !important;
+}
+
+.btn-add2:hover {
+ color: #222222;
+}
+
+.btn-add2 i {
+ height: 45px;
+ width: 45px;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ color: #fff !important;
+ border-radius: 50%;
+ padding: 12px;
+ margin-right: 13px;
+ color: #222222 !important;
+}
+
+.btn-add2 i:hover {
+ background-image: linear-gradient(45deg, #22c1c3 0%, #e0d8d8 60%);
+}
+
+.btn-shop {
+ color: #222222;
+ display: block;
+ position: absolute;
+ z-index: 2;
+ left: 41%;
+ top: 62%;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ padding: 14px 27px;
+ font-weight: 600;
+ border-radius: 25px;
+}
+
+@media screen and (max-width: 996px) {
+ .btn-shop {
+ top: 75%;
+ }
+}
+
+.btn-shop:hover {
+ text-decoration: none;
+ color: #222222;
+}
+
+.btn-cart {
+ color: #fff;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ padding: 14px 35px;
+ font-weight: 600;
+ border-radius: 6px;
+ box-shadow: none !important;
+}
+
+.btn-cart:hover {
+ text-decoration: none;
+ color: #fff;
+}
+
+.btn-replay {
+ color: #000;
+ border: 1px solid !important;
+ border-radius: 25px;
+ border-color: #777777 !important;
+ padding: 5px 15px;
+ box-shadow: none !important;
+}
+
+.btn-replay:hover {
+ text-decoration: none;
+ color: #fff;
+ background-color: #00c2fb !important;
+ border: none !important;
+}
+
+.btn-login {
+ color: #fff;
+ border-radius: 0px;
+ background-color: #00c2fb !important;
+ padding: 8px 22px;
+ box-shadow: none !important;
+ border-radius: 5px;
+ font-weight: 600;
+}
+
+.btn-login:hover {
+ text-decoration: none;
+ color: #fff;
+ border: none !important;
+}
+
+.btn-checkout_c {
+ text-transform: uppercase !important;
+ font-size: 14px;
+ font-weight: 600;
+ color: #fff;
+ height: 50px;
+ padding-top: 15px;
+ display: block;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ text-decoration: none !important;
+}
+
+.btn-checkout_c:hover {
+ color: #fff;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+}
+
+.btn-update {
+ background-color: #acdfee99 !important;
+ padding: 12px 36px;
+ color: #000 !important;
+ font-size: 16px;
+ border-radius: 0;
+}
+
+.btn-update:hover {
+ border: none !important;
+ color: #000 !important;
+}
+
+.btn-update2 {
+ background-color: #acdfee99 !important;
+ display: block;
+ padding: 12px 36px;
+ color: #000 !important;
+ font-size: 16px;
+ border-radius: 0;
+}
+
+.btn-update2:hover {
+ border: none !important;
+ color: #000 !important;
+}
+
+.btn-cartc {
+ color: #fff;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ padding: 14px 35px;
+ font-weight: 600;
+ box-shadow: none !important;
+}
+
+.btn-cartc:hover {
+ text-decoration: none;
+ color: #fff;
+}
+
+@media screen and (max-width: 474px) {
+ .btn-cartc {
+ margin-bottom: 15px;
+ padding: 14px 38px;
+ }
+}
+
+.btn-cartd {
+ color: #fff;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ padding: 14px 28px;
+ font-weight: 600;
+ box-shadow: none !important;
+}
+
+.btn-cartd:hover {
+ text-decoration: none;
+ color: #fff;
+}
+
+.btn-register {
+ color: #fff;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ padding: 14px 28px;
+ font-weight: 600;
+ box-shadow: none !important;
+ border-radius: 0 !important;
+}
+
+.btn-register:hover {
+ text-decoration: none;
+ color: #fff;
+}
+
+.btn-login {
+ color: #fff;
+ display: block;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ padding: 14px 28px;
+ font-weight: 600;
+ box-shadow: none !important;
+ border-radius: 0 !important;
+}
+
+.btn-login:hover {
+ text-decoration: none;
+ color: #fff;
+}
+
+.btn-send {
+ background-color: #00c2fb !important;
+ border-color: #fff;
+ padding: 8px 40px;
+ color: #fff !important;
+ font-size: 16px;
+ border-radius: 0;
+ margin-top: 31px;
+ margin-left: auto;
+ margin-right: 16px;
+}
+
+.btn-send:hover {
+ border: none !important;
+ background: #00aee2 !important;
+}
+
+.product {
+ margin-top: 100px;
+}
+
+.product .main_heading {
+ text-align: center;
+ padding-bottom: 10px;
+}
+
+.product .main_heading h3 {
+ font-size: 25px;
+ font-weight: 600;
+ text-transform: uppercase;
+ font-family: "Poppins", sans-serif;
+ color: #222222;
+}
+
+.product .main_heading p {
+ color: #777777;
+ line-height: 24px;
+ margin-bottom: 33px;
+}
+
+.product .wrapper {
+ margin-top: 40px;
+}
+
+.product .wrapper .product_img {
+ margin-bottom: 50px;
+}
+
+@media screen and (max-width: 576px) {
+ .product .wrapper .product_img {
+ margin: 0 10px;
+ padding-bottom: 30px;
+ }
+}
+
+.product .wrapper .product_img .wrapper_img {
+ padding-bottom: 15px;
+}
+
+.product .wrapper .product_img .wrapper_img img {
+ width: 100%;
+}
+
+.product .wrapper .product_img h5 {
+ color: #222222;
+ text-transform: uppercase;
+ font-weight: 600;
+ margin-top: 15px;
+ font-family: "Poppins", sans-serif;
+}
+
+.product .wrapper .product_img .rate {
+ display: flex;
+ padding-top: 10px;
+}
+
+.product .wrapper .product_img .rate p {
+ color: #222222;
+ margin-right: 50px;
+}
+
+.product .wrapper .product_img .rate span {
+ color: #777777;
+ text-decoration: line-through;
+}
+
+.product .wrapper .product_img .product_bottom {
+ display: flex;
+ padding-left: 0;
+ position: relative;
+}
+
+.product .wrapper .product_img .product_bottom li {
+ height: 35px;
+ width: 35px;
+ border-radius: 50%;
+ background-color: #fc5205;
+ margin-right: 12px;
+}
+
+.product .wrapper .product_img .product_bottom a {
+ color: #fff;
+}
+
+.product .wrapper .product_img .product_bottom a span {
+ padding: 11px;
+}
+
+.main_heading {
+ text-align: center;
+ padding-bottom: 10px;
+}
+
+.main_heading h3 {
+ font-size: 25px;
+ font-weight: 600;
+ text-transform: uppercase;
+ font-family: "Poppins", sans-serif;
+ color: #222222;
+}
+
+.main_heading p {
+ color: #777777;
+ line-height: 24px;
+ margin-bottom: 33px;
+}
+
+.fixed-top {
+ position: unset;
+ top: 30px;
+ transition: all 0.3s ease 0s;
+ background: #fff;
+ left: 2.5%;
+ width: 95%;
+ padding: 20px 0;
+}
+
+.navbar-dark {
+ color: #000;
+}
+
+.navbar-dark #top_menu_collapse {
+ margin: 0px auto 0;
+ display: flex;
+}
+
+.navbar-dark .navbar-toggler {
+ background-color: #00c2fb;
+ color: #fff;
+}
+
+@media screen and (max-width: 610px) {
+ .navbar-dark #top_menu_collapse .navbar-toggler {
+ margin-right: 20px;
+ }
+}
+
+.navbar-dark .navbar-brand {
+ color: #00c2fb;
+ font-family: "Poppins", sans-serif;
+ font-size: 30px;
+ font-weight: 600;
+ letter-spacing: 2px;
+ padding-left: 10px;
+}
+
+.navbar-dark .navbar-brand:hover {
+ color: #00c2fb !important;
+}
+
+@media screen and (max-width: 996px) {
+ .navbar-dark .navbar-collapse {
+ text-align: center;
+ }
+}
+
+.navbar-dark .navbar-collapse .navbar-nav .nav-item.active .nav-link {
+ color: #00c2fb !important;
+}
+
+.navbar-dark .navbar-collapse .navbar-nav .dropdown-menu {
+ border: 0;
+ border-radius: 0;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ -ms-border-radius: 0;
+ -o-border-radius: 0;
+ padding: 15px 15px;
+}
+
+.navbar-dark .navbar-collapse .navbar-nav .dropdown-menu .dropdown-item {
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+
+@media screen and (max-width: 996px) {
+ .navbar-dark .navbar-collapse .navbar-nav .dropdown-menu .dropdown-item {
+ text-align: center;
+ }
+}
+
+.navbar-dark .navbar-collapse .navbar-nav .dropdown-menu .dropdown-item:hover {
+ color: #fff;
+ background-color: #00c2fb;
+}
+
+.navbar-dark .navbar-collapse .navbar-nav .dropdown:hover > .dropdown-menu {
+ display: block;
+}
+
+.navbar-dark .navbar-collapse .nav-item {
+ text-transform: uppercase;
+ padding: 0 12px;
+}
+
+.navbar-dark .navbar-collapse .nav-item .nav-link {
+ color: #222222;
+ font-weight: 500;
+ font-size: 13px;
+}
+
+.navbar-dark .navbar-collapse .nav-item .nav-link:hover {
+ color: #00c2fb;
+}
+
+.navbar-dark .navbar-collapse .nav-item .nav-link:hover i{
+ color: #00c2fb !important;
+}
+
+.navbar-dark .nav_right {
+ display: flex;
+}
+
+@media screen and (max-width: 996px) {
+ .navbar-dark .nav_right {
+ justify-content: center;
+ }
+}
+
+.navbar-dark .nav_right .nav_cart {
+ padding: 0 12px;
+}
+
+.navbar-dark .nav_right .nav_cart a {
+ color: #222222;
+}
+
+.navbar-dark .nav_right .nav_cart a:hover {
+ color: #00c2fb;
+}
+
+.navbar-dark .nav_right .nav_search {
+ padding: 0 12px;
+}
+
+.navbar-dark .nav_right .nav_search a {
+ color: #222222;
+}
+
+.navbar-dark .nav_right .nav_search a:hover {
+ color: #00c2fb;
+}
+
+#new {
+ transition: 0.5s;
+}
+.o_footer {
+ background-color: transparent !important;
+ color: #222222 !important;
+}
+.o_footer .o_footer_copyright{
+ background-color: #30353b !important;
+}
+
+.footer {
+ margin-top: 10px;
+ background-color: #222222;
+}
+
+.footer .footer_content {
+ padding-top: 90px;
+ padding-bottom: 90px;
+}
+
+@media screen and (max-width: 996px) {
+ .footer .footer_content .ft_b {
+ margin-top: 45px;
+ }
+}
+
+.footer .footer_content .wrapper h6 {
+ color: #fff;
+ font-weight: 600;
+ font-size: 23px;
+ margin-bottom: 30px;
+}
+
+.footer .footer_content .wrapper p {
+ color: #777777;
+ line-height: 21px;
+ font-size: 14px;
+}
+
+@media screen and (max-width: 768px) {
+ .footer .footer_content .wrapper p {
+ margin-bottom: 45px;
+ }
+}
+
+.footer .footer_content .wrapper .input-group {
+ width: 100%;
+ height: 50px;
+ border-radius: 0;
+ margin-top: 30px;
+}
+
+.footer .footer_content .wrapper .input-group .form-control {
+ border-radius: 0;
+ height: 50px;
+}
+
+.footer .footer_content .wrapper .input-group .input-group-text {
+ border-radius: 0;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #e0d8d8 60%);
+ padding: 0 20px;
+ color: #fff;
+ height: 50px;
+ font-weight: 700;
+}
+
+.footer .footer_content .wrapper .footer_icon {
+ display: flex;
+ margin-top: 30px;
+}
+
+.footer .footer_content .wrapper .footer_icon a {
+ color: #fff;
+ margin-right: 18px;
+}
+
+.footer .footer_content .wrapper .footer_icon a:hover {
+ color: #f1a138;
+}
+
+.footer .footer_content .wrapper .footer_icon a span {
+ font-size: 12px;
+}
+
+.footer .footer_content .footer_bottom {
+ margin-top: 50px;
+ text-align: center;
+ color: #777777;
+ margin-bottom: 20px;
+ width: 100%;
+}
+
+@media screen and (max-width: 996px) {
+ .footer .footer_content .footer_bottom {
+ text-align: left;
+ padding-left: 12px;
+ }
+}
+
+.footer .footer_content .footer_bottom a {
+ color: #00c2fb;
+ text-decoration: none;
+}
+
+.footer .footer_content .footer_bottom a:hover {
+ color: #f1a138;
+}
+
+.sidebar .wrapper {
+ margin-bottom: 20px;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+ transition: all 0.3s ease 0s;
+ -ms-transition: all 0.3s ease 0s;
+}
+
+.sidebar .wrapper .sidebar_head {
+ background: #fc5205;
+ color: #fff;
+ padding: 18px 10px;
+ padding-left: 20px;
+ margin-bottom: 20px;
+}
+
+.sidebar .wrapper .sidebar_content .categories__accordion .card {
+ border: none;
+ border-radius: 0;
+ padding-left: 20px;
+ padding-bottom: 12px;
+ border-bottom: 1px solid #f2f2f2 !important;
+ margin-bottom: 12px;
+}
+
+.sidebar .wrapper .sidebar_content .categories__accordion .card-heading {
+ cursor: pointer;
+}
+
+.sidebar .wrapper .sidebar_content .categories__accordion .card-heading a {
+ font-size: 14px;
+ font-weight: 500;
+ color: #000;
+ display: block;
+ text-decoration: none;
+}
+
+.sidebar .wrapper .sidebar_content .categories__accordion .card-body {
+ padding-left: 0;
+ padding-top: 6px;
+ padding-bottom: 0;
+}
+
+.sidebar .wrapper .sidebar_content .categories__accordion .card-body li {
+ list-style: none;
+ position: relative;
+ padding-left: 16px;
+}
+
+.sidebar .wrapper .sidebar_content .categories__accordion .card-body li:before {
+ position: absolute;
+ left: 4px;
+ top: 14px;
+ height: 1px;
+ width: 4px;
+ background: #666666;
+ content: "";
+}
+
+.sidebar .wrapper .sidebar_content .categories__accordion .card-body li a {
+ font-size: 14px;
+ color: #666666;
+ line-height: 30px;
+}
+
+.sidebar .wrapper .sidebar_content .filter_head {
+ color: #000;
+ font-size: 20px;
+ font-weight: 600;
+ padding: 18px 10px;
+}
+
+.sidebar .wrapper .sidebar_content .filter {
+ padding-left: 20px;
+ padding-right: 10px;
+ padding-bottom: 20px;
+ /* Hide the browser's default radio button */
+ /* Create a custom radio button */
+ /* On mouse-over, add a grey background color */
+ /* When the radio button is checked, add a blue background */
+ /* Create the indicator (the dot/circle - hidden when not checked) */
+ /* Show the indicator (dot/circle) when checked */
+ /* Style the indicator (dot/circle) */
+}
+
+.sidebar .wrapper .sidebar_content .filter .container {
+ display: block;
+ position: relative;
+ padding-left: 35px;
+ margin-bottom: 12px;
+ cursor: pointer;
+ font-size: 14px;
+ user-select: none;
+ color: #777777;
+}
+
+.sidebar .wrapper .sidebar_content .filter .container input {
+ position: absolute;
+ opacity: 0;
+ cursor: pointer;
+}
+
+.sidebar .wrapper .sidebar_content .filter .checkmark {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 20px;
+ width: 20px;
+ background-color: #4e4848;
+ border-radius: 50%;
+}
+
+.sidebar .wrapper .sidebar_content .filter .container:hover input ~ .checkmark {
+ background-color: #f1a138;
+}
+
+.sidebar .wrapper .sidebar_content .filter .container input:checked ~ .checkmark {
+ background-color: #00c2fb;
+}
+
+.sidebar .wrapper .sidebar_content .filter .checkmark:after {
+ content: "";
+ position: absolute;
+ display: none;
+}
+
+.sidebar .wrapper .sidebar_content .filter .container input:checked ~ .checkmark:after {
+ display: block;
+}
+
+.sidebar__filter {
+ position: relative;
+}
+
+.sidebar__filter input {
+ font-family: inherit;
+ font-size: 100%;
+ line-height: 1.15;
+ margin: 0;
+ width: 50%;
+}
+
+.sidebar__filter .section-title {
+ margin-bottom: 50px;
+}
+
+.sidebar__filter .section-title .borderd_header {
+ text-transform: uppercase;
+}
+
+.sidebar__filter .section-title h4 {
+ font-size: 18px;
+}
+
+#slider-range {
+ margin-bottom: 30px;
+ background-color: #fc5205;
+ border: none;
+ height: 8px;
+ border-radius: 8px;
+}
+
+#slider-range .ui-state-default,
+#slider-range .ui-widget-content .ui-state-default {
+ background-color: #3a3a3a;
+ border: none;
+ height: 18px;
+ width: 18px;
+ top: -4.8px;
+ position: absolute;
+ border-radius: 50%;
+}
+
+#slider-range.ui-slider-horizontal .ui-slider-range {
+ top: 0;
+ background-color: #fc5205 !important;
+ left: 0%;
+ width: 60%;
+ position: absolute;
+ height: 8px;
+ border-radius: 8px;
+}
+
+.services {
+ margin-top: 100px;
+}
+
+.services .wrapper {
+ text-align: center;
+}
+
+@media screen and (max-width: 576px) {
+ .services .wrapper {
+ padding-bottom: 20px;
+ }
+}
+
+.services .wrapper i {
+ font-size: 48px;
+ padding-bottom: 16px;
+}
+
+.services .wrapper h6 {
+ font-size: 18px;
+ font-weight: 500;
+ font-family: "Poppins", sans-serif;
+ padding-bottom: 2px;
+}
+
+.services .wrapper p {
+ color: #777777;
+}
+
+.offers {
+ padding-top: 100px;
+}
+
+@media screen and (max-width: 996px) {
+ .offers {
+ padding-top: 75px;
+ }
+}
+
+@media screen and (max-width: 996px) {
+ .offers .tt {
+ margin-top: 20px;
+ }
+}
+
+.offers .offer_img {
+ position: relative;
+}
+
+.offers .offer_img .inline-photo {
+ opacity: 0;
+ transform: translateY(0em) rotateZ(0deg);
+ transition: transform 6s 0.25s cubic-bezier(0, 1, 0.3, 1), opacity 0.9s 0.25s ease-out;
+ will-change: transform, opacity;
+ -webkit-transform: translateY(0em) rotateZ(0deg);
+ -moz-transform: translateY(0em) rotateZ(0deg);
+ -ms-transform: translateY(0em) rotateZ(0deg);
+ -o-transform: translateY(0em) rotateZ(0deg);
+ -webkit-transition: transform 6s 0.25s cubic-bezier(0, 1, 0.3, 1), opacity 0.9s 0.25s ease-out;
+ -moz-transition: transform 6s 0.25s cubic-bezier(0, 1, 0.3, 1), opacity 0.9s 0.25s ease-out;
+ -ms-transition: transform 6s 0.25s cubic-bezier(0, 1, 0.3, 1), opacity 0.9s 0.25s ease-out;
+ -o-transition: transform 6s 0.25s cubic-bezier(0, 1, 0.3, 1), opacity 0.9s 0.25s ease-out;
+}
+
+.offers .offer_img .inline-photo.is-visible {
+ opacity: 1;
+ transform: rotateZ(0deg);
+ -webkit-transform: rotateZ(0deg);
+ -moz-transform: rotateZ(0deg);
+ -ms-transform: rotateZ(0deg);
+ -o-transform: rotateZ(0deg);
+}
+
+.offers .offer_img img {
+ width: 100%;
+ display: block;
+ height: auto;
+}
+
+.offers .offer_img .overlay {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 100%;
+ width: 100%;
+ opacity: 0;
+ transition: 0.5s ease;
+ background-color: #00000069;
+}
+
+
+.overlay.open {
+ display: block;
+ z-index: 1028;
+}
+
+.offers .offer_img .overlay:hover {
+ opacity: 1;
+}
+
+.offers .offer_img .overlay .text {
+ color: white;
+ font-size: 20px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+}
+
+.offers .offer_left {
+ position: relative;
+}
+
+@media screen and (max-width: 996px) {
+ .offers .offer_left {
+ margin-top: 25px;
+ }
+}
+
+.offers .offer_left img {
+ width: 100%;
+}
+
+.offers .offer_left .overlay {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 100%;
+ width: 100%;
+ opacity: 0;
+ transition: 0.5s ease;
+ background-color: #00000069;
+}
+
+.offers .offer_left .overlay:hover {
+ opacity: 1;
+}
+
+.offers .offer_left .overlay .text {
+ color: white;
+ font-size: 20px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+}
+
+.hot {
+ margin-top: 70px;
+}
+
+.hot .left {
+ background-image: url(./../img/exclusive.jpg);
+ height: 100vh;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: cover;
+ position: relative;
+}
+
+.hot .left:after {
+ content: "";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 100%;
+ width: 100%;
+ background-color: #00000069;
+}
+
+.hot .left .wrapper {
+ text-align: center;
+ position: relative;
+ padding: 33px 109px;
+ z-index: 1;
+}
+
+@media screen and (max-width: 996px) {
+ .hot .left .wrapper {
+ padding: 73px 109px;
+ }
+}
+
+@media screen and (max-width: 576px) {
+ .hot .left .wrapper {
+ padding: 30px 50px;
+ }
+}
+
+.hot .left .wrapper .deal {
+ color: #fff;
+ font-size: 33px;
+ font-weight: 600;
+ padding-top: 120px;
+ margin-bottom: 7px;
+}
+
+.hot .left .bt {
+ color: #fff;
+ font-size: 15px;
+}
+
+.hot .left #countdown {
+ width: 100%;
+ border-radius: 8px;
+ margin-top: 65px;
+}
+
+@media screen and (max-width: 576px) {
+ .hot .left #countdown {
+ margin-top: 30px;
+ }
+}
+
+.hot .left label {
+ clear: both;
+ display: block;
+}
+
+.hot .left #countdown span {
+ color: #fff;
+ font-size: 45px;
+ font-weight: 700;
+ text-align: center;
+ width: 25%;
+ float: left;
+}
+
+.hot .right {
+ background-color: #f9f9ff;
+ height: 100%;
+ padding-top: 20%;
+}
+
+.hot .right .wrapper {
+ text-align: center;
+ position: relative;
+}
+
+.hot .right .wrapper .img_right {
+ max-width: 350px;
+ margin: auto;
+}
+
+.hot .right .wrapper .img_right img {
+ width: 100%;
+}
+
+.hot .right .wrapper h5 {
+ color: #222222;
+ text-transform: uppercase;
+ font-weight: 600;
+ margin-top: 15px;
+ font-family: "Poppins", sans-serif;
+ font-size: 25px;
+ margin-bottom: 30px;
+}
+
+.hot .right .wrapper .rate {
+ display: flex;
+ justify-content: center;
+ padding-top: 10px;
+}
+
+.hot .right .wrapper .rate p {
+ color: #222222;
+ margin-right: 50px;
+}
+
+.hot .right .wrapper .rate span {
+ color: #777777;
+ text-decoration: line-through;
+}
+
+.hot .right #owl-theme2 {
+ position: relative;
+}
+
+.hot .right #owl-theme2 .owl-nav .owl-prev {
+ color: #f1a138;
+}
+
+.hot .right #owl-theme2 .owl-nav .owl-prev:hover {
+ color: #000;
+}
+
+.hot .right #owl-theme2 .owl-nav .owl-prev i {
+ font-size: 27px;
+ padding: 10px;
+}
+
+.hot .right #owl-theme2 .owl-nav .owl-next {
+ color: #f1a138;
+}
+
+.hot .right #owl-theme2 .owl-nav .owl-next:hover {
+ color: #000;
+}
+
+.hot .right #owl-theme2 .owl-nav .owl-next i {
+ font-size: 27px;
+}
+
+.brands {
+ margin-top: 100px;
+}
+
+@media screen and (max-width: 996px) {
+ .brands {
+ margin-top: 75px;
+ }
+}
+
+@media screen and (max-width: 996px) {
+ .brands {
+ margin-top: 50px;
+ }
+}
+
+.brands .brand_img {
+ max-width: 120px;
+ display: block;
+ margin: auto;
+}
+
+@media screen and (max-width: 996px) {
+ .brands .brand_img {
+ margin-bottom: 15px;
+ }
+}
+
+.brands .brand_img img {
+ width: 100%;
+ opacity: 0.2;
+ transition: all 0.3s ease 0s;
+}
+
+.brands .brand_img img:hover {
+ opacity: 0.8;
+}
+
+.deals {
+ margin-top: 100px;
+}
+
+@media screen and (max-width: 996px) {
+ .deals {
+ margin-top: 75px;
+ }
+}
+
+@media screen and (max-width: 996px) {
+ .deals {
+ margin-top: 50px;
+ }
+}
+
+.deals .r_wrapper {
+ margin-bottom: 20px;
+}
+
+.deals .r_wrapper .r_img img {
+ width: 70px;
+ height: 70px;
+}
+
+.deals .r_wrapper .p_details {
+ padding-left: 10px;
+}
+
+.deals .r_wrapper .p_details a {
+ text-decoration: none;
+}
+
+.deals .r_wrapper .p_details a h5 {
+ color: #222222;
+ text-transform: uppercase;
+ font-weight: 400;
+ margin-top: 14px !important;
+ font-family: "Poppins", sans-serif;
+ font-size: 14px;
+}
+
+.deals .r_wrapper .p_details a h5 span{
+ color: #222222;
+ text-transform: uppercase;
+ font-weight: 400;
+ margin-top: 14px !important;
+ font-family: "Poppins", sans-serif;
+ font-size: 14px;
+}
+
+.deals .r_wrapper .p_details a h5:hover {
+ color: #f1a138 !important;
+ transition: 0.5s;
+}
+
+.deals .r_wrapper .p_details a h5 span:hover {
+ color: #f1a138 !important;
+ transition: 0.5s;
+}
+
+
+.deals .r_wrapper .p_details .rate {
+ display: flex;
+ padding-top: 5x;
+}
+
+.deals .r_wrapper .p_details .rate p {
+ color: #222222;
+ margin-right: 10px;
+ font-weight: 600;
+}
+
+
+.deals .r_wrapper .p_details .rate p span {
+ color: #222222;
+ margin-right: 10px;
+ font-weight: 600;
+ text-decoration: none;
+}
+.deals .r_wrapper .p_details .rate p span:hover {
+ text-decoration: none;
+}
+
+.deals a {
+ color: #222222;
+ margin-right: 10px;
+ font-weight: 600;
+}
+
+.deals .r_wrapper .p_details .rate span {
+ color: #777777;
+ text-decoration: line-through;
+}
+
+.deals .d_right_img {
+ max-width: 250px;
+}
+
+@media screen and (max-width: 996px) {
+ .deals .d_right_img {
+ max-width: 100%;
+ margin-top: 40px;
+ }
+}
+
+.deals .d_right_img img {
+ width: 100%;
+}
+
+.main_product {
+ margin-top: 0px !important;
+}
+
+@media screen and (max-width: 600px) {
+ .main_product {
+ margin-top: 70px;
+ padding: 0 10px;
+ }
+}
+
+.main_product .product_top {
+ background: #fc5205;
+ padding: 13px 10px;
+ margin-bottom: 20px;
+}
+
+
+.main_product .product_top .left .drp2 {
+ margin-left: 15px !important;
+}
+
+.main_product .product_top .dropdown {
+ width: 100%;
+}
+
+
+.main_product .product_top .dropdown .btn-secondary-1{
+background: #fcfcfc;
+ border-radius: 0;
+ color: #777777;
+ width: 50%;
+}
+
+
+
+.main_product .product_top .dropdown .btn-secondary {
+ background: #fcfcfc;
+ border-radius: 0;
+ color: #777777;
+ width: 80%;
+}
+
+.main_product .product_top .dropdown .dropdown-menu {
+ border-radius: 0;
+ border: 0;
+}
+
+.main_product .product_top .dropdown .dropdown-menu .dropdown-item {
+ color: #777777;
+ padding: 10px 4px;
+}
+
+.main_product .product_top .dropdown .dropdown-menu .dropdown-item:hover {
+ background: #f1a138 !important;
+ color: #fff;
+}
+
+.user {
+ margin-left: auto !important;
+}
+
+.main_product .product_top .right .shop_pagination_area {
+ text-align: center;
+ display: flex;
+ justify-content: end;
+}
+
+@media screen and (max-width: 768px) {
+ .main_product .product_top .right .shop_pagination_area {
+ justify-content: left;
+ }
+}
+
+.main_product .product_top .right .shop_pagination_area .pagination .page-item.active .page-link {
+ color: #fff;
+ background-color: #00c2fb;
+}
+
+.main_product .product_top .right .shop_pagination_area .pagination .page-item .page-link {
+ color: #000;
+ background-color: #fff;
+ border: 0;
+ font-size: 15px;
+ font-weight: 600;
+ border: 2px solid;
+ border: 0;
+ border-radius: 0;
+ border-color: #777777;
+ height: 35px;
+ width: 37px;
+ box-shadow: none;
+ padding: 8px 10px;
+}
+
+.main_product .product_top .right .shop_pagination_area .pagination .page-item .page-link:hover {
+ color: #fff;
+ background-color: #00c2fb;
+}
+
+.main_product .product_top .right .shop_pagination_area .pagination .page-item:nth-child(4) .page-link {
+ background-color: transparent !important;
+}
+
+.main_product .product_shop .main_heading {
+ text-align: center;
+ padding-bottom: 10px;
+}
+
+.main_product .product_shop .main_heading h3 {
+ font-size: 25px;
+ font-weight: 600;
+ text-transform: uppercase;
+ font-family: "Poppins", sans-serif;
+ color: #222222;
+}
+
+.main_product .product_shop .main_heading p {
+ color: #777777;
+ line-height: 24px;
+ margin-bottom: 33px;
+}
+
+.main_product .product_shop .wrapper .product_img {
+ margin-bottom: 50px;
+}
+
+.main_product .product_shop .wrapper .product_img .wrapper_img {
+ padding-bottom: 25px;
+}
+
+.main_product .product_shop .wrapper .product_img .wrapper_img img {
+ width: 100%;
+}
+
+.main_product .product_shop .wrapper .product_img h5 {
+ color: #222222;
+ text-transform: uppercase;
+ font-weight: 600;
+ margin-top: 15px;
+ font-family: "Poppins", sans-serif;
+}
+
+.main_product .product_shop .wrapper .product_img .rate {
+ display: flex;
+ padding-top: 10px;
+}
+
+.main_product .product_shop .wrapper .product_img .rate p {
+ color: #222222;
+ margin-right: 50px;
+}
+
+.main_product .product_shop .wrapper .product_img .rate span {
+ color: #777777;
+ text-decoration: line-through;
+}
+
+.main_product .product_shop .wrapper .product_img .product_bottom {
+ display: flex;
+ padding-left: 0;
+ position: relative;
+ justify-content: center;
+}
+
+.main_product .product_shop .wrapper .product_img .product_bottom li {
+ height: 35px;
+ width: 35px;
+ border-radius: 50%;
+ background-color: #fc5205;
+ margin-right: 12px;
+ margin-left: 12px;
+}
+
+.main_product .product_shop .wrapper .product_img .product_bottom a {
+ color: #fff;
+}
+
+.main_product .product_shop .wrapper .product_img .product_bottom a span {
+ padding: 11px;
+}
+
+.Poduct_preview {
+ margin-top: 100px;
+}
+
+@media screen and (max-width: 996px) {
+ .Poduct_preview {
+ margin-top: 10px;
+ }
+}
+
+.Poduct_preview .preview_img {
+ padding-top: 30px;
+ position: relative;
+}
+
+.Poduct_preview .preview_img .wrapper {
+ max-width: 600px;
+}
+
+@media screen and (max-width: 768px) {
+ .Poduct_preview .preview_img .wrapper {
+ padding-bottom: 30px;
+ }
+}
+
+.Poduct_preview .preview_img .wrapper img {
+ width: 100%;
+}
+
+.Poduct_preview .preview_img .owl-carousel button.owl-dot span {
+ height: 25px;
+ width: 7px;
+ border-radius: 8px;
+ background-color: #fff;
+ background-color: #00c2fb;
+ display: block;
+ font-weight: 700;
+ margin: 2px;
+}
+
+@media screen and (max-width: 576px) {
+ .Poduct_preview .preview_img .owl-carousel button.owl-dot span {
+ height: 18px;
+ width: 5px;
+ margin: 1px;
+ }
+}
+
+.Poduct_preview .preview_img .owl-carousel button.owl-dot.active span {
+ height: 40px;
+ width: 7px;
+ border-radius: 8px;
+ background-color: #fc5205;
+}
+
+@media screen and (max-width: 576px) {
+ .Poduct_preview .preview_img .owl-carousel button.owl-dot.active span {
+ height: 25px;
+ width: 5px;
+ }
+}
+
+.Poduct_preview .preview_img .owl-carousel {
+ position: relative;
+}
+
+.Poduct_preview .preview_img .owl-carousel .owl-dots {
+ position: absolute;
+ bottom: 1%;
+ left: 75%;
+ transform: rotate(89deg);
+}
+
+@media screen and (max-width: 768px) {
+ .Poduct_preview .preview_img .owl-carousel .owl-dots {
+ bottom: 0;
+ }
+}
+
+.Poduct_preview .preview_details {
+ padding-top: 30px;
+ margin-left: 20px;
+}
+
+.Poduct_preview .preview_details .preview_heading {
+ color: #222222;
+ font-size: 25px;
+ font-weight: 600;
+ letter-spacing: 1px;
+}
+
+.Poduct_preview .preview_details .price {
+ color: #00c2fb;
+ font-size: 28px;
+ font-weight: 700;
+ padding-top: 10px;
+}
+
+.Poduct_preview .preview_details .category {
+ padding-left: 0;
+ margin-top: 20px;
+}
+
+.Poduct_preview .preview_details .category li {
+ padding-bottom: 10px;
+}
+
+.Poduct_preview .preview_details .category li a {
+ color: #555;
+ text-decoration: none;
+}
+
+.Poduct_preview .preview_details .category li a span {
+ color: #00c2fb;
+ padding-left: 15px;
+}
+
+.Poduct_preview .preview_details p {
+ padding-top: 30px;
+ color: #777777;
+ line-height: 25px;
+}
+
+.Poduct_preview .preview_details .product_quantity {
+ display: flex;
+ align-items: center;
+ margin-top: 40px;
+}
+
+.Poduct_preview .preview_details .product_quantity span {
+ color: #777777;
+ padding-right: 10px;
+}
+
+.Poduct_preview .preview_details .product_quantity #myform {
+ text-align: center;
+ border: 2px solid #ccc;
+ display: flex;
+ border-radius: 0px;
+ width: 100px;
+ justify-content: space-around;
+ align-items: center;
+}
+
+.Poduct_preview .preview_details .product_quantity #myform .wrapper_q {
+ display: block !important;
+}
+
+.Poduct_preview .preview_details .product_quantity .qty {
+ width: 40px;
+ height: 15px;
+ text-align: center;
+ border: none;
+}
+
+.Poduct_preview .preview_details .product_quantity input.qtyplus {
+ width: 25px;
+ border: none;
+ background-color: transparent;
+ display: block !important;
+ padding-top: 4px;
+}
+
+.Poduct_preview .preview_details .product_quantity input.qtyminus {
+ width: 25px;
+ border: none;
+ background-color: transparent;
+}
+
+.Poduct_preview .preview_details .add_c {
+ display: flex;
+ align-items: center;
+ margin-top: 20px;
+}
+
+.Poduct_preview .preview_details .add_c .c_icon {
+ padding-left: 10px;
+}
+
+.Poduct_preview .preview_details .add_c .c_icon a {
+ color: #fff;
+ font-size: 18px;
+}
+
+.Poduct_preview .preview_details .add_c .c_icon span {
+ height: 37px;
+ width: 37px;
+ background-color: #fc5205;
+ border-radius: 50%;
+ padding: 11px;
+ margin-left: 10px;
+}
+
+.Poduct_preview .preview_details .add_c .c_icon span:hover {
+ background-color: #00c2fb;
+ transition: 0.5s;
+}
+
+.preview_tab {
+ margin-top: 100px;
+}
+
+.preview_tab .nav-pills {
+ justify-content: center;
+}
+
+.preview_tab .nav-pills .nav-item {
+ padding: 12px 22px;
+}
+
+.preview_tab .nav-pills .nav-item .active {
+ color: #fff !important;
+ border: none;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ border-radius: 0;
+ padding: 12px 22px;
+}
+
+.preview_tab .nav-pills .nav-item .nav-link {
+ color: #000;
+}
+
+.preview_tab .tab-content {
+ padding-top: 20px;
+}
+
+.preview_tab .tab-content .tab-pane {
+ line-height: 24px;
+ font-size: 14px;
+ font-family: "Roboto", sans-serif;
+ font-weight: 400;
+ color: #777777;
+}
+
+.preview_tab .tab-content .tab-pane .det {
+ padding: 0 15px;
+}
+
+.preview_tab .tab-content .tab-pane table {
+ color: #777777;
+}
+
+@media screen and (max-width: 600px) {
+ .preview_tab .tab-content .tab-pane table {
+ padding: 0 15px;
+ }
+}
+
+@media screen and (max-width: 600px) {
+ .preview_tab .tab-content .tab-pane .comments {
+ padding: 0 15px;
+ }
+}
+
+.preview_tab .tab-content .tab-pane .comments .over_all {
+ margin: auto;
+ text-align: center;
+ background-color: #e8e8e8;
+ height: 150px;
+ width: 150px;
+}
+
+.preview_tab .tab-content .tab-pane .comments .over_all h5 {
+ color: #000;
+ margin-bottom: 10px;
+ padding-top: 25px;
+ font-size: 20px;
+ font-weight: 600;
+}
+
+.preview_tab .tab-content .tab-pane .comments .over_all .num {
+ color: #00c2fb;
+ font-size: 40px;
+ font-weight: 700;
+ padding-bottom: 10px;
+}
+
+.preview_tab .tab-content .tab-pane .comments .wrapper {
+ margin-top: 20px;
+}
+
+.preview_tab .tab-content .tab-pane .comments .person {
+ display: flex !important;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.preview_tab .tab-content .tab-pane .comments .person .p_img {
+ display: flex;
+ align-items: center;
+}
+
+.preview_tab .tab-content .tab-pane .comments .person .p_img .img_d {
+ padding-top: 15px;
+ margin-left: 10px;
+}
+
+.preview_tab .tab-content .tab-pane .comments .person .p_img .img_d h6 {
+ color: #000;
+}
+
+.preview_tab .tab-content .tab-pane .comments .c_p {
+ line-height: 24px;
+ font-size: 14px;
+ font-family: "Roboto", sans-serif;
+ font-weight: 400;
+ color: #777777;
+ margin-top: 20px;
+}
+
+.preview_tab .tab-content .tab-pane .p_comment .rating {
+ display: flex;
+ padding-bottom: 20px;
+}
+
+.preview_tab .tab-content .tab-pane .p_comment .rating .star {
+ display: flex;
+ padding-left: 0;
+ margin: 0 10px;
+}
+
+.preview_tab .tab-content .tab-pane .p_comment .rating .star li a {
+ margin-right: 4px;
+ color: #ff9800;
+}
+
+.preview_tab .tab-content .tab-pane .p_comment .rating .star li a span {
+ font-size: 13px;
+}
+
+.preview_tab .tab-content .tab-pane .p_comment h5 {
+ color: #000;
+}
+
+.preview_tab .tab-content .tab-pane .p_comment .contact-form {
+ margin-top: 10px;
+}
+
+.preview_tab .tab-content .tab-pane .p_comment .contact-form .form-control {
+ display: block;
+ width: 100%;
+ height: calc(2.5em + 0.75rem + 2px);
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid #ced4da;
+ border-color: transparent;
+ border-bottom-color: #000;
+ border-radius: 0;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+.preview_tab .tab-content .tab-pane .p_comment .contact-form .form-control:focus {
+ color: #495057;
+ background-color: #fff;
+ border-bottom-color: #000 !important;
+ outline: 0;
+ box-shadow: none;
+}
+
+.preview_tab .tab-content .tab-pane .p_comment .contact-form .input-block {
+ margin-bottom: 30px;
+}
+
+.preview_tab .tab-content .tab-pane .p_comment .contact-form .input-block label {
+ color: #777777;
+}
+
+.checkout {
+ margin-top: 100px;
+}
+
+.checkout .wrapper {
+ background-color: #faffcb;
+ padding: 20 20px;
+}
+
+.checkout .checkout_top .wrp {
+ padding: 0 15px;
+}
+
+.checkout .checkout_top .one {
+ background-color: #f2ede2;
+ text-align: left;
+ display: block;
+ width: 100%;
+ padding: 15px 0px 15px 10px;
+}
+
+.checkout .checkout_top .one a {
+ color: #c5322d;
+ text-decoration: none;
+ padding-left: 5px;
+}
+
+.checkout .checkout_top p {
+ color: #777777;
+ padding: 15px 0;
+}
+
+.checkout .checkout_top .md-form {
+ color: #777777;
+ margin-right: 20px;
+}
+
+.checkout .checkout_top .form-control {
+ display: block;
+ width: 100%;
+ height: calc(2em + 0.85rem + 3px);
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ background-color: #e3e3e3;
+ background-clip: padding-box;
+ border: 1px solid;
+ border-color: #00c2fb !important;
+ border-radius: 0;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+.checkout .checkout_top .coupon {
+ display: block;
+ width: 100%;
+ height: calc(2em + 0.85rem + 3px);
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ background-color: #e3e3e300;
+ background-clip: padding-box;
+ border: 1px solid;
+ border-color: #00c2fb !important;
+ border-radius: 0;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+.checkout .checkout_top .coupon:focus {
+ color: #495057;
+ background-color: #c2bfbf !important;
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.25);
+}
+
+.checkout .checkout_top .form-control:focus {
+ color: #495057;
+ background-color: #fff;
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.25);
+}
+
+.checkout .checkout_top .custom-control-input:checked ~ .custom-control-label::before {
+ color: red;
+ border-color: red;
+ background-color: red;
+ outline: none !important;
+ box-shadow: none !important;
+}
+
+.checkout .checkout_top .form-check-input:checked {
+ outline: none !important;
+ box-shadow: none !important;
+}
+
+.checkout .checkout_left {
+ margin-top: 70px;
+}
+
+.checkout .checkout_left .billing h3 {
+ font-weight: 600;
+ color: #ff6c00;
+ text-transform: uppercase;
+}
+
+.checkout .checkout_left .billing p {
+ color: #777777;
+ margin-top: 15px;
+}
+
+.checkout .checkout_left .form-control {
+ display: block;
+ width: 100%;
+ height: calc(2em + 0.85rem + 3px);
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ background-color: #e3e3e3;
+ background-clip: padding-box;
+ border: 1px solid;
+ border-color: transparent !important;
+ border-radius: 0;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+.checkout .checkout_left .form-control:focus {
+ color: #495057;
+ background-color: #fff;
+ border-color: #ff6c00 !important;
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.25);
+}
+
+.checkout .checkout_left .custom-select {
+ display: inline-block;
+ width: 100%;
+ height: calc(2em + 0.85rem + 3px);
+ padding: 0.375rem 1.75rem 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ vertical-align: middle;
+ border: 1px solid #777777;
+ border-radius: 0;
+ appearance: none;
+ box-shadow: none;
+}
+
+.checkout .checkout_left .card {
+ border: none;
+ background-color: #f2ede2;
+}
+
+.checkout .checkout_left .card .card-body .md-form {
+ color: #777777;
+}
+
+.checkout .checkout_left .card .card-body .md-form .lable {
+ color: #000;
+}
+
+.checkout .checkout_left .card .card-body .custom-control-input:checked ~ .custom-control-label::before {
+ color: #f1a138;
+ border-color: #f1a138;
+ background-color: #f1a138;
+ outline: none;
+}
+
+.checkout .checkout_left .card .card-body .form-check-input:checked ~ .form-check-label::before {
+ color: #f1a138 !important;
+ border-color: #f1a138 !important;
+ background-color: #f1a138 !important;
+ content: "";
+}
+
+.checkout .checkout_left .card .card-body .input[type="checkbox"]:before,
+.checkout .checkout_left .card .card-body input[type="radio"]:before {
+ position: absolute;
+ top: 0.25rem;
+ left: -1.5rem;
+ display: block;
+ width: 1rem;
+ height: 1rem;
+ pointer-events: none;
+ background-color: #8a1717;
+ border: #3e71a5 solid 1px;
+}
+
+.checkout .checkout_right {
+ margin-top: 70px;
+}
+
+.checkout .checkout_right .order h3 {
+ font-weight: 600;
+ color: #ff6c00;
+}
+
+.checkout .checkout_right .order .subhead {
+ color: #777777;
+ padding-top: 10px;
+}
+
+.checkout .checkout_right .order .wrapper {
+ padding-left: 30px;
+}
+
+.checkout .checkout_right .order ul {
+ padding-top: 20px;
+ padding-left: 0;
+}
+
+.checkout .checkout_right .order ul li {
+ display: flex;
+ justify-content: space-between;
+ margin-top: 20px;
+ padding-bottom: 15px;
+}
+
+.checkout .checkout_right .order ul li span {
+ padding-right: 30px;
+}
+
+.checkout .checkout_right .order ul li .nn {
+ color: #000;
+}
+
+.checkout .checkout_right .order .payment label {
+ color: #000;
+}
+
+.checkout .checkout_right .order .payment [type="radio"]:checked,
+.checkout .checkout_right .order .payment [type="radio"]:not(:checked) {
+ position: absolute;
+ left: -9999px;
+}
+
+.checkout .checkout_right .order .payment [type="radio"]:checked + label,
+.checkout .checkout_right .order .payment [type="radio"]:not(:checked) + label {
+ position: relative;
+ padding-left: 28px;
+ cursor: pointer;
+ line-height: 20px;
+ display: inline-block;
+ color: #666;
+}
+
+.checkout .checkout_right .order .payment [type="radio"]:checked + label:before,
+.checkout .checkout_right .order .payment [type="radio"]:not(:checked) + label:before {
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 18px;
+ height: 18px;
+ border: 1px solid;
+ border-color: #f1a138;
+ border-radius: 100%;
+ background: #fff;
+}
+
+.checkout .checkout_right .order .payment [type="radio"]:checked + label:after,
+.checkout .checkout_right .order .payment [type="radio"]:not(:checked) + label:after {
+ content: "";
+ width: 11px;
+ height: 12px;
+ background: #f1a138;
+ position: absolute;
+ top: 3px;
+ left: 3px;
+ border-radius: 100%;
+ transition: all 0.2s ease;
+}
+
+.checkout .checkout_right .order .payment [type="radio"]:not(:checked) + label:after {
+ opacity: 0;
+ transform: scale(0);
+}
+
+.checkout .checkout_right .order .payment [type="radio"]:checked + label:after {
+ opacity: 1;
+ transform: scale(1);
+}
+
+.checkout .checkout_right .order .order_text {
+ font-style: italic;
+ color: #777777;
+ margin-top: 55px;
+ margin-bottom: 20px;
+}
+
+.cart {
+ margin-top: 90px;
+}
+
+.cart .table_wrapper {
+ overflow: auto;
+}
+
+.cart .table_wrapper .table {
+ overflow-x: auto;
+}
+
+.cart .table_wrapper .table thead {
+ background-color: #acdfee99;
+}
+
+.cart .table_wrapper .table tbody .cart_img {
+ display: flex;
+ align-items: center;
+ padding-bottom: 30px;
+}
+
+@media screen and (max-width: 576px) {
+ .cart .table_wrapper .table tbody .cart_img {
+ margin-top: 30px;
+ }
+}
+
+.cart .table_wrapper .table tbody .cart_img .wrapper {
+ max-width: 150px;
+}
+
+.cart .table_wrapper .table tbody .cart_img .wrapper img {
+ width: 100%;
+}
+
+.cart .table_wrapper .table tbody .cart_img h6 {
+ color: #00c2fb;
+ font-size: 23px;
+ padding-left: 20px;
+}
+
+@media screen and (max-width: 600px) {
+ .cart .table_wrapper .table tbody .cart_img h6 {
+ font-size: 12px;
+ padding-left: 10px;
+ }
+}
+
+.cart .table_wrapper .table tbody td {
+ vertical-align: middle;
+}
+
+.cart .table_wrapper .table tbody td .cart_q {
+ position: relative;
+}
+
+.cart .table_wrapper .table tbody td .quantity {
+ position: absolute;
+ top: -21px;
+ left: 30px;
+}
+
+@media screen and (max-width: 576px) {
+ .cart .table_wrapper .table tbody td .quantity {
+ padding-left: 15px;
+ left: 10px;
+ }
+}
+
+.cart .table_wrapper .table tbody td input[type="number"]::-webkit-inner-spin-button,
+.cart .table_wrapper .table tbody td input[type="number"]::-webkit-outer-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
+
+.cart .table_wrapper .table tbody td input[type="number"] {
+ -moz-appearance: textfield;
+}
+
+.cart .table_wrapper .table tbody td .quantity input {
+ width: 45px;
+ height: 42px;
+ line-height: 1.65;
+ display: block;
+ padding: 0;
+ margin: 0;
+ padding-left: 20px;
+ border: 1px solid #eee;
+}
+
+.cart .table_wrapper .table tbody td .quantity input:focus {
+ outline: 0;
+}
+
+.cart .table_wrapper .table tbody td .quantity-nav {
+ float: left;
+ position: relative;
+ height: 42px;
+}
+
+.cart .table_wrapper .table tbody td .quantity-button {
+ position: relative;
+ cursor: pointer;
+ border-left: 1px solid #eee;
+ width: 20px;
+ text-align: center;
+ color: #333;
+ font-size: 13px;
+ line-height: 1.7;
+ transform: translateX(-100%);
+ -o-user-select: none;
+ user-select: none;
+}
+
+.cart .table_wrapper .table tbody td .quantity-button.quantity-up {
+ position: absolute;
+ height: 50%;
+ top: -38px;
+ border-bottom: 1px solid #eee;
+}
+
+.cart .table_wrapper .table tbody td .quantity-button.quantity-down {
+ position: absolute;
+ bottom: 38px;
+ height: 50%;
+}
+
+.cart .table_bottom {
+ margin-top: 30px;
+}
+
+.cart .table_bottom .input-group {
+ width: 100%;
+ height: 50px;
+ border-radius: 0;
+}
+
+@media screen and (max-width: 768px) {
+ .cart .table_bottom .input-group {
+ padding-top: 20px;
+ }
+}
+
+.cart .table_bottom .input-group .form-control {
+ border-radius: 0;
+ height: 50px;
+}
+
+.cart .table_bottom .input-group .input-group-text {
+ border-radius: 0;
+ background-color: #00c2fb;
+ padding: 0 20px;
+ color: #fff;
+ border: 1px solid;
+ font-weight: 700;
+}
+
+.cart .table_bottom .form-control:focus {
+ color: #495057;
+ background-color: #fff;
+ border-color: #00c2fb;
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.25);
+}
+
+.cart .price_details {
+ margin-top: 50px;
+}
+
+.cart .price_details .total {
+ display: flex;
+ justify-content: space-between;
+ padding: 0 75px;
+}
+
+.cart .price_details .bb {
+ margin-top: 30px;
+}
+
+.cart .wrap {
+ justify-content: space-between;
+ margin-top: 40px;
+ padding: 0 40px;
+}
+
+.cart .wrap .ship {
+ padding-left: 40px;
+ font-weight: 600;
+}
+
+.cart .payment {
+ /* Hide the browser's default radio button */
+ /* Create a custom radio button */
+ /* On mouse-over, add a grey background color */
+ /* When the radio button is checked, add a blue background */
+ /* Create the indicator (the dot/circle - hidden when not checked) */
+ /* Show the indicator (dot/circle) when checked */
+ /* Style the indicator (dot/circle) */
+}
+
+.cart .payment .c1 {
+ display: block;
+ position: relative;
+ padding-left: 35px;
+ margin-bottom: 12px;
+ cursor: pointer;
+ font-size: 15px;
+ user-select: none;
+}
+
+.cart .payment .c1 input {
+ position: absolute;
+ opacity: 0;
+ cursor: pointer;
+}
+
+.cart .payment .checkmark {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 20px;
+ width: 20px;
+ background-color: #d4d4d4;
+ border-radius: 50%;
+}
+
+.cart .payment .c1:hover input ~ .checkmark {
+ background-color: rgba(204, 204, 204, 0);
+}
+
+.cart .payment .c1 input:checked ~ .checkmark {
+ background-color: #f0e76c;
+}
+
+.cart .payment .checkmark:after {
+ content: "";
+ position: absolute;
+ display: none;
+}
+
+.cart .payment .c1 input:checked ~ .checkmark:after {
+ display: block;
+}
+
+.cart .payment .c1 .checkmark:after {
+ top: 9px;
+ left: 9px;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: rgba(255, 255, 255, 0);
+}
+
+.confirmation {
+ margin-top: 100px;
+}
+
+@media screen and (max-width: 768px) {
+ .confirmation .wrapper {
+ padding-bottom: 15px;
+ }
+}
+
+.confirmation .wrapper h5 {
+ font-weight: 600;
+ margin-bottom: 40px;
+}
+
+@media screen and (max-width: 768px) {
+ .confirmation .wrapper h5 {
+ padding-left: 15px;
+ }
+}
+
+.confirmation .wrapper ul {
+ padding-left: 0;
+ padding-right: 30px;
+}
+
+@media screen and (max-width: 768px) {
+ .confirmation .wrapper ul {
+ padding: 0 15px;
+ }
+}
+
+.confirmation .wrapper ul li {
+ color: #777777;
+ display: flex;
+ margin-bottom: 15px;
+ justify-content: space-between;
+}
+
+.confirmation .wrapper ul li span {
+ color: #000;
+}
+
+.confirmation .billing_details {
+ margin-top: 50px;
+ background-color: #acdfee99;
+ padding: 20px 40px;
+}
+
+.confirmation .billing_details table tr {
+ padding-bottom: 10px;
+}
+
+.login {
+ margin-top: 100px;
+}
+
+.login .wrapper_img {
+ position: relative;
+}
+
+.login .wrapper_img::before {
+ content: "";
+ position: absolute;
+ background-color: #0000008a;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+}
+
+.login .wrapper_img .register {
+ position: absolute;
+ padding: 0 30px;
+ bottom: 30%;
+ color: #fff;
+ text-align: center;
+}
+
+.login .wrapper_img .register h5 {
+ margin-bottom: 15px;
+ font-size: 22px;
+}
+
+.login .wrapper_img img {
+ width: 100%;
+}
+
+.login .login_form {
+ margin-top: 70px;
+ padding: 0 20px;
+}
+
+.login .login_form h4 {
+ margin-bottom: 50px;
+}
+
+.login .login_form .contact-form {
+ margin-top: 10px;
+}
+
+.login .login_form .contact-form .form-control {
+ display: block;
+ width: 100%;
+ height: calc(2.5em + 0.75rem + 2px);
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid #ced4da;
+ border-color: transparent;
+ border-bottom-color: #000;
+ border-radius: 0;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+.login .login_form .contact-form .form-control:focus {
+ color: #495057;
+ background-color: #fff;
+ border-bottom-color: #000 !important;
+ outline: 0;
+ box-shadow: none;
+}
+
+.login .login_form .contact-form .input-block {
+ margin-bottom: 30px;
+}
+
+.login .login_form .contact-form .input-block label {
+ color: #777777;
+}
+
+.login .login_form .forgot {
+ color: #777777;
+ display: block;
+ text-decoration: none;
+ text-align: center;
+ margin-top: 20px;
+}
+
+.tracking {
+ margin-top: 100px;
+}
+
+.tracking .track_form {
+ max-width: 70%;
+ margin: auto;
+}
+
+.tracking .track_form p {
+ padding-bottom: 15px;
+}
+
+.tracking .track_form .contact-form {
+ margin-top: 10px;
+}
+
+.tracking .track_form .contact-form .form-control {
+ display: block;
+ width: 100%;
+ height: calc(2.5em + 0.75rem + 2px);
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid #ced4da;
+ border-color: transparent;
+ border-bottom-color: #000;
+ border-radius: 0;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+.tracking .track_form .contact-form .form-control:focus {
+ color: #495057;
+ background-color: #fff;
+ border-bottom-color: #000 !important;
+ outline: 0;
+ box-shadow: none;
+}
+
+.tracking .track_form .contact-form .input-block {
+ margin-bottom: 30px;
+}
+
+.tracking .track_form .contact-form .input-block label {
+ color: #777777;
+}
+
+.contact {
+ margin-top: 100px;
+}
+
+.contact .map .mapouter {
+ position: relative;
+ text-align: right;
+ height: 400px;
+ widows: 100%;
+}
+
+.contact .map .mapouter .mapouter {
+ overflow: hidden;
+ background: none !important;
+ height: 100%;
+ width: 100%;
+}
+
+.contact .contact_form {
+ margin-top: 70px;
+}
+
+.contact .contact_form .contact_left {
+ margin-top: 100px;
+}
+
+.contact .contact_form .contact_left .wrapper {
+ display: flex;
+ margin-bottom: 20px;
+}
+
+.contact .contact_form .contact_left .wrapper span {
+ color: #00c2fb;
+ font-size: 20px;
+}
+
+.contact .contact_form .contact_left .wrapper .rc {
+ padding-left: 15px;
+}
+
+.contact .contact_form .contact_left .wrapper .rc h4 {
+ font-size: 16px;
+ font-weight: 600;
+}
+
+.contact .contact_form .contact_left .wrapper .rc p {
+ color: #777777;
+}
+
+.contact .contact_right .form-control:focus {
+ color: #495057;
+ background-color: #fff;
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.25);
+}
+
+.contact .contact_right .custom-control-input:checked ~ .custom-control-label::before {
+ color: red;
+ border-color: red;
+ background-color: red;
+ outline: none !important;
+ box-shadow: none !important;
+}
+
+.contact .contact_right .form-check-input:checked {
+ outline: none !important;
+ box-shadow: none !important;
+}
+
+.contact .contact_right .form-control {
+ display: block;
+ width: 100%;
+ height: calc(2em + 0.85rem + 3px);
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #495057;
+ background-color: #e3e3e3;
+ background-clip: padding-box;
+ border: 1px solid;
+ border-color: #00c2fb !important;
+ border-radius: 0;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+.contact .contact_right .card {
+ border: none;
+ background-color: #f2ede2;
+}
+
+.contact .contact_right .card .card-body .md-form {
+ color: #777777;
+}
+
+.contact .contact_right .card .card-body .md-form .lable {
+ color: #000;
+}
+
+.contact .contact_right .card .card-body .custom-control-input:checked ~ .custom-control-label::before {
+ color: #f1a138;
+ border-color: #f1a138;
+ background-color: #f1a138;
+ outline: none;
+}
+
+.contact .contact_right .card .card-body .form-check-input:checked ~ .form-check-label::before {
+ color: #f1a138 !important;
+ border-color: #f1a138 !important;
+ background-color: #f1a138 !important;
+ content: "";
+}
+
+.contact .contact_right .card .card-body .input[type="checkbox"]:before,
+.contact .contact_right .card .card-body input[type="radio"]:before {
+ position: absolute;
+ top: 0.25rem;
+ left: -1.5rem;
+ display: block;
+ width: 1rem;
+ height: 1rem;
+ pointer-events: none;
+ background-color: #8a1717;
+ border: #3e71a5 solid 1px;
+}
+
+/*new created styles*/
+
+.container .products_pager{
+ background: #fc5205;
+ padding: 13px 10px;
+ margin-bottom: 25px;
+ margin-top: 50px
+}
+
+
+.container .products_pager .btn-secondary {
+ background: #fcfcfc;
+ border-radius: 0;
+ color: #777777;
+ width: 80%;
+}
+
+.oe_product_cart .oe_product_image {
+ border: 0.1rem solid black;
+}
+
+.oe_product_cart .o_wsale_product_information .o_wsale_product_information_text .o_wsale_products_item_title a{
+ color: #040404;
+ text-decoration: none;
+}
+.product_buttons .product_bottom {
+ display: flex;
+ padding-left: 0;
+ position: relative;
+}
+
+.product_buttons .product_bottom li {
+ height: 35px;
+ width: 35px;
+ border-radius: 50%;
+ background-color: #fc5205;
+ margin-right: 12px;
+}
+
+.product_buttons .product_bottom a {
+ color: #fff;
+}
+
+.product_buttons .product_bottom a span {
+ padding: 11px;
+}
+
+.nav-pills .nav-link.active {
+ color: #fff !important;
+ background-color: #fc5205 !important;
+ padding: 13px;
+ border-radius: 0px;
+}
+
+.nav-pills .nav-link {
+ color: #040404;
+}
+
+#products_grid_before #wsale_products_categories_collapse {
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+}
+
+.price .product_price .oe_price_h4 .oe_price {
+ font-size: 28px ;
+}
+.price .product_price .oe_price_h4 .oe_price .oe_currency_value{
+ font-size: 28px ;
+}
+.products_header.btn-toolbar.flex-nowrap.align-items-center.justify-content-between.mb-3 {
+ background-color: #fc5205;
+ padding: 15px;
+}
+.btn-primary {
+ background-color: #fff !important;
+ padding: 4px 12px !important;
+
+ border: 0px solid !important;
+}
+.btn.btn-primary.a-submit {
+ border: 0px solid !important;
+
+ background-color: #fc5205 !important;
+
+}
+.o_wsale_product_btn .btn.btn-primary.a-submit {
+ color: #fff !important;
+}
+.bg-white {
+ background-color: #fc5205 !important;
+ color: #fff !important;
+}
+
+.btn.btn-primary.a-submit {
+ border: 0px solid !important;
+ border-radius: .25rem;
+
+
+}
+.oe_currency_value {
+ padding: 4px;
+}
+.o_wsale_products_grid_before_rail.vh-100.pe-lg-2.pb-lg-5.overflow-y-auto {
+ padding-left: 16px !important;
+}
+.navbar.navbar-expand-sm.navbar-light {
+ margin-top: 128px;
+}
+.navbar.navbar-light.border-top.shadow-sm.d-print-none {
+ margin-top: 128px;
+}
+.col-xl-11, .col-xl-12, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-auto {
+
+ margin-top: 53px;
+}
+
+
+#wrap {
+ margin-top: 0px !important;
+}
+.btn.btn-link.js_add_cart_json {
+ background-color: #6c757d !important;
+ color: #fff !important;
+}
+#add_to_cart {
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ padding: 14px 36px !important;
+ font-weight: 600;
+ border-radius: 6px;
+ box-shadow: none !important;
+ color: #fff !important;
+ background-color: transparent !important;
+}
+#add_to_cart:hover {
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%) !important;
+ background-color: transparent !important;
+}
+.o_wsale_product_btn {
+ position: static !important;
+ width: 100px;
+ display: flex;
+}
+
+
+#products_grid:where(:not(.o_wsale_layout_list)) .o_wsale_products_grid_table .oe_product:not(.oe_product_size_stretch):not(:hover) .o_wsale_product_btn {
+ opacity: 1;
+}
+o_wsale_product_btn button {
+ margin-left: 5px !important;
+}
+.oe_product_cart .o_wsale_product_btn .btn {
+ background-color: #fc5205 !important;
+ margin-left: 4px;
+}
+.d-none.d-md-inline-block.btn.btn-outline-primary.bg-white.o_add_compare {
+ background-color: #fc5205 !important;
+ margin-left: 4px;
+}
+.btn.btn-secondary.float-end.d-none.d-xl-inline-block {
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%) !important;
+ padding: 14px 28px !important;
+background-color: transparent !important;
+ }
+.btn-secondary {
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%) !important;
+ padding: 14px 28px !important;
+background-color: transparent !important;
+}
+.btn.btn-primary.o_sale_product_configurator_edit {
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%) !important;
+ padding: 14px 26px !important;
+background-color: transparent !important;
+ color: #fff !important;
+ border-radius: 3px;
+}
+.btn.btn-primary.float-end {
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%) !important;
+ padding: 14px 26px !important;
+ background-color: transparent !important;
+ color: #fff !important;
+ border-radius: 3px;
+}
+.col-12 .mt-3 .float-end .btn.btn-primary {
+ padding: 14px 26px !important;
+ background-color: transparent !important;
+ color: #fff !important;
+ border-radius: 3px;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%) !important;
+}
+.wrap {
+ margin-top: 130px;
+}
+.btn.btn-link.float_left.js_add_cart_json.d-none.d-md-inline-block {
+ margin-top: 0px !important;
+ margin-left: 0px !important;
+
+}
+.input-group .btn-secondary {
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%) !important;
+ background-color: transparent !important;
+ color: #fff !important;
+ padding: inherit !important;
+}
+.coupon_form .input-group a {
+ width: 20% !important;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.oe_login_form .input-group a {
+ width: 20% !important;
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+}
+
+.page-link {
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%) !important;
+}
+
+.d-flex .btn.btn-primary.mb32 {
+ padding: 14px 28px;
+ font-weight: 600;
+ box-shadow: none !important;
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%);
+ color: #fff !important;
+ border-radius: 3px;
+ padding: 14px 26px !important;
+}
+.btn.btn-primary.mb32:hover {
+ background-image: linear-gradient(45deg, #22c1c3 0%, #21392b59 60%) !important;
+}
+/*# sourceMappingURL=style.css.map */
+
+nav .navbar .navbar-collapse {
+ justify-content: center;
+}
+
+@media screen and (max-width: 992px) {
+ .header_modern_light .nav_modern nav .navbar-collapse {
+ background-color: white;
+ height: 107vh !important;
+ padding: 20px;
+ margin-top: 15px;
+ overflow: scroll;
+ justify-content: start !important;
+ }
+}
+
+.btn-primary {
+ background-color: transparent !important;
+ color: #181717 !important;
+ border-radius: 0 !important;
+ border-color: #5FED83 !important;
+ font-size: 16px;
+ font-weight: 600;
+ border: 3px solid !important;
+}
+
+.btn-primary:hover {
+ border-color: #181717 !important;
+ color: #fff !important;
+ background: #181717 !important;
+}
+
+.warning {
+ margin-bottom: 0px !important;
+ padding-top: 0px !important;
+ padding-left: 20px;
+}
diff --git a/theme_lego/static/src/img/banner/banner-1.png b/theme_lego/static/src/img/banner/banner-1.png
new file mode 100644
index 0000000000..ce5709e421
Binary files /dev/null and b/theme_lego/static/src/img/banner/banner-1.png differ
diff --git a/theme_lego/static/src/img/banner/banner-bg.jpg b/theme_lego/static/src/img/banner/banner-bg.jpg
new file mode 100644
index 0000000000..afce07f08e
Binary files /dev/null and b/theme_lego/static/src/img/banner/banner-bg.jpg differ
diff --git a/theme_lego/static/src/img/blog/add.jpg b/theme_lego/static/src/img/blog/add.jpg
new file mode 100644
index 0000000000..f04fa80af8
Binary files /dev/null and b/theme_lego/static/src/img/blog/add.jpg differ
diff --git a/theme_lego/static/src/img/blog/author.png b/theme_lego/static/src/img/blog/author.png
new file mode 100644
index 0000000000..8d8893a251
Binary files /dev/null and b/theme_lego/static/src/img/blog/author.png differ
diff --git a/theme_lego/static/src/img/blog/c1.jpg b/theme_lego/static/src/img/blog/c1.jpg
new file mode 100644
index 0000000000..c59d4bfb16
Binary files /dev/null and b/theme_lego/static/src/img/blog/c1.jpg differ
diff --git a/theme_lego/static/src/img/blog/c2.jpg b/theme_lego/static/src/img/blog/c2.jpg
new file mode 100644
index 0000000000..dc601f4de9
Binary files /dev/null and b/theme_lego/static/src/img/blog/c2.jpg differ
diff --git a/theme_lego/static/src/img/blog/c3.jpg b/theme_lego/static/src/img/blog/c3.jpg
new file mode 100644
index 0000000000..d8086dbfaf
Binary files /dev/null and b/theme_lego/static/src/img/blog/c3.jpg differ
diff --git a/theme_lego/static/src/img/blog/c4.jpg b/theme_lego/static/src/img/blog/c4.jpg
new file mode 100644
index 0000000000..88fccaec0d
Binary files /dev/null and b/theme_lego/static/src/img/blog/c4.jpg differ
diff --git a/theme_lego/static/src/img/blog/c5.jpg b/theme_lego/static/src/img/blog/c5.jpg
new file mode 100644
index 0000000000..9397bc321e
Binary files /dev/null and b/theme_lego/static/src/img/blog/c5.jpg differ
diff --git a/theme_lego/static/src/img/blog/c6.jpg b/theme_lego/static/src/img/blog/c6.jpg
new file mode 100644
index 0000000000..8d56fc0fce
Binary files /dev/null and b/theme_lego/static/src/img/blog/c6.jpg differ
diff --git a/theme_lego/static/src/img/blog/cat-post/cat-post-1.jpg b/theme_lego/static/src/img/blog/cat-post/cat-post-1.jpg
new file mode 100644
index 0000000000..85df6ce84d
Binary files /dev/null and b/theme_lego/static/src/img/blog/cat-post/cat-post-1.jpg differ
diff --git a/theme_lego/static/src/img/blog/cat-post/cat-post-2.jpg b/theme_lego/static/src/img/blog/cat-post/cat-post-2.jpg
new file mode 100644
index 0000000000..7969c5d66f
Binary files /dev/null and b/theme_lego/static/src/img/blog/cat-post/cat-post-2.jpg differ
diff --git a/theme_lego/static/src/img/blog/cat-post/cat-post-3.jpg b/theme_lego/static/src/img/blog/cat-post/cat-post-3.jpg
new file mode 100644
index 0000000000..095fc64af7
Binary files /dev/null and b/theme_lego/static/src/img/blog/cat-post/cat-post-3.jpg differ
diff --git a/theme_lego/static/src/img/blog/causes/causes-1.jpg b/theme_lego/static/src/img/blog/causes/causes-1.jpg
new file mode 100644
index 0000000000..1808351e86
Binary files /dev/null and b/theme_lego/static/src/img/blog/causes/causes-1.jpg differ
diff --git a/theme_lego/static/src/img/blog/causes/causes-2.jpg b/theme_lego/static/src/img/blog/causes/causes-2.jpg
new file mode 100644
index 0000000000..b18950e724
Binary files /dev/null and b/theme_lego/static/src/img/blog/causes/causes-2.jpg differ
diff --git a/theme_lego/static/src/img/blog/causes/causes-3.jpg b/theme_lego/static/src/img/blog/causes/causes-3.jpg
new file mode 100644
index 0000000000..a5f12c6da8
Binary files /dev/null and b/theme_lego/static/src/img/blog/causes/causes-3.jpg differ
diff --git a/theme_lego/static/src/img/blog/feature-img1.jpg b/theme_lego/static/src/img/blog/feature-img1.jpg
new file mode 100644
index 0000000000..eb117b12cf
Binary files /dev/null and b/theme_lego/static/src/img/blog/feature-img1.jpg differ
diff --git a/theme_lego/static/src/img/blog/latest-post/l-post-1.jpg b/theme_lego/static/src/img/blog/latest-post/l-post-1.jpg
new file mode 100644
index 0000000000..1eca2b83dc
Binary files /dev/null and b/theme_lego/static/src/img/blog/latest-post/l-post-1.jpg differ
diff --git a/theme_lego/static/src/img/blog/latest-post/l-post-2.jpg b/theme_lego/static/src/img/blog/latest-post/l-post-2.jpg
new file mode 100644
index 0000000000..8af01ea6b4
Binary files /dev/null and b/theme_lego/static/src/img/blog/latest-post/l-post-2.jpg differ
diff --git a/theme_lego/static/src/img/blog/latest-post/l-post-3.jpg b/theme_lego/static/src/img/blog/latest-post/l-post-3.jpg
new file mode 100644
index 0000000000..18560feb31
Binary files /dev/null and b/theme_lego/static/src/img/blog/latest-post/l-post-3.jpg differ
diff --git a/theme_lego/static/src/img/blog/latest-post/l-post-4.jpg b/theme_lego/static/src/img/blog/latest-post/l-post-4.jpg
new file mode 100644
index 0000000000..1e3c4d96a6
Binary files /dev/null and b/theme_lego/static/src/img/blog/latest-post/l-post-4.jpg differ
diff --git a/theme_lego/static/src/img/blog/main-blog/m-blog-1.jpg b/theme_lego/static/src/img/blog/main-blog/m-blog-1.jpg
new file mode 100644
index 0000000000..ef842e9a85
Binary files /dev/null and b/theme_lego/static/src/img/blog/main-blog/m-blog-1.jpg differ
diff --git a/theme_lego/static/src/img/blog/main-blog/m-blog-2.jpg b/theme_lego/static/src/img/blog/main-blog/m-blog-2.jpg
new file mode 100644
index 0000000000..2ea1b791c2
Binary files /dev/null and b/theme_lego/static/src/img/blog/main-blog/m-blog-2.jpg differ
diff --git a/theme_lego/static/src/img/blog/main-blog/m-blog-3.jpg b/theme_lego/static/src/img/blog/main-blog/m-blog-3.jpg
new file mode 100644
index 0000000000..588a609e07
Binary files /dev/null and b/theme_lego/static/src/img/blog/main-blog/m-blog-3.jpg differ
diff --git a/theme_lego/static/src/img/blog/main-blog/m-blog-4.jpg b/theme_lego/static/src/img/blog/main-blog/m-blog-4.jpg
new file mode 100644
index 0000000000..f71baa0c7d
Binary files /dev/null and b/theme_lego/static/src/img/blog/main-blog/m-blog-4.jpg differ
diff --git a/theme_lego/static/src/img/blog/main-blog/m-blog-5.jpg b/theme_lego/static/src/img/blog/main-blog/m-blog-5.jpg
new file mode 100644
index 0000000000..f81e833075
Binary files /dev/null and b/theme_lego/static/src/img/blog/main-blog/m-blog-5.jpg differ
diff --git a/theme_lego/static/src/img/blog/next.jpg b/theme_lego/static/src/img/blog/next.jpg
new file mode 100644
index 0000000000..03134da3b0
Binary files /dev/null and b/theme_lego/static/src/img/blog/next.jpg differ
diff --git a/theme_lego/static/src/img/blog/popular-post/post1.jpg b/theme_lego/static/src/img/blog/popular-post/post1.jpg
new file mode 100644
index 0000000000..4c1de36442
Binary files /dev/null and b/theme_lego/static/src/img/blog/popular-post/post1.jpg differ
diff --git a/theme_lego/static/src/img/blog/popular-post/post2.jpg b/theme_lego/static/src/img/blog/popular-post/post2.jpg
new file mode 100644
index 0000000000..1651ec924a
Binary files /dev/null and b/theme_lego/static/src/img/blog/popular-post/post2.jpg differ
diff --git a/theme_lego/static/src/img/blog/popular-post/post3.jpg b/theme_lego/static/src/img/blog/popular-post/post3.jpg
new file mode 100644
index 0000000000..3562e9bc4d
Binary files /dev/null and b/theme_lego/static/src/img/blog/popular-post/post3.jpg differ
diff --git a/theme_lego/static/src/img/blog/popular-post/post4.jpg b/theme_lego/static/src/img/blog/popular-post/post4.jpg
new file mode 100644
index 0000000000..3e83c192d0
Binary files /dev/null and b/theme_lego/static/src/img/blog/popular-post/post4.jpg differ
diff --git a/theme_lego/static/src/img/blog/post-img1.jpg b/theme_lego/static/src/img/blog/post-img1.jpg
new file mode 100644
index 0000000000..205cb40b49
Binary files /dev/null and b/theme_lego/static/src/img/blog/post-img1.jpg differ
diff --git a/theme_lego/static/src/img/blog/post-img2.jpg b/theme_lego/static/src/img/blog/post-img2.jpg
new file mode 100644
index 0000000000..cb10676754
Binary files /dev/null and b/theme_lego/static/src/img/blog/post-img2.jpg differ
diff --git a/theme_lego/static/src/img/blog/prev.jpg b/theme_lego/static/src/img/blog/prev.jpg
new file mode 100644
index 0000000000..f27c826ab9
Binary files /dev/null and b/theme_lego/static/src/img/blog/prev.jpg differ
diff --git a/theme_lego/static/src/img/brand/1.png b/theme_lego/static/src/img/brand/1.png
new file mode 100644
index 0000000000..e22bce5aa7
Binary files /dev/null and b/theme_lego/static/src/img/brand/1.png differ
diff --git a/theme_lego/static/src/img/brand/2.png b/theme_lego/static/src/img/brand/2.png
new file mode 100644
index 0000000000..a9faf47fc1
Binary files /dev/null and b/theme_lego/static/src/img/brand/2.png differ
diff --git a/theme_lego/static/src/img/brand/3.png b/theme_lego/static/src/img/brand/3.png
new file mode 100644
index 0000000000..4d58ae9073
Binary files /dev/null and b/theme_lego/static/src/img/brand/3.png differ
diff --git a/theme_lego/static/src/img/brand/4.png b/theme_lego/static/src/img/brand/4.png
new file mode 100644
index 0000000000..33c2a4febc
Binary files /dev/null and b/theme_lego/static/src/img/brand/4.png differ
diff --git a/theme_lego/static/src/img/brand/5.png b/theme_lego/static/src/img/brand/5.png
new file mode 100644
index 0000000000..796e04bd82
Binary files /dev/null and b/theme_lego/static/src/img/brand/5.png differ
diff --git a/theme_lego/static/src/img/cart.jpg b/theme_lego/static/src/img/cart.jpg
new file mode 100644
index 0000000000..253108344e
Binary files /dev/null and b/theme_lego/static/src/img/cart.jpg differ
diff --git a/theme_lego/static/src/img/cart2.jpg b/theme_lego/static/src/img/cart2.jpg
new file mode 100644
index 0000000000..41037751fb
Binary files /dev/null and b/theme_lego/static/src/img/cart2.jpg differ
diff --git a/theme_lego/static/src/img/category/c1.jpg b/theme_lego/static/src/img/category/c1.jpg
new file mode 100644
index 0000000000..714d5990a5
Binary files /dev/null and b/theme_lego/static/src/img/category/c1.jpg differ
diff --git a/theme_lego/static/src/img/category/c1L.jpg b/theme_lego/static/src/img/category/c1L.jpg
new file mode 100644
index 0000000000..399a0c920b
Binary files /dev/null and b/theme_lego/static/src/img/category/c1L.jpg differ
diff --git a/theme_lego/static/src/img/category/c2.jpg b/theme_lego/static/src/img/category/c2.jpg
new file mode 100644
index 0000000000..ea45d029ba
Binary files /dev/null and b/theme_lego/static/src/img/category/c2.jpg differ
diff --git a/theme_lego/static/src/img/category/c2L.jpg b/theme_lego/static/src/img/category/c2L.jpg
new file mode 100644
index 0000000000..1f414023bd
Binary files /dev/null and b/theme_lego/static/src/img/category/c2L.jpg differ
diff --git a/theme_lego/static/src/img/category/c3.jpg b/theme_lego/static/src/img/category/c3.jpg
new file mode 100644
index 0000000000..d1952b0a65
Binary files /dev/null and b/theme_lego/static/src/img/category/c3.jpg differ
diff --git a/theme_lego/static/src/img/category/c3L.jpg b/theme_lego/static/src/img/category/c3L.jpg
new file mode 100644
index 0000000000..f870e43136
Binary files /dev/null and b/theme_lego/static/src/img/category/c3L.jpg differ
diff --git a/theme_lego/static/src/img/category/c4.jpg b/theme_lego/static/src/img/category/c4.jpg
new file mode 100644
index 0000000000..828980f5bb
Binary files /dev/null and b/theme_lego/static/src/img/category/c4.jpg differ
diff --git a/theme_lego/static/src/img/category/c4L.jpg b/theme_lego/static/src/img/category/c4L.jpg
new file mode 100644
index 0000000000..11e06e1111
Binary files /dev/null and b/theme_lego/static/src/img/category/c4L.jpg differ
diff --git a/theme_lego/static/src/img/category/c5.jpg b/theme_lego/static/src/img/category/c5.jpg
new file mode 100644
index 0000000000..1ac8b3017b
Binary files /dev/null and b/theme_lego/static/src/img/category/c5.jpg differ
diff --git a/theme_lego/static/src/img/category/pexels-markus-spiske-191159.jpg b/theme_lego/static/src/img/category/pexels-markus-spiske-191159.jpg
new file mode 100644
index 0000000000..8814e41912
Binary files /dev/null and b/theme_lego/static/src/img/category/pexels-markus-spiske-191159.jpg differ
diff --git a/theme_lego/static/src/img/category/s-p1.jpg b/theme_lego/static/src/img/category/s-p1.jpg
new file mode 100644
index 0000000000..6fa789b6f5
Binary files /dev/null and b/theme_lego/static/src/img/category/s-p1.jpg differ
diff --git a/theme_lego/static/src/img/deals/pexels-min-an-1437149.jpg b/theme_lego/static/src/img/deals/pexels-min-an-1437149.jpg
new file mode 100644
index 0000000000..ff8dc1f8c0
Binary files /dev/null and b/theme_lego/static/src/img/deals/pexels-min-an-1437149.jpg differ
diff --git a/theme_lego/static/src/img/deals/pexels-ray-piedra-1478441.jpg b/theme_lego/static/src/img/deals/pexels-ray-piedra-1478441.jpg
new file mode 100644
index 0000000000..fbcf3806d4
Binary files /dev/null and b/theme_lego/static/src/img/deals/pexels-ray-piedra-1478441.jpg differ
diff --git a/theme_lego/static/src/img/deals/pexels-ray-piedra-1537671.jpg b/theme_lego/static/src/img/deals/pexels-ray-piedra-1537671.jpg
new file mode 100644
index 0000000000..ef6271ec37
Binary files /dev/null and b/theme_lego/static/src/img/deals/pexels-ray-piedra-1537671.jpg differ
diff --git a/theme_lego/static/src/img/deals/pexels-wallace-chuck-2838793.jpg b/theme_lego/static/src/img/deals/pexels-wallace-chuck-2838793.jpg
new file mode 100644
index 0000000000..c6cf076668
Binary files /dev/null and b/theme_lego/static/src/img/deals/pexels-wallace-chuck-2838793.jpg differ
diff --git a/theme_lego/static/src/img/deals/pexels-wallace-chuck-3261069.jpg b/theme_lego/static/src/img/deals/pexels-wallace-chuck-3261069.jpg
new file mode 100644
index 0000000000..8cbe433fd0
Binary files /dev/null and b/theme_lego/static/src/img/deals/pexels-wallace-chuck-3261069.jpg differ
diff --git a/theme_lego/static/src/img/deals/r1.jpg b/theme_lego/static/src/img/deals/r1.jpg
new file mode 100644
index 0000000000..af2cd29d4d
Binary files /dev/null and b/theme_lego/static/src/img/deals/r1.jpg differ
diff --git a/theme_lego/static/src/img/deals/r10.jpg b/theme_lego/static/src/img/deals/r10.jpg
new file mode 100644
index 0000000000..4a81b8ab6f
Binary files /dev/null and b/theme_lego/static/src/img/deals/r10.jpg differ
diff --git a/theme_lego/static/src/img/deals/r11.jpg b/theme_lego/static/src/img/deals/r11.jpg
new file mode 100644
index 0000000000..b0f54c26c4
Binary files /dev/null and b/theme_lego/static/src/img/deals/r11.jpg differ
diff --git a/theme_lego/static/src/img/deals/r12.jpg b/theme_lego/static/src/img/deals/r12.jpg
new file mode 100644
index 0000000000..7f0cc9a31c
Binary files /dev/null and b/theme_lego/static/src/img/deals/r12.jpg differ
diff --git a/theme_lego/static/src/img/deals/r2.jpg b/theme_lego/static/src/img/deals/r2.jpg
new file mode 100644
index 0000000000..ef02f14f71
Binary files /dev/null and b/theme_lego/static/src/img/deals/r2.jpg differ
diff --git a/theme_lego/static/src/img/deals/r3.jpg b/theme_lego/static/src/img/deals/r3.jpg
new file mode 100644
index 0000000000..62ec4bc579
Binary files /dev/null and b/theme_lego/static/src/img/deals/r3.jpg differ
diff --git a/theme_lego/static/src/img/deals/r4.jpg b/theme_lego/static/src/img/deals/r4.jpg
new file mode 100644
index 0000000000..48a747b2ce
Binary files /dev/null and b/theme_lego/static/src/img/deals/r4.jpg differ
diff --git a/theme_lego/static/src/img/deals/r5.jpg b/theme_lego/static/src/img/deals/r5.jpg
new file mode 100644
index 0000000000..cb62303bc3
Binary files /dev/null and b/theme_lego/static/src/img/deals/r5.jpg differ
diff --git a/theme_lego/static/src/img/deals/r6.jpg b/theme_lego/static/src/img/deals/r6.jpg
new file mode 100644
index 0000000000..f4c6315e90
Binary files /dev/null and b/theme_lego/static/src/img/deals/r6.jpg differ
diff --git a/theme_lego/static/src/img/deals/r7.jpg b/theme_lego/static/src/img/deals/r7.jpg
new file mode 100644
index 0000000000..a75b4eaee2
Binary files /dev/null and b/theme_lego/static/src/img/deals/r7.jpg differ
diff --git a/theme_lego/static/src/img/deals/r8.jpg b/theme_lego/static/src/img/deals/r8.jpg
new file mode 100644
index 0000000000..5a8555f9c9
Binary files /dev/null and b/theme_lego/static/src/img/deals/r8.jpg differ
diff --git a/theme_lego/static/src/img/deals/r9.jpg b/theme_lego/static/src/img/deals/r9.jpg
new file mode 100644
index 0000000000..8e5071f0e8
Binary files /dev/null and b/theme_lego/static/src/img/deals/r9.jpg differ
diff --git a/theme_lego/static/src/img/deals/xcx.jpg b/theme_lego/static/src/img/deals/xcx.jpg
new file mode 100644
index 0000000000..c63d61acbb
Binary files /dev/null and b/theme_lego/static/src/img/deals/xcx.jpg differ
diff --git a/theme_lego/static/src/img/exclusive.jpg b/theme_lego/static/src/img/exclusive.jpg
new file mode 100644
index 0000000000..e73ba12901
Binary files /dev/null and b/theme_lego/static/src/img/exclusive.jpg differ
diff --git a/theme_lego/static/src/img/instagram/i1.jpg b/theme_lego/static/src/img/instagram/i1.jpg
new file mode 100644
index 0000000000..36fead4701
Binary files /dev/null and b/theme_lego/static/src/img/instagram/i1.jpg differ
diff --git a/theme_lego/static/src/img/instagram/i2.jpg b/theme_lego/static/src/img/instagram/i2.jpg
new file mode 100644
index 0000000000..9446b574e6
Binary files /dev/null and b/theme_lego/static/src/img/instagram/i2.jpg differ
diff --git a/theme_lego/static/src/img/instagram/i3.jpg b/theme_lego/static/src/img/instagram/i3.jpg
new file mode 100644
index 0000000000..9d865c518c
Binary files /dev/null and b/theme_lego/static/src/img/instagram/i3.jpg differ
diff --git a/theme_lego/static/src/img/instagram/i4.jpg b/theme_lego/static/src/img/instagram/i4.jpg
new file mode 100644
index 0000000000..ed75c2e9f5
Binary files /dev/null and b/theme_lego/static/src/img/instagram/i4.jpg differ
diff --git a/theme_lego/static/src/img/instagram/i5.jpg b/theme_lego/static/src/img/instagram/i5.jpg
new file mode 100644
index 0000000000..99a5606255
Binary files /dev/null and b/theme_lego/static/src/img/instagram/i5.jpg differ
diff --git a/theme_lego/static/src/img/instagram/i6.jpg b/theme_lego/static/src/img/instagram/i6.jpg
new file mode 100644
index 0000000000..8d930ae189
Binary files /dev/null and b/theme_lego/static/src/img/instagram/i6.jpg differ
diff --git a/theme_lego/static/src/img/instagram/i7.jpg b/theme_lego/static/src/img/instagram/i7.jpg
new file mode 100644
index 0000000000..17f3a26d59
Binary files /dev/null and b/theme_lego/static/src/img/instagram/i7.jpg differ
diff --git a/theme_lego/static/src/img/instagram/i8.jpg b/theme_lego/static/src/img/instagram/i8.jpg
new file mode 100644
index 0000000000..9446b574e6
Binary files /dev/null and b/theme_lego/static/src/img/instagram/i8.jpg differ
diff --git a/theme_lego/static/src/img/l.jpg b/theme_lego/static/src/img/l.jpg
new file mode 100644
index 0000000000..0e0b8fa0c4
Binary files /dev/null and b/theme_lego/static/src/img/l.jpg differ
diff --git a/theme_lego/static/src/img/login/login.jpg b/theme_lego/static/src/img/login/login.jpg
new file mode 100644
index 0000000000..bf68cc88f0
Binary files /dev/null and b/theme_lego/static/src/img/login/login.jpg differ
diff --git a/theme_lego/static/src/img/product/P1.jpg b/theme_lego/static/src/img/product/P1.jpg
new file mode 100644
index 0000000000..4cc7b97d08
Binary files /dev/null and b/theme_lego/static/src/img/product/P1.jpg differ
diff --git a/theme_lego/static/src/img/product/e-p1.jpg b/theme_lego/static/src/img/product/e-p1.jpg
new file mode 100644
index 0000000000..ed54c43c75
Binary files /dev/null and b/theme_lego/static/src/img/product/e-p1.jpg differ
diff --git a/theme_lego/static/src/img/product/p2.jpg b/theme_lego/static/src/img/product/p2.jpg
new file mode 100644
index 0000000000..7bca589fe1
Binary files /dev/null and b/theme_lego/static/src/img/product/p2.jpg differ
diff --git a/theme_lego/static/src/img/product/p3.jpg b/theme_lego/static/src/img/product/p3.jpg
new file mode 100644
index 0000000000..e15802934c
Binary files /dev/null and b/theme_lego/static/src/img/product/p3.jpg differ
diff --git a/theme_lego/static/src/img/product/p4.jpg b/theme_lego/static/src/img/product/p4.jpg
new file mode 100644
index 0000000000..fcd4ac498c
Binary files /dev/null and b/theme_lego/static/src/img/product/p4.jpg differ
diff --git a/theme_lego/static/src/img/product/p5.jpg b/theme_lego/static/src/img/product/p5.jpg
new file mode 100644
index 0000000000..6de0b1a891
Binary files /dev/null and b/theme_lego/static/src/img/product/p5.jpg differ
diff --git a/theme_lego/static/src/img/product/p6.jpg b/theme_lego/static/src/img/product/p6.jpg
new file mode 100644
index 0000000000..fdba4266dd
Binary files /dev/null and b/theme_lego/static/src/img/product/p6.jpg differ
diff --git a/theme_lego/static/src/img/product/p7.jpg b/theme_lego/static/src/img/product/p7.jpg
new file mode 100644
index 0000000000..5f5fb28166
Binary files /dev/null and b/theme_lego/static/src/img/product/p7.jpg differ
diff --git a/theme_lego/static/src/img/product/p8.jpg b/theme_lego/static/src/img/product/p8.jpg
new file mode 100644
index 0000000000..7b443b8615
Binary files /dev/null and b/theme_lego/static/src/img/product/p8.jpg differ
diff --git a/theme_lego/static/src/img/product/pexels-melvin-buezo-2529158.jpg b/theme_lego/static/src/img/product/pexels-melvin-buezo-2529158.jpg
new file mode 100644
index 0000000000..46ffc78f9f
Binary files /dev/null and b/theme_lego/static/src/img/product/pexels-melvin-buezo-2529158.jpg differ
diff --git a/theme_lego/static/src/img/product/pexels-mister-mister-3490360.jpg b/theme_lego/static/src/img/product/pexels-mister-mister-3490360.jpg
new file mode 100644
index 0000000000..c0047b1d32
Binary files /dev/null and b/theme_lego/static/src/img/product/pexels-mister-mister-3490360.jpg differ
diff --git a/theme_lego/static/src/img/product/pexels-ray-piedra-1456706.jpg b/theme_lego/static/src/img/product/pexels-ray-piedra-1456706.jpg
new file mode 100644
index 0000000000..8a14cb32b6
Binary files /dev/null and b/theme_lego/static/src/img/product/pexels-ray-piedra-1456706.jpg differ
diff --git a/theme_lego/static/src/img/product/review-1.png b/theme_lego/static/src/img/product/review-1.png
new file mode 100644
index 0000000000..81924ae01d
Binary files /dev/null and b/theme_lego/static/src/img/product/review-1.png differ
diff --git a/theme_lego/static/src/img/product/review-2.png b/theme_lego/static/src/img/product/review-2.png
new file mode 100644
index 0000000000..dd56a79d07
Binary files /dev/null and b/theme_lego/static/src/img/product/review-2.png differ
diff --git a/theme_lego/static/src/img/product/review-3.png b/theme_lego/static/src/img/product/review-3.png
new file mode 100644
index 0000000000..d1d54aeb9e
Binary files /dev/null and b/theme_lego/static/src/img/product/review-3.png differ
diff --git a/theme_lego/static/src/img/sd/c1.jpg b/theme_lego/static/src/img/sd/c1.jpg
new file mode 100644
index 0000000000..21b802d519
Binary files /dev/null and b/theme_lego/static/src/img/sd/c1.jpg differ
diff --git a/theme_lego/static/src/img/sd/c2.jpg b/theme_lego/static/src/img/sd/c2.jpg
new file mode 100644
index 0000000000..fd983d9bad
Binary files /dev/null and b/theme_lego/static/src/img/sd/c2.jpg differ
diff --git a/theme_lego/static/src/img/sd/c3.jpg b/theme_lego/static/src/img/sd/c3.jpg
new file mode 100644
index 0000000000..c4a5c315fd
Binary files /dev/null and b/theme_lego/static/src/img/sd/c3.jpg differ
diff --git a/theme_lego/static/src/img/sd/c4.jpg b/theme_lego/static/src/img/sd/c4.jpg
new file mode 100644
index 0000000000..1ab87ddd67
Binary files /dev/null and b/theme_lego/static/src/img/sd/c4.jpg differ
diff --git a/theme_lego/static/src/img/sd/c5.jpg b/theme_lego/static/src/img/sd/c5.jpg
new file mode 100644
index 0000000000..57e90fe384
Binary files /dev/null and b/theme_lego/static/src/img/sd/c5.jpg differ
diff --git a/theme_lego/static/src/img/snippets/banner-block.jpg b/theme_lego/static/src/img/snippets/banner-block.jpg
new file mode 100644
index 0000000000..3a5423a3fd
Binary files /dev/null and b/theme_lego/static/src/img/snippets/banner-block.jpg differ
diff --git a/theme_lego/static/src/img/snippets/brands-block.jpg b/theme_lego/static/src/img/snippets/brands-block.jpg
new file mode 100644
index 0000000000..c304fb71b4
Binary files /dev/null and b/theme_lego/static/src/img/snippets/brands-block.jpg differ
diff --git a/theme_lego/static/src/img/snippets/contact-block.jpg b/theme_lego/static/src/img/snippets/contact-block.jpg
new file mode 100644
index 0000000000..772d5914de
Binary files /dev/null and b/theme_lego/static/src/img/snippets/contact-block.jpg differ
diff --git a/theme_lego/static/src/img/snippets/deals-of-the-day-blocks.jpg b/theme_lego/static/src/img/snippets/deals-of-the-day-blocks.jpg
new file mode 100644
index 0000000000..13fce2bb71
Binary files /dev/null and b/theme_lego/static/src/img/snippets/deals-of-the-day-blocks.jpg differ
diff --git a/theme_lego/static/src/img/snippets/front-gallery-block.jpg b/theme_lego/static/src/img/snippets/front-gallery-block.jpg
new file mode 100644
index 0000000000..e3b5657c23
Binary files /dev/null and b/theme_lego/static/src/img/snippets/front-gallery-block.jpg differ
diff --git a/theme_lego/static/src/img/snippets/half-columns-block.jpg b/theme_lego/static/src/img/snippets/half-columns-block.jpg
new file mode 100644
index 0000000000..65cbec636f
Binary files /dev/null and b/theme_lego/static/src/img/snippets/half-columns-block.jpg differ
diff --git a/theme_lego/static/src/img/snippets/home-banner-blockt.jpg b/theme_lego/static/src/img/snippets/home-banner-blockt.jpg
new file mode 100644
index 0000000000..50b10d4d30
Binary files /dev/null and b/theme_lego/static/src/img/snippets/home-banner-blockt.jpg differ
diff --git a/theme_lego/static/src/img/snippets/login-block.jpg b/theme_lego/static/src/img/snippets/login-block.jpg
new file mode 100644
index 0000000000..32f08d9efc
Binary files /dev/null and b/theme_lego/static/src/img/snippets/login-block.jpg differ
diff --git a/theme_lego/static/src/img/snippets/map-block.jpg b/theme_lego/static/src/img/snippets/map-block.jpg
new file mode 100644
index 0000000000..9fe9cfebc0
Binary files /dev/null and b/theme_lego/static/src/img/snippets/map-block.jpg differ
diff --git a/theme_lego/static/src/img/snippets/services-block.jpg b/theme_lego/static/src/img/snippets/services-block.jpg
new file mode 100644
index 0000000000..e00924ad70
Binary files /dev/null and b/theme_lego/static/src/img/snippets/services-block.jpg differ
diff --git a/theme_lego/static/src/img/snippets/upcoming-products-blocks.jpg b/theme_lego/static/src/img/snippets/upcoming-products-blocks.jpg
new file mode 100644
index 0000000000..5613f6bb21
Binary files /dev/null and b/theme_lego/static/src/img/snippets/upcoming-products-blocks.jpg differ
diff --git a/theme_lego/static/src/js/deal.js b/theme_lego/static/src/js/deal.js
new file mode 100644
index 0000000000..6f0cc6ef34
--- /dev/null
+++ b/theme_lego/static/src/js/deal.js
@@ -0,0 +1,18 @@
+/** @odoo-module **/
+
+import { rpc } from "@web/core/network/rpc";
+import publicWidget from "@web/legacy/js/public/public_widget";
+import animations from "@website/js/content/snippets.animation";
+
+publicWidget.registry.DealWeek = animations.Animation.extend({
+ selector: '.deal',
+ async start() {
+ var self = this;
+ // Call backend JSON endpoint to fetch the products marked as 'Deal of the Week'
+ var data = await rpc('/get_deal_of_the_week', {})
+ if (data) {
+ // Render the fetched product information on the webpage
+ self.$target.empty().append(data);
+ }
+ }
+});
diff --git a/theme_lego/static/src/js/index.js b/theme_lego/static/src/js/index.js
new file mode 100644
index 0000000000..88ac92aed9
--- /dev/null
+++ b/theme_lego/static/src/js/index.js
@@ -0,0 +1,30 @@
+/** @odoo-module **/
+// Import the PublicWidget module
+import publicWidget from "@web/legacy/js/public/public_widget";
+// Define a new class named "Slider" that extends the "PublicWidget" class
+publicWidget.registry.slider = publicWidget.Widget.extend({
+ // Set the CSS selector for the widget element
+ selector: '.owl-carousel',
+ start() {
+ // Call the "onSlider" function to initialize the owlCarousel slider
+ this.onSlider();
+ },
+ // Define the "onSlider" function that initializes the owlCarousel slider
+ onSlider() {
+ // Initialize the slider with owlCarousel options
+ this.$el.owlCarousel({
+ items: 1,
+ loop: true,
+ margin: 30,
+ stagePadding: 30,
+ smartSpeed: 450,
+ autoplay: true,
+ autoPlaySpeed: 1000,
+ autoPlayTimeout: 1000,
+ autoplayHoverPause: true,
+ dots: true,
+ nav: true,
+ navText: [' ', ' ']
+ });
+ }
+});
\ No newline at end of file
diff --git a/theme_lego/static/src/js/owl.carousel.js b/theme_lego/static/src/js/owl.carousel.js
new file mode 100644
index 0000000000..e65140ad58
--- /dev/null
+++ b/theme_lego/static/src/js/owl.carousel.js
@@ -0,0 +1,2951 @@
+/**
+ * Owl Carousel v2.3.4
+ * Copyright 2013-2018 David Deutsch
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
+ */
+/**
+ * Owl carousel
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ * @todo Lazy Load Icon
+ * @todo prevent animationend bubling
+ * @todo itemsScaleUp
+ * @todo Test Zepto
+ * @todo stagePadding calculate wrong active classes
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates a carousel.
+ * @class The Owl Carousel.
+ * @public
+ * @param {HTMLElement|jQuery} element - The element to create the carousel for.
+ * @param {Object} [options] - The options
+ */
+ function Owl(element, options) {
+ /**
+ * Current settings for the carousel.
+ * @public
+ */
+ this.settings = null;
+ /**
+ * Current options set by the caller including defaults.
+ * @public
+ */
+ this.options = $.extend({}, Owl.Defaults, options);
+ /**
+ * Plugin element.
+ * @public
+ */
+ this.$element = $(element);
+ /**
+ * Proxied event handlers.
+ * @protected
+ */
+ this._handlers = {};
+ /**
+ * References to the running plugins of this carousel.
+ * @protected
+ */
+ this._plugins = {};
+ /**
+ * Currently suppressed events to prevent them from being retriggered.
+ * @protected
+ */
+ this._supress = {};
+ /**
+ * Absolute current position.
+ * @protected
+ */
+ this._current = null;
+ /**
+ * Animation speed in milliseconds.
+ * @protected
+ */
+ this._speed = null;
+ /**
+ * Coordinates of all items in pixel.
+ * @todo The name of this member is missleading.
+ * @protected
+ */
+ this._coordinates = [];
+ /**
+ * Current breakpoint.
+ * @todo Real media queries would be nice.
+ * @protected
+ */
+ this._breakpoint = null;
+ /**
+ * Current width of the plugin element.
+ */
+ this._width = null;
+ /**
+ * All real items.
+ * @protected
+ */
+ this._items = [];
+ /**
+ * All cloned items.
+ * @protected
+ */
+ this._clones = [];
+ /**
+ * Merge values of all items.
+ * @todo Maybe this could be part of a plugin.
+ * @protected
+ */
+ this._mergers = [];
+ /**
+ * Widths of all items.
+ */
+ this._widths = [];
+ /**
+ * Invalidated parts within the update process.
+ * @protected
+ */
+ this._invalidated = {};
+ /**
+ * Ordered list of workers for the update process.
+ * @protected
+ */
+ this._pipe = [];
+ /**
+ * Current state information for the drag operation.
+ * @todo #261
+ * @protected
+ */
+ this._drag = {
+ time: null,
+ target: null,
+ pointer: null,
+ stage: {
+ start: null,
+ current: null
+ },
+ direction: null
+ };
+ /**
+ * Current state information and their tags.
+ * @type {Object}
+ * @protected
+ */
+ this._states = {
+ current: {},
+ tags: {
+ 'initializing': [ 'busy' ],
+ 'animating': [ 'busy' ],
+ 'dragging': [ 'interacting' ]
+ }
+ };
+ $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
+ this._handlers[handler] = $.proxy(this[handler], this);
+ }, this));
+ $.each(Owl.Plugins, $.proxy(function(key, plugin) {
+ this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
+ = new plugin(this);
+ }, this));
+ $.each(Owl.Workers, $.proxy(function(priority, worker) {
+ this._pipe.push({
+ 'filter': worker.filter,
+ 'run': $.proxy(worker.run, this)
+ });
+ }, this));
+ this.setup();
+ this.initialize();
+ }
+ /**
+ * Default options for the carousel.
+ * @public
+ */
+ Owl.Defaults = {
+ items: 3,
+ loop: false,
+ center: false,
+ rewind: false,
+ checkVisibility: true,
+ mouseDrag: true,
+ touchDrag: true,
+ pullDrag: true,
+ freeDrag: false,
+ margin: 0,
+ stagePadding: 0,
+ merge: false,
+ mergeFit: true,
+ autoWidth: false,
+ startPosition: 0,
+ rtl: false,
+ smartSpeed: 250,
+ fluidSpeed: false,
+ dragEndSpeed: false,
+ responsive: {},
+ responsiveRefreshRate: 200,
+ responsiveBaseElement: window,
+ fallbackEasing: 'swing',
+ slideTransition: '',
+ info: false,
+ nestedItemSelector: false,
+ itemElement: 'div',
+ stageElement: 'div',
+ refreshClass: 'owl-refresh',
+ loadedClass: 'owl-loaded',
+ loadingClass: 'owl-loading',
+ rtlClass: 'owl-rtl',
+ responsiveClass: 'owl-responsive',
+ dragClass: 'owl-drag',
+ itemClass: 'owl-item',
+ stageClass: 'owl-stage',
+ stageOuterClass: 'owl-stage-outer',
+ grabClass: 'owl-grab'
+ };
+ /**
+ * Enumeration for width.
+ * @public
+ * @readonly
+ * @enum {String}
+ */
+ Owl.Width = {
+ Default: 'default',
+ Inner: 'inner',
+ Outer: 'outer'
+ };
+ /**
+ * Enumeration for types.
+ * @public
+ * @readonly
+ * @enum {String}
+ */
+ Owl.Type = {
+ Event: 'event',
+ State: 'state'
+ };
+ /**
+ * Contains all registered plugins.
+ * @public
+ */
+ Owl.Plugins = {};
+ /**
+ * List of workers involved in the update process.
+ */
+ Owl.Workers = [ {
+ filter: [ 'width', 'settings' ],
+ run: function() {
+ this._width = this.$element.width();
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ cache.current = this._items && this._items[this.relative(this._current)];
+ }
+ }, {
+ filter: [ 'items', 'settings' ],
+ run: function() {
+ this.$stage.children('.cloned').remove();
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ var margin = this.settings.margin || '',
+ grid = !this.settings.autoWidth,
+ rtl = this.settings.rtl,
+ css = {
+ 'width': 'auto',
+ 'margin-left': rtl ? margin : '',
+ 'margin-right': rtl ? '' : margin
+ };
+ !grid && this.$stage.children().css(css);
+ cache.css = css;
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
+ merge = null,
+ iterator = this._items.length,
+ grid = !this.settings.autoWidth,
+ widths = [];
+ cache.items = {
+ merge: false,
+ width: width
+ };
+ while (iterator--) {
+ merge = this._mergers[iterator];
+ merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
+ cache.items.merge = merge > 1 || cache.items.merge;
+ widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
+ }
+ this._widths = widths;
+ }
+ }, {
+ filter: [ 'items', 'settings' ],
+ run: function() {
+ var clones = [],
+ items = this._items,
+ settings = this.settings,
+ // TODO: Should be computed from number of min width items in stage
+ view = Math.max(settings.items * 2, 4),
+ size = Math.ceil(items.length / 2) * 2,
+ repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
+ append = '',
+ prepend = '';
+ repeat /= 2;
+ while (repeat > 0) {
+ // Switch to only using appended clones
+ clones.push(this.normalize(clones.length / 2, true));
+ append = append + items[clones[clones.length - 1]][0].outerHTML;
+ clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
+ prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
+ repeat -= 1;
+ }
+ this._clones = clones;
+ $(append).addClass('cloned').appendTo(this.$stage);
+ $(prepend).addClass('cloned').prependTo(this.$stage);
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function() {
+ var rtl = this.settings.rtl ? 1 : -1,
+ size = this._clones.length + this._items.length,
+ iterator = -1,
+ previous = 0,
+ current = 0,
+ coordinates = [];
+ while (++iterator < size) {
+ previous = coordinates[iterator - 1] || 0;
+ current = this._widths[this.relative(iterator)] + this.settings.margin;
+ coordinates.push(previous + current * rtl);
+ }
+ this._coordinates = coordinates;
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function() {
+ var padding = this.settings.stagePadding,
+ coordinates = this._coordinates,
+ css = {
+ 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
+ 'padding-left': padding || '',
+ 'padding-right': padding || ''
+ };
+ this.$stage.css(css);
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ var iterator = this._coordinates.length,
+ grid = !this.settings.autoWidth,
+ items = this.$stage.children();
+ if (grid && cache.items.merge) {
+ while (iterator--) {
+ cache.css.width = this._widths[this.relative(iterator)];
+ items.eq(iterator).css(cache.css);
+ }
+ } else if (grid) {
+ cache.css.width = cache.items.width;
+ items.css(cache.css);
+ }
+ }
+ }, {
+ filter: [ 'items' ],
+ run: function() {
+ this._coordinates.length < 1 && this.$stage.removeAttr('style');
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
+ cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
+ this.reset(cache.current);
+ }
+ }, {
+ filter: [ 'position' ],
+ run: function() {
+ this.animate(this.coordinates(this._current));
+ }
+ }, {
+ filter: [ 'width', 'position', 'items', 'settings' ],
+ run: function() {
+ var rtl = this.settings.rtl ? 1 : -1,
+ padding = this.settings.stagePadding * 2,
+ begin = this.coordinates(this.current()) + padding,
+ end = begin + this.width() * rtl,
+ inner, outer, matches = [], i, n;
+ for (i = 0, n = this._coordinates.length; i < n; i++) {
+ inner = this._coordinates[i - 1] || 0;
+ outer = Math.abs(this._coordinates[i]) + padding * rtl;
+ if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
+ || (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
+ matches.push(i);
+ }
+ }
+ this.$stage.children('.active').removeClass('active');
+ this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
+ this.$stage.children('.center').removeClass('center');
+ if (this.settings.center) {
+ this.$stage.children().eq(this.current()).addClass('center');
+ }
+ }
+ } ];
+ /**
+ * Create the stage DOM element
+ */
+ Owl.prototype.initializeStage = function() {
+ this.$stage = this.$element.find('.' + this.settings.stageClass);
+ // if the stage is already in the DOM, grab it and skip stage initialization
+ if (this.$stage.length) {
+ return;
+ }
+ this.$element.addClass(this.options.loadingClass);
+ // create stage
+ this.$stage = $('<' + this.settings.stageElement + '>', {
+ "class": this.settings.stageClass
+ }).wrap( $( '
', {
+ "class": this.settings.stageOuterClass
+ }));
+ // append stage
+ this.$element.append(this.$stage.parent());
+ };
+ /**
+ * Create item DOM elements
+ */
+ Owl.prototype.initializeItems = function() {
+ var $items = this.$element.find('.owl-item');
+ // if the items are already in the DOM, grab them and skip item initialization
+ if ($items.length) {
+ this._items = $items.get().map(function(item) {
+ return $(item);
+ });
+ this._mergers = this._items.map(function() {
+ return 1;
+ });
+ this.refresh();
+ return;
+ }
+ // append content
+ this.replace(this.$element.children().not(this.$stage.parent()));
+ // check visibility
+ if (this.isVisible()) {
+ // update view
+ this.refresh();
+ } else {
+ // invalidate width
+ this.invalidate('width');
+ }
+ this.$element
+ .removeClass(this.options.loadingClass)
+ .addClass(this.options.loadedClass);
+ };
+ /**
+ * Initializes the carousel.
+ * @protected
+ */
+ Owl.prototype.initialize = function() {
+ this.enter('initializing');
+ this.trigger('initialize');
+ this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
+ if (this.settings.autoWidth && !this.is('pre-loading')) {
+ var imgs, nestedSelector, width;
+ imgs = this.$element.find('img');
+ nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
+ width = this.$element.children(nestedSelector).width();
+ if (imgs.length && width <= 0) {
+ this.preloadAutoWidthImages(imgs);
+ }
+ }
+ this.initializeStage();
+ this.initializeItems();
+ // register event handlers
+ this.registerEventHandlers();
+ this.leave('initializing');
+ this.trigger('initialized');
+ };
+ /**
+ * @returns {Boolean} visibility of $element
+ * if you know the carousel will always be visible you can set `checkVisibility` to `false` to
+ * prevent the expensive browser layout forced reflow the $element.is(':visible') does
+ */
+ Owl.prototype.isVisible = function() {
+ return this.settings.checkVisibility
+ ? this.$element.is(':visible')
+ : true;
+ };
+ /**
+ * Setups the current settings.
+ * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
+ * @todo Support for media queries by using `matchMedia` would be nice.
+ * @public
+ */
+ Owl.prototype.setup = function() {
+ var viewport = this.viewport(),
+ overwrites = this.options.responsive,
+ match = -1,
+ settings = null;
+ if (!overwrites) {
+ settings = $.extend({}, this.options);
+ } else {
+ $.each(overwrites, function(breakpoint) {
+ if (breakpoint <= viewport && breakpoint > match) {
+ match = Number(breakpoint);
+ }
+ });
+ settings = $.extend({}, this.options, overwrites[match]);
+ if (typeof settings.stagePadding === 'function') {
+ settings.stagePadding = settings.stagePadding();
+ }
+ delete settings.responsive;
+ // responsive class
+ if (settings.responsiveClass) {
+ this.$element.attr('class',
+ this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
+ );
+ }
+ }
+ this.trigger('change', { property: { name: 'settings', value: settings } });
+ this._breakpoint = match;
+ this.settings = settings;
+ this.invalidate('settings');
+ this.trigger('changed', { property: { name: 'settings', value: this.settings } });
+ };
+ /**
+ * Updates option logic if necessery.
+ * @protected
+ */
+ Owl.prototype.optionsLogic = function() {
+ if (this.settings.autoWidth) {
+ this.settings.stagePadding = false;
+ this.settings.merge = false;
+ }
+ };
+ /**
+ * Prepares an item before add.
+ * @todo Rename event parameter `content` to `item`.
+ * @protected
+ * @returns {jQuery|HTMLElement} - The item container.
+ */
+ Owl.prototype.prepare = function(item) {
+ var event = this.trigger('prepare', { content: item });
+ if (!event.data) {
+ event.data = $('<' + this.settings.itemElement + '/>')
+ .addClass(this.options.itemClass).append(item)
+ }
+ this.trigger('prepared', { content: event.data });
+ return event.data;
+ };
+ /**
+ * Updates the view.
+ * @public
+ */
+ Owl.prototype.update = function() {
+ var i = 0,
+ n = this._pipe.length,
+ filter = $.proxy(function(p) { return this[p] }, this._invalidated),
+ cache = {};
+ while (i < n) {
+ if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
+ this._pipe[i].run(cache);
+ }
+ i++;
+ }
+ this._invalidated = {};
+ !this.is('valid') && this.enter('valid');
+ };
+ /**
+ * Gets the width of the view.
+ * @public
+ * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
+ * @returns {Number} - The width of the view in pixel.
+ */
+ Owl.prototype.width = function(dimension) {
+ dimension = dimension || Owl.Width.Default;
+ switch (dimension) {
+ case Owl.Width.Inner:
+ case Owl.Width.Outer:
+ return this._width;
+ default:
+ return this._width - this.settings.stagePadding * 2 + this.settings.margin;
+ }
+ };
+ /**
+ * Refreshes the carousel primarily for adaptive purposes.
+ * @public
+ */
+ Owl.prototype.refresh = function() {
+ this.enter('refreshing');
+ this.trigger('refresh');
+ this.setup();
+ this.optionsLogic();
+ this.$element.addClass(this.options.refreshClass);
+ this.update();
+ this.$element.removeClass(this.options.refreshClass);
+ this.leave('refreshing');
+ this.trigger('refreshed');
+ };
+ /**
+ * Checks window `resize` event.
+ * @protected
+ */
+ Owl.prototype.onThrottledResize = function() {
+ window.clearTimeout(this.resizeTimer);
+ this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
+ };
+ /**
+ * Checks window `resize` event.
+ * @protected
+ */
+ Owl.prototype.onResize = function() {
+ if (!this._items.length) {
+ return false;
+ }
+ if (this._width === this.$element.width()) {
+ return false;
+ }
+ if (!this.isVisible()) {
+ return false;
+ }
+ this.enter('resizing');
+ if (this.trigger('resize').isDefaultPrevented()) {
+ this.leave('resizing');
+ return false;
+ }
+ this.invalidate('width');
+ this.refresh();
+ this.leave('resizing');
+ this.trigger('resized');
+ };
+ /**
+ * Registers event handlers.
+ * @todo Check `msPointerEnabled`
+ * @todo #261
+ * @protected
+ */
+ Owl.prototype.registerEventHandlers = function() {
+ if ($.support.transition) {
+ this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
+ }
+ if (this.settings.responsive !== false) {
+ this.on(window, 'resize', this._handlers.onThrottledResize);
+ }
+ if (this.settings.mouseDrag) {
+ this.$element.addClass(this.options.dragClass);
+ this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
+ this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
+ }
+ if (this.settings.touchDrag){
+ this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
+ this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
+ }
+ };
+ /**
+ * Handles `touchstart` and `mousedown` events.
+ * @todo Horizontal swipe threshold as option
+ * @todo #261
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onDragStart = function(event) {
+ var stage = null;
+ if (event.which === 3) {
+ return;
+ }
+ if ($.support.transform) {
+ stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
+ stage = {
+ x: stage[stage.length === 16 ? 12 : 4],
+ y: stage[stage.length === 16 ? 13 : 5]
+ };
+ } else {
+ stage = this.$stage.position();
+ stage = {
+ x: this.settings.rtl ?
+ stage.left + this.$stage.width() - this.width() + this.settings.margin :
+ stage.left,
+ y: stage.top
+ };
+ }
+ if (this.is('animating')) {
+ $.support.transform ? this.animate(stage.x) : this.$stage.stop()
+ this.invalidate('position');
+ }
+ this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
+ this.speed(0);
+ this._drag.time = new Date().getTime();
+ this._drag.target = $(event.target);
+ this._drag.stage.start = stage;
+ this._drag.stage.current = stage;
+ this._drag.pointer = this.pointer(event);
+ $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
+ $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
+ var delta = this.difference(this._drag.pointer, this.pointer(event));
+ $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
+ if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
+ return;
+ }
+ event.preventDefault();
+ this.enter('dragging');
+ this.trigger('drag');
+ }, this));
+ };
+ /**
+ * Handles the `touchmove` and `mousemove` events.
+ * @todo #261
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onDragMove = function(event) {
+ var minimum = null,
+ maximum = null,
+ pull = null,
+ delta = this.difference(this._drag.pointer, this.pointer(event)),
+ stage = this.difference(this._drag.stage.start, delta);
+ if (!this.is('dragging')) {
+ return;
+ }
+ event.preventDefault();
+ if (this.settings.loop) {
+ minimum = this.coordinates(this.minimum());
+ maximum = this.coordinates(this.maximum() + 1) - minimum;
+ stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
+ } else {
+ minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
+ maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
+ pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
+ stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
+ }
+ this._drag.stage.current = stage;
+ this.animate(stage.x);
+ };
+ /**
+ * Handles the `touchend` and `mouseup` events.
+ * @todo #261
+ * @todo Threshold for click event
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onDragEnd = function(event) {
+ var delta = this.difference(this._drag.pointer, this.pointer(event)),
+ stage = this._drag.stage.current,
+ direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
+ $(document).off('.owl.core');
+ this.$element.removeClass(this.options.grabClass);
+ if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
+ this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
+ this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
+ this.invalidate('position');
+ this.update();
+ this._drag.direction = direction;
+ if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
+ this._drag.target.one('click.owl.core', function() { return false; });
+ }
+ }
+ if (!this.is('dragging')) {
+ return;
+ }
+ this.leave('dragging');
+ this.trigger('dragged');
+ };
+ /**
+ * Gets absolute position of the closest item for a coordinate.
+ * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
+ * @protected
+ * @param {Number} coordinate - The coordinate in pixel.
+ * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
+ * @return {Number} - The absolute position of the closest item.
+ */
+ Owl.prototype.closest = function(coordinate, direction) {
+ var position = -1,
+ pull = 30,
+ width = this.width(),
+ coordinates = this.coordinates();
+ if (!this.settings.freeDrag) {
+ // check closest item
+ $.each(coordinates, $.proxy(function(index, value) {
+ // on a left pull, check on current index
+ if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
+ position = index;
+ // on a right pull, check on previous index
+ // to do so, subtract width from value and set position = index + 1
+ } else if (direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull) {
+ position = index + 1;
+ } else if (this.op(coordinate, '<', value)
+ && this.op(coordinate, '>', coordinates[index + 1] !== undefined ? coordinates[index + 1] : value - width)) {
+ position = direction === 'left' ? index + 1 : index;
+ }
+ return position === -1;
+ }, this));
+ }
+ if (!this.settings.loop) {
+ // non loop boundries
+ if (this.op(coordinate, '>', coordinates[this.minimum()])) {
+ position = coordinate = this.minimum();
+ } else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
+ position = coordinate = this.maximum();
+ }
+ }
+ return position;
+ };
+ /**
+ * Animates the stage.
+ * @todo #270
+ * @public
+ * @param {Number} coordinate - The coordinate in pixels.
+ */
+ Owl.prototype.animate = function(coordinate) {
+ var animate = this.speed() > 0;
+ this.is('animating') && this.onTransitionEnd();
+ if (animate) {
+ this.enter('animating');
+ this.trigger('translate');
+ }
+ if ($.support.transform3d && $.support.transition) {
+ this.$stage.css({
+ transform: 'translate3d(' + coordinate + 'px,0px,0px)',
+ transition: (this.speed() / 1000) + 's' + (
+ this.settings.slideTransition ? ' ' + this.settings.slideTransition : ''
+ )
+ });
+ } else if (animate) {
+ this.$stage.animate({
+ left: coordinate + 'px'
+ }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
+ } else {
+ this.$stage.css({
+ left: coordinate + 'px'
+ });
+ }
+ };
+ /**
+ * Checks whether the carousel is in a specific state or not.
+ * @param {String} state - The state to check.
+ * @returns {Boolean} - The flag which indicates if the carousel is busy.
+ */
+ Owl.prototype.is = function(state) {
+ return this._states.current[state] && this._states.current[state] > 0;
+ };
+ /**
+ * Sets the absolute position of the current item.
+ * @public
+ * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
+ * @returns {Number} - The absolute position of the current item.
+ */
+ Owl.prototype.current = function(position) {
+ if (position === undefined) {
+ return this._current;
+ }
+ if (this._items.length === 0) {
+ return undefined;
+ }
+ position = this.normalize(position);
+ if (this._current !== position) {
+ var event = this.trigger('change', { property: { name: 'position', value: position } });
+ if (event.data !== undefined) {
+ position = this.normalize(event.data);
+ }
+ this._current = position;
+ this.invalidate('position');
+ this.trigger('changed', { property: { name: 'position', value: this._current } });
+ }
+ return this._current;
+ };
+ /**
+ * Invalidates the given part of the update routine.
+ * @param {String} [part] - The part to invalidate.
+ * @returns {Array.} - The invalidated parts.
+ */
+ Owl.prototype.invalidate = function(part) {
+ if ($.type(part) === 'string') {
+ this._invalidated[part] = true;
+ this.is('valid') && this.leave('valid');
+ }
+ return $.map(this._invalidated, function(v, i) { return i });
+ };
+ /**
+ * Resets the absolute position of the current item.
+ * @public
+ * @param {Number} position - The absolute position of the new item.
+ */
+ Owl.prototype.reset = function(position) {
+ position = this.normalize(position);
+ if (position === undefined) {
+ return;
+ }
+ this._speed = 0;
+ this._current = position;
+ this.suppress([ 'translate', 'translated' ]);
+ this.animate(this.coordinates(position));
+ this.release([ 'translate', 'translated' ]);
+ };
+ /**
+ * Normalizes an absolute or a relative position of an item.
+ * @public
+ * @param {Number} position - The absolute or relative position to normalize.
+ * @param {Boolean} [relative=false] - Whether the given position is relative or not.
+ * @returns {Number} - The normalized position.
+ */
+ Owl.prototype.normalize = function(position, relative) {
+ var n = this._items.length,
+ m = relative ? 0 : this._clones.length;
+ if (!this.isNumeric(position) || n < 1) {
+ position = undefined;
+ } else if (position < 0 || position >= n + m) {
+ position = ((position - m / 2) % n + n) % n + m / 2;
+ }
+ return position;
+ };
+ /**
+ * Converts an absolute position of an item into a relative one.
+ * @public
+ * @param {Number} position - The absolute position to convert.
+ * @returns {Number} - The converted position.
+ */
+ Owl.prototype.relative = function(position) {
+ position -= this._clones.length / 2;
+ return this.normalize(position, true);
+ };
+ /**
+ * Gets the maximum position for the current item.
+ * @public
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
+ * @returns {Number}
+ */
+ Owl.prototype.maximum = function(relative) {
+ var settings = this.settings,
+ maximum = this._coordinates.length,
+ iterator,
+ reciprocalItemsWidth,
+ elementWidth;
+ if (settings.loop) {
+ maximum = this._clones.length / 2 + this._items.length - 1;
+ } else if (settings.autoWidth || settings.merge) {
+ iterator = this._items.length;
+ if (iterator) {
+ reciprocalItemsWidth = this._items[--iterator].width();
+ elementWidth = this.$element.width();
+ while (iterator--) {
+ reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
+ if (reciprocalItemsWidth > elementWidth) {
+ break;
+ }
+ }
+ }
+ maximum = iterator + 1;
+ } else if (settings.center) {
+ maximum = this._items.length - 1;
+ } else {
+ maximum = this._items.length - settings.items;
+ }
+ if (relative) {
+ maximum -= this._clones.length / 2;
+ }
+ return Math.max(maximum, 0);
+ };
+ /**
+ * Gets the minimum position for the current item.
+ * @public
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
+ * @returns {Number}
+ */
+ Owl.prototype.minimum = function(relative) {
+ return relative ? 0 : this._clones.length / 2;
+ };
+ /**
+ * Gets an item at the specified relative position.
+ * @public
+ * @param {Number} [position] - The relative position of the item.
+ * @return {jQuery|Array.} - The item at the given position or all items if no position was given.
+ */
+ Owl.prototype.items = function(position) {
+ if (position === undefined) {
+ return this._items.slice();
+ }
+ position = this.normalize(position, true);
+ return this._items[position];
+ };
+ /**
+ * Gets an item at the specified relative position.
+ * @public
+ * @param {Number} [position] - The relative position of the item.
+ * @return {jQuery|Array.} - The item at the given position or all items if no position was given.
+ */
+ Owl.prototype.mergers = function(position) {
+ if (position === undefined) {
+ return this._mergers.slice();
+ }
+ position = this.normalize(position, true);
+ return this._mergers[position];
+ };
+ /**
+ * Gets the absolute positions of clones for an item.
+ * @public
+ * @param {Number} [position] - The relative position of the item.
+ * @returns {Array.} - The absolute positions of clones for the item or all if no position was given.
+ */
+ Owl.prototype.clones = function(position) {
+ var odd = this._clones.length / 2,
+ even = odd + this._items.length,
+ map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
+ if (position === undefined) {
+ return $.map(this._clones, function(v, i) { return map(i) });
+ }
+ return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
+ };
+ /**
+ * Sets the current animation speed.
+ * @public
+ * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
+ * @returns {Number} - The current animation speed in milliseconds.
+ */
+ Owl.prototype.speed = function(speed) {
+ if (speed !== undefined) {
+ this._speed = speed;
+ }
+ return this._speed;
+ };
+ /**
+ * Gets the coordinate of an item.
+ * @todo The name of this method is missleanding.
+ * @public
+ * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
+ * @returns {Number|Array.} - The coordinate of the item in pixel or all coordinates.
+ */
+ Owl.prototype.coordinates = function(position) {
+ var multiplier = 1,
+ newPosition = position - 1,
+ coordinate;
+ if (position === undefined) {
+ return $.map(this._coordinates, $.proxy(function(coordinate, index) {
+ return this.coordinates(index);
+ }, this));
+ }
+ if (this.settings.center) {
+ if (this.settings.rtl) {
+ multiplier = -1;
+ newPosition = position + 1;
+ }
+ coordinate = this._coordinates[position];
+ coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
+ } else {
+ coordinate = this._coordinates[newPosition] || 0;
+ }
+ coordinate = Math.ceil(coordinate);
+ return coordinate;
+ };
+ /**
+ * Calculates the speed for a translation.
+ * @protected
+ * @param {Number} from - The absolute position of the start item.
+ * @param {Number} to - The absolute position of the target item.
+ * @param {Number} [factor=undefined] - The time factor in milliseconds.
+ * @returns {Number} - The time in milliseconds for the translation.
+ */
+ Owl.prototype.duration = function(from, to, factor) {
+ if (factor === 0) {
+ return 0;
+ }
+ return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
+ };
+ /**
+ * Slides to the specified item.
+ * @public
+ * @param {Number} position - The position of the item.
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ */
+ Owl.prototype.to = function(position, speed) {
+ var current = this.current(),
+ revert = null,
+ distance = position - this.relative(current),
+ direction = (distance > 0) - (distance < 0),
+ items = this._items.length,
+ minimum = this.minimum(),
+ maximum = this.maximum();
+ if (this.settings.loop) {
+ if (!this.settings.rewind && Math.abs(distance) > items / 2) {
+ distance += direction * -1 * items;
+ }
+ position = current + distance;
+ revert = ((position - minimum) % items + items) % items + minimum;
+ if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
+ current = revert - distance;
+ position = revert;
+ this.reset(current);
+ }
+ } else if (this.settings.rewind) {
+ maximum += 1;
+ position = (position % maximum + maximum) % maximum;
+ } else {
+ position = Math.max(minimum, Math.min(maximum, position));
+ }
+ this.speed(this.duration(current, position, speed));
+ this.current(position);
+ if (this.isVisible()) {
+ this.update();
+ }
+ };
+ /**
+ * Slides to the next item.
+ * @public
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ */
+ Owl.prototype.next = function(speed) {
+ speed = speed || false;
+ this.to(this.relative(this.current()) + 1, speed);
+ };
+ /**
+ * Slides to the previous item.
+ * @public
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ */
+ Owl.prototype.prev = function(speed) {
+ speed = speed || false;
+ this.to(this.relative(this.current()) - 1, speed);
+ };
+ /**
+ * Handles the end of an animation.
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onTransitionEnd = function(event) {
+
+ // if css2 animation then event object is undefined
+ if (event !== undefined) {
+ event.stopPropagation();
+
+ // Catch only owl-stage transitionEnd event
+ if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
+ return false;
+ }
+ }
+ this.leave('animating');
+ this.trigger('translated');
+ };
+ /**
+ * Gets viewport width.
+ * @protected
+ * @return {Number} - The width in pixel.
+ */
+ Owl.prototype.viewport = function() {
+ var width;
+ if (this.options.responsiveBaseElement !== window) {
+ width = $(this.options.responsiveBaseElement).width();
+ } else if (window.innerWidth) {
+ width = window.innerWidth;
+ } else if (document.documentElement && document.documentElement.clientWidth) {
+ width = document.documentElement.clientWidth;
+ } else {
+ console.warn('Can not detect viewport width.');
+ }
+ return width;
+ };
+ /**
+ * Replaces the current content.
+ * @public
+ * @param {HTMLElement|jQuery|String} content - The new content.
+ */
+ Owl.prototype.replace = function(content) {
+ this.$stage.empty();
+ this._items = [];
+ if (content) {
+ content = (content instanceof jQuery) ? content : $(content);
+ }
+ if (this.settings.nestedItemSelector) {
+ content = content.find('.' + this.settings.nestedItemSelector);
+ }
+ content.filter(function() {
+ return this.nodeType === 1;
+ }).each($.proxy(function(index, item) {
+ item = this.prepare(item);
+ this.$stage.append(item);
+ this._items.push(item);
+ this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
+ }, this));
+ this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
+ this.invalidate('items');
+ };
+ /**
+ * Adds an item.
+ * @todo Use `item` instead of `content` for the event arguments.
+ * @public
+ * @param {HTMLElement|jQuery|String} content - The item content to add.
+ * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
+ */
+ Owl.prototype.add = function(content, position) {
+ var current = this.relative(this._current);
+ position = position === undefined ? this._items.length : this.normalize(position, true);
+ content = content instanceof jQuery ? content : $(content);
+ this.trigger('add', { content: content, position: position });
+ content = this.prepare(content);
+ if (this._items.length === 0 || position === this._items.length) {
+ this._items.length === 0 && this.$stage.append(content);
+ this._items.length !== 0 && this._items[position - 1].after(content);
+ this._items.push(content);
+ this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
+ } else {
+ this._items[position].before(content);
+ this._items.splice(position, 0, content);
+ this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
+ }
+ this._items[current] && this.reset(this._items[current].index());
+ this.invalidate('items');
+ this.trigger('added', { content: content, position: position });
+ };
+ /**
+ * Removes an item by its position.
+ * @todo Use `item` instead of `content` for the event arguments.
+ * @public
+ * @param {Number} position - The relative position of the item to remove.
+ */
+ Owl.prototype.remove = function(position) {
+ position = this.normalize(position, true);
+ if (position === undefined) {
+ return;
+ }
+ this.trigger('remove', { content: this._items[position], position: position });
+ this._items[position].remove();
+ this._items.splice(position, 1);
+ this._mergers.splice(position, 1);
+ this.invalidate('items');
+ this.trigger('removed', { content: null, position: position });
+ };
+ /**
+ * Preloads images with auto width.
+ * @todo Replace by a more generic approach
+ * @protected
+ */
+ Owl.prototype.preloadAutoWidthImages = function(images) {
+ images.each($.proxy(function(i, element) {
+ this.enter('pre-loading');
+ element = $(element);
+ $(new Image()).one('load', $.proxy(function(e) {
+ element.attr('src', e.target.src);
+ element.css('opacity', 1);
+ this.leave('pre-loading');
+ !this.is('pre-loading') && !this.is('initializing') && this.refresh();
+ }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
+ }, this));
+ };
+ /**
+ * Destroys the carousel.
+ * @public
+ */
+ Owl.prototype.destroy = function() {
+ this.$element.off('.owl.core');
+ this.$stage.off('.owl.core');
+ $(document).off('.owl.core');
+ if (this.settings.responsive !== false) {
+ window.clearTimeout(this.resizeTimer);
+ this.off(window, 'resize', this._handlers.onThrottledResize);
+ }
+ for (var i in this._plugins) {
+ this._plugins[i].destroy();
+ }
+ this.$stage.children('.cloned').remove();
+ this.$stage.unwrap();
+ this.$stage.children().contents().unwrap();
+ this.$stage.children().unwrap();
+ this.$stage.remove();
+ this.$element
+ .removeClass(this.options.refreshClass)
+ .removeClass(this.options.loadingClass)
+ .removeClass(this.options.loadedClass)
+ .removeClass(this.options.rtlClass)
+ .removeClass(this.options.dragClass)
+ .removeClass(this.options.grabClass)
+ .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
+ .removeData('owl.carousel');
+ };
+ /**
+ * Operators to calculate right-to-left and left-to-right.
+ * @protected
+ * @param {Number} [a] - The left side operand.
+ * @param {String} [o] - The operator.
+ * @param {Number} [b] - The right side operand.
+ */
+ Owl.prototype.op = function(a, o, b) {
+ var rtl = this.settings.rtl;
+ switch (o) {
+ case '<':
+ return rtl ? a > b : a < b;
+ case '>':
+ return rtl ? a < b : a > b;
+ case '>=':
+ return rtl ? a <= b : a >= b;
+ case '<=':
+ return rtl ? a >= b : a <= b;
+ default:
+ break;
+ }
+ };
+ /**
+ * Attaches to an internal event.
+ * @protected
+ * @param {HTMLElement} element - The event source.
+ * @param {String} event - The event name.
+ * @param {Function} listener - The event handler to attach.
+ * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
+ */
+ Owl.prototype.on = function(element, event, listener, capture) {
+ if (element.addEventListener) {
+ element.addEventListener(event, listener, capture);
+ } else if (element.attachEvent) {
+ element.attachEvent('on' + event, listener);
+ }
+ };
+ /**
+ * Detaches from an internal event.
+ * @protected
+ * @param {HTMLElement} element - The event source.
+ * @param {String} event - The event name.
+ * @param {Function} listener - The attached event handler to detach.
+ * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
+ */
+ Owl.prototype.off = function(element, event, listener, capture) {
+ if (element.removeEventListener) {
+ element.removeEventListener(event, listener, capture);
+ } else if (element.detachEvent) {
+ element.detachEvent('on' + event, listener);
+ }
+ };
+ /**
+ * Triggers a public event.
+ * @todo Remove `status`, `relatedTarget` should be used instead.
+ * @protected
+ * @param {String} name - The event name.
+ * @param {*} [data=null] - The event data.
+ * @param {String} [namespace=carousel] - The event namespace.
+ * @param {String} [state] - The state which is associated with the event.
+ * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
+ * @returns {Event} - The event arguments.
+ */
+ Owl.prototype.trigger = function(name, data, namespace, state, enter) {
+ var status = {
+ item: { count: this._items.length, index: this.current() }
+ }, handler = $.camelCase(
+ $.grep([ 'on', name, namespace ], function(v) { return v })
+ .join('-').toLowerCase()
+ ), event = $.Event(
+ [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
+ $.extend({ relatedTarget: this }, status, data)
+ );
+ if (!this._supress[name]) {
+ $.each(this._plugins, function(name, plugin) {
+ if (plugin.onTrigger) {
+ plugin.onTrigger(event);
+ }
+ });
+ this.register({ type: Owl.Type.Event, name: name });
+ this.$element.trigger(event);
+ if (this.settings && typeof this.settings[handler] === 'function') {
+ this.settings[handler].call(this, event);
+ }
+ }
+ return event;
+ };
+ /**
+ * Enters a state.
+ * @param name - The state name.
+ */
+ Owl.prototype.enter = function(name) {
+ $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
+ if (this._states.current[name] === undefined) {
+ this._states.current[name] = 0;
+ }
+ this._states.current[name]++;
+ }, this));
+ };
+ /**
+ * Leaves a state.
+ * @param name - The state name.
+ */
+ Owl.prototype.leave = function(name) {
+ $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
+ this._states.current[name]--;
+ }, this));
+ };
+ /**
+ * Registers an event or state.
+ * @public
+ * @param {Object} object - The event or state to register.
+ */
+ Owl.prototype.register = function(object) {
+ if (object.type === Owl.Type.Event) {
+ if (!$.event.special[object.name]) {
+ $.event.special[object.name] = {};
+ }
+ if (!$.event.special[object.name].owl) {
+ var _default = $.event.special[object.name]._default;
+ $.event.special[object.name]._default = function(e) {
+ if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
+ return _default.apply(this, arguments);
+ }
+ return e.namespace && e.namespace.indexOf('owl') > -1;
+ };
+ $.event.special[object.name].owl = true;
+ }
+ } else if (object.type === Owl.Type.State) {
+ if (!this._states.tags[object.name]) {
+ this._states.tags[object.name] = object.tags;
+ } else {
+ this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
+ }
+ this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
+ return $.inArray(tag, this._states.tags[object.name]) === i;
+ }, this));
+ }
+ };
+ /**
+ * Suppresses events.
+ * @protected
+ * @param {Array.} events - The events to suppress.
+ */
+ Owl.prototype.suppress = function(events) {
+ $.each(events, $.proxy(function(index, event) {
+ this._supress[event] = true;
+ }, this));
+ };
+ /**
+ * Releases suppressed events.
+ * @protected
+ * @param {Array.} events - The events to release.
+ */
+ Owl.prototype.release = function(events) {
+ $.each(events, $.proxy(function(index, event) {
+ delete this._supress[event];
+ }, this));
+ };
+ /**
+ * Gets unified pointer coordinates from event.
+ * @todo #261
+ * @protected
+ * @param {Event} - The `mousedown` or `touchstart` event.
+ * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
+ */
+ Owl.prototype.pointer = function(event) {
+ var result = { x: null, y: null };
+ event = event.originalEvent || event || window.event;
+ event = event.touches && event.touches.length ?
+ event.touches[0] : event.changedTouches && event.changedTouches.length ?
+ event.changedTouches[0] : event;
+ if (event.pageX) {
+ result.x = event.pageX;
+ result.y = event.pageY;
+ } else {
+ result.x = event.clientX;
+ result.y = event.clientY;
+ }
+ return result;
+ };
+ /**
+ * Determines if the input is a Number or something that can be coerced to a Number
+ * @protected
+ * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
+ * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
+ */
+ Owl.prototype.isNumeric = function(number) {
+ return !isNaN(parseFloat(number));
+ };
+ /**
+ * Gets the difference of two vectors.
+ * @todo #261
+ * @protected
+ * @param {Object} - The first vector.
+ * @param {Object} - The second vector.
+ * @returns {Object} - The difference.
+ */
+ Owl.prototype.difference = function(first, second) {
+ return {
+ x: first.x - second.x,
+ y: first.y - second.y
+ };
+ };
+ /**
+ * The jQuery Plugin for the Owl Carousel
+ * @todo Navigation plugin `next` and `prev`
+ * @public
+ */
+ $.fn.owlCarousel = function(option) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return this.each(function() {
+ var $this = $(this),
+ data = $this.data('owl.carousel');
+ if (!data) {
+ data = new Owl(this, typeof option == 'object' && option);
+ $this.data('owl.carousel', data);
+ $.each([
+ 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
+ ], function(i, event) {
+ data.register({ type: Owl.Type.Event, name: event });
+ data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
+ if (e.namespace && e.relatedTarget !== this) {
+ this.suppress([ event ]);
+ data[event].apply(this, [].slice.call(arguments, 1));
+ this.release([ event ]);
+ }
+ }, data));
+ });
+ }
+ if (typeof option == 'string' && option.charAt(0) !== '_') {
+ data[option].apply(data, args);
+ }
+ });
+ };
+ /**
+ * The constructor for the jQuery Plugin
+ * @public
+ */
+ $.fn.owlCarousel.Constructor = Owl;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * AutoRefresh Plugin
+ * @version 2.3.4
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the auto refresh plugin.
+ * @class The Auto Refresh Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var AutoRefresh = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ /**
+ * Refresh interval.
+ * @protected
+ * @type {number}
+ */
+ this._interval = null;
+ /**
+ * Whether the element is currently visible or not.
+ * @protected
+ * @type {Boolean}
+ */
+ this._visible = null;
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoRefresh) {
+ this.watch();
+ }
+ }, this)
+ };
+ // set default options
+ this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
+ // register event handlers
+ this._core.$element.on(this._handlers);
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ AutoRefresh.Defaults = {
+ autoRefresh: true,
+ autoRefreshInterval: 500
+ };
+ /**
+ * Watches the element.
+ */
+ AutoRefresh.prototype.watch = function() {
+ if (this._interval) {
+ return;
+ }
+ this._visible = this._core.isVisible();
+ this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
+ };
+ /**
+ * Refreshes the element.
+ */
+ AutoRefresh.prototype.refresh = function() {
+ if (this._core.isVisible() === this._visible) {
+ return;
+ }
+ this._visible = !this._visible;
+ this._core.$element.toggleClass('owl-hidden', !this._visible);
+ this._visible && (this._core.invalidate('width') && this._core.refresh());
+ };
+ /**
+ * Destroys the plugin.
+ */
+ AutoRefresh.prototype.destroy = function() {
+ var handler, property;
+ window.clearInterval(this._interval);
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * Lazy Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the lazy plugin.
+ * @class The Lazy Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var Lazy = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ /**
+ * Already loaded items.
+ * @protected
+ * @type {Array.}
+ */
+ this._loaded = [];
+ /**
+ * Event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function(e) {
+ if (!e.namespace) {
+ return;
+ }
+ if (!this._core.settings || !this._core.settings.lazyLoad) {
+ return;
+ }
+ if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
+ var settings = this._core.settings,
+ n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
+ i = ((settings.center && n * -1) || 0),
+ position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i,
+ clones = this._core.clones().length,
+ load = $.proxy(function(i, v) { this.load(v) }, this);
+ //TODO: Need documentation for this new option
+ if (settings.lazyLoadEager > 0) {
+ n += settings.lazyLoadEager;
+ // If the carousel is looping also preload images that are to the "left"
+ if (settings.loop) {
+ position -= settings.lazyLoadEager;
+ n++;
+ }
+ }
+ while (i++ < n) {
+ this.load(clones / 2 + this._core.relative(position));
+ clones && $.each(this._core.clones(this._core.relative(position)), load);
+ position++;
+ }
+ }
+ }, this)
+ };
+ // set the default options
+ this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
+ // register event handler
+ this._core.$element.on(this._handlers);
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ Lazy.Defaults = {
+ lazyLoad: false,
+ lazyLoadEager: 0
+ };
+ /**
+ * Loads all resources of an item at the specified position.
+ * @param {Number} position - The absolute position of the item.
+ * @protected
+ */
+ Lazy.prototype.load = function(position) {
+ var $item = this._core.$stage.children().eq(position),
+ $elements = $item && $item.find('.owl-lazy');
+ if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
+ return;
+ }
+ $elements.each($.proxy(function(index, element) {
+ var $element = $(element), image,
+ url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src') || $element.attr('data-srcset');
+ this._core.trigger('load', { element: $element, url: url }, 'lazy');
+ if ($element.is('img')) {
+ $element.one('load.owl.lazy', $.proxy(function() {
+ $element.css('opacity', 1);
+ this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
+ }, this)).attr('src', url);
+ } else if ($element.is('source')) {
+ $element.one('load.owl.lazy', $.proxy(function() {
+ this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
+ }, this)).attr('srcset', url);
+ } else {
+ image = new Image();
+ image.onload = $.proxy(function() {
+ $element.css({
+ 'background-image': 'url("' + url + '")',
+ 'opacity': '1'
+ });
+ this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
+ }, this);
+ image.src = url;
+ }
+ }, this));
+ this._loaded.push($item.get(0));
+ };
+ /**
+ * Destroys the plugin.
+ * @public
+ */
+ Lazy.prototype.destroy = function() {
+ var handler, property;
+ for (handler in this.handlers) {
+ this._core.$element.off(handler, this.handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * AutoHeight Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the auto height plugin.
+ * @class The Auto Height Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var AutoHeight = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ this._previousHeight = null;
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoHeight) {
+ this.update();
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoHeight && e.property.name === 'position'){
+ this.update();
+ }
+ }, this),
+ 'loaded.owl.lazy': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoHeight
+ && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
+ this.update();
+ }
+ }, this)
+ };
+ // set default options
+ this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
+ // register event handlers
+ this._core.$element.on(this._handlers);
+ this._intervalId = null;
+ var refThis = this;
+ // These changes have been taken from a PR by gavrochelegnou proposed in #1575
+ // and have been made compatible with the latest jQuery version
+ $(window).on('load', function() {
+ if (refThis._core.settings.autoHeight) {
+ refThis.update();
+ }
+ });
+ // Autoresize the height of the carousel when window is resized
+ // When carousel has images, the height is dependent on the width
+ // and should also change on resize
+ $(window).resize(function() {
+ if (refThis._core.settings.autoHeight) {
+ if (refThis._intervalId != null) {
+ clearTimeout(refThis._intervalId);
+ }
+ refThis._intervalId = setTimeout(function() {
+ refThis.update();
+ }, 250);
+ }
+ });
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ AutoHeight.Defaults = {
+ autoHeight: false,
+ autoHeightClass: 'owl-height'
+ };
+ /**
+ * Updates the view.
+ */
+ AutoHeight.prototype.update = function() {
+ var start = this._core._current,
+ end = start + this._core.settings.items,
+ lazyLoadEnabled = this._core.settings.lazyLoad,
+ visible = this._core.$stage.children().toArray().slice(start, end),
+ heights = [],
+ maxheight = 0;
+ $.each(visible, function(index, item) {
+ heights.push($(item).height());
+ });
+ maxheight = Math.max.apply(null, heights);
+ if (maxheight <= 1 && lazyLoadEnabled && this._previousHeight) {
+ maxheight = this._previousHeight;
+ }
+ this._previousHeight = maxheight;
+ this._core.$stage.parent()
+ .height(maxheight)
+ .addClass(this._core.settings.autoHeightClass);
+ };
+ AutoHeight.prototype.destroy = function() {
+ var handler, property;
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] !== 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * Video Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the video plugin.
+ * @class The Video Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var Video = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ /**
+ * Cache all video URLs.
+ * @protected
+ * @type {Object}
+ */
+ this._videos = {};
+ /**
+ * Current playing item.
+ * @protected
+ * @type {jQuery}
+ */
+ this._playing = null;
+ /**
+ * All event handlers.
+ * @todo The cloned content removale is too late
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace) {
+ this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
+ }
+ }, this),
+ 'resize.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
+ e.preventDefault();
+ }
+ }, this),
+ 'refreshed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.is('resizing')) {
+ this._core.$stage.find('.cloned .owl-video-frame').remove();
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name === 'position' && this._playing) {
+ this.stop();
+ }
+ }, this),
+ 'prepared.owl.carousel': $.proxy(function(e) {
+ if (!e.namespace) {
+ return;
+ }
+ var $element = $(e.content).find('.owl-video');
+ if ($element.length) {
+ $element.css('display', 'none');
+ this.fetch($element, $(e.content));
+ }
+ }, this)
+ };
+ // set default options
+ this._core.options = $.extend({}, Video.Defaults, this._core.options);
+ // register event handlers
+ this._core.$element.on(this._handlers);
+ this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
+ this.play(e);
+ }, this));
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ Video.Defaults = {
+ video: false,
+ videoHeight: false,
+ videoWidth: false
+ };
+ /**
+ * Gets the video ID and the type (YouTube/Vimeo/vzaar only).
+ * @protected
+ * @param {jQuery} target - The target containing the video data.
+ * @param {jQuery} item - The item containing the video.
+ */
+ Video.prototype.fetch = function(target, item) {
+ var type = (function() {
+ if (target.attr('data-vimeo-id')) {
+ return 'vimeo';
+ } else if (target.attr('data-vzaar-id')) {
+ return 'vzaar'
+ } else {
+ return 'youtube';
+ }
+ })(),
+ id = target.attr('data-vimeo-id') || target.attr('data-youtube-id') || target.attr('data-vzaar-id'),
+ width = target.attr('data-width') || this._core.settings.videoWidth,
+ height = target.attr('data-height') || this._core.settings.videoHeight,
+ url = target.attr('href');
+ if (url) {
+ /*
+ Parses the id's out of the following urls (and probably more):
+ https://www.youtube.com/watch?v=:id
+ https://youtu.be/:id
+ https://vimeo.com/:id
+ https://vimeo.com/channels/:channel/:id
+ https://vimeo.com/groups/:group/videos/:id
+ https://app.vzaar.com/videos/:id
+ Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F
+ */
+ id = url.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com|be\-nocookie\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
+ if (id[3].indexOf('youtu') > -1) {
+ type = 'youtube';
+ } else if (id[3].indexOf('vimeo') > -1) {
+ type = 'vimeo';
+ } else if (id[3].indexOf('vzaar') > -1) {
+ type = 'vzaar';
+ } else {
+ throw new Error('Video URL not supported.');
+ }
+ id = id[6];
+ } else {
+ throw new Error('Missing video URL.');
+ }
+ this._videos[url] = {
+ type: type,
+ id: id,
+ width: width,
+ height: height
+ };
+ item.attr('data-video', url);
+ this.thumbnail(target, this._videos[url]);
+ };
+ /**
+ * Creates video thumbnail.
+ * @protected
+ * @param {jQuery} target - The target containing the video data.
+ * @param {Object} info - The video info object.
+ * @see `fetch`
+ */
+ Video.prototype.thumbnail = function(target, video) {
+ var tnLink,
+ icon,
+ path,
+ dimensions = video.width && video.height ? 'width:' + video.width + 'px;height:' + video.height + 'px;' : '',
+ customTn = target.find('img'),
+ srcType = 'src',
+ lazyClass = '',
+ settings = this._core.settings,
+ create = function(path) {
+ icon = '
';
+ if (settings.lazyLoad) {
+ tnLink = $('
',{
+ "class": 'owl-video-tn ' + lazyClass,
+ "srcType": path
+ });
+ } else {
+ tnLink = $( '
', {
+ "class": "owl-video-tn",
+ "style": 'opacity:1;background-image:url(' + path + ')'
+ });
+ }
+ target.after(tnLink);
+ target.after(icon);
+ };
+ // wrap video content into owl-video-wrapper div
+ target.wrap( $( '
', {
+ "class": "owl-video-wrapper",
+ "style": dimensions
+ }));
+ if (this._core.settings.lazyLoad) {
+ srcType = 'data-src';
+ lazyClass = 'owl-lazy';
+ }
+ // custom thumbnail
+ if (customTn.length) {
+ create(customTn.attr(srcType));
+ customTn.remove();
+ return false;
+ }
+ if (video.type === 'youtube') {
+ path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
+ create(path);
+ } else if (video.type === 'vimeo') {
+ $.ajax({
+ type: 'GET',
+ url: '//vimeo.com/api/v2/video/' + video.id + '.json',
+ jsonp: 'callback',
+ dataType: 'jsonp',
+ success: function(data) {
+ path = data[0].thumbnail_large;
+ create(path);
+ }
+ });
+ } else if (video.type === 'vzaar') {
+ $.ajax({
+ type: 'GET',
+ url: '//vzaar.com/api/videos/' + video.id + '.json',
+ jsonp: 'callback',
+ dataType: 'jsonp',
+ success: function(data) {
+ path = data.framegrab_url;
+ create(path);
+ }
+ });
+ }
+ };
+ /**
+ * Stops the current video.
+ * @public
+ */
+ Video.prototype.stop = function() {
+ this._core.trigger('stop', null, 'video');
+ this._playing.find('.owl-video-frame').remove();
+ this._playing.removeClass('owl-video-playing');
+ this._playing = null;
+ this._core.leave('playing');
+ this._core.trigger('stopped', null, 'video');
+ };
+ /**
+ * Starts the current video.
+ * @public
+ * @param {Event} event - The event arguments.
+ */
+ Video.prototype.play = function(event) {
+ var target = $(event.target),
+ item = target.closest('.' + this._core.settings.itemClass),
+ video = this._videos[item.attr('data-video')],
+ width = video.width || '100%',
+ height = video.height || this._core.$stage.height(),
+ html,
+ iframe;
+ if (this._playing) {
+ return;
+ }
+ this._core.enter('playing');
+ this._core.trigger('play', null, 'video');
+ item = this._core.items(this._core.relative(item.index()));
+ this._core.reset(item.index());
+ html = $( '' );
+ html.attr( 'height', height );
+ html.attr( 'width', width );
+ if (video.type === 'youtube') {
+ html.attr( 'src', '//www.youtube.com/embed/' + video.id + '?autoplay=1&rel=0&v=' + video.id );
+ } else if (video.type === 'vimeo') {
+ html.attr( 'src', '//player.vimeo.com/video/' + video.id + '?autoplay=1' );
+ } else if (video.type === 'vzaar') {
+ html.attr( 'src', '//view.vzaar.com/' + video.id + '/player?autoplay=true' );
+ }
+ iframe = $(html).wrap( '
' ).insertAfter(item.find('.owl-video'));
+ this._playing = item.addClass('owl-video-playing');
+ };
+ /**
+ * Checks whether an video is currently in full screen mode or not.
+ * @todo Bad style because looks like a readonly method but changes members.
+ * @protected
+ * @returns {Boolean}
+ */
+ Video.prototype.isInFullScreen = function() {
+ var element = document.fullscreenElement || document.mozFullScreenElement ||
+ document.webkitFullscreenElement;
+ return element && $(element).parent().hasClass('owl-video-frame');
+ };
+ /**
+ * Destroys the plugin.
+ */
+ Video.prototype.destroy = function() {
+ var handler, property;
+ this._core.$element.off('click.owl.video');
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.Video = Video;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * Animate Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the animate plugin.
+ * @class The Navigation Plugin
+ * @param {Owl} scope - The Owl Carousel
+ */
+ var Animate = function(scope) {
+ this.core = scope;
+ this.core.options = $.extend({}, Animate.Defaults, this.core.options);
+ this.swapping = true;
+ this.previous = undefined;
+ this.next = undefined;
+ this.handlers = {
+ 'change.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name == 'position') {
+ this.previous = this.core.current();
+ this.next = e.property.value;
+ }
+ }, this),
+ 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
+ if (e.namespace) {
+ this.swapping = e.type == 'translated';
+ }
+ }, this),
+ 'translate.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
+ this.swap();
+ }
+ }, this)
+ };
+ this.core.$element.on(this.handlers);
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ Animate.Defaults = {
+ animateOut: false,
+ animateIn: false
+ };
+ /**
+ * Toggles the animation classes whenever an translations starts.
+ * @protected
+ * @returns {Boolean|undefined}
+ */
+ Animate.prototype.swap = function() {
+ if (this.core.settings.items !== 1) {
+ return;
+ }
+ if (!$.support.animation || !$.support.transition) {
+ return;
+ }
+ this.core.speed(0);
+ var left,
+ clear = $.proxy(this.clear, this),
+ previous = this.core.$stage.children().eq(this.previous),
+ next = this.core.$stage.children().eq(this.next),
+ incoming = this.core.settings.animateIn,
+ outgoing = this.core.settings.animateOut;
+ if (this.core.current() === this.previous) {
+ return;
+ }
+ if (outgoing) {
+ left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
+ previous.one($.support.animation.end, clear)
+ .css( { 'left': left + 'px' } )
+ .addClass('animated owl-animated-out')
+ .addClass(outgoing);
+ }
+ if (incoming) {
+ next.one($.support.animation.end, clear)
+ .addClass('animated owl-animated-in')
+ .addClass(incoming);
+ }
+ };
+ Animate.prototype.clear = function(e) {
+ $(e.target).css( { 'left': '' } )
+ .removeClass('animated owl-animated-out owl-animated-in')
+ .removeClass(this.core.settings.animateIn)
+ .removeClass(this.core.settings.animateOut);
+ this.core.onTransitionEnd();
+ };
+ /**
+ * Destroys the plugin.
+ * @public
+ */
+ Animate.prototype.destroy = function() {
+ var handler, property;
+ for (handler in this.handlers) {
+ this.core.$element.off(handler, this.handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * Autoplay Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @author Tom De Caluwé
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ /**
+ * Creates the autoplay plugin.
+ * @class The Autoplay Plugin
+ * @param {Owl} scope - The Owl Carousel
+ */
+ var Autoplay = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ /**
+ * The autoplay timeout id.
+ * @type {Number}
+ */
+ this._call = null;
+ /**
+ * Depending on the state of the plugin, this variable contains either
+ * the start time of the timer or the current timer value if it's
+ * paused. Since we start in a paused state we initialize the timer
+ * value.
+ * @type {Number}
+ */
+ this._time = 0;
+ /**
+ * Stores the timeout currently used.
+ * @type {Number}
+ */
+ this._timeout = 0;
+ /**
+ * Indicates whenever the autoplay is paused.
+ * @type {Boolean}
+ */
+ this._paused = true;
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name === 'settings') {
+ if (this._core.settings.autoplay) {
+ this.play();
+ } else {
+ this.stop();
+ }
+ } else if (e.namespace && e.property.name === 'position' && this._paused) {
+ // Reset the timer. This code is triggered when the position
+ // of the carousel was changed through user interaction.
+ this._time = 0;
+ }
+ }, this),
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoplay) {
+ this.play();
+ }
+ }, this),
+ 'play.owl.autoplay': $.proxy(function(e, t, s) {
+ if (e.namespace) {
+ this.play(t, s);
+ }
+ }, this),
+ 'stop.owl.autoplay': $.proxy(function(e) {
+ if (e.namespace) {
+ this.stop();
+ }
+ }, this),
+ 'mouseover.owl.autoplay': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
+ this.pause();
+ }
+ }, this),
+ 'mouseleave.owl.autoplay': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
+ this.play();
+ }
+ }, this),
+ 'touchstart.owl.core': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
+ this.pause();
+ }
+ }, this),
+ 'touchend.owl.core': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause) {
+ this.play();
+ }
+ }, this)
+ };
+ // register event handlers
+ this._core.$element.on(this._handlers);
+ // set default options
+ this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ Autoplay.Defaults = {
+ autoplay: false,
+ autoplayTimeout: 5000,
+ autoplayHoverPause: false,
+ autoplaySpeed: false
+ };
+ /**
+ * Transition to the next slide and set a timeout for the next transition.
+ * @private
+ * @param {Number} [speed] - The animation speed for the animations.
+ */
+ Autoplay.prototype._next = function(speed) {
+ this._call = window.setTimeout(
+ $.proxy(this._next, this, speed),
+ this._timeout * (Math.round(this.read() / this._timeout) + 1) - this.read()
+ );
+ if (this._core.is('interacting') || document.hidden) {
+ return;
+ }
+ this._core.next(speed || this._core.settings.autoplaySpeed);
+ }
+ /**
+ * Reads the current timer value when the timer is playing.
+ * @public
+ */
+ Autoplay.prototype.read = function() {
+ return new Date().getTime() - this._time;
+ };
+ /**
+ * Starts the autoplay.
+ * @public
+ * @param {Number} [timeout] - The interval before the next animation starts.
+ * @param {Number} [speed] - The animation speed for the animations.
+ */
+ Autoplay.prototype.play = function(timeout, speed) {
+ var elapsed;
+ if (!this._core.is('rotating')) {
+ this._core.enter('rotating');
+ }
+ timeout = timeout || this._core.settings.autoplayTimeout;
+ // Calculate the elapsed time since the last transition. If the carousel
+ // wasn't playing this calculation will yield zero.
+ elapsed = Math.min(this._time % (this._timeout || timeout), timeout);
+ if (this._paused) {
+ // Start the clock.
+ this._time = this.read();
+ this._paused = false;
+ } else {
+ // Clear the active timeout to allow replacement.
+ window.clearTimeout(this._call);
+ }
+ // Adjust the origin of the timer to match the new timeout value.
+ this._time += this.read() % timeout - elapsed;
+ this._timeout = timeout;
+ this._call = window.setTimeout($.proxy(this._next, this, speed), timeout - elapsed);
+ };
+ /**
+ * Stops the autoplay.
+ * @public
+ */
+ Autoplay.prototype.stop = function() {
+ if (this._core.is('rotating')) {
+ // Reset the clock.
+ this._time = 0;
+ this._paused = true;
+ window.clearTimeout(this._call);
+ this._core.leave('rotating');
+ }
+ };
+ /**
+ * Pauses the autoplay.
+ * @public
+ */
+ Autoplay.prototype.pause = function() {
+ if (this._core.is('rotating') && !this._paused) {
+ // Pause the clock.
+ this._time = this.read();
+ this._paused = true;
+ window.clearTimeout(this._call);
+ }
+ };
+ /**
+ * Destroys the plugin.
+ */
+ Autoplay.prototype.destroy = function() {
+ var handler, property;
+ this.stop();
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * Navigation Plugin
+ * @version 2.3.4
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ 'use strict';
+ /**
+ * Creates the navigation plugin.
+ * @class The Navigation Plugin
+ * @param {Owl} carousel - The Owl Carousel.
+ */
+ var Navigation = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ /**
+ * Indicates whether the plugin is initialized or not.
+ * @protected
+ * @type {Boolean}
+ */
+ this._initialized = false;
+ /**
+ * The current paging indexes.
+ * @protected
+ * @type {Array}
+ */
+ this._pages = [];
+ /**
+ * All DOM elements of the user interface.
+ * @protected
+ * @type {Object}
+ */
+ this._controls = {};
+ /**
+ * Markup for an indicator.
+ * @protected
+ * @type {Array.}
+ */
+ this._templates = [];
+ /**
+ * The carousel element.
+ * @type {jQuery}
+ */
+ this.$element = this._core.$element;
+ /**
+ * Overridden methods of the carousel.
+ * @protected
+ * @type {Object}
+ */
+ this._overrides = {
+ next: this._core.next,
+ prev: this._core.prev,
+ to: this._core.to
+ };
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'prepared.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.dotsData) {
+ this._templates.push('' +
+ $(e.content).find('[data-dot]').addBack('[data-dot]').attr('data-dot') + '
');
+ }
+ }, this),
+ 'added.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.dotsData) {
+ this._templates.splice(e.position, 0, this._templates.pop());
+ }
+ }, this),
+ 'remove.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.dotsData) {
+ this._templates.splice(e.position, 1);
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name == 'position') {
+ this.draw();
+ }
+ }, this),
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && !this._initialized) {
+ this._core.trigger('initialize', null, 'navigation');
+ this.initialize();
+ this.update();
+ this.draw();
+ this._initialized = true;
+ this._core.trigger('initialized', null, 'navigation');
+ }
+ }, this),
+ 'refreshed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._initialized) {
+ this._core.trigger('refresh', null, 'navigation');
+ this.update();
+ this.draw();
+ this._core.trigger('refreshed', null, 'navigation');
+ }
+ }, this)
+ };
+ // set default options
+ this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
+ // register event handlers
+ this.$element.on(this._handlers);
+ };
+ /**
+ * Default options.
+ * @public
+ * @todo Rename `slideBy` to `navBy`
+ */
+ Navigation.Defaults = {
+ nav: false,
+ navText: [
+ '‹ ',
+ '› '
+ ],
+ navSpeed: false,
+ navElement: 'button type="button" role="presentation"',
+ navContainer: false,
+ navContainerClass: 'owl-nav',
+ navClass: [
+ 'owl-prev',
+ 'owl-next'
+ ],
+ slideBy: 1,
+ dotClass: 'owl-dot',
+ dotsClass: 'owl-dots',
+ dots: true,
+ dotsEach: false,
+ dotsData: false,
+ dotsSpeed: false,
+ dotsContainer: false
+ };
+ /**
+ * Initializes the layout of the plugin and extends the carousel.
+ * @protected
+ */
+ Navigation.prototype.initialize = function() {
+ var override,
+ settings = this._core.settings;
+ // create DOM structure for relative navigation
+ this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
+ : $('').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
+ this._controls.$previous = $('<' + settings.navElement + '>')
+ .addClass(settings.navClass[0])
+ .html(settings.navText[0])
+ .prependTo(this._controls.$relative)
+ .on('click', $.proxy(function(e) {
+ this.prev(settings.navSpeed);
+ }, this));
+ this._controls.$next = $('<' + settings.navElement + '>')
+ .addClass(settings.navClass[1])
+ .html(settings.navText[1])
+ .appendTo(this._controls.$relative)
+ .on('click', $.proxy(function(e) {
+ this.next(settings.navSpeed);
+ }, this));
+ // create DOM structure for absolute navigation
+ if (!settings.dotsData) {
+ this._templates = [ $('
')
+ .addClass(settings.dotClass)
+ .append($(''))
+ .prop('outerHTML') ];
+ }
+ this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
+ : $('').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
+ this._controls.$absolute.on('click', 'button', $.proxy(function(e) {
+ var index = $(e.target).parent().is(this._controls.$absolute)
+ ? $(e.target).index() : $(e.target).parent().index();
+ e.preventDefault();
+ this.to(index, settings.dotsSpeed);
+ }, this));
+ // override public methods of the carousel
+ for (override in this._overrides) {
+ this._core[override] = $.proxy(this[override], this);
+ }
+ };
+ /**
+ * Destroys the plugin.
+ * @protected
+ */
+ Navigation.prototype.destroy = function() {
+ var handler, control, property, override, settings;
+ settings = this._core.settings;
+ for (handler in this._handlers) {
+ this.$element.off(handler, this._handlers[handler]);
+ }
+ for (control in this._controls) {
+ if (control === '$relative' && settings.navContainer) {
+ this._controls[control].html('');
+ } else {
+ this._controls[control].remove();
+ }
+ }
+ for (override in this.overides) {
+ this._core[override] = this._overrides[override];
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ /**
+ * Updates the internal state.
+ * @protected
+ */
+ Navigation.prototype.update = function() {
+ var i, j, k,
+ lower = this._core.clones().length / 2,
+ upper = lower + this._core.items().length,
+ maximum = this._core.maximum(true),
+ settings = this._core.settings,
+ size = settings.center || settings.autoWidth || settings.dotsData
+ ? 1 : settings.dotsEach || settings.items;
+ if (settings.slideBy !== 'page') {
+ settings.slideBy = Math.min(settings.slideBy, settings.items);
+ }
+ if (settings.dots || settings.slideBy == 'page') {
+ this._pages = [];
+ for (i = lower, j = 0, k = 0; i < upper; i++) {
+ if (j >= size || j === 0) {
+ this._pages.push({
+ start: Math.min(maximum, i - lower),
+ end: i - lower + size - 1
+ });
+ if (Math.min(maximum, i - lower) === maximum) {
+ break;
+ }
+ j = 0, ++k;
+ }
+ j += this._core.mergers(this._core.relative(i));
+ }
+ }
+ };
+ /**
+ * Draws the user interface.
+ * @todo The option `dotsData` wont work.
+ * @protected
+ */
+ Navigation.prototype.draw = function() {
+ var difference,
+ settings = this._core.settings,
+ disabled = this._core.items().length <= settings.items,
+ index = this._core.relative(this._core.current()),
+ loop = settings.loop || settings.rewind;
+ this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
+ if (settings.nav) {
+ this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
+ this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
+ }
+ this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
+ if (settings.dots) {
+ difference = this._pages.length - this._controls.$absolute.children().length;
+ if (settings.dotsData && difference !== 0) {
+ this._controls.$absolute.html(this._templates.join(''));
+ } else if (difference > 0) {
+ this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
+ } else if (difference < 0) {
+ this._controls.$absolute.children().slice(difference).remove();
+ }
+ this._controls.$absolute.find('.active').removeClass('active');
+ this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
+ }
+ };
+ /**
+ * Extends event data.
+ * @protected
+ * @param {Event} event - The event object which gets thrown.
+ */
+ Navigation.prototype.onTrigger = function(event) {
+ var settings = this._core.settings;
+ event.page = {
+ index: $.inArray(this.current(), this._pages),
+ count: this._pages.length,
+ size: settings && (settings.center || settings.autoWidth || settings.dotsData
+ ? 1 : settings.dotsEach || settings.items)
+ };
+ };
+ /**
+ * Gets the current page position of the carousel.
+ * @protected
+ * @returns {Number}
+ */
+ Navigation.prototype.current = function() {
+ var current = this._core.relative(this._core.current());
+ return $.grep(this._pages, $.proxy(function(page, index) {
+ return page.start <= current && page.end >= current;
+ }, this)).pop();
+ };
+ /**
+ * Gets the current succesor/predecessor position.
+ * @protected
+ * @returns {Number}
+ */
+ Navigation.prototype.getPosition = function(successor) {
+ var position, length,
+ settings = this._core.settings;
+ if (settings.slideBy == 'page') {
+ position = $.inArray(this.current(), this._pages);
+ length = this._pages.length;
+ successor ? ++position : --position;
+ position = this._pages[((position % length) + length) % length].start;
+ } else {
+ position = this._core.relative(this._core.current());
+ length = this._core.items().length;
+ successor ? position += settings.slideBy : position -= settings.slideBy;
+ }
+ return position;
+ };
+ /**
+ * Slides to the next item or page.
+ * @public
+ * @param {Number} [speed=false] - The time in milliseconds for the transition.
+ */
+ Navigation.prototype.next = function(speed) {
+ $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
+ };
+ /**
+ * Slides to the previous item or page.
+ * @public
+ * @param {Number} [speed=false] - The time in milliseconds for the transition.
+ */
+ Navigation.prototype.prev = function(speed) {
+ $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
+ };
+ /**
+ * Slides to the specified item or page.
+ * @public
+ * @param {Number} position - The position of the item or page.
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
+ */
+ Navigation.prototype.to = function(position, speed, standard) {
+ var length;
+ if (!standard && this._pages.length) {
+ length = this._pages.length;
+ $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
+ } else {
+ $.proxy(this._overrides.to, this._core)(position, speed);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * Hash Plugin
+ * @version 2.3.4
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ 'use strict';
+ /**
+ * Creates the hash plugin.
+ * @class The Hash Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var Hash = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+ /**
+ * Hash index for the items.
+ * @protected
+ * @type {Object}
+ */
+ this._hashes = {};
+ /**
+ * The carousel element.
+ * @type {jQuery}
+ */
+ this.$element = this._core.$element;
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.startPosition === 'URLHash') {
+ $(window).trigger('hashchange.owl.navigation');
+ }
+ }, this),
+ 'prepared.owl.carousel': $.proxy(function(e) {
+ if (e.namespace) {
+ var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
+ if (!hash) {
+ return;
+ }
+ this._hashes[hash] = e.content;
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name === 'position') {
+ var current = this._core.items(this._core.relative(this._core.current())),
+ hash = $.map(this._hashes, function(item, hash) {
+ return item === current ? hash : null;
+ }).join();
+ if (!hash || window.location.hash.slice(1) === hash) {
+ return;
+ }
+ window.location.hash = hash;
+ }
+ }, this)
+ };
+ // set default options
+ this._core.options = $.extend({}, Hash.Defaults, this._core.options);
+ // register the event handlers
+ this.$element.on(this._handlers);
+ // register event listener for hash navigation
+ $(window).on('hashchange.owl.navigation', $.proxy(function(e) {
+ var hash = window.location.hash.substring(1),
+ items = this._core.$stage.children(),
+ position = this._hashes[hash] && items.index(this._hashes[hash]);
+ if (position === undefined || position === this._core.current()) {
+ return;
+ }
+ this._core.to(this._core.relative(position), false, true);
+ }, this));
+ };
+ /**
+ * Default options.
+ * @public
+ */
+ Hash.Defaults = {
+ URLhashListener: false
+ };
+ /**
+ * Destroys the plugin.
+ * @public
+ */
+ Hash.prototype.destroy = function() {
+ var handler, property;
+ $(window).off('hashchange.owl.navigation');
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+ $.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
+})(window.Zepto || window.jQuery, window, document);
+/**
+ * Support Plugin
+ *
+ * @version 2.3.4
+ * @author Vivid Planet Software GmbH
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ var style = $('
').get(0).style,
+ prefixes = 'Webkit Moz O ms'.split(' '),
+ events = {
+ transition: {
+ end: {
+ WebkitTransition: 'webkitTransitionEnd',
+ MozTransition: 'transitionend',
+ OTransition: 'oTransitionEnd',
+ transition: 'transitionend'
+ }
+ },
+ animation: {
+ end: {
+ WebkitAnimation: 'webkitAnimationEnd',
+ MozAnimation: 'animationend',
+ OAnimation: 'oAnimationEnd',
+ animation: 'animationend'
+ }
+ }
+ },
+ tests = {
+ csstransforms: function() {
+ return !!test('transform');
+ },
+ csstransforms3d: function() {
+ return !!test('perspective');
+ },
+ csstransitions: function() {
+ return !!test('transition');
+ },
+ cssanimations: function() {
+ return !!test('animation');
+ }
+ };
+ function test(property, prefixed) {
+ var result = false,
+ upper = property.charAt(0).toUpperCase() + property.slice(1);
+
+ $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
+ if (style[property] !== undefined) {
+ result = prefixed ? property : true;
+ return false;
+ }
+ });
+
+ return result;
+ }
+ function prefixed(property) {
+ return test(property, true);
+ }
+ if (tests.csstransitions()) {
+ /* jshint -W053 */
+ $.support.transition = new String(prefixed('transition'))
+ $.support.transition.end = events.transition.end[ $.support.transition ];
+ }
+ if (tests.cssanimations()) {
+ /* jshint -W053 */
+ $.support.animation = new String(prefixed('animation'))
+ $.support.animation.end = events.animation.end[ $.support.animation ];
+ }
+ if (tests.csstransforms()) {
+ /* jshint -W053 */
+ $.support.transform = new String(prefixed('transform'));
+ $.support.transform3d = tests.csstransforms3d();
+ }
+})(window.Zepto || window.jQuery, window, document);
diff --git a/theme_lego/static/src/js/owl.carousel.min.js b/theme_lego/static/src/js/owl.carousel.min.js
new file mode 100644
index 0000000000..fbbffc5340
--- /dev/null
+++ b/theme_lego/static/src/js/owl.carousel.min.js
@@ -0,0 +1,7 @@
+/**
+ * Owl Carousel v2.3.4
+ * Copyright 2013-2018 David Deutsch
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
+ */
+!function(a,b,c,d){function e(b,c){this.settings=null,this.options=a.extend({},e.Defaults,c),this.$element=a(b),this._handlers={},this._plugins={},this._supress={},this._current=null,this._speed=null,this._coordinates=[],this._breakpoint=null,this._width=null,this._items=[],this._clones=[],this._mergers=[],this._widths=[],this._invalidated={},this._pipe=[],this._drag={time:null,target:null,pointer:null,stage:{start:null,current:null},direction:null},this._states={current:{},tags:{initializing:["busy"],animating:["busy"],dragging:["interacting"]}},a.each(["onResize","onThrottledResize"],a.proxy(function(b,c){this._handlers[c]=a.proxy(this[c],this)},this)),a.each(e.Plugins,a.proxy(function(a,b){this._plugins[a.charAt(0).toLowerCase()+a.slice(1)]=new b(this)},this)),a.each(e.Workers,a.proxy(function(b,c){this._pipe.push({filter:c.filter,run:a.proxy(c.run,this)})},this)),this.setup(),this.initialize()}e.Defaults={items:3,loop:!1,center:!1,rewind:!1,checkVisibility:!0,mouseDrag:!0,touchDrag:!0,pullDrag:!0,freeDrag:!1,margin:0,stagePadding:0,merge:!1,mergeFit:!0,autoWidth:!1,startPosition:0,rtl:!1,smartSpeed:250,fluidSpeed:!1,dragEndSpeed:!1,responsive:{},responsiveRefreshRate:200,responsiveBaseElement:b,fallbackEasing:"swing",slideTransition:"",info:!1,nestedItemSelector:!1,itemElement:"div",stageElement:"div",refreshClass:"owl-refresh",loadedClass:"owl-loaded",loadingClass:"owl-loading",rtlClass:"owl-rtl",responsiveClass:"owl-responsive",dragClass:"owl-drag",itemClass:"owl-item",stageClass:"owl-stage",stageOuterClass:"owl-stage-outer",grabClass:"owl-grab"},e.Width={Default:"default",Inner:"inner",Outer:"outer"},e.Type={Event:"event",State:"state"},e.Plugins={},e.Workers=[{filter:["width","settings"],run:function(){this._width=this.$element.width()}},{filter:["width","items","settings"],run:function(a){a.current=this._items&&this._items[this.relative(this._current)]}},{filter:["items","settings"],run:function(){this.$stage.children(".cloned").remove()}},{filter:["width","items","settings"],run:function(a){var b=this.settings.margin||"",c=!this.settings.autoWidth,d=this.settings.rtl,e={width:"auto","margin-left":d?b:"","margin-right":d?"":b};!c&&this.$stage.children().css(e),a.css=e}},{filter:["width","items","settings"],run:function(a){var b=(this.width()/this.settings.items).toFixed(3)-this.settings.margin,c=null,d=this._items.length,e=!this.settings.autoWidth,f=[];for(a.items={merge:!1,width:b};d--;)c=this._mergers[d],c=this.settings.mergeFit&&Math.min(c,this.settings.items)||c,a.items.merge=c>1||a.items.merge,f[d]=e?b*c:this._items[d].width();this._widths=f}},{filter:["items","settings"],run:function(){var b=[],c=this._items,d=this.settings,e=Math.max(2*d.items,4),f=2*Math.ceil(c.length/2),g=d.loop&&c.length?d.rewind?e:Math.max(e,f):0,h="",i="";for(g/=2;g>0;)b.push(this.normalize(b.length/2,!0)),h+=c[b[b.length-1]][0].outerHTML,b.push(this.normalize(c.length-1-(b.length-1)/2,!0)),i=c[b[b.length-1]][0].outerHTML+i,g-=1;this._clones=b,a(h).addClass("cloned").appendTo(this.$stage),a(i).addClass("cloned").prependTo(this.$stage)}},{filter:["width","items","settings"],run:function(){for(var a=this.settings.rtl?1:-1,b=this._clones.length+this._items.length,c=-1,d=0,e=0,f=[];++c",h)||this.op(b,"<",g)&&this.op(b,">",h))&&i.push(c);this.$stage.children(".active").removeClass("active"),this.$stage.children(":eq("+i.join("), :eq(")+")").addClass("active"),this.$stage.children(".center").removeClass("center"),this.settings.center&&this.$stage.children().eq(this.current()).addClass("center")}}],e.prototype.initializeStage=function(){this.$stage=this.$element.find("."+this.settings.stageClass),this.$stage.length||(this.$element.addClass(this.options.loadingClass),this.$stage=a("<"+this.settings.stageElement+">",{class:this.settings.stageClass}).wrap(a("
",{class:this.settings.stageOuterClass})),this.$element.append(this.$stage.parent()))},e.prototype.initializeItems=function(){var b=this.$element.find(".owl-item");if(b.length)return this._items=b.get().map(function(b){return a(b)}),this._mergers=this._items.map(function(){return 1}),void this.refresh();this.replace(this.$element.children().not(this.$stage.parent())),this.isVisible()?this.refresh():this.invalidate("width"),this.$element.removeClass(this.options.loadingClass).addClass(this.options.loadedClass)},e.prototype.initialize=function(){if(this.enter("initializing"),this.trigger("initialize"),this.$element.toggleClass(this.settings.rtlClass,this.settings.rtl),this.settings.autoWidth&&!this.is("pre-loading")){var a,b,c;a=this.$element.find("img"),b=this.settings.nestedItemSelector?"."+this.settings.nestedItemSelector:d,c=this.$element.children(b).width(),a.length&&c<=0&&this.preloadAutoWidthImages(a)}this.initializeStage(),this.initializeItems(),this.registerEventHandlers(),this.leave("initializing"),this.trigger("initialized")},e.prototype.isVisible=function(){return!this.settings.checkVisibility||this.$element.is(":visible")},e.prototype.setup=function(){var b=this.viewport(),c=this.options.responsive,d=-1,e=null;c?(a.each(c,function(a){a<=b&&a>d&&(d=Number(a))}),e=a.extend({},this.options,c[d]),"function"==typeof e.stagePadding&&(e.stagePadding=e.stagePadding()),delete e.responsive,e.responsiveClass&&this.$element.attr("class",this.$element.attr("class").replace(new RegExp("("+this.options.responsiveClass+"-)\\S+\\s","g"),"$1"+d))):e=a.extend({},this.options),this.trigger("change",{property:{name:"settings",value:e}}),this._breakpoint=d,this.settings=e,this.invalidate("settings"),this.trigger("changed",{property:{name:"settings",value:this.settings}})},e.prototype.optionsLogic=function(){this.settings.autoWidth&&(this.settings.stagePadding=!1,this.settings.merge=!1)},e.prototype.prepare=function(b){var c=this.trigger("prepare",{content:b});return c.data||(c.data=a("<"+this.settings.itemElement+"/>").addClass(this.options.itemClass).append(b)),this.trigger("prepared",{content:c.data}),c.data},e.prototype.update=function(){for(var b=0,c=this._pipe.length,d=a.proxy(function(a){return this[a]},this._invalidated),e={};b0)&&this._pipe[b].run(e),b++;this._invalidated={},!this.is("valid")&&this.enter("valid")},e.prototype.width=function(a){switch(a=a||e.Width.Default){case e.Width.Inner:case e.Width.Outer:return this._width;default:return this._width-2*this.settings.stagePadding+this.settings.margin}},e.prototype.refresh=function(){this.enter("refreshing"),this.trigger("refresh"),this.setup(),this.optionsLogic(),this.$element.addClass(this.options.refreshClass),this.update(),this.$element.removeClass(this.options.refreshClass),this.leave("refreshing"),this.trigger("refreshed")},e.prototype.onThrottledResize=function(){b.clearTimeout(this.resizeTimer),this.resizeTimer=b.setTimeout(this._handlers.onResize,this.settings.responsiveRefreshRate)},e.prototype.onResize=function(){return!!this._items.length&&(this._width!==this.$element.width()&&(!!this.isVisible()&&(this.enter("resizing"),this.trigger("resize").isDefaultPrevented()?(this.leave("resizing"),!1):(this.invalidate("width"),this.refresh(),this.leave("resizing"),void this.trigger("resized")))))},e.prototype.registerEventHandlers=function(){a.support.transition&&this.$stage.on(a.support.transition.end+".owl.core",a.proxy(this.onTransitionEnd,this)),!1!==this.settings.responsive&&this.on(b,"resize",this._handlers.onThrottledResize),this.settings.mouseDrag&&(this.$element.addClass(this.options.dragClass),this.$stage.on("mousedown.owl.core",a.proxy(this.onDragStart,this)),this.$stage.on("dragstart.owl.core selectstart.owl.core",function(){return!1})),this.settings.touchDrag&&(this.$stage.on("touchstart.owl.core",a.proxy(this.onDragStart,this)),this.$stage.on("touchcancel.owl.core",a.proxy(this.onDragEnd,this)))},e.prototype.onDragStart=function(b){var d=null;3!==b.which&&(a.support.transform?(d=this.$stage.css("transform").replace(/.*\(|\)| /g,"").split(","),d={x:d[16===d.length?12:4],y:d[16===d.length?13:5]}):(d=this.$stage.position(),d={x:this.settings.rtl?d.left+this.$stage.width()-this.width()+this.settings.margin:d.left,y:d.top}),this.is("animating")&&(a.support.transform?this.animate(d.x):this.$stage.stop(),this.invalidate("position")),this.$element.toggleClass(this.options.grabClass,"mousedown"===b.type),this.speed(0),this._drag.time=(new Date).getTime(),this._drag.target=a(b.target),this._drag.stage.start=d,this._drag.stage.current=d,this._drag.pointer=this.pointer(b),a(c).on("mouseup.owl.core touchend.owl.core",a.proxy(this.onDragEnd,this)),a(c).one("mousemove.owl.core touchmove.owl.core",a.proxy(function(b){var d=this.difference(this._drag.pointer,this.pointer(b));a(c).on("mousemove.owl.core touchmove.owl.core",a.proxy(this.onDragMove,this)),Math.abs(d.x)0^this.settings.rtl?"left":"right";a(c).off(".owl.core"),this.$element.removeClass(this.options.grabClass),(0!==d.x&&this.is("dragging")||!this.is("valid"))&&(this.speed(this.settings.dragEndSpeed||this.settings.smartSpeed),this.current(this.closest(e.x,0!==d.x?f:this._drag.direction)),this.invalidate("position"),this.update(),this._drag.direction=f,(Math.abs(d.x)>3||(new Date).getTime()-this._drag.time>300)&&this._drag.target.one("click.owl.core",function(){return!1})),this.is("dragging")&&(this.leave("dragging"),this.trigger("dragged"))},e.prototype.closest=function(b,c){var e=-1,f=30,g=this.width(),h=this.coordinates();return this.settings.freeDrag||a.each(h,a.proxy(function(a,i){return"left"===c&&b>i-f&&bi-g-f&&b",h[a+1]!==d?h[a+1]:i-g)&&(e="left"===c?a+1:a),-1===e},this)),this.settings.loop||(this.op(b,">",h[this.minimum()])?e=b=this.minimum():this.op(b,"<",h[this.maximum()])&&(e=b=this.maximum())),e},e.prototype.animate=function(b){var c=this.speed()>0;this.is("animating")&&this.onTransitionEnd(),c&&(this.enter("animating"),this.trigger("translate")),a.support.transform3d&&a.support.transition?this.$stage.css({transform:"translate3d("+b+"px,0px,0px)",transition:this.speed()/1e3+"s"+(this.settings.slideTransition?" "+this.settings.slideTransition:"")}):c?this.$stage.animate({left:b+"px"},this.speed(),this.settings.fallbackEasing,a.proxy(this.onTransitionEnd,this)):this.$stage.css({left:b+"px"})},e.prototype.is=function(a){return this._states.current[a]&&this._states.current[a]>0},e.prototype.current=function(a){if(a===d)return this._current;if(0===this._items.length)return d;if(a=this.normalize(a),this._current!==a){var b=this.trigger("change",{property:{name:"position",value:a}});b.data!==d&&(a=this.normalize(b.data)),this._current=a,this.invalidate("position"),this.trigger("changed",{property:{name:"position",value:this._current}})}return this._current},e.prototype.invalidate=function(b){return"string"===a.type(b)&&(this._invalidated[b]=!0,this.is("valid")&&this.leave("valid")),a.map(this._invalidated,function(a,b){return b})},e.prototype.reset=function(a){(a=this.normalize(a))!==d&&(this._speed=0,this._current=a,this.suppress(["translate","translated"]),this.animate(this.coordinates(a)),this.release(["translate","translated"]))},e.prototype.normalize=function(a,b){var c=this._items.length,e=b?0:this._clones.length;return!this.isNumeric(a)||c<1?a=d:(a<0||a>=c+e)&&(a=((a-e/2)%c+c)%c+e/2),a},e.prototype.relative=function(a){return a-=this._clones.length/2,this.normalize(a,!0)},e.prototype.maximum=function(a){var b,c,d,e=this.settings,f=this._coordinates.length;if(e.loop)f=this._clones.length/2+this._items.length-1;else if(e.autoWidth||e.merge){if(b=this._items.length)for(c=this._items[--b].width(),d=this.$element.width();b--&&!((c+=this._items[b].width()+this.settings.margin)>d););f=b+1}else f=e.center?this._items.length-1:this._items.length-e.items;return a&&(f-=this._clones.length/2),Math.max(f,0)},e.prototype.minimum=function(a){return a?0:this._clones.length/2},e.prototype.items=function(a){return a===d?this._items.slice():(a=this.normalize(a,!0),this._items[a])},e.prototype.mergers=function(a){return a===d?this._mergers.slice():(a=this.normalize(a,!0),this._mergers[a])},e.prototype.clones=function(b){var c=this._clones.length/2,e=c+this._items.length,f=function(a){return a%2==0?e+a/2:c-(a+1)/2};return b===d?a.map(this._clones,function(a,b){return f(b)}):a.map(this._clones,function(a,c){return a===b?f(c):null})},e.prototype.speed=function(a){return a!==d&&(this._speed=a),this._speed},e.prototype.coordinates=function(b){var c,e=1,f=b-1;return b===d?a.map(this._coordinates,a.proxy(function(a,b){return this.coordinates(b)},this)):(this.settings.center?(this.settings.rtl&&(e=-1,f=b+1),c=this._coordinates[b],c+=(this.width()-c+(this._coordinates[f]||0))/2*e):c=this._coordinates[f]||0,c=Math.ceil(c))},e.prototype.duration=function(a,b,c){return 0===c?0:Math.min(Math.max(Math.abs(b-a),1),6)*Math.abs(c||this.settings.smartSpeed)},e.prototype.to=function(a,b){var c=this.current(),d=null,e=a-this.relative(c),f=(e>0)-(e<0),g=this._items.length,h=this.minimum(),i=this.maximum();this.settings.loop?(!this.settings.rewind&&Math.abs(e)>g/2&&(e+=-1*f*g),a=c+e,(d=((a-h)%g+g)%g+h)!==a&&d-e<=i&&d-e>0&&(c=d-e,a=d,this.reset(c))):this.settings.rewind?(i+=1,a=(a%i+i)%i):a=Math.max(h,Math.min(i,a)),this.speed(this.duration(c,a,b)),this.current(a),this.isVisible()&&this.update()},e.prototype.next=function(a){a=a||!1,this.to(this.relative(this.current())+1,a)},e.prototype.prev=function(a){a=a||!1,this.to(this.relative(this.current())-1,a)},e.prototype.onTransitionEnd=function(a){if(a!==d&&(a.stopPropagation(),(a.target||a.srcElement||a.originalTarget)!==this.$stage.get(0)))return!1;this.leave("animating"),this.trigger("translated")},e.prototype.viewport=function(){var d;return this.options.responsiveBaseElement!==b?d=a(this.options.responsiveBaseElement).width():b.innerWidth?d=b.innerWidth:c.documentElement&&c.documentElement.clientWidth?d=c.documentElement.clientWidth:console.warn("Can not detect viewport width."),d},e.prototype.replace=function(b){this.$stage.empty(),this._items=[],b&&(b=b instanceof jQuery?b:a(b)),this.settings.nestedItemSelector&&(b=b.find("."+this.settings.nestedItemSelector)),b.filter(function(){return 1===this.nodeType}).each(a.proxy(function(a,b){b=this.prepare(b),this.$stage.append(b),this._items.push(b),this._mergers.push(1*b.find("[data-merge]").addBack("[data-merge]").attr("data-merge")||1)},this)),this.reset(this.isNumeric(this.settings.startPosition)?this.settings.startPosition:0),this.invalidate("items")},e.prototype.add=function(b,c){var e=this.relative(this._current);c=c===d?this._items.length:this.normalize(c,!0),b=b instanceof jQuery?b:a(b),this.trigger("add",{content:b,position:c}),b=this.prepare(b),0===this._items.length||c===this._items.length?(0===this._items.length&&this.$stage.append(b),0!==this._items.length&&this._items[c-1].after(b),this._items.push(b),this._mergers.push(1*b.find("[data-merge]").addBack("[data-merge]").attr("data-merge")||1)):(this._items[c].before(b),this._items.splice(c,0,b),this._mergers.splice(c,0,1*b.find("[data-merge]").addBack("[data-merge]").attr("data-merge")||1)),this._items[e]&&this.reset(this._items[e].index()),this.invalidate("items"),this.trigger("added",{content:b,position:c})},e.prototype.remove=function(a){(a=this.normalize(a,!0))!==d&&(this.trigger("remove",{content:this._items[a],position:a}),this._items[a].remove(),this._items.splice(a,1),this._mergers.splice(a,1),this.invalidate("items"),this.trigger("removed",{content:null,position:a}))},e.prototype.preloadAutoWidthImages=function(b){b.each(a.proxy(function(b,c){this.enter("pre-loading"),c=a(c),a(new Image).one("load",a.proxy(function(a){c.attr("src",a.target.src),c.css("opacity",1),this.leave("pre-loading"),!this.is("pre-loading")&&!this.is("initializing")&&this.refresh()},this)).attr("src",c.attr("src")||c.attr("data-src")||c.attr("data-src-retina"))},this))},e.prototype.destroy=function(){this.$element.off(".owl.core"),this.$stage.off(".owl.core"),a(c).off(".owl.core"),!1!==this.settings.responsive&&(b.clearTimeout(this.resizeTimer),this.off(b,"resize",this._handlers.onThrottledResize));for(var d in this._plugins)this._plugins[d].destroy();this.$stage.children(".cloned").remove(),this.$stage.unwrap(),this.$stage.children().contents().unwrap(),this.$stage.children().unwrap(),this.$stage.remove(),this.$element.removeClass(this.options.refreshClass).removeClass(this.options.loadingClass).removeClass(this.options.loadedClass).removeClass(this.options.rtlClass).removeClass(this.options.dragClass).removeClass(this.options.grabClass).attr("class",this.$element.attr("class").replace(new RegExp(this.options.responsiveClass+"-\\S+\\s","g"),"")).removeData("owl.carousel")},e.prototype.op=function(a,b,c){var d=this.settings.rtl;switch(b){case"<":return d?a>c:a":return d?ac;case">=":return d?a<=c:a>=c;case"<=":return d?a>=c:a<=c}},e.prototype.on=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,d):a.attachEvent&&a.attachEvent("on"+b,c)},e.prototype.off=function(a,b,c,d){a.removeEventListener?a.removeEventListener(b,c,d):a.detachEvent&&a.detachEvent("on"+b,c)},e.prototype.trigger=function(b,c,d,f,g){var h={item:{count:this._items.length,index:this.current()}},i=a.camelCase(a.grep(["on",b,d],function(a){return a}).join("-").toLowerCase()),j=a.Event([b,"owl",d||"carousel"].join(".").toLowerCase(),a.extend({relatedTarget:this},h,c));return this._supress[b]||(a.each(this._plugins,function(a,b){b.onTrigger&&b.onTrigger(j)}),this.register({type:e.Type.Event,name:b}),this.$element.trigger(j),this.settings&&"function"==typeof this.settings[i]&&this.settings[i].call(this,j)),j},e.prototype.enter=function(b){a.each([b].concat(this._states.tags[b]||[]),a.proxy(function(a,b){this._states.current[b]===d&&(this._states.current[b]=0),this._states.current[b]++},this))},e.prototype.leave=function(b){a.each([b].concat(this._states.tags[b]||[]),a.proxy(function(a,b){this._states.current[b]--},this))},e.prototype.register=function(b){if(b.type===e.Type.Event){if(a.event.special[b.name]||(a.event.special[b.name]={}),!a.event.special[b.name].owl){var c=a.event.special[b.name]._default;a.event.special[b.name]._default=function(a){return!c||!c.apply||a.namespace&&-1!==a.namespace.indexOf("owl")?a.namespace&&a.namespace.indexOf("owl")>-1:c.apply(this,arguments)},a.event.special[b.name].owl=!0}}else b.type===e.Type.State&&(this._states.tags[b.name]?this._states.tags[b.name]=this._states.tags[b.name].concat(b.tags):this._states.tags[b.name]=b.tags,this._states.tags[b.name]=a.grep(this._states.tags[b.name],a.proxy(function(c,d){return a.inArray(c,this._states.tags[b.name])===d},this)))},e.prototype.suppress=function(b){a.each(b,a.proxy(function(a,b){this._supress[b]=!0},this))},e.prototype.release=function(b){a.each(b,a.proxy(function(a,b){delete this._supress[b]},this))},e.prototype.pointer=function(a){var c={x:null,y:null};return a=a.originalEvent||a||b.event,a=a.touches&&a.touches.length?a.touches[0]:a.changedTouches&&a.changedTouches.length?a.changedTouches[0]:a,a.pageX?(c.x=a.pageX,c.y=a.pageY):(c.x=a.clientX,c.y=a.clientY),c},e.prototype.isNumeric=function(a){return!isNaN(parseFloat(a))},e.prototype.difference=function(a,b){return{x:a.x-b.x,y:a.y-b.y}},a.fn.owlCarousel=function(b){var c=Array.prototype.slice.call(arguments,1);return this.each(function(){var d=a(this),f=d.data("owl.carousel");f||(f=new e(this,"object"==typeof b&&b),d.data("owl.carousel",f),a.each(["next","prev","to","destroy","refresh","replace","add","remove"],function(b,c){f.register({type:e.Type.Event,name:c}),f.$element.on(c+".owl.carousel.core",a.proxy(function(a){a.namespace&&a.relatedTarget!==this&&(this.suppress([c]),f[c].apply(this,[].slice.call(arguments,1)),this.release([c]))},f))})),"string"==typeof b&&"_"!==b.charAt(0)&&f[b].apply(f,c)})},a.fn.owlCarousel.Constructor=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._interval=null,this._visible=null,this._handlers={"initialized.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoRefresh&&this.watch()},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers)};e.Defaults={autoRefresh:!0,autoRefreshInterval:500},e.prototype.watch=function(){this._interval||(this._visible=this._core.isVisible(),this._interval=b.setInterval(a.proxy(this.refresh,this),this._core.settings.autoRefreshInterval))},e.prototype.refresh=function(){this._core.isVisible()!==this._visible&&(this._visible=!this._visible,this._core.$element.toggleClass("owl-hidden",!this._visible),this._visible&&this._core.invalidate("width")&&this._core.refresh())},e.prototype.destroy=function(){var a,c;b.clearInterval(this._interval);for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(c in Object.getOwnPropertyNames(this))"function"!=typeof this[c]&&(this[c]=null)},a.fn.owlCarousel.Constructor.Plugins.AutoRefresh=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._loaded=[],this._handlers={"initialized.owl.carousel change.owl.carousel resized.owl.carousel":a.proxy(function(b){if(b.namespace&&this._core.settings&&this._core.settings.lazyLoad&&(b.property&&"position"==b.property.name||"initialized"==b.type)){var c=this._core.settings,e=c.center&&Math.ceil(c.items/2)||c.items,f=c.center&&-1*e||0,g=(b.property&&b.property.value!==d?b.property.value:this._core.current())+f,h=this._core.clones().length,i=a.proxy(function(a,b){this.load(b)},this);for(c.lazyLoadEager>0&&(e+=c.lazyLoadEager,c.loop&&(g-=c.lazyLoadEager,e++));f++-1||(e.each(a.proxy(function(c,d){var e,f=a(d),g=b.devicePixelRatio>1&&f.attr("data-src-retina")||f.attr("data-src")||f.attr("data-srcset");this._core.trigger("load",{element:f,url:g},"lazy"),f.is("img")?f.one("load.owl.lazy",a.proxy(function(){f.css("opacity",1),this._core.trigger("loaded",{element:f,url:g},"lazy")},this)).attr("src",g):f.is("source")?f.one("load.owl.lazy",a.proxy(function(){this._core.trigger("loaded",{element:f,url:g},"lazy")},this)).attr("srcset",g):(e=new Image,e.onload=a.proxy(function(){f.css({"background-image":'url("'+g+'")',opacity:"1"}),this._core.trigger("loaded",{element:f,url:g},"lazy")},this),e.src=g)},this)),this._loaded.push(d.get(0)))},e.prototype.destroy=function(){var a,b;for(a in this.handlers)this._core.$element.off(a,this.handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Lazy=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(c){this._core=c,this._previousHeight=null,this._handlers={"initialized.owl.carousel refreshed.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&this.update()},this),"changed.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&"position"===a.property.name&&this.update()},this),"loaded.owl.lazy":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&a.element.closest("."+this._core.settings.itemClass).index()===this._core.current()&&this.update()},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers),this._intervalId=null;var d=this;a(b).on("load",function(){d._core.settings.autoHeight&&d.update()}),a(b).resize(function(){d._core.settings.autoHeight&&(null!=d._intervalId&&clearTimeout(d._intervalId),d._intervalId=setTimeout(function(){d.update()},250))})};e.Defaults={autoHeight:!1,autoHeightClass:"owl-height"},e.prototype.update=function(){var b=this._core._current,c=b+this._core.settings.items,d=this._core.settings.lazyLoad,e=this._core.$stage.children().toArray().slice(b,c),f=[],g=0;a.each(e,function(b,c){f.push(a(c).height())}),g=Math.max.apply(null,f),g<=1&&d&&this._previousHeight&&(g=this._previousHeight),this._previousHeight=g,this._core.$stage.parent().height(g).addClass(this._core.settings.autoHeightClass)},e.prototype.destroy=function(){var a,b;for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.AutoHeight=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._videos={},this._playing=null,this._handlers={"initialized.owl.carousel":a.proxy(function(a){a.namespace&&this._core.register({type:"state",name:"playing",tags:["interacting"]})},this),"resize.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.video&&this.isInFullScreen()&&a.preventDefault()},this),"refreshed.owl.carousel":a.proxy(function(a){a.namespace&&this._core.is("resizing")&&this._core.$stage.find(".cloned .owl-video-frame").remove()},this),"changed.owl.carousel":a.proxy(function(a){a.namespace&&"position"===a.property.name&&this._playing&&this.stop()},this),"prepared.owl.carousel":a.proxy(function(b){if(b.namespace){var c=a(b.content).find(".owl-video");c.length&&(c.css("display","none"),this.fetch(c,a(b.content)))}},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers),this._core.$element.on("click.owl.video",".owl-video-play-icon",a.proxy(function(a){this.play(a)},this))};e.Defaults={video:!1,videoHeight:!1,videoWidth:!1},e.prototype.fetch=function(a,b){var c=function(){return a.attr("data-vimeo-id")?"vimeo":a.attr("data-vzaar-id")?"vzaar":"youtube"}(),d=a.attr("data-vimeo-id")||a.attr("data-youtube-id")||a.attr("data-vzaar-id"),e=a.attr("data-width")||this._core.settings.videoWidth,f=a.attr("data-height")||this._core.settings.videoHeight,g=a.attr("href");if(!g)throw new Error("Missing video URL.");if(d=g.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com|be\-nocookie\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/),d[3].indexOf("youtu")>-1)c="youtube";else if(d[3].indexOf("vimeo")>-1)c="vimeo";else{if(!(d[3].indexOf("vzaar")>-1))throw new Error("Video URL not supported.");c="vzaar"}d=d[6],this._videos[g]={type:c,id:d,width:e,height:f},b.attr("data-video",g),this.thumbnail(a,this._videos[g])},e.prototype.thumbnail=function(b,c){var d,e,f,g=c.width&&c.height?"width:"+c.width+"px;height:"+c.height+"px;":"",h=b.find("img"),i="src",j="",k=this._core.settings,l=function(c){e='
',d=k.lazyLoad?a("
",{class:"owl-video-tn "+j,srcType:c}):a("
",{class:"owl-video-tn",style:"opacity:1;background-image:url("+c+")"}),b.after(d),b.after(e)};if(b.wrap(a("
",{class:"owl-video-wrapper",style:g})),this._core.settings.lazyLoad&&(i="data-src",j="owl-lazy"),h.length)return l(h.attr(i)),h.remove(),!1;"youtube"===c.type?(f="//img.youtube.com/vi/"+c.id+"/hqdefault.jpg",l(f)):"vimeo"===c.type?a.ajax({type:"GET",url:"//vimeo.com/api/v2/video/"+c.id+".json",jsonp:"callback",dataType:"jsonp",success:function(a){f=a[0].thumbnail_large,l(f)}}):"vzaar"===c.type&&a.ajax({type:"GET",url:"//vzaar.com/api/videos/"+c.id+".json",jsonp:"callback",dataType:"jsonp",success:function(a){f=a.framegrab_url,l(f)}})},e.prototype.stop=function(){this._core.trigger("stop",null,"video"),this._playing.find(".owl-video-frame").remove(),this._playing.removeClass("owl-video-playing"),this._playing=null,this._core.leave("playing"),this._core.trigger("stopped",null,"video")},e.prototype.play=function(b){var c,d=a(b.target),e=d.closest("."+this._core.settings.itemClass),f=this._videos[e.attr("data-video")],g=f.width||"100%",h=f.height||this._core.$stage.height();this._playing||(this._core.enter("playing"),this._core.trigger("play",null,"video"),e=this._core.items(this._core.relative(e.index())),this._core.reset(e.index()),c=a(''),c.attr("height",h),c.attr("width",g),"youtube"===f.type?c.attr("src","//www.youtube.com/embed/"+f.id+"?autoplay=1&rel=0&v="+f.id):"vimeo"===f.type?c.attr("src","//player.vimeo.com/video/"+f.id+"?autoplay=1"):"vzaar"===f.type&&c.attr("src","//view.vzaar.com/"+f.id+"/player?autoplay=true"),a(c).wrap('
').insertAfter(e.find(".owl-video")),this._playing=e.addClass("owl-video-playing"))},e.prototype.isInFullScreen=function(){var b=c.fullscreenElement||c.mozFullScreenElement||c.webkitFullscreenElement;return b&&a(b).parent().hasClass("owl-video-frame")},e.prototype.destroy=function(){var a,b;this._core.$element.off("click.owl.video");for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Video=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this.core=b,this.core.options=a.extend({},e.Defaults,this.core.options),this.swapping=!0,this.previous=d,this.next=d,this.handlers={"change.owl.carousel":a.proxy(function(a){a.namespace&&"position"==a.property.name&&(this.previous=this.core.current(),this.next=a.property.value)},this),"drag.owl.carousel dragged.owl.carousel translated.owl.carousel":a.proxy(function(a){a.namespace&&(this.swapping="translated"==a.type)},this),"translate.owl.carousel":a.proxy(function(a){a.namespace&&this.swapping&&(this.core.options.animateOut||this.core.options.animateIn)&&this.swap()},this)},this.core.$element.on(this.handlers)};e.Defaults={animateOut:!1,
+animateIn:!1},e.prototype.swap=function(){if(1===this.core.settings.items&&a.support.animation&&a.support.transition){this.core.speed(0);var b,c=a.proxy(this.clear,this),d=this.core.$stage.children().eq(this.previous),e=this.core.$stage.children().eq(this.next),f=this.core.settings.animateIn,g=this.core.settings.animateOut;this.core.current()!==this.previous&&(g&&(b=this.core.coordinates(this.previous)-this.core.coordinates(this.next),d.one(a.support.animation.end,c).css({left:b+"px"}).addClass("animated owl-animated-out").addClass(g)),f&&e.one(a.support.animation.end,c).addClass("animated owl-animated-in").addClass(f))}},e.prototype.clear=function(b){a(b.target).css({left:""}).removeClass("animated owl-animated-out owl-animated-in").removeClass(this.core.settings.animateIn).removeClass(this.core.settings.animateOut),this.core.onTransitionEnd()},e.prototype.destroy=function(){var a,b;for(a in this.handlers)this.core.$element.off(a,this.handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Animate=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._call=null,this._time=0,this._timeout=0,this._paused=!0,this._handlers={"changed.owl.carousel":a.proxy(function(a){a.namespace&&"settings"===a.property.name?this._core.settings.autoplay?this.play():this.stop():a.namespace&&"position"===a.property.name&&this._paused&&(this._time=0)},this),"initialized.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoplay&&this.play()},this),"play.owl.autoplay":a.proxy(function(a,b,c){a.namespace&&this.play(b,c)},this),"stop.owl.autoplay":a.proxy(function(a){a.namespace&&this.stop()},this),"mouseover.owl.autoplay":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is("rotating")&&this.pause()},this),"mouseleave.owl.autoplay":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is("rotating")&&this.play()},this),"touchstart.owl.core":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is("rotating")&&this.pause()},this),"touchend.owl.core":a.proxy(function(){this._core.settings.autoplayHoverPause&&this.play()},this)},this._core.$element.on(this._handlers),this._core.options=a.extend({},e.Defaults,this._core.options)};e.Defaults={autoplay:!1,autoplayTimeout:5e3,autoplayHoverPause:!1,autoplaySpeed:!1},e.prototype._next=function(d){this._call=b.setTimeout(a.proxy(this._next,this,d),this._timeout*(Math.round(this.read()/this._timeout)+1)-this.read()),this._core.is("interacting")||c.hidden||this._core.next(d||this._core.settings.autoplaySpeed)},e.prototype.read=function(){return(new Date).getTime()-this._time},e.prototype.play=function(c,d){var e;this._core.is("rotating")||this._core.enter("rotating"),c=c||this._core.settings.autoplayTimeout,e=Math.min(this._time%(this._timeout||c),c),this._paused?(this._time=this.read(),this._paused=!1):b.clearTimeout(this._call),this._time+=this.read()%c-e,this._timeout=c,this._call=b.setTimeout(a.proxy(this._next,this,d),c-e)},e.prototype.stop=function(){this._core.is("rotating")&&(this._time=0,this._paused=!0,b.clearTimeout(this._call),this._core.leave("rotating"))},e.prototype.pause=function(){this._core.is("rotating")&&!this._paused&&(this._time=this.read(),this._paused=!0,b.clearTimeout(this._call))},e.prototype.destroy=function(){var a,b;this.stop();for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.autoplay=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){"use strict";var e=function(b){this._core=b,this._initialized=!1,this._pages=[],this._controls={},this._templates=[],this.$element=this._core.$element,this._overrides={next:this._core.next,prev:this._core.prev,to:this._core.to},this._handlers={"prepared.owl.carousel":a.proxy(function(b){b.namespace&&this._core.settings.dotsData&&this._templates.push(''+a(b.content).find("[data-dot]").addBack("[data-dot]").attr("data-dot")+"
")},this),"added.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.dotsData&&this._templates.splice(a.position,0,this._templates.pop())},this),"remove.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.dotsData&&this._templates.splice(a.position,1)},this),"changed.owl.carousel":a.proxy(function(a){a.namespace&&"position"==a.property.name&&this.draw()},this),"initialized.owl.carousel":a.proxy(function(a){a.namespace&&!this._initialized&&(this._core.trigger("initialize",null,"navigation"),this.initialize(),this.update(),this.draw(),this._initialized=!0,this._core.trigger("initialized",null,"navigation"))},this),"refreshed.owl.carousel":a.proxy(function(a){a.namespace&&this._initialized&&(this._core.trigger("refresh",null,"navigation"),this.update(),this.draw(),this._core.trigger("refreshed",null,"navigation"))},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this.$element.on(this._handlers)};e.Defaults={nav:!1,navText:['‹ ','› '],navSpeed:!1,navElement:'button type="button" role="presentation"',navContainer:!1,navContainerClass:"owl-nav",navClass:["owl-prev","owl-next"],slideBy:1,dotClass:"owl-dot",dotsClass:"owl-dots",dots:!0,dotsEach:!1,dotsData:!1,dotsSpeed:!1,dotsContainer:!1},e.prototype.initialize=function(){var b,c=this._core.settings;this._controls.$relative=(c.navContainer?a(c.navContainer):a("").addClass(c.navContainerClass).appendTo(this.$element)).addClass("disabled"),this._controls.$previous=a("<"+c.navElement+">").addClass(c.navClass[0]).html(c.navText[0]).prependTo(this._controls.$relative).on("click",a.proxy(function(a){this.prev(c.navSpeed)},this)),this._controls.$next=a("<"+c.navElement+">").addClass(c.navClass[1]).html(c.navText[1]).appendTo(this._controls.$relative).on("click",a.proxy(function(a){this.next(c.navSpeed)},this)),c.dotsData||(this._templates=[a('
').addClass(c.dotClass).append(a("")).prop("outerHTML")]),this._controls.$absolute=(c.dotsContainer?a(c.dotsContainer):a("").addClass(c.dotsClass).appendTo(this.$element)).addClass("disabled"),this._controls.$absolute.on("click","button",a.proxy(function(b){var d=a(b.target).parent().is(this._controls.$absolute)?a(b.target).index():a(b.target).parent().index();b.preventDefault(),this.to(d,c.dotsSpeed)},this));for(b in this._overrides)this._core[b]=a.proxy(this[b],this)},e.prototype.destroy=function(){var a,b,c,d,e;e=this._core.settings;for(a in this._handlers)this.$element.off(a,this._handlers[a]);for(b in this._controls)"$relative"===b&&e.navContainer?this._controls[b].html(""):this._controls[b].remove();for(d in this.overides)this._core[d]=this._overrides[d];for(c in Object.getOwnPropertyNames(this))"function"!=typeof this[c]&&(this[c]=null)},e.prototype.update=function(){var a,b,c,d=this._core.clones().length/2,e=d+this._core.items().length,f=this._core.maximum(!0),g=this._core.settings,h=g.center||g.autoWidth||g.dotsData?1:g.dotsEach||g.items;if("page"!==g.slideBy&&(g.slideBy=Math.min(g.slideBy,g.items)),g.dots||"page"==g.slideBy)for(this._pages=[],a=d,b=0,c=0;a
=h||0===b){if(this._pages.push({start:Math.min(f,a-d),end:a-d+h-1}),Math.min(f,a-d)===f)break;b=0,++c}b+=this._core.mergers(this._core.relative(a))}},e.prototype.draw=function(){var b,c=this._core.settings,d=this._core.items().length<=c.items,e=this._core.relative(this._core.current()),f=c.loop||c.rewind;this._controls.$relative.toggleClass("disabled",!c.nav||d),c.nav&&(this._controls.$previous.toggleClass("disabled",!f&&e<=this._core.minimum(!0)),this._controls.$next.toggleClass("disabled",!f&&e>=this._core.maximum(!0))),this._controls.$absolute.toggleClass("disabled",!c.dots||d),c.dots&&(b=this._pages.length-this._controls.$absolute.children().length,c.dotsData&&0!==b?this._controls.$absolute.html(this._templates.join("")):b>0?this._controls.$absolute.append(new Array(b+1).join(this._templates[0])):b<0&&this._controls.$absolute.children().slice(b).remove(),this._controls.$absolute.find(".active").removeClass("active"),this._controls.$absolute.children().eq(a.inArray(this.current(),this._pages)).addClass("active"))},e.prototype.onTrigger=function(b){var c=this._core.settings;b.page={index:a.inArray(this.current(),this._pages),count:this._pages.length,size:c&&(c.center||c.autoWidth||c.dotsData?1:c.dotsEach||c.items)}},e.prototype.current=function(){var b=this._core.relative(this._core.current());return a.grep(this._pages,a.proxy(function(a,c){return a.start<=b&&a.end>=b},this)).pop()},e.prototype.getPosition=function(b){var c,d,e=this._core.settings;return"page"==e.slideBy?(c=a.inArray(this.current(),this._pages),d=this._pages.length,b?++c:--c,c=this._pages[(c%d+d)%d].start):(c=this._core.relative(this._core.current()),d=this._core.items().length,b?c+=e.slideBy:c-=e.slideBy),c},e.prototype.next=function(b){a.proxy(this._overrides.to,this._core)(this.getPosition(!0),b)},e.prototype.prev=function(b){a.proxy(this._overrides.to,this._core)(this.getPosition(!1),b)},e.prototype.to=function(b,c,d){var e;!d&&this._pages.length?(e=this._pages.length,a.proxy(this._overrides.to,this._core)(this._pages[(b%e+e)%e].start,c)):a.proxy(this._overrides.to,this._core)(b,c)},a.fn.owlCarousel.Constructor.Plugins.Navigation=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){"use strict";var e=function(c){this._core=c,this._hashes={},this.$element=this._core.$element,this._handlers={"initialized.owl.carousel":a.proxy(function(c){c.namespace&&"URLHash"===this._core.settings.startPosition&&a(b).trigger("hashchange.owl.navigation")},this),"prepared.owl.carousel":a.proxy(function(b){if(b.namespace){var c=a(b.content).find("[data-hash]").addBack("[data-hash]").attr("data-hash");if(!c)return;this._hashes[c]=b.content}},this),"changed.owl.carousel":a.proxy(function(c){if(c.namespace&&"position"===c.property.name){var d=this._core.items(this._core.relative(this._core.current())),e=a.map(this._hashes,function(a,b){return a===d?b:null}).join();if(!e||b.location.hash.slice(1)===e)return;b.location.hash=e}},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this.$element.on(this._handlers),a(b).on("hashchange.owl.navigation",a.proxy(function(a){var c=b.location.hash.substring(1),e=this._core.$stage.children(),f=this._hashes[c]&&e.index(this._hashes[c]);f!==d&&f!==this._core.current()&&this._core.to(this._core.relative(f),!1,!0)},this))};e.Defaults={URLhashListener:!1},e.prototype.destroy=function(){var c,d;a(b).off("hashchange.owl.navigation");for(c in this._handlers)this._core.$element.off(c,this._handlers[c]);for(d in Object.getOwnPropertyNames(this))"function"!=typeof this[d]&&(this[d]=null)},a.fn.owlCarousel.Constructor.Plugins.Hash=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){function e(b,c){var e=!1,f=b.charAt(0).toUpperCase()+b.slice(1);return a.each((b+" "+h.join(f+" ")+f).split(" "),function(a,b){if(g[b]!==d)return e=!c||b,!1}),e}function f(a){return e(a,!0)}var g=a("").get(0).style,h="Webkit Moz O ms".split(" "),i={transition:{end:{WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",transition:"transitionend"}},animation:{end:{WebkitAnimation:"webkitAnimationEnd",MozAnimation:"animationend",OAnimation:"oAnimationEnd",animation:"animationend"}}},j={csstransforms:function(){return!!e("transform")},csstransforms3d:function(){return!!e("perspective")},csstransitions:function(){return!!e("transition")},cssanimations:function(){return!!e("animation")}};j.csstransitions()&&(a.support.transition=new String(f("transition")),a.support.transition.end=i.transition.end[a.support.transition]),j.cssanimations()&&(a.support.animation=new String(f("animation")),a.support.animation.end=i.animation.end[a.support.animation]),j.csstransforms()&&(a.support.transform=new String(f("transform")),a.support.transform3d=j.csstransforms3d())}(window.Zepto||window.jQuery,window,document);
\ No newline at end of file
diff --git a/theme_lego/static/src/js/subscription.js b/theme_lego/static/src/js/subscription.js
new file mode 100644
index 0000000000..d3e9e0e785
--- /dev/null
+++ b/theme_lego/static/src/js/subscription.js
@@ -0,0 +1,36 @@
+/** @odoo-module **/
+
+import publicWidget from "@web/legacy/js/public/public_widget";
+import { rpc } from "@web/core/network/rpc";
+
+publicWidget.registry.WebsiteSaleCart = publicWidget.Widget.extend({
+ selector: '#wrapwrap',
+ events: {
+ 'click .subscribe-btn': 'onClickSubscribe',
+ },
+
+ async onClickSubscribe(ev) {
+ // Function for subscribe newsletter.
+ const $button = $(ev.currentTarget);
+ const $input = $(ev.currentTarget.parentElement).find('input');
+ this.$el.removeClass('o_has_error').find('.form-control').removeClass('is-invalid');
+ if ($input.val().match(/.+@.+/)) {
+ let data = await rpc('/newsletter_subscription', {
+ email: $input.val()
+ });
+ if (data) {
+ $(ev.currentTarget.parentElement.parentElement).find('.warning').hide();
+ $input.css('pointer-events', 'none');
+ $button.css('background-color', 'green !important');
+ $button.text("THANKS");
+ } else {
+ $(ev.currentTarget.parentElement.parentElement).find('.warning').text("Already subscribed to the newsletter.");
+ $(ev.currentTarget.parentElement.parentElement).find('.warning').show();
+ }
+ } else {
+ this.$el.addClass('o_has_error').find('.form-control').addClass('is-invalid');
+ $(ev.currentTarget.parentElement.parentElement).find('.warning').text("Enter a valid email.");
+ $(ev.currentTarget.parentElement.parentElement).find('.warning').show();
+ }
+ },
+})
\ No newline at end of file
diff --git a/theme_lego/static/src/views/website_preview.xml b/theme_lego/static/src/views/website_preview.xml
new file mode 100644
index 0000000000..d81e4b9f09
--- /dev/null
+++ b/theme_lego/static/src/views/website_preview.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
Welcome to your Homepage !
+
Click on Edit in the top right corner to start designing.
+
+
+
+
diff --git a/theme_lego/views/add_to_cart_templates.xml b/theme_lego/views/add_to_cart_templates.xml
new file mode 100644
index 0000000000..3586f23500
--- /dev/null
+++ b/theme_lego/views/add_to_cart_templates.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
Product preview
+
+
+
+ Home
+
+
+
+
+ SHOP
+
+
+
+ PRODUCTS
+ PREVIEW
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Uncategorized
+
+
+
+
+
+
+
+
+
+
+
+
+ or
+
+
+
+ Specification
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/views/footer_templates.xml b/theme_lego/views/footer_templates.xml
new file mode 100644
index 0000000000..03beb00535
--- /dev/null
+++ b/theme_lego/views/footer_templates.xml
@@ -0,0 +1,114 @@
+
+
+
+
+
diff --git a/theme_lego/views/header_templates.xml b/theme_lego/views/header_templates.xml
new file mode 100644
index 0000000000..570e9fd789
--- /dev/null
+++ b/theme_lego/views/header_templates.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
diff --git a/theme_lego/views/login_templates.xml b/theme_lego/views/login_templates.xml
new file mode 100644
index 0000000000..468588a163
--- /dev/null
+++ b/theme_lego/views/login_templates.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
Login
+
+
+
+ Home
+
+
+
+ Login
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/views/payment_templates.xml b/theme_lego/views/payment_templates.xml
new file mode 100644
index 0000000000..1679b74362
--- /dev/null
+++ b/theme_lego/views/payment_templates.xml
@@ -0,0 +1,214 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Home
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ x
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Uncategorized
+
+
+
+
+
+
+
+
+
+
+ ,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Comparison
+
+
+
+ Home
+
+
+
+
+ COMPARISON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Wishlist
+
+
+
+ Home
+
+
+
+
+ WISHLIST
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/views/product_template_views.xml b/theme_lego/views/product_template_views.xml
new file mode 100644
index 0000000000..f2dd3d4d17
--- /dev/null
+++ b/theme_lego/views/product_template_views.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ product.template.view.form.inherit.theme.lego
+ product.template
+
+
+
+
+
+
+
+
diff --git a/theme_lego/views/shop_templates.xml b/theme_lego/views/shop_templates.xml
new file mode 100644
index 0000000000..75679df7c3
--- /dev/null
+++ b/theme_lego/views/shop_templates.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
Shop Category page
+
+
+
+ Home
+
+
+
+
+ SHOP
+
+
+
+ PRODUCTS
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_lego/views/snippets/snippet_templates.xml b/theme_lego/views/snippets/snippet_templates.xml
new file mode 100644
index 0000000000..d6af6285ae
--- /dev/null
+++ b/theme_lego/views/snippets/snippet_templates.xml
@@ -0,0 +1,493 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Adidas New Collection !
+
+ Lorem ipsum dolor sit amet,
+ consectetur adipisicing
+ elit, sed do eiusmod tempor
+ incididunt ut
+ labore et
+ dolore magna aliqua. Ut enim
+ ad minim veniam, quis
+ nostrud exercitation.
+
+
+
+ add
+ Add to bag
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Adidas New Collection !
+
+ Lorem ipsum dolor sit amet,
+ consectetur adipisicing
+ elit, sed do eiusmod tempor
+ incididunt ut
+ labore et
+ dolore magna aliqua. Ut enim
+ ad minim veniam, quis
+ nostrud exercitation.
+
+
+ add Add to
+ bag
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Adidas New Collection !
+
+ Lorem ipsum dolor sit amet,
+ consectetur adipisicing
+ elit, sed do eiusmod tempor
+ incididunt ut
+ labore et
+ dolore magna aliqua. Ut enim
+ ad minim veniam, quis
+ nostrud exercitation.
+
+
+ add Add to
+ bag
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Contact
+
+
+
+ Home
+
+
+
+ Contact
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Deals of the week
+
+ Lorem Ipsum is simply dummy text of the printing
+ and typesetting industry. Lorem Ipsum has been
+ the industry's standard dummy text ever since
+ the 1500s, when an unknown printer took a galley
+ of type and scrambled it to make a type specimen
+ book.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Deals of the week
+
+ Lorem Ipsum is simply dummy text of the printing
+ and typesetting industry. Lorem Ipsum has been
+ the industry's standard dummy text ever since
+ the 1500s, when an unknown printer took a galley
+ of type and scrambled it to make a type specimen
+ book.
+
+
+
+
+
+
+
+
+ We're out of deals for now — but fresh ones are on the way. Stay tuned!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Deals of the week
+
+ Lorem Ipsum is simply dummy text of the printing
+ and typesetting industry. Lorem Ipsum has been
+ the industry's standard dummy text ever since
+ the 1500s, when an unknown printer took a galley
+ of type and scrambled it to make a type specimen
+ book.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/README.rst b/theme_levelup/README.rst
new file mode 100644
index 0000000000..ed08eb9149
--- /dev/null
+++ b/theme_levelup/README.rst
@@ -0,0 +1,48 @@
+.. image:: https://img.shields.io/badge/license-LGPL--3-green.svg
+ :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html
+ :alt: License: LGPL-3
+
+Theme LevelUp
+=============
+* Design Web Pages with Theme LevelUp
+
+Configuration
+=============
+ - www.odoo.com/documentation/18.0/setup/install.html
+ - Install our custom addon
+
+License
+-------
+General Public License, Version 3 (LGPL v3).
+(https://www.gnu.org/licenses/lgpl-3.0-standalone.html)
+
+Company
+-------
+* `Cybrosys Techno Solutions: `__
+
+Credits
+-------
+Developers: (V16) Nisarudheen @ Cybrosys,
+ (V17) Advaith BG @ Cybrosys,
+ (V18) Athira K @Cybrosys
+Contact: odoo@cybrosys.com
+
+Contacts
+--------
+* Mail Contact : odoo@cybrosys.com
+* Website : https://cybrosys.com
+
+Bug Tracker
+-----------
+Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
+
+Maintainer
+==========
+.. image:: https://cybrosys.com/images/logo.png
+ :target: https://cybrosys.com
+This module is maintained by Cybrosys Technologies.
+For support and more information, please visit https://www.cybrosys.com
+
+Further information
+===================
+HTML Description: ``__
diff --git a/theme_levelup/__init__.py b/theme_levelup/__init__.py
new file mode 100644
index 0000000000..79cf3e0e40
--- /dev/null
+++ b/theme_levelup/__init__.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Athira K(odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+from . import controllers
diff --git a/theme_levelup/__manifest__.py b/theme_levelup/__manifest__.py
new file mode 100644
index 0000000000..7904d8f0fe
--- /dev/null
+++ b/theme_levelup/__manifest__.py
@@ -0,0 +1,92 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Athira K(odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+{
+ "name": "Theme LevelUp",
+ "version": "18.0.1.0.0",
+ "category": "Theme/Corporate",
+ "summary": "The perfect website theme for your growing business"
+ "can used to apply new design to website and adding more menus "
+ "and feature",
+ "description": "Introducing Theme LevelUp,"
+ " your gateway to the future of web design. "
+ "This cutting-edge theme has been meticulously crafted to "
+ "transform your website into a captivating online presence."
+ " With its breathtaking, visuals, sleek animations, "
+ "and modern layouts, Theme LevelUp promises to elevate your "
+ "digital identity to new heights. Prepare to amaze your"
+ " visitors from the moment they set foot on your home page "
+ "and guide them through an immersive web experience like "
+ "never before.",
+ "author": "Cybrosys Techno Solutions",
+ "company": "Cybrosys Techno Solutions",
+ "maintainer": "Cybrosys Techno Solutions",
+ "website": "https://www.cybrosys.com",
+ "depends": ["website", "website_blog","website_sale_wishlist"],
+ "data": [
+ "data/website_menus.xml",
+ "views/blog_templates.xml",
+ "views/portfolio_templates.xml",
+ "views/about_us_templates.xml",
+ "views/footer_templates.xml",
+ "views/header_templates.xml",
+ "views/layout_templates.xml",
+ "views/contact_us_templates.xml",
+ "views/team_templates.xml",
+ "views/service_templates.xml",
+ "views/snippets/s_snippet_templates.xml",
+ "views/snippets/s_awards_templates.xml",
+ "views/snippets/s_service_templates.xml",
+ 'views/snippets/s_feature_templates.xml',
+ "views/snippets/s_excited_templates.xml",
+ "views/snippets/s_testimonial_templates.xml",
+ "views/snippets/s_client_templates.xml",
+ "views/snippets/s_banner_templates.xml",
+ "views/snippets/s_about_templates.xml",
+ "views/snippets/s_gallery_templates.xml",
+ "views/snippets/s_blog_templates.xml",
+ ],
+ "assets": {
+ "web.assets_frontend": [
+ "theme_levelup/static/src/css/animate.min.css",
+ "theme_levelup/static/src/css/owl.carousel.min.css",
+ "theme_levelup/static/src/css/owl.theme.default.min.css",
+ "theme_levelup/static/src/css/style.css",
+ "theme_levelup/static/src/css/font.css",
+ "theme_levelup/static/src/css/bootstrap.css",
+ "https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/"
+ "bootstrap.min.js",
+ "theme_levelup/static/src/js/index.js",
+ "theme_levelup/static/src/js/owl.carousel.js",
+ "theme_levelup/static/src/js/owl.carousel.min.js",
+ "theme_levelup/static/src/js/service_slider.js",
+ "theme_levelup/static/src/js/about_slider.js",
+ ],
+ },
+ "images": [
+ "static/description/banner.jpg",
+ "static/description/theme_screenshot.jpg",
+ ],
+ "license": "LGPL-3",
+ "installable": True,
+ "auto_install": False,
+ "application": False,
+}
diff --git a/theme_levelup/controllers/__init__.py b/theme_levelup/controllers/__init__.py
new file mode 100644
index 0000000000..f86465ed08
--- /dev/null
+++ b/theme_levelup/controllers/__init__.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Athira K(odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+from . import theme_levelup
diff --git a/theme_levelup/controllers/theme_levelup.py b/theme_levelup/controllers/theme_levelup.py
new file mode 100644
index 0000000000..f78298ed37
--- /dev/null
+++ b/theme_levelup/controllers/theme_levelup.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Athira K(odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+import logging
+from odoo import http
+from odoo.http import request
+
+_logger = logging.getLogger(__name__)
+
+
+class MenuController(http.Controller):
+ """This controller will be used to redirect to the
+ mentioned pages by clicking the menus."""
+
+ @http.route('/about', website=True, type='http', auth='public', csrf=False)
+ def about_page(self):
+ """This router will be redirected to the about page."""
+ return request.render('theme_levelup.about_page')
+
+ @http.route('/portfolio', website=True, type='http', auth='public',
+ csrf=False)
+ def portfolio_page(self):
+ """This router will be redirected to the portfolio page."""
+ return request.render('theme_levelup.portfolio_page')
+
+ @http.route('/team', website=True, type='http', auth='public', csrf=False)
+ def team_page(self):
+ """This router will be redirected to the team page."""
+ return request.render('theme_levelup.team_page')
+
+ @http.route('/service', website=True, type='http', auth='public',
+ csrf=False)
+ def service_page(self):
+ """This router will be redirected to the service page."""
+ return request.render('theme_levelup.service_page')
+
+ @http.route('/blog_snippet', auth="public", type='json', website=True)
+ def latest_blog(self):
+ """This router will be redirected to the blog page."""
+ return request.env['blog.post'].sudo().search_read([], limit=3)
diff --git a/theme_levelup/data/website_menus.xml b/theme_levelup/data/website_menus.xml
new file mode 100644
index 0000000000..983afd7afc
--- /dev/null
+++ b/theme_levelup/data/website_menus.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/doc/RELEASE_NOTE.md b/theme_levelup/doc/RELEASE_NOTE.md
new file mode 100644
index 0000000000..5024ba7bb7
--- /dev/null
+++ b/theme_levelup/doc/RELEASE_NOTE.md
@@ -0,0 +1,5 @@
+## Module
+#### 17.06.2025
+#### Version 18.0.1.0.0
+#### ADD
+Initial commit for Theme LevelUp
diff --git a/theme_levelup/static/description/banner.jpg b/theme_levelup/static/description/banner.jpg
new file mode 100644
index 0000000000..4d98f2b5de
Binary files /dev/null and b/theme_levelup/static/description/banner.jpg differ
diff --git a/theme_levelup/static/description/icon.png b/theme_levelup/static/description/icon.png
new file mode 100644
index 0000000000..e501f80e61
Binary files /dev/null and b/theme_levelup/static/description/icon.png differ
diff --git a/theme_levelup/static/description/img/1.jpg b/theme_levelup/static/description/img/1.jpg
new file mode 100644
index 0000000000..84a1cc66ea
Binary files /dev/null and b/theme_levelup/static/description/img/1.jpg differ
diff --git a/theme_levelup/static/description/img/2.jpg b/theme_levelup/static/description/img/2.jpg
new file mode 100644
index 0000000000..d51404fa73
Binary files /dev/null and b/theme_levelup/static/description/img/2.jpg differ
diff --git a/theme_levelup/static/description/img/3.jpg b/theme_levelup/static/description/img/3.jpg
new file mode 100644
index 0000000000..ead979beb8
Binary files /dev/null and b/theme_levelup/static/description/img/3.jpg differ
diff --git a/theme_levelup/static/description/img/4.jpg b/theme_levelup/static/description/img/4.jpg
new file mode 100644
index 0000000000..322fbd5b47
Binary files /dev/null and b/theme_levelup/static/description/img/4.jpg differ
diff --git a/theme_levelup/static/description/img/5.jpg b/theme_levelup/static/description/img/5.jpg
new file mode 100644
index 0000000000..04325d6aac
Binary files /dev/null and b/theme_levelup/static/description/img/5.jpg differ
diff --git a/theme_levelup/static/description/img/6.jpg b/theme_levelup/static/description/img/6.jpg
new file mode 100644
index 0000000000..956db1a3b3
Binary files /dev/null and b/theme_levelup/static/description/img/6.jpg differ
diff --git a/theme_levelup/static/description/img/arrows-repeat.svg b/theme_levelup/static/description/img/arrows-repeat.svg
new file mode 100644
index 0000000000..94fb8f7f90
--- /dev/null
+++ b/theme_levelup/static/description/img/arrows-repeat.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/banner-bg-1.svg b/theme_levelup/static/description/img/banner-bg-1.svg
new file mode 100644
index 0000000000..7af9bab87d
--- /dev/null
+++ b/theme_levelup/static/description/img/banner-bg-1.svg
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/banner.jpg b/theme_levelup/static/description/img/banner.jpg
new file mode 100644
index 0000000000..7418893478
Binary files /dev/null and b/theme_levelup/static/description/img/banner.jpg differ
diff --git a/theme_levelup/static/description/img/banner.svg b/theme_levelup/static/description/img/banner.svg
new file mode 100644
index 0000000000..a508123202
--- /dev/null
+++ b/theme_levelup/static/description/img/banner.svg
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/check.svg b/theme_levelup/static/description/img/check.svg
new file mode 100644
index 0000000000..8bc79333dc
--- /dev/null
+++ b/theme_levelup/static/description/img/check.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/demo-1.png b/theme_levelup/static/description/img/demo-1.png
new file mode 100644
index 0000000000..4314e897cd
Binary files /dev/null and b/theme_levelup/static/description/img/demo-1.png differ
diff --git a/theme_levelup/static/description/img/demo-2.jpg b/theme_levelup/static/description/img/demo-2.jpg
new file mode 100644
index 0000000000..124d7114c5
Binary files /dev/null and b/theme_levelup/static/description/img/demo-2.jpg differ
diff --git a/theme_levelup/static/description/img/demo-3.jpg b/theme_levelup/static/description/img/demo-3.jpg
new file mode 100644
index 0000000000..00891d8852
Binary files /dev/null and b/theme_levelup/static/description/img/demo-3.jpg differ
diff --git a/theme_levelup/static/description/img/feature-star.svg b/theme_levelup/static/description/img/feature-star.svg
new file mode 100644
index 0000000000..a913270e8e
--- /dev/null
+++ b/theme_levelup/static/description/img/feature-star.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/front screen.png b/theme_levelup/static/description/img/front screen.png
new file mode 100644
index 0000000000..b090d2008e
Binary files /dev/null and b/theme_levelup/static/description/img/front screen.png differ
diff --git a/theme_levelup/static/description/img/gear.svg b/theme_levelup/static/description/img/gear.svg
new file mode 100644
index 0000000000..ce383059da
--- /dev/null
+++ b/theme_levelup/static/description/img/gear.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/hero.png b/theme_levelup/static/description/img/hero.png
new file mode 100644
index 0000000000..4597fe787e
Binary files /dev/null and b/theme_levelup/static/description/img/hero.png differ
diff --git a/theme_levelup/static/description/img/hire-odoo.svg b/theme_levelup/static/description/img/hire-odoo.svg
new file mode 100644
index 0000000000..9cfec4e447
--- /dev/null
+++ b/theme_levelup/static/description/img/hire-odoo.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/icon.png b/theme_levelup/static/description/img/icon.png
new file mode 100644
index 0000000000..27fcb2cd46
Binary files /dev/null and b/theme_levelup/static/description/img/icon.png differ
diff --git a/theme_levelup/static/description/img/laptop-screenshots.jpg b/theme_levelup/static/description/img/laptop-screenshots.jpg
new file mode 100644
index 0000000000..2ee85aa1ec
Binary files /dev/null and b/theme_levelup/static/description/img/laptop-screenshots.jpg differ
diff --git a/theme_levelup/static/description/img/life-ring-icon.svg b/theme_levelup/static/description/img/life-ring-icon.svg
new file mode 100644
index 0000000000..b6c797ba14
--- /dev/null
+++ b/theme_levelup/static/description/img/life-ring-icon.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/mobileview.png b/theme_levelup/static/description/img/mobileview.png
new file mode 100644
index 0000000000..e33ed26712
Binary files /dev/null and b/theme_levelup/static/description/img/mobileview.png differ
diff --git a/theme_levelup/static/description/img/new/home-1.png b/theme_levelup/static/description/img/new/home-1.png
new file mode 100644
index 0000000000..9357426400
Binary files /dev/null and b/theme_levelup/static/description/img/new/home-1.png differ
diff --git a/theme_levelup/static/description/img/new/home-10.png b/theme_levelup/static/description/img/new/home-10.png
new file mode 100644
index 0000000000..ca7049348f
Binary files /dev/null and b/theme_levelup/static/description/img/new/home-10.png differ
diff --git a/theme_levelup/static/description/img/new/home-4.png b/theme_levelup/static/description/img/new/home-4.png
new file mode 100644
index 0000000000..1c1b13cedb
Binary files /dev/null and b/theme_levelup/static/description/img/new/home-4.png differ
diff --git a/theme_levelup/static/description/img/new/home-9.png b/theme_levelup/static/description/img/new/home-9.png
new file mode 100644
index 0000000000..5996d6e7a3
Binary files /dev/null and b/theme_levelup/static/description/img/new/home-9.png differ
diff --git a/theme_levelup/static/description/img/new/portfolio-2.png b/theme_levelup/static/description/img/new/portfolio-2.png
new file mode 100644
index 0000000000..4f86961a6e
Binary files /dev/null and b/theme_levelup/static/description/img/new/portfolio-2.png differ
diff --git a/theme_levelup/static/description/img/new/team-2.png b/theme_levelup/static/description/img/new/team-2.png
new file mode 100644
index 0000000000..681f55f58a
Binary files /dev/null and b/theme_levelup/static/description/img/new/team-2.png differ
diff --git a/theme_levelup/static/description/img/odoo-consultancy.svg b/theme_levelup/static/description/img/odoo-consultancy.svg
new file mode 100644
index 0000000000..c2c27e6083
--- /dev/null
+++ b/theme_levelup/static/description/img/odoo-consultancy.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/theme_levelup/static/description/img/odoo-licencing.svg b/theme_levelup/static/description/img/odoo-licencing.svg
new file mode 100644
index 0000000000..8a520b40f1
--- /dev/null
+++ b/theme_levelup/static/description/img/odoo-licencing.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/theme_levelup/static/description/img/patter.svg b/theme_levelup/static/description/img/patter.svg
new file mode 100644
index 0000000000..9b7b0d7cda
--- /dev/null
+++ b/theme_levelup/static/description/img/patter.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/phone-screenshots.jpg b/theme_levelup/static/description/img/phone-screenshots.jpg
new file mode 100644
index 0000000000..c7a8b18679
Binary files /dev/null and b/theme_levelup/static/description/img/phone-screenshots.jpg differ
diff --git a/theme_levelup/static/description/img/puzzle-piece-icon.svg b/theme_levelup/static/description/img/puzzle-piece-icon.svg
new file mode 100644
index 0000000000..ab5e56fa7b
--- /dev/null
+++ b/theme_levelup/static/description/img/puzzle-piece-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/screenshot-1.svg b/theme_levelup/static/description/img/screenshot-1.svg
new file mode 100644
index 0000000000..72eeb921b4
--- /dev/null
+++ b/theme_levelup/static/description/img/screenshot-1.svg
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/screenshot-2.png b/theme_levelup/static/description/img/screenshot-2.png
new file mode 100644
index 0000000000..e13b876da6
Binary files /dev/null and b/theme_levelup/static/description/img/screenshot-2.png differ
diff --git a/theme_levelup/static/description/img/screenshot-3.png b/theme_levelup/static/description/img/screenshot-3.png
new file mode 100644
index 0000000000..be1acdfd51
Binary files /dev/null and b/theme_levelup/static/description/img/screenshot-3.png differ
diff --git a/theme_levelup/static/description/img/screenshot-4.png b/theme_levelup/static/description/img/screenshot-4.png
new file mode 100644
index 0000000000..1d01e11fc7
Binary files /dev/null and b/theme_levelup/static/description/img/screenshot-4.png differ
diff --git a/theme_levelup/static/description/img/screenshot-5.svg b/theme_levelup/static/description/img/screenshot-5.svg
new file mode 100644
index 0000000000..923e355bf9
--- /dev/null
+++ b/theme_levelup/static/description/img/screenshot-5.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/screenshot-main.png b/theme_levelup/static/description/img/screenshot-main.png
new file mode 100644
index 0000000000..575f8e676b
Binary files /dev/null and b/theme_levelup/static/description/img/screenshot-main.png differ
diff --git a/theme_levelup/static/description/img/shop/shop1.png b/theme_levelup/static/description/img/shop/shop1.png
new file mode 100644
index 0000000000..ec3ede3044
Binary files /dev/null and b/theme_levelup/static/description/img/shop/shop1.png differ
diff --git a/theme_levelup/static/description/img/shop/shop2.png b/theme_levelup/static/description/img/shop/shop2.png
new file mode 100644
index 0000000000..f26dd46b51
Binary files /dev/null and b/theme_levelup/static/description/img/shop/shop2.png differ
diff --git a/theme_levelup/static/description/img/theme_screenshot.jpg b/theme_levelup/static/description/img/theme_screenshot.jpg
new file mode 100644
index 0000000000..4f8dad2101
Binary files /dev/null and b/theme_levelup/static/description/img/theme_screenshot.jpg differ
diff --git a/theme_levelup/static/description/img/translate.svg b/theme_levelup/static/description/img/translate.svg
new file mode 100644
index 0000000000..eea7295427
--- /dev/null
+++ b/theme_levelup/static/description/img/translate.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/img/wrench-icon.svg b/theme_levelup/static/description/img/wrench-icon.svg
new file mode 100644
index 0000000000..4e0ce1d016
--- /dev/null
+++ b/theme_levelup/static/description/img/wrench-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/index.html b/theme_levelup/static/description/index.html
new file mode 100644
index 0000000000..7c8d0ac7bc
--- /dev/null
+++ b/theme_levelup/static/description/index.html
@@ -0,0 +1,563 @@
+
+
+
+
+
+ app index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Supports:
+
+ Community
+
+
+ Enterprise
+
+
+
+
+
+
Availability:
+
+ Odoo Online
+
+
+ Odoo.sh
+
+
+ On Premise
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Our Features
+
+
info includes 300+ elements that you may need to create website without
+ external plugins.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
HIGHLIGHT
+
Your clients
+
User Interface in new look
+
+
+
+
+
+
+
+
+
+
+
+
+ HIGHLIGHT
+
Featured Products
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HIGHLIGHT
+
New Colour pattern
+
+
+
+
+
+
+
+
+
+
+
+
+ HIGHLIGHT
+
Team
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HIGHLIGHT
+
Products
+
+
+
+
+
+
+
+
+
+
+
+
+ HIGHLIGHT
+
Testimonials
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/description/theme_screenshot.jpg b/theme_levelup/static/description/theme_screenshot.jpg
new file mode 100644
index 0000000000..61168f4d67
Binary files /dev/null and b/theme_levelup/static/description/theme_screenshot.jpg differ
diff --git a/theme_levelup/static/src/css/animate.css b/theme_levelup/static/src/css/animate.css
new file mode 100644
index 0000000000..f784ce8f69
--- /dev/null
+++ b/theme_levelup/static/src/css/animate.css
@@ -0,0 +1,3158 @@
+@charset "UTF-8";
+/*!
+Animate.css - http://daneden.me/animate
+Licensed under the MIT license - http://opensource.org/licenses/MIT
+
+Copyright (c) 2014 Daniel Eden
+*/
+
+.animated {
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+.animated.infinite {
+ -webkit-animation-iteration-count: infinite;
+ animation-iteration-count: infinite;
+}
+
+.animated.hinge {
+ -webkit-animation-duration: 2s;
+ animation-duration: 2s;
+}
+
+@-webkit-keyframes bounce {
+ 0%, 20%, 53%, 80%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ -webkit-transform: translate3d(0,0,0);
+ transform: translate3d(0,0,0);
+ }
+
+ 40%, 43% {
+ -webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ -webkit-transform: translate3d(0, -30px, 0);
+ transform: translate3d(0, -30px, 0);
+ }
+
+ 70% {
+ -webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ -webkit-transform: translate3d(0, -15px, 0);
+ transform: translate3d(0, -15px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0,-4px,0);
+ transform: translate3d(0,-4px,0);
+ }
+}
+
+@keyframes bounce {
+ 0%, 20%, 53%, 80%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ -webkit-transform: translate3d(0,0,0);
+ transform: translate3d(0,0,0);
+ }
+
+ 40%, 43% {
+ -webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ -webkit-transform: translate3d(0, -30px, 0);
+ transform: translate3d(0, -30px, 0);
+ }
+
+ 70% {
+ -webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ -webkit-transform: translate3d(0, -15px, 0);
+ transform: translate3d(0, -15px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0,-4px,0);
+ transform: translate3d(0,-4px,0);
+ }
+}
+
+.bounce {
+ -webkit-animation-name: bounce;
+ animation-name: bounce;
+ -webkit-transform-origin: center bottom;
+ -ms-transform-origin: center bottom;
+ transform-origin: center bottom;
+}
+
+@-webkit-keyframes flash {
+ 0%, 50%, 100% {
+ opacity: 1;
+ }
+
+ 25%, 75% {
+ opacity: 0;
+ }
+}
+
+@keyframes flash {
+ 0%, 50%, 100% {
+ opacity: 1;
+ }
+
+ 25%, 75% {
+ opacity: 0;
+ }
+}
+
+.flash {
+ -webkit-animation-name: flash;
+ animation-name: flash;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes pulse {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 50% {
+ -webkit-transform: scale3d(1.05, 1.05, 1.05);
+ transform: scale3d(1.05, 1.05, 1.05);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+@keyframes pulse {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 50% {
+ -webkit-transform: scale3d(1.05, 1.05, 1.05);
+ transform: scale3d(1.05, 1.05, 1.05);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+.pulse {
+ -webkit-animation-name: pulse;
+ animation-name: pulse;
+}
+
+@-webkit-keyframes rubberBand {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 30% {
+ -webkit-transform: scale3d(1.25, 0.75, 1);
+ transform: scale3d(1.25, 0.75, 1);
+ }
+
+ 40% {
+ -webkit-transform: scale3d(0.75, 1.25, 1);
+ transform: scale3d(0.75, 1.25, 1);
+ }
+
+ 50% {
+ -webkit-transform: scale3d(1.15, 0.85, 1);
+ transform: scale3d(1.15, 0.85, 1);
+ }
+
+ 65% {
+ -webkit-transform: scale3d(.95, 1.05, 1);
+ transform: scale3d(.95, 1.05, 1);
+ }
+
+ 75% {
+ -webkit-transform: scale3d(1.05, .95, 1);
+ transform: scale3d(1.05, .95, 1);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+@keyframes rubberBand {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 30% {
+ -webkit-transform: scale3d(1.25, 0.75, 1);
+ transform: scale3d(1.25, 0.75, 1);
+ }
+
+ 40% {
+ -webkit-transform: scale3d(0.75, 1.25, 1);
+ transform: scale3d(0.75, 1.25, 1);
+ }
+
+ 50% {
+ -webkit-transform: scale3d(1.15, 0.85, 1);
+ transform: scale3d(1.15, 0.85, 1);
+ }
+
+ 65% {
+ -webkit-transform: scale3d(.95, 1.05, 1);
+ transform: scale3d(.95, 1.05, 1);
+ }
+
+ 75% {
+ -webkit-transform: scale3d(1.05, .95, 1);
+ transform: scale3d(1.05, .95, 1);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+.rubberBand {
+ -webkit-animation-name: rubberBand;
+ animation-name: rubberBand;
+}
+
+@-webkit-keyframes shake {
+ 0%, 100% {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+
+ 10%, 30%, 50%, 70%, 90% {
+ -webkit-transform: translate3d(-10px, 0, 0);
+ transform: translate3d(-10px, 0, 0);
+ }
+
+ 20%, 40%, 60%, 80% {
+ -webkit-transform: translate3d(10px, 0, 0);
+ transform: translate3d(10px, 0, 0);
+ }
+}
+
+@keyframes shake {
+ 0%, 100% {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+
+ 10%, 30%, 50%, 70%, 90% {
+ -webkit-transform: translate3d(-10px, 0, 0);
+ transform: translate3d(-10px, 0, 0);
+ }
+
+ 20%, 40%, 60%, 80% {
+ -webkit-transform: translate3d(10px, 0, 0);
+ transform: translate3d(10px, 0, 0);
+ }
+}
+
+.shake {
+ -webkit-animation-name: shake;
+ animation-name: shake;
+}
+
+@-webkit-keyframes swing {
+ 20% {
+ -webkit-transform: rotate3d(0, 0, 1, 15deg);
+ transform: rotate3d(0, 0, 1, 15deg);
+ }
+
+ 40% {
+ -webkit-transform: rotate3d(0, 0, 1, -10deg);
+ transform: rotate3d(0, 0, 1, -10deg);
+ }
+
+ 60% {
+ -webkit-transform: rotate3d(0, 0, 1, 5deg);
+ transform: rotate3d(0, 0, 1, 5deg);
+ }
+
+ 80% {
+ -webkit-transform: rotate3d(0, 0, 1, -5deg);
+ transform: rotate3d(0, 0, 1, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: rotate3d(0, 0, 1, 0deg);
+ transform: rotate3d(0, 0, 1, 0deg);
+ }
+}
+
+@keyframes swing {
+ 20% {
+ -webkit-transform: rotate3d(0, 0, 1, 15deg);
+ transform: rotate3d(0, 0, 1, 15deg);
+ }
+
+ 40% {
+ -webkit-transform: rotate3d(0, 0, 1, -10deg);
+ transform: rotate3d(0, 0, 1, -10deg);
+ }
+
+ 60% {
+ -webkit-transform: rotate3d(0, 0, 1, 5deg);
+ transform: rotate3d(0, 0, 1, 5deg);
+ }
+
+ 80% {
+ -webkit-transform: rotate3d(0, 0, 1, -5deg);
+ transform: rotate3d(0, 0, 1, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: rotate3d(0, 0, 1, 0deg);
+ transform: rotate3d(0, 0, 1, 0deg);
+ }
+}
+
+.swing {
+ -webkit-transform-origin: top center;
+ -ms-transform-origin: top center;
+ transform-origin: top center;
+ -webkit-animation-name: swing;
+ animation-name: swing;
+}
+
+@-webkit-keyframes tada {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 10%, 20% {
+ -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
+ transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 30%, 50%, 70%, 90% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+ transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+ }
+
+ 40%, 60%, 80% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+ transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+@keyframes tada {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 10%, 20% {
+ -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
+ transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 30%, 50%, 70%, 90% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+ transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+ }
+
+ 40%, 60%, 80% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+ transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+.tada {
+ -webkit-animation-name: tada;
+ animation-name: tada;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes wobble {
+ 0% {
+ -webkit-transform: none;
+ transform: none;
+ }
+
+ 15% {
+ -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+ transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+ }
+
+ 30% {
+ -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+ transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+ }
+
+ 45% {
+ -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+ transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 60% {
+ -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+ transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+ transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes wobble {
+ 0% {
+ -webkit-transform: none;
+ transform: none;
+ }
+
+ 15% {
+ -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+ transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+ }
+
+ 30% {
+ -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+ transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+ }
+
+ 45% {
+ -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+ transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 60% {
+ -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+ transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+ transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.wobble {
+ -webkit-animation-name: wobble;
+ animation-name: wobble;
+}
+
+@-webkit-keyframes bounceIn {
+ 0%, 20%, 40%, 60%, 80%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 20% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1);
+ transform: scale3d(1.1, 1.1, 1.1);
+ }
+
+ 40% {
+ -webkit-transform: scale3d(.9, .9, .9);
+ transform: scale3d(.9, .9, .9);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(1.03, 1.03, 1.03);
+ transform: scale3d(1.03, 1.03, 1.03);
+ }
+
+ 80% {
+ -webkit-transform: scale3d(.97, .97, .97);
+ transform: scale3d(.97, .97, .97);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+@keyframes bounceIn {
+ 0%, 20%, 40%, 60%, 80%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 20% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1);
+ transform: scale3d(1.1, 1.1, 1.1);
+ }
+
+ 40% {
+ -webkit-transform: scale3d(.9, .9, .9);
+ transform: scale3d(.9, .9, .9);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(1.03, 1.03, 1.03);
+ transform: scale3d(1.03, 1.03, 1.03);
+ }
+
+ 80% {
+ -webkit-transform: scale3d(.97, .97, .97);
+ transform: scale3d(.97, .97, .97);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+.bounceIn {
+ -webkit-animation-name: bounceIn;
+ animation-name: bounceIn;
+ -webkit-animation-duration: .75s;
+ animation-duration: .75s;
+}
+
+@-webkit-keyframes bounceInDown {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -3000px, 0);
+ transform: translate3d(0, -3000px, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, 25px, 0);
+ transform: translate3d(0, 25px, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(0, -10px, 0);
+ transform: translate3d(0, -10px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0, 5px, 0);
+ transform: translate3d(0, 5px, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes bounceInDown {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -3000px, 0);
+ transform: translate3d(0, -3000px, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, 25px, 0);
+ transform: translate3d(0, 25px, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(0, -10px, 0);
+ transform: translate3d(0, -10px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0, 5px, 0);
+ transform: translate3d(0, 5px, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.bounceInDown {
+ -webkit-animation-name: bounceInDown;
+ animation-name: bounceInDown;
+}
+
+@-webkit-keyframes bounceInLeft {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-3000px, 0, 0);
+ transform: translate3d(-3000px, 0, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(25px, 0, 0);
+ transform: translate3d(25px, 0, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(-10px, 0, 0);
+ transform: translate3d(-10px, 0, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(5px, 0, 0);
+ transform: translate3d(5px, 0, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes bounceInLeft {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-3000px, 0, 0);
+ transform: translate3d(-3000px, 0, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(25px, 0, 0);
+ transform: translate3d(25px, 0, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(-10px, 0, 0);
+ transform: translate3d(-10px, 0, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(5px, 0, 0);
+ transform: translate3d(5px, 0, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.bounceInLeft {
+ -webkit-animation-name: bounceInLeft;
+ animation-name: bounceInLeft;
+}
+
+@-webkit-keyframes bounceInRight {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(3000px, 0, 0);
+ transform: translate3d(3000px, 0, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(-25px, 0, 0);
+ transform: translate3d(-25px, 0, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(10px, 0, 0);
+ transform: translate3d(10px, 0, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(-5px, 0, 0);
+ transform: translate3d(-5px, 0, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes bounceInRight {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(3000px, 0, 0);
+ transform: translate3d(3000px, 0, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(-25px, 0, 0);
+ transform: translate3d(-25px, 0, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(10px, 0, 0);
+ transform: translate3d(10px, 0, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(-5px, 0, 0);
+ transform: translate3d(-5px, 0, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.bounceInRight {
+ -webkit-animation-name: bounceInRight;
+ animation-name: bounceInRight;
+}
+
+@-webkit-keyframes bounceInUp {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 3000px, 0);
+ transform: translate3d(0, 3000px, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, -20px, 0);
+ transform: translate3d(0, -20px, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(0, 10px, 0);
+ transform: translate3d(0, 10px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0, -5px, 0);
+ transform: translate3d(0, -5px, 0);
+ }
+
+ 100% {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+}
+
+@keyframes bounceInUp {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 3000px, 0);
+ transform: translate3d(0, 3000px, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, -20px, 0);
+ transform: translate3d(0, -20px, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(0, 10px, 0);
+ transform: translate3d(0, 10px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0, -5px, 0);
+ transform: translate3d(0, -5px, 0);
+ }
+
+ 100% {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+}
+
+.bounceInUp {
+ -webkit-animation-name: bounceInUp;
+ animation-name: bounceInUp;
+}
+
+@-webkit-keyframes bounceOut {
+ 20% {
+ -webkit-transform: scale3d(.9, .9, .9);
+ transform: scale3d(.9, .9, .9);
+ }
+
+ 50%, 55% {
+ opacity: 1;
+ -webkit-transform: scale3d(1.1, 1.1, 1.1);
+ transform: scale3d(1.1, 1.1, 1.1);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+}
+
+@keyframes bounceOut {
+ 20% {
+ -webkit-transform: scale3d(.9, .9, .9);
+ transform: scale3d(.9, .9, .9);
+ }
+
+ 50%, 55% {
+ opacity: 1;
+ -webkit-transform: scale3d(1.1, 1.1, 1.1);
+ transform: scale3d(1.1, 1.1, 1.1);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+}
+
+.bounceOut {
+ -webkit-animation-name: bounceOut;
+ animation-name: bounceOut;
+ -webkit-animation-duration: .75s;
+ animation-duration: .75s;
+}
+
+@-webkit-keyframes bounceOutDown {
+ 20% {
+ -webkit-transform: translate3d(0, 10px, 0);
+ transform: translate3d(0, 10px, 0);
+ }
+
+ 40%, 45% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, -20px, 0);
+ transform: translate3d(0, -20px, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+}
+
+@keyframes bounceOutDown {
+ 20% {
+ -webkit-transform: translate3d(0, 10px, 0);
+ transform: translate3d(0, 10px, 0);
+ }
+
+ 40%, 45% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, -20px, 0);
+ transform: translate3d(0, -20px, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+}
+
+.bounceOutDown {
+ -webkit-animation-name: bounceOutDown;
+ animation-name: bounceOutDown;
+}
+
+@-webkit-keyframes bounceOutLeft {
+ 20% {
+ opacity: 1;
+ -webkit-transform: translate3d(20px, 0, 0);
+ transform: translate3d(20px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+}
+
+@keyframes bounceOutLeft {
+ 20% {
+ opacity: 1;
+ -webkit-transform: translate3d(20px, 0, 0);
+ transform: translate3d(20px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+}
+
+.bounceOutLeft {
+ -webkit-animation-name: bounceOutLeft;
+ animation-name: bounceOutLeft;
+}
+
+@-webkit-keyframes bounceOutRight {
+ 20% {
+ opacity: 1;
+ -webkit-transform: translate3d(-20px, 0, 0);
+ transform: translate3d(-20px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+}
+
+@keyframes bounceOutRight {
+ 20% {
+ opacity: 1;
+ -webkit-transform: translate3d(-20px, 0, 0);
+ transform: translate3d(-20px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+}
+
+.bounceOutRight {
+ -webkit-animation-name: bounceOutRight;
+ animation-name: bounceOutRight;
+}
+
+@-webkit-keyframes bounceOutUp {
+ 20% {
+ -webkit-transform: translate3d(0, -10px, 0);
+ transform: translate3d(0, -10px, 0);
+ }
+
+ 40%, 45% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, 20px, 0);
+ transform: translate3d(0, 20px, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+}
+
+@keyframes bounceOutUp {
+ 20% {
+ -webkit-transform: translate3d(0, -10px, 0);
+ transform: translate3d(0, -10px, 0);
+ }
+
+ 40%, 45% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, 20px, 0);
+ transform: translate3d(0, 20px, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+}
+
+.bounceOutUp {
+ -webkit-animation-name: bounceOutUp;
+ animation-name: bounceOutUp;
+}
+
+@-webkit-keyframes fadeIn {
+ 0% {opacity: 0;}
+ 100% {opacity: 1;}
+}
+
+@keyframes fadeIn {
+ 0% {opacity: 0;}
+ 100% {opacity: 1;}
+}
+
+.fadeIn {
+ -webkit-animation-name: fadeIn;
+ animation-name: fadeIn;
+}
+
+@-webkit-keyframes fadeInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInDown {
+ -webkit-animation-name: fadeInDown;
+ animation-name: fadeInDown;
+}
+
+@-webkit-keyframes fadeInDownBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInDownBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInDownBig {
+ -webkit-animation-name: fadeInDownBig;
+ animation-name: fadeInDownBig;
+}
+
+@-webkit-keyframes fadeInLeft {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInLeft {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInLeft {
+ -webkit-animation-name: fadeInLeft;
+ animation-name: fadeInLeft;
+}
+
+@-webkit-keyframes fadeInLeftBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInLeftBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInLeftBig {
+ -webkit-animation-name: fadeInLeftBig;
+ animation-name: fadeInLeftBig;
+}
+
+@-webkit-keyframes fadeInRight {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInRight {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInRight {
+ -webkit-animation-name: fadeInRight;
+ animation-name: fadeInRight;
+}
+
+@-webkit-keyframes fadeInRightBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInRightBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInRightBig {
+ -webkit-animation-name: fadeInRightBig;
+ animation-name: fadeInRightBig;
+}
+
+@-webkit-keyframes fadeInUp {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 100%, 0);
+ transform: translate3d(0, 100%, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInUp {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 100%, 0);
+ transform: translate3d(0, 100%, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInUp {
+ -webkit-animation-name: fadeInUp;
+ animation-name: fadeInUp;
+}
+
+@-webkit-keyframes fadeInUpBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInUpBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInUpBig {
+ -webkit-animation-name: fadeInUpBig;
+ animation-name: fadeInUpBig;
+}
+
+@-webkit-keyframes fadeOut {
+ 0% {opacity: 1;}
+ 100% {opacity: 0;}
+}
+
+@keyframes fadeOut {
+ 0% {opacity: 1;}
+ 100% {opacity: 0;}
+}
+
+.fadeOut {
+ -webkit-animation-name: fadeOut;
+ animation-name: fadeOut;
+}
+
+@-webkit-keyframes fadeOutDown {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 100%, 0);
+ transform: translate3d(0, 100%, 0);
+ }
+}
+
+@keyframes fadeOutDown {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 100%, 0);
+ transform: translate3d(0, 100%, 0);
+ }
+}
+
+.fadeOutDown {
+ -webkit-animation-name: fadeOutDown;
+ animation-name: fadeOutDown;
+}
+
+@-webkit-keyframes fadeOutDownBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+}
+
+@keyframes fadeOutDownBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+}
+
+.fadeOutDownBig {
+ -webkit-animation-name: fadeOutDownBig;
+ animation-name: fadeOutDownBig;
+}
+
+@-webkit-keyframes fadeOutLeft {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+}
+
+@keyframes fadeOutLeft {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+}
+
+.fadeOutLeft {
+ -webkit-animation-name: fadeOutLeft;
+ animation-name: fadeOutLeft;
+}
+
+@-webkit-keyframes fadeOutLeftBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+}
+
+@keyframes fadeOutLeftBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+}
+
+.fadeOutLeftBig {
+ -webkit-animation-name: fadeOutLeftBig;
+ animation-name: fadeOutLeftBig;
+}
+
+@-webkit-keyframes fadeOutRight {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+}
+
+@keyframes fadeOutRight {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+}
+
+.fadeOutRight {
+ -webkit-animation-name: fadeOutRight;
+ animation-name: fadeOutRight;
+}
+
+@-webkit-keyframes fadeOutRightBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+}
+
+@keyframes fadeOutRightBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+}
+
+.fadeOutRightBig {
+ -webkit-animation-name: fadeOutRightBig;
+ animation-name: fadeOutRightBig;
+}
+
+@-webkit-keyframes fadeOutUp {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+}
+
+@keyframes fadeOutUp {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+}
+
+.fadeOutUp {
+ -webkit-animation-name: fadeOutUp;
+ animation-name: fadeOutUp;
+}
+
+@-webkit-keyframes fadeOutUpBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+}
+
+@keyframes fadeOutUpBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+}
+
+.fadeOutUpBig {
+ -webkit-animation-name: fadeOutUpBig;
+ animation-name: fadeOutUpBig;
+}
+
+@-webkit-keyframes flip {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+ transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out;
+ }
+
+ 50% {
+ -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+ transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) scale3d(.95, .95, .95);
+ transform: perspective(400px) scale3d(.95, .95, .95);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+}
+
+@keyframes flip {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+ transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out;
+ }
+
+ 50% {
+ -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+ transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) scale3d(.95, .95, .95);
+ transform: perspective(400px) scale3d(.95, .95, .95);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+}
+
+.animated.flip {
+ -webkit-backface-visibility: visible;
+ backface-visibility: visible;
+ -webkit-animation-name: flip;
+ animation-name: flip;
+}
+
+@-webkit-keyframes flipInX {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ opacity: 0;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ }
+
+ 60% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+}
+
+@keyframes flipInX {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ opacity: 0;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ }
+
+ 60% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+}
+
+.flipInX {
+ -webkit-backface-visibility: visible !important;
+ backface-visibility: visible !important;
+ -webkit-animation-name: flipInX;
+ animation-name: flipInX;
+}
+
+@-webkit-keyframes flipInY {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ opacity: 0;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ }
+
+ 60% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+}
+
+@keyframes flipInY {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ opacity: 0;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ }
+
+ 60% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+}
+
+.flipInY {
+ -webkit-backface-visibility: visible !important;
+ backface-visibility: visible !important;
+ -webkit-animation-name: flipInY;
+ animation-name: flipInY;
+}
+
+@-webkit-keyframes flipOutX {
+ 0% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+
+ 30% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ opacity: 0;
+ }
+}
+
+@keyframes flipOutX {
+ 0% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+
+ 30% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ opacity: 0;
+ }
+}
+
+.flipOutX {
+ -webkit-animation-name: flipOutX;
+ animation-name: flipOutX;
+ -webkit-animation-duration: .75s;
+ animation-duration: .75s;
+ -webkit-backface-visibility: visible !important;
+ backface-visibility: visible !important;
+}
+
+@-webkit-keyframes flipOutY {
+ 0% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+
+ 30% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ opacity: 0;
+ }
+}
+
+@keyframes flipOutY {
+ 0% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+
+ 30% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ opacity: 0;
+ }
+}
+
+.flipOutY {
+ -webkit-backface-visibility: visible !important;
+ backface-visibility: visible !important;
+ -webkit-animation-name: flipOutY;
+ animation-name: flipOutY;
+ -webkit-animation-duration: .75s;
+ animation-duration: .75s;
+}
+
+@-webkit-keyframes lightSpeedIn {
+ 0% {
+ -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);
+ transform: translate3d(100%, 0, 0) skewX(-30deg);
+ opacity: 0;
+ }
+
+ 60% {
+ -webkit-transform: skewX(20deg);
+ transform: skewX(20deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: skewX(-5deg);
+ transform: skewX(-5deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes lightSpeedIn {
+ 0% {
+ -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);
+ transform: translate3d(100%, 0, 0) skewX(-30deg);
+ opacity: 0;
+ }
+
+ 60% {
+ -webkit-transform: skewX(20deg);
+ transform: skewX(20deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: skewX(-5deg);
+ transform: skewX(-5deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.lightSpeedIn {
+ -webkit-animation-name: lightSpeedIn;
+ animation-name: lightSpeedIn;
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out;
+}
+
+@-webkit-keyframes lightSpeedOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: translate3d(100%, 0, 0) skewX(30deg);
+ transform: translate3d(100%, 0, 0) skewX(30deg);
+ opacity: 0;
+ }
+}
+
+@keyframes lightSpeedOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: translate3d(100%, 0, 0) skewX(30deg);
+ transform: translate3d(100%, 0, 0) skewX(30deg);
+ opacity: 0;
+ }
+}
+
+.lightSpeedOut {
+ -webkit-animation-name: lightSpeedOut;
+ animation-name: lightSpeedOut;
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+}
+
+@-webkit-keyframes rotateIn {
+ 0% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: rotate3d(0, 0, 1, -200deg);
+ transform: rotate3d(0, 0, 1, -200deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes rotateIn {
+ 0% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: rotate3d(0, 0, 1, -200deg);
+ transform: rotate3d(0, 0, 1, -200deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.rotateIn {
+ -webkit-animation-name: rotateIn;
+ animation-name: rotateIn;
+}
+
+@-webkit-keyframes rotateInDownLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes rotateInDownLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.rotateInDownLeft {
+ -webkit-animation-name: rotateInDownLeft;
+ animation-name: rotateInDownLeft;
+}
+
+@-webkit-keyframes rotateInDownRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes rotateInDownRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.rotateInDownRight {
+ -webkit-animation-name: rotateInDownRight;
+ animation-name: rotateInDownRight;
+}
+
+@-webkit-keyframes rotateInUpLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes rotateInUpLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.rotateInUpLeft {
+ -webkit-animation-name: rotateInUpLeft;
+ animation-name: rotateInUpLeft;
+}
+
+@-webkit-keyframes rotateInUpRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -90deg);
+ transform: rotate3d(0, 0, 1, -90deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes rotateInUpRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -90deg);
+ transform: rotate3d(0, 0, 1, -90deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.rotateInUpRight {
+ -webkit-animation-name: rotateInUpRight;
+ animation-name: rotateInUpRight;
+}
+
+@-webkit-keyframes rotateOut {
+ 0% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: rotate3d(0, 0, 1, 200deg);
+ transform: rotate3d(0, 0, 1, 200deg);
+ opacity: 0;
+ }
+}
+
+@keyframes rotateOut {
+ 0% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: rotate3d(0, 0, 1, 200deg);
+ transform: rotate3d(0, 0, 1, 200deg);
+ opacity: 0;
+ }
+}
+
+.rotateOut {
+ -webkit-animation-name: rotateOut;
+ animation-name: rotateOut;
+}
+
+@-webkit-keyframes rotateOutDownLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+}
+
+@keyframes rotateOutDownLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+}
+
+.rotateOutDownLeft {
+ -webkit-animation-name: rotateOutDownLeft;
+ animation-name: rotateOutDownLeft;
+}
+
+@-webkit-keyframes rotateOutDownRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+}
+
+@keyframes rotateOutDownRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+}
+
+.rotateOutDownRight {
+ -webkit-animation-name: rotateOutDownRight;
+ animation-name: rotateOutDownRight;
+}
+
+@-webkit-keyframes rotateOutUpLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+}
+
+@keyframes rotateOutUpLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+}
+
+.rotateOutUpLeft {
+ -webkit-animation-name: rotateOutUpLeft;
+ animation-name: rotateOutUpLeft;
+}
+
+@-webkit-keyframes rotateOutUpRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 90deg);
+ transform: rotate3d(0, 0, 1, 90deg);
+ opacity: 0;
+ }
+}
+
+@keyframes rotateOutUpRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 90deg);
+ transform: rotate3d(0, 0, 1, 90deg);
+ opacity: 0;
+ }
+}
+
+.rotateOutUpRight {
+ -webkit-animation-name: rotateOutUpRight;
+ animation-name: rotateOutUpRight;
+}
+
+@-webkit-keyframes hinge {
+ 0% {
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ }
+
+ 20%, 60% {
+ -webkit-transform: rotate3d(0, 0, 1, 80deg);
+ transform: rotate3d(0, 0, 1, 80deg);
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ }
+
+ 40%, 80% {
+ -webkit-transform: rotate3d(0, 0, 1, 60deg);
+ transform: rotate3d(0, 0, 1, 60deg);
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: translate3d(0, 700px, 0);
+ transform: translate3d(0, 700px, 0);
+ opacity: 0;
+ }
+}
+
+@keyframes hinge {
+ 0% {
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ }
+
+ 20%, 60% {
+ -webkit-transform: rotate3d(0, 0, 1, 80deg);
+ transform: rotate3d(0, 0, 1, 80deg);
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ }
+
+ 40%, 80% {
+ -webkit-transform: rotate3d(0, 0, 1, 60deg);
+ transform: rotate3d(0, 0, 1, 60deg);
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: translate3d(0, 700px, 0);
+ transform: translate3d(0, 700px, 0);
+ opacity: 0;
+ }
+}
+
+.hinge {
+ -webkit-animation-name: hinge;
+ animation-name: hinge;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes rollIn {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+ transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes rollIn {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+ transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.rollIn {
+ -webkit-animation-name: rollIn;
+ animation-name: rollIn;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes rollOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+ transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+ }
+}
+
+@keyframes rollOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+ transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+ }
+}
+
+.rollOut {
+ -webkit-animation-name: rollOut;
+ animation-name: rollOut;
+}
+
+@-webkit-keyframes zoomIn {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 50% {
+ opacity: 1;
+ }
+}
+
+@keyframes zoomIn {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 50% {
+ opacity: 1;
+ }
+}
+
+.zoomIn {
+ -webkit-animation-name: zoomIn;
+ animation-name: zoomIn;
+}
+
+@-webkit-keyframes zoomInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomInDown {
+ -webkit-animation-name: zoomInDown;
+ animation-name: zoomInDown;
+}
+
+@-webkit-keyframes zoomInLeft {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);
+ transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomInLeft {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);
+ transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomInLeft {
+ -webkit-animation-name: zoomInLeft;
+ animation-name: zoomInLeft;
+}
+
+@-webkit-keyframes zoomInRight {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);
+ transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomInRight {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);
+ transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomInRight {
+ -webkit-animation-name: zoomInRight;
+ animation-name: zoomInRight;
+}
+
+@-webkit-keyframes zoomInUp {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomInUp {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomInUp {
+ -webkit-animation-name: zoomInUp;
+ animation-name: zoomInUp;
+}
+
+@-webkit-keyframes zoomOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 50% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 100% {
+ opacity: 0;
+ }
+}
+
+@keyframes zoomOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 50% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 100% {
+ opacity: 0;
+ }
+}
+
+.zoomOut {
+ -webkit-animation-name: zoomOut;
+ animation-name: zoomOut;
+}
+
+@-webkit-keyframes zoomOutDown {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);
+ -webkit-transform-origin: center bottom;
+ transform-origin: center bottom;
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomOutDown {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);
+ -webkit-transform-origin: center bottom;
+ transform-origin: center bottom;
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomOutDown {
+ -webkit-animation-name: zoomOutDown;
+ animation-name: zoomOutDown;
+}
+
+@-webkit-keyframes zoomOutLeft {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translate3d(-2000px, 0, 0);
+ transform: scale(.1) translate3d(-2000px, 0, 0);
+ -webkit-transform-origin: left center;
+ transform-origin: left center;
+ }
+}
+
+@keyframes zoomOutLeft {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translate3d(-2000px, 0, 0);
+ transform: scale(.1) translate3d(-2000px, 0, 0);
+ -webkit-transform-origin: left center;
+ transform-origin: left center;
+ }
+}
+
+.zoomOutLeft {
+ -webkit-animation-name: zoomOutLeft;
+ animation-name: zoomOutLeft;
+}
+
+@-webkit-keyframes zoomOutRight {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translate3d(2000px, 0, 0);
+ transform: scale(.1) translate3d(2000px, 0, 0);
+ -webkit-transform-origin: right center;
+ transform-origin: right center;
+ }
+}
+
+@keyframes zoomOutRight {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translate3d(2000px, 0, 0);
+ transform: scale(.1) translate3d(2000px, 0, 0);
+ -webkit-transform-origin: right center;
+ transform-origin: right center;
+ }
+}
+
+.zoomOutRight {
+ -webkit-animation-name: zoomOutRight;
+ animation-name: zoomOutRight;
+}
+
+@-webkit-keyframes zoomOutUp {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);
+ -webkit-transform-origin: center bottom;
+ transform-origin: center bottom;
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomOutUp {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);
+ -webkit-transform-origin: center bottom;
+ transform-origin: center bottom;
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomOutUp {
+ -webkit-animation-name: zoomOutUp;
+ animation-name: zoomOutUp;
+}
+
+@-webkit-keyframes slideInDown {
+ 0% {
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+}
+
+@keyframes slideInDown {
+ 0% {
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+}
+
+.slideInDown {
+ -webkit-animation-name: slideInDown;
+ animation-name: slideInDown;
+}
+
+@-webkit-keyframes slideInLeft {
+ 0% {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+@keyframes slideInLeft {
+ 0% {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+.slideInLeft {
+ -webkit-animation-name: slideInLeft;
+ animation-name: slideInLeft;
+}
+
+@-webkit-keyframes slideInRight {
+ 0% {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+@keyframes slideInRight {
+ 0% {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+.slideInRight {
+ -webkit-animation-name: slideInRight;
+ animation-name: slideInRight;
+}
+
+@-webkit-keyframes slideInUp {
+ 0% {
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+}
+
+@keyframes slideInUp {
+ 0% {
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+}
+
+.slideInUp {
+ -webkit-animation-name: slideInUp;
+ animation-name: slideInUp;
+}
+
+@-webkit-keyframes slideOutDown {
+ 0% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ }
+}
+
+@keyframes slideOutDown {
+ 0% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ }
+}
+
+.slideOutDown {
+ -webkit-animation-name: slideOutDown;
+ animation-name: slideOutDown;
+}
+
+@-webkit-keyframes slideOutLeft {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ }
+}
+
+@keyframes slideOutLeft {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ }
+}
+
+.slideOutLeft {
+ -webkit-animation-name: slideOutLeft;
+ animation-name: slideOutLeft;
+}
+
+@-webkit-keyframes slideOutRight {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ }
+}
+
+@keyframes slideOutRight {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ }
+}
+
+.slideOutRight {
+ -webkit-animation-name: slideOutRight;
+ animation-name: slideOutRight;
+}
+
+@-webkit-keyframes slideOutUp {
+ 0% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ }
+}
+
+@keyframes slideOutUp {
+ 0% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ }
+}
+
+.slideOutUp {
+ -webkit-animation-name: slideOutUp;
+ animation-name: slideOutUp;
+}
diff --git a/theme_levelup/static/src/css/animate.min.css b/theme_levelup/static/src/css/animate.min.css
new file mode 100644
index 0000000000..073e89ceed
--- /dev/null
+++ b/theme_levelup/static/src/css/animate.min.css
@@ -0,0 +1,2 @@
+@charset "UTF-8";
+.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.hinge{-webkit-animation-duration:2s;animation-duration:2s}@-webkit-keyframes bounce{0%,20%,53%,80%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-transition-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);transition-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-transition-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);transition-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{0%,20%,53%,80%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-transition-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);transition-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-transition-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);transition-timing-function:cubic-bezier(0.755,0.050,0.855,0.060);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;-ms-transform-origin:center bottom;transform-origin:center bottom}@-webkit-keyframes flash{0%,50%,100%{opacity:1}25%,75%{opacity:0}}@keyframes flash{0%,50%,100%{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes pulse{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,0.75,1);transform:scale3d(1.25,0.75,1)}40%{-webkit-transform:scale3d(0.75,1.25,1);transform:scale3d(0.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,0.85,1);transform:scale3d(1.15,0.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes rubberBand{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,0.75,1);transform:scale3d(1.25,0.75,1)}40%{-webkit-transform:scale3d(0.75,1.25,1);transform:scale3d(0.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,0.85,1);transform:scale3d(1.15,0.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{0%,100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{0%,100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}100%{-webkit-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}@keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}100%{-webkit-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}.swing{-webkit-transform-origin:top center;-ms-transform-origin:top center;transform-origin:top center;-webkit-animation-name:swing;animation-name:swing}@-webkit-keyframes tada{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes tada{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}100%{-webkit-transform:none;transform:none}}@keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}100%{-webkit-transform:none;transform:none}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes bounceIn{0%,20%,40%,60%,80%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}100%{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes bounceIn{0%,20%,40%,60%,80%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}100%{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.bounceIn{-webkit-animation-name:bounceIn;animation-name:bounceIn;-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounceInDown{0%,60%,75%,90%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInDown{0%,60%,75%,90%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}100%{-webkit-transform:none;transform:none}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{0%,60%,75%,90%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInLeft{0%,60%,75%,90%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}100%{-webkit-transform:none;transform:none}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{0%,60%,75%,90%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInRight{0%,60%,75%,90%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}100%{-webkit-transform:none;transform:none}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{0%,60%,75%,90%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes bounceInUp{0%,60%,75%,90%,100%{-webkit-transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000);transition-timing-function:cubic-bezier(0.215,0.610,0.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}100%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}100%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-name:bounceOut;animation-name:bounceOut;-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@keyframes fadeOut{0%{opacity:1}100%{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}100%{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}@keyframes flip{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}100%{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}.animated.flip{-webkit-backface-visibility:visible;backface-visibility:visible;-webkit-animation-name:flip;animation-name:flip}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{0%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInX;animation-name:flipInX}@-webkit-keyframes flipInY{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInY;animation-name:flipInY}@-webkit-keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}@keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}.flipOutX{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-animation-duration:.75s;animation-duration:.75s;-webkit-backface-visibility:visible!important;backface-visibility:visible!important}@-webkit-keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}@keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}.flipOutY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipOutY;animation-name:flipOutY;-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}100%{-webkit-transform:none;transform:none;opacity:1}}@keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}100%{-webkit-transform:none;transform:none;opacity:1}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{0%{opacity:1}100%{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}@keyframes lightSpeedOut{0%{opacity:1}100%{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{0%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateIn{0%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{0%{-webkit-transform-origin:center;transform-origin:center;opacity:1}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}@keyframes rotateOut{0%{-webkit-transform-origin:center;transform-origin:center;opacity:1}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}}@keyframes rotateOutDownLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutDownRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutUpLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}@keyframes rotateOutUpRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}100%{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}@keyframes hinge{0%{-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}100%{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}.hinge{-webkit-animation-name:hinge;animation-name:hinge}@-webkit-keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}100%{opacity:1;-webkit-transform:none;transform:none}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}@keyframes rollOut{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}@keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}@keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}@keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}@keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{0%{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}100%{opacity:0}}@keyframes zoomOut{0%{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}100%{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}@keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}@keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}@keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}@keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190);animation-timing-function:cubic-bezier(0.550,0.055,0.675,0.190)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,0.885,0.320,1);animation-timing-function:cubic-bezier(0.175,0.885,0.320,1)}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{0%{-webkit-transform:translateY(-100%);transform:translateY(-100%);visibility:visible}100%{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes slideInDown{0%{-webkit-transform:translateY(-100%);transform:translateY(-100%);visibility:visible}100%{-webkit-transform:translateY(0);transform:translateY(0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%);visibility:visible}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%);visibility:visible}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{0%{-webkit-transform:translateX(100%);transform:translateX(100%);visibility:visible}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight{0%{-webkit-transform:translateX(100%);transform:translateX(100%);visibility:visible}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{0%{-webkit-transform:translateY(100%);transform:translateY(100%);visibility:visible}100%{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes slideInUp{0%{-webkit-transform:translateY(100%);transform:translateY(100%);visibility:visible}100%{-webkit-transform:translateY(0);transform:translateY(0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{0%{-webkit-transform:translateY(0);transform:translateY(0)}100%{visibility:hidden;-webkit-transform:translateY(100%);transform:translateY(100%)}}@keyframes slideOutDown{0%{-webkit-transform:translateY(0);transform:translateY(0)}100%{visibility:hidden;-webkit-transform:translateY(100%);transform:translateY(100%)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{visibility:hidden;-webkit-transform:translateX(-100%);transform:translateX(-100%)}}@keyframes slideOutLeft{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{visibility:hidden;-webkit-transform:translateX(-100%);transform:translateX(-100%)}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{visibility:hidden;-webkit-transform:translateX(100%);transform:translateX(100%)}}@keyframes slideOutRight{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{visibility:hidden;-webkit-transform:translateX(100%);transform:translateX(100%)}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{0%{-webkit-transform:translateY(0);transform:translateY(0)}100%{visibility:hidden;-webkit-transform:translateY(-100%);transform:translateY(-100%)}}@keyframes slideOutUp{0%{-webkit-transform:translateY(0);transform:translateY(0)}100%{visibility:hidden;-webkit-transform:translateY(-100%);transform:translateY(-100%)}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp}
\ No newline at end of file
diff --git a/theme_levelup/static/src/css/bootstrap.css b/theme_levelup/static/src/css/bootstrap.css
new file mode 100644
index 0000000000..1cea36773a
--- /dev/null
+++ b/theme_levelup/static/src/css/bootstrap.css
@@ -0,0 +1,1390 @@
+@font-face {
+ font-family: "bootstrap-icons";
+ src: url("./fonts/bootstrap-icons.woff2?856008caa5eb66df68595e734e59580d") format("woff2"),
+url("./fonts/bootstrap-icons.woff?856008caa5eb66df68595e734e59580d") format("woff");
+}
+
+[class^="bi-"]::before,
+[class*=" bi-"]::before {
+ display: inline-block;
+ font-family: bootstrap-icons !important;
+ font-style: normal;
+ font-weight: normal !important;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+ vertical-align: -.125em;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.bi-alarm-fill::before { content: "\f101"; }
+.bi-alarm::before { content: "\f102"; }
+.bi-align-bottom::before { content: "\f103"; }
+.bi-align-center::before { content: "\f104"; }
+.bi-align-end::before { content: "\f105"; }
+.bi-align-middle::before { content: "\f106"; }
+.bi-align-start::before { content: "\f107"; }
+.bi-align-top::before { content: "\f108"; }
+.bi-alt::before { content: "\f109"; }
+.bi-app-indicator::before { content: "\f10a"; }
+.bi-app::before { content: "\f10b"; }
+.bi-archive-fill::before { content: "\f10c"; }
+.bi-archive::before { content: "\f10d"; }
+.bi-arrow-90deg-down::before { content: "\f10e"; }
+.bi-arrow-90deg-left::before { content: "\f10f"; }
+.bi-arrow-90deg-right::before { content: "\f110"; }
+.bi-arrow-90deg-up::before { content: "\f111"; }
+.bi-arrow-bar-down::before { content: "\f112"; }
+.bi-arrow-bar-left::before { content: "\f113"; }
+.bi-arrow-bar-right::before { content: "\f114"; }
+.bi-arrow-bar-up::before { content: "\f115"; }
+.bi-arrow-clockwise::before { content: "\f116"; }
+.bi-arrow-counterclockwise::before { content: "\f117"; }
+.bi-arrow-down-circle-fill::before { content: "\f118"; }
+.bi-arrow-down-circle::before { content: "\f119"; }
+.bi-arrow-down-left-circle-fill::before { content: "\f11a"; }
+.bi-arrow-down-left-circle::before { content: "\f11b"; }
+.bi-arrow-down-left-square-fill::before { content: "\f11c"; }
+.bi-arrow-down-left-square::before { content: "\f11d"; }
+.bi-arrow-down-left::before { content: "\f11e"; }
+.bi-arrow-down-right-circle-fill::before { content: "\f11f"; }
+.bi-arrow-down-right-circle::before { content: "\f120"; }
+.bi-arrow-down-right-square-fill::before { content: "\f121"; }
+.bi-arrow-down-right-square::before { content: "\f122"; }
+.bi-arrow-down-right::before { content: "\f123"; }
+.bi-arrow-down-short::before { content: "\f124"; }
+.bi-arrow-down-square-fill::before { content: "\f125"; }
+.bi-arrow-down-square::before { content: "\f126"; }
+.bi-arrow-down-up::before { content: "\f127"; }
+.bi-arrow-down::before { content: "\f128"; }
+.bi-arrow-left-circle-fill::before { content: "\f129"; }
+.bi-arrow-left-circle::before { content: "\f12a"; }
+.bi-arrow-left-right::before { content: "\f12b"; }
+.bi-arrow-left-short::before { content: "\f12c"; }
+.bi-arrow-left-square-fill::before { content: "\f12d"; }
+.bi-arrow-left-square::before { content: "\f12e"; }
+.bi-arrow-left::before { content: "\f12f"; }
+.bi-arrow-repeat::before { content: "\f130"; }
+.bi-arrow-return-left::before { content: "\f131"; }
+.bi-arrow-return-right::before { content: "\f132"; }
+.bi-arrow-right-circle-fill::before { content: "\f133"; }
+.bi-arrow-right-circle::before { content: "\f134"; }
+.bi-arrow-right-short::before { content: "\f135"; }
+.bi-arrow-right-square-fill::before { content: "\f136"; }
+.bi-arrow-right-square::before { content: "\f137"; }
+.bi-arrow-right::before { content: "\f138"; }
+.bi-arrow-up-circle-fill::before { content: "\f139"; }
+.bi-arrow-up-circle::before { content: "\f13a"; }
+.bi-arrow-up-left-circle-fill::before { content: "\f13b"; }
+.bi-arrow-up-left-circle::before { content: "\f13c"; }
+.bi-arrow-up-left-square-fill::before { content: "\f13d"; }
+.bi-arrow-up-left-square::before { content: "\f13e"; }
+.bi-arrow-up-left::before { content: "\f13f"; }
+.bi-arrow-up-right-circle-fill::before { content: "\f140"; }
+.bi-arrow-up-right-circle::before { content: "\f141"; }
+.bi-arrow-up-right-square-fill::before { content: "\f142"; }
+.bi-arrow-up-right-square::before { content: "\f143"; }
+.bi-arrow-up-right::before { content: "\f144"; }
+.bi-arrow-up-short::before { content: "\f145"; }
+.bi-arrow-up-square-fill::before { content: "\f146"; }
+.bi-arrow-up-square::before { content: "\f147"; }
+.bi-arrow-up::before { content: "\f148"; }
+.bi-arrows-angle-contract::before { content: "\f149"; }
+.bi-arrows-angle-expand::before { content: "\f14a"; }
+.bi-arrows-collapse::before { content: "\f14b"; }
+.bi-arrows-expand::before { content: "\f14c"; }
+.bi-arrows-fullscreen::before { content: "\f14d"; }
+.bi-arrows-move::before { content: "\f14e"; }
+.bi-aspect-ratio-fill::before { content: "\f14f"; }
+.bi-aspect-ratio::before { content: "\f150"; }
+.bi-asterisk::before { content: "\f151"; }
+.bi-at::before { content: "\f152"; }
+.bi-award-fill::before { content: "\f153"; }
+.bi-award::before { content: "\f154"; }
+.bi-back::before { content: "\f155"; }
+.bi-backspace-fill::before { content: "\f156"; }
+.bi-backspace-reverse-fill::before { content: "\f157"; }
+.bi-backspace-reverse::before { content: "\f158"; }
+.bi-backspace::before { content: "\f159"; }
+.bi-badge-3d-fill::before { content: "\f15a"; }
+.bi-badge-3d::before { content: "\f15b"; }
+.bi-badge-4k-fill::before { content: "\f15c"; }
+.bi-badge-4k::before { content: "\f15d"; }
+.bi-badge-8k-fill::before { content: "\f15e"; }
+.bi-badge-8k::before { content: "\f15f"; }
+.bi-badge-ad-fill::before { content: "\f160"; }
+.bi-badge-ad::before { content: "\f161"; }
+.bi-badge-ar-fill::before { content: "\f162"; }
+.bi-badge-ar::before { content: "\f163"; }
+.bi-badge-cc-fill::before { content: "\f164"; }
+.bi-badge-cc::before { content: "\f165"; }
+.bi-badge-hd-fill::before { content: "\f166"; }
+.bi-badge-hd::before { content: "\f167"; }
+.bi-badge-tm-fill::before { content: "\f168"; }
+.bi-badge-tm::before { content: "\f169"; }
+.bi-badge-vo-fill::before { content: "\f16a"; }
+.bi-badge-vo::before { content: "\f16b"; }
+.bi-badge-vr-fill::before { content: "\f16c"; }
+.bi-badge-vr::before { content: "\f16d"; }
+.bi-badge-wc-fill::before { content: "\f16e"; }
+.bi-badge-wc::before { content: "\f16f"; }
+.bi-bag-check-fill::before { content: "\f170"; }
+.bi-bag-check::before { content: "\f171"; }
+.bi-bag-dash-fill::before { content: "\f172"; }
+.bi-bag-dash::before { content: "\f173"; }
+.bi-bag-fill::before { content: "\f174"; }
+.bi-bag-plus-fill::before { content: "\f175"; }
+.bi-bag-plus::before { content: "\f176"; }
+.bi-bag-x-fill::before { content: "\f177"; }
+.bi-bag-x::before { content: "\f178"; }
+.bi-bag::before { content: "\f179"; }
+.bi-bar-chart-fill::before { content: "\f17a"; }
+.bi-bar-chart-line-fill::before { content: "\f17b"; }
+.bi-bar-chart-line::before { content: "\f17c"; }
+.bi-bar-chart-steps::before { content: "\f17d"; }
+.bi-bar-chart::before { content: "\f17e"; }
+.bi-basket-fill::before { content: "\f17f"; }
+.bi-basket::before { content: "\f180"; }
+.bi-basket2-fill::before { content: "\f181"; }
+.bi-basket2::before { content: "\f182"; }
+.bi-basket3-fill::before { content: "\f183"; }
+.bi-basket3::before { content: "\f184"; }
+.bi-battery-charging::before { content: "\f185"; }
+.bi-battery-full::before { content: "\f186"; }
+.bi-battery-half::before { content: "\f187"; }
+.bi-battery::before { content: "\f188"; }
+.bi-bell-fill::before { content: "\f189"; }
+.bi-bell::before { content: "\f18a"; }
+.bi-bezier::before { content: "\f18b"; }
+.bi-bezier2::before { content: "\f18c"; }
+.bi-bicycle::before { content: "\f18d"; }
+.bi-binoculars-fill::before { content: "\f18e"; }
+.bi-binoculars::before { content: "\f18f"; }
+.bi-blockquote-left::before { content: "\f190"; }
+.bi-blockquote-right::before { content: "\f191"; }
+.bi-book-fill::before { content: "\f192"; }
+.bi-book-half::before { content: "\f193"; }
+.bi-book::before { content: "\f194"; }
+.bi-bookmark-check-fill::before { content: "\f195"; }
+.bi-bookmark-check::before { content: "\f196"; }
+.bi-bookmark-dash-fill::before { content: "\f197"; }
+.bi-bookmark-dash::before { content: "\f198"; }
+.bi-bookmark-fill::before { content: "\f199"; }
+.bi-bookmark-heart-fill::before { content: "\f19a"; }
+.bi-bookmark-heart::before { content: "\f19b"; }
+.bi-bookmark-plus-fill::before { content: "\f19c"; }
+.bi-bookmark-plus::before { content: "\f19d"; }
+.bi-bookmark-star-fill::before { content: "\f19e"; }
+.bi-bookmark-star::before { content: "\f19f"; }
+.bi-bookmark-x-fill::before { content: "\f1a0"; }
+.bi-bookmark-x::before { content: "\f1a1"; }
+.bi-bookmark::before { content: "\f1a2"; }
+.bi-bookmarks-fill::before { content: "\f1a3"; }
+.bi-bookmarks::before { content: "\f1a4"; }
+.bi-bookshelf::before { content: "\f1a5"; }
+.bi-bootstrap-fill::before { content: "\f1a6"; }
+.bi-bootstrap-reboot::before { content: "\f1a7"; }
+.bi-bootstrap::before { content: "\f1a8"; }
+.bi-border-all::before { content: "\f1a9"; }
+.bi-border-bottom::before { content: "\f1aa"; }
+.bi-border-center::before { content: "\f1ab"; }
+.bi-border-inner::before { content: "\f1ac"; }
+.bi-border-left::before { content: "\f1ad"; }
+.bi-border-middle::before { content: "\f1ae"; }
+.bi-border-outer::before { content: "\f1af"; }
+.bi-border-right::before { content: "\f1b0"; }
+.bi-border-style::before { content: "\f1b1"; }
+.bi-border-top::before { content: "\f1b2"; }
+.bi-border-width::before { content: "\f1b3"; }
+.bi-border::before { content: "\f1b4"; }
+.bi-bounding-box-circles::before { content: "\f1b5"; }
+.bi-bounding-box::before { content: "\f1b6"; }
+.bi-box-arrow-down-left::before { content: "\f1b7"; }
+.bi-box-arrow-down-right::before { content: "\f1b8"; }
+.bi-box-arrow-down::before { content: "\f1b9"; }
+.bi-box-arrow-in-down-left::before { content: "\f1ba"; }
+.bi-box-arrow-in-down-right::before { content: "\f1bb"; }
+.bi-box-arrow-in-down::before { content: "\f1bc"; }
+.bi-box-arrow-in-left::before { content: "\f1bd"; }
+.bi-box-arrow-in-right::before { content: "\f1be"; }
+.bi-box-arrow-in-up-left::before { content: "\f1bf"; }
+.bi-box-arrow-in-up-right::before { content: "\f1c0"; }
+.bi-box-arrow-in-up::before { content: "\f1c1"; }
+.bi-box-arrow-left::before { content: "\f1c2"; }
+.bi-box-arrow-right::before { content: "\f1c3"; }
+.bi-box-arrow-up-left::before { content: "\f1c4"; }
+.bi-box-arrow-up-right::before { content: "\f1c5"; }
+.bi-box-arrow-up::before { content: "\f1c6"; }
+.bi-box-seam::before { content: "\f1c7"; }
+.bi-box::before { content: "\f1c8"; }
+.bi-braces::before { content: "\f1c9"; }
+.bi-bricks::before { content: "\f1ca"; }
+.bi-briefcase-fill::before { content: "\f1cb"; }
+.bi-briefcase::before { content: "\f1cc"; }
+.bi-brightness-alt-high-fill::before { content: "\f1cd"; }
+.bi-brightness-alt-high::before { content: "\f1ce"; }
+.bi-brightness-alt-low-fill::before { content: "\f1cf"; }
+.bi-brightness-alt-low::before { content: "\f1d0"; }
+.bi-brightness-high-fill::before { content: "\f1d1"; }
+.bi-brightness-high::before { content: "\f1d2"; }
+.bi-brightness-low-fill::before { content: "\f1d3"; }
+.bi-brightness-low::before { content: "\f1d4"; }
+.bi-broadcast-pin::before { content: "\f1d5"; }
+.bi-broadcast::before { content: "\f1d6"; }
+.bi-brush-fill::before { content: "\f1d7"; }
+.bi-brush::before { content: "\f1d8"; }
+.bi-bucket-fill::before { content: "\f1d9"; }
+.bi-bucket::before { content: "\f1da"; }
+.bi-bug-fill::before { content: "\f1db"; }
+.bi-bug::before { content: "\f1dc"; }
+.bi-building::before { content: "\f1dd"; }
+.bi-bullseye::before { content: "\f1de"; }
+.bi-calculator-fill::before { content: "\f1df"; }
+.bi-calculator::before { content: "\f1e0"; }
+.bi-calendar-check-fill::before { content: "\f1e1"; }
+.bi-calendar-check::before { content: "\f1e2"; }
+.bi-calendar-date-fill::before { content: "\f1e3"; }
+.bi-calendar-date::before { content: "\f1e4"; }
+.bi-calendar-day-fill::before { content: "\f1e5"; }
+.bi-calendar-day::before { content: "\f1e6"; }
+.bi-calendar-event-fill::before { content: "\f1e7"; }
+.bi-calendar-event::before { content: "\f1e8"; }
+.bi-calendar-fill::before { content: "\f1e9"; }
+.bi-calendar-minus-fill::before { content: "\f1ea"; }
+.bi-calendar-minus::before { content: "\f1eb"; }
+.bi-calendar-month-fill::before { content: "\f1ec"; }
+.bi-calendar-month::before { content: "\f1ed"; }
+.bi-calendar-plus-fill::before { content: "\f1ee"; }
+.bi-calendar-plus::before { content: "\f1ef"; }
+.bi-calendar-range-fill::before { content: "\f1f0"; }
+.bi-calendar-range::before { content: "\f1f1"; }
+.bi-calendar-week-fill::before { content: "\f1f2"; }
+.bi-calendar-week::before { content: "\f1f3"; }
+.bi-calendar-x-fill::before { content: "\f1f4"; }
+.bi-calendar-x::before { content: "\f1f5"; }
+.bi-calendar::before { content: "\f1f6"; }
+.bi-calendar2-check-fill::before { content: "\f1f7"; }
+.bi-calendar2-check::before { content: "\f1f8"; }
+.bi-calendar2-date-fill::before { content: "\f1f9"; }
+.bi-calendar2-date::before { content: "\f1fa"; }
+.bi-calendar2-day-fill::before { content: "\f1fb"; }
+.bi-calendar2-day::before { content: "\f1fc"; }
+.bi-calendar2-event-fill::before { content: "\f1fd"; }
+.bi-calendar2-event::before { content: "\f1fe"; }
+.bi-calendar2-fill::before { content: "\f1ff"; }
+.bi-calendar2-minus-fill::before { content: "\f200"; }
+.bi-calendar2-minus::before { content: "\f201"; }
+.bi-calendar2-month-fill::before { content: "\f202"; }
+.bi-calendar2-month::before { content: "\f203"; }
+.bi-calendar2-plus-fill::before { content: "\f204"; }
+.bi-calendar2-plus::before { content: "\f205"; }
+.bi-calendar2-range-fill::before { content: "\f206"; }
+.bi-calendar2-range::before { content: "\f207"; }
+.bi-calendar2-week-fill::before { content: "\f208"; }
+.bi-calendar2-week::before { content: "\f209"; }
+.bi-calendar2-x-fill::before { content: "\f20a"; }
+.bi-calendar2-x::before { content: "\f20b"; }
+.bi-calendar2::before { content: "\f20c"; }
+.bi-calendar3-event-fill::before { content: "\f20d"; }
+.bi-calendar3-event::before { content: "\f20e"; }
+.bi-calendar3-fill::before { content: "\f20f"; }
+.bi-calendar3-range-fill::before { content: "\f210"; }
+.bi-calendar3-range::before { content: "\f211"; }
+.bi-calendar3-week-fill::before { content: "\f212"; }
+.bi-calendar3-week::before { content: "\f213"; }
+.bi-calendar3::before { content: "\f214"; }
+.bi-calendar4-event::before { content: "\f215"; }
+.bi-calendar4-range::before { content: "\f216"; }
+.bi-calendar4-week::before { content: "\f217"; }
+.bi-calendar4::before { content: "\f218"; }
+.bi-camera-fill::before { content: "\f219"; }
+.bi-camera-reels-fill::before { content: "\f21a"; }
+.bi-camera-reels::before { content: "\f21b"; }
+.bi-camera-video-fill::before { content: "\f21c"; }
+.bi-camera-video-off-fill::before { content: "\f21d"; }
+.bi-camera-video-off::before { content: "\f21e"; }
+.bi-camera-video::before { content: "\f21f"; }
+.bi-camera::before { content: "\f220"; }
+.bi-camera2::before { content: "\f221"; }
+.bi-capslock-fill::before { content: "\f222"; }
+.bi-capslock::before { content: "\f223"; }
+.bi-card-checklist::before { content: "\f224"; }
+.bi-card-heading::before { content: "\f225"; }
+.bi-card-image::before { content: "\f226"; }
+.bi-card-list::before { content: "\f227"; }
+.bi-card-text::before { content: "\f228"; }
+.bi-caret-down-fill::before { content: "\f229"; }
+.bi-caret-down-square-fill::before { content: "\f22a"; }
+.bi-caret-down-square::before { content: "\f22b"; }
+.bi-caret-down::before { content: "\f22c"; }
+.bi-caret-left-fill::before { content: "\f22d"; }
+.bi-caret-left-square-fill::before { content: "\f22e"; }
+.bi-caret-left-square::before { content: "\f22f"; }
+.bi-caret-left::before { content: "\f230"; }
+.bi-caret-right-fill::before { content: "\f231"; }
+.bi-caret-right-square-fill::before { content: "\f232"; }
+.bi-caret-right-square::before { content: "\f233"; }
+.bi-caret-right::before { content: "\f234"; }
+.bi-caret-up-fill::before { content: "\f235"; }
+.bi-caret-up-square-fill::before { content: "\f236"; }
+.bi-caret-up-square::before { content: "\f237"; }
+.bi-caret-up::before { content: "\f238"; }
+.bi-cart-check-fill::before { content: "\f239"; }
+.bi-cart-check::before { content: "\f23a"; }
+.bi-cart-dash-fill::before { content: "\f23b"; }
+.bi-cart-dash::before { content: "\f23c"; }
+.bi-cart-fill::before { content: "\f23d"; }
+.bi-cart-plus-fill::before { content: "\f23e"; }
+.bi-cart-plus::before { content: "\f23f"; }
+.bi-cart-x-fill::before { content: "\f240"; }
+.bi-cart-x::before { content: "\f241"; }
+.bi-cart::before { content: "\f242"; }
+.bi-cart2::before { content: "\f243"; }
+.bi-cart3::before { content: "\f244"; }
+.bi-cart4::before { content: "\f245"; }
+.bi-cash-stack::before { content: "\f246"; }
+.bi-cash::before { content: "\f247"; }
+.bi-cast::before { content: "\f248"; }
+.bi-chat-dots-fill::before { content: "\f249"; }
+.bi-chat-dots::before { content: "\f24a"; }
+.bi-chat-fill::before { content: "\f24b"; }
+.bi-chat-left-dots-fill::before { content: "\f24c"; }
+.bi-chat-left-dots::before { content: "\f24d"; }
+.bi-chat-left-fill::before { content: "\f24e"; }
+.bi-chat-left-quote-fill::before { content: "\f24f"; }
+.bi-chat-left-quote::before { content: "\f250"; }
+.bi-chat-left-text-fill::before { content: "\f251"; }
+.bi-chat-left-text::before { content: "\f252"; }
+.bi-chat-left::before { content: "\f253"; }
+.bi-chat-quote-fill::before { content: "\f254"; }
+.bi-chat-quote::before { content: "\f255"; }
+.bi-chat-right-dots-fill::before { content: "\f256"; }
+.bi-chat-right-dots::before { content: "\f257"; }
+.bi-chat-right-fill::before { content: "\f258"; }
+.bi-chat-right-quote-fill::before { content: "\f259"; }
+.bi-chat-right-quote::before { content: "\f25a"; }
+.bi-chat-right-text-fill::before { content: "\f25b"; }
+.bi-chat-right-text::before { content: "\f25c"; }
+.bi-chat-right::before { content: "\f25d"; }
+.bi-chat-square-dots-fill::before { content: "\f25e"; }
+.bi-chat-square-dots::before { content: "\f25f"; }
+.bi-chat-square-fill::before { content: "\f260"; }
+.bi-chat-square-quote-fill::before { content: "\f261"; }
+.bi-chat-square-quote::before { content: "\f262"; }
+.bi-chat-square-text-fill::before { content: "\f263"; }
+.bi-chat-square-text::before { content: "\f264"; }
+.bi-chat-square::before { content: "\f265"; }
+.bi-chat-text-fill::before { content: "\f266"; }
+.bi-chat-text::before { content: "\f267"; }
+.bi-chat::before { content: "\f268"; }
+.bi-check-all::before { content: "\f269"; }
+.bi-check-circle-fill::before { content: "\f26a"; }
+.bi-check-circle::before { content: "\f26b"; }
+.bi-check-square-fill::before { content: "\f26c"; }
+.bi-check-square::before { content: "\f26d"; }
+.bi-check::before { content: "\f26e"; }
+.bi-check2-all::before { content: "\f26f"; }
+.bi-check2-circle::before { content: "\f270"; }
+.bi-check2-square::before { content: "\f271"; }
+.bi-check2::before { content: "\f272"; }
+.bi-chevron-bar-contract::before { content: "\f273"; }
+.bi-chevron-bar-down::before { content: "\f274"; }
+.bi-chevron-bar-expand::before { content: "\f275"; }
+.bi-chevron-bar-left::before { content: "\f276"; }
+.bi-chevron-bar-right::before { content: "\f277"; }
+.bi-chevron-bar-up::before { content: "\f278"; }
+.bi-chevron-compact-down::before { content: "\f279"; }
+.bi-chevron-compact-left::before { content: "\f27a"; }
+.bi-chevron-compact-right::before { content: "\f27b"; }
+.bi-chevron-compact-up::before { content: "\f27c"; }
+.bi-chevron-contract::before { content: "\f27d"; }
+.bi-chevron-double-down::before { content: "\f27e"; }
+.bi-chevron-double-left::before { content: "\f27f"; }
+.bi-chevron-double-right::before { content: "\f280"; }
+.bi-chevron-double-up::before { content: "\f281"; }
+.bi-chevron-down::before { content: "\f282"; }
+.bi-chevron-expand::before { content: "\f283"; }
+.bi-chevron-left::before { content: "\f284"; }
+.bi-chevron-right::before { content: "\f285"; }
+.bi-chevron-up::before { content: "\f286"; }
+.bi-circle-fill::before { content: "\f287"; }
+.bi-circle-half::before { content: "\f288"; }
+.bi-circle-square::before { content: "\f289"; }
+.bi-circle::before { content: "\f28a"; }
+.bi-clipboard-check::before { content: "\f28b"; }
+.bi-clipboard-data::before { content: "\f28c"; }
+.bi-clipboard-minus::before { content: "\f28d"; }
+.bi-clipboard-plus::before { content: "\f28e"; }
+.bi-clipboard-x::before { content: "\f28f"; }
+.bi-clipboard::before { content: "\f290"; }
+.bi-clock-fill::before { content: "\f291"; }
+.bi-clock-history::before { content: "\f292"; }
+.bi-clock::before { content: "\f293"; }
+.bi-cloud-arrow-down-fill::before { content: "\f294"; }
+.bi-cloud-arrow-down::before { content: "\f295"; }
+.bi-cloud-arrow-up-fill::before { content: "\f296"; }
+.bi-cloud-arrow-up::before { content: "\f297"; }
+.bi-cloud-check-fill::before { content: "\f298"; }
+.bi-cloud-check::before { content: "\f299"; }
+.bi-cloud-download-fill::before { content: "\f29a"; }
+.bi-cloud-download::before { content: "\f29b"; }
+.bi-cloud-drizzle-fill::before { content: "\f29c"; }
+.bi-cloud-drizzle::before { content: "\f29d"; }
+.bi-cloud-fill::before { content: "\f29e"; }
+.bi-cloud-fog-fill::before { content: "\f29f"; }
+.bi-cloud-fog::before { content: "\f2a0"; }
+.bi-cloud-fog2-fill::before { content: "\f2a1"; }
+.bi-cloud-fog2::before { content: "\f2a2"; }
+.bi-cloud-hail-fill::before { content: "\f2a3"; }
+.bi-cloud-hail::before { content: "\f2a4"; }
+.bi-cloud-haze-1::before { content: "\f2a5"; }
+.bi-cloud-haze-fill::before { content: "\f2a6"; }
+.bi-cloud-haze::before { content: "\f2a7"; }
+.bi-cloud-haze2-fill::before { content: "\f2a8"; }
+.bi-cloud-lightning-fill::before { content: "\f2a9"; }
+.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; }
+.bi-cloud-lightning-rain::before { content: "\f2ab"; }
+.bi-cloud-lightning::before { content: "\f2ac"; }
+.bi-cloud-minus-fill::before { content: "\f2ad"; }
+.bi-cloud-minus::before { content: "\f2ae"; }
+.bi-cloud-moon-fill::before { content: "\f2af"; }
+.bi-cloud-moon::before { content: "\f2b0"; }
+.bi-cloud-plus-fill::before { content: "\f2b1"; }
+.bi-cloud-plus::before { content: "\f2b2"; }
+.bi-cloud-rain-fill::before { content: "\f2b3"; }
+.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; }
+.bi-cloud-rain-heavy::before { content: "\f2b5"; }
+.bi-cloud-rain::before { content: "\f2b6"; }
+.bi-cloud-slash-fill::before { content: "\f2b7"; }
+.bi-cloud-slash::before { content: "\f2b8"; }
+.bi-cloud-sleet-fill::before { content: "\f2b9"; }
+.bi-cloud-sleet::before { content: "\f2ba"; }
+.bi-cloud-snow-fill::before { content: "\f2bb"; }
+.bi-cloud-snow::before { content: "\f2bc"; }
+.bi-cloud-sun-fill::before { content: "\f2bd"; }
+.bi-cloud-sun::before { content: "\f2be"; }
+.bi-cloud-upload-fill::before { content: "\f2bf"; }
+.bi-cloud-upload::before { content: "\f2c0"; }
+.bi-cloud::before { content: "\f2c1"; }
+.bi-clouds-fill::before { content: "\f2c2"; }
+.bi-clouds::before { content: "\f2c3"; }
+.bi-cloudy-fill::before { content: "\f2c4"; }
+.bi-cloudy::before { content: "\f2c5"; }
+.bi-code-slash::before { content: "\f2c6"; }
+.bi-code-square::before { content: "\f2c7"; }
+.bi-code::before { content: "\f2c8"; }
+.bi-collection-fill::before { content: "\f2c9"; }
+.bi-collection-play-fill::before { content: "\f2ca"; }
+.bi-collection-play::before { content: "\f2cb"; }
+.bi-collection::before { content: "\f2cc"; }
+.bi-columns-gap::before { content: "\f2cd"; }
+.bi-columns::before { content: "\f2ce"; }
+.bi-command::before { content: "\f2cf"; }
+.bi-compass-fill::before { content: "\f2d0"; }
+.bi-compass::before { content: "\f2d1"; }
+.bi-cone-striped::before { content: "\f2d2"; }
+.bi-cone::before { content: "\f2d3"; }
+.bi-controller::before { content: "\f2d4"; }
+.bi-cpu-fill::before { content: "\f2d5"; }
+.bi-cpu::before { content: "\f2d6"; }
+.bi-credit-card-2-back-fill::before { content: "\f2d7"; }
+.bi-credit-card-2-back::before { content: "\f2d8"; }
+.bi-credit-card-2-front-fill::before { content: "\f2d9"; }
+.bi-credit-card-2-front::before { content: "\f2da"; }
+.bi-credit-card-fill::before { content: "\f2db"; }
+.bi-credit-card::before { content: "\f2dc"; }
+.bi-crop::before { content: "\f2dd"; }
+.bi-cup-fill::before { content: "\f2de"; }
+.bi-cup-straw::before { content: "\f2df"; }
+.bi-cup::before { content: "\f2e0"; }
+.bi-cursor-fill::before { content: "\f2e1"; }
+.bi-cursor-text::before { content: "\f2e2"; }
+.bi-cursor::before { content: "\f2e3"; }
+.bi-dash-circle-dotted::before { content: "\f2e4"; }
+.bi-dash-circle-fill::before { content: "\f2e5"; }
+.bi-dash-circle::before { content: "\f2e6"; }
+.bi-dash-square-dotted::before { content: "\f2e7"; }
+.bi-dash-square-fill::before { content: "\f2e8"; }
+.bi-dash-square::before { content: "\f2e9"; }
+.bi-dash::before { content: "\f2ea"; }
+.bi-diagram-2-fill::before { content: "\f2eb"; }
+.bi-diagram-2::before { content: "\f2ec"; }
+.bi-diagram-3-fill::before { content: "\f2ed"; }
+.bi-diagram-3::before { content: "\f2ee"; }
+.bi-diamond-fill::before { content: "\f2ef"; }
+.bi-diamond-half::before { content: "\f2f0"; }
+.bi-diamond::before { content: "\f2f1"; }
+.bi-dice-1-fill::before { content: "\f2f2"; }
+.bi-dice-1::before { content: "\f2f3"; }
+.bi-dice-2-fill::before { content: "\f2f4"; }
+.bi-dice-2::before { content: "\f2f5"; }
+.bi-dice-3-fill::before { content: "\f2f6"; }
+.bi-dice-3::before { content: "\f2f7"; }
+.bi-dice-4-fill::before { content: "\f2f8"; }
+.bi-dice-4::before { content: "\f2f9"; }
+.bi-dice-5-fill::before { content: "\f2fa"; }
+.bi-dice-5::before { content: "\f2fb"; }
+.bi-dice-6-fill::before { content: "\f2fc"; }
+.bi-dice-6::before { content: "\f2fd"; }
+.bi-disc-fill::before { content: "\f2fe"; }
+.bi-disc::before { content: "\f2ff"; }
+.bi-discord::before { content: "\f300"; }
+.bi-display-fill::before { content: "\f301"; }
+.bi-display::before { content: "\f302"; }
+.bi-distribute-horizontal::before { content: "\f303"; }
+.bi-distribute-vertical::before { content: "\f304"; }
+.bi-door-closed-fill::before { content: "\f305"; }
+.bi-door-closed::before { content: "\f306"; }
+.bi-door-open-fill::before { content: "\f307"; }
+.bi-door-open::before { content: "\f308"; }
+.bi-dot::before { content: "\f309"; }
+.bi-download::before { content: "\f30a"; }
+.bi-droplet-fill::before { content: "\f30b"; }
+.bi-droplet-half::before { content: "\f30c"; }
+.bi-droplet::before { content: "\f30d"; }
+.bi-earbuds::before { content: "\f30e"; }
+.bi-easel-fill::before { content: "\f30f"; }
+.bi-easel::before { content: "\f310"; }
+.bi-egg-fill::before { content: "\f311"; }
+.bi-egg-fried::before { content: "\f312"; }
+.bi-egg::before { content: "\f313"; }
+.bi-eject-fill::before { content: "\f314"; }
+.bi-eject::before { content: "\f315"; }
+.bi-emoji-angry-fill::before { content: "\f316"; }
+.bi-emoji-angry::before { content: "\f317"; }
+.bi-emoji-dizzy-fill::before { content: "\f318"; }
+.bi-emoji-dizzy::before { content: "\f319"; }
+.bi-emoji-expressionless-fill::before { content: "\f31a"; }
+.bi-emoji-expressionless::before { content: "\f31b"; }
+.bi-emoji-frown-fill::before { content: "\f31c"; }
+.bi-emoji-frown::before { content: "\f31d"; }
+.bi-emoji-heart-eyes-fill::before { content: "\f31e"; }
+.bi-emoji-heart-eyes::before { content: "\f31f"; }
+.bi-emoji-laughing-fill::before { content: "\f320"; }
+.bi-emoji-laughing::before { content: "\f321"; }
+.bi-emoji-neutral-fill::before { content: "\f322"; }
+.bi-emoji-neutral::before { content: "\f323"; }
+.bi-emoji-smile-fill::before { content: "\f324"; }
+.bi-emoji-smile-upside-down-fill::before { content: "\f325"; }
+.bi-emoji-smile-upside-down::before { content: "\f326"; }
+.bi-emoji-smile::before { content: "\f327"; }
+.bi-emoji-sunglasses-fill::before { content: "\f328"; }
+.bi-emoji-sunglasses::before { content: "\f329"; }
+.bi-emoji-wink-fill::before { content: "\f32a"; }
+.bi-emoji-wink::before { content: "\f32b"; }
+.bi-envelope-fill::before { content: "\f32c"; }
+.bi-envelope-open-fill::before { content: "\f32d"; }
+.bi-envelope-open::before { content: "\f32e"; }
+.bi-envelope::before { content: "\f32f"; }
+.bi-eraser-fill::before { content: "\f330"; }
+.bi-eraser::before { content: "\f331"; }
+.bi-exclamation-circle-fill::before { content: "\f332"; }
+.bi-exclamation-circle::before { content: "\f333"; }
+.bi-exclamation-diamond-fill::before { content: "\f334"; }
+.bi-exclamation-diamond::before { content: "\f335"; }
+.bi-exclamation-octagon-fill::before { content: "\f336"; }
+.bi-exclamation-octagon::before { content: "\f337"; }
+.bi-exclamation-square-fill::before { content: "\f338"; }
+.bi-exclamation-square::before { content: "\f339"; }
+.bi-exclamation-triangle-fill::before { content: "\f33a"; }
+.bi-exclamation-triangle::before { content: "\f33b"; }
+.bi-exclamation::before { content: "\f33c"; }
+.bi-exclude::before { content: "\f33d"; }
+.bi-eye-fill::before { content: "\f33e"; }
+.bi-eye-slash-fill::before { content: "\f33f"; }
+.bi-eye-slash::before { content: "\f340"; }
+.bi-eye::before { content: "\f341"; }
+.bi-eyedropper::before { content: "\f342"; }
+.bi-eyeglasses::before { content: "\f343"; }
+.bi-facebook::before { content: "\f344"; }
+.bi-file-arrow-down-fill::before { content: "\f345"; }
+.bi-file-arrow-down::before { content: "\f346"; }
+.bi-file-arrow-up-fill::before { content: "\f347"; }
+.bi-file-arrow-up::before { content: "\f348"; }
+.bi-file-bar-graph-fill::before { content: "\f349"; }
+.bi-file-bar-graph::before { content: "\f34a"; }
+.bi-file-binary-fill::before { content: "\f34b"; }
+.bi-file-binary::before { content: "\f34c"; }
+.bi-file-break-fill::before { content: "\f34d"; }
+.bi-file-break::before { content: "\f34e"; }
+.bi-file-check-fill::before { content: "\f34f"; }
+.bi-file-check::before { content: "\f350"; }
+.bi-file-code-fill::before { content: "\f351"; }
+.bi-file-code::before { content: "\f352"; }
+.bi-file-diff-fill::before { content: "\f353"; }
+.bi-file-diff::before { content: "\f354"; }
+.bi-file-earmark-arrow-down-fill::before { content: "\f355"; }
+.bi-file-earmark-arrow-down::before { content: "\f356"; }
+.bi-file-earmark-arrow-up-fill::before { content: "\f357"; }
+.bi-file-earmark-arrow-up::before { content: "\f358"; }
+.bi-file-earmark-bar-graph-fill::before { content: "\f359"; }
+.bi-file-earmark-bar-graph::before { content: "\f35a"; }
+.bi-file-earmark-binary-fill::before { content: "\f35b"; }
+.bi-file-earmark-binary::before { content: "\f35c"; }
+.bi-file-earmark-break-fill::before { content: "\f35d"; }
+.bi-file-earmark-break::before { content: "\f35e"; }
+.bi-file-earmark-check-fill::before { content: "\f35f"; }
+.bi-file-earmark-check::before { content: "\f360"; }
+.bi-file-earmark-code-fill::before { content: "\f361"; }
+.bi-file-earmark-code::before { content: "\f362"; }
+.bi-file-earmark-diff-fill::before { content: "\f363"; }
+.bi-file-earmark-diff::before { content: "\f364"; }
+.bi-file-earmark-easel-fill::before { content: "\f365"; }
+.bi-file-earmark-easel::before { content: "\f366"; }
+.bi-file-earmark-excel-fill::before { content: "\f367"; }
+.bi-file-earmark-excel::before { content: "\f368"; }
+.bi-file-earmark-fill::before { content: "\f369"; }
+.bi-file-earmark-font-fill::before { content: "\f36a"; }
+.bi-file-earmark-font::before { content: "\f36b"; }
+.bi-file-earmark-image-fill::before { content: "\f36c"; }
+.bi-file-earmark-image::before { content: "\f36d"; }
+.bi-file-earmark-lock-fill::before { content: "\f36e"; }
+.bi-file-earmark-lock::before { content: "\f36f"; }
+.bi-file-earmark-lock2-fill::before { content: "\f370"; }
+.bi-file-earmark-lock2::before { content: "\f371"; }
+.bi-file-earmark-medical-fill::before { content: "\f372"; }
+.bi-file-earmark-medical::before { content: "\f373"; }
+.bi-file-earmark-minus-fill::before { content: "\f374"; }
+.bi-file-earmark-minus::before { content: "\f375"; }
+.bi-file-earmark-music-fill::before { content: "\f376"; }
+.bi-file-earmark-music::before { content: "\f377"; }
+.bi-file-earmark-person-fill::before { content: "\f378"; }
+.bi-file-earmark-person::before { content: "\f379"; }
+.bi-file-earmark-play-fill::before { content: "\f37a"; }
+.bi-file-earmark-play::before { content: "\f37b"; }
+.bi-file-earmark-plus-fill::before { content: "\f37c"; }
+.bi-file-earmark-plus::before { content: "\f37d"; }
+.bi-file-earmark-post-fill::before { content: "\f37e"; }
+.bi-file-earmark-post::before { content: "\f37f"; }
+.bi-file-earmark-ppt-fill::before { content: "\f380"; }
+.bi-file-earmark-ppt::before { content: "\f381"; }
+.bi-file-earmark-richtext-fill::before { content: "\f382"; }
+.bi-file-earmark-richtext::before { content: "\f383"; }
+.bi-file-earmark-ruled-fill::before { content: "\f384"; }
+.bi-file-earmark-ruled::before { content: "\f385"; }
+.bi-file-earmark-slides-fill::before { content: "\f386"; }
+.bi-file-earmark-slides::before { content: "\f387"; }
+.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; }
+.bi-file-earmark-spreadsheet::before { content: "\f389"; }
+.bi-file-earmark-text-fill::before { content: "\f38a"; }
+.bi-file-earmark-text::before { content: "\f38b"; }
+.bi-file-earmark-word-fill::before { content: "\f38c"; }
+.bi-file-earmark-word::before { content: "\f38d"; }
+.bi-file-earmark-x-fill::before { content: "\f38e"; }
+.bi-file-earmark-x::before { content: "\f38f"; }
+.bi-file-earmark-zip-fill::before { content: "\f390"; }
+.bi-file-earmark-zip::before { content: "\f391"; }
+.bi-file-earmark::before { content: "\f392"; }
+.bi-file-easel-fill::before { content: "\f393"; }
+.bi-file-easel::before { content: "\f394"; }
+.bi-file-excel-fill::before { content: "\f395"; }
+.bi-file-excel::before { content: "\f396"; }
+.bi-file-fill::before { content: "\f397"; }
+.bi-file-font-fill::before { content: "\f398"; }
+.bi-file-font::before { content: "\f399"; }
+.bi-file-image-fill::before { content: "\f39a"; }
+.bi-file-image::before { content: "\f39b"; }
+.bi-file-lock-fill::before { content: "\f39c"; }
+.bi-file-lock::before { content: "\f39d"; }
+.bi-file-lock2-fill::before { content: "\f39e"; }
+.bi-file-lock2::before { content: "\f39f"; }
+.bi-file-medical-fill::before { content: "\f3a0"; }
+.bi-file-medical::before { content: "\f3a1"; }
+.bi-file-minus-fill::before { content: "\f3a2"; }
+.bi-file-minus::before { content: "\f3a3"; }
+.bi-file-music-fill::before { content: "\f3a4"; }
+.bi-file-music::before { content: "\f3a5"; }
+.bi-file-person-fill::before { content: "\f3a6"; }
+.bi-file-person::before { content: "\f3a7"; }
+.bi-file-play-fill::before { content: "\f3a8"; }
+.bi-file-play::before { content: "\f3a9"; }
+.bi-file-plus-fill::before { content: "\f3aa"; }
+.bi-file-plus::before { content: "\f3ab"; }
+.bi-file-post-fill::before { content: "\f3ac"; }
+.bi-file-post::before { content: "\f3ad"; }
+.bi-file-ppt-fill::before { content: "\f3ae"; }
+.bi-file-ppt::before { content: "\f3af"; }
+.bi-file-richtext-fill::before { content: "\f3b0"; }
+.bi-file-richtext::before { content: "\f3b1"; }
+.bi-file-ruled-fill::before { content: "\f3b2"; }
+.bi-file-ruled::before { content: "\f3b3"; }
+.bi-file-slides-fill::before { content: "\f3b4"; }
+.bi-file-slides::before { content: "\f3b5"; }
+.bi-file-spreadsheet-fill::before { content: "\f3b6"; }
+.bi-file-spreadsheet::before { content: "\f3b7"; }
+.bi-file-text-fill::before { content: "\f3b8"; }
+.bi-file-text::before { content: "\f3b9"; }
+.bi-file-word-fill::before { content: "\f3ba"; }
+.bi-file-word::before { content: "\f3bb"; }
+.bi-file-x-fill::before { content: "\f3bc"; }
+.bi-file-x::before { content: "\f3bd"; }
+.bi-file-zip-fill::before { content: "\f3be"; }
+.bi-file-zip::before { content: "\f3bf"; }
+.bi-file::before { content: "\f3c0"; }
+.bi-files-alt::before { content: "\f3c1"; }
+.bi-files::before { content: "\f3c2"; }
+.bi-film::before { content: "\f3c3"; }
+.bi-filter-circle-fill::before { content: "\f3c4"; }
+.bi-filter-circle::before { content: "\f3c5"; }
+.bi-filter-left::before { content: "\f3c6"; }
+.bi-filter-right::before { content: "\f3c7"; }
+.bi-filter-square-fill::before { content: "\f3c8"; }
+.bi-filter-square::before { content: "\f3c9"; }
+.bi-filter::before { content: "\f3ca"; }
+.bi-flag-fill::before { content: "\f3cb"; }
+.bi-flag::before { content: "\f3cc"; }
+.bi-flower1::before { content: "\f3cd"; }
+.bi-flower2::before { content: "\f3ce"; }
+.bi-flower3::before { content: "\f3cf"; }
+.bi-folder-check::before { content: "\f3d0"; }
+.bi-folder-fill::before { content: "\f3d1"; }
+.bi-folder-minus::before { content: "\f3d2"; }
+.bi-folder-plus::before { content: "\f3d3"; }
+.bi-folder-symlink-fill::before { content: "\f3d4"; }
+.bi-folder-symlink::before { content: "\f3d5"; }
+.bi-folder-x::before { content: "\f3d6"; }
+.bi-folder::before { content: "\f3d7"; }
+.bi-folder2-open::before { content: "\f3d8"; }
+.bi-folder2::before { content: "\f3d9"; }
+.bi-fonts::before { content: "\f3da"; }
+.bi-forward-fill::before { content: "\f3db"; }
+.bi-forward::before { content: "\f3dc"; }
+.bi-front::before { content: "\f3dd"; }
+.bi-fullscreen-exit::before { content: "\f3de"; }
+.bi-fullscreen::before { content: "\f3df"; }
+.bi-funnel-fill::before { content: "\f3e0"; }
+.bi-funnel::before { content: "\f3e1"; }
+.bi-gear-fill::before { content: "\f3e2"; }
+.bi-gear-wide-connected::before { content: "\f3e3"; }
+.bi-gear-wide::before { content: "\f3e4"; }
+.bi-gear::before { content: "\f3e5"; }
+.bi-gem::before { content: "\f3e6"; }
+.bi-geo-alt-fill::before { content: "\f3e7"; }
+.bi-geo-alt::before { content: "\f3e8"; }
+.bi-geo-fill::before { content: "\f3e9"; }
+.bi-geo::before { content: "\f3ea"; }
+.bi-gift-fill::before { content: "\f3eb"; }
+.bi-gift::before { content: "\f3ec"; }
+.bi-github::before { content: "\f3ed"; }
+.bi-globe::before { content: "\f3ee"; }
+.bi-globe2::before { content: "\f3ef"; }
+.bi-google::before { content: "\f3f0"; }
+.bi-graph-down::before { content: "\f3f1"; }
+.bi-graph-up::before { content: "\f3f2"; }
+.bi-grid-1x2-fill::before { content: "\f3f3"; }
+.bi-grid-1x2::before { content: "\f3f4"; }
+.bi-grid-3x2-gap-fill::before { content: "\f3f5"; }
+.bi-grid-3x2-gap::before { content: "\f3f6"; }
+.bi-grid-3x2::before { content: "\f3f7"; }
+.bi-grid-3x3-gap-fill::before { content: "\f3f8"; }
+.bi-grid-3x3-gap::before { content: "\f3f9"; }
+.bi-grid-3x3::before { content: "\f3fa"; }
+.bi-grid-fill::before { content: "\f3fb"; }
+.bi-grid::before { content: "\f3fc"; }
+.bi-grip-horizontal::before { content: "\f3fd"; }
+.bi-grip-vertical::before { content: "\f3fe"; }
+.bi-hammer::before { content: "\f3ff"; }
+.bi-hand-index-fill::before { content: "\f400"; }
+.bi-hand-index-thumb-fill::before { content: "\f401"; }
+.bi-hand-index-thumb::before { content: "\f402"; }
+.bi-hand-index::before { content: "\f403"; }
+.bi-hand-thumbs-down-fill::before { content: "\f404"; }
+.bi-hand-thumbs-down::before { content: "\f405"; }
+.bi-hand-thumbs-up-fill::before { content: "\f406"; }
+.bi-hand-thumbs-up::before { content: "\f407"; }
+.bi-handbag-fill::before { content: "\f408"; }
+.bi-handbag::before { content: "\f409"; }
+.bi-hash::before { content: "\f40a"; }
+.bi-hdd-fill::before { content: "\f40b"; }
+.bi-hdd-network-fill::before { content: "\f40c"; }
+.bi-hdd-network::before { content: "\f40d"; }
+.bi-hdd-rack-fill::before { content: "\f40e"; }
+.bi-hdd-rack::before { content: "\f40f"; }
+.bi-hdd-stack-fill::before { content: "\f410"; }
+.bi-hdd-stack::before { content: "\f411"; }
+.bi-hdd::before { content: "\f412"; }
+.bi-headphones::before { content: "\f413"; }
+.bi-headset::before { content: "\f414"; }
+.bi-heart-fill::before { content: "\f415"; }
+.bi-heart-half::before { content: "\f416"; }
+.bi-heart::before { content: "\f417"; }
+.bi-heptagon-fill::before { content: "\f418"; }
+.bi-heptagon-half::before { content: "\f419"; }
+.bi-heptagon::before { content: "\f41a"; }
+.bi-hexagon-fill::before { content: "\f41b"; }
+.bi-hexagon-half::before { content: "\f41c"; }
+.bi-hexagon::before { content: "\f41d"; }
+.bi-hourglass-bottom::before { content: "\f41e"; }
+.bi-hourglass-split::before { content: "\f41f"; }
+.bi-hourglass-top::before { content: "\f420"; }
+.bi-hourglass::before { content: "\f421"; }
+.bi-house-door-fill::before { content: "\f422"; }
+.bi-house-door::before { content: "\f423"; }
+.bi-house-fill::before { content: "\f424"; }
+.bi-house::before { content: "\f425"; }
+.bi-hr::before { content: "\f426"; }
+.bi-hurricane::before { content: "\f427"; }
+.bi-image-alt::before { content: "\f428"; }
+.bi-image-fill::before { content: "\f429"; }
+.bi-image::before { content: "\f42a"; }
+.bi-images::before { content: "\f42b"; }
+.bi-inbox-fill::before { content: "\f42c"; }
+.bi-inbox::before { content: "\f42d"; }
+.bi-inboxes-fill::before { content: "\f42e"; }
+.bi-inboxes::before { content: "\f42f"; }
+.bi-info-circle-fill::before { content: "\f430"; }
+.bi-info-circle::before { content: "\f431"; }
+.bi-info-square-fill::before { content: "\f432"; }
+.bi-info-square::before { content: "\f433"; }
+.bi-info::before { content: "\f434"; }
+.bi-input-cursor-text::before { content: "\f435"; }
+.bi-input-cursor::before { content: "\f436"; }
+.bi-instagram::before { content: "\f437"; }
+.bi-intersect::before { content: "\f438"; }
+.bi-journal-album::before { content: "\f439"; }
+.bi-journal-arrow-down::before { content: "\f43a"; }
+.bi-journal-arrow-up::before { content: "\f43b"; }
+.bi-journal-bookmark-fill::before { content: "\f43c"; }
+.bi-journal-bookmark::before { content: "\f43d"; }
+.bi-journal-check::before { content: "\f43e"; }
+.bi-journal-code::before { content: "\f43f"; }
+.bi-journal-medical::before { content: "\f440"; }
+.bi-journal-minus::before { content: "\f441"; }
+.bi-journal-plus::before { content: "\f442"; }
+.bi-journal-richtext::before { content: "\f443"; }
+.bi-journal-text::before { content: "\f444"; }
+.bi-journal-x::before { content: "\f445"; }
+.bi-journal::before { content: "\f446"; }
+.bi-journals::before { content: "\f447"; }
+.bi-joystick::before { content: "\f448"; }
+.bi-justify-left::before { content: "\f449"; }
+.bi-justify-right::before { content: "\f44a"; }
+.bi-justify::before { content: "\f44b"; }
+.bi-kanban-fill::before { content: "\f44c"; }
+.bi-kanban::before { content: "\f44d"; }
+.bi-key-fill::before { content: "\f44e"; }
+.bi-key::before { content: "\f44f"; }
+.bi-keyboard-fill::before { content: "\f450"; }
+.bi-keyboard::before { content: "\f451"; }
+.bi-ladder::before { content: "\f452"; }
+.bi-lamp-fill::before { content: "\f453"; }
+.bi-lamp::before { content: "\f454"; }
+.bi-laptop-fill::before { content: "\f455"; }
+.bi-laptop::before { content: "\f456"; }
+.bi-layer-backward::before { content: "\f457"; }
+.bi-layer-forward::before { content: "\f458"; }
+.bi-layers-fill::before { content: "\f459"; }
+.bi-layers-half::before { content: "\f45a"; }
+.bi-layers::before { content: "\f45b"; }
+.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; }
+.bi-layout-sidebar-inset::before { content: "\f45d"; }
+.bi-layout-sidebar-reverse::before { content: "\f45e"; }
+.bi-layout-sidebar::before { content: "\f45f"; }
+.bi-layout-split::before { content: "\f460"; }
+.bi-layout-text-sidebar-reverse::before { content: "\f461"; }
+.bi-layout-text-sidebar::before { content: "\f462"; }
+.bi-layout-text-window-reverse::before { content: "\f463"; }
+.bi-layout-text-window::before { content: "\f464"; }
+.bi-layout-three-columns::before { content: "\f465"; }
+.bi-layout-wtf::before { content: "\f466"; }
+.bi-life-preserver::before { content: "\f467"; }
+.bi-lightbulb-fill::before { content: "\f468"; }
+.bi-lightbulb-off-fill::before { content: "\f469"; }
+.bi-lightbulb-off::before { content: "\f46a"; }
+.bi-lightbulb::before { content: "\f46b"; }
+.bi-lightning-charge-fill::before { content: "\f46c"; }
+.bi-lightning-charge::before { content: "\f46d"; }
+.bi-lightning-fill::before { content: "\f46e"; }
+.bi-lightning::before { content: "\f46f"; }
+.bi-link-45deg::before { content: "\f470"; }
+.bi-link::before { content: "\f471"; }
+.bi-linkedin::before { content: "\f472"; }
+.bi-list-check::before { content: "\f473"; }
+.bi-list-nested::before { content: "\f474"; }
+.bi-list-ol::before { content: "\f475"; }
+.bi-list-stars::before { content: "\f476"; }
+.bi-list-task::before { content: "\f477"; }
+.bi-list-ul::before { content: "\f478"; }
+.bi-list::before { content: "\f479"; }
+.bi-lock-fill::before { content: "\f47a"; }
+.bi-lock::before { content: "\f47b"; }
+.bi-mailbox::before { content: "\f47c"; }
+.bi-mailbox2::before { content: "\f47d"; }
+.bi-map-fill::before { content: "\f47e"; }
+.bi-map::before { content: "\f47f"; }
+.bi-markdown-fill::before { content: "\f480"; }
+.bi-markdown::before { content: "\f481"; }
+.bi-mask::before { content: "\f482"; }
+.bi-megaphone-fill::before { content: "\f483"; }
+.bi-megaphone::before { content: "\f484"; }
+.bi-menu-app-fill::before { content: "\f485"; }
+.bi-menu-app::before { content: "\f486"; }
+.bi-menu-button-fill::before { content: "\f487"; }
+.bi-menu-button-wide-fill::before { content: "\f488"; }
+.bi-menu-button-wide::before { content: "\f489"; }
+.bi-menu-button::before { content: "\f48a"; }
+.bi-menu-down::before { content: "\f48b"; }
+.bi-menu-up::before { content: "\f48c"; }
+.bi-mic-fill::before { content: "\f48d"; }
+.bi-mic-mute-fill::before { content: "\f48e"; }
+.bi-mic-mute::before { content: "\f48f"; }
+.bi-mic::before { content: "\f490"; }
+.bi-minecart-loaded::before { content: "\f491"; }
+.bi-minecart::before { content: "\f492"; }
+.bi-moisture::before { content: "\f493"; }
+.bi-moon-fill::before { content: "\f494"; }
+.bi-moon-stars-fill::before { content: "\f495"; }
+.bi-moon-stars::before { content: "\f496"; }
+.bi-moon::before { content: "\f497"; }
+.bi-mouse-fill::before { content: "\f498"; }
+.bi-mouse::before { content: "\f499"; }
+.bi-mouse2-fill::before { content: "\f49a"; }
+.bi-mouse2::before { content: "\f49b"; }
+.bi-mouse3-fill::before { content: "\f49c"; }
+.bi-mouse3::before { content: "\f49d"; }
+.bi-music-note-beamed::before { content: "\f49e"; }
+.bi-music-note-list::before { content: "\f49f"; }
+.bi-music-note::before { content: "\f4a0"; }
+.bi-music-player-fill::before { content: "\f4a1"; }
+.bi-music-player::before { content: "\f4a2"; }
+.bi-newspaper::before { content: "\f4a3"; }
+.bi-node-minus-fill::before { content: "\f4a4"; }
+.bi-node-minus::before { content: "\f4a5"; }
+.bi-node-plus-fill::before { content: "\f4a6"; }
+.bi-node-plus::before { content: "\f4a7"; }
+.bi-nut-fill::before { content: "\f4a8"; }
+.bi-nut::before { content: "\f4a9"; }
+.bi-octagon-fill::before { content: "\f4aa"; }
+.bi-octagon-half::before { content: "\f4ab"; }
+.bi-octagon::before { content: "\f4ac"; }
+.bi-option::before { content: "\f4ad"; }
+.bi-outlet::before { content: "\f4ae"; }
+.bi-paint-bucket::before { content: "\f4af"; }
+.bi-palette-fill::before { content: "\f4b0"; }
+.bi-palette::before { content: "\f4b1"; }
+.bi-palette2::before { content: "\f4b2"; }
+.bi-paperclip::before { content: "\f4b3"; }
+.bi-paragraph::before { content: "\f4b4"; }
+.bi-patch-check-fill::before { content: "\f4b5"; }
+.bi-patch-check::before { content: "\f4b6"; }
+.bi-patch-exclamation-fill::before { content: "\f4b7"; }
+.bi-patch-exclamation::before { content: "\f4b8"; }
+.bi-patch-minus-fill::before { content: "\f4b9"; }
+.bi-patch-minus::before { content: "\f4ba"; }
+.bi-patch-plus-fill::before { content: "\f4bb"; }
+.bi-patch-plus::before { content: "\f4bc"; }
+.bi-patch-question-fill::before { content: "\f4bd"; }
+.bi-patch-question::before { content: "\f4be"; }
+.bi-pause-btn-fill::before { content: "\f4bf"; }
+.bi-pause-btn::before { content: "\f4c0"; }
+.bi-pause-circle-fill::before { content: "\f4c1"; }
+.bi-pause-circle::before { content: "\f4c2"; }
+.bi-pause-fill::before { content: "\f4c3"; }
+.bi-pause::before { content: "\f4c4"; }
+.bi-peace-fill::before { content: "\f4c5"; }
+.bi-peace::before { content: "\f4c6"; }
+.bi-pen-fill::before { content: "\f4c7"; }
+.bi-pen::before { content: "\f4c8"; }
+.bi-pencil-fill::before { content: "\f4c9"; }
+.bi-pencil-square::before { content: "\f4ca"; }
+.bi-pencil::before { content: "\f4cb"; }
+.bi-pentagon-fill::before { content: "\f4cc"; }
+.bi-pentagon-half::before { content: "\f4cd"; }
+.bi-pentagon::before { content: "\f4ce"; }
+.bi-people-fill::before { content: "\f4cf"; }
+.bi-people::before { content: "\f4d0"; }
+.bi-percent::before { content: "\f4d1"; }
+.bi-person-badge-fill::before { content: "\f4d2"; }
+.bi-person-badge::before { content: "\f4d3"; }
+.bi-person-bounding-box::before { content: "\f4d4"; }
+.bi-person-check-fill::before { content: "\f4d5"; }
+.bi-person-check::before { content: "\f4d6"; }
+.bi-person-circle::before { content: "\f4d7"; }
+.bi-person-dash-fill::before { content: "\f4d8"; }
+.bi-person-dash::before { content: "\f4d9"; }
+.bi-person-fill::before { content: "\f4da"; }
+.bi-person-lines-fill::before { content: "\f4db"; }
+.bi-person-plus-fill::before { content: "\f4dc"; }
+.bi-person-plus::before { content: "\f4dd"; }
+.bi-person-square::before { content: "\f4de"; }
+.bi-person-x-fill::before { content: "\f4df"; }
+.bi-person-x::before { content: "\f4e0"; }
+.bi-person::before { content: "\f4e1"; }
+.bi-phone-fill::before { content: "\f4e2"; }
+.bi-phone-landscape-fill::before { content: "\f4e3"; }
+.bi-phone-landscape::before { content: "\f4e4"; }
+.bi-phone-vibrate-fill::before { content: "\f4e5"; }
+.bi-phone-vibrate::before { content: "\f4e6"; }
+.bi-phone::before { content: "\f4e7"; }
+.bi-pie-chart-fill::before { content: "\f4e8"; }
+.bi-pie-chart::before { content: "\f4e9"; }
+.bi-pin-angle-fill::before { content: "\f4ea"; }
+.bi-pin-angle::before { content: "\f4eb"; }
+.bi-pin-fill::before { content: "\f4ec"; }
+.bi-pin::before { content: "\f4ed"; }
+.bi-pip-fill::before { content: "\f4ee"; }
+.bi-pip::before { content: "\f4ef"; }
+.bi-play-btn-fill::before { content: "\f4f0"; }
+.bi-play-btn::before { content: "\f4f1"; }
+.bi-play-circle-fill::before { content: "\f4f2"; }
+.bi-play-circle::before { content: "\f4f3"; }
+.bi-play-fill::before { content: "\f4f4"; }
+.bi-play::before { content: "\f4f5"; }
+.bi-plug-fill::before { content: "\f4f6"; }
+.bi-plug::before { content: "\f4f7"; }
+.bi-plus-circle-dotted::before { content: "\f4f8"; }
+.bi-plus-circle-fill::before { content: "\f4f9"; }
+.bi-plus-circle::before { content: "\f4fa"; }
+.bi-plus-square-dotted::before { content: "\f4fb"; }
+.bi-plus-square-fill::before { content: "\f4fc"; }
+.bi-plus-square::before { content: "\f4fd"; }
+.bi-plus::before { content: "\f4fe"; }
+.bi-power::before { content: "\f4ff"; }
+.bi-printer-fill::before { content: "\f500"; }
+.bi-printer::before { content: "\f501"; }
+.bi-puzzle-fill::before { content: "\f502"; }
+.bi-puzzle::before { content: "\f503"; }
+.bi-question-circle-fill::before { content: "\f504"; }
+.bi-question-circle::before { content: "\f505"; }
+.bi-question-diamond-fill::before { content: "\f506"; }
+.bi-question-diamond::before { content: "\f507"; }
+.bi-question-octagon-fill::before { content: "\f508"; }
+.bi-question-octagon::before { content: "\f509"; }
+.bi-question-square-fill::before { content: "\f50a"; }
+.bi-question-square::before { content: "\f50b"; }
+.bi-question::before { content: "\f50c"; }
+.bi-rainbow::before { content: "\f50d"; }
+.bi-receipt-cutoff::before { content: "\f50e"; }
+.bi-receipt::before { content: "\f50f"; }
+.bi-reception-0::before { content: "\f510"; }
+.bi-reception-1::before { content: "\f511"; }
+.bi-reception-2::before { content: "\f512"; }
+.bi-reception-3::before { content: "\f513"; }
+.bi-reception-4::before { content: "\f514"; }
+.bi-record-btn-fill::before { content: "\f515"; }
+.bi-record-btn::before { content: "\f516"; }
+.bi-record-circle-fill::before { content: "\f517"; }
+.bi-record-circle::before { content: "\f518"; }
+.bi-record-fill::before { content: "\f519"; }
+.bi-record::before { content: "\f51a"; }
+.bi-record2-fill::before { content: "\f51b"; }
+.bi-record2::before { content: "\f51c"; }
+.bi-reply-all-fill::before { content: "\f51d"; }
+.bi-reply-all::before { content: "\f51e"; }
+.bi-reply-fill::before { content: "\f51f"; }
+.bi-reply::before { content: "\f520"; }
+.bi-rss-fill::before { content: "\f521"; }
+.bi-rss::before { content: "\f522"; }
+.bi-rulers::before { content: "\f523"; }
+.bi-save-fill::before { content: "\f524"; }
+.bi-save::before { content: "\f525"; }
+.bi-save2-fill::before { content: "\f526"; }
+.bi-save2::before { content: "\f527"; }
+.bi-scissors::before { content: "\f528"; }
+.bi-screwdriver::before { content: "\f529"; }
+.bi-search::before { content: "\f52a"; }
+.bi-segmented-nav::before { content: "\f52b"; }
+.bi-server::before { content: "\f52c"; }
+.bi-share-fill::before { content: "\f52d"; }
+.bi-share::before { content: "\f52e"; }
+.bi-shield-check::before { content: "\f52f"; }
+.bi-shield-exclamation::before { content: "\f530"; }
+.bi-shield-fill-check::before { content: "\f531"; }
+.bi-shield-fill-exclamation::before { content: "\f532"; }
+.bi-shield-fill-minus::before { content: "\f533"; }
+.bi-shield-fill-plus::before { content: "\f534"; }
+.bi-shield-fill-x::before { content: "\f535"; }
+.bi-shield-fill::before { content: "\f536"; }
+.bi-shield-lock-fill::before { content: "\f537"; }
+.bi-shield-lock::before { content: "\f538"; }
+.bi-shield-minus::before { content: "\f539"; }
+.bi-shield-plus::before { content: "\f53a"; }
+.bi-shield-shaded::before { content: "\f53b"; }
+.bi-shield-slash-fill::before { content: "\f53c"; }
+.bi-shield-slash::before { content: "\f53d"; }
+.bi-shield-x::before { content: "\f53e"; }
+.bi-shield::before { content: "\f53f"; }
+.bi-shift-fill::before { content: "\f540"; }
+.bi-shift::before { content: "\f541"; }
+.bi-shop-window::before { content: "\f542"; }
+.bi-shop::before { content: "\f543"; }
+.bi-shuffle::before { content: "\f544"; }
+.bi-signpost-2-fill::before { content: "\f545"; }
+.bi-signpost-2::before { content: "\f546"; }
+.bi-signpost-fill::before { content: "\f547"; }
+.bi-signpost-split-fill::before { content: "\f548"; }
+.bi-signpost-split::before { content: "\f549"; }
+.bi-signpost::before { content: "\f54a"; }
+.bi-sim-fill::before { content: "\f54b"; }
+.bi-sim::before { content: "\f54c"; }
+.bi-skip-backward-btn-fill::before { content: "\f54d"; }
+.bi-skip-backward-btn::before { content: "\f54e"; }
+.bi-skip-backward-circle-fill::before { content: "\f54f"; }
+.bi-skip-backward-circle::before { content: "\f550"; }
+.bi-skip-backward-fill::before { content: "\f551"; }
+.bi-skip-backward::before { content: "\f552"; }
+.bi-skip-end-btn-fill::before { content: "\f553"; }
+.bi-skip-end-btn::before { content: "\f554"; }
+.bi-skip-end-circle-fill::before { content: "\f555"; }
+.bi-skip-end-circle::before { content: "\f556"; }
+.bi-skip-end-fill::before { content: "\f557"; }
+.bi-skip-end::before { content: "\f558"; }
+.bi-skip-forward-btn-fill::before { content: "\f559"; }
+.bi-skip-forward-btn::before { content: "\f55a"; }
+.bi-skip-forward-circle-fill::before { content: "\f55b"; }
+.bi-skip-forward-circle::before { content: "\f55c"; }
+.bi-skip-forward-fill::before { content: "\f55d"; }
+.bi-skip-forward::before { content: "\f55e"; }
+.bi-skip-start-btn-fill::before { content: "\f55f"; }
+.bi-skip-start-btn::before { content: "\f560"; }
+.bi-skip-start-circle-fill::before { content: "\f561"; }
+.bi-skip-start-circle::before { content: "\f562"; }
+.bi-skip-start-fill::before { content: "\f563"; }
+.bi-skip-start::before { content: "\f564"; }
+.bi-slack::before { content: "\f565"; }
+.bi-slash-circle-fill::before { content: "\f566"; }
+.bi-slash-circle::before { content: "\f567"; }
+.bi-slash-square-fill::before { content: "\f568"; }
+.bi-slash-square::before { content: "\f569"; }
+.bi-slash::before { content: "\f56a"; }
+.bi-sliders::before { content: "\f56b"; }
+.bi-smartwatch::before { content: "\f56c"; }
+.bi-snow::before { content: "\f56d"; }
+.bi-snow2::before { content: "\f56e"; }
+.bi-snow3::before { content: "\f56f"; }
+.bi-sort-alpha-down-alt::before { content: "\f570"; }
+.bi-sort-alpha-down::before { content: "\f571"; }
+.bi-sort-alpha-up-alt::before { content: "\f572"; }
+.bi-sort-alpha-up::before { content: "\f573"; }
+.bi-sort-down-alt::before { content: "\f574"; }
+.bi-sort-down::before { content: "\f575"; }
+.bi-sort-numeric-down-alt::before { content: "\f576"; }
+.bi-sort-numeric-down::before { content: "\f577"; }
+.bi-sort-numeric-up-alt::before { content: "\f578"; }
+.bi-sort-numeric-up::before { content: "\f579"; }
+.bi-sort-up-alt::before { content: "\f57a"; }
+.bi-sort-up::before { content: "\f57b"; }
+.bi-soundwave::before { content: "\f57c"; }
+.bi-speaker-fill::before { content: "\f57d"; }
+.bi-speaker::before { content: "\f57e"; }
+.bi-speedometer::before { content: "\f57f"; }
+.bi-speedometer2::before { content: "\f580"; }
+.bi-spellcheck::before { content: "\f581"; }
+.bi-square-fill::before { content: "\f582"; }
+.bi-square-half::before { content: "\f583"; }
+.bi-square::before { content: "\f584"; }
+.bi-stack::before { content: "\f585"; }
+.bi-star-fill::before { content: "\f586"; }
+.bi-star-half::before { content: "\f587"; }
+.bi-star::before { content: "\f588"; }
+.bi-stars::before { content: "\f589"; }
+.bi-stickies-fill::before { content: "\f58a"; }
+.bi-stickies::before { content: "\f58b"; }
+.bi-sticky-fill::before { content: "\f58c"; }
+.bi-sticky::before { content: "\f58d"; }
+.bi-stop-btn-fill::before { content: "\f58e"; }
+.bi-stop-btn::before { content: "\f58f"; }
+.bi-stop-circle-fill::before { content: "\f590"; }
+.bi-stop-circle::before { content: "\f591"; }
+.bi-stop-fill::before { content: "\f592"; }
+.bi-stop::before { content: "\f593"; }
+.bi-stoplights-fill::before { content: "\f594"; }
+.bi-stoplights::before { content: "\f595"; }
+.bi-stopwatch-fill::before { content: "\f596"; }
+.bi-stopwatch::before { content: "\f597"; }
+.bi-subtract::before { content: "\f598"; }
+.bi-suit-club-fill::before { content: "\f599"; }
+.bi-suit-club::before { content: "\f59a"; }
+.bi-suit-diamond-fill::before { content: "\f59b"; }
+.bi-suit-diamond::before { content: "\f59c"; }
+.bi-suit-heart-fill::before { content: "\f59d"; }
+.bi-suit-heart::before { content: "\f59e"; }
+.bi-suit-spade-fill::before { content: "\f59f"; }
+.bi-suit-spade::before { content: "\f5a0"; }
+.bi-sun-fill::before { content: "\f5a1"; }
+.bi-sun::before { content: "\f5a2"; }
+.bi-sunglasses::before { content: "\f5a3"; }
+.bi-sunrise-fill::before { content: "\f5a4"; }
+.bi-sunrise::before { content: "\f5a5"; }
+.bi-sunset-fill::before { content: "\f5a6"; }
+.bi-sunset::before { content: "\f5a7"; }
+.bi-symmetry-horizontal::before { content: "\f5a8"; }
+.bi-symmetry-vertical::before { content: "\f5a9"; }
+.bi-table::before { content: "\f5aa"; }
+.bi-tablet-fill::before { content: "\f5ab"; }
+.bi-tablet-landscape-fill::before { content: "\f5ac"; }
+.bi-tablet-landscape::before { content: "\f5ad"; }
+.bi-tablet::before { content: "\f5ae"; }
+.bi-tag-fill::before { content: "\f5af"; }
+.bi-tag::before { content: "\f5b0"; }
+.bi-tags-fill::before { content: "\f5b1"; }
+.bi-tags::before { content: "\f5b2"; }
+.bi-telegram::before { content: "\f5b3"; }
+.bi-telephone-fill::before { content: "\f5b4"; }
+.bi-telephone-forward-fill::before { content: "\f5b5"; }
+.bi-telephone-forward::before { content: "\f5b6"; }
+.bi-telephone-inbound-fill::before { content: "\f5b7"; }
+.bi-telephone-inbound::before { content: "\f5b8"; }
+.bi-telephone-minus-fill::before { content: "\f5b9"; }
+.bi-telephone-minus::before { content: "\f5ba"; }
+.bi-telephone-outbound-fill::before { content: "\f5bb"; }
+.bi-telephone-outbound::before { content: "\f5bc"; }
+.bi-telephone-plus-fill::before { content: "\f5bd"; }
+.bi-telephone-plus::before { content: "\f5be"; }
+.bi-telephone-x-fill::before { content: "\f5bf"; }
+.bi-telephone-x::before { content: "\f5c0"; }
+.bi-telephone::before { content: "\f5c1"; }
+.bi-terminal-fill::before { content: "\f5c2"; }
+.bi-terminal::before { content: "\f5c3"; }
+.bi-text-center::before { content: "\f5c4"; }
+.bi-text-indent-left::before { content: "\f5c5"; }
+.bi-text-indent-right::before { content: "\f5c6"; }
+.bi-text-left::before { content: "\f5c7"; }
+.bi-text-paragraph::before { content: "\f5c8"; }
+.bi-text-right::before { content: "\f5c9"; }
+.bi-textarea-resize::before { content: "\f5ca"; }
+.bi-textarea-t::before { content: "\f5cb"; }
+.bi-textarea::before { content: "\f5cc"; }
+.bi-thermometer-half::before { content: "\f5cd"; }
+.bi-thermometer-high::before { content: "\f5ce"; }
+.bi-thermometer-low::before { content: "\f5cf"; }
+.bi-thermometer-snow::before { content: "\f5d0"; }
+.bi-thermometer-sun::before { content: "\f5d1"; }
+.bi-thermometer::before { content: "\f5d2"; }
+.bi-three-dots-vertical::before { content: "\f5d3"; }
+.bi-three-dots::before { content: "\f5d4"; }
+.bi-toggle-off::before { content: "\f5d5"; }
+.bi-toggle-on::before { content: "\f5d6"; }
+.bi-toggle2-off::before { content: "\f5d7"; }
+.bi-toggle2-on::before { content: "\f5d8"; }
+.bi-toggles::before { content: "\f5d9"; }
+.bi-toggles2::before { content: "\f5da"; }
+.bi-tools::before { content: "\f5db"; }
+.bi-tornado::before { content: "\f5dc"; }
+.bi-trash-fill::before { content: "\f5dd"; }
+.bi-trash::before { content: "\f5de"; }
+.bi-trash2-fill::before { content: "\f5df"; }
+.bi-trash2::before { content: "\f5e0"; }
+.bi-tree-fill::before { content: "\f5e1"; }
+.bi-tree::before { content: "\f5e2"; }
+.bi-triangle-fill::before { content: "\f5e3"; }
+.bi-triangle-half::before { content: "\f5e4"; }
+.bi-triangle::before { content: "\f5e5"; }
+.bi-trophy-fill::before { content: "\f5e6"; }
+.bi-trophy::before { content: "\f5e7"; }
+.bi-tropical-storm::before { content: "\f5e8"; }
+.bi-truck-flatbed::before { content: "\f5e9"; }
+.bi-truck::before { content: "\f5ea"; }
+.bi-tsunami::before { content: "\f5eb"; }
+.bi-tv-fill::before { content: "\f5ec"; }
+.bi-tv::before { content: "\f5ed"; }
+.bi-twitch::before { content: "\f5ee"; }
+.bi-twitter::before { content: "\f5ef"; }
+.bi-type-bold::before { content: "\f5f0"; }
+.bi-type-h1::before { content: "\f5f1"; }
+.bi-type-h2::before { content: "\f5f2"; }
+.bi-type-h3::before { content: "\f5f3"; }
+.bi-type-italic::before { content: "\f5f4"; }
+.bi-type-strikethrough::before { content: "\f5f5"; }
+.bi-type-underline::before { content: "\f5f6"; }
+.bi-type::before { content: "\f5f7"; }
+.bi-ui-checks-grid::before { content: "\f5f8"; }
+.bi-ui-checks::before { content: "\f5f9"; }
+.bi-ui-radios-grid::before { content: "\f5fa"; }
+.bi-ui-radios::before { content: "\f5fb"; }
+.bi-umbrella-fill::before { content: "\f5fc"; }
+.bi-umbrella::before { content: "\f5fd"; }
+.bi-union::before { content: "\f5fe"; }
+.bi-unlock-fill::before { content: "\f5ff"; }
+.bi-unlock::before { content: "\f600"; }
+.bi-upc-scan::before { content: "\f601"; }
+.bi-upc::before { content: "\f602"; }
+.bi-upload::before { content: "\f603"; }
+.bi-vector-pen::before { content: "\f604"; }
+.bi-view-list::before { content: "\f605"; }
+.bi-view-stacked::before { content: "\f606"; }
+.bi-vinyl-fill::before { content: "\f607"; }
+.bi-vinyl::before { content: "\f608"; }
+.bi-voicemail::before { content: "\f609"; }
+.bi-volume-down-fill::before { content: "\f60a"; }
+.bi-volume-down::before { content: "\f60b"; }
+.bi-volume-mute-fill::before { content: "\f60c"; }
+.bi-volume-mute::before { content: "\f60d"; }
+.bi-volume-off-fill::before { content: "\f60e"; }
+.bi-volume-off::before { content: "\f60f"; }
+.bi-volume-up-fill::before { content: "\f610"; }
+.bi-volume-up::before { content: "\f611"; }
+.bi-vr::before { content: "\f612"; }
+.bi-wallet-fill::before { content: "\f613"; }
+.bi-wallet::before { content: "\f614"; }
+.bi-wallet2::before { content: "\f615"; }
+.bi-watch::before { content: "\f616"; }
+.bi-water::before { content: "\f617"; }
+.bi-whatsapp::before { content: "\f618"; }
+.bi-wifi-1::before { content: "\f619"; }
+.bi-wifi-2::before { content: "\f61a"; }
+.bi-wifi-off::before { content: "\f61b"; }
+.bi-wifi::before { content: "\f61c"; }
+.bi-wind::before { content: "\f61d"; }
+.bi-window-dock::before { content: "\f61e"; }
+.bi-window-sidebar::before { content: "\f61f"; }
+.bi-window::before { content: "\f620"; }
+.bi-wrench::before { content: "\f621"; }
+.bi-x-circle-fill::before { content: "\f622"; }
+.bi-x-circle::before { content: "\f623"; }
+.bi-x-diamond-fill::before { content: "\f624"; }
+.bi-x-diamond::before { content: "\f625"; }
+.bi-x-octagon-fill::before { content: "\f626"; }
+.bi-x-octagon::before { content: "\f627"; }
+.bi-x-square-fill::before { content: "\f628"; }
+.bi-x-square::before { content: "\f629"; }
+.bi-x::before { content: "\f62a"; }
+.bi-youtube::before { content: "\f62b"; }
+.bi-zoom-in::before { content: "\f62c"; }
+.bi-zoom-out::before { content: "\f62d"; }
+.bi-bank::before { content: "\f62e"; }
+.bi-bank2::before { content: "\f62f"; }
+.bi-bell-slash-fill::before { content: "\f630"; }
+.bi-bell-slash::before { content: "\f631"; }
+.bi-cash-coin::before { content: "\f632"; }
+.bi-check-lg::before { content: "\f633"; }
+.bi-coin::before { content: "\f634"; }
+.bi-currency-bitcoin::before { content: "\f635"; }
+.bi-currency-dollar::before { content: "\f636"; }
+.bi-currency-euro::before { content: "\f637"; }
+.bi-currency-exchange::before { content: "\f638"; }
+.bi-currency-pound::before { content: "\f639"; }
+.bi-currency-yen::before { content: "\f63a"; }
+.bi-dash-lg::before { content: "\f63b"; }
+.bi-exclamation-lg::before { content: "\f63c"; }
+.bi-file-earmark-pdf-fill::before { content: "\f63d"; }
+.bi-file-earmark-pdf::before { content: "\f63e"; }
+.bi-file-pdf-fill::before { content: "\f63f"; }
+.bi-file-pdf::before { content: "\f640"; }
+.bi-gender-ambiguous::before { content: "\f641"; }
+.bi-gender-female::before { content: "\f642"; }
+.bi-gender-male::before { content: "\f643"; }
+.bi-gender-trans::before { content: "\f644"; }
+.bi-headset-vr::before { content: "\f645"; }
+.bi-info-lg::before { content: "\f646"; }
+.bi-mastodon::before { content: "\f647"; }
+.bi-messenger::before { content: "\f648"; }
+.bi-piggy-bank-fill::before { content: "\f649"; }
+.bi-piggy-bank::before { content: "\f64a"; }
+.bi-pin-map-fill::before { content: "\f64b"; }
+.bi-pin-map::before { content: "\f64c"; }
+.bi-plus-lg::before { content: "\f64d"; }
+.bi-question-lg::before { content: "\f64e"; }
+.bi-recycle::before { content: "\f64f"; }
+.bi-reddit::before { content: "\f650"; }
+.bi-safe-fill::before { content: "\f651"; }
+.bi-safe2-fill::before { content: "\f652"; }
+.bi-safe2::before { content: "\f653"; }
+.bi-sd-card-fill::before { content: "\f654"; }
+.bi-sd-card::before { content: "\f655"; }
+.bi-skype::before { content: "\f656"; }
+.bi-slash-lg::before { content: "\f657"; }
+.bi-translate::before { content: "\f658"; }
+.bi-x-lg::before { content: "\f659"; }
+.bi-safe::before { content: "\f65a"; }
\ No newline at end of file
diff --git a/theme_levelup/static/src/css/font.css b/theme_levelup/static/src/css/font.css
new file mode 100644
index 0000000000..d1d7e426a7
--- /dev/null
+++ b/theme_levelup/static/src/css/font.css
@@ -0,0 +1,216 @@
+/* devanagari */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 100;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiGyp8kv8JHgFVrLPTucXtAKPY.woff2) format('woff2');
+ unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
+}
+/* latin-ext */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 100;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiGyp8kv8JHgFVrLPTufntAKPY.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 100;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiGyp8kv8JHgFVrLPTucHtA.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* devanagari */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 200;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLFj_Z11lFc-K.woff2) format('woff2');
+ unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
+}
+/* latin-ext */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 200;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLFj_Z1JlFc-K.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 200;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLFj_Z1xlFQ.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* devanagari */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 300;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLDz8Z11lFc-K.woff2) format('woff2');
+ unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
+}
+/* latin-ext */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 300;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLDz8Z1JlFc-K.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 300;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLDz8Z1xlFQ.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* devanagari */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 400;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJbecmNE.woff2) format('woff2');
+ unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
+}
+/* latin-ext */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 400;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJnecmNE.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 400;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJfecg.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* devanagari */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 500;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLGT9Z11lFc-K.woff2) format('woff2');
+ unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
+}
+/* latin-ext */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 500;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLGT9Z1JlFc-K.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 500;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLGT9Z1xlFQ.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* devanagari */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 600;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLEj6Z11lFc-K.woff2) format('woff2');
+ unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
+}
+/* latin-ext */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 600;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLEj6Z1JlFc-K.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 600;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLEj6Z1xlFQ.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* devanagari */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 700;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLCz7Z11lFc-K.woff2) format('woff2');
+ unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
+}
+/* latin-ext */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 700;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLCz7Z1JlFc-K.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 700;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* devanagari */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 800;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLDD4Z11lFc-K.woff2) format('woff2');
+ unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
+}
+/* latin-ext */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 800;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLDD4Z1JlFc-K.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 800;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLDD4Z1xlFQ.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
+/* devanagari */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 900;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLBT5Z11lFc-K.woff2) format('woff2');
+ unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
+}
+/* latin-ext */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 900;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLBT5Z1JlFc-K.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+}
+/* latin */
+@font-face {
+ font-family: 'Poppins';
+ font-style: normal;
+ font-weight: 900;
+ src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLBT5Z1xlFQ.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+}
\ No newline at end of file
diff --git a/theme_levelup/static/src/css/owl.carousel.min.css b/theme_levelup/static/src/css/owl.carousel.min.css
new file mode 100644
index 0000000000..a71df11c01
--- /dev/null
+++ b/theme_levelup/static/src/css/owl.carousel.min.css
@@ -0,0 +1,6 @@
+/**
+ * Owl Carousel v2.3.4
+ * Copyright 2013-2018 David Deutsch
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
+ */
+.owl-carousel,.owl-carousel .owl-item{-webkit-tap-highlight-color:transparent;position:relative}.owl-carousel{display:none;width:100%;z-index:1}.owl-carousel .owl-stage{position:relative;-ms-touch-action:pan-Y;touch-action:manipulation;-moz-backface-visibility:hidden}.owl-carousel .owl-stage:after{content:".";display:block;clear:both;visibility:hidden;line-height:0;height:0}.owl-carousel .owl-stage-outer{position:relative;overflow:hidden;-webkit-transform:translate3d(0,0,0)}.owl-carousel .owl-item,.owl-carousel .owl-wrapper{-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0)}.owl-carousel .owl-item{min-height:1px;float:left;-webkit-backface-visibility:hidden;-webkit-touch-callout:none}.owl-carousel .owl-item img{display:block;width:100%}.owl-carousel .owl-dots.disabled,.owl-carousel .owl-nav.disabled{display:none}.no-js .owl-carousel,.owl-carousel.owl-loaded{display:block}.owl-carousel .owl-dot,.owl-carousel .owl-nav .owl-next,.owl-carousel .owl-nav .owl-prev{cursor:pointer;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.owl-carousel .owl-nav button.owl-next,.owl-carousel .owl-nav button.owl-prev,.owl-carousel button.owl-dot{background:0 0;color:inherit;border:none;padding:0!important;font:inherit}.owl-carousel.owl-loading{opacity:0;display:block}.owl-carousel.owl-hidden{opacity:0}.owl-carousel.owl-refresh .owl-item{visibility:hidden}.owl-carousel.owl-drag .owl-item{-ms-touch-action:pan-y;touch-action:pan-y;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.owl-carousel.owl-grab{cursor:move;cursor:grab}.owl-carousel.owl-rtl{direction:rtl}.owl-carousel.owl-rtl .owl-item{float:right}.owl-carousel .animated{animation-duration:1s;animation-fill-mode:both}.owl-carousel .owl-animated-in{z-index:0}.owl-carousel .owl-animated-out{z-index:1}.owl-carousel .fadeOut{animation-name:fadeOut}@keyframes fadeOut{0%{opacity:1}100%{opacity:0}}.owl-height{transition:height .5s ease-in-out}.owl-carousel .owl-item .owl-lazy{opacity:0;transition:opacity .4s ease}.owl-carousel .owl-item .owl-lazy:not([src]),.owl-carousel .owl-item .owl-lazy[src^=""]{max-height:0}.owl-carousel .owl-item img.owl-lazy{transform-style:preserve-3d}.owl-carousel .owl-video-wrapper{position:relative;height:100%;background:#000}.owl-carousel .owl-video-play-icon{position:absolute;height:80px;width:80px;left:50%;top:50%;margin-left:-40px;margin-top:-40px;background:url(owl.video.play.png) no-repeat;cursor:pointer;z-index:1;-webkit-backface-visibility:hidden;transition:transform .1s ease}.owl-carousel .owl-video-play-icon:hover{-ms-transform:scale(1.3,1.3);transform:scale(1.3,1.3)}.owl-carousel .owl-video-playing .owl-video-play-icon,.owl-carousel .owl-video-playing .owl-video-tn{display:none}.owl-carousel .owl-video-tn{opacity:0;height:100%;background-position:center center;background-repeat:no-repeat;background-size:contain;transition:opacity .4s ease}.owl-carousel .owl-video-frame{position:relative;z-index:1;height:100%;width:100%}
\ No newline at end of file
diff --git a/theme_levelup/static/src/css/owl.theme.default.min.css b/theme_levelup/static/src/css/owl.theme.default.min.css
new file mode 100644
index 0000000000..487088d2e3
--- /dev/null
+++ b/theme_levelup/static/src/css/owl.theme.default.min.css
@@ -0,0 +1,6 @@
+/**
+ * Owl Carousel v2.3.4
+ * Copyright 2013-2018 David Deutsch
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
+ */
+.owl-theme .owl-dots,.owl-theme .owl-nav{text-align:center;-webkit-tap-highlight-color:transparent}.owl-theme .owl-nav{margin-top:10px}.owl-theme .owl-nav [class*=owl-]{color:#FFF;font-size:14px;margin:5px;padding:4px 7px;background:#D6D6D6;display:inline-block;cursor:pointer;border-radius:3px}.owl-theme .owl-nav [class*=owl-]:hover{background:#869791;color:#FFF;text-decoration:none}.owl-theme .owl-nav .disabled{opacity:.5;cursor:default}.owl-theme .owl-nav.disabled+.owl-dots{margin-top:10px}.owl-theme .owl-dots .owl-dot{display:inline-block;zoom:1}.owl-theme .owl-dots .owl-dot span{width:10px;height:10px;margin:5px 7px;background:#D6D6D6;display:block;-webkit-backface-visibility:visible;transition:opacity .2s ease;border-radius:30px}.owl-theme .owl-dots .owl-dot.active span,.owl-theme .owl-dots .owl-dot:hover span{background:#869791}
\ No newline at end of file
diff --git a/theme_levelup/static/src/css/shuffle-styles.css b/theme_levelup/static/src/css/shuffle-styles.css
new file mode 100644
index 0000000000..2f805139ec
--- /dev/null
+++ b/theme_levelup/static/src/css/shuffle-styles.css
@@ -0,0 +1,151 @@
+/*=============================================*\
+ Some styles to show off masonry layout
+\*=============================================*/
+.picture-item {
+ height: 220px;
+ margin-top: 24px;
+ margin-left: 0;
+ /* shuffle items shouldn't have a left margin*/
+}
+
+.picture-item img {
+ display: block;
+ width: 100%;
+}
+
+@supports (object-fit: cover) {
+ .picture-item img {
+ max-width: none;
+ height: 100%;
+ object-fit: cover;
+ }
+}
+
+.picture-item--h2 {
+ height: 464px;
+ /* 2x the height + 1 gutter */
+}
+
+.picture-item__inner {
+ position: relative;
+ height: 100%;
+ overflow: hidden;
+ background: #ECF0F1;
+}
+
+img.picture-item__blur {
+ display: none;
+}
+
+.picture-item__details {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ width: 100%;
+ padding: 1em;
+}
+
+.picture-item__description {
+ width: 100%;
+ padding: 0 2em 1em 1em;
+ margin: 0;
+}
+
+.picture-item__title {
+ flex-shrink: 0;
+ margin-right: 4px;
+}
+
+.picture-item__tags {
+ flex-shrink: 1;
+ text-align: right;
+ margin: 0;
+}
+
+@media screen and (min-width: 768px) {
+ .picture-item--overlay .picture-item__details {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ background-color: rgba(0, 0, 0, 0.6);
+ color: white;
+ overflow: hidden;
+ }
+ .picture-item--overlay .picture-item__description {
+ display: none;
+ }
+ @supports (filter: blur(1px)) and (clip-path: inset(0 0 0 0)) {
+ .picture-item--overlay .picture-item__blur {
+ position: absolute;
+ z-index: 1;
+ top: 0;
+ left: 0;
+ display: block;
+ filter: blur(7px);
+ clip-path: inset(170px 0 0 0);
+ }
+ .picture-item--overlay .picture-item__details {
+ background: none;
+ }
+ .picture-item--overlay .picture-item__tags,
+ .picture-item--overlay .picture-item__title {
+ position: relative;
+ z-index: 2;
+ }
+ }
+}
+
+/*
+ Shuffle needs either relative or absolute positioning on the container
+ It will set it for you, but it'll cause another style recalculation and layout.
+ AKA worse performance - so just set it here
+ */
+.my-shuffle-container {
+ position: relative;
+ overflow: hidden;
+}
+
+.my-sizer-element {
+ position: absolute;
+ opacity: 0;
+ visibility: hidden;
+}
+
+/* Animate in styles */
+.shuffle--animatein {
+ overflow: visible;
+}
+
+.shuffle--animatein .picture-item__inner {
+ opacity: 0;
+ transform: translate(0, 220px);
+}
+
+.shuffle--animatein .picture-item__inner--transition {
+ transition: all .6s ease;
+}
+
+.shuffle--animatein .picture-item.in .picture-item__inner {
+ opacity: 1;
+ transform: translate(0, 0);
+}
+
+@media screen and (max-width: 767px) {
+ .picture-item {
+ height: auto;
+ margin-top: 20px;
+ }
+ .picture-item__details,
+ .picture-item__description {
+ font-size: .875em;
+ padding: .625em;
+ }
+ .picture-item__description {
+ padding-right: .875em;
+ padding-bottom: 1.25em;
+ }
+ .picture-item--h2 {
+ height: auto;
+ }
+}
diff --git a/theme_levelup/static/src/css/style.css b/theme_levelup/static/src/css/style.css
new file mode 100644
index 0000000000..890435d898
--- /dev/null
+++ b/theme_levelup/static/src/css/style.css
@@ -0,0 +1,4415 @@
+:root {
+ --level-brand:#fcb017;
+ --level-color-1: #253237;
+ --level-color-2: #000;
+ --level-color-3: #181818;
+ --section-bg: #f2f2f2;
+ --section-bg2: #FDF4DA5E;
+ --section-bg3: #FEF9ED;
+ --sub-color-1: #dc3545;
+ --sub-color-2: #2250fc;
+ --sub-color-3: #c52132;
+ --button-color: #50449c;
+ --p-color: #484848;
+ --p-color2: #777;
+ --p-color3: #eaeaea;
+ --p-color4:#a2abb7;
+ --banner-title-bg: #f8f9fa;
+ --subhead-color: #000000;
+ --white-color: #ffffff;
+ --level-up-black:#151515;
+ --footer-main: #f3f3f3;
+ --footer-sub: #f8f9fa !important;
+ --border-color2: #eeecec;
+ --border-color: #dad6d6;
+ --body-bg:#FFFCF8;
+}
+
+*:focus {
+ outline: 0 !important;
+}
+
+*:hover {
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+}
+
+*:focus {
+ outline: 0 !important;
+ box-shadow: none !important;
+}
+
+* button:focus {
+ border: none;
+ outline: none;
+ box-shadow: none;
+}
+
+* {
+ list-style-type: none;
+ font-family: "Red Hat Display", sans-serif;
+}
+*:focus, *:active {
+ outline: none !important;
+}
+
+html.sr .load-hidden {
+ visibility: hidden;
+}
+
+*:hover {
+ -webkit-transition: 0.8s !important;
+ transition: 0.8s !important;
+}
+
+*::selection {
+ color: rgb(243, 235, 238);
+ background-color: black;
+}
+
+* a,
+a:visited {
+ color: #990000;
+ text-decoration: none;
+}
+
+.affix {
+ top: 0;
+ width: 100%;
+ z-index: 9999 !important;
+}
+
+html {
+ scroll-behavior: smooth !important;
+}
+
+body {
+ scroll-behavior: smooth !important;
+ background-color: var(--body-bg);
+ position: relative;
+}
+
+.bold_heading {
+ color: var(--level-up-black);
+ font-weight: 700;
+ padding-bottom: 15px;
+ line-height: 120px;
+ font-size: 13.5vh;
+}
+@media screen and (max-width: 992px) {
+ .bold_heading {
+ font-size: 7vh;
+ line-height: normal;
+ }
+}
+@media screen and (max-width: 768px) {
+ .bold_heading {
+ font-size: 4vh;
+ line-height: normal;
+ }
+}
+
+.b_head {
+ color: var(--level-up-black);
+ font-weight: 700;
+ padding-bottom: 15px;
+ line-height: 90px;
+ font-size: 9.5vh;
+}
+@media screen and (max-width: 768px) {
+ .b_head {
+ font-size: 7vh;
+ line-height: 60px;
+ }
+}
+
+.p_text {
+ color: var(--p-color2);
+ font-size: 14px;
+ font-weight: 600;
+ text-transform: capitalize;
+ letter-spacing: 1.4px;
+ padding-top: 25px;
+ line-height: 1.9;
+}
+
+.u_sub_heading {
+ font-size: 32px;
+ color: var(--level-brand);
+ font-weight: 500;
+ padding-bottom: 15px;
+}
+
+/* Responsive adjustments */
+@media (max-width: 767.98px) {
+ .lead_wrapper {
+ margin-bottom: 30px;
+ }
+
+ .members_img {
+ margin-bottom: 20px;
+ }
+
+ .custom_margin_top {
+ margin-top: 0 !important;
+ }
+
+ .banner_content h1 {
+ font-size: 2rem;
+ }
+
+ .bold_heading {
+ font-size: 1.8rem;
+ }
+
+ .join h4 {
+ font-size: 1.5rem;
+ }
+
+ .r_img img {
+ max-width: 60px;
+ }
+}
+
+/* Ensure proper image scaling */
+.img-fluid {
+ max-width: 100%;
+ height: auto;
+}
+
+/* Adjust team member info display */
+.members_info {
+ text-align: center;
+}
+
+.u_sub_heading_dark {
+ font-size: 32px;
+ color: var(--level-up-black);
+ font-weight: 500;
+}
+
+.main_heading {
+ text-align: center;
+}
+.main_heading h3 {
+ color: var(--level-color-3);
+ font-size: 48px;
+ font-weight: 700;
+ text-transform: capitalize;
+ line-height: 1.3;
+}
+@media screen and (max-width: 576px) {
+ .main_heading h3 {
+ font-size: 25px;
+ }
+}
+.main_heading p {
+ color: var(--level-brand);
+ font-size: 14px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 1.4px;
+}
+
+.heading_c {
+ color: var(--eco-color-1);
+ font-size: 24px;
+ font-weight: 700;
+ text-transform: capitalize;
+}
+
+.p_top {
+ padding-top: 80px;
+}
+
+.p_bottom {
+ padding-bottom: 80px;
+}
+
+.m_top {
+ margin-top: 40px;
+}
+
+.m_bottom {
+ margin-bottom: 40px;
+}
+
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+/* Document
+ ========================================================================== */
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+html {
+ line-height: 1.15; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/* Sections
+ ========================================================================== */
+/**
+ * Remove the margin in all browsers.
+ */
+body {
+ margin: 0;
+}
+
+/**
+ * Render the `main` element consistently in IE.
+ */
+main {
+ display: block;
+}
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/* Grouping content
+ ========================================================================== */
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+hr {
+ box-sizing: content-box; /* 1 */
+ height: 0; /* 1 */
+ overflow: visible; /* 2 */
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+pre {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/* Text-level semantics
+ ========================================================================== */
+/**
+ * Remove the gray background on active links in IE 10.
+ */
+a {
+ background-color: transparent;
+}
+
+/**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+abbr[title] {
+ border-bottom: none; /* 1 */
+ text-decoration: underline; /* 2 */
+ text-decoration: underline dotted; /* 2 */
+}
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+b,
+strong {
+ font-weight: bolder;
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+code,
+kbd,
+samp {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/**
+ * Add the correct font size in all browsers.
+ */
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/* Embedded content
+ ========================================================================== */
+/**
+ * Remove the border on images inside links in IE 10.
+ */
+img {
+ border-style: none;
+}
+
+/* Forms
+ ========================================================================== */
+/**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+}
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+button,
+input { /* 1 */
+ overflow: visible;
+}
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+button,
+select { /* 1 */
+ text-transform: none;
+}
+
+/**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+button,
+[type=button],
+[type=reset],
+[type=submit] {
+ -webkit-appearance: button;
+}
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+button::-moz-focus-inner,
+[type=button]::-moz-focus-inner,
+[type=reset]::-moz-focus-inner,
+[type=submit]::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+}
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+button:-moz-focusring,
+[type=button]:-moz-focusring,
+[type=reset]:-moz-focusring,
+[type=submit]:-moz-focusring {
+ outline: 1px dotted ButtonText;
+}
+
+/**
+ * Correct the padding in Firefox.
+ */
+fieldset {
+ padding: 0.35em 0.75em 0.625em;
+}
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ * `fieldset` elements in all browsers.
+ */
+legend {
+ box-sizing: border-box; /* 1 */
+ color: inherit; /* 2 */
+ display: table; /* 1 */
+ max-width: 100%; /* 1 */
+ padding: 0; /* 3 */
+ white-space: normal; /* 1 */
+}
+
+/**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+progress {
+ vertical-align: baseline;
+}
+
+/**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+textarea {
+ overflow: auto;
+}
+
+/**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+[type=checkbox],
+[type=radio] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+[type=number]::-webkit-inner-spin-button,
+[type=number]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+[type=search] {
+ -webkit-appearance: textfield; /* 1 */
+ outline-offset: -2px; /* 2 */
+}
+
+/**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+[type=search]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+::-webkit-file-upload-button {
+ -webkit-appearance: button; /* 1 */
+ font: inherit; /* 2 */
+}
+
+/* Interactive
+ ========================================================================== */
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+details {
+ display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+summary {
+ display: list-item;
+}
+
+/* Misc
+ ========================================================================== */
+/**
+ * Add the correct display in IE 10+.
+ */
+template {
+ display: none;
+}
+
+/**
+ * Add the correct display in IE 10.
+ */
+[hidden] {
+ display: none;
+}
+
+.btn {
+ border: none !important;
+ outline: 0 !important;
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+}
+.btn-primary {
+ border-radius: 0px;
+ border: 2px solid var(--level-up-black) !important;
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.6px;
+ text-decoration: none;
+ padding:5px 21px !important;
+ position: relative;
+ background-color: var(--level-up-black) !important;
+ color: var(--white-color) !important;
+ transition: all 0.3s;
+ line-height: 14px;
+}
+.btn-primary:hover {
+ background-color: var(--white-color) !important;
+ color: var(--level-color-1) !important;
+}
+.btn-light:hover {
+ background-color: cyan !important;
+ color: var(--level-color-1) !important;
+}
+.nav-link:hover{
+ background-color: cyan !important;
+ color: var(--level-color-1) !important;
+}
+.btn-secondary {
+ border-radius: 0;
+ border: 0px solid var(--white-color) !important;
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.6px;
+ text-decoration: none;
+ padding: 15px 25px;
+ position: relative;
+ text-transform: uppercase;
+ background-color: transparent;
+ color: var(--white-color) !important;
+ transition: all 0.3s;
+ line-height: 14px;
+}
+.btn-secondary:hover {
+ background-color: var(--white-color) !important;
+ color: var(--level-color-1) !important;
+}
+.btn-dark {
+ border-radius: 0;
+ border: 2px solid var(--level-up-black) !important;
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.6px;
+ text-decoration: none;
+ padding: 15px 25px;
+ position: relative;
+ text-transform: uppercase;
+ background-color: transparent;
+ color:#fff !important;
+ transition: all 0.3s;
+ line-height: 14px;
+}
+.btn-dark:hover {
+ background-color: var(--white-color) !important;
+ color: var(--level-color-1) !important;
+ border: 2px solid var(--level-up-black) !important;
+}
+.btn-white {
+ border-radius: 0;
+ border: 2px solid var(--white-color) !important;
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.6px;
+ text-decoration: none;
+ padding: 15px 25px;
+ position: relative;
+ text-transform: uppercase;
+ background-color: transparent;
+ color: var(--white-color) !important;
+ transition: all 0.3s;
+ line-height: 14px;
+}
+.btn-white:hover {
+ background-color: var(--white-color) !important;
+ color: var(--level-color-1) !important;
+ border: 2px solid var(--level-up-black) !important;
+}
+
+.banner {
+ background-image: url("../images/banner/a.jpg") !important;
+ background-position: inherit;
+ background-size: 64%;
+ background-repeat: no-repeat;
+ background-position-x: 120% !important;
+ background-position-y: 76%;
+ position: relative;
+}
+@media screen and (max-width: 992px) {
+ .banner {
+ background-size: cover;
+ background-position: center !important;
+ }
+ .banner::after {
+ position: absolute;
+ content: " ";
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ background-color: rgba(255, 232, 193, 0.226);
+ }
+}
+@media screen and (max-width: 768px) {
+ .banner .wrapper {
+ padding: 50px 0;
+ }
+}
+.banner .wrapper .banner_content {
+ width: 100%;
+ height: 100vh;
+ display: flex;
+ justify-content: left;
+ align-items: center;
+ z-index: 1;
+ text-align: left;
+}
+.banner .wrapper .banner_content .c_wrapper {
+ position: absolute;
+ z-index: 999;
+}
+@media screen and (max-width: 992px) {
+ .banner .wrapper .banner_left .bold_heading {
+ font-weight: 700;
+ font-size: 8vh;
+ line-height: 60px;
+ }
+ .banner .wrapper .banner_left p {
+ color: var(--white-color);
+ }
+}
+@media screen and (max-width: 768px) {
+ .banner .wrapper .banner_left {
+ font-size: 5vh;
+ }
+}
+
+.banner_about {
+ position: relative;
+ height: 500px;
+ background-size: 140vh;
+ background-repeat: no-repeat;
+ background-position: right;
+}
+@media screen and (max-width: 992px) {
+ .banner_about {
+ height: 50vh;
+ }
+}
+.banner_about .banner_content {
+ width: 100% !important;
+ height: 75vh;
+ display: flex;
+ font-weight: 700;
+ font-size: 96px;
+ justify-content: start;
+ align-items: center;
+}
+
+
+@media screen and (max-width: 576px) {
+ .banner_about .banner_content {
+ font-size: 60px;
+ justify-content: center;
+ }
+}
+.banner_about .banner_content .c_wrapper {
+ position: absolute;
+ top: 0px;
+ left: -100px;
+ bottom: 0;
+ z-index: -1;
+ font-size: 20rem;
+ font-weight: 900;
+ color: rgba(198, 198, 198, 0.2705882353);
+}
+@media screen and (max-width: 992px) {
+ .banner_about .banner_content .c_wrapper {
+ font-size: 10rem;
+ top: 100px;
+ }
+}
+@media screen and (max-width: 650px) {
+ .banner_about .banner_content .c_wrapper {
+ display: none;
+ }
+}
+
+.banner_service {
+ position: relative;
+ height: 500px;
+ background-size: 140vh;
+ background-repeat: no-repeat;
+ background-position: right;
+}
+@media screen and (max-width: 768px) {
+ .banner_service {
+ height: 50vh;
+ }
+}
+.banner_service .banner_content {
+ width: 100% !important;
+ height: 75vh;
+ display: flex;
+ align-items: center;
+}
+@media screen and (max-width: 768px) {
+ .banner_service .banner_content {
+ justify-content: center;
+ text-align: center;
+ height: 50vh;
+ }
+}
+.banner_service .banner_content .text {
+ font-weight: 700;
+ font-size: 8rem;
+ background: -webkit-linear-gradient(285deg, #ffaa00 26%, white 90%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+}
+@media screen and (max-width: 992px) {
+ .banner_service .banner_content .text {
+ font-size: 6rem;
+ }
+}
+@media screen and (max-width: 576px) {
+ .banner_service .banner_content .text {
+ font-size: 3.5rem;
+ }
+}
+
+.banner_portfolio {
+ background-image: url("../images/banner/banner_portfolio.jpg") !important;
+}
+
+.banner_team {
+ background-image: url"../images/Main_bg/circle_trans.png") !important;
+}
+
+/* Default Odoo Cart Summary Styling */
+
+#o_cart_summary {
+ /* Remove any custom positioning - let it flow naturally */
+ position: static;
+ margin: 0;
+ padding: 0;
+}
+
+.o_total_card {
+ /* Reset to default Bootstrap/Odoo card styling */
+ background-color: #fff;
+ border: 1px solid rgba(0, 0, 0, 0.125);
+ border-radius: 0.375rem;
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
+ margin-bottom: 1.5rem;
+
+ /* Remove any custom positioning */
+ position: static;
+ width: auto;
+ max-width: none;
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 0;
+}
+
+.o_total_card .card-body {
+ padding: 1.25rem;
+}
+
+.o_total_card .card-header {
+ padding: 0.75rem 1.25rem;
+ margin-bottom: 0;
+ background-color: rgba(0, 0, 0, 0.03);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.125);
+}
+
+/* Reset any Bootstrap overrides */
+.o_total_card h6,
+.o_total_card .h6 {
+ margin-bottom: 0.5rem;
+ font-weight: 500;
+ line-height: 1.2;
+}
+
+/* Ensure proper spacing for cart totals */
+.o_total_card .row {
+ margin-right: -0.75rem;
+ margin-left: -0.75rem;
+}
+
+.o_total_card .col,
+.o_total_card .col-sm {
+ padding-right: 0.75rem;
+ padding-left: 0.75rem;
+}
+
+/* Remove any conflicting custom styles */
+#o_cart_summary * {
+ position: static !important;
+ transform: none !important;
+ top: auto !important;
+ left: auto !important;
+ right: auto !important;
+ bottom: auto !important;
+}
+
+/* Restore default text alignment */
+#o_cart_summary {
+ text-align: left;
+}
+
+/* Remove any flexbox or grid overrides */
+#o_cart_summary {
+ display: block;
+}
+
+.o_total_card {
+ display: block;
+ position: unset;
+}
+@media screen and (max-width: 992px) {
+div[name="website_sale_cart_line_quantity"]{
+ width: 120px;
+ flex-direction: row;
+}
+}
+
+.combo-item-grid .product-card .card-header.p-0 {
+ width: 200px;
+ justify-content: center;
+ display: flex;
+}
+
+.combo-item-grid .w-100 {
+ height: 200px;
+ width: 100px !important;
+}
+
+.combo-item-grid .product-card {
+ width: 200px !important;
+}
+
+.footer {
+ background-color: var(--level-up-black);
+ padding: 40px 0px 50px 0px;
+}
+
+@media screen and (max-width: 992px) {
+ .footer {
+ padding: 100px 15px 50px 15px;
+ }
+}
+.footer .wrapper .top {
+ margin-bottom: 50px;
+}
+.footer .wrapper .footer_c .footer_brand {
+ font-size: 24px;
+ color: var(--white-color);
+ font-weight: 700;
+}
+@media screen and (max-width: 1200px) {
+ .footer .wrapper .footer_c .footer_brand {
+ margin-right: auto;
+ padding-left: 15px;
+ }
+}
+@media screen and (max-width: 576px) {
+ .footer .wrapper .footer_c .footer_brand {
+ margin-right: auto;
+ padding-left: 0px;
+ }
+}
+.footer .wrapper .footer_c .footer_brand span {
+ max-width: 90px;
+ display: inline-block;
+}
+
+.footer .wrapper .footer_c .footer_brand span img {
+ width: 100%;
+ margin-top: -16px;
+}
+.footer .wrapper .footer_c .footer_heading {
+ color: var(--white-color);
+ font-weight: 600;
+ font-size: 24px;
+ margin-bottom: 20px;
+}
+.footer .wrapper .footer_c p {
+ color: var(--p-color4) !important;
+ font-size: 16px;
+ line-height: 1.9;
+ margin-right: 50px;
+ padding-top: 20px;
+ text-transform: capitalize;
+}
+.footer .wrapper .footer_c ul {
+ padding-left: 0;
+ padding-top: 30 px;
+}
+.footer .wrapper .footer_c ul li {
+ padding-bottom: 15px;
+}
+.footer .wrapper .footer_c ul li a {
+ color: var(--p-color4);
+ font-size: 16px;
+ line-height: 1.9;
+ text-transform: capitalize;
+}
+.footer .wrapper .footer_c ul li a:hover {
+ color: var(--white-color) !important;
+ text-decoration: none;
+}
+.footer .wrapper .footer_c .input-group .form-control {
+ box-shadow: none !important;
+ outline: none !important;
+ font-size: 12px !important;
+ padding: 10px 10px;
+ color: var(--p-color3);
+ border: none !important;
+}
+.footer .wrapper .footer_c .input-group .input-group-append .btn-outline-secondary {
+ padding: 10px 20px;
+ background-color: var(--level-brand) !important;
+}
+.footer .wrapper .footer_c .input-group .input-group-append .btn-outline-secondary i {
+ color: var(--white-color);
+}
+
+.header_modern_light {
+ margin-bottom: 91px;
+}
+.header_modern_light .navigation {
+ top:0px !important;
+ transition: background-color 0.4s ease-out;
+ background-color: var(--white-color);
+}
+.header_modern_light .navigation .navbar {
+ margin: 10px 0px 10px 0px;
+ padding-left: 0;
+ padding-right: 0;
+}
+.header_modern_light .navigation .navbar .navbar-brand {
+ font-size: 30px;
+ color: var(--level-color-1);
+ font-weight: 700;
+}
+@media screen and (max-width: 1200px) {
+ .header_modern_light .navigation .navbar .navbar-brand {
+ margin-right: auto;
+ padding-left: 15px;
+ }
+}
+.header_modern_light .navigation .navbar .navbar-brand span {
+ max-width: 46px;
+ display: inline-block;
+}
+.header_modern_light .navigation .navbar .navbar-brand span img {
+ width: 100px;
+ margin-top: -16px;
+}
+@media screen and (max-width: 1200px) {
+ .header_modern_light .navigation .navbar .navbar-collapse {
+ background-color: var(--white-color);
+ padding: 15px 15px;
+ }
+}
+.header_modern_light .navigation .navbar .navbar-nav {
+ margin: auto;
+}
+@media screen and (max-width: 990px) {
+ .header_modern_light .navigation .navbar .navbar-nav .nav-item {
+ padding: 5px 0;
+ }
+}
+.header_modern_light .navigation .navbar .navbar-nav .nav-item .nav-link {
+ color: var(--level-color-1);
+ font-size: 14px;
+ margin: 0px 15px;
+ font-weight: 500;
+}
+.header_modern_light .navigation .navbar .navbar-nav .nav-item .nav-link.active {
+ color: var(--level-up-black) !important;
+ font-weight: 700;
+}
+.header_modern_light .navigation .navbar .navbar-nav .nav-item .nav-link:hover {
+ color: var(--p-color3);
+}
+@media screen and (max-width: 1200px) {
+ .header_modern_light .navigation .navbar .navbar-nav .nav-item .nav-link {
+ color: var(--p-color2);
+ }
+ .header_modern_light .navigation .navbar .navbar-nav .nav-item .nav-link:hover {
+ color: var(--p-color1);
+ }
+}
+.header_modern_light .navigation .navbar form {
+ margin-left: 15px;
+}
+.header_modern_light .navigation .navbar form span {
+ padding-right: 15px;
+}
+.header_modern_light .navigation .navbar form span a {
+ color: var(--white-color);
+ margin-right: 15px;
+}
+.bg_white {
+ background-color: var(--white-color);
+ transition: background-color 0.4s ease-out;
+}
+
+.fadeInDown {
+ -webkit-animation-name: fadeInDown;
+ animation-name: fadeInDown;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+.text_color {
+ color: var(--level-color-1) !important;
+}
+
+@-webkit-keyframes fadeInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+@keyframes fadeInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+.fadeInup {
+ -webkit-animation-name: fadeInup;
+ animation-name: fadeInup;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ animation-direction: reverse;
+}
+
+@-webkit-keyframes fadeInup {
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+ 0% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+@keyframes fadeInup {
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+ 0% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+.b_shadow {
+ box-shadow: 0px 3px 6px 1px rgba(200, 187, 201, 0.48);
+}
+
+/* top line needs a little padding */
+.navbar-toggler span:nth-child(1) {
+ margin-top: 0.3em;
+}
+
+/**
+ * Animate collapse into X.
+ */
+/* top line rotates 45 degrees clockwise and moves up and in a bit to close the center of the X in the center of the button */
+.navbar-toggler:not(.collapsed) span:nth-child(1) {
+ transform: translate(15%, -33%) rotate(45deg);
+}
+
+/* center line goes transparent */
+.navbar-toggler:not(.collapsed) span:nth-child(2) {
+ opacity: 0;
+}
+
+/* bottom line rotates 45 degrees counter clockwise, in, and down a bit to close the center of the X in the center of the button */
+.navbar-toggler:not(.collapsed) span:nth-child(3) {
+ transform: translate(15%, 33%) rotate(-45deg);
+}
+
+/**
+ * Animate collapse open into hamburger menu
+ */
+/* top line moves back to initial position and rotates back to 0 degrees */
+.navbar-toggler span:nth-child(1) {
+ transform: translate(0%, 0%) rotate(0deg);
+}
+
+.expert-img {
+ width: 70px;
+ height: 70px;
+ border-radius: 50%;
+ object-fit: cover;
+ border: 2px solid #fff;
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
+ }
+
+ /* Team Members Grid Styling */
+ .member-card {
+ position: relative;
+ overflow: hidden;
+ border-radius: 8px;
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1);
+ transition: all 0.3s ease;
+ }
+
+ .member-card:hover {
+ transform: translateY(-5px);
+ }
+
+ .member-img-wrapper img {
+ width: 100%;
+ height: auto;
+ display: block;
+ }
+
+ .member-info {
+ padding: 15px;
+ background: #fff;
+ text-align: center;
+ }
+
+ .member-info h6 {
+ margin-bottom: 5px;
+ font-weight: 600;
+ }
+
+ .member-info p {
+ margin-bottom: 0;
+ color: #666;
+ font-size: 14px;
+ }
+
+ .trust {
+ font-weight: 600;
+ color: #333;
+ margin-top: 20px !important;
+ text-align: center;
+ }
+
+ @media (max-width: 767px) {
+ .expert-img {
+ width: 50px;
+ height: 50px;
+ }
+
+ .member-card {
+ margin-bottom: 15px;
+ }
+ }
+/* middle line goes back to regular color and opacity */
+.navbar-toggler span:nth-child(2) {
+ opacity: 1;
+}
+
+/* bottom line goes back to initial position and rotates back to 0 degrees */
+.navbar-toggler span:nth-child(3) {
+ transform: translate(0%, 0%) rotate(0deg);
+}
+
+.navbar-toggler .menu_icon {
+ display: block;
+ background-color: var(--level-up-black);
+ height: 3px;
+ width: 25px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+ position: relative;
+ border-radius: 2px;
+ left: 0;
+ opacity: 1;
+ transition: all 0.35s ease-out;
+ transform-origin: center left;
+}
+
+@media screen and (max-width: 1200px) {
+ .navbar-toggler {
+ margin-right: 25px;
+ }
+}
+
+.menu_color {
+ background-color: var(--level-color-1) !important;
+}
+
+.index_about {
+ margin-bottom: 40px;
+}
+.index_about .ss_wrapper .about_right .desc_img {
+ margin-top: 50px;
+ max-width: 100%;
+}
+@media screen and (max-width: 768px) {
+ .index_about .ss_wrapper .about_right .desc_img {
+ max-width: 100%;
+ }
+}
+.index_about .ss_wrapper .about_right .desc_img img {
+ width: 100%;
+}
+.index_about .ss_wrapper .barnding .brand_flex {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+.index_about .ss_wrapper .barnding .brand_img {
+ max-width: 100px;
+ margin: auto;
+ cursor: pointer;
+ margin-bottom: 15px;
+}
+.index_about .ss_wrapper .barnding .brand_img img {
+ width: 100%;
+}
+.index_about .ss_wrapper h5 {
+ padding-top: 20px;
+}
+.index_about .ss_wrapper .about_etc .wrapper .card {
+ border: none;
+}
+.index_about .ss_wrapper .about_etc .wrapper .card .card_img {
+ max-width: 100%;
+}
+.index_about .ss_wrapper .about_etc .wrapper .card .card_img img {
+ width: 100%;
+ border-radius: 5px;
+}
+.index_about .ss_wrapper .about_etc .wrapper .card .caption {
+ padding-top: 20px;
+ font-size: 26px;
+ color: var(--p-color2);
+}
+@media screen and (max-width: 768px) {
+ .index_about .ss_wrapper .about_etc .wrapper .card .caption {
+ font-size: 18px;
+ }
+}
+.index_about .ss_wrapper .about_etc .wrapper .card .details {
+ padding-top: 20px;
+ font-size: 26px;
+ color: var(--level-up-black);
+ font-weight: 500;
+}
+@media screen and (max-width: 768px) {
+ .index_about .ss_wrapper .about_etc .wrapper .card .details {
+ font-size: 18px;
+ }
+}
+
+.custom_margin {
+ margin-top: 140px;
+}
+@media screen and (max-width: 768px) {
+ .custom_margin {
+ margin-top: 50px;
+ }
+}
+
+.custom_margin_m {
+ margin-top: -115px;
+}
+@media screen and (max-width: 768px) {
+ .custom_margin_m {
+ margin-top: 0px;
+ }
+}
+
+.gallery .wrapper .bg_heading {
+ position: relative;
+ background-image: url("../images/Main_bg/circles.png") !important;
+ height: 500px;
+ background-size: 140vh;
+ background-repeat: no-repeat;
+ background-position: center;
+}
+@media screen and (max-width: 992px) {
+ .gallery .wrapper .bg_heading {
+ display: flex;
+ align-items: center;
+ height: 250px;
+ }
+}
+.gallery .wrapper .bg_heading .gallery_head {
+ font-size: 13.5vh;
+ background: -webkit-radial-gradient(#a0a0a0, #262626);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ font-weight: 900;
+ width: 70%;
+ line-height: 115px;
+ height: 75%;
+}
+@media screen and (max-width: 992px) {
+ .gallery .wrapper .bg_heading .gallery_head {
+ width: 100%;
+ }
+}
+.o_cart_product .d-block{
+width:300px !important;
+@media screen and (max-width: 1200px) {
+width:100px !important;
+}
+}
+@media screen and (max-width: 768px) {
+ .gallery .wrapper .bg_heading .gallery_head {
+ font-size: 8vh;
+ margin-top: 0;
+ line-height: normal;
+ margin-bottom: 0;
+ height: fit-content;
+ }
+}
+.gallery .wrapper .img_group {
+ margin-top: 20px;
+}
+.gallery .wrapper .img_group .card {
+ border: none;
+}
+.gallery .wrapper .img_group .card .card_img {
+ max-width: 100%;
+}
+.gallery .wrapper .img_group .card .card_img img {
+ width: 100%;
+ border-radius: 5px;
+}
+.gallery .wrapper .img_group .bottom_link {
+ padding-top: 50px;
+}
+.gallery .wrapper .img_group .bottom_link p {
+ color: var(--level-up-black);
+ font-size: 24px;
+ font-weight: 600;
+}
+.gallery .wrapper .img_group .bottom_link .left_link {
+ text-align: end;
+}
+.gallery .wrapper .img_group .bottom_link .left_link a {
+ color: var(--level-brand);
+ font-size: 24px;
+ font-weight: 600;
+ border: 1px solid var(--level-brand);
+ border-color: transparent;
+ border-bottom-color: var(--level-brand) !important;
+ padding-bottom: 10px;
+ border-width: 2px;
+}
+
+.featured {
+ background-color: var(--section-bg);
+ padding-top: 90px;
+ padding-bottom: 70px;
+ margin-bottom: 70px;
+}
+@media screen and (max-width: 992px) {
+ .featured {
+ padding-top: 50px;
+ padding-bottom: 40px;
+ }
+}
+.featured .wrapper {
+ margin-top: 40px;
+}
+.featured .wrapper .featured_content {
+ padding-top: 70px;
+}
+.featured .wrapper .featured_content .card-deck {
+ padding-bottom: 20px;
+ margin-bottom: 20px;
+}
+.featured .wrapper .featured_content .card-deck .card {
+ border: none;
+ position: relative;
+}
+@media screen and (max-width: 992px) {
+ .featured .wrapper .featured_content .card-deck .card {
+ margin-bottom: 40px;
+ }
+}
+.featured .wrapper .featured_content .card-deck .card_image {
+ position: relative;
+ display: block;
+}
+.featured .wrapper .featured_content .card-deck .card_image::after {
+ content: " ";
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ width: 100%;
+ background-color: rgba(0, 0, 0, 0.493);
+ transition: all 1s ease;
+ opacity: 0;
+ z-index: 999;
+}
+.featured .wrapper .featured_content .card-deck .card_image:hover::after {
+ opacity: 1 !important;
+}
+.featured .wrapper .featured_content .card-deck .card_image .card-img-top {
+ border-radius: 0 !important;
+}
+.featured .wrapper .featured_content .card-deck .card-body {
+ -webkit-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ -moz-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ text-align: center;
+}
+.featured .wrapper .featured_content .card-deck .card-body .card-title {
+ font-size: 16px;
+ font-weight: 500;
+ margin-top: 15px;
+}
+.featured .wrapper .featured_content .card-deck .card-body .card-text {
+ font-size: 14px;
+ color: var(--p-color2);
+ margin-bottom: 15px;
+}
+
+.awards .wrapper .t_c {
+ margin-top: 100px;
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .t_c {
+ margin-top: 50px;
+ }
+}
+.awards .wrapper h5 {
+ padding-top: 20px;
+}
+.awards .wrapper .bg_round {
+ position: relative;
+ background-image: url("../images/Main_bg/circle_trans.png");
+ background-repeat: no-repeat;
+ background-position: center;
+ height: 270px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-size: contain;
+}
+@media screen and (max-width: 992px) {
+ .awards .wrapper .bg_round {
+ justify-content: flex-start;
+ }
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .bg_round {
+ height: 150px;
+ }
+}
+.awards .wrapper .area {
+ padding-top: 40px;
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .left_link {
+ padding-top: 50px !important;
+ }
+}
+@media screen and (max-width: 576px) {
+ .awards .wrapper .left_link {
+ padding-top: 20px !important;
+ }
+}
+.awards .wrapper .left_link a {
+ color: var(--level-brand);
+ font-size: 24px;
+ font-weight: 600;
+ border: 1px solid var(--level-brand);
+ border-color: transparent;
+ border-bottom-color: var(--level-brand) !important;
+ padding-bottom: 10px;
+ border-width: 2px;
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .img_flex {
+ display: flex;
+ padding-bottom: 40px;
+ }
+ .awards .wrapper .img_flex img {
+ margin-top: 0 !important;
+ }
+}
+.awards .wrapper .accordion {
+ padding-top: 50px;
+}
+.awards .wrapper .accordion .accordion-item {
+ border: 1px solid transparent;
+ border-bottom-color: var(--border-color);
+ margin-bottom: 30px;
+}
+.awards .wrapper .accordion .accordion-item .accordion-header {
+ margin-bottom: 20px;
+}
+.awards .wrapper .accordion .accordion-item .accordion-header .accordion-button {
+ background-color: transparent;
+ border: transparent;
+ font-size: 32px;
+ color: var(--level-color-3);
+ font-weight: 700;
+ letter-spacing: 0.03em;
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ text-align: left;
+}
+.awards .wrapper .accordion .accordion-item .accordion-body {
+ padding-top: 15px;
+ padding-bottom: 30px;
+}
+.awards .wrapper .accordion .accordion-item .accordion-body ul li {
+ font-size: 32px;
+ color: var(--level-color-3);
+ font-weight: 400;
+ margin-bottom: 15px;
+ list-style: disc;
+ letter-spacing: 0.03em;
+}
+.awards .wrapper .accordion .accordion-item .accordion-body p {
+ color: var(--p-color2);
+ font-weight: 400;
+ font-size: 24px;
+ line-height: 50px;
+ letter-spacing: 0.03em;
+}
+.awards .wrapper .accordion .accordion-item .accordion-body .left_link a {
+ color: var(--level-brand);
+ font-size: 18px;
+ font-weight: 600;
+ border: 1px solid var(--level-brand);
+ border-color: transparent;
+ border-bottom-color: var(--level-brand) !important;
+ padding-bottom: 10px;
+ border-width: 2px;
+}
+.awards .wrapper .accordion-icon {
+ float: right;
+ font-weight: bold;
+ font-size:20px;
+}
+
+.accordion-button::after{
+
+ display:none !important;
+
+}
+
+.awards .wrapper .accordion-button[aria-expanded=true] .accordion-icon::before {
+ content: "-";
+}
+.awards .wrapper .accordion-button[aria-expanded=false] .accordion-icon::before {
+ content: "+";
+}
+.awards .wrapper .client_logo {
+ padding-top: 50px;
+}
+.awards .wrapper .client_logo .img_wrapper {
+ width: 150px;
+ height: 150px;
+ overflow: hidden;
+ display: grid;
+ place-items: center;
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .client_logo .img_wrapper {
+ max-width: 150px;
+ }
+}
+.awards .wrapper .client_logo .img_wrapper img {
+ width: 100%;
+ height: auto;
+ display: block;
+}
+.awards .wrapper .t_slider {
+ padding-top: 50px;
+}
+.awards .wrapper .t_slider .item.active {
+ display: flex;
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .t_slider .item.active {
+ flex-direction: column;
+ }
+}
+.awards .wrapper .t_slider .item .img_wrapper {
+ max-width: 200px;
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .t_slider .item .img_wrapper {
+ margin: auto;
+ padding-bottom: 20px;
+ }
+}
+.awards .wrapper .t_slider .item .img_wrapper img {
+ width: 100%;
+ border-radius: 50%;
+}
+.awards .wrapper .t_slider .item .p_info {
+ padding-left: 50px;
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .t_slider .item .p_info {
+ text-align: center;
+ padding-left: 0px;
+ }
+}
+.awards .wrapper .t_slider .item .p_info .comment {
+ color: var(--level-up-black);
+ font-size: 24px;
+ line-height: 50px;
+ letter-spacing: 3%;
+ font-weight: 600;
+}
+.awards .wrapper .t_slider .item .p_info .detail {
+ padding-top: 15px;
+ color: var(--p-color2);
+}
+.awards .wrapper .t_slider .item .p_info .detail h6 {
+ font-size: 18px;
+ letter-spacing: 3%;
+ font-weight: 600;
+}
+.awards .wrapper .t_slider .custom-nav {
+ width: 50%;
+ margin: auto;
+ padding-left: 22px;
+ padding-top: 4px;
+ display: grid;
+ grid-auto-flow: column;
+ justify-content: start;
+ grid-gap: 15px;
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .t_slider .custom-nav {
+ justify-content: center;
+ }
+}
+@media screen and (max-width: 768px) {
+ .o_cart_product d-flex {
+ position: absolute;
+ margin-left: 200px;
+ }
+.oe_website_sale .table-comparator .img{
+ width: 80px;
+}
+.oe_website_sale .table-comparator .o_add_cart_form_compare .btn{
+ width: 10px;
+}
+ }
+ @media screen and (max-width: 991px) {
+ .oe_website_sale .table-comparator .img{
+ width: 80px;
+}
+}
+
+.awards .wrapper .t_slider .custom-nav .prev,
+.awards .wrapper .t_slider .custom-nav .next {
+ height: 30px;
+ width: 30px;
+ background-color: var(--level-up-black);
+ border-radius: 50%;
+ display: grid;
+ justify-content: center;
+ align-items: center;
+}
+.awards .wrapper .t_slider .custom-nav .prev svg,
+.awards .wrapper .t_slider .custom-nav .next svg {
+ width: 15px;
+}
+.awards .wrapper .blog_slider {
+ padding-top: 70px;
+}
+.awards .wrapper .blog_slider .item.active {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-gap: 0;
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .blog_slider .item {
+ grid-template-columns: 1fr 2fr;
+ }
+}
+.awards .wrapper .blog_slider .item .img_wrapper {
+ height: 100%;
+ background-image: url("../images/testimoinial/fds.png");
+ background-size: cover;
+ background-position: center;
+}
+
+.awards .wrapper .blog_slider .item .p_info {
+ height: 100%;
+ padding: 40px 50px 20px 30px;
+ background-color: var(--level-up-black);
+ color: var(--white-color);
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .blog_slider .item .p_info {
+ padding: 20px 20px 40px 20px;
+ }
+}
+.awards .wrapper .blog_slider .item .p_info .date {
+ padding-top: 15px;
+}
+.awards .wrapper .blog_slider .item .p_info .date h6 {
+ font-size: 24px;
+ letter-spacing: 3%;
+ font-weight: 600;
+}
+.awards .wrapper .blog_slider .item .p_info .date span {
+ font-size: 16px;
+ font-weight: normal;
+}
+.awards .wrapper .blog_slider .item .p_info .comment {
+ font-size: 24px;
+ line-height: 45px;
+ letter-spacing: 3%;
+ font-weight: 600;
+ padding-top: 20px;
+}
+.awards .wrapper .blog_slider .item .p_info .left_link {
+ padding-top: 40px;
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .blog_slider .item .p_info .left_link {
+ padding-top: 20px;
+ }
+}
+.awards .wrapper .blog_slider .item .p_info .left_link a {
+ color: var(--level-brand);
+ font-size: 18px;
+ font-weight: 600;
+ border: 1px solid var(--level-brand);
+ border-color: transparent;
+ border-bottom-color: var(--level-brand) !important;
+ padding-bottom: 10px;
+ border-width: 2px;
+ text-decoration: none;
+}
+.awards .wrapper .blog_slider .custom-nav {
+ width: 100%;
+ margin: auto;
+ padding-left: 22px;
+ padding-top: 4px;
+ display: grid;
+ grid-auto-flow: column;
+ justify-content: center;
+ grid-gap: 30px;
+}
+.awards .wrapper .blog_slider .custom-nav .slider {
+ position: relative;
+}
+.awards .wrapper .blog_slider .custom-nav .slider-counter {
+ text-align: center;
+ color: var(--level-up-black);
+ font-size: 18px;
+}
+.awards .wrapper .blog_slider .custom-nav .prev,
+.awards .wrapper .blog_slider .custom-nav .next {
+ height: 30px;
+ width: 30px;
+ display: grid;
+ justify-content: center;
+ align-items: center;
+}
+.awards .wrapper .blog_slider .custom-nav .prev svg,
+.awards .wrapper .blog_slider .custom-nav .next svg {
+ width: 20px;
+}
+.awards .wrapper .blog_slider .custom-nav .prev svg path,
+.awards .wrapper .blog_slider .custom-nav .next svg path {
+ fill: black !important;
+}
+.awards .wrapper .excited {
+ font-weight: 700;
+ font-size: 12rem;
+ background: -webkit-linear-gradient(285deg, #ffaa00 26%, white 90%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+}
+@media screen and (max-width: 992px) {
+ .awards .wrapper .excited {
+ font-size: 8rem;
+ line-height: normal;
+ }
+}
+@media screen and (max-width: 768px) {
+ .awards .wrapper .excited {
+ font-size: 4rem;
+ line-height: normal;
+ margin-bottom: 0;
+ }
+}
+
+.service {
+ background-image: url("../images/service/service-bg.jpg");
+ background-position: center;
+ background-size: cover;
+ padding-bottom: 50px;
+}
+@media screen and (max-width: 992px) {
+ .service {
+ padding-bottom: 20px;
+ }
+}
+.service .wrapper {
+ padding-bottom: 70px;
+}
+@media screen and (max-width: 992px) {
+ .service .wrapper {
+ padding-bottom: 20px;
+ }
+}
+.service .wrapper .service_left {
+ padding: 150px 100px 0px 100px;
+}
+@media screen and (max-width: 1200px) {
+ .service .wrapper .service_left {
+ padding: 50px 50px 0px 100px;
+ }
+}
+@media screen and (max-width: 992px) {
+ .service .wrapper .service_left {
+ padding: 70px 0px 70px 15px;
+ }
+}
+.service .wrapper .service_left .s_p {
+ margin-top: 40px;
+ color: var(--p-color2);
+ font-size: 14px;
+ line-height: 1.9rem;
+ padding-bottom: 30px;
+}
+.service .wrapper .service_right img {
+ width: 100%;
+ border-radius: 8px;
+}
+
+.amazing {
+ background-color: var(--section-bg);
+ padding-top: 90px;
+ padding-bottom: 70px;
+ margin-bottom: 70px;
+}
+@media screen and (max-width: 768px) {
+ .amazing .wrapper .rm_br br {
+ display: none !important;
+ }
+}
+.amazing .wrapper .amazing_content {
+ padding-top: 50px;
+ margin-top: 40px;
+}
+.amazing .wrapper .amazing_content .card-deck {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+}
+@media screen and (max-width: 768px) {
+ .amazing .wrapper .amazing_content .card-deck {
+ grid-template-columns: 1fr;
+ }
+}
+.amazing .wrapper .amazing_content .card {
+ position: relative;
+ -webkit-backface-visibility: hidden;
+ background-color: transparent !important;
+ margin-bottom: 35px;
+ max-width: 100%;
+ border: none;
+ border-radius: 5px;
+ padding: 0;
+}
+.amazing .wrapper .amazing_content .card-body {
+ -ms-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+ -webkit-transform-style: preserve-3d;
+ perspective: 1000px;
+ -webkit-perspective: 1000px;
+ padding: 0;
+}
+.amazing .wrapper .amazing_content .flip-box-front .icon_wrapper {
+ margin-bottom: 15px;
+ text-align: center;
+ padding-top: 15px;
+}
+.amazing .wrapper .amazing_content .flip-box-front .icon_wrapper svg {
+ fill: #fcb017;
+ height: 50px;
+ width: 50px;
+}
+.amazing .wrapper .amazing_content .flip-box-front .inner {
+ border-radius: 5px;
+}
+.amazing .wrapper .amazing_content .flip-box-front .inner .card-heading {
+ padding-top: 15px;
+ color: var(--level-color3);
+ font-size: 16px;
+ font-weight: 600;
+ text-align: center;
+}
+.amazing .wrapper .amazing_content .flip-box-front .inner .card-text {
+ padding-top: 15px;
+ color: var(--p-color2);
+ font-size: 14px;
+ text-align: center;
+ line-height: 1.9rem;
+}
+.amazing .wrapper .amazing_content .flip-box-back {
+ background: rgb(241, 104, 104);
+ background: linear-gradient(38deg, rgb(241, 104, 104) 14%, rgb(252, 176, 23) 60%, rgb(252, 176, 23) 100%);
+ border-radius: 5px;
+}
+.amazing .wrapper .amazing_content .flip-box-back .inner .card-heading {
+ padding-top: 15px;
+ color: var(--color-white) !important;
+ font-size: 16px;
+ font-weight: 600;
+ text-align: center;
+}
+.amazing .wrapper .amazing_content .flip-box-back .inner .card-text {
+ padding-top: 15px;
+ color: var(--color-white) !important;
+ font-size: 14px;
+ text-align: center;
+ line-height: 1.9rem;
+}
+.amazing .wrapper .amazing_content .flip-box-front,
+.amazing .wrapper .amazing_content .flip-box-back {
+ min-height: 300px;
+ -ms-transition: transform 0.7s cubic-bezier(0.4, 0.2, 0.2, 1);
+ transition: transform 0.7s cubic-bezier(0.4, 0.2, 0.2, 1);
+ -webkit-transition: transform 0.7s cubic-bezier(0.4, 0.2, 0.2, 1);
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+}
+@media screen and (max-width: 992px) {
+ .amazing .wrapper .amazing_content .flip-box-front,
+ .amazing .wrapper .amazing_content .flip-box-back {
+ min-height: 330px;
+ }
+}
+
+@media screen and (max-width: 992px) {
+ .amazing .wrapper .amazing_content .flip-box-front,
+ .amazing .wrapper .amazing_content .flip-box-back {
+ min-height: 350px;
+ }
+}
+@media screen and (max-width: 768px) {
+ .amazing .wrapper .amazing_content .flip-box-front,
+ .amazing .wrapper .amazing_content .flip-box-back {
+ min-height: 300px;
+ }
+}
+.amazing .wrapper .amazing_content .flip-box-front {
+ -ms-transform: rotateY(0deg);
+ -webkit-transform: rotateY(0deg);
+ transform: rotateY(0deg);
+ -webkit-transform-style: preserve-3d;
+ -ms-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+ padding: 20px;
+}
+.amazing .wrapper .amazing_content .card-body:hover .flip-box-front {
+ -ms-transform: rotateY(-180deg);
+ -webkit-transform: rotateY(-180deg);
+ transform: rotateY(-180deg);
+ -webkit-transform-style: preserve-3d;
+ -ms-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+}
+.amazing .wrapper .amazing_content .flip-box-back {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ -ms-transform: rotateY(180deg);
+ -webkit-transform: rotateY(180deg);
+ transform: rotateY(180deg);
+ -webkit-transform-style: preserve-3d;
+ -ms-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+}
+.amazing .wrapper .amazing_content .flip-box-back .inner {
+ background-color: transparent !important;
+ padding: 40px !important;
+}
+.amazing .wrapper .amazing_content .card-body:hover .flip-box-back {
+ -ms-transform: rotateY(0deg);
+ -webkit-transform: rotateY(0deg);
+ transform: rotateY(0deg);
+ -webkit-transform-style: preserve-3d;
+ -ms-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+}
+.amazing .wrapper .amazing_content .card-body .inner {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ -webkit-perspective: inherit;
+ perspective: inherit;
+ z-index: 2;
+ background-color: white;
+ transform: translateY(-50%) translateZ(60px) scale(0.94);
+ -webkit-transform: translateY(-50%) translateZ(60px) scale(0.94);
+ -ms-transform: translateY(-50%) translateZ(60px) scale(0.94);
+ top: 50%;
+ padding: 20px;
+}
+.amazing .wrapper .amazing_content .flip-box-button {
+ background-color: transparent;
+ border: 2px solid #fff;
+ border-radius: 2px;
+ color: #fff;
+ cursor: pointer;
+ font-size: 20px;
+ font-weight: bold;
+ margin-top: 25px;
+ padding: 15px 20px;
+ text-transform: uppercase;
+}
+
+.partners {
+ padding-bottom: 50px;
+ border: 1px solid;
+ border-color: transparent;
+ border-bottom-color: var(--border-color2) !important;
+ margin-bottom: 20px;
+}
+@media screen and (max-width: 768px) {
+ .partners {
+ padding-bottom: 20px;
+ }
+}
+.partners .wrapper .p_img {
+ max-width: 200px;
+ margin: auto;
+}
+@media screen and (max-width: 768px) {
+ .partners .wrapper .p_img {
+ margin-bottom: 30px;
+ }
+}
+.partners .wrapper .p_img img {
+ width: 100%;
+ filter: grayscale(1);
+}
+.partners .wrapper .p_img img:hover {
+ filter: grayscale(0);
+}
+
+.creative {
+ padding-top: 50px;
+ padding-bottom: 70px;
+}
+@media screen and (max-width: 768px) {
+ .creative {
+ padding-bottom: 40px;
+ }
+}
+.creative .wrapper {
+ margin-top: 50px;
+ margin-bottom: 50px;
+}
+.creative .wrapper .c_wrapper {
+ padding-top: 70px;
+}
+.creative .wrapper .c_wrapper .c_img {
+ max-width: 300px;
+ overflow: hidden;
+ position: relative;
+ margin-bottom: 40px;
+}
+@media screen and (max-width: 768px) {
+ .creative .wrapper .c_wrapper .c_img {
+ max-width: 450px;
+ margin: auto;
+ margin-bottom: 40px;
+ }
+}
+.creative .wrapper .c_wrapper .c_img:after {
+ position: absolute;
+ content: " ";
+ height: 100%;
+ width: 100%;
+ top: 0;
+ left: 0;
+ background: #00000054 !important;
+ opacity: 0;
+ transition: 0.5s ease;
+}
+.creative .wrapper .c_wrapper .c_img img {
+ width: 100%;
+ border-radius: 5px;
+ transform: scale(1);
+ transition: 0.5s ease-in-out;
+}
+.creative .wrapper .c_wrapper .c_img:hover img {
+ transform: scale(1.3) !important;
+}
+.creative .wrapper .c_wrapper .c_img:hover:after {
+ opacity: 1 !important;
+}
+.creative .wrapper .c_wrapper .c_img:hover .info {
+ display: block !important;
+ width: 100%;
+ height: 100%;
+}
+.creative .wrapper .c_wrapper .c_img:hover .info .i_wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+}
+.creative .wrapper .c_wrapper .c_img:hover .info .i_wrapper .ss {
+ text-align: center;
+ color: var(--white-color) !important;
+}
+.creative .wrapper .c_wrapper .c_img:hover .info .i_wrapper .ss h5 {
+ font-size: 18px;
+}
+.creative .wrapper .c_wrapper .c_img:hover .info .i_wrapper .ss p {
+ font-size: 12px;
+}
+.creative .wrapper .c_wrapper .info {
+ display: none;
+ position: absolute;
+ z-index: 3;
+ top: 0;
+ left: 0;
+}
+.counter_main {
+ width: 100%;
+ background-color: var(--white-color);
+ position: relative;
+ height: 30vh;
+ overflow: hidden;
+ margin-top: 70px;
+}
+@media screen and (max-width: 992px) {
+ .counter_main {
+ margin-top: 40px;
+ }
+}
+@media screen and (max-width: 768px) {
+ .counter_main {
+ height: 55vh;
+ }
+}
+@media screen and (max-width: 576px) {
+ .counter_main {
+ height: 90vh;
+ }
+}
+.counter_main .overlay {
+ width: 100%;
+ height: 100%;
+ background-color: #00000300;
+ position: absolute;
+ top: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 3;
+}
+.counter_main .overlay #counter-section-container {
+ width: 100%;
+ text-align: center;
+}
+.counter_main .overlay #counter-box-container {
+ /*border: 1px solid #999999;*/
+ overflow: /home/cybrosys/odoo16/custom/theme_levelup/static/src/css/style.csshidden;
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr;
+}
+@media screen and (max-width: 768px) {
+ .counter_main .overlay #counter-box-container {
+ grid-template-columns: 2fr 2fr;
+ }
+}
+@media screen and (max-width: 576px) {
+ .counter_main .overlay #counter-box-container {
+ grid-template-columns: 1fr;
+ }
+}
+.counter_main .overlay #counter-box {
+ /*width: 33.22%;*/
+ margin: 5px 5px 5px 5px;
+ padding: 5px 5px 5px 5px;
+ float: left;
+ text-align: center;
+ position: relative;
+}
+.counter_main .overlay #counter-box p {
+ padding-top: 10px;
+ text-transform: uppercase;
+ font-size: 14px;
+ color: var(--p-color2);
+ font-weight: 500;
+}
+.counter_main .overlay .counter {
+ font-size: 40px;
+ font-weight: 600;
+ color: var(--level-color-3);
+}
+
+.latest {
+ background-color: var(--section-bg);
+ padding: 100px 0px 100px 0px;
+}
+@media screen and (max-width: 768px) {
+ .latest {
+ padding: 70px 0px 25px 0px;
+ }
+}
+.latest .wrapper {
+ margin-top: 30px;
+}
+.latest .wrapper .latest_content {
+ margin-top: 90px !important;
+ margin-bottom: 40px;
+}
+.latest .wrapper .latest_content .card-deck {
+ padding-bottom: 20px;
+ margin-bottom: 20px;
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+}
+.latest .wrapper .latest_content .card-deck .card {
+ border: none;
+ position: relative;
+}
+@media screen and (max-width: 768px) {
+ .latest .wrapper .latest_content .card-deck .card {
+ margin-bottom: 30px;
+ }
+}
+.latest .wrapper .latest_content .card-deck .card .type {
+ position: absolute;
+ background-color: rgba(0, 0, 0, 0.481);
+ color: var(--white-color);
+ font-size: 10px;
+ padding: 6px 15px;
+ letter-spacing: 1px;
+ top: 20px;
+ right: 20px;
+ z-index: 1000;
+ text-transform: uppercase;
+}
+.latest .wrapper .latest_content .card-deck .card .card_image {
+ position: relative;
+ display: block;
+}
+.latest .wrapper .latest_content .card-deck .card .card_image::after {
+ content: " ";
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ width: 100%;
+ background-color: rgba(0, 0, 0, 0.271);
+ transition: all 1s ease;
+ opacity: 1;
+ z-index: 999;
+}
+.latest .wrapper .latest_content .card-deck .card .card_image .card-img-top {
+ border-radius: 0 !important;
+}
+.latest .wrapper .latest_content .card-deck .card .card-body {
+ -webkit-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ -moz-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ text-align: start;
+ padding: 35px;
+}
+.latest .wrapper .latest_content .card-deck .card .card-body .card-title a {
+ font-size: 16px;
+ font-weight: 500;
+ margin-top: 15px;
+ text-decoration: none;
+ color: var(--level-color-3);
+}
+.latest .wrapper .latest_content .card-deck .card .card-body .card-text {
+ font-size: 14px;
+ color: var(--p-color2);
+ margin-bottom: 15px;
+ line-height: 2;
+}
+@media screen and (max-width: 768px) {
+ .latest .wrapper .latest_content .card-deck {
+ grid-template-columns: 1fr;
+ }
+}
+.latest .wrapper .latest_content:hover .card_image::after {
+ opacity: 0 !important;
+}
+.latest .wrapper .latest_content:hover .card-body {
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ box-shadow: 0 0 11px rgba(33, 33, 33, 0.2) !important;
+}
+
+.about {
+ position: relative;
+ padding-top: 100px;
+}
+@media screen and (max-width: 768px) {
+ .about {
+ padding-top: 70px;
+ }
+}
+.about .wrapper {
+ margin-top: 40px;
+}
+.about .wrapper .intro .left {
+ background-color: rgba(253, 244, 218, 0.368627451);
+ padding-left: 170px;
+ padding-top: 40px;
+ padding-bottom: 60px;
+}
+@media screen and (max-width: 992px) {
+ .about .wrapper .intro .left {
+ padding-left: 15px;
+ }
+}
+.about .wrapper .intro .right {
+ padding-right: 170px;
+ padding-left: 15px;
+ padding-top: 40px;
+}
+@media screen and (max-width: 992px) {
+ .about .wrapper .intro .right {
+ padding-top: 50px;
+ padding-right: 0px;
+ }
+}
+.about .wrapper .intro .right h6 {
+ font-size: 16px;
+ font-weight: 500;
+ text-decoration: none;
+ color: var(--level-color-3);
+}
+.about .wrapper .intro .right p {
+ margin-top: 18px;
+ color: var(--p-color2);
+ font-size: 14px;
+ line-height: 1.9rem;
+ padding-bottom: 30px;
+}
+.about .wrapper .intro .right .next a {
+ display: flex;
+ align-items: center;
+}
+.about .wrapper .intro .right .next a .arrow {
+ height: 32px;
+ width: 32px;
+ border-radius: 50%;
+ background-color: var(--level-brand);
+ display: inline-block;
+ padding-top: 4px;
+ position: relative;
+}
+.about .wrapper .intro .right .next a .arrow i {
+ position: absolute;
+ top: -2px;
+ left: -5px;
+ color: var(--white-color);
+ font-size: 25px;
+ margin-left: 10px;
+}
+.about .wrapper .intro .right .next a span {
+ padding-left: 10px;
+ color: var(--level-color-3);
+ font-weight: 700;
+ font-size: 16px;
+}
+.about .wrapper .slider {
+ padding-top: 80px;
+ margin-bottom: 100px;
+}
+@media screen and (max-width: 992px) {
+ .about .wrapper .slider {
+ padding-top: 30px;
+ }
+}
+.about .wrapper .slider .owl-carousel .owl-item.active.center {
+ transform: scale(1.5);
+ margin-top: 0 !important;
+ position: relative;
+ z-index: 999;
+ -webkit-transform: scale(1);
+ transform: scale(1);
+}
+.about .wrapper .slider .owl-carousel .owl-item {
+ transform: scale(0.7);
+ padding: 10px 0px;
+ transition: all 0.5s;
+}
+.about .wrapper .slider .item {
+ position: relative;
+ opacity: 1;
+ transition: 0.4s ease all;
+ margin: 0 -200px;
+ margin-top: 40px;
+}
+.about .wrapper .slider .bg1 {
+ margin-top: 40px;
+}
+.about .wrapper .slider .bg1 img {
+ width: 100%;
+}
+.about .wrapper .awards {
+ padding-top: 40px;
+}
+.about .wrapper .awards ul li .aw_sub {
+ margin-bottom: 30px;
+}
+.about .wrapper .awards ul li .aw_sub .year {
+ font-size: 36px;
+ color: var(--p-color2);
+}
+.about .wrapper .awards ul li .aw_sub p {
+ font-size: 40px;
+ font-weight: 600;
+ color: var(--level-color-3);
+}
+@media screen and (max-width: 768px) {
+ .about .wrapper .awards ul li .aw_sub p {
+ font-size: 30px;
+ }
+}
+.about .socail_media {
+ padding-top: 80px;
+ position: relative;
+}
+@media screen and (max-width: 992px) {
+ .about .socail_media {
+ padding-top: 0;
+ }
+}
+.about .socail_media .big_heading {
+ color: var(--section-bg);
+ font-size: 7em;
+ font-weight: 700;
+ text-align: center;
+ margin-bottom: -70px;
+ text-transform: capitalize;
+}
+@media screen and (max-width: 992px) {
+ .about .socail_media .big_heading {
+ font-size: 4em;
+ margin-bottom: -40px;
+ }
+}
+@media screen and (max-width: 768px) {
+ .about .socail_media .big_heading {
+ font-size: 3em;
+ margin-bottom: -30px;
+ }
+}
+@media screen and (max-width: 576px) {
+ .about .socail_media .big_heading {
+ display: none;
+ }
+}
+.about .socail_media .warpper_s {
+ padding-top: 100px;
+ padding-bottom: 80px;
+}
+.about .socail_media .warpper_s .content {
+ padding-top: 70px;
+}
+@media screen and (max-width: 768px) {
+ .about .socail_media .warpper_s .content {
+ padding-left: 15px;
+ padding-right: 15px;
+ }
+}
+.about .socail_media .warpper_s .content .card-deck {
+ padding-bottom: 40px;
+ display: grid;
+ grid-template-columns: 3fr 3fr 3fr;
+}
+@media screen and (max-width: 768px) {
+ .about .socail_media .warpper_s .content .card-deck {
+ flex-flow: column !important;
+ display: flex !important;
+ }
+}
+.about .socail_media .warpper_s .content .card-deck .card {
+ margin-top: 20px;
+ border: none;
+ border-radius: 5px;
+ padding: 10px 10px 10x 10px;
+ box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
+ background-color: #F2EFEC;
+ text-align: start;
+}
+@media screen and (max-width: 768px) {
+ .about .socail_media .warpper_s .content .card-deck .card {
+ text-align: center;
+ }
+}
+.about .socail_media .warpper_s .content .card-deck .card .card-body .icon_wrapper {
+ max-width: 100px;
+ margin: auto;
+}
+.about .socail_media .warpper_s .content .card-deck .card .card-body .icon_wrapper svg {
+ width: 50px;
+ height: 50px;
+ fill: var(--level-brand);
+ margin-bottom: 15px;
+ padding-top: 15px;
+}
+.about .socail_media .warpper_s .content .card-deck .card .card-body .card-heading {
+ padding-top: 15px;
+ color: var(--level-color3);
+ font-size: 16px;
+ font-weight: 700;
+}
+.about .socail_media .warpper_s .content .card-deck .card .card-body .card-text {
+ padding-top: 15px;
+ color: var(--p-color2);
+ font-size: 14px;
+ line-height: 1.9rem;
+}
+.about .skills {
+ padding-top: 100px;
+ background-color: var(--section-bg2) !important;
+}
+@media screen and (max-width: 768px) {
+ .about .skills {
+ padding-top: 50px;
+ }
+}
+.about .skills .wrapper .top {
+ padding: 0px 50px;
+}
+.about .skills .wrapper .top .s_info {
+ padding-top: 0px;
+ color: var(--p-color2);
+ font-size: 32px;
+ line-height: 3.1rem;
+}
+@media screen and (max-width: 768px) {
+ .about .skills .wrapper .top .s_info {
+ font-size: 24px;
+ }
+}
+.about .skills .wrapper .top .right .progress_wrapp {
+ margin-top: 80px;
+ padding-bottom: 80px;
+}
+@media screen and (max-width: 768px) {
+ .about .skills .wrapper .top .right .progress_wrapp {
+ padding-top: 20px !important;
+ }
+}
+.about .skills .wrapper .top .right .progress_wrapp .chart {
+ width: var(--size);
+ height: var(--size);
+ margin: 1em auto;
+ border-radius: 50%;
+ background-image: conic-gradient(#fcb017 var(--value), white var(--value));
+ position: relative;
+ display: flex !important;
+ justify-content: center;
+ align-items: center;
+}
+@media screen and (max-width: 768px) {
+ .about .skills .wrapper .top .right .progress_wrapp .chart {
+ margin-bottom: 50px !important;
+ }
+}
+.about .skills .wrapper .top .right .progress_wrapp .chart::after {
+ content: "";
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ width: calc(95% - var(--bord));
+ height: calc(95% - var(--bord));
+ border-radius: var(--b-radius);
+ background: white;
+ border-radius: inherit;
+}
+.about .skills .wrapper .top .right .progress_wrapp p {
+ position: relative;
+ z-index: 1;
+ font-size: 2em;
+}
+.about .skills .wrapper .top .right .progress_wrapp .x-70 {
+ --value: 70%;
+}
+.about .skills .wrapper .top .right .progress_wrapp .x-85 {
+ --value: 85%;
+}
+.about .skills .wrapper .top .right .progress_wrapp .x-95 {
+ --value: 95%;
+}
+.about .skill_img .bottom {
+ padding-top: 0px;
+ margin-top: 30px;
+}
+.about .skill_img .bottom .img_wrapper {
+ max-width: 550px;
+ margin: auto;
+ position: relative;
+ top: 150px;
+ z-index: 1;
+}
+.about .skill_img .bottom .img_wrapper img {
+ width: 100%;
+ border-radius: 25px;
+}
+@media screen and (max-width: 768px) {
+ .about .skill_img .bottom .img_wrapper img {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+}
+.about .skill_img .bottom .b_right {
+ padding-top: 260px;
+ background-color: white;
+ box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
+ border-radius: 0px 8px 0px 9px;
+ padding-right: 50px;
+ padding-left: 50px;
+ padding-bottom: 80px;
+}
+.about .skill_img .bottom .b_info {
+ color: var(--p-color2);
+ font-size: 32px;
+ line-height: 3.1rem;
+ margin-bottom: 40px;
+}
+@media screen and (max-width: 768px) {
+ .about .skill_img .bottom .b_info {
+ font-size: 24px;
+ padding-top: 40px;
+ }
+}
+.about .roll .asd {
+ padding: 60px 0px;
+ position: relative;
+}
+@media screen and (max-width: 768px) {
+ .about .roll .asd {
+ margin-top: 40px;
+ padding-bottom: 30px;
+ }
+}
+.about .roll .asd .as {
+ text-align: center;
+ border: 3px solid #000000;
+ padding: 70px 20px;
+}
+@media screen and (max-width: 768px) {
+ .about .roll .asd .as {
+ margin-bottom: 40px;
+ }
+}
+.about .roll .asd .as h6 {
+ color: var(--level-color3);
+ font-size: 28px;
+ font-weight: 600;
+ word-break: break-word;
+}
+.about .roll .asd .as p {
+ color: var(--p-color2);
+ font-size: 24px;
+ text-align: center;
+}
+.about .roll .asd .as:hover {
+ background-color: #F2EFEC;
+}
+.about .roll .asd .as:hover p {
+ color: var(--level-brand);
+}
+.about .abt_video {
+ margin-top: 40px;
+ padding-top: 80px;
+ margin-bottom: 40px;
+}
+.about .abt_video .bg_img2 {
+ position: absolute;
+ z-index: 7;
+ width: 1000px;
+ top: -150px;
+ right: 0px;
+}
+@media screen and (max-width: 768px) {
+ .about .abt_video {
+ padding-top: 30px;
+ }
+}
+.about .abt_video .wrapper {
+ background-image: url("../images/about_page/jason-goodman-0K7GgiA8lVE-unsplash.jpg");
+ background-position: center;
+ background-size: cover;
+ height: 70vh;
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: rgba(0, 0, 0, 0.277);
+ margin: 0px 100px;
+}
+@media screen and (max-width: 768px) {
+ .about .abt_video .wrapper {
+ margin: 0px;
+ }
+}
+.about .abt_video .wrapper .play a {
+ display: block;
+ max-width: 100px;
+}
+.about .abt_video .wrapper .play a:hover svg circle {
+ fill: white !important;
+}
+.about .abt_video .wrapper .play a:hover svg path {
+ fill: var(--level-brand) !important;
+}
+
+.subscribe {
+ position: relative;
+ padding-top: 100px;
+ background: rgba(253, 244, 218, 0.37);
+ margin-bottom: 200px;
+}
+.subscribe .wrapper {
+ margin-top: 40px;
+ text-align: center;
+ height: 40vh;
+}
+.subscribe .wrapper .bg_sub {
+ position: absolute;
+ z-index: -1;
+ width: 600px;
+ left: 50%;
+ transform: translate(-50%, 15%);
+}
+@media screen and (max-width: 768px) {
+ .subscribe .wrapper .bg_sub {
+ width: 100%;
+ }
+}
+.subscribe .wrapper .wrapper_sub {
+ width: 100%;
+ position: absolute;
+ z-index: 999;
+}
+
+.bg_img {
+ position: absolute;
+ z-index: 7;
+ width: 1000px;
+ top: -150px;
+ right: 0px;
+}
+@media screen and (max-width: 500px) {
+ .bg_img {
+ width: 500px;
+ top: -100px;
+ }
+}
+
+.creative {
+ padding-top: 50px;
+ padding-bottom: 70px;
+}
+.creative .wrapper {
+ margin-top: 50px;
+ margin-bottom: 50px;
+}
+.creative .wrapper .c_wrapper {
+ padding-top: 70px;
+}
+.creative .wrapper .c_wrapper .c_img {
+ max-width: 300px;
+ overflow: hidden;
+ position: relative;
+ margin-bottom: 40px;
+}
+.creative .wrapper .c_wrapper .c_img:after {
+ position: absolute;
+ content: " ";
+ height: 100%;
+ width: 100%;
+ top: 0;
+ left: 0;
+ background: #00000054 !important;
+ opacity: 0;
+ transition: 0.5s ease;
+}
+.creative .wrapper .c_wrapper .c_img img {
+ width: 100%;
+ border-radius: 5px;
+ transform: scale(1);
+ transition: 0.5s ease-in-out;
+}
+.creative .wrapper .c_wrapper .c_img:hover img {
+ transform: scale(1.3) !important;
+}
+.creative .wrapper .c_wrapper .c_img:hover:after {
+ opacity: 1 !important;
+}
+.creative .wrapper .c_wrapper .c_img:hover .info {
+ display: block !important;
+ width: 100%;
+ height: 100%;
+}
+.creative .wrapper .c_wrapper .c_img:hover .info .i_wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+}
+.creative .wrapper .c_wrapper .c_img:hover .info .i_wrapper .ss {
+ text-align: center;
+ color: var(--white-color) !important;
+}
+.creative .wrapper .c_wrapper .c_img:hover .info .i_wrapper .ss h5 {
+ font-size: 18px;
+}
+.creative .wrapper .c_wrapper .c_img:hover .info .i_wrapper .ss p {
+ font-size: 12px;
+}
+.creative .wrapper .c_wrapper .info {
+ display: none;
+ position: absolute;
+ z-index: 3;
+ top: 0;
+ left: 0;
+}
+
+@media screen and (max-width: 768px) {
+ .creative {
+ padding-bottom: 40px;
+ }
+ .creative .wrapper .c_wrapper .c_img {
+ max-width: 450px;
+ margin: auto;
+ margin-bottom: 40px;
+ }
+}
+:root {
+ --size: 150px;
+ --bord: 10px;
+ --b-radius: 10;
+}
+
+.service_page {
+ padding-top: 50px;
+}
+.service_page .wrapper {
+ margin-bottom: 100px;
+}
+.service_page .wrapper .s_content {
+ padding-top: 100px;
+ padding-bottom: 100px;
+ margin-top: 30px;
+ margin-bottom: 70px;
+ background-color: var(--section-bg3);
+}
+@media screen and (max-width: 768px) {
+ .service_page .wrapper .s_content {
+ margin-bottom: 20px;
+ }
+}
+.service_page .wrapper .s_content .img_top {
+ max-width: 600px;
+ border: 3px solid;
+ padding: 5px;
+ border-color: var(--level-color-3);
+}
+.service_page .wrapper .s_content .img_top img {
+ width: 100%;
+}
+@media screen and (max-width: 992px) {
+ .service_page .wrapper .s_content .img_top img {
+ position: unset;
+ }
+}
+@media screen and (max-width: 992px) {
+ .service_page .wrapper .s_content .b_right {
+ padding: 80px 30px 0px 0px;
+ }
+}
+.service_page .wrapper .s_content .b_right .b_info {
+ padding-top: 15px;
+ color: var(--p-color2);
+ font-size: 20px;
+ line-height: 36px;
+ padding-bottom: 50px;
+}
+.service_page .wrapper .our_services {
+ background-color: var(--section-bg);
+ padding: 100px 0px 100px 0px;
+}
+@media screen and (max-width: 768px) {
+ .service_page .wrapper .our_services {
+ padding: 100px 0px 10px 0px;
+ }
+}
+.service_page .wrapper .our_services .wrapper {
+ margin-top: 30px;
+}
+.service_page .wrapper .our_services .wrapper .latest_content {
+ margin-top: 90px !important;
+ margin-bottom: 40px;
+}
+.service_page .wrapper .our_services .wrapper .latest_content .card-deck {
+ padding-bottom: 20px;
+ margin-bottom: 20px;
+}
+@media screen and (max-width: 768px) {
+ .service_page .wrapper .our_services .wrapper .latest_content .card-deck {
+ flex-flow: column;
+ }
+}
+.service_page .wrapper .our_services .wrapper .latest_content .card-deck .card {
+ border: none;
+ position: relative;
+}
+@media screen and (max-width: 768px) {
+ .service_page .wrapper .our_services .wrapper .latest_content .card-deck .card {
+ margin-bottom: 20px;
+ }
+}
+.service_page .wrapper .our_services .wrapper .latest_content .card-deck .card_image {
+ position: relative;
+ display: block;
+ overflow: hidden;
+}
+.service_page .wrapper .our_services .wrapper .latest_content .card-deck .card_image::after {
+ content: " ";
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ width: 100%;
+ background-color: rgba(0, 0, 0, 0.271);
+ transition: all 1s ease;
+ opacity: 1;
+ z-index: 999;
+}
+.service_page .wrapper .our_services .wrapper .latest_content .card-deck .card_image .card-img-top {
+ border-radius: 0 !important;
+ transform: scale(1);
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+}
+.service_page .wrapper .our_services .wrapper .latest_content .card-deck .card-body {
+ -webkit-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ -moz-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ text-align: start;
+ padding: 35px;
+}
+.service_page .wrapper .our_services .wrapper .latest_content .card-deck .card-body .card-title a {
+ font-size: 16px;
+ font-weight: 500;
+ margin-top: 15px;
+ text-decoration: none;
+ color: var(--level-color-3);
+}
+.service_page .wrapper .our_services .wrapper .latest_content .card-deck .card-body .card-text {
+ font-size: 14px;
+ color: var(--p-color2);
+ margin-bottom: 15px;
+ line-height: 2;
+}
+.service_page .wrapper .our_services .wrapper .latest_content .card-deck:hover .card_image::after {
+ opacity: 0 !important;
+}
+.service_page .wrapper .our_services .wrapper .latest_content .card-deck:hover .card_image .card-img-top {
+ transform: scale(1.3) !important;
+}
+.service_page .wrapper .our_services .wrapper .latest_content .card-deck:hover .card-body {
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ box-shadow: 0 0 11px rgba(33, 33, 33, 0.2) !important;
+}
+.service_page .wrapper .icon_service {
+ margin-top: 70px;
+ padding-top: 40px;
+}
+@media screen and (max-width: 768px) {
+ .service_page .wrapper .icon_service {
+ margin-top: 30px;
+ padding-bottom: 70px;
+ }
+}
+.service_page .wrapper .icon_service .i_content {
+ margin-top: 20px;
+ border: 1px solid;
+ padding: 20px 25px;
+ padding-top: 30px;
+ margin-bottom: 70px;
+ text-align: center;
+}
+.service_page .wrapper .icon_service .i_content:hover {
+ background-color: var(--section-bg3);
+ border: none !important;
+ box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
+}
+.service_page .wrapper .icon_service .i_content .icon_wrapper {
+ background-color: var(--level-brand);
+ margin: auto;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 70px;
+ width: 70px;
+ border-radius: 50%;
+ box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
+ position: absolute;
+ left: 50%;
+ transform: translate(-50%, 0);
+ top: -20px;
+}
+.service_page .wrapper .icon_service .i_content .icon_wrapper svg {
+ height: 45px;
+ width: 45px;
+}
+.service_page .wrapper .icon_service .i_content h5 {
+ padding-top: 15px;
+ color: var(--level-color3);
+ font-size: 28px;
+ font-weight: 600;
+}
+.service_page .wrapper .icon_service .i_content p {
+ padding-top: 15px;
+ color: var(--p-color2);
+ font-size: 20px;
+ line-height: 2.1rem;
+}
+.service_page .wrapper .pricing {
+ padding: 100px 0px 100px 0px;
+ position: relative;
+}
+.service_page .wrapper .pricing .bg_color {
+ position: absolute;
+ height: 50vh;
+ width: 100%;
+ background-color: var(--section-bg3);
+ bottom: 0;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content {
+ margin-top: 50px;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card-deck {
+ padding-bottom: 20px;
+ margin-bottom: 20px;
+}
+@media screen and (max-width: 992px) {
+ .service_page .wrapper .pricing .wrapper_p .p_content .card-deck {
+ flex-flow: column;
+ }
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .cd {
+ margin: 30px 0;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card {
+ padding: 20px 30px;
+ border: none;
+ box-shadow: -1px 2px 8px rgba(0, 0, 0, 0.25);
+ border-radius: 0;
+ background-color: var(--section-bg) !important;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card:nth-child(2) {
+ box-shadow: none !important;
+ background-color: var(--level-brand) !important;
+ margin: 0px 30px;
+}
+@media screen and (max-width: 992px) {
+ .service_page .wrapper .pricing .wrapper_p .p_content .card:nth-child(2) {
+ margin: 0;
+ }
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card:nth-child(2) .p_card {
+ text-align: center;
+ margin: 50px 30px;
+ padding: 25px 0;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card:nth-child(2) .p_card h6 {
+ color: var(--white-color);
+ font-size: 28px;
+ text-transform: uppercase;
+ margin-bottom: 45px;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card:nth-child(2) .p_card .center_bg {
+ background-color: var(--section-bg3);
+ border-radius: 32px;
+ padding: 0px 22px 15px 22px;
+ margin-bottom: 25px;
+ box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card:nth-child(2) .p_card .center_bg .price {
+ padding-top: 20px;
+ font-weight: 700;
+ color: var(--level-color-3);
+ font-size: 50px;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card:nth-child(2) .p_card .center_bg .month {
+ margin-top: 5px;
+ font-size: 14px;
+ font-weight: 700;
+ color: var(--level-color-3);
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card:nth-child(2) .p_card .center_bg ul {
+ padding-top: 20px;
+ padding-left: 0;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card:nth-child(2) .p_card .center_bg ul li {
+ color: var(--level-color-3);
+ font-size: 15px;
+ padding: 15px;
+ border: 1px solid;
+ border-color: transparent;
+ border-bottom-color: var(--level-color-3);
+ margin-bottom: 10px;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card:nth-child(2) .p_card .center_bg ul li:last-child {
+ border: none !important;
+ margin-bottom: 0px;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card .p_card {
+ text-align: center;
+ margin: 30px 30px !important;
+ padding: 25px 0;
+}
+
+.service_page .wrapper .pricing .wrapper_p .p_content .card .p_card h6 {
+ color: var(--level-brand);
+ font-size: 28px;
+ text-transform: uppercase;
+}
+
+.service_page .wrapper .pricing .wrapper_p .p_content .card .p_card .price {
+ padding-top: 20px;
+ color: var(--level-color3);
+ font-size: 50px;
+ font-weight: 700;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card .p_card .month {
+ margin-top: 5px;
+ font-size: 14px;
+ font-weight: 700;
+ color: var(--level-color-3);
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card .p_card ul {
+ padding-top: 20px;
+ padding-left: 0;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card .p_card ul li {
+ color: var(--level-color-3);
+ font-size: 20px;
+ padding: 15px;
+ border: 1px solid;
+ border-color: transparent;
+ border-bottom-color: var(--level-color-3);
+ margin-bottom: 10px;
+}
+.service_page .wrapper .pricing .wrapper_p .p_content .card .p_card ul li:last-child {
+ border: none !important;
+ margin-bottom: 30px;
+}
+.service_page .wrapper .faq {
+ padding-top: 80px;
+ margin-top: 70px;
+}
+@media screen and (max-width: 992px) {
+ .service_page .wrapper .faq {
+ margin-top: 0px;
+ }
+}
+.service_page .wrapper .faq .wrapper {
+ margin-top: 50px;
+}
+.service_page .wrapper .faq .wrapper .accordion {
+ padding-top: 50px;
+}
+.service_page .wrapper .faq .wrapper .accordion .accordion-item {
+ border: 1px solid transparent;
+ border-bottom-color: var(--border-color);
+ margin-bottom: 30px;
+}
+.service_page .wrapper .faq .wrapper .accordion .accordion-item .accordion-header {
+ margin-bottom: 40px;
+}
+.service_page .wrapper .faq .wrapper .accordion .accordion-item .accordion-header .accordion-button {
+ background-color: transparent;
+ border: transparent;
+ font-size: 32px;
+ color: var(--level-color-3);
+ font-weight: 700;
+ letter-spacing: 0.03em;
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ text-align: left;
+}
+.service_page .wrapper .faq .wrapper .accordion .accordion-item .accordion-body {
+ padding-top: 15px;
+ padding-bottom: 30px;
+}
+.service_page .wrapper .faq .wrapper .accordion-icon {
+ float: right;
+ font-weight: bold;
+}
+.service_page .wrapper .faq .wrapper .accordion-button[aria-expanded=true] .accordion-icon::before {
+ content: "-";
+}
+.service_page .wrapper .faq .wrapper .accordion-button[aria-expanded=false] .accordion-icon::before {
+ content: "+";
+}
+.service_page .wrapper .testimonial {
+ padding-top: 80px;
+}
+.service_page .wrapper .testimonial .wrapper {
+ padding-top: 50px;
+ margin-bottom: 100px;
+}
+@media screen and (max-width: 992px) {
+ .service_page .wrapper .testimonial .wrapper {
+ padding-top: 30px;
+ }
+}
+.service_page .wrapper .testimonial .wrapper .owl-carousel .owl-item.active.center {
+ transform: scale(1.5);
+ margin-top: 0 !important;
+ position: relative;
+ z-index: 999;
+ -webkit-transform: scale(0.9);
+ transform: scale(1);
+}
+.service_page .wrapper .testimonial .wrapper .owl-carousel .owl-item.active.center .item {
+ margin-top: 0px !important;
+}
+.service_page .wrapper .testimonial .wrapper .owl-carousel .owl-item.active.center .item .t_details {
+ display: block !important;
+}
+.service_page .wrapper .testimonial .wrapper .owl-carousel .owl-item.active.center .item .t_content .img_wrapper {
+ max-width: 170px;
+ margin: auto;
+ border: 2px solid;
+ border-color: var(--level-brand) !important;
+ border-radius: 50%;
+ position: relative;
+}
+.service_page .wrapper .testimonial .wrapper .owl-carousel .owl-item.active.center .item .t_content .img_wrapper img {
+ width: 100%;
+ border-radius: 50%;
+}
+.service_page .wrapper .testimonial .wrapper .owl-carousel .owl-item.active.center .item .t_content .t_details {
+ background: #FEF9ED !important;
+ box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
+ border-radius: 21px;
+ padding: 160px 20px 20px 20px;
+ margin-top: -160px;
+ text-align: center;
+ display: none;
+}
+.service_page .wrapper .testimonial .wrapper .owl-carousel .owl-item {
+ transform: scale(0.7);
+ padding: 10px 0px;
+ transition: all 0.5s;
+}
+.service_page .wrapper .testimonial .wrapper .item {
+ position: relative;
+ opacity: 1;
+ transition: 0.4s ease all;
+ margin: 0 -100px;
+ margin-top: 40px;
+ margin-top: 150px;
+}
+.service_page .wrapper .testimonial .wrapper .item .t_content {
+ text-align: center;
+}
+.service_page .wrapper .testimonial .wrapper .item .t_content .img_wrapper {
+ max-width: 200px;
+ margin: auto;
+}
+.service_page .wrapper .testimonial .wrapper .item .t_content .img_wrapper img {
+ width: 100%;
+ border-radius: 50%;
+}
+.service_page .wrapper .testimonial .wrapper .item .t_content h4 {
+ font-size: 32px;
+ font-weight: 700;
+ padding-top: 20px;
+}
+.service_page .wrapper .testimonial .wrapper .item .t_content .roll {
+ font-size: 18px;
+ color: var(--p-color2);
+}
+.service_page .wrapper .testimonial .wrapper .item .t_content .t_details {
+ display: none;
+}
+.service_page .wrapper .testimonial .wrapper .item .t_content .t_details p {
+ padding-top: 15px;
+ color: var(--level-color-3);
+ font-size: 26px;
+ line-height: 2.5rem;
+}
+.service_page .wrapper .testimonial .wrapper .item .t_content .t_details ul {
+ display: flex;
+ padding-left: 0;
+ justify-content: center;
+}
+.service_page .wrapper .testimonial .wrapper .custom-nav {
+ width: 50%;
+ margin: auto;
+ margin-top: 40px;
+ padding-top: 4px;
+ display: grid;
+ grid-auto-flow: column;
+ justify-content: center;
+ grid-gap: 15px;
+}
+@media screen and (max-width: 768px) {
+ .service_page .wrapper .testimonial .wrapper .custom-nav {
+ justify-content: center;
+ }
+}
+.service_page .wrapper .testimonial .wrapper .custom-nav .prev,
+.service_page .wrapper .testimonial .wrapper .custom-nav .next {
+ height: 30px;
+ width: 30px;
+ border-radius: 50%;
+ display: grid;
+ justify-content: center;
+ align-items: center;
+}
+.service_page .wrapper .testimonial .wrapper .custom-nav .prev svg,
+.service_page .wrapper .testimonial .wrapper .custom-nav .next svg {
+ width: 15px;
+}
+
+.contact .wrapper .ct {
+ margin-bottom: 40px;
+}
+@media screen and (max-width: 992px) {
+ .contact .wrapper .ct {
+ padding-top: 0px;
+ }
+}
+
+.contact .wrapper .ct .wrapper_c {
+ background-image: url("../images/contact/c1.jpg");
+ background-position: center;
+ background-size: cover;
+ height: 90vh;
+ position: relative;
+}
+@media screen and (max-width: 992px) {
+ .contact .wrapper .ct .wrapper_c {
+ height: 130vh;
+ }
+}
+@media screen and (max-width: 768px) {
+ .contact .wrapper .ct .wrapper_c {
+ height: 180vh;
+ }
+}
+@media screen and (max-width: 567px) {
+ .contact .wrapper .ct .wrapper_c {
+ height: 165vh;
+ }
+}
+.contact .wrapper .ct .wrapper_c::after {
+ position: absolute;
+ content: " ";
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ background-color: rgba(0, 0, 0, 0.73);
+ z-index: 1;
+}
+.contact .wrapper .ct .wrapper_c .contact_details {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ z-index: 2;
+ padding-top: 110px;
+}
+.contact .wrapper .ct .wrapper_c .contact_details .location_details {
+ text-align: center;
+}
+@media screen and (max-width: 768px) {
+ .contact .wrapper .ct .wrapper_c .contact_details .location_details {
+ margin-bottom: 60px;
+ padding: 0px 20px;
+ }
+}
+.contact .wrapper .ct .wrapper_c .contact_details .location_details .c_icon {
+ margin-bottom: 15px;
+}
+.contact .wrapper .ct .wrapper_c .contact_details .location_details .l_heading {
+ color: var(--level-brand);
+ font-size: 40px;
+ font-weight: 700;
+}
+@media screen and (max-width: 768px) {
+ .contact .wrapper .ct .wrapper_c .contact_details .location_details .l_heading {
+ font-size: 32px;
+ }
+}
+.contact .wrapper .ct .wrapper_c .contact_details .location_details .address {
+ padding-top: 15px;
+}
+.contact .wrapper .ct .wrapper_c .contact_details .location_details .address p {
+ color: var(--white-color);
+ font-size: 32px;
+ line-height: 3.5rem;
+}
+@media screen and (max-width: 768px) {
+ .contact .wrapper .ct .wrapper_c .contact_details .location_details .address p {
+ font-size: 24px;
+ }
+}
+.contact .wrapper .ct .asd {
+ background-color: var(--white-color);
+ padding: 80px 30px;
+ border-radius: 0px;
+ margin-top: -75px;
+ box-shadow: 0px 2px 8px -1px rgb(217, 217, 217);
+ position: relative;
+ position: relative;
+ z-index: 999;
+}
+@media screen and (max-width: 992px) {
+ .contact .wrapper .ct .asd {
+ margin-top: 80px;
+ }
+}
+.contact .wrapper .ct .asd .c_heading {
+ text-align: center;
+ padding-bottom: 30px;
+ margin-bottom: 30px;
+}
+.contact .wrapper .ct .asd .c_heading h3 {
+ font-size: 62px;
+ font-weight: 700;
+ color: var(--level-color-3);
+}
+@media screen and (max-width: 992px) {
+ .contact .wrapper .ct .asd .contact_form {
+ margin-bottom: 40px;
+ }
+}
+@media screen and (max-width: 576px) {
+ .contact .wrapper .ct .asd .contact_form {
+ padding: 20px 0px 20px 0px;
+ }
+}
+.contact .wrapper .ct .asd form .form-group {
+ position: relative;
+ margin-bottom: 40px;
+}
+.contact .wrapper .ct .asd form .form-group label {
+ display: inline-block;
+ margin-bottom: 0.5rem;
+ position: absolute;
+ top: -10px;
+ left: 15px;
+ font-size: 18px !important;
+ font-weight: 500;
+ background-color: var(--white-color);
+ width: 90px;
+ text-align: center;
+}
+.contact .wrapper .ct .asd form .form-control {
+ display: block;
+ width: 100%;
+ padding: 0.375rem rem 0.75rem;
+ font-size: 1rem;
+ line-height: 2.5;
+ color: #101010;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 2px solid #000000;
+ border-radius: 8px;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+.contact .wrapper .c_t_s {
+ padding-top: 50px;
+ margin-bottom: 70px;
+}
+@media screen and (max-width: 992px) {
+ .contact .wrapper .c_t_s {
+ padding-top: 40px;
+ }
+}
+.contact .wrapper .c_t_s .social_media {
+ text-align: center;
+}
+@media screen and (max-width: 768px) {
+ .contact .wrapper .c_t_s .social_media {
+ display: block;
+ }
+}
+.contact .wrapper .c_t_s .social_media h4 {
+ color: var(--level-color-3);
+ font-size: 30px;
+ font-weight: 700;
+ margin-bottom: 25px;
+}
+.contact .wrapper .c_t_s .social_media ul {
+ display: flex;
+ padding-left: 0;
+ justify-content: center;
+}
+@media screen and (max-width: 768px) {
+ .contact .wrapper .c_t_s .social_media ul {
+ padding-left: 0px;
+ margin-top: 40px;
+ }
+}
+.contact .wrapper .c_t_s .social_media ul li {
+ margin-left: 15px;
+}
+.contact .wrapper .c_t_s .social_media ul li a {
+ display: block;
+ max-width: 30px;
+}
+.contact .wrapper .c_t_s .social_media ul li a img {
+ width: 100%;
+}
+
+.portfolio_grid {
+ padding-top: 100px;
+ margin-bottom: 80px;
+ padding-bottom: 80px;
+}
+@media screen and (max-width: 768px) {
+ .portfolio_grid {
+ padding-bottom: 0px;
+ }
+}
+.portfolio_grid .wrapper .portfolio_grid_wrapper .p_c_margin {
+ margin-top: 120px;
+}
+@media screen and (max-width: 768px) {
+ .portfolio_grid .wrapper .portfolio_grid_wrapper .p_c_margin {
+ margin-top: 0px;
+ padding-bottom: 70px;
+ }
+}
+.portfolio_grid .wrapper .portfolio_grid_wrapper .p_r {
+ padding-right: 30px;
+}
+@media screen and (max-width: 768px) {
+ .portfolio_grid .wrapper .portfolio_grid_wrapper .p_r {
+ padding-right: 15px;
+ padding-bottom: 70px;
+ }
+}
+.portfolio_grid .wrapper .portfolio_grid_wrapper .P_l {
+ padding-left: 30px;
+}
+@media screen and (max-width: 768px) {
+ .portfolio_grid .wrapper .portfolio_grid_wrapper .P_l {
+ padding-left: 15px;
+ }
+}
+.portfolio_grid .wrapper .portfolio_grid_wrapper .portfolio_img {
+ position: relative;
+ overflow: hidden;
+}
+.portfolio_grid .wrapper .portfolio_grid_wrapper .portfolio_img .portfolio_info {
+ position: absolute;
+ z-index: 999;
+ left: 0;
+ bottom: 100px;
+ display: none;
+ background-color: rgba(0, 0, 0, 0.43);
+ height: 200px;
+ width: 300px;
+ padding: 20px;
+}
+.portfolio_grid .wrapper .portfolio_grid_wrapper .portfolio_img .portfolio_info h6 {
+ color: var(--white-color);
+ font-size: 30px;
+ font-weight: 600;
+}
+.portfolio_grid .wrapper .portfolio_grid_wrapper .portfolio_img .portfolio_info p {
+ color: var(--white-color);
+ font-size: 18px;
+ font-weight: 400;
+ line-height: 40px;
+}
+.portfolio_grid .wrapper .portfolio_grid_wrapper .portfolio_img:hover .portfolio_info {
+ display: block !important;
+}
+.portfolio_grid .wrapper .portfolio_grid_wrapper .portfolio_img .img_wrapper img {
+ width: 100%;
+}
+
+.slideInLeft {
+ -webkit-animation-name: slideInLeft;
+ animation-name: slideInLeft;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+@-webkit-keyframes slideInLeft {
+ 0% {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ visibility: visible;
+ }
+ 100% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+@keyframes slideInLeft {
+ 0% {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ visibility: visible;
+ }
+ 100% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+.page_team {
+ padding-top: 100px;
+ padding-bottom: 70px;
+ background-color: var(--section-bg3);
+}
+@media screen and (max-width: 992px) {
+ .page_team {
+ padding-bottom: 40px;
+ }
+}
+.page_team .wrapper {
+ margin-bottom: 50px;
+}
+.page_team .wrapper .leads .lead_wrapper {
+ padding-top: 80px;
+}
+.page_team .wrapper .leads .lead_wrapper .lead_img {
+ max-width: 160px;
+ margin: auto;
+}
+.page_team .wrapper .leads .lead_wrapper .lead_img img {
+ width: 100%;
+ transition: transform 0.5s;
+ box-shadow: none;
+ border-radius: 50%;
+}
+.page_team .wrapper .leads .lead_wrapper:hover img {
+ transform: perspective(1000px) rotateY(20deg);
+ box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
+ border-radius: 50%;
+ transition: transform 0.5s;
+}
+.page_team .wrapper .leads .lead_wrapper .leads_body {
+ padding: 120px 30px 50px 30px;
+ background-color: var(--white-color);
+ box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
+ text-align: center;
+ margin-top: -80px;
+ border-radius: 8px;
+}
+.page_team .wrapper .leads .lead_wrapper .leads_body h6 {
+ font-size: 32px;
+ color: var(--level-color-3);
+ font-weight: 700;
+}
+.page_team .wrapper .leads .lead_wrapper .leads_body .roll {
+ font-size: 24px;
+ color: var(--level-brand);
+ font-weight: 500;
+ padding-bottom: 15px;
+}
+.page_team .wrapper .leads .lead_wrapper .leads_body p {
+ font-size: 18px;
+ color: var(--p-color2);
+ line-height: 32px;
+}
+.page_team .wrapper .leads .lead_wrapper .leads_body ul {
+ display: flex;
+ padding-left: 0;
+ justify-content: center;
+ align-items: center;
+ padding-top: 15px;
+}
+.page_team .wrapper .leads .lead_wrapper .leads_body ul li {
+ padding: 0px 15px;
+}
+.page_team .wrapper .leads .lead_wrapper .leads_body ul li a {
+ max-width: 30px;
+}
+.page_team .wrapper .leads .lead_wrapper .leads_body ul li a svg {
+ width: 100%;
+ height: 25px;
+}
+.page_team .wrapper .behind {
+ margin-top: 80px;
+ padding-bottom: 50px;
+}
+.page_team .wrapper .behind .behind_warpper {
+ padding-top: 40px;
+}
+.page_team .wrapper .behind .behind_warpper .abt_team {
+ color: var(--p-color);
+ font-weight: 600;
+ font-size: 28px;
+ line-height: 51px;
+}
+.page_team .wrapper .behind .behind_warpper .team_img {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ margin-top: 45px;
+}
+@media screen and (max-width: 500px) {
+ .page_team .wrapper .behind .behind_warpper .team_img {
+ grid-template-columns: 1fr;
+ }
+}
+.page_team .wrapper .behind .behind_warpper .team_img .r_img {
+ position: relative;
+ top: 0;
+ left: 0;
+}
+@media screen and (max-width: 500px) {
+ .page_team .wrapper .behind .behind_warpper .team_img .r_img {
+ padding-bottom: 40px;
+ }
+}
+@media screen and (max-width: 500px) {
+ .row {
+ display: flex;
+ flex-direction:row !important;
+ align:center !important;
+ }
+}
+@media screen and (max-width: 500px) {
+ .col-6{
+ width:300px;
+ justify-content:center !important;
+ }
+}
+@media screen and (max-width: 500px) {
+ .abt_team {
+ width:300px;
+ }
+}
+@media screen and (max-width: 500px) {
+ .team_img {
+ width:300px;
+ }
+}
+@media screen and (max-width: 500px) {
+ .person {
+ width:300px;
+ }
+}
+@media screen and (max-width: 500px) {
+ .xox {
+ width:300px;
+ }
+}
+@media screen and (max-width: 500px) {
+ .main_heading {
+ width:300px;
+ text-align:center;
+ }
+}
+@media screen and (max-width: 500px) {
+ .left {
+ width:300px;
+ }
+}
+@media screen and (max-width: 500px) {
+ .members_img {
+ width:300px;
+ }
+}
+@media screen and (max-width: 500px) {
+ .lead_wrapper {
+ width: 300px;
+
+ }
+}
+
+.page_team .wrapper .behind .behind_warpper .team_img .r_img .image1 {
+ position: relative;
+ top: 0;
+ left: 0;
+}
+.page_team .wrapper .behind .behind_warpper .team_img .r_img .image2 {
+ position: absolute;
+ top: 0px;
+ left: 30px;
+}
+.page_team .wrapper .behind .behind_warpper .team_img .r_img .image3 {
+ position: relative;
+ top: 0;
+}
+.page_team .wrapper .behind .behind_warpper .team_img .r_img .image4 {
+ position: relative;
+ top: 0px;
+ left: -30px;
+}
+.page_team .wrapper .behind .behind_warpper .team_img .trust {
+ color: var(--level-brand);
+ font-weight: 600;
+ font-size: 20px;
+ width: 100%;
+}
+.page_team .wrapper .behind .behind_warpper .members {
+ padding-top: 100px;
+}
+.page_team .wrapper .behind .behind_warpper .members .members_img {
+ position: relative;
+ overflow: hidden;
+}
+@media screen and (max-width: 768px) {
+ .page_team .wrapper .behind .behind_warpper .members .members_img {
+ margin-bottom: 40px;
+ }
+}
+.page_team .wrapper .behind .behind_warpper .members .members_img .members_info {
+ position: absolute;
+ z-index: 999;
+ left: 0;
+ bottom: 100px;
+ display: none;
+ background-color: rgba(0, 0, 0, 0.43);
+ height: 100px;
+ width: 150px;
+ padding: 20px;
+ text-align: center;
+}
+.page_team .wrapper .behind .behind_warpper .members .members_img .members_info h6 {
+ color: var(--white-color);
+ font-size: 20px;
+ font-weight: 600;
+ margin-bottom: 0;
+}
+.page_team .wrapper .behind .behind_warpper .members .members_img .members_info p {
+ color: var(--level-brand);
+ font-size: 18px;
+ font-weight: 400;
+ line-height: 40px;
+}
+.page_team .wrapper .behind .behind_warpper .members .members_img:hover .members_info {
+ display: block !important;
+}
+.page_team .wrapper .behind .behind_warpper .members .members_img .img_wrapper img {
+ width: 100%;
+}
+.page_team .wrapper .behind .behind_warpper .members .custom_margin_top {
+ margin-top: 100px;
+}
+@media screen and (max-width: 768px) {
+ .page_team .wrapper .behind .behind_warpper .members .custom_margin_top {
+ margin-top: 0px;
+ }
+}
+.page_team .wrapper .join {
+ background-image: url("../images/team/business-team-giving-high-five.png");
+ background-position: center;
+ background-size: cover;
+ height: 70vh;
+ position: relative;
+ margin-top: 100px;
+}
+@media screen and (max-width: 768px) {
+ .page_team .wrapper .join {
+ height: 100vh;
+ }
+}
+.page_team .wrapper .join .wrapper_j {
+ position: absolute;
+ height: 100%;
+ width: 100%;
+ background: linear-gradient(71.6deg, #F16868 -4.82%, rgba(252, 176, 23, 0.78) 101.09%, #FCB017 141.26%, #FCB017 228.46%);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+.page_team .wrapper .join .wrapper_j .content {
+ text-align: center;
+ color: var(--white-color);
+}
+.page_team .wrapper .join .wrapper_j .content p {
+ font-size: 28px;
+ font-weight: 500;
+}
+.page_team .wrapper .join .wrapper_j .content h4 {
+ font-size: 64px;
+ font-weight: 700;
+ line-height: 81px;
+ padding-bottom: 20px;
+}
+.page_team .wrapper .words {
+ padding-top: 100px;
+}
+@media screen and (max-width: 768px) {
+ .page_team .wrapper .words {
+ padding-top: 0;
+ }
+}
+.page_team .wrapper .words .wrapper_w {
+ padding-top: 100px;
+}
+.page_team .wrapper .words .wrapper_w .left {
+ margin-top: 100px;
+}
+@media screen and (max-width: 992px) {
+ .page_team .wrapper .words .wrapper_w .left {
+ margin-bottom: 50px;
+ max-width: 500px;
+ }
+}
+@media screen and (max-width: 992px) {
+ .page_team .wrapper .words .wrapper_w .left .img_w1 {
+ width: 100%;
+ }
+}
+.page_team .wrapper .words .wrapper_w .left .img_w2 {
+ position: absolute;
+ left: 20%;
+ top: 0%;
+}
+@media screen and (max-width: 992px) {
+ .page_team .wrapper .words .wrapper_w .left .img_w2 {
+ width: 70%;
+ }
+}
+@media screen and (max-width: 768px) {
+ .page_team .wrapper .words .wrapper_w .left .img_w2 {
+ display: none;
+ }
+}
+.page_team .wrapper .words .wrapper_w .right {
+ padding-top: 50px;
+}
+.page_team .wrapper .words .wrapper_w .right .xox {
+ color: var(--p-color2);
+ font-size: 32px;
+ line-height: 3.1rem;
+}
+@media screen and (max-width: 768px) {
+ .page_team .wrapper .words .wrapper_w .right .xox {
+ font-size: 22px;
+ }
+}
+.page_team .wrapper .words .wrapper_w .right .person {
+ display: flex;
+ justify-content: end;
+ align-items: center;
+ margin-top: 50px;
+ padding-left: 30px;
+}
+@media screen and (max-width: 768px) {
+ .page_team .wrapper .words .wrapper_w .right .person {
+ padding-left: 0;
+ }
+}
+.page_team .wrapper .words .wrapper_w .right .person .details {
+ padding-right: 20px;
+}
+.page_team .wrapper .words .wrapper_w .right .person .details h6 {
+ font-size: 28px;
+ color: var(--level-color-3);
+ font-weight: 700;
+}
+.page_team .wrapper .words .wrapper_w .right .person .details p {
+ font-size: 24px;
+ font-weight: 400;
+ color: var(--p-color2);
+ margin-bottom: 0;
+}
+
+.blog_page {
+ background-color: var(--section-bg3);
+ padding-top: 100px;
+ padding-bottom: 100px;
+}
+.blog_page .wrapper .card {
+ border: none;
+ position: relative;
+ margin-bottom: 30px;
+ background-color: transparent !important;
+}
+.blog_page .wrapper .card:hover .card_image::after {
+ opacity: 0 !important;
+}
+.blog_page .wrapper .card_image {
+ position: relative;
+ display: block;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+}
+.blog_page .wrapper .card_image::after {
+ content: " ";
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ width: 100%;
+ border-radius: 15px;
+ background-color: rgba(0, 0, 0, 0.271);
+ transition: all 1s ease;
+ opacity: 1;
+ z-index: 999;
+}
+.blog_page .wrapper .card_image .card-img-top {
+ border-radius: 0 !important;
+}
+.blog_page .wrapper .card-body {
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ text-align: start;
+ padding: 35px;
+ padding-left: 0;
+}
+.blog_page .wrapper .card-body .card-title a {
+ font-size: 32px;
+ font-weight: 700;
+ margin-top: 15px;
+ text-decoration: none;
+ color: var(--level-color-3);
+}
+.blog_page .wrapper .card-body .card-title a:hover {
+ text-decoration: none;
+ color: var(--p-color2);
+}
+.blog_page .wrapper .card-body .card-text {
+ font-size: 24px;
+ color: var(--p-color2);
+ margin-bottom: 15px;
+ line-height: 2;
+}
+.blog_page .wrapper .blog_sidebar {
+ padding-left: 20px;
+}
+.blog_page .wrapper .blog_sidebar .s_wrapper .sidebar_heading {
+ font-size: 40px;
+ color: var(--level-brand);
+ font-weight: 500;
+ padding-bottom: 15px;
+ margin-bottom: 20px;
+}
+.blog_page .wrapper .blog_sidebar .s_wrapper .populor_feed {
+ display: flex;
+ margin-bottom: 40px;
+
+
+}
+.blog_page .wrapper .blog_sidebar .s_wrapper .populor_feed .img_wrapper {
+ margin-right: 15px;
+ width: 100px !important;
+ height: 50px;
+}
+.blog_page .wrapper .blog_sidebar .s_wrapper .populor_feed .img_wrapper img {
+ width: 100%;
+ border-radius: 5px;
+}
+.blog_page .wrapper .blog_sidebar .s_wrapper .populor_feed .p_f_detials .date {
+ font-size: 16px;
+ color: var(--p-color2);
+}
+.blog_page .wrapper .blog_sidebar .s_wrapper .populor_feed .p_f_detials .feed_caption {
+ font-size: 18px;
+ font-weight: 700;
+ color: var(--level-color-3);
+}
+.blog_page .wrapper .blog_sidebar .s_wrapper .populor_feed .p_f_detials .feed_caption:hover {
+ text-decoration: none;
+ color: var(--p-color2);
+}
+.btn{
+ border-radius:1px !important;
+}
+.img-fluid{
+ max-width: 200% !important;
+}
+.btn-light{
+ color: #fff !important;
+}
+.map_container iframe{
+ height:66%;
+}
+
+.btn-price_m:hover{
+color:#000 !important;
+background-color:#fff !important;
+border:2px solid #000 !important;
+
+}
+
+.btn-price, .btn-price_m{
+color:#fff !important;
+padding: 8px !important;
+ margin-top: -1px !important;
+ background-color:black;
+}
+.btn-price:hover{
+color:#000 !important;
+background-color:#fff !important;
+border:2px solid #000 !important;
+
+}
+.website_blog #o_wblog_posts_loop .o_record_cover_container{
+ padding-top: 60%;
+}
+.btn-schedule{
+ margin-top: 0px !important;
+}
+.btn-light {
+ color:#212529 !important;
+}
+.new-nav-color{
+ color: var(--level-color-1) !important;
+ font-size: 14px;
+ margin: 0px 15px !important;
+ font-weight: 500;
+ padding-top: 17px;
+}
+ .btn-new-call{
+ background-color:#000 !important;
+}
+.blog_text{
+background: black;
+ color: white;
+ text-align: center;
+ height: 300px;
+}
+.header_modern_light .navigation .navbar .navbar-nav .nav-item .nav-link {
+ margin-top: 11px !important;
+ color: var(--level-color-1);
+ font-size: 14px;
+ margin: 0px 15px;
+ font-weight: 500;
+}
+@media screen and (max-width:1025px){
+
+main .banner_about .banner_content .c_wrapper {
+ font-size: 9rem !important;
+}
+
+main .banner_about .banner_content {
+
+ height: 45vh !important;
+ font-size: 71px !important;
+
+}
+
+}
+
+@media screen and (max-width: 650px){
+.banner_about .banner_content .c_wrapper {
+ display: flex;
+ justify-content: center;
+ font-size: 5rem;
+ left:31px;
+}
+.portfolio_grid .wrapper .portfolio_grid_wrapper .portfolio_img:hover .portfolio_info {
+ width: 257px;
+ bottom: 20px;
+ height: 204px;
+ display: block !important;
+}
+
+.banner_about .banner_content{
+
+height:42vh;
+
+}
+
+.banner_about .portfolio {
+ height: 30vh !important;
+}
+
+main .banner_about .banner_content .c_wrapper{
+ font-size:5rem !important;
+
+}
+
+.subscribe{
+
+ overflow:hidden !important;
+
+ }
+
+ #o_wblog_index_content{
+
+ overflow:hidden !important;
+
+ }
+}
+.banner_about .banner_content .c_wrapper {
+
+ top: 71px !important;
+ left: 0px !important;
+ font-size: 17rem !important;
+}
+@media screen and (max-width: 768px){
+.gallery .wrapper .bg_heading .gallery_head {
+ font-size: 6vh;
+ margin-top: 0px;
+ line-height: normal;
+ margin-bottom: 0px;
+ height: fit-content;
+}
+.service_page .wrapper .testimonial .wrapper .item .t_content {
+ width: 142px;
+ text-align: center;
+ margin-left: 82px;
+ height: 460px;
+}
+.service_page .wrapper .testimonial .wrapper .item .t_content .t_details p {
+ padding-top: 6px;
+ color: var(--level-color-3);
+ font-size: 16px;
+ line-height: 1.5rem;
+}
+svg:not(:root) {
+ width: 82px;
+ overflow: hidden;
+}
+}
+@media (max-width: 491px) {
+ .leads_body h6 {
+ font-size: 24px !important;
+ }
+ .leads_body .roll {
+ font-size: 18px !important;
+ }
+ .leads_body p {
+ font-size: 15px !important;
+ }
+}
+@media (max-width: 541px) {
+ .leads_body ul.socilal_media svg {
+ width: 15px !important;
+ }
+}
+@media (max-width: 768px) {
+ section.service_page svg:not(:root) {
+ width: 22px !important;
+ }
+}
+div#wrapwrap {
+ overflow: auto !important;
+}
+.navbar #top_menu.o_menu_loading {
+ opacity: 100 !important;
+}
+@media (min-width: 1200px) {
+ margin-left: 25% !important;
+}
+.footer .wrapper .footer_c .footer_brand span img {
+ width: 35px !important;
+}
+ul.nav a.dropdown-toggle::after {
+ display: none !important;
+}
+ul.nav a.dropdown-toggle i::before {
+ content: "\f2be" !important;
+}
+@media (max-width: 768px) {
+ .gallery .wrapper .img_group .bottom_link .left_link a {
+ margin-left: -9px !important;
+ font-size: 22px !important;
+ }
+}
+ul.nav a.dropdown-toggle i.fa-user {
+ font-size: 20px;
+}
+@media (max-width: 574px) {
+ ul.mobile {
+ display: flex !important;
+ margin-left: -10% !important;
+ margin-bottom: 10px !important;
+ }
+ nav.navbar a.navbar-toggler {
+ margin-left: 50%;
+ }
+}
+
+@media (min-width: 768px) {
+ .sale-combo-configurator-dialog .modal-footer {
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ padding: 1rem; /* restore Odoo's standard padding */
+ border-top: 1px solid #dee2e6; /* typical Bootstrap/Odoo modal border */
+ background-color: #fff; /* ensure white background */
+ }
+
+ .sale-combo-configurator-dialog .modal-footer > * {
+ margin-left: 0.5rem; /* spacing between buttons */
+ }
+}
+.o_sale_product_configurator_dialog .form-check-input{
+ position: initial;
+}
+
+#billing_address_row #use_delivery_as_billing_label{
+ margin-left: 1.3rem !important;
+}
+
+
+#o_wsale_total_accordion_item .o_cta_navigation_container {
+ position: static !important;
+ display: contents;
+}
\ No newline at end of file
diff --git a/theme_levelup/static/src/images/Main_bg/circle_trans.png b/theme_levelup/static/src/images/Main_bg/circle_trans.png
new file mode 100644
index 0000000000..9178e1eaca
Binary files /dev/null and b/theme_levelup/static/src/images/Main_bg/circle_trans.png differ
diff --git a/theme_levelup/static/src/images/Main_bg/circles.png b/theme_levelup/static/src/images/Main_bg/circles.png
new file mode 100644
index 0000000000..1aa13c92d2
Binary files /dev/null and b/theme_levelup/static/src/images/Main_bg/circles.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/behance.png b/theme_levelup/static/src/images/Social Media Icons/behance.png
new file mode 100644
index 0000000000..d900ce68bb
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/behance.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/dribbble.png b/theme_levelup/static/src/images/Social Media Icons/dribbble.png
new file mode 100644
index 0000000000..6b7053fcc0
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/dribbble.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/dropbox.png b/theme_levelup/static/src/images/Social Media Icons/dropbox.png
new file mode 100644
index 0000000000..c7bfceb60d
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/dropbox.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/facebook.png b/theme_levelup/static/src/images/Social Media Icons/facebook.png
new file mode 100644
index 0000000000..1eb64d2d3e
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/facebook.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/google-plus.png b/theme_levelup/static/src/images/Social Media Icons/google-plus.png
new file mode 100644
index 0000000000..09f9c39808
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/google-plus.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/instagram.png b/theme_levelup/static/src/images/Social Media Icons/instagram.png
new file mode 100644
index 0000000000..029909d879
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/instagram.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/linkedin.png b/theme_levelup/static/src/images/Social Media Icons/linkedin.png
new file mode 100644
index 0000000000..861cf90c4c
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/linkedin.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/pinterest.png b/theme_levelup/static/src/images/Social Media Icons/pinterest.png
new file mode 100644
index 0000000000..4fb2e86ad4
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/pinterest.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/skype.png b/theme_levelup/static/src/images/Social Media Icons/skype.png
new file mode 100644
index 0000000000..b791e7064b
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/skype.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/snapchat.png b/theme_levelup/static/src/images/Social Media Icons/snapchat.png
new file mode 100644
index 0000000000..f3213e6cf3
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/snapchat.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/spotify.png b/theme_levelup/static/src/images/Social Media Icons/spotify.png
new file mode 100644
index 0000000000..e8aab702ce
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/spotify.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/tumblr.png b/theme_levelup/static/src/images/Social Media Icons/tumblr.png
new file mode 100644
index 0000000000..4144b97daa
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/tumblr.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/twitter.png b/theme_levelup/static/src/images/Social Media Icons/twitter.png
new file mode 100644
index 0000000000..d4ee8fab57
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/twitter.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/vimeo.png b/theme_levelup/static/src/images/Social Media Icons/vimeo.png
new file mode 100644
index 0000000000..302ce86ccb
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/vimeo.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/whatsapp.png b/theme_levelup/static/src/images/Social Media Icons/whatsapp.png
new file mode 100644
index 0000000000..ce5677dcaa
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/whatsapp.png differ
diff --git a/theme_levelup/static/src/images/Social Media Icons/youtube.png b/theme_levelup/static/src/images/Social Media Icons/youtube.png
new file mode 100644
index 0000000000..2db89d2078
Binary files /dev/null and b/theme_levelup/static/src/images/Social Media Icons/youtube.png differ
diff --git a/theme_levelup/static/src/images/abou_icon/bar-chart-line.svg b/theme_levelup/static/src/images/abou_icon/bar-chart-line.svg
new file mode 100644
index 0000000000..e0d618f47e
--- /dev/null
+++ b/theme_levelup/static/src/images/abou_icon/bar-chart-line.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/theme_levelup/static/src/images/abou_icon/briefcase.svg b/theme_levelup/static/src/images/abou_icon/briefcase.svg
new file mode 100644
index 0000000000..849646f383
--- /dev/null
+++ b/theme_levelup/static/src/images/abou_icon/briefcase.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/theme_levelup/static/src/images/abou_icon/gear.svg b/theme_levelup/static/src/images/abou_icon/gear.svg
new file mode 100644
index 0000000000..905ada72a0
--- /dev/null
+++ b/theme_levelup/static/src/images/abou_icon/gear.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/theme_levelup/static/src/images/abou_icon/globe.svg b/theme_levelup/static/src/images/abou_icon/globe.svg
new file mode 100644
index 0000000000..09b341f452
--- /dev/null
+++ b/theme_levelup/static/src/images/abou_icon/globe.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/theme_levelup/static/src/images/abou_icon/pencil-square (1).svg b/theme_levelup/static/src/images/abou_icon/pencil-square (1).svg
new file mode 100644
index 0000000000..c107c95b49
--- /dev/null
+++ b/theme_levelup/static/src/images/abou_icon/pencil-square (1).svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/theme_levelup/static/src/images/abou_icon/pencil-square.svg b/theme_levelup/static/src/images/abou_icon/pencil-square.svg
new file mode 100644
index 0000000000..c107c95b49
--- /dev/null
+++ b/theme_levelup/static/src/images/abou_icon/pencil-square.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/theme_levelup/static/src/images/abou_icon/pinterest.svg b/theme_levelup/static/src/images/abou_icon/pinterest.svg
new file mode 100644
index 0000000000..f73d932919
--- /dev/null
+++ b/theme_levelup/static/src/images/abou_icon/pinterest.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/theme_levelup/static/src/images/abou_icon/unity.svg b/theme_levelup/static/src/images/abou_icon/unity.svg
new file mode 100644
index 0000000000..b510af04a5
--- /dev/null
+++ b/theme_levelup/static/src/images/abou_icon/unity.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/theme_levelup/static/src/images/about_home/1 1.png b/theme_levelup/static/src/images/about_home/1 1.png
new file mode 100644
index 0000000000..25ccce7fed
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/1 1.png differ
diff --git a/theme_levelup/static/src/images/about_home/2.png b/theme_levelup/static/src/images/about_home/2.png
new file mode 100644
index 0000000000..36465d2ce7
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/2.png differ
diff --git a/theme_levelup/static/src/images/about_home/3.png b/theme_levelup/static/src/images/about_home/3.png
new file mode 100644
index 0000000000..8862a4d08c
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/3.png differ
diff --git a/theme_levelup/static/src/images/about_home/4.png b/theme_levelup/static/src/images/about_home/4.png
new file mode 100644
index 0000000000..43f40cf6f4
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/4.png differ
diff --git a/theme_levelup/static/src/images/about_home/Place Your Image Here (Double Click to Edit) 2.png b/theme_levelup/static/src/images/about_home/Place Your Image Here (Double Click to Edit) 2.png
new file mode 100644
index 0000000000..fa159064b7
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/Place Your Image Here (Double Click to Edit) 2.png differ
diff --git a/theme_levelup/static/src/images/about_home/client (1).png b/theme_levelup/static/src/images/about_home/client (1).png
new file mode 100644
index 0000000000..2d760297f6
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/client (1).png differ
diff --git a/theme_levelup/static/src/images/about_home/client (2).png b/theme_levelup/static/src/images/about_home/client (2).png
new file mode 100644
index 0000000000..a3afaef8cc
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/client (2).png differ
diff --git a/theme_levelup/static/src/images/about_home/client (3).png b/theme_levelup/static/src/images/about_home/client (3).png
new file mode 100644
index 0000000000..d98fb91086
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/client (3).png differ
diff --git a/theme_levelup/static/src/images/about_home/client (4).png b/theme_levelup/static/src/images/about_home/client (4).png
new file mode 100644
index 0000000000..3024291945
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/client (4).png differ
diff --git a/theme_levelup/static/src/images/about_home/client (5).png b/theme_levelup/static/src/images/about_home/client (5).png
new file mode 100644
index 0000000000..7f07e6c72c
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/client (5).png differ
diff --git a/theme_levelup/static/src/images/about_home/client (6).png b/theme_levelup/static/src/images/about_home/client (6).png
new file mode 100644
index 0000000000..a0b394bd9f
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/client (6).png differ
diff --git a/theme_levelup/static/src/images/about_home/image 1.png b/theme_levelup/static/src/images/about_home/image 1.png
new file mode 100644
index 0000000000..b8b1a2caee
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/image 1.png differ
diff --git a/theme_levelup/static/src/images/about_home/image 2.png b/theme_levelup/static/src/images/about_home/image 2.png
new file mode 100644
index 0000000000..53b259166a
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/image 2.png differ
diff --git a/theme_levelup/static/src/images/about_home/image 3.png b/theme_levelup/static/src/images/about_home/image 3.png
new file mode 100644
index 0000000000..e0f8dc6dd2
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/image 3.png differ
diff --git a/theme_levelup/static/src/images/about_home/image 4.png b/theme_levelup/static/src/images/about_home/image 4.png
new file mode 100644
index 0000000000..38b91cd452
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/image 4.png differ
diff --git a/theme_levelup/static/src/images/about_home/image 5.png b/theme_levelup/static/src/images/about_home/image 5.png
new file mode 100644
index 0000000000..84c8b88a6c
Binary files /dev/null and b/theme_levelup/static/src/images/about_home/image 5.png differ
diff --git a/theme_levelup/static/src/images/about_page/jason-goodman-0K7GgiA8lVE-unsplash.jpg b/theme_levelup/static/src/images/about_page/jason-goodman-0K7GgiA8lVE-unsplash.jpg
new file mode 100644
index 0000000000..47740934c6
Binary files /dev/null and b/theme_levelup/static/src/images/about_page/jason-goodman-0K7GgiA8lVE-unsplash.jpg differ
diff --git a/theme_levelup/static/src/images/about_page/play (1).svg b/theme_levelup/static/src/images/about_page/play (1).svg
new file mode 100644
index 0000000000..a818d36ddc
--- /dev/null
+++ b/theme_levelup/static/src/images/about_page/play (1).svg
@@ -0,0 +1,2 @@
+
+
diff --git a/theme_levelup/static/src/images/about_page/play-button.png b/theme_levelup/static/src/images/about_page/play-button.png
new file mode 100644
index 0000000000..5e5cf50ee4
Binary files /dev/null and b/theme_levelup/static/src/images/about_page/play-button.png differ
diff --git a/theme_levelup/static/src/images/about_page/portrait-happy-successful-young-businessman-wears-white-shirt-office.jpg b/theme_levelup/static/src/images/about_page/portrait-happy-successful-young-businessman-wears-white-shirt-office.jpg
new file mode 100644
index 0000000000..86605529bf
Binary files /dev/null and b/theme_levelup/static/src/images/about_page/portrait-happy-successful-young-businessman-wears-white-shirt-office.jpg differ
diff --git a/theme_levelup/static/src/images/about_page/slider1.jpg b/theme_levelup/static/src/images/about_page/slider1.jpg
new file mode 100644
index 0000000000..cdb0efde45
Binary files /dev/null and b/theme_levelup/static/src/images/about_page/slider1.jpg differ
diff --git a/theme_levelup/static/src/images/about_page/slider2.jpg b/theme_levelup/static/src/images/about_page/slider2.jpg
new file mode 100644
index 0000000000..aa6c2d6221
Binary files /dev/null and b/theme_levelup/static/src/images/about_page/slider2.jpg differ
diff --git a/theme_levelup/static/src/images/about_page/slider3.jpg b/theme_levelup/static/src/images/about_page/slider3.jpg
new file mode 100644
index 0000000000..f6e5ba4d7e
Binary files /dev/null and b/theme_levelup/static/src/images/about_page/slider3.jpg differ
diff --git a/theme_levelup/static/src/images/banner/8542740 1.png b/theme_levelup/static/src/images/banner/8542740 1.png
new file mode 100644
index 0000000000..d6bdf18225
Binary files /dev/null and b/theme_levelup/static/src/images/banner/8542740 1.png differ
diff --git a/theme_levelup/static/src/images/banner/a.jpg b/theme_levelup/static/src/images/banner/a.jpg
new file mode 100644
index 0000000000..8454e33e27
Binary files /dev/null and b/theme_levelup/static/src/images/banner/a.jpg differ
diff --git a/theme_levelup/static/src/images/banner/banner-1.jpg b/theme_levelup/static/src/images/banner/banner-1.jpg
new file mode 100644
index 0000000000..c228cba9db
Binary files /dev/null and b/theme_levelup/static/src/images/banner/banner-1.jpg differ
diff --git a/theme_levelup/static/src/images/banner/banner-2.jpg b/theme_levelup/static/src/images/banner/banner-2.jpg
new file mode 100644
index 0000000000..0774795fca
Binary files /dev/null and b/theme_levelup/static/src/images/banner/banner-2.jpg differ
diff --git a/theme_levelup/static/src/images/banner/banner-3.jpg b/theme_levelup/static/src/images/banner/banner-3.jpg
new file mode 100644
index 0000000000..b18c49982f
Binary files /dev/null and b/theme_levelup/static/src/images/banner/banner-3.jpg differ
diff --git a/theme_levelup/static/src/images/banner/banner_about.jpg b/theme_levelup/static/src/images/banner/banner_about.jpg
new file mode 100644
index 0000000000..1ea43e7cf6
Binary files /dev/null and b/theme_levelup/static/src/images/banner/banner_about.jpg differ
diff --git a/theme_levelup/static/src/images/banner/banner_portfolio.jpg b/theme_levelup/static/src/images/banner/banner_portfolio.jpg
new file mode 100644
index 0000000000..6e3cfc2130
Binary files /dev/null and b/theme_levelup/static/src/images/banner/banner_portfolio.jpg differ
diff --git a/theme_levelup/static/src/images/banner/banner_team.jpg b/theme_levelup/static/src/images/banner/banner_team.jpg
new file mode 100644
index 0000000000..2176c3e1c5
Binary files /dev/null and b/theme_levelup/static/src/images/banner/banner_team.jpg differ
diff --git a/theme_levelup/static/src/images/banner/bg.png b/theme_levelup/static/src/images/banner/bg.png
new file mode 100644
index 0000000000..2628028079
Binary files /dev/null and b/theme_levelup/static/src/images/banner/bg.png differ
diff --git a/theme_levelup/static/src/images/blog/blog (1).jpg b/theme_levelup/static/src/images/blog/blog (1).jpg
new file mode 100644
index 0000000000..b54e1691de
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (1).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (10).jpg b/theme_levelup/static/src/images/blog/blog (10).jpg
new file mode 100644
index 0000000000..4884db2b96
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (10).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (11).jpg b/theme_levelup/static/src/images/blog/blog (11).jpg
new file mode 100644
index 0000000000..77e60dff7e
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (11).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (12).jpg b/theme_levelup/static/src/images/blog/blog (12).jpg
new file mode 100644
index 0000000000..450b129719
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (12).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (13).jpg b/theme_levelup/static/src/images/blog/blog (13).jpg
new file mode 100644
index 0000000000..4df67da6a8
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (13).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (14).jpg b/theme_levelup/static/src/images/blog/blog (14).jpg
new file mode 100644
index 0000000000..5351f82fcb
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (14).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (2).jpg b/theme_levelup/static/src/images/blog/blog (2).jpg
new file mode 100644
index 0000000000..df5ad9420b
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (2).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (3).jpg b/theme_levelup/static/src/images/blog/blog (3).jpg
new file mode 100644
index 0000000000..212e594f16
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (3).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (4).jpg b/theme_levelup/static/src/images/blog/blog (4).jpg
new file mode 100644
index 0000000000..657549a7a2
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (4).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (5).jpg b/theme_levelup/static/src/images/blog/blog (5).jpg
new file mode 100644
index 0000000000..b3143a53a2
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (5).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (6).jpg b/theme_levelup/static/src/images/blog/blog (6).jpg
new file mode 100644
index 0000000000..5ae7381794
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (6).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (7).jpg b/theme_levelup/static/src/images/blog/blog (7).jpg
new file mode 100644
index 0000000000..e3cf2b4769
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (7).jpg differ
diff --git a/theme_levelup/static/src/images/blog/blog (9).jpg b/theme_levelup/static/src/images/blog/blog (9).jpg
new file mode 100644
index 0000000000..7f6ab8ac41
Binary files /dev/null and b/theme_levelup/static/src/images/blog/blog (9).jpg differ
diff --git a/theme_levelup/static/src/images/branding/Group (3).png b/theme_levelup/static/src/images/branding/Group (3).png
new file mode 100644
index 0000000000..772ff6601c
Binary files /dev/null and b/theme_levelup/static/src/images/branding/Group (3).png differ
diff --git a/theme_levelup/static/src/images/branding/Group 108.png b/theme_levelup/static/src/images/branding/Group 108.png
new file mode 100644
index 0000000000..d130710a86
Binary files /dev/null and b/theme_levelup/static/src/images/branding/Group 108.png differ
diff --git a/theme_levelup/static/src/images/branding/Vector (2).png b/theme_levelup/static/src/images/branding/Vector (2).png
new file mode 100644
index 0000000000..b81b68f447
Binary files /dev/null and b/theme_levelup/static/src/images/branding/Vector (2).png differ
diff --git a/theme_levelup/static/src/images/branding/branding1.jpg b/theme_levelup/static/src/images/branding/branding1.jpg
new file mode 100644
index 0000000000..7ec182bbc3
Binary files /dev/null and b/theme_levelup/static/src/images/branding/branding1.jpg differ
diff --git a/theme_levelup/static/src/images/branding/branding2.jpg b/theme_levelup/static/src/images/branding/branding2.jpg
new file mode 100644
index 0000000000..bac2ce2a1d
Binary files /dev/null and b/theme_levelup/static/src/images/branding/branding2.jpg differ
diff --git a/theme_levelup/static/src/images/branding/branding3.jpg b/theme_levelup/static/src/images/branding/branding3.jpg
new file mode 100644
index 0000000000..df14ac0c73
Binary files /dev/null and b/theme_levelup/static/src/images/branding/branding3.jpg differ
diff --git a/theme_levelup/static/src/images/branding/branding4.jpg b/theme_levelup/static/src/images/branding/branding4.jpg
new file mode 100644
index 0000000000..18f5ca11f8
Binary files /dev/null and b/theme_levelup/static/src/images/branding/branding4.jpg differ
diff --git a/theme_levelup/static/src/images/contact/business-people-shaking-hands-together.jpg b/theme_levelup/static/src/images/contact/business-people-shaking-hands-together.jpg
new file mode 100644
index 0000000000..d7abbadf7a
Binary files /dev/null and b/theme_levelup/static/src/images/contact/business-people-shaking-hands-together.jpg differ
diff --git a/theme_levelup/static/src/images/contact/c1.jpg b/theme_levelup/static/src/images/contact/c1.jpg
new file mode 100644
index 0000000000..5d06896a97
Binary files /dev/null and b/theme_levelup/static/src/images/contact/c1.jpg differ
diff --git a/theme_levelup/static/src/images/creative/craetive (1).jpg b/theme_levelup/static/src/images/creative/craetive (1).jpg
new file mode 100644
index 0000000000..cb8117eea1
Binary files /dev/null and b/theme_levelup/static/src/images/creative/craetive (1).jpg differ
diff --git a/theme_levelup/static/src/images/creative/craetive (2).jpg b/theme_levelup/static/src/images/creative/craetive (2).jpg
new file mode 100644
index 0000000000..11ee39ea5d
Binary files /dev/null and b/theme_levelup/static/src/images/creative/craetive (2).jpg differ
diff --git a/theme_levelup/static/src/images/creative/craetive (3).jpg b/theme_levelup/static/src/images/creative/craetive (3).jpg
new file mode 100644
index 0000000000..cee7cf3982
Binary files /dev/null and b/theme_levelup/static/src/images/creative/craetive (3).jpg differ
diff --git a/theme_levelup/static/src/images/featured/featured (1).jpg b/theme_levelup/static/src/images/featured/featured (1).jpg
new file mode 100644
index 0000000000..57a9cebf41
Binary files /dev/null and b/theme_levelup/static/src/images/featured/featured (1).jpg differ
diff --git a/theme_levelup/static/src/images/featured/featured (2).jpg b/theme_levelup/static/src/images/featured/featured (2).jpg
new file mode 100644
index 0000000000..17d70102bb
Binary files /dev/null and b/theme_levelup/static/src/images/featured/featured (2).jpg differ
diff --git a/theme_levelup/static/src/images/featured/featured (3).jpg b/theme_levelup/static/src/images/featured/featured (3).jpg
new file mode 100644
index 0000000000..6a67986cb1
Binary files /dev/null and b/theme_levelup/static/src/images/featured/featured (3).jpg differ
diff --git a/theme_levelup/static/src/images/featured/featured (4).jpg b/theme_levelup/static/src/images/featured/featured (4).jpg
new file mode 100644
index 0000000000..880716b0f2
Binary files /dev/null and b/theme_levelup/static/src/images/featured/featured (4).jpg differ
diff --git a/theme_levelup/static/src/images/featured/featured (5).jpg b/theme_levelup/static/src/images/featured/featured (5).jpg
new file mode 100644
index 0000000000..578e22b788
Binary files /dev/null and b/theme_levelup/static/src/images/featured/featured (5).jpg differ
diff --git a/theme_levelup/static/src/images/featured/featured (6).jpg b/theme_levelup/static/src/images/featured/featured (6).jpg
new file mode 100644
index 0000000000..afa6aec325
Binary files /dev/null and b/theme_levelup/static/src/images/featured/featured (6).jpg differ
diff --git a/theme_levelup/static/src/images/gallery/g1 (1).png b/theme_levelup/static/src/images/gallery/g1 (1).png
new file mode 100644
index 0000000000..0c2565c572
Binary files /dev/null and b/theme_levelup/static/src/images/gallery/g1 (1).png differ
diff --git a/theme_levelup/static/src/images/gallery/g1 (2).png b/theme_levelup/static/src/images/gallery/g1 (2).png
new file mode 100644
index 0000000000..a5a3c66b83
Binary files /dev/null and b/theme_levelup/static/src/images/gallery/g1 (2).png differ
diff --git a/theme_levelup/static/src/images/gallery/g1 (3).png b/theme_levelup/static/src/images/gallery/g1 (3).png
new file mode 100644
index 0000000000..6d27abf8b3
Binary files /dev/null and b/theme_levelup/static/src/images/gallery/g1 (3).png differ
diff --git a/theme_levelup/static/src/images/gallery/g1 (4).png b/theme_levelup/static/src/images/gallery/g1 (4).png
new file mode 100644
index 0000000000..5d879e8b20
Binary files /dev/null and b/theme_levelup/static/src/images/gallery/g1 (4).png differ
diff --git a/theme_levelup/static/src/images/latest/latest1.jpg b/theme_levelup/static/src/images/latest/latest1.jpg
new file mode 100644
index 0000000000..4094fb5289
Binary files /dev/null and b/theme_levelup/static/src/images/latest/latest1.jpg differ
diff --git a/theme_levelup/static/src/images/latest/latest2.jpg b/theme_levelup/static/src/images/latest/latest2.jpg
new file mode 100644
index 0000000000..2002a1b31d
Binary files /dev/null and b/theme_levelup/static/src/images/latest/latest2.jpg differ
diff --git a/theme_levelup/static/src/images/latest/latest3.jpg b/theme_levelup/static/src/images/latest/latest3.jpg
new file mode 100644
index 0000000000..e7860e3d33
Binary files /dev/null and b/theme_levelup/static/src/images/latest/latest3.jpg differ
diff --git a/theme_levelup/static/src/images/logo/logo.svg b/theme_levelup/static/src/images/logo/logo.svg
new file mode 100644
index 0000000000..7659f1a37a
--- /dev/null
+++ b/theme_levelup/static/src/images/logo/logo.svg
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/static/src/images/portfolio/fil (1).jpg b/theme_levelup/static/src/images/portfolio/fil (1).jpg
new file mode 100644
index 0000000000..c360eda4fe
Binary files /dev/null and b/theme_levelup/static/src/images/portfolio/fil (1).jpg differ
diff --git a/theme_levelup/static/src/images/portfolio/fil (2).jpg b/theme_levelup/static/src/images/portfolio/fil (2).jpg
new file mode 100644
index 0000000000..2fb0c03d06
Binary files /dev/null and b/theme_levelup/static/src/images/portfolio/fil (2).jpg differ
diff --git a/theme_levelup/static/src/images/portfolio/fil (3).jpg b/theme_levelup/static/src/images/portfolio/fil (3).jpg
new file mode 100644
index 0000000000..0e3c84283e
Binary files /dev/null and b/theme_levelup/static/src/images/portfolio/fil (3).jpg differ
diff --git a/theme_levelup/static/src/images/portfolio/fil (4).jpg b/theme_levelup/static/src/images/portfolio/fil (4).jpg
new file mode 100644
index 0000000000..a1e3997a19
Binary files /dev/null and b/theme_levelup/static/src/images/portfolio/fil (4).jpg differ
diff --git a/theme_levelup/static/src/images/portfolio/fil (5).jpg b/theme_levelup/static/src/images/portfolio/fil (5).jpg
new file mode 100644
index 0000000000..fc4a1d22e9
Binary files /dev/null and b/theme_levelup/static/src/images/portfolio/fil (5).jpg differ
diff --git a/theme_levelup/static/src/images/portfolio/fil (6).jpg b/theme_levelup/static/src/images/portfolio/fil (6).jpg
new file mode 100644
index 0000000000..9bf152239d
Binary files /dev/null and b/theme_levelup/static/src/images/portfolio/fil (6).jpg differ
diff --git a/theme_levelup/static/src/images/service/boss-workers-meeting.jpg b/theme_levelup/static/src/images/service/boss-workers-meeting.jpg
new file mode 100644
index 0000000000..3d1800f220
Binary files /dev/null and b/theme_levelup/static/src/images/service/boss-workers-meeting.jpg differ
diff --git a/theme_levelup/static/src/images/service/service-bg.jpg b/theme_levelup/static/src/images/service/service-bg.jpg
new file mode 100644
index 0000000000..9506e732f8
Binary files /dev/null and b/theme_levelup/static/src/images/service/service-bg.jpg differ
diff --git a/theme_levelup/static/src/images/service/service-left.jpg b/theme_levelup/static/src/images/service/service-left.jpg
new file mode 100644
index 0000000000..86bf09ac5c
Binary files /dev/null and b/theme_levelup/static/src/images/service/service-left.jpg differ
diff --git a/theme_levelup/static/src/images/service_page/bruce-mars-8YG31Xn4dSw-unsplash.jpg b/theme_levelup/static/src/images/service_page/bruce-mars-8YG31Xn4dSw-unsplash.jpg
new file mode 100644
index 0000000000..8a87b52716
Binary files /dev/null and b/theme_levelup/static/src/images/service_page/bruce-mars-8YG31Xn4dSw-unsplash.jpg differ
diff --git a/theme_levelup/static/src/images/service_page/photo-successful-handsome-business-man-with-his-team-working-office.jpg b/theme_levelup/static/src/images/service_page/photo-successful-handsome-business-man-with-his-team-working-office.jpg
new file mode 100644
index 0000000000..450d7096d5
Binary files /dev/null and b/theme_levelup/static/src/images/service_page/photo-successful-handsome-business-man-with-his-team-working-office.jpg differ
diff --git a/theme_levelup/static/src/images/service_page/portrait-handsome-smiling-serious-indian-man.jpg b/theme_levelup/static/src/images/service_page/portrait-handsome-smiling-serious-indian-man.jpg
new file mode 100644
index 0000000000..81472c5da7
Binary files /dev/null and b/theme_levelup/static/src/images/service_page/portrait-handsome-smiling-serious-indian-man.jpg differ
diff --git a/theme_levelup/static/src/images/snippet.icon/About.png b/theme_levelup/static/src/images/snippet.icon/About.png
new file mode 100644
index 0000000000..14f319f063
Binary files /dev/null and b/theme_levelup/static/src/images/snippet.icon/About.png differ
diff --git a/theme_levelup/static/src/images/snippet.icon/Award.png b/theme_levelup/static/src/images/snippet.icon/Award.png
new file mode 100644
index 0000000000..cce3ca4cb1
Binary files /dev/null and b/theme_levelup/static/src/images/snippet.icon/Award.png differ
diff --git a/theme_levelup/static/src/images/snippet.icon/Banner.png b/theme_levelup/static/src/images/snippet.icon/Banner.png
new file mode 100644
index 0000000000..29a9203d91
Binary files /dev/null and b/theme_levelup/static/src/images/snippet.icon/Banner.png differ
diff --git a/theme_levelup/static/src/images/snippet.icon/Blog.png b/theme_levelup/static/src/images/snippet.icon/Blog.png
new file mode 100644
index 0000000000..8ae5a768c3
Binary files /dev/null and b/theme_levelup/static/src/images/snippet.icon/Blog.png differ
diff --git a/theme_levelup/static/src/images/snippet.icon/client.png b/theme_levelup/static/src/images/snippet.icon/client.png
new file mode 100644
index 0000000000..67d63b4573
Binary files /dev/null and b/theme_levelup/static/src/images/snippet.icon/client.png differ
diff --git a/theme_levelup/static/src/images/snippet.icon/excited.png b/theme_levelup/static/src/images/snippet.icon/excited.png
new file mode 100644
index 0000000000..90f43a9537
Binary files /dev/null and b/theme_levelup/static/src/images/snippet.icon/excited.png differ
diff --git a/theme_levelup/static/src/images/snippet.icon/feature.png b/theme_levelup/static/src/images/snippet.icon/feature.png
new file mode 100644
index 0000000000..d3bf30dfac
Binary files /dev/null and b/theme_levelup/static/src/images/snippet.icon/feature.png differ
diff --git a/theme_levelup/static/src/images/snippet.icon/gallery.png b/theme_levelup/static/src/images/snippet.icon/gallery.png
new file mode 100644
index 0000000000..9bf315337e
Binary files /dev/null and b/theme_levelup/static/src/images/snippet.icon/gallery.png differ
diff --git a/theme_levelup/static/src/images/snippet.icon/service.png b/theme_levelup/static/src/images/snippet.icon/service.png
new file mode 100644
index 0000000000..39c5d97647
Binary files /dev/null and b/theme_levelup/static/src/images/snippet.icon/service.png differ
diff --git a/theme_levelup/static/src/images/snippet.icon/testimonial.png b/theme_levelup/static/src/images/snippet.icon/testimonial.png
new file mode 100644
index 0000000000..b19d830c6c
Binary files /dev/null and b/theme_levelup/static/src/images/snippet.icon/testimonial.png differ
diff --git a/theme_levelup/static/src/images/team/Ellipse 26.png b/theme_levelup/static/src/images/team/Ellipse 26.png
new file mode 100644
index 0000000000..709a0c18bf
Binary files /dev/null and b/theme_levelup/static/src/images/team/Ellipse 26.png differ
diff --git a/theme_levelup/static/src/images/team/Ellipse 27.png b/theme_levelup/static/src/images/team/Ellipse 27.png
new file mode 100644
index 0000000000..fbf1df62af
Binary files /dev/null and b/theme_levelup/static/src/images/team/Ellipse 27.png differ
diff --git a/theme_levelup/static/src/images/team/Ellipse 28.png b/theme_levelup/static/src/images/team/Ellipse 28.png
new file mode 100644
index 0000000000..2a5d7264ce
Binary files /dev/null and b/theme_levelup/static/src/images/team/Ellipse 28.png differ
diff --git a/theme_levelup/static/src/images/team/Ellipse 29.png b/theme_levelup/static/src/images/team/Ellipse 29.png
new file mode 100644
index 0000000000..808208b27b
Binary files /dev/null and b/theme_levelup/static/src/images/team/Ellipse 29.png differ
diff --git a/theme_levelup/static/src/images/team/Rectangle 124.png b/theme_levelup/static/src/images/team/Rectangle 124.png
new file mode 100644
index 0000000000..7c780cf48c
Binary files /dev/null and b/theme_levelup/static/src/images/team/Rectangle 124.png differ
diff --git a/theme_levelup/static/src/images/team/aa.png b/theme_levelup/static/src/images/team/aa.png
new file mode 100644
index 0000000000..063de509c9
Binary files /dev/null and b/theme_levelup/static/src/images/team/aa.png differ
diff --git a/theme_levelup/static/src/images/team/as.png b/theme_levelup/static/src/images/team/as.png
new file mode 100644
index 0000000000..2dc530e658
Binary files /dev/null and b/theme_levelup/static/src/images/team/as.png differ
diff --git a/theme_levelup/static/src/images/team/business-people-office.jpg b/theme_levelup/static/src/images/team/business-people-office.jpg
new file mode 100644
index 0000000000..a44f4a840b
Binary files /dev/null and b/theme_levelup/static/src/images/team/business-people-office.jpg differ
diff --git a/theme_levelup/static/src/images/team/business-team-giving-high-five.png b/theme_levelup/static/src/images/team/business-team-giving-high-five.png
new file mode 100644
index 0000000000..efa2bf712e
Binary files /dev/null and b/theme_levelup/static/src/images/team/business-team-giving-high-five.png differ
diff --git a/theme_levelup/static/src/images/team/business-team-working-office-discussing-job-issues.jpg b/theme_levelup/static/src/images/team/business-team-working-office-discussing-job-issues.jpg
new file mode 100644
index 0000000000..c21c80e445
Binary files /dev/null and b/theme_levelup/static/src/images/team/business-team-working-office-discussing-job-issues.jpg differ
diff --git a/theme_levelup/static/src/images/team/c_t2.jpg b/theme_levelup/static/src/images/team/c_t2.jpg
new file mode 100644
index 0000000000..365779a2d7
Binary files /dev/null and b/theme_levelup/static/src/images/team/c_t2.jpg differ
diff --git a/theme_levelup/static/src/images/team/lead (1).png b/theme_levelup/static/src/images/team/lead (1).png
new file mode 100644
index 0000000000..8b05ce359d
Binary files /dev/null and b/theme_levelup/static/src/images/team/lead (1).png differ
diff --git a/theme_levelup/static/src/images/team/lead (2).png b/theme_levelup/static/src/images/team/lead (2).png
new file mode 100644
index 0000000000..954b3441d3
Binary files /dev/null and b/theme_levelup/static/src/images/team/lead (2).png differ
diff --git a/theme_levelup/static/src/images/team/lead (3).png b/theme_levelup/static/src/images/team/lead (3).png
new file mode 100644
index 0000000000..27f3587be3
Binary files /dev/null and b/theme_levelup/static/src/images/team/lead (3).png differ
diff --git a/theme_levelup/static/src/images/team/lead (4).png b/theme_levelup/static/src/images/team/lead (4).png
new file mode 100644
index 0000000000..54236faf7c
Binary files /dev/null and b/theme_levelup/static/src/images/team/lead (4).png differ
diff --git a/theme_levelup/static/src/images/team/tr (1).png b/theme_levelup/static/src/images/team/tr (1).png
new file mode 100644
index 0000000000..9757e3bffe
Binary files /dev/null and b/theme_levelup/static/src/images/team/tr (1).png differ
diff --git a/theme_levelup/static/src/images/team/tr (2).png b/theme_levelup/static/src/images/team/tr (2).png
new file mode 100644
index 0000000000..e43ae1f967
Binary files /dev/null and b/theme_levelup/static/src/images/team/tr (2).png differ
diff --git a/theme_levelup/static/src/images/team/tr (3).png b/theme_levelup/static/src/images/team/tr (3).png
new file mode 100644
index 0000000000..4f3d6ca402
Binary files /dev/null and b/theme_levelup/static/src/images/team/tr (3).png differ
diff --git a/theme_levelup/static/src/images/team/tr (4).png b/theme_levelup/static/src/images/team/tr (4).png
new file mode 100644
index 0000000000..77623d8118
Binary files /dev/null and b/theme_levelup/static/src/images/team/tr (4).png differ
diff --git a/theme_levelup/static/src/images/testimoinial/Yellow_background.jpg b/theme_levelup/static/src/images/testimoinial/Yellow_background.jpg
new file mode 100644
index 0000000000..3ca630c62c
Binary files /dev/null and b/theme_levelup/static/src/images/testimoinial/Yellow_background.jpg differ
diff --git a/theme_levelup/static/src/images/testimoinial/c_t1.jpg b/theme_levelup/static/src/images/testimoinial/c_t1.jpg
new file mode 100644
index 0000000000..0012e9c07a
Binary files /dev/null and b/theme_levelup/static/src/images/testimoinial/c_t1.jpg differ
diff --git a/theme_levelup/static/src/images/testimoinial/c_t2.jpg b/theme_levelup/static/src/images/testimoinial/c_t2.jpg
new file mode 100644
index 0000000000..365779a2d7
Binary files /dev/null and b/theme_levelup/static/src/images/testimoinial/c_t2.jpg differ
diff --git a/theme_levelup/static/src/images/testimoinial/c_t3.jpg b/theme_levelup/static/src/images/testimoinial/c_t3.jpg
new file mode 100644
index 0000000000..00f1a6d722
Binary files /dev/null and b/theme_levelup/static/src/images/testimoinial/c_t3.jpg differ
diff --git a/theme_levelup/static/src/images/testimoinial/f.png b/theme_levelup/static/src/images/testimoinial/f.png
new file mode 100644
index 0000000000..a8ace58fd1
Binary files /dev/null and b/theme_levelup/static/src/images/testimoinial/f.png differ
diff --git a/theme_levelup/static/src/images/testimoinial/fds.png b/theme_levelup/static/src/images/testimoinial/fds.png
new file mode 100644
index 0000000000..27699ca811
Binary files /dev/null and b/theme_levelup/static/src/images/testimoinial/fds.png differ
diff --git a/theme_levelup/static/src/images/testimoinial/testimonial.jpg b/theme_levelup/static/src/images/testimoinial/testimonial.jpg
new file mode 100644
index 0000000000..a7fd6e62f3
Binary files /dev/null and b/theme_levelup/static/src/images/testimoinial/testimonial.jpg differ
diff --git a/theme_levelup/static/src/js/about_slider.js b/theme_levelup/static/src/js/about_slider.js
new file mode 100644
index 0000000000..66a6b25103
--- /dev/null
+++ b/theme_levelup/static/src/js/about_slider.js
@@ -0,0 +1,33 @@
+/** @odoo-module */
+import PublicWidget from "@web/legacy/js/public/public_widget"
+
+export const aboutSlider = PublicWidget.Widget.extend({
+ selector: "#wrapwrap",
+ /* Start function for calling slider function */
+ start() {
+ this.about_carousel()
+ },
+ /* Function for about page carousel slider */
+ about_carousel() {
+ if(this.$el.find("#owl-slider-8")){
+ this.$el.find("#owl-slider-8").owlCarousel({
+ items: 3,
+ loop: true,
+ margin: 40,
+ stagePadding: 0,
+ smartSpeed: 450,
+ autoplay: true,
+ autoPlaySpeed: 3000,
+ autoPlayTimeout: 1000,
+ autoplayHoverPause: true,
+ dots: true,
+ nav: true,
+ animateIn: "fadeIn",
+ animateOut: "fadeOut",
+ center: true,
+ })
+ }
+ },
+})
+
+PublicWidget.registry.aboutSlider = aboutSlider
diff --git a/theme_levelup/static/src/js/index.js b/theme_levelup/static/src/js/index.js
new file mode 100644
index 0000000000..22ee076355
--- /dev/null
+++ b/theme_levelup/static/src/js/index.js
@@ -0,0 +1,34 @@
+/** @odoo-module */
+import PublicWidget from "@web/legacy/js/public/public_widget"
+
+var header
+var nav
+var pos
+
+export const themeIndex = PublicWidget.Widget.extend({
+ selector: "#wrapwrap",
+ events: {
+ 'wheel main': '_handleScroll',
+ },
+ /* Start function fetching the classes */
+ start() {
+ header = this.$el.find(".header_modern_light")
+ nav = this.$el.find('.navigation')
+ pos = header.position()
+ },
+ /* Function for website header scroll */
+ _handleScroll() {
+ var windowpos = $('#wrapwrap').scrollTop();
+ if (windowpos >= pos.top & windowpos >= 100) {
+ nav.addClass("fadeInDown");
+ nav.addClass("bg_white");
+ nav.addClass("b_shadow");
+ } else {
+ nav.removeClass("fadeInDown");
+ nav.removeClass("bg_white");
+ nav.removeClass("b_shadow");
+ }
+ },
+})
+
+PublicWidget.registry.themeIndex = themeIndex
diff --git a/theme_levelup/static/src/js/owl.carousel.js b/theme_levelup/static/src/js/owl.carousel.js
new file mode 100644
index 0000000000..66c67ebe09
--- /dev/null
+++ b/theme_levelup/static/src/js/owl.carousel.js
@@ -0,0 +1,3448 @@
+/**
+ * Owl Carousel v2.3.4
+ * Copyright 2013-2018 David Deutsch
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
+ */
+/**
+ * Owl carousel
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ * @todo Lazy Load Icon
+ * @todo prevent animationend bubling
+ * @todo itemsScaleUp
+ * @todo Test Zepto
+ * @todo stagePadding calculate wrong active classes
+ */
+;(function($, window, document, undefined) {
+
+ /**
+ * Creates a carousel.
+ * @class The Owl Carousel.
+ * @public
+ * @param {HTMLElement|jQuery} element - The element to create the carousel for.
+ * @param {Object} [options] - The options
+ */
+ function Owl(element, options) {
+
+ /**
+ * Current settings for the carousel.
+ * @public
+ */
+ this.settings = null;
+
+ /**
+ * Current options set by the caller including defaults.
+ * @public
+ */
+ this.options = $.extend({}, Owl.Defaults, options);
+
+ /**
+ * Plugin element.
+ * @public
+ */
+ this.$element = $(element);
+
+ /**
+ * Proxied event handlers.
+ * @protected
+ */
+ this._handlers = {};
+
+ /**
+ * References to the running plugins of this carousel.
+ * @protected
+ */
+ this._plugins = {};
+
+ /**
+ * Currently suppressed events to prevent them from being retriggered.
+ * @protected
+ */
+ this._supress = {};
+
+ /**
+ * Absolute current position.
+ * @protected
+ */
+ this._current = null;
+
+ /**
+ * Animation speed in milliseconds.
+ * @protected
+ */
+ this._speed = null;
+
+ /**
+ * Coordinates of all items in pixel.
+ * @todo The name of this member is missleading.
+ * @protected
+ */
+ this._coordinates = [];
+
+ /**
+ * Current breakpoint.
+ * @todo Real media queries would be nice.
+ * @protected
+ */
+ this._breakpoint = null;
+
+ /**
+ * Current width of the plugin element.
+ */
+ this._width = null;
+
+ /**
+ * All real items.
+ * @protected
+ */
+ this._items = [];
+
+ /**
+ * All cloned items.
+ * @protected
+ */
+ this._clones = [];
+
+ /**
+ * Merge values of all items.
+ * @todo Maybe this could be part of a plugin.
+ * @protected
+ */
+ this._mergers = [];
+
+ /**
+ * Widths of all items.
+ */
+ this._widths = [];
+
+ /**
+ * Invalidated parts within the update process.
+ * @protected
+ */
+ this._invalidated = {};
+
+ /**
+ * Ordered list of workers for the update process.
+ * @protected
+ */
+ this._pipe = [];
+
+ /**
+ * Current state information for the drag operation.
+ * @todo #261
+ * @protected
+ */
+ this._drag = {
+ time: null,
+ target: null,
+ pointer: null,
+ stage: {
+ start: null,
+ current: null
+ },
+ direction: null
+ };
+
+ /**
+ * Current state information and their tags.
+ * @type {Object}
+ * @protected
+ */
+ this._states = {
+ current: {},
+ tags: {
+ 'initializing': [ 'busy' ],
+ 'animating': [ 'busy' ],
+ 'dragging': [ 'interacting' ]
+ }
+ };
+
+ $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
+ this._handlers[handler] = $.proxy(this[handler], this);
+ }, this));
+
+ $.each(Owl.Plugins, $.proxy(function(key, plugin) {
+ this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
+ = new plugin(this);
+ }, this));
+
+ $.each(Owl.Workers, $.proxy(function(priority, worker) {
+ this._pipe.push({
+ 'filter': worker.filter,
+ 'run': $.proxy(worker.run, this)
+ });
+ }, this));
+
+ this.setup();
+ this.initialize();
+ }
+
+ /**
+ * Default options for the carousel.
+ * @public
+ */
+ Owl.Defaults = {
+ items: 3,
+ loop: false,
+ center: false,
+ rewind: false,
+ checkVisibility: true,
+
+ mouseDrag: true,
+ touchDrag: true,
+ pullDrag: true,
+ freeDrag: false,
+
+ margin: 0,
+ stagePadding: 0,
+
+ merge: false,
+ mergeFit: true,
+ autoWidth: false,
+
+ startPosition: 0,
+ rtl: false,
+
+ smartSpeed: 250,
+ fluidSpeed: false,
+ dragEndSpeed: false,
+
+ responsive: {},
+ responsiveRefreshRate: 200,
+ responsiveBaseElement: window,
+
+ fallbackEasing: 'swing',
+ slideTransition: '',
+
+ info: false,
+
+ nestedItemSelector: false,
+ itemElement: 'div',
+ stageElement: 'div',
+
+ refreshClass: 'owl-refresh',
+ loadedClass: 'owl-loaded',
+ loadingClass: 'owl-loading',
+ rtlClass: 'owl-rtl',
+ responsiveClass: 'owl-responsive',
+ dragClass: 'owl-drag',
+ itemClass: 'owl-item',
+ stageClass: 'owl-stage',
+ stageOuterClass: 'owl-stage-outer',
+ grabClass: 'owl-grab'
+ };
+
+ /**
+ * Enumeration for width.
+ * @public
+ * @readonly
+ * @enum {String}
+ */
+ Owl.Width = {
+ Default: 'default',
+ Inner: 'inner',
+ Outer: 'outer'
+ };
+
+ /**
+ * Enumeration for types.
+ * @public
+ * @readonly
+ * @enum {String}
+ */
+ Owl.Type = {
+ Event: 'event',
+ State: 'state'
+ };
+
+ /**
+ * Contains all registered plugins.
+ * @public
+ */
+ Owl.Plugins = {};
+
+ /**
+ * List of workers involved in the update process.
+ */
+ Owl.Workers = [ {
+ filter: [ 'width', 'settings' ],
+ run: function() {
+ this._width = this.$element.width();
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ cache.current = this._items && this._items[this.relative(this._current)];
+ }
+ }, {
+ filter: [ 'items', 'settings' ],
+ run: function() {
+ this.$stage.children('.cloned').remove();
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ var margin = this.settings.margin || '',
+ grid = !this.settings.autoWidth,
+ rtl = this.settings.rtl,
+ css = {
+ 'width': 'auto',
+ 'margin-left': rtl ? margin : '',
+ 'margin-right': rtl ? '' : margin
+ };
+
+ !grid && this.$stage.children().css(css);
+
+ cache.css = css;
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
+ merge = null,
+ iterator = this._items.length,
+ grid = !this.settings.autoWidth,
+ widths = [];
+
+ cache.items = {
+ merge: false,
+ width: width
+ };
+
+ while (iterator--) {
+ merge = this._mergers[iterator];
+ merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
+
+ cache.items.merge = merge > 1 || cache.items.merge;
+
+ widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
+ }
+
+ this._widths = widths;
+ }
+ }, {
+ filter: [ 'items', 'settings' ],
+ run: function() {
+ var clones = [],
+ items = this._items,
+ settings = this.settings,
+ // TODO: Should be computed from number of min width items in stage
+ view = Math.max(settings.items * 2, 4),
+ size = Math.ceil(items.length / 2) * 2,
+ repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
+ append = '',
+ prepend = '';
+
+ repeat /= 2;
+
+ while (repeat > 0) {
+ // Switch to only using appended clones
+ clones.push(this.normalize(clones.length / 2, true));
+ append = append + items[clones[clones.length - 1]][0].outerHTML;
+ clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
+ prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
+ repeat -= 1;
+ }
+
+ this._clones = clones;
+
+ $(append).addClass('cloned').appendTo(this.$stage);
+ $(prepend).addClass('cloned').prependTo(this.$stage);
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function() {
+ var rtl = this.settings.rtl ? 1 : -1,
+ size = this._clones.length + this._items.length,
+ iterator = -1,
+ previous = 0,
+ current = 0,
+ coordinates = [];
+
+ while (++iterator < size) {
+ previous = coordinates[iterator - 1] || 0;
+ current = this._widths[this.relative(iterator)] + this.settings.margin;
+ coordinates.push(previous + current * rtl);
+ }
+
+ this._coordinates = coordinates;
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function() {
+ var padding = this.settings.stagePadding,
+ coordinates = this._coordinates,
+ css = {
+ 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
+ 'padding-left': padding || '',
+ 'padding-right': padding || ''
+ };
+
+ this.$stage.css(css);
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ var iterator = this._coordinates.length,
+ grid = !this.settings.autoWidth,
+ items = this.$stage.children();
+
+ if (grid && cache.items.merge) {
+ while (iterator--) {
+ cache.css.width = this._widths[this.relative(iterator)];
+ items.eq(iterator).css(cache.css);
+ }
+ } else if (grid) {
+ cache.css.width = cache.items.width;
+ items.css(cache.css);
+ }
+ }
+ }, {
+ filter: [ 'items' ],
+ run: function() {
+ this._coordinates.length < 1 && this.$stage.removeAttr('style');
+ }
+ }, {
+ filter: [ 'width', 'items', 'settings' ],
+ run: function(cache) {
+ cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
+ cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
+ this.reset(cache.current);
+ }
+ }, {
+ filter: [ 'position' ],
+ run: function() {
+ this.animate(this.coordinates(this._current));
+ }
+ }, {
+ filter: [ 'width', 'position', 'items', 'settings' ],
+ run: function() {
+ var rtl = this.settings.rtl ? 1 : -1,
+ padding = this.settings.stagePadding * 2,
+ begin = this.coordinates(this.current()) + padding,
+ end = begin + this.width() * rtl,
+ inner, outer, matches = [], i, n;
+
+ for (i = 0, n = this._coordinates.length; i < n; i++) {
+ inner = this._coordinates[i - 1] || 0;
+ outer = Math.abs(this._coordinates[i]) + padding * rtl;
+
+ if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
+ || (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
+ matches.push(i);
+ }
+ }
+
+ this.$stage.children('.active').removeClass('active');
+ this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
+
+ this.$stage.children('.center').removeClass('center');
+ if (this.settings.center) {
+ this.$stage.children().eq(this.current()).addClass('center');
+ }
+ }
+ } ];
+
+ /**
+ * Create the stage DOM element
+ */
+ Owl.prototype.initializeStage = function() {
+ this.$stage = this.$element.find('.' + this.settings.stageClass);
+
+ // if the stage is already in the DOM, grab it and skip stage initialization
+ if (this.$stage.length) {
+ return;
+ }
+
+ this.$element.addClass(this.options.loadingClass);
+
+ // create stage
+ this.$stage = $('<' + this.settings.stageElement + '>', {
+ "class": this.settings.stageClass
+ }).wrap( $( '
', {
+ "class": this.settings.stageOuterClass
+ }));
+
+ // append stage
+ this.$element.append(this.$stage.parent());
+ };
+
+ /**
+ * Create item DOM elements
+ */
+ Owl.prototype.initializeItems = function() {
+ var $items = this.$element.find('.owl-item');
+
+ // if the items are already in the DOM, grab them and skip item initialization
+ if ($items.length) {
+ this._items = $items.get().map(function(item) {
+ return $(item);
+ });
+
+ this._mergers = this._items.map(function() {
+ return 1;
+ });
+
+ this.refresh();
+
+ return;
+ }
+
+ // append content
+ this.replace(this.$element.children().not(this.$stage.parent()));
+
+ // check visibility
+ if (this.isVisible()) {
+ // update view
+ this.refresh();
+ } else {
+ // invalidate width
+ this.invalidate('width');
+ }
+
+ this.$element
+ .removeClass(this.options.loadingClass)
+ .addClass(this.options.loadedClass);
+ };
+
+ /**
+ * Initializes the carousel.
+ * @protected
+ */
+ Owl.prototype.initialize = function() {
+ this.enter('initializing');
+ this.trigger('initialize');
+
+ this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
+
+ if (this.settings.autoWidth && !this.is('pre-loading')) {
+ var imgs, nestedSelector, width;
+ imgs = this.$element.find('img');
+ nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
+ width = this.$element.children(nestedSelector).width();
+
+ if (imgs.length && width <= 0) {
+ this.preloadAutoWidthImages(imgs);
+ }
+ }
+
+ this.initializeStage();
+ this.initializeItems();
+
+ // register event handlers
+ this.registerEventHandlers();
+
+ this.leave('initializing');
+ this.trigger('initialized');
+ };
+
+ /**
+ * @returns {Boolean} visibility of $element
+ * if you know the carousel will always be visible you can set `checkVisibility` to `false` to
+ * prevent the expensive browser layout forced reflow the $element.is(':visible') does
+ */
+ Owl.prototype.isVisible = function() {
+ return this.settings.checkVisibility
+ ? this.$element.is(':visible')
+ : true;
+ };
+
+ /**
+ * Setups the current settings.
+ * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
+ * @todo Support for media queries by using `matchMedia` would be nice.
+ * @public
+ */
+ Owl.prototype.setup = function() {
+ var viewport = this.viewport(),
+ overwrites = this.options.responsive,
+ match = -1,
+ settings = null;
+
+ if (!overwrites) {
+ settings = $.extend({}, this.options);
+ } else {
+ $.each(overwrites, function(breakpoint) {
+ if (breakpoint <= viewport && breakpoint > match) {
+ match = Number(breakpoint);
+ }
+ });
+
+ settings = $.extend({}, this.options, overwrites[match]);
+ if (typeof settings.stagePadding === 'function') {
+ settings.stagePadding = settings.stagePadding();
+ }
+ delete settings.responsive;
+
+ // responsive class
+ if (settings.responsiveClass) {
+ this.$element.attr('class',
+ this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
+ );
+ }
+ }
+
+ this.trigger('change', { property: { name: 'settings', value: settings } });
+ this._breakpoint = match;
+ this.settings = settings;
+ this.invalidate('settings');
+ this.trigger('changed', { property: { name: 'settings', value: this.settings } });
+ };
+
+ /**
+ * Updates option logic if necessery.
+ * @protected
+ */
+ Owl.prototype.optionsLogic = function() {
+ if (this.settings.autoWidth) {
+ this.settings.stagePadding = false;
+ this.settings.merge = false;
+ }
+ };
+
+ /**
+ * Prepares an item before add.
+ * @todo Rename event parameter `content` to `item`.
+ * @protected
+ * @returns {jQuery|HTMLElement} - The item container.
+ */
+ Owl.prototype.prepare = function(item) {
+ var event = this.trigger('prepare', { content: item });
+
+ if (!event.data) {
+ event.data = $('<' + this.settings.itemElement + '/>')
+ .addClass(this.options.itemClass).append(item)
+ }
+
+ this.trigger('prepared', { content: event.data });
+
+ return event.data;
+ };
+
+ /**
+ * Updates the view.
+ * @public
+ */
+ Owl.prototype.update = function() {
+ var i = 0,
+ n = this._pipe.length,
+ filter = $.proxy(function(p) { return this[p] }, this._invalidated),
+ cache = {};
+
+ while (i < n) {
+ if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
+ this._pipe[i].run(cache);
+ }
+ i++;
+ }
+
+ this._invalidated = {};
+
+ !this.is('valid') && this.enter('valid');
+ };
+
+ /**
+ * Gets the width of the view.
+ * @public
+ * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
+ * @returns {Number} - The width of the view in pixel.
+ */
+ Owl.prototype.width = function(dimension) {
+ dimension = dimension || Owl.Width.Default;
+ switch (dimension) {
+ case Owl.Width.Inner:
+ case Owl.Width.Outer:
+ return this._width;
+ default:
+ return this._width - this.settings.stagePadding * 2 + this.settings.margin;
+ }
+ };
+
+ /**
+ * Refreshes the carousel primarily for adaptive purposes.
+ * @public
+ */
+ Owl.prototype.refresh = function() {
+ this.enter('refreshing');
+ this.trigger('refresh');
+
+ this.setup();
+
+ this.optionsLogic();
+
+ this.$element.addClass(this.options.refreshClass);
+
+ this.update();
+
+ this.$element.removeClass(this.options.refreshClass);
+
+ this.leave('refreshing');
+ this.trigger('refreshed');
+ };
+
+ /**
+ * Checks window `resize` event.
+ * @protected
+ */
+ Owl.prototype.onThrottledResize = function() {
+ window.clearTimeout(this.resizeTimer);
+ this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
+ };
+
+ /**
+ * Checks window `resize` event.
+ * @protected
+ */
+ Owl.prototype.onResize = function() {
+ if (!this._items.length) {
+ return false;
+ }
+
+ if (this._width === this.$element.width()) {
+ return false;
+ }
+
+ if (!this.isVisible()) {
+ return false;
+ }
+
+ this.enter('resizing');
+
+ if (this.trigger('resize').isDefaultPrevented()) {
+ this.leave('resizing');
+ return false;
+ }
+
+ this.invalidate('width');
+
+ this.refresh();
+
+ this.leave('resizing');
+ this.trigger('resized');
+ };
+
+ /**
+ * Registers event handlers.
+ * @todo Check `msPointerEnabled`
+ * @todo #261
+ * @protected
+ */
+ Owl.prototype.registerEventHandlers = function() {
+ if ($.support.transition) {
+ this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
+ }
+
+ if (this.settings.responsive !== false) {
+ this.on(window, 'resize', this._handlers.onThrottledResize);
+ }
+
+ if (this.settings.mouseDrag) {
+ this.$element.addClass(this.options.dragClass);
+ this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
+ this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
+ }
+
+ if (this.settings.touchDrag){
+ this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
+ this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
+ }
+ };
+
+ /**
+ * Handles `touchstart` and `mousedown` events.
+ * @todo Horizontal swipe threshold as option
+ * @todo #261
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onDragStart = function(event) {
+ var stage = null;
+
+ if (event.which === 3) {
+ return;
+ }
+
+ if ($.support.transform) {
+ stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
+ stage = {
+ x: stage[stage.length === 16 ? 12 : 4],
+ y: stage[stage.length === 16 ? 13 : 5]
+ };
+ } else {
+ stage = this.$stage.position();
+ stage = {
+ x: this.settings.rtl ?
+ stage.left + this.$stage.width() - this.width() + this.settings.margin :
+ stage.left,
+ y: stage.top
+ };
+ }
+
+ if (this.is('animating')) {
+ $.support.transform ? this.animate(stage.x) : this.$stage.stop()
+ this.invalidate('position');
+ }
+
+ this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
+
+ this.speed(0);
+
+ this._drag.time = new Date().getTime();
+ this._drag.target = $(event.target);
+ this._drag.stage.start = stage;
+ this._drag.stage.current = stage;
+ this._drag.pointer = this.pointer(event);
+
+ $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
+
+ $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
+ var delta = this.difference(this._drag.pointer, this.pointer(event));
+
+ $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
+
+ if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
+ return;
+ }
+
+ event.preventDefault();
+
+ this.enter('dragging');
+ this.trigger('drag');
+ }, this));
+ };
+
+ /**
+ * Handles the `touchmove` and `mousemove` events.
+ * @todo #261
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onDragMove = function(event) {
+ var minimum = null,
+ maximum = null,
+ pull = null,
+ delta = this.difference(this._drag.pointer, this.pointer(event)),
+ stage = this.difference(this._drag.stage.start, delta);
+
+ if (!this.is('dragging')) {
+ return;
+ }
+
+ event.preventDefault();
+
+ if (this.settings.loop) {
+ minimum = this.coordinates(this.minimum());
+ maximum = this.coordinates(this.maximum() + 1) - minimum;
+ stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
+ } else {
+ minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
+ maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
+ pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
+ stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
+ }
+
+ this._drag.stage.current = stage;
+
+ this.animate(stage.x);
+ };
+
+ /**
+ * Handles the `touchend` and `mouseup` events.
+ * @todo #261
+ * @todo Threshold for click event
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onDragEnd = function(event) {
+ var delta = this.difference(this._drag.pointer, this.pointer(event)),
+ stage = this._drag.stage.current,
+ direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
+
+ $(document).off('.owl.core');
+
+ this.$element.removeClass(this.options.grabClass);
+
+ if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
+ this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
+ this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
+ this.invalidate('position');
+ this.update();
+
+ this._drag.direction = direction;
+
+ if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
+ this._drag.target.one('click.owl.core', function() { return false; });
+ }
+ }
+
+ if (!this.is('dragging')) {
+ return;
+ }
+
+ this.leave('dragging');
+ this.trigger('dragged');
+ };
+
+ /**
+ * Gets absolute position of the closest item for a coordinate.
+ * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
+ * @protected
+ * @param {Number} coordinate - The coordinate in pixel.
+ * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
+ * @return {Number} - The absolute position of the closest item.
+ */
+ Owl.prototype.closest = function(coordinate, direction) {
+ var position = -1,
+ pull = 30,
+ width = this.width(),
+ coordinates = this.coordinates();
+
+ if (!this.settings.freeDrag) {
+ // check closest item
+ $.each(coordinates, $.proxy(function(index, value) {
+ // on a left pull, check on current index
+ if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
+ position = index;
+ // on a right pull, check on previous index
+ // to do so, subtract width from value and set position = index + 1
+ } else if (direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull) {
+ position = index + 1;
+ } else if (this.op(coordinate, '<', value)
+ && this.op(coordinate, '>', coordinates[index + 1] !== undefined ? coordinates[index + 1] : value - width)) {
+ position = direction === 'left' ? index + 1 : index;
+ }
+ return position === -1;
+ }, this));
+ }
+
+ if (!this.settings.loop) {
+ // non loop boundries
+ if (this.op(coordinate, '>', coordinates[this.minimum()])) {
+ position = coordinate = this.minimum();
+ } else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
+ position = coordinate = this.maximum();
+ }
+ }
+
+ return position;
+ };
+
+ /**
+ * Animates the stage.
+ * @todo #270
+ * @public
+ * @param {Number} coordinate - The coordinate in pixels.
+ */
+ Owl.prototype.animate = function(coordinate) {
+ var animate = this.speed() > 0;
+
+ this.is('animating') && this.onTransitionEnd();
+
+ if (animate) {
+ this.enter('animating');
+ this.trigger('translate');
+ }
+
+ if ($.support.transform3d && $.support.transition) {
+ this.$stage.css({
+ transform: 'translate3d(' + coordinate + 'px,0px,0px)',
+ transition: (this.speed() / 1000) + 's' + (
+ this.settings.slideTransition ? ' ' + this.settings.slideTransition : ''
+ )
+ });
+ } else if (animate) {
+ this.$stage.animate({
+ left: coordinate + 'px'
+ }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
+ } else {
+ this.$stage.css({
+ left: coordinate + 'px'
+ });
+ }
+ };
+
+ /**
+ * Checks whether the carousel is in a specific state or not.
+ * @param {String} state - The state to check.
+ * @returns {Boolean} - The flag which indicates if the carousel is busy.
+ */
+ Owl.prototype.is = function(state) {
+ return this._states.current[state] && this._states.current[state] > 0;
+ };
+
+ /**
+ * Sets the absolute position of the current item.
+ * @public
+ * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
+ * @returns {Number} - The absolute position of the current item.
+ */
+ Owl.prototype.current = function(position) {
+ if (position === undefined) {
+ return this._current;
+ }
+
+ if (this._items.length === 0) {
+ return undefined;
+ }
+
+ position = this.normalize(position);
+
+ if (this._current !== position) {
+ var event = this.trigger('change', { property: { name: 'position', value: position } });
+
+ if (event.data !== undefined) {
+ position = this.normalize(event.data);
+ }
+
+ this._current = position;
+
+ this.invalidate('position');
+
+ this.trigger('changed', { property: { name: 'position', value: this._current } });
+ }
+
+ return this._current;
+ };
+
+ /**
+ * Invalidates the given part of the update routine.
+ * @param {String} [part] - The part to invalidate.
+ * @returns {Array.} - The invalidated parts.
+ */
+ Owl.prototype.invalidate = function(part) {
+ if ($.type(part) === 'string') {
+ this._invalidated[part] = true;
+ this.is('valid') && this.leave('valid');
+ }
+ return $.map(this._invalidated, function(v, i) { return i });
+ };
+
+ /**
+ * Resets the absolute position of the current item.
+ * @public
+ * @param {Number} position - The absolute position of the new item.
+ */
+ Owl.prototype.reset = function(position) {
+ position = this.normalize(position);
+
+ if (position === undefined) {
+ return;
+ }
+
+ this._speed = 0;
+ this._current = position;
+
+ this.suppress([ 'translate', 'translated' ]);
+
+ this.animate(this.coordinates(position));
+
+ this.release([ 'translate', 'translated' ]);
+ };
+
+ /**
+ * Normalizes an absolute or a relative position of an item.
+ * @public
+ * @param {Number} position - The absolute or relative position to normalize.
+ * @param {Boolean} [relative=false] - Whether the given position is relative or not.
+ * @returns {Number} - The normalized position.
+ */
+ Owl.prototype.normalize = function(position, relative) {
+ var n = this._items.length,
+ m = relative ? 0 : this._clones.length;
+
+ if (!this.isNumeric(position) || n < 1) {
+ position = undefined;
+ } else if (position < 0 || position >= n + m) {
+ position = ((position - m / 2) % n + n) % n + m / 2;
+ }
+
+ return position;
+ };
+
+ /**
+ * Converts an absolute position of an item into a relative one.
+ * @public
+ * @param {Number} position - The absolute position to convert.
+ * @returns {Number} - The converted position.
+ */
+ Owl.prototype.relative = function(position) {
+ position -= this._clones.length / 2;
+ return this.normalize(position, true);
+ };
+
+ /**
+ * Gets the maximum position for the current item.
+ * @public
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
+ * @returns {Number}
+ */
+ Owl.prototype.maximum = function(relative) {
+ var settings = this.settings,
+ maximum = this._coordinates.length,
+ iterator,
+ reciprocalItemsWidth,
+ elementWidth;
+
+ if (settings.loop) {
+ maximum = this._clones.length / 2 + this._items.length - 1;
+ } else if (settings.autoWidth || settings.merge) {
+ iterator = this._items.length;
+ if (iterator) {
+ reciprocalItemsWidth = this._items[--iterator].width();
+ elementWidth = this.$element.width();
+ while (iterator--) {
+ reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
+ if (reciprocalItemsWidth > elementWidth) {
+ break;
+ }
+ }
+ }
+ maximum = iterator + 1;
+ } else if (settings.center) {
+ maximum = this._items.length - 1;
+ } else {
+ maximum = this._items.length - settings.items;
+ }
+
+ if (relative) {
+ maximum -= this._clones.length / 2;
+ }
+
+ return Math.max(maximum, 0);
+ };
+
+ /**
+ * Gets the minimum position for the current item.
+ * @public
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
+ * @returns {Number}
+ */
+ Owl.prototype.minimum = function(relative) {
+ return relative ? 0 : this._clones.length / 2;
+ };
+
+ /**
+ * Gets an item at the specified relative position.
+ * @public
+ * @param {Number} [position] - The relative position of the item.
+ * @return {jQuery|Array.} - The item at the given position or all items if no position was given.
+ */
+ Owl.prototype.items = function(position) {
+ if (position === undefined) {
+ return this._items.slice();
+ }
+
+ position = this.normalize(position, true);
+ return this._items[position];
+ };
+
+ /**
+ * Gets an item at the specified relative position.
+ * @public
+ * @param {Number} [position] - The relative position of the item.
+ * @return {jQuery|Array.} - The item at the given position or all items if no position was given.
+ */
+ Owl.prototype.mergers = function(position) {
+ if (position === undefined) {
+ return this._mergers.slice();
+ }
+
+ position = this.normalize(position, true);
+ return this._mergers[position];
+ };
+
+ /**
+ * Gets the absolute positions of clones for an item.
+ * @public
+ * @param {Number} [position] - The relative position of the item.
+ * @returns {Array.} - The absolute positions of clones for the item or all if no position was given.
+ */
+ Owl.prototype.clones = function(position) {
+ var odd = this._clones.length / 2,
+ even = odd + this._items.length,
+ map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
+
+ if (position === undefined) {
+ return $.map(this._clones, function(v, i) { return map(i) });
+ }
+
+ return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
+ };
+
+ /**
+ * Sets the current animation speed.
+ * @public
+ * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
+ * @returns {Number} - The current animation speed in milliseconds.
+ */
+ Owl.prototype.speed = function(speed) {
+ if (speed !== undefined) {
+ this._speed = speed;
+ }
+
+ return this._speed;
+ };
+
+ /**
+ * Gets the coordinate of an item.
+ * @todo The name of this method is missleanding.
+ * @public
+ * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
+ * @returns {Number|Array.} - The coordinate of the item in pixel or all coordinates.
+ */
+ Owl.prototype.coordinates = function(position) {
+ var multiplier = 1,
+ newPosition = position - 1,
+ coordinate;
+
+ if (position === undefined) {
+ return $.map(this._coordinates, $.proxy(function(coordinate, index) {
+ return this.coordinates(index);
+ }, this));
+ }
+
+ if (this.settings.center) {
+ if (this.settings.rtl) {
+ multiplier = -1;
+ newPosition = position + 1;
+ }
+
+ coordinate = this._coordinates[position];
+ coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
+ } else {
+ coordinate = this._coordinates[newPosition] || 0;
+ }
+
+ coordinate = Math.ceil(coordinate);
+
+ return coordinate;
+ };
+
+ /**
+ * Calculates the speed for a translation.
+ * @protected
+ * @param {Number} from - The absolute position of the start item.
+ * @param {Number} to - The absolute position of the target item.
+ * @param {Number} [factor=undefined] - The time factor in milliseconds.
+ * @returns {Number} - The time in milliseconds for the translation.
+ */
+ Owl.prototype.duration = function(from, to, factor) {
+ if (factor === 0) {
+ return 0;
+ }
+
+ return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
+ };
+
+ /**
+ * Slides to the specified item.
+ * @public
+ * @param {Number} position - The position of the item.
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ */
+ Owl.prototype.to = function(position, speed) {
+ var current = this.current(),
+ revert = null,
+ distance = position - this.relative(current),
+ direction = (distance > 0) - (distance < 0),
+ items = this._items.length,
+ minimum = this.minimum(),
+ maximum = this.maximum();
+
+ if (this.settings.loop) {
+ if (!this.settings.rewind && Math.abs(distance) > items / 2) {
+ distance += direction * -1 * items;
+ }
+
+ position = current + distance;
+ revert = ((position - minimum) % items + items) % items + minimum;
+
+ if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
+ current = revert - distance;
+ position = revert;
+ this.reset(current);
+ }
+ } else if (this.settings.rewind) {
+ maximum += 1;
+ position = (position % maximum + maximum) % maximum;
+ } else {
+ position = Math.max(minimum, Math.min(maximum, position));
+ }
+
+ this.speed(this.duration(current, position, speed));
+ this.current(position);
+
+ if (this.isVisible()) {
+ this.update();
+ }
+ };
+
+ /**
+ * Slides to the next item.
+ * @public
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ */
+ Owl.prototype.next = function(speed) {
+ speed = speed || false;
+ this.to(this.relative(this.current()) + 1, speed);
+ };
+
+ /**
+ * Slides to the previous item.
+ * @public
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ */
+ Owl.prototype.prev = function(speed) {
+ speed = speed || false;
+ this.to(this.relative(this.current()) - 1, speed);
+ };
+
+ /**
+ * Handles the end of an animation.
+ * @protected
+ * @param {Event} event - The event arguments.
+ */
+ Owl.prototype.onTransitionEnd = function(event) {
+
+ // if css2 animation then event object is undefined
+ if (event !== undefined) {
+ event.stopPropagation();
+
+ // Catch only owl-stage transitionEnd event
+ if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
+ return false;
+ }
+ }
+
+ this.leave('animating');
+ this.trigger('translated');
+ };
+
+ /**
+ * Gets viewport width.
+ * @protected
+ * @return {Number} - The width in pixel.
+ */
+ Owl.prototype.viewport = function() {
+ var width;
+ if (this.options.responsiveBaseElement !== window) {
+ width = $(this.options.responsiveBaseElement).width();
+ } else if (window.innerWidth) {
+ width = window.innerWidth;
+ } else if (document.documentElement && document.documentElement.clientWidth) {
+ width = document.documentElement.clientWidth;
+ } else {
+ console.warn('Can not detect viewport width.');
+ }
+ return width;
+ };
+
+ /**
+ * Replaces the current content.
+ * @public
+ * @param {HTMLElement|jQuery|String} content - The new content.
+ */
+ Owl.prototype.replace = function(content) {
+ this.$stage.empty();
+ this._items = [];
+
+ if (content) {
+ content = (content instanceof jQuery) ? content : $(content);
+ }
+
+ if (this.settings.nestedItemSelector) {
+ content = content.find('.' + this.settings.nestedItemSelector);
+ }
+
+ content.filter(function() {
+ return this.nodeType === 1;
+ }).each($.proxy(function(index, item) {
+ item = this.prepare(item);
+ this.$stage.append(item);
+ this._items.push(item);
+ this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
+ }, this));
+
+ this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
+
+ this.invalidate('items');
+ };
+
+ /**
+ * Adds an item.
+ * @todo Use `item` instead of `content` for the event arguments.
+ * @public
+ * @param {HTMLElement|jQuery|String} content - The item content to add.
+ * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
+ */
+ Owl.prototype.add = function(content, position) {
+ var current = this.relative(this._current);
+
+ position = position === undefined ? this._items.length : this.normalize(position, true);
+ content = content instanceof jQuery ? content : $(content);
+
+ this.trigger('add', { content: content, position: position });
+
+ content = this.prepare(content);
+
+ if (this._items.length === 0 || position === this._items.length) {
+ this._items.length === 0 && this.$stage.append(content);
+ this._items.length !== 0 && this._items[position - 1].after(content);
+ this._items.push(content);
+ this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
+ } else {
+ this._items[position].before(content);
+ this._items.splice(position, 0, content);
+ this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
+ }
+
+ this._items[current] && this.reset(this._items[current].index());
+
+ this.invalidate('items');
+
+ this.trigger('added', { content: content, position: position });
+ };
+
+ /**
+ * Removes an item by its position.
+ * @todo Use `item` instead of `content` for the event arguments.
+ * @public
+ * @param {Number} position - The relative position of the item to remove.
+ */
+ Owl.prototype.remove = function(position) {
+ position = this.normalize(position, true);
+
+ if (position === undefined) {
+ return;
+ }
+
+ this.trigger('remove', { content: this._items[position], position: position });
+
+ this._items[position].remove();
+ this._items.splice(position, 1);
+ this._mergers.splice(position, 1);
+
+ this.invalidate('items');
+
+ this.trigger('removed', { content: null, position: position });
+ };
+
+ /**
+ * Preloads images with auto width.
+ * @todo Replace by a more generic approach
+ * @protected
+ */
+ Owl.prototype.preloadAutoWidthImages = function(images) {
+ images.each($.proxy(function(i, element) {
+ this.enter('pre-loading');
+ element = $(element);
+ $(new Image()).one('load', $.proxy(function(e) {
+ element.attr('src', e.target.src);
+ element.css('opacity', 1);
+ this.leave('pre-loading');
+ !this.is('pre-loading') && !this.is('initializing') && this.refresh();
+ }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
+ }, this));
+ };
+
+ /**
+ * Destroys the carousel.
+ * @public
+ */
+ Owl.prototype.destroy = function() {
+
+ this.$element.off('.owl.core');
+ this.$stage.off('.owl.core');
+ $(document).off('.owl.core');
+
+ if (this.settings.responsive !== false) {
+ window.clearTimeout(this.resizeTimer);
+ this.off(window, 'resize', this._handlers.onThrottledResize);
+ }
+
+ for (var i in this._plugins) {
+ this._plugins[i].destroy();
+ }
+
+ this.$stage.children('.cloned').remove();
+
+ this.$stage.unwrap();
+ this.$stage.children().contents().unwrap();
+ this.$stage.children().unwrap();
+ this.$stage.remove();
+ this.$element
+ .removeClass(this.options.refreshClass)
+ .removeClass(this.options.loadingClass)
+ .removeClass(this.options.loadedClass)
+ .removeClass(this.options.rtlClass)
+ .removeClass(this.options.dragClass)
+ .removeClass(this.options.grabClass)
+ .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
+ .removeData('owl.carousel');
+ };
+
+ /**
+ * Operators to calculate right-to-left and left-to-right.
+ * @protected
+ * @param {Number} [a] - The left side operand.
+ * @param {String} [o] - The operator.
+ * @param {Number} [b] - The right side operand.
+ */
+ Owl.prototype.op = function(a, o, b) {
+ var rtl = this.settings.rtl;
+ switch (o) {
+ case '<':
+ return rtl ? a > b : a < b;
+ case '>':
+ return rtl ? a < b : a > b;
+ case '>=':
+ return rtl ? a <= b : a >= b;
+ case '<=':
+ return rtl ? a >= b : a <= b;
+ default:
+ break;
+ }
+ };
+
+ /**
+ * Attaches to an internal event.
+ * @protected
+ * @param {HTMLElement} element - The event source.
+ * @param {String} event - The event name.
+ * @param {Function} listener - The event handler to attach.
+ * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
+ */
+ Owl.prototype.on = function(element, event, listener, capture) {
+ if (element.addEventListener) {
+ element.addEventListener(event, listener, capture);
+ } else if (element.attachEvent) {
+ element.attachEvent('on' + event, listener);
+ }
+ };
+
+ /**
+ * Detaches from an internal event.
+ * @protected
+ * @param {HTMLElement} element - The event source.
+ * @param {String} event - The event name.
+ * @param {Function} listener - The attached event handler to detach.
+ * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
+ */
+ Owl.prototype.off = function(element, event, listener, capture) {
+ if (element.removeEventListener) {
+ element.removeEventListener(event, listener, capture);
+ } else if (element.detachEvent) {
+ element.detachEvent('on' + event, listener);
+ }
+ };
+
+ /**
+ * Triggers a public event.
+ * @todo Remove `status`, `relatedTarget` should be used instead.
+ * @protected
+ * @param {String} name - The event name.
+ * @param {*} [data=null] - The event data.
+ * @param {String} [namespace=carousel] - The event namespace.
+ * @param {String} [state] - The state which is associated with the event.
+ * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
+ * @returns {Event} - The event arguments.
+ */
+ Owl.prototype.trigger = function(name, data, namespace, state, enter) {
+ var status = {
+ item: { count: this._items.length, index: this.current() }
+ }, handler = $.camelCase(
+ $.grep([ 'on', name, namespace ], function(v) { return v })
+ .join('-').toLowerCase()
+ ), event = $.Event(
+ [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
+ $.extend({ relatedTarget: this }, status, data)
+ );
+
+ if (!this._supress[name]) {
+ $.each(this._plugins, function(name, plugin) {
+ if (plugin.onTrigger) {
+ plugin.onTrigger(event);
+ }
+ });
+
+ this.register({ type: Owl.Type.Event, name: name });
+ this.$element.trigger(event);
+
+ if (this.settings && typeof this.settings[handler] === 'function') {
+ this.settings[handler].call(this, event);
+ }
+ }
+
+ return event;
+ };
+
+ /**
+ * Enters a state.
+ * @param name - The state name.
+ */
+ Owl.prototype.enter = function(name) {
+ $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
+ if (this._states.current[name] === undefined) {
+ this._states.current[name] = 0;
+ }
+
+ this._states.current[name]++;
+ }, this));
+ };
+
+ /**
+ * Leaves a state.
+ * @param name - The state name.
+ */
+ Owl.prototype.leave = function(name) {
+ $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
+ this._states.current[name]--;
+ }, this));
+ };
+
+ /**
+ * Registers an event or state.
+ * @public
+ * @param {Object} object - The event or state to register.
+ */
+ Owl.prototype.register = function(object) {
+ if (object.type === Owl.Type.Event) {
+ if (!$.event.special[object.name]) {
+ $.event.special[object.name] = {};
+ }
+
+ if (!$.event.special[object.name].owl) {
+ var _default = $.event.special[object.name]._default;
+ $.event.special[object.name]._default = function(e) {
+ if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
+ return _default.apply(this, arguments);
+ }
+ return e.namespace && e.namespace.indexOf('owl') > -1;
+ };
+ $.event.special[object.name].owl = true;
+ }
+ } else if (object.type === Owl.Type.State) {
+ if (!this._states.tags[object.name]) {
+ this._states.tags[object.name] = object.tags;
+ } else {
+ this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
+ }
+
+ this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
+ return $.inArray(tag, this._states.tags[object.name]) === i;
+ }, this));
+ }
+ };
+
+ /**
+ * Suppresses events.
+ * @protected
+ * @param {Array.} events - The events to suppress.
+ */
+ Owl.prototype.suppress = function(events) {
+ $.each(events, $.proxy(function(index, event) {
+ this._supress[event] = true;
+ }, this));
+ };
+
+ /**
+ * Releases suppressed events.
+ * @protected
+ * @param {Array.} events - The events to release.
+ */
+ Owl.prototype.release = function(events) {
+ $.each(events, $.proxy(function(index, event) {
+ delete this._supress[event];
+ }, this));
+ };
+
+ /**
+ * Gets unified pointer coordinates from event.
+ * @todo #261
+ * @protected
+ * @param {Event} - The `mousedown` or `touchstart` event.
+ * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
+ */
+ Owl.prototype.pointer = function(event) {
+ var result = { x: null, y: null };
+
+ event = event.originalEvent || event || window.event;
+
+ event = event.touches && event.touches.length ?
+ event.touches[0] : event.changedTouches && event.changedTouches.length ?
+ event.changedTouches[0] : event;
+
+ if (event.pageX) {
+ result.x = event.pageX;
+ result.y = event.pageY;
+ } else {
+ result.x = event.clientX;
+ result.y = event.clientY;
+ }
+
+ return result;
+ };
+
+ /**
+ * Determines if the input is a Number or something that can be coerced to a Number
+ * @protected
+ * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
+ * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
+ */
+ Owl.prototype.isNumeric = function(number) {
+ return !isNaN(parseFloat(number));
+ };
+
+ /**
+ * Gets the difference of two vectors.
+ * @todo #261
+ * @protected
+ * @param {Object} - The first vector.
+ * @param {Object} - The second vector.
+ * @returns {Object} - The difference.
+ */
+ Owl.prototype.difference = function(first, second) {
+ return {
+ x: first.x - second.x,
+ y: first.y - second.y
+ };
+ };
+
+ /**
+ * The jQuery Plugin for the Owl Carousel
+ * @todo Navigation plugin `next` and `prev`
+ * @public
+ */
+ $.fn.owlCarousel = function(option) {
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ return this.each(function() {
+ var $this = $(this),
+ data = $this.data('owl.carousel');
+
+ if (!data) {
+ data = new Owl(this, typeof option == 'object' && option);
+ $this.data('owl.carousel', data);
+
+ $.each([
+ 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
+ ], function(i, event) {
+ data.register({ type: Owl.Type.Event, name: event });
+ data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
+ if (e.namespace && e.relatedTarget !== this) {
+ this.suppress([ event ]);
+ data[event].apply(this, [].slice.call(arguments, 1));
+ this.release([ event ]);
+ }
+ }, data));
+ });
+ }
+
+ if (typeof option == 'string' && option.charAt(0) !== '_') {
+ data[option].apply(data, args);
+ }
+ });
+ };
+
+ /**
+ * The constructor for the jQuery Plugin
+ * @public
+ */
+ $.fn.owlCarousel.Constructor = Owl;
+
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * AutoRefresh Plugin
+ * @version 2.3.4
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+
+ /**
+ * Creates the auto refresh plugin.
+ * @class The Auto Refresh Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var AutoRefresh = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+
+ /**
+ * Refresh interval.
+ * @protected
+ * @type {number}
+ */
+ this._interval = null;
+
+ /**
+ * Whether the element is currently visible or not.
+ * @protected
+ * @type {Boolean}
+ */
+ this._visible = null;
+
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoRefresh) {
+ this.watch();
+ }
+ }, this)
+ };
+
+ // set default options
+ this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
+
+ // register event handlers
+ this._core.$element.on(this._handlers);
+ };
+
+ /**
+ * Default options.
+ * @public
+ */
+ AutoRefresh.Defaults = {
+ autoRefresh: true,
+ autoRefreshInterval: 500
+ };
+
+ /**
+ * Watches the element.
+ */
+ AutoRefresh.prototype.watch = function() {
+ if (this._interval) {
+ return;
+ }
+
+ this._visible = this._core.isVisible();
+ this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
+ };
+
+ /**
+ * Refreshes the element.
+ */
+ AutoRefresh.prototype.refresh = function() {
+ if (this._core.isVisible() === this._visible) {
+ return;
+ }
+
+ this._visible = !this._visible;
+
+ this._core.$element.toggleClass('owl-hidden', !this._visible);
+
+ this._visible && (this._core.invalidate('width') && this._core.refresh());
+ };
+
+ /**
+ * Destroys the plugin.
+ */
+ AutoRefresh.prototype.destroy = function() {
+ var handler, property;
+
+ window.clearInterval(this._interval);
+
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+
+ $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
+
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * Lazy Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+
+ /**
+ * Creates the lazy plugin.
+ * @class The Lazy Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var Lazy = function(carousel) {
+
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+
+ /**
+ * Already loaded items.
+ * @protected
+ * @type {Array.}
+ */
+ this._loaded = [];
+
+ /**
+ * Event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function(e) {
+ if (!e.namespace) {
+ return;
+ }
+
+ if (!this._core.settings || !this._core.settings.lazyLoad) {
+ return;
+ }
+
+ if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
+ var settings = this._core.settings,
+ n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
+ i = ((settings.center && n * -1) || 0),
+ position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i,
+ clones = this._core.clones().length,
+ load = $.proxy(function(i, v) { this.load(v) }, this);
+ //TODO: Need documentation for this new option
+ if (settings.lazyLoadEager > 0) {
+ n += settings.lazyLoadEager;
+ // If the carousel is looping also preload images that are to the "left"
+ if (settings.loop) {
+ position -= settings.lazyLoadEager;
+ n++;
+ }
+ }
+
+ while (i++ < n) {
+ this.load(clones / 2 + this._core.relative(position));
+ clones && $.each(this._core.clones(this._core.relative(position)), load);
+ position++;
+ }
+ }
+ }, this)
+ };
+
+ // set the default options
+ this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
+
+ // register event handler
+ this._core.$element.on(this._handlers);
+ };
+
+ /**
+ * Default options.
+ * @public
+ */
+ Lazy.Defaults = {
+ lazyLoad: false,
+ lazyLoadEager: 0
+ };
+
+ /**
+ * Loads all resources of an item at the specified position.
+ * @param {Number} position - The absolute position of the item.
+ * @protected
+ */
+ Lazy.prototype.load = function(position) {
+ var $item = this._core.$stage.children().eq(position),
+ $elements = $item && $item.find('.owl-lazy');
+
+ if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
+ return;
+ }
+
+ $elements.each($.proxy(function(index, element) {
+ var $element = $(element), image,
+ url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src') || $element.attr('data-srcset');
+
+ this._core.trigger('load', { element: $element, url: url }, 'lazy');
+
+ if ($element.is('img')) {
+ $element.one('load.owl.lazy', $.proxy(function() {
+ $element.css('opacity', 1);
+ this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
+ }, this)).attr('src', url);
+ } else if ($element.is('source')) {
+ $element.one('load.owl.lazy', $.proxy(function() {
+ this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
+ }, this)).attr('srcset', url);
+ } else {
+ image = new Image();
+ image.onload = $.proxy(function() {
+ $element.css({
+ 'background-image': 'url("' + url + '")',
+ 'opacity': '1'
+ });
+ this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
+ }, this);
+ image.src = url;
+ }
+ }, this));
+
+ this._loaded.push($item.get(0));
+ };
+
+ /**
+ * Destroys the plugin.
+ * @public
+ */
+ Lazy.prototype.destroy = function() {
+ var handler, property;
+
+ for (handler in this.handlers) {
+ this._core.$element.off(handler, this.handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+
+ $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
+
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * AutoHeight Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+
+ /**
+ * Creates the auto height plugin.
+ * @class The Auto Height Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var AutoHeight = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+
+ this._previousHeight = null;
+
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoHeight) {
+ this.update();
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoHeight && e.property.name === 'position'){
+ this.update();
+ }
+ }, this),
+ 'loaded.owl.lazy': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoHeight
+ && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
+ this.update();
+ }
+ }, this)
+ };
+
+ // set default options
+ this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
+
+ // register event handlers
+ this._core.$element.on(this._handlers);
+ this._intervalId = null;
+ var refThis = this;
+
+ // These changes have been taken from a PR by gavrochelegnou proposed in #1575
+ // and have been made compatible with the latest jQuery version
+ $(window).on('load', function() {
+ if (refThis._core.settings.autoHeight) {
+ refThis.update();
+ }
+ });
+
+ // Autoresize the height of the carousel when window is resized
+ // When carousel has images, the height is dependent on the width
+ // and should also change on resize
+ $(window).resize(function() {
+ if (refThis._core.settings.autoHeight) {
+ if (refThis._intervalId != null) {
+ clearTimeout(refThis._intervalId);
+ }
+
+ refThis._intervalId = setTimeout(function() {
+ refThis.update();
+ }, 250);
+ }
+ });
+
+ };
+
+ /**
+ * Default options.
+ * @public
+ */
+ AutoHeight.Defaults = {
+ autoHeight: false,
+ autoHeightClass: 'owl-height'
+ };
+
+ /**
+ * Updates the view.
+ */
+ AutoHeight.prototype.update = function() {
+ var start = this._core._current,
+ end = start + this._core.settings.items,
+ lazyLoadEnabled = this._core.settings.lazyLoad,
+ visible = this._core.$stage.children().toArray().slice(start, end),
+ heights = [],
+ maxheight = 0;
+
+ $.each(visible, function(index, item) {
+ heights.push($(item).height());
+ });
+
+ maxheight = Math.max.apply(null, heights);
+
+ if (maxheight <= 1 && lazyLoadEnabled && this._previousHeight) {
+ maxheight = this._previousHeight;
+ }
+
+ this._previousHeight = maxheight;
+
+ this._core.$stage.parent()
+ .height(maxheight)
+ .addClass(this._core.settings.autoHeightClass);
+ };
+
+ AutoHeight.prototype.destroy = function() {
+ var handler, property;
+
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] !== 'function' && (this[property] = null);
+ }
+ };
+
+ $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
+
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * Video Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+
+ /**
+ * Creates the video plugin.
+ * @class The Video Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var Video = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+
+ /**
+ * Cache all video URLs.
+ * @protected
+ * @type {Object}
+ */
+ this._videos = {};
+
+ /**
+ * Current playing item.
+ * @protected
+ * @type {jQuery}
+ */
+ this._playing = null;
+
+ /**
+ * All event handlers.
+ * @todo The cloned content removale is too late
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace) {
+ this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
+ }
+ }, this),
+ 'resize.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
+ e.preventDefault();
+ }
+ }, this),
+ 'refreshed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.is('resizing')) {
+ this._core.$stage.find('.cloned .owl-video-frame').remove();
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name === 'position' && this._playing) {
+ this.stop();
+ }
+ }, this),
+ 'prepared.owl.carousel': $.proxy(function(e) {
+ if (!e.namespace) {
+ return;
+ }
+
+ var $element = $(e.content).find('.owl-video');
+
+ if ($element.length) {
+ $element.css('display', 'none');
+ this.fetch($element, $(e.content));
+ }
+ }, this)
+ };
+
+ // set default options
+ this._core.options = $.extend({}, Video.Defaults, this._core.options);
+
+ // register event handlers
+ this._core.$element.on(this._handlers);
+
+ this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
+ this.play(e);
+ }, this));
+ };
+
+ /**
+ * Default options.
+ * @public
+ */
+ Video.Defaults = {
+ video: false,
+ videoHeight: false,
+ videoWidth: false
+ };
+
+ /**
+ * Gets the video ID and the type (YouTube/Vimeo/vzaar only).
+ * @protected
+ * @param {jQuery} target - The target containing the video data.
+ * @param {jQuery} item - The item containing the video.
+ */
+ Video.prototype.fetch = function(target, item) {
+ var type = (function() {
+ if (target.attr('data-vimeo-id')) {
+ return 'vimeo';
+ } else if (target.attr('data-vzaar-id')) {
+ return 'vzaar'
+ } else {
+ return 'youtube';
+ }
+ })(),
+ id = target.attr('data-vimeo-id') || target.attr('data-youtube-id') || target.attr('data-vzaar-id'),
+ width = target.attr('data-width') || this._core.settings.videoWidth,
+ height = target.attr('data-height') || this._core.settings.videoHeight,
+ url = target.attr('href');
+
+ if (url) {
+
+ /*
+ Parses the id's out of the following urls (and probably more):
+ https://www.youtube.com/watch?v=:id
+ https://youtu.be/:id
+ https://vimeo.com/:id
+ https://vimeo.com/channels/:channel/:id
+ https://vimeo.com/groups/:group/videos/:id
+ https://app.vzaar.com/videos/:id
+
+ Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F
+ */
+
+ id = url.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com|be\-nocookie\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
+
+ if (id[3].indexOf('youtu') > -1) {
+ type = 'youtube';
+ } else if (id[3].indexOf('vimeo') > -1) {
+ type = 'vimeo';
+ } else if (id[3].indexOf('vzaar') > -1) {
+ type = 'vzaar';
+ } else {
+ throw new Error('Video URL not supported.');
+ }
+ id = id[6];
+ } else {
+ throw new Error('Missing video URL.');
+ }
+
+ this._videos[url] = {
+ type: type,
+ id: id,
+ width: width,
+ height: height
+ };
+
+ item.attr('data-video', url);
+
+ this.thumbnail(target, this._videos[url]);
+ };
+
+ /**
+ * Creates video thumbnail.
+ * @protected
+ * @param {jQuery} target - The target containing the video data.
+ * @param {Object} info - The video info object.
+ * @see `fetch`
+ */
+ Video.prototype.thumbnail = function(target, video) {
+ var tnLink,
+ icon,
+ path,
+ dimensions = video.width && video.height ? 'width:' + video.width + 'px;height:' + video.height + 'px;' : '',
+ customTn = target.find('img'),
+ srcType = 'src',
+ lazyClass = '',
+ settings = this._core.settings,
+ create = function(path) {
+ icon = '
';
+
+ if (settings.lazyLoad) {
+ tnLink = $('
',{
+ "class": 'owl-video-tn ' + lazyClass,
+ "srcType": path
+ });
+ } else {
+ tnLink = $( '
', {
+ "class": "owl-video-tn",
+ "style": 'opacity:1;background-image:url(' + path + ')'
+ });
+ }
+ target.after(tnLink);
+ target.after(icon);
+ };
+
+ // wrap video content into owl-video-wrapper div
+ target.wrap( $( '
', {
+ "class": "owl-video-wrapper",
+ "style": dimensions
+ }));
+
+ if (this._core.settings.lazyLoad) {
+ srcType = 'data-src';
+ lazyClass = 'owl-lazy';
+ }
+
+ // custom thumbnail
+ if (customTn.length) {
+ create(customTn.attr(srcType));
+ customTn.remove();
+ return false;
+ }
+
+ if (video.type === 'youtube') {
+ path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
+ create(path);
+ } else if (video.type === 'vimeo') {
+ $.ajax({
+ type: 'GET',
+ url: '//vimeo.com/api/v2/video/' + video.id + '.json',
+ jsonp: 'callback',
+ dataType: 'jsonp',
+ success: function(data) {
+ path = data[0].thumbnail_large;
+ create(path);
+ }
+ });
+ } else if (video.type === 'vzaar') {
+ $.ajax({
+ type: 'GET',
+ url: '//vzaar.com/api/videos/' + video.id + '.json',
+ jsonp: 'callback',
+ dataType: 'jsonp',
+ success: function(data) {
+ path = data.framegrab_url;
+ create(path);
+ }
+ });
+ }
+ };
+
+ /**
+ * Stops the current video.
+ * @public
+ */
+ Video.prototype.stop = function() {
+ this._core.trigger('stop', null, 'video');
+ this._playing.find('.owl-video-frame').remove();
+ this._playing.removeClass('owl-video-playing');
+ this._playing = null;
+ this._core.leave('playing');
+ this._core.trigger('stopped', null, 'video');
+ };
+
+ /**
+ * Starts the current video.
+ * @public
+ * @param {Event} event - The event arguments.
+ */
+ Video.prototype.play = function(event) {
+ var target = $(event.target),
+ item = target.closest('.' + this._core.settings.itemClass),
+ video = this._videos[item.attr('data-video')],
+ width = video.width || '100%',
+ height = video.height || this._core.$stage.height(),
+ html,
+ iframe;
+
+ if (this._playing) {
+ return;
+ }
+
+ this._core.enter('playing');
+ this._core.trigger('play', null, 'video');
+
+ item = this._core.items(this._core.relative(item.index()));
+
+ this._core.reset(item.index());
+
+ html = $( '' );
+ html.attr( 'height', height );
+ html.attr( 'width', width );
+ if (video.type === 'youtube') {
+ html.attr( 'src', '//www.youtube.com/embed/' + video.id + '?autoplay=1&rel=0&v=' + video.id );
+ } else if (video.type === 'vimeo') {
+ html.attr( 'src', '//player.vimeo.com/video/' + video.id + '?autoplay=1' );
+ } else if (video.type === 'vzaar') {
+ html.attr( 'src', '//view.vzaar.com/' + video.id + '/player?autoplay=true' );
+ }
+
+ iframe = $(html).wrap( '
' ).insertAfter(item.find('.owl-video'));
+
+ this._playing = item.addClass('owl-video-playing');
+ };
+
+ /**
+ * Checks whether an video is currently in full screen mode or not.
+ * @todo Bad style because looks like a readonly method but changes members.
+ * @protected
+ * @returns {Boolean}
+ */
+ Video.prototype.isInFullScreen = function() {
+ var element = document.fullscreenElement || document.mozFullScreenElement ||
+ document.webkitFullscreenElement;
+
+ return element && $(element).parent().hasClass('owl-video-frame');
+ };
+
+ /**
+ * Destroys the plugin.
+ */
+ Video.prototype.destroy = function() {
+ var handler, property;
+
+ this._core.$element.off('click.owl.video');
+
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+
+ $.fn.owlCarousel.Constructor.Plugins.Video = Video;
+
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * Animate Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+
+ /**
+ * Creates the animate plugin.
+ * @class The Navigation Plugin
+ * @param {Owl} scope - The Owl Carousel
+ */
+ var Animate = function(scope) {
+ this.core = scope;
+ this.core.options = $.extend({}, Animate.Defaults, this.core.options);
+ this.swapping = true;
+ this.previous = undefined;
+ this.next = undefined;
+
+ this.handlers = {
+ 'change.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name == 'position') {
+ this.previous = this.core.current();
+ this.next = e.property.value;
+ }
+ }, this),
+ 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
+ if (e.namespace) {
+ this.swapping = e.type == 'translated';
+ }
+ }, this),
+ 'translate.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
+ this.swap();
+ }
+ }, this)
+ };
+
+ this.core.$element.on(this.handlers);
+ };
+
+ /**
+ * Default options.
+ * @public
+ */
+ Animate.Defaults = {
+ animateOut: false,
+ animateIn: false
+ };
+
+ /**
+ * Toggles the animation classes whenever an translations starts.
+ * @protected
+ * @returns {Boolean|undefined}
+ */
+ Animate.prototype.swap = function() {
+
+ if (this.core.settings.items !== 1) {
+ return;
+ }
+
+ if (!$.support.animation || !$.support.transition) {
+ return;
+ }
+
+ this.core.speed(0);
+
+ var left,
+ clear = $.proxy(this.clear, this),
+ previous = this.core.$stage.children().eq(this.previous),
+ next = this.core.$stage.children().eq(this.next),
+ incoming = this.core.settings.animateIn,
+ outgoing = this.core.settings.animateOut;
+
+ if (this.core.current() === this.previous) {
+ return;
+ }
+
+ if (outgoing) {
+ left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
+ previous.one($.support.animation.end, clear)
+ .css( { 'left': left + 'px' } )
+ .addClass('animated owl-animated-out')
+ .addClass(outgoing);
+ }
+
+ if (incoming) {
+ next.one($.support.animation.end, clear)
+ .addClass('animated owl-animated-in')
+ .addClass(incoming);
+ }
+ };
+
+ Animate.prototype.clear = function(e) {
+ $(e.target).css( { 'left': '' } )
+ .removeClass('animated owl-animated-out owl-animated-in')
+ .removeClass(this.core.settings.animateIn)
+ .removeClass(this.core.settings.animateOut);
+ this.core.onTransitionEnd();
+ };
+
+ /**
+ * Destroys the plugin.
+ * @public
+ */
+ Animate.prototype.destroy = function() {
+ var handler, property;
+
+ for (handler in this.handlers) {
+ this.core.$element.off(handler, this.handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+
+ $.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
+
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * Autoplay Plugin
+ * @version 2.3.4
+ * @author Bartosz Wojciechowski
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @author Tom De Caluwé
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+
+ /**
+ * Creates the autoplay plugin.
+ * @class The Autoplay Plugin
+ * @param {Owl} scope - The Owl Carousel
+ */
+ var Autoplay = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+
+ /**
+ * The autoplay timeout id.
+ * @type {Number}
+ */
+ this._call = null;
+
+ /**
+ * Depending on the state of the plugin, this variable contains either
+ * the start time of the timer or the current timer value if it's
+ * paused. Since we start in a paused state we initialize the timer
+ * value.
+ * @type {Number}
+ */
+ this._time = 0;
+
+ /**
+ * Stores the timeout currently used.
+ * @type {Number}
+ */
+ this._timeout = 0;
+
+ /**
+ * Indicates whenever the autoplay is paused.
+ * @type {Boolean}
+ */
+ this._paused = true;
+
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name === 'settings') {
+ if (this._core.settings.autoplay) {
+ this.play();
+ } else {
+ this.stop();
+ }
+ } else if (e.namespace && e.property.name === 'position' && this._paused) {
+ // Reset the timer. This code is triggered when the position
+ // of the carousel was changed through user interaction.
+ this._time = 0;
+ }
+ }, this),
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.autoplay) {
+ this.play();
+ }
+ }, this),
+ 'play.owl.autoplay': $.proxy(function(e, t, s) {
+ if (e.namespace) {
+ this.play(t, s);
+ }
+ }, this),
+ 'stop.owl.autoplay': $.proxy(function(e) {
+ if (e.namespace) {
+ this.stop();
+ }
+ }, this),
+ 'mouseover.owl.autoplay': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
+ this.pause();
+ }
+ }, this),
+ 'mouseleave.owl.autoplay': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
+ this.play();
+ }
+ }, this),
+ 'touchstart.owl.core': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
+ this.pause();
+ }
+ }, this),
+ 'touchend.owl.core': $.proxy(function() {
+ if (this._core.settings.autoplayHoverPause) {
+ this.play();
+ }
+ }, this)
+ };
+
+ // register event handlers
+ this._core.$element.on(this._handlers);
+
+ // set default options
+ this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
+ };
+
+ /**
+ * Default options.
+ * @public
+ */
+ Autoplay.Defaults = {
+ autoplay: false,
+ autoplayTimeout: 5000,
+ autoplayHoverPause: false,
+ autoplaySpeed: false
+ };
+
+ /**
+ * Transition to the next slide and set a timeout for the next transition.
+ * @private
+ * @param {Number} [speed] - The animation speed for the animations.
+ */
+ Autoplay.prototype._next = function(speed) {
+ this._call = window.setTimeout(
+ $.proxy(this._next, this, speed),
+ this._timeout * (Math.round(this.read() / this._timeout) + 1) - this.read()
+ );
+
+ if (this._core.is('interacting') || document.hidden) {
+ return;
+ }
+ this._core.next(speed || this._core.settings.autoplaySpeed);
+ }
+
+ /**
+ * Reads the current timer value when the timer is playing.
+ * @public
+ */
+ Autoplay.prototype.read = function() {
+ return new Date().getTime() - this._time;
+ };
+
+ /**
+ * Starts the autoplay.
+ * @public
+ * @param {Number} [timeout] - The interval before the next animation starts.
+ * @param {Number} [speed] - The animation speed for the animations.
+ */
+ Autoplay.prototype.play = function(timeout, speed) {
+ var elapsed;
+
+ if (!this._core.is('rotating')) {
+ this._core.enter('rotating');
+ }
+
+ timeout = timeout || this._core.settings.autoplayTimeout;
+
+ // Calculate the elapsed time since the last transition. If the carousel
+ // wasn't playing this calculation will yield zero.
+ elapsed = Math.min(this._time % (this._timeout || timeout), timeout);
+
+ if (this._paused) {
+ // Start the clock.
+ this._time = this.read();
+ this._paused = false;
+ } else {
+ // Clear the active timeout to allow replacement.
+ window.clearTimeout(this._call);
+ }
+
+ // Adjust the origin of the timer to match the new timeout value.
+ this._time += this.read() % timeout - elapsed;
+
+ this._timeout = timeout;
+ this._call = window.setTimeout($.proxy(this._next, this, speed), timeout - elapsed);
+ };
+
+ /**
+ * Stops the autoplay.
+ * @public
+ */
+ Autoplay.prototype.stop = function() {
+ if (this._core.is('rotating')) {
+ // Reset the clock.
+ this._time = 0;
+ this._paused = true;
+
+ window.clearTimeout(this._call);
+ this._core.leave('rotating');
+ }
+ };
+
+ /**
+ * Pauses the autoplay.
+ * @public
+ */
+ Autoplay.prototype.pause = function() {
+ if (this._core.is('rotating') && !this._paused) {
+ // Pause the clock.
+ this._time = this.read();
+ this._paused = true;
+
+ window.clearTimeout(this._call);
+ }
+ };
+
+ /**
+ * Destroys the plugin.
+ */
+ Autoplay.prototype.destroy = function() {
+ var handler, property;
+
+ this.stop();
+
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+
+ $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
+
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * Navigation Plugin
+ * @version 2.3.4
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ 'use strict';
+
+ /**
+ * Creates the navigation plugin.
+ * @class The Navigation Plugin
+ * @param {Owl} carousel - The Owl Carousel.
+ */
+ var Navigation = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+
+ /**
+ * Indicates whether the plugin is initialized or not.
+ * @protected
+ * @type {Boolean}
+ */
+ this._initialized = false;
+
+ /**
+ * The current paging indexes.
+ * @protected
+ * @type {Array}
+ */
+ this._pages = [];
+
+ /**
+ * All DOM elements of the user interface.
+ * @protected
+ * @type {Object}
+ */
+ this._controls = {};
+
+ /**
+ * Markup for an indicator.
+ * @protected
+ * @type {Array.}
+ */
+ this._templates = [];
+
+ /**
+ * The carousel element.
+ * @type {jQuery}
+ */
+ this.$element = this._core.$element;
+
+ /**
+ * Overridden methods of the carousel.
+ * @protected
+ * @type {Object}
+ */
+ this._overrides = {
+ next: this._core.next,
+ prev: this._core.prev,
+ to: this._core.to
+ };
+
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'prepared.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.dotsData) {
+ this._templates.push('' +
+ $(e.content).find('[data-dot]').addBack('[data-dot]').attr('data-dot') + '
');
+ }
+ }, this),
+ 'added.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.dotsData) {
+ this._templates.splice(e.position, 0, this._templates.pop());
+ }
+ }, this),
+ 'remove.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.dotsData) {
+ this._templates.splice(e.position, 1);
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name == 'position') {
+ this.draw();
+ }
+ }, this),
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && !this._initialized) {
+ this._core.trigger('initialize', null, 'navigation');
+ this.initialize();
+ this.update();
+ this.draw();
+ this._initialized = true;
+ this._core.trigger('initialized', null, 'navigation');
+ }
+ }, this),
+ 'refreshed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._initialized) {
+ this._core.trigger('refresh', null, 'navigation');
+ this.update();
+ this.draw();
+ this._core.trigger('refreshed', null, 'navigation');
+ }
+ }, this)
+ };
+
+ // set default options
+ this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
+
+ // register event handlers
+ this.$element.on(this._handlers);
+ };
+
+ /**
+ * Default options.
+ * @public
+ * @todo Rename `slideBy` to `navBy`
+ */
+ Navigation.Defaults = {
+ nav: false,
+ navText: [
+ '‹ ',
+ '› '
+ ],
+ navSpeed: false,
+ navElement: 'button type="button" role="presentation"',
+ navContainer: false,
+ navContainerClass: 'owl-nav',
+ navClass: [
+ 'owl-prev',
+ 'owl-next'
+ ],
+ slideBy: 1,
+ dotClass: 'owl-dot',
+ dotsClass: 'owl-dots',
+ dots: true,
+ dotsEach: false,
+ dotsData: false,
+ dotsSpeed: false,
+ dotsContainer: false
+ };
+
+ /**
+ * Initializes the layout of the plugin and extends the carousel.
+ * @protected
+ */
+ Navigation.prototype.initialize = function() {
+ var override,
+ settings = this._core.settings;
+
+ // create DOM structure for relative navigation
+ this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
+ : $('').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
+
+ this._controls.$previous = $('<' + settings.navElement + '>')
+ .addClass(settings.navClass[0])
+ .html(settings.navText[0])
+ .prependTo(this._controls.$relative)
+ .on('click', $.proxy(function(e) {
+ this.prev(settings.navSpeed);
+ }, this));
+ this._controls.$next = $('<' + settings.navElement + '>')
+ .addClass(settings.navClass[1])
+ .html(settings.navText[1])
+ .appendTo(this._controls.$relative)
+ .on('click', $.proxy(function(e) {
+ this.next(settings.navSpeed);
+ }, this));
+
+ // create DOM structure for absolute navigation
+ if (!settings.dotsData) {
+ this._templates = [ $('
')
+ .addClass(settings.dotClass)
+ .append($(''))
+ .prop('outerHTML') ];
+ }
+
+ this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
+ : $('').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
+
+ this._controls.$absolute.on('click', 'button', $.proxy(function(e) {
+ var index = $(e.target).parent().is(this._controls.$absolute)
+ ? $(e.target).index() : $(e.target).parent().index();
+
+ e.preventDefault();
+
+ this.to(index, settings.dotsSpeed);
+ }, this));
+
+ /*$el.on('focusin', function() {
+ $(document).off(".carousel");
+
+ $(document).on('keydown.carousel', function(e) {
+ if(e.keyCode == 37) {
+ $el.trigger('prev.owl')
+ }
+ if(e.keyCode == 39) {
+ $el.trigger('next.owl')
+ }
+ });
+ });*/
+
+ // override public methods of the carousel
+ for (override in this._overrides) {
+ this._core[override] = $.proxy(this[override], this);
+ }
+ };
+
+ /**
+ * Destroys the plugin.
+ * @protected
+ */
+ Navigation.prototype.destroy = function() {
+ var handler, control, property, override, settings;
+ settings = this._core.settings;
+
+ for (handler in this._handlers) {
+ this.$element.off(handler, this._handlers[handler]);
+ }
+ for (control in this._controls) {
+ if (control === '$relative' && settings.navContainer) {
+ this._controls[control].html('');
+ } else {
+ this._controls[control].remove();
+ }
+ }
+ for (override in this.overides) {
+ this._core[override] = this._overrides[override];
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+
+ /**
+ * Updates the internal state.
+ * @protected
+ */
+ Navigation.prototype.update = function() {
+ var i, j, k,
+ lower = this._core.clones().length / 2,
+ upper = lower + this._core.items().length,
+ maximum = this._core.maximum(true),
+ settings = this._core.settings,
+ size = settings.center || settings.autoWidth || settings.dotsData
+ ? 1 : settings.dotsEach || settings.items;
+
+ if (settings.slideBy !== 'page') {
+ settings.slideBy = Math.min(settings.slideBy, settings.items);
+ }
+
+ if (settings.dots || settings.slideBy == 'page') {
+ this._pages = [];
+
+ for (i = lower, j = 0, k = 0; i < upper; i++) {
+ if (j >= size || j === 0) {
+ this._pages.push({
+ start: Math.min(maximum, i - lower),
+ end: i - lower + size - 1
+ });
+ if (Math.min(maximum, i - lower) === maximum) {
+ break;
+ }
+ j = 0, ++k;
+ }
+ j += this._core.mergers(this._core.relative(i));
+ }
+ }
+ };
+
+ /**
+ * Draws the user interface.
+ * @todo The option `dotsData` wont work.
+ * @protected
+ */
+ Navigation.prototype.draw = function() {
+ var difference,
+ settings = this._core.settings,
+ disabled = this._core.items().length <= settings.items,
+ index = this._core.relative(this._core.current()),
+ loop = settings.loop || settings.rewind;
+
+ this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
+
+ if (settings.nav) {
+ this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
+ this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
+ }
+
+ this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
+
+ if (settings.dots) {
+ difference = this._pages.length - this._controls.$absolute.children().length;
+
+ if (settings.dotsData && difference !== 0) {
+ this._controls.$absolute.html(this._templates.join(''));
+ } else if (difference > 0) {
+ this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
+ } else if (difference < 0) {
+ this._controls.$absolute.children().slice(difference).remove();
+ }
+
+ this._controls.$absolute.find('.active').removeClass('active');
+ this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
+ }
+ };
+
+ /**
+ * Extends event data.
+ * @protected
+ * @param {Event} event - The event object which gets thrown.
+ */
+ Navigation.prototype.onTrigger = function(event) {
+ var settings = this._core.settings;
+
+ event.page = {
+ index: $.inArray(this.current(), this._pages),
+ count: this._pages.length,
+ size: settings && (settings.center || settings.autoWidth || settings.dotsData
+ ? 1 : settings.dotsEach || settings.items)
+ };
+ };
+
+ /**
+ * Gets the current page position of the carousel.
+ * @protected
+ * @returns {Number}
+ */
+ Navigation.prototype.current = function() {
+ var current = this._core.relative(this._core.current());
+ return $.grep(this._pages, $.proxy(function(page, index) {
+ return page.start <= current && page.end >= current;
+ }, this)).pop();
+ };
+
+ /**
+ * Gets the current succesor/predecessor position.
+ * @protected
+ * @returns {Number}
+ */
+ Navigation.prototype.getPosition = function(successor) {
+ var position, length,
+ settings = this._core.settings;
+
+ if (settings.slideBy == 'page') {
+ position = $.inArray(this.current(), this._pages);
+ length = this._pages.length;
+ successor ? ++position : --position;
+ position = this._pages[((position % length) + length) % length].start;
+ } else {
+ position = this._core.relative(this._core.current());
+ length = this._core.items().length;
+ successor ? position += settings.slideBy : position -= settings.slideBy;
+ }
+
+ return position;
+ };
+
+ /**
+ * Slides to the next item or page.
+ * @public
+ * @param {Number} [speed=false] - The time in milliseconds for the transition.
+ */
+ Navigation.prototype.next = function(speed) {
+ $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
+ };
+
+ /**
+ * Slides to the previous item or page.
+ * @public
+ * @param {Number} [speed=false] - The time in milliseconds for the transition.
+ */
+ Navigation.prototype.prev = function(speed) {
+ $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
+ };
+
+ /**
+ * Slides to the specified item or page.
+ * @public
+ * @param {Number} position - The position of the item or page.
+ * @param {Number} [speed] - The time in milliseconds for the transition.
+ * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
+ */
+ Navigation.prototype.to = function(position, speed, standard) {
+ var length;
+
+ if (!standard && this._pages.length) {
+ length = this._pages.length;
+ $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
+ } else {
+ $.proxy(this._overrides.to, this._core)(position, speed);
+ }
+ };
+
+ $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
+
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * Hash Plugin
+ * @version 2.3.4
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+ 'use strict';
+
+ /**
+ * Creates the hash plugin.
+ * @class The Hash Plugin
+ * @param {Owl} carousel - The Owl Carousel
+ */
+ var Hash = function(carousel) {
+ /**
+ * Reference to the core.
+ * @protected
+ * @type {Owl}
+ */
+ this._core = carousel;
+
+ /**
+ * Hash index for the items.
+ * @protected
+ * @type {Object}
+ */
+ this._hashes = {};
+
+ /**
+ * The carousel element.
+ * @type {jQuery}
+ */
+ this.$element = this._core.$element;
+
+ /**
+ * All event handlers.
+ * @protected
+ * @type {Object}
+ */
+ this._handlers = {
+ 'initialized.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && this._core.settings.startPosition === 'URLHash') {
+ $(window).trigger('hashchange.owl.navigation');
+ }
+ }, this),
+ 'prepared.owl.carousel': $.proxy(function(e) {
+ if (e.namespace) {
+ var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
+
+ if (!hash) {
+ return;
+ }
+
+ this._hashes[hash] = e.content;
+ }
+ }, this),
+ 'changed.owl.carousel': $.proxy(function(e) {
+ if (e.namespace && e.property.name === 'position') {
+ var current = this._core.items(this._core.relative(this._core.current())),
+ hash = $.map(this._hashes, function(item, hash) {
+ return item === current ? hash : null;
+ }).join();
+
+ if (!hash || window.location.hash.slice(1) === hash) {
+ return;
+ }
+
+ window.location.hash = hash;
+ }
+ }, this)
+ };
+
+ // set default options
+ this._core.options = $.extend({}, Hash.Defaults, this._core.options);
+
+ // register the event handlers
+ this.$element.on(this._handlers);
+
+ // register event listener for hash navigation
+ $(window).on('hashchange.owl.navigation', $.proxy(function(e) {
+ var hash = window.location.hash.substring(1),
+ items = this._core.$stage.children(),
+ position = this._hashes[hash] && items.index(this._hashes[hash]);
+
+ if (position === undefined || position === this._core.current()) {
+ return;
+ }
+
+ this._core.to(this._core.relative(position), false, true);
+ }, this));
+ };
+
+ /**
+ * Default options.
+ * @public
+ */
+ Hash.Defaults = {
+ URLhashListener: false
+ };
+
+ /**
+ * Destroys the plugin.
+ * @public
+ */
+ Hash.prototype.destroy = function() {
+ var handler, property;
+
+ $(window).off('hashchange.owl.navigation');
+
+ for (handler in this._handlers) {
+ this._core.$element.off(handler, this._handlers[handler]);
+ }
+ for (property in Object.getOwnPropertyNames(this)) {
+ typeof this[property] != 'function' && (this[property] = null);
+ }
+ };
+
+ $.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
+
+})(window.Zepto || window.jQuery, window, document);
+
+/**
+ * Support Plugin
+ *
+ * @version 2.3.4
+ * @author Vivid Planet Software GmbH
+ * @author Artus Kolanowski
+ * @author David Deutsch
+ * @license The MIT License (MIT)
+ */
+;(function($, window, document, undefined) {
+
+ var style = $('
').get(0).style,
+ prefixes = 'Webkit Moz O ms'.split(' '),
+ events = {
+ transition: {
+ end: {
+ WebkitTransition: 'webkitTransitionEnd',
+ MozTransition: 'transitionend',
+ OTransition: 'oTransitionEnd',
+ transition: 'transitionend'
+ }
+ },
+ animation: {
+ end: {
+ WebkitAnimation: 'webkitAnimationEnd',
+ MozAnimation: 'animationend',
+ OAnimation: 'oAnimationEnd',
+ animation: 'animationend'
+ }
+ }
+ },
+ tests = {
+ csstransforms: function() {
+ return !!test('transform');
+ },
+ csstransforms3d: function() {
+ return !!test('perspective');
+ },
+ csstransitions: function() {
+ return !!test('transition');
+ },
+ cssanimations: function() {
+ return !!test('animation');
+ }
+ };
+
+ function test(property, prefixed) {
+ var result = false,
+ upper = property.charAt(0).toUpperCase() + property.slice(1);
+
+ $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
+ if (style[property] !== undefined) {
+ result = prefixed ? property : true;
+ return false;
+ }
+ });
+
+ return result;
+ }
+
+ function prefixed(property) {
+ return test(property, true);
+ }
+
+ if (tests.csstransitions()) {
+ /* jshint -W053 */
+ $.support.transition = new String(prefixed('transition'))
+ $.support.transition.end = events.transition.end[ $.support.transition ];
+ }
+
+ if (tests.cssanimations()) {
+ /* jshint -W053 */
+ $.support.animation = new String(prefixed('animation'))
+ $.support.animation.end = events.animation.end[ $.support.animation ];
+ }
+
+ if (tests.csstransforms()) {
+ /* jshint -W053 */
+ $.support.transform = new String(prefixed('transform'));
+ $.support.transform3d = tests.csstransforms3d();
+ }
+
+})(window.Zepto || window.jQuery, window, document);
diff --git a/theme_levelup/static/src/js/owl.carousel.min.js b/theme_levelup/static/src/js/owl.carousel.min.js
new file mode 100644
index 0000000000..241d0a97a6
--- /dev/null
+++ b/theme_levelup/static/src/js/owl.carousel.min.js
@@ -0,0 +1,7 @@
+/**
+ * Owl Carousel v2.3.4
+ * Copyright 2013-2018 David Deutsch
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
+ */
+!function(a,b,c,d){function e(b,c){this.settings=null,this.options=a.extend({},e.Defaults,c),this.$element=a(b),this._handlers={},this._plugins={},this._supress={},this._current=null,this._speed=null,this._coordinates=[],this._breakpoint=null,this._width=null,this._items=[],this._clones=[],this._mergers=[],this._widths=[],this._invalidated={},this._pipe=[],this._drag={time:null,target:null,pointer:null,stage:{start:null,current:null},direction:null},this._states={current:{},tags:{initializing:["busy"],animating:["busy"],dragging:["interacting"]}},a.each(["onResize","onThrottledResize"],a.proxy(function(b,c){this._handlers[c]=a.proxy(this[c],this)},this)),a.each(e.Plugins,a.proxy(function(a,b){this._plugins[a.charAt(0).toLowerCase()+a.slice(1)]=new b(this)},this)),a.each(e.Workers,a.proxy(function(b,c){this._pipe.push({filter:c.filter,run:a.proxy(c.run,this)})},this)),this.setup(),this.initialize()}e.Defaults={items:3,loop:!1,center:!1,rewind:!1,checkVisibility:!0,mouseDrag:!0,touchDrag:!0,pullDrag:!0,freeDrag:!1,margin:0,stagePadding:0,merge:!1,mergeFit:!0,autoWidth:!1,startPosition:0,rtl:!1,smartSpeed:250,fluidSpeed:!1,dragEndSpeed:!1,responsive:{},responsiveRefreshRate:200,responsiveBaseElement:b,fallbackEasing:"swing",slideTransition:"",info:!1,nestedItemSelector:!1,itemElement:"div",stageElement:"div",refreshClass:"owl-refresh",loadedClass:"owl-loaded",loadingClass:"owl-loading",rtlClass:"owl-rtl",responsiveClass:"owl-responsive",dragClass:"owl-drag",itemClass:"owl-item",stageClass:"owl-stage",stageOuterClass:"owl-stage-outer",grabClass:"owl-grab"},e.Width={Default:"default",Inner:"inner",Outer:"outer"},e.Type={Event:"event",State:"state"},e.Plugins={},e.Workers=[{filter:["width","settings"],run:function(){this._width=this.$element.width()}},{filter:["width","items","settings"],run:function(a){a.current=this._items&&this._items[this.relative(this._current)]}},{filter:["items","settings"],run:function(){this.$stage.children(".cloned").remove()}},{filter:["width","items","settings"],run:function(a){var b=this.settings.margin||"",c=!this.settings.autoWidth,d=this.settings.rtl,e={width:"auto","margin-left":d?b:"","margin-right":d?"":b};!c&&this.$stage.children().css(e),a.css=e}},{filter:["width","items","settings"],run:function(a){var b=(this.width()/this.settings.items).toFixed(3)-this.settings.margin,c=null,d=this._items.length,e=!this.settings.autoWidth,f=[];for(a.items={merge:!1,width:b};d--;)c=this._mergers[d],c=this.settings.mergeFit&&Math.min(c,this.settings.items)||c,a.items.merge=c>1||a.items.merge,f[d]=e?b*c:this._items[d].width();this._widths=f}},{filter:["items","settings"],run:function(){var b=[],c=this._items,d=this.settings,e=Math.max(2*d.items,4),f=2*Math.ceil(c.length/2),g=d.loop&&c.length?d.rewind?e:Math.max(e,f):0,h="",i="";for(g/=2;g>0;)b.push(this.normalize(b.length/2,!0)),h+=c[b[b.length-1]][0].outerHTML,b.push(this.normalize(c.length-1-(b.length-1)/2,!0)),i=c[b[b.length-1]][0].outerHTML+i,g-=1;this._clones=b,a(h).addClass("cloned").appendTo(this.$stage),a(i).addClass("cloned").prependTo(this.$stage)}},{filter:["width","items","settings"],run:function(){for(var a=this.settings.rtl?1:-1,b=this._clones.length+this._items.length,c=-1,d=0,e=0,f=[];++c",h)||this.op(b,"<",g)&&this.op(b,">",h))&&i.push(c);this.$stage.children(".active").removeClass("active"),this.$stage.children(":eq("+i.join("), :eq(")+")").addClass("active"),this.$stage.children(".center").removeClass("center"),this.settings.center&&this.$stage.children().eq(this.current()).addClass("center")}}],e.prototype.initializeStage=function(){this.$stage=this.$element.find("."+this.settings.stageClass),this.$stage.length||(this.$element.addClass(this.options.loadingClass),this.$stage=a("<"+this.settings.stageElement+">",{class:this.settings.stageClass}).wrap(a("
",{class:this.settings.stageOuterClass})),this.$element.append(this.$stage.parent()))},e.prototype.initializeItems=function(){var b=this.$element.find(".owl-item");if(b.length)return this._items=b.get().map(function(b){return a(b)}),this._mergers=this._items.map(function(){return 1}),void this.refresh();this.replace(this.$element.children().not(this.$stage.parent())),this.isVisible()?this.refresh():this.invalidate("width"),this.$element.removeClass(this.options.loadingClass).addClass(this.options.loadedClass)},e.prototype.initialize=function(){if(this.enter("initializing"),this.trigger("initialize"),this.$element.toggleClass(this.settings.rtlClass,this.settings.rtl),this.settings.autoWidth&&!this.is("pre-loading")){var a,b,c;a=this.$element.find("img"),b=this.settings.nestedItemSelector?"."+this.settings.nestedItemSelector:d,c=this.$element.children(b).width(),a.length&&c<=0&&this.preloadAutoWidthImages(a)}this.initializeStage(),this.initializeItems(),this.registerEventHandlers(),this.leave("initializing"),this.trigger("initialized")},e.prototype.isVisible=function(){return!this.settings.checkVisibility||this.$element.is(":visible")},e.prototype.setup=function(){var b=this.viewport(),c=this.options.responsive,d=-1,e=null;c?(a.each(c,function(a){a<=b&&a>d&&(d=Number(a))}),e=a.extend({},this.options,c[d]),"function"==typeof e.stagePadding&&(e.stagePadding=e.stagePadding()),delete e.responsive,e.responsiveClass&&this.$element.attr("class",this.$element.attr("class").replace(new RegExp("("+this.options.responsiveClass+"-)\\S+\\s","g"),"$1"+d))):e=a.extend({},this.options),this.trigger("change",{property:{name:"settings",value:e}}),this._breakpoint=d,this.settings=e,this.invalidate("settings"),this.trigger("changed",{property:{name:"settings",value:this.settings}})},e.prototype.optionsLogic=function(){this.settings.autoWidth&&(this.settings.stagePadding=!1,this.settings.merge=!1)},e.prototype.prepare=function(b){var c=this.trigger("prepare",{content:b});return c.data||(c.data=a("<"+this.settings.itemElement+"/>").addClass(this.options.itemClass).append(b)),this.trigger("prepared",{content:c.data}),c.data},e.prototype.update=function(){for(var b=0,c=this._pipe.length,d=a.proxy(function(a){return this[a]},this._invalidated),e={};b0)&&this._pipe[b].run(e),b++;this._invalidated={},!this.is("valid")&&this.enter("valid")},e.prototype.width=function(a){switch(a=a||e.Width.Default){case e.Width.Inner:case e.Width.Outer:return this._width;default:return this._width-2*this.settings.stagePadding+this.settings.margin}},e.prototype.refresh=function(){this.enter("refreshing"),this.trigger("refresh"),this.setup(),this.optionsLogic(),this.$element.addClass(this.options.refreshClass),this.update(),this.$element.removeClass(this.options.refreshClass),this.leave("refreshing"),this.trigger("refreshed")},e.prototype.onThrottledResize=function(){b.clearTimeout(this.resizeTimer),this.resizeTimer=b.setTimeout(this._handlers.onResize,this.settings.responsiveRefreshRate)},e.prototype.onResize=function(){return!!this._items.length&&(this._width!==this.$element.width()&&(!!this.isVisible()&&(this.enter("resizing"),this.trigger("resize").isDefaultPrevented()?(this.leave("resizing"),!1):(this.invalidate("width"),this.refresh(),this.leave("resizing"),void this.trigger("resized")))))},e.prototype.registerEventHandlers=function(){a.support.transition&&this.$stage.on(a.support.transition.end+".owl.core",a.proxy(this.onTransitionEnd,this)),!1!==this.settings.responsive&&this.on(b,"resize",this._handlers.onThrottledResize),this.settings.mouseDrag&&(this.$element.addClass(this.options.dragClass),this.$stage.on("mousedown.owl.core",a.proxy(this.onDragStart,this)),this.$stage.on("dragstart.owl.core selectstart.owl.core",function(){return!1})),this.settings.touchDrag&&(this.$stage.on("touchstart.owl.core",a.proxy(this.onDragStart,this)),this.$stage.on("touchcancel.owl.core",a.proxy(this.onDragEnd,this)))},e.prototype.onDragStart=function(b){var d=null;3!==b.which&&(a.support.transform?(d=this.$stage.css("transform").replace(/.*\(|\)| /g,"").split(","),d={x:d[16===d.length?12:4],y:d[16===d.length?13:5]}):(d=this.$stage.position(),d={x:this.settings.rtl?d.left+this.$stage.width()-this.width()+this.settings.margin:d.left,y:d.top}),this.is("animating")&&(a.support.transform?this.animate(d.x):this.$stage.stop(),this.invalidate("position")),this.$element.toggleClass(this.options.grabClass,"mousedown"===b.type),this.speed(0),this._drag.time=(new Date).getTime(),this._drag.target=a(b.target),this._drag.stage.start=d,this._drag.stage.current=d,this._drag.pointer=this.pointer(b),a(c).on("mouseup.owl.core touchend.owl.core",a.proxy(this.onDragEnd,this)),a(c).one("mousemove.owl.core touchmove.owl.core",a.proxy(function(b){var d=this.difference(this._drag.pointer,this.pointer(b));a(c).on("mousemove.owl.core touchmove.owl.core",a.proxy(this.onDragMove,this)),Math.abs(d.x)0^this.settings.rtl?"left":"right";a(c).off(".owl.core"),this.$element.removeClass(this.options.grabClass),(0!==d.x&&this.is("dragging")||!this.is("valid"))&&(this.speed(this.settings.dragEndSpeed||this.settings.smartSpeed),this.current(this.closest(e.x,0!==d.x?f:this._drag.direction)),this.invalidate("position"),this.update(),this._drag.direction=f,(Math.abs(d.x)>3||(new Date).getTime()-this._drag.time>300)&&this._drag.target.one("click.owl.core",function(){return!1})),this.is("dragging")&&(this.leave("dragging"),this.trigger("dragged"))},e.prototype.closest=function(b,c){var e=-1,f=30,g=this.width(),h=this.coordinates();return this.settings.freeDrag||a.each(h,a.proxy(function(a,i){return"left"===c&&b>i-f&&bi-g-f&&b",h[a+1]!==d?h[a+1]:i-g)&&(e="left"===c?a+1:a),-1===e},this)),this.settings.loop||(this.op(b,">",h[this.minimum()])?e=b=this.minimum():this.op(b,"<",h[this.maximum()])&&(e=b=this.maximum())),e},e.prototype.animate=function(b){var c=this.speed()>0;this.is("animating")&&this.onTransitionEnd(),c&&(this.enter("animating"),this.trigger("translate")),a.support.transform3d&&a.support.transition?this.$stage.css({transform:"translate3d("+b+"px,0px,0px)",transition:this.speed()/1e3+"s"+(this.settings.slideTransition?" "+this.settings.slideTransition:"")}):c?this.$stage.animate({left:b+"px"},this.speed(),this.settings.fallbackEasing,a.proxy(this.onTransitionEnd,this)):this.$stage.css({left:b+"px"})},e.prototype.is=function(a){return this._states.current[a]&&this._states.current[a]>0},e.prototype.current=function(a){if(a===d)return this._current;if(0===this._items.length)return d;if(a=this.normalize(a),this._current!==a){var b=this.trigger("change",{property:{name:"position",value:a}});b.data!==d&&(a=this.normalize(b.data)),this._current=a,this.invalidate("position"),this.trigger("changed",{property:{name:"position",value:this._current}})}return this._current},e.prototype.invalidate=function(b){return"string"===a.type(b)&&(this._invalidated[b]=!0,this.is("valid")&&this.leave("valid")),a.map(this._invalidated,function(a,b){return b})},e.prototype.reset=function(a){(a=this.normalize(a))!==d&&(this._speed=0,this._current=a,this.suppress(["translate","translated"]),this.animate(this.coordinates(a)),this.release(["translate","translated"]))},e.prototype.normalize=function(a,b){var c=this._items.length,e=b?0:this._clones.length;return!this.isNumeric(a)||c<1?a=d:(a<0||a>=c+e)&&(a=((a-e/2)%c+c)%c+e/2),a},e.prototype.relative=function(a){return a-=this._clones.length/2,this.normalize(a,!0)},e.prototype.maximum=function(a){var b,c,d,e=this.settings,f=this._coordinates.length;if(e.loop)f=this._clones.length/2+this._items.length-1;else if(e.autoWidth||e.merge){if(b=this._items.length)for(c=this._items[--b].width(),d=this.$element.width();b--&&!((c+=this._items[b].width()+this.settings.margin)>d););f=b+1}else f=e.center?this._items.length-1:this._items.length-e.items;return a&&(f-=this._clones.length/2),Math.max(f,0)},e.prototype.minimum=function(a){return a?0:this._clones.length/2},e.prototype.items=function(a){return a===d?this._items.slice():(a=this.normalize(a,!0),this._items[a])},e.prototype.mergers=function(a){return a===d?this._mergers.slice():(a=this.normalize(a,!0),this._mergers[a])},e.prototype.clones=function(b){var c=this._clones.length/2,e=c+this._items.length,f=function(a){return a%2==0?e+a/2:c-(a+1)/2};return b===d?a.map(this._clones,function(a,b){return f(b)}):a.map(this._clones,function(a,c){return a===b?f(c):null})},e.prototype.speed=function(a){return a!==d&&(this._speed=a),this._speed},e.prototype.coordinates=function(b){var c,e=1,f=b-1;return b===d?a.map(this._coordinates,a.proxy(function(a,b){return this.coordinates(b)},this)):(this.settings.center?(this.settings.rtl&&(e=-1,f=b+1),c=this._coordinates[b],c+=(this.width()-c+(this._coordinates[f]||0))/2*e):c=this._coordinates[f]||0,c=Math.ceil(c))},e.prototype.duration=function(a,b,c){return 0===c?0:Math.min(Math.max(Math.abs(b-a),1),6)*Math.abs(c||this.settings.smartSpeed)},e.prototype.to=function(a,b){var c=this.current(),d=null,e=a-this.relative(c),f=(e>0)-(e<0),g=this._items.length,h=this.minimum(),i=this.maximum();this.settings.loop?(!this.settings.rewind&&Math.abs(e)>g/2&&(e+=-1*f*g),a=c+e,(d=((a-h)%g+g)%g+h)!==a&&d-e<=i&&d-e>0&&(c=d-e,a=d,this.reset(c))):this.settings.rewind?(i+=1,a=(a%i+i)%i):a=Math.max(h,Math.min(i,a)),this.speed(this.duration(c,a,b)),this.current(a),this.isVisible()&&this.update()},e.prototype.next=function(a){a=a||!1,this.to(this.relative(this.current())+1,a)},e.prototype.prev=function(a){a=a||!1,this.to(this.relative(this.current())-1,a)},e.prototype.onTransitionEnd=function(a){if(a!==d&&(a.stopPropagation(),(a.target||a.srcElement||a.originalTarget)!==this.$stage.get(0)))return!1;this.leave("animating"),this.trigger("translated")},e.prototype.viewport=function(){var d;return this.options.responsiveBaseElement!==b?d=a(this.options.responsiveBaseElement).width():b.innerWidth?d=b.innerWidth:c.documentElement&&c.documentElement.clientWidth?d=c.documentElement.clientWidth:console.warn("Can not detect viewport width."),d},e.prototype.replace=function(b){this.$stage.empty(),this._items=[],b&&(b=b instanceof jQuery?b:a(b)),this.settings.nestedItemSelector&&(b=b.find("."+this.settings.nestedItemSelector)),b.filter(function(){return 1===this.nodeType}).each(a.proxy(function(a,b){b=this.prepare(b),this.$stage.append(b),this._items.push(b),this._mergers.push(1*b.find("[data-merge]").addBack("[data-merge]").attr("data-merge")||1)},this)),this.reset(this.isNumeric(this.settings.startPosition)?this.settings.startPosition:0),this.invalidate("items")},e.prototype.add=function(b,c){var e=this.relative(this._current);c=c===d?this._items.length:this.normalize(c,!0),b=b instanceof jQuery?b:a(b),this.trigger("add",{content:b,position:c}),b=this.prepare(b),0===this._items.length||c===this._items.length?(0===this._items.length&&this.$stage.append(b),0!==this._items.length&&this._items[c-1].after(b),this._items.push(b),this._mergers.push(1*b.find("[data-merge]").addBack("[data-merge]").attr("data-merge")||1)):(this._items[c].before(b),this._items.splice(c,0,b),this._mergers.splice(c,0,1*b.find("[data-merge]").addBack("[data-merge]").attr("data-merge")||1)),this._items[e]&&this.reset(this._items[e].index()),this.invalidate("items"),this.trigger("added",{content:b,position:c})},e.prototype.remove=function(a){(a=this.normalize(a,!0))!==d&&(this.trigger("remove",{content:this._items[a],position:a}),this._items[a].remove(),this._items.splice(a,1),this._mergers.splice(a,1),this.invalidate("items"),this.trigger("removed",{content:null,position:a}))},e.prototype.preloadAutoWidthImages=function(b){b.each(a.proxy(function(b,c){this.enter("pre-loading"),c=a(c),a(new Image).one("load",a.proxy(function(a){c.attr("src",a.target.src),c.css("opacity",1),this.leave("pre-loading"),!this.is("pre-loading")&&!this.is("initializing")&&this.refresh()},this)).attr("src",c.attr("src")||c.attr("data-src")||c.attr("data-src-retina"))},this))},e.prototype.destroy=function(){this.$element.off(".owl.core"),this.$stage.off(".owl.core"),a(c).off(".owl.core"),!1!==this.settings.responsive&&(b.clearTimeout(this.resizeTimer),this.off(b,"resize",this._handlers.onThrottledResize));for(var d in this._plugins)this._plugins[d].destroy();this.$stage.children(".cloned").remove(),this.$stage.unwrap(),this.$stage.children().contents().unwrap(),this.$stage.children().unwrap(),this.$stage.remove(),this.$element.removeClass(this.options.refreshClass).removeClass(this.options.loadingClass).removeClass(this.options.loadedClass).removeClass(this.options.rtlClass).removeClass(this.options.dragClass).removeClass(this.options.grabClass).attr("class",this.$element.attr("class").replace(new RegExp(this.options.responsiveClass+"-\\S+\\s","g"),"")).removeData("owl.carousel")},e.prototype.op=function(a,b,c){var d=this.settings.rtl;switch(b){case"<":return d?a>c:a":return d?ac;case">=":return d?a<=c:a>=c;case"<=":return d?a>=c:a<=c}},e.prototype.on=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,d):a.attachEvent&&a.attachEvent("on"+b,c)},e.prototype.off=function(a,b,c,d){a.removeEventListener?a.removeEventListener(b,c,d):a.detachEvent&&a.detachEvent("on"+b,c)},e.prototype.trigger=function(b,c,d,f,g){var h={item:{count:this._items.length,index:this.current()}},i=a.camelCase(a.grep(["on",b,d],function(a){return a}).join("-").toLowerCase()),j=a.Event([b,"owl",d||"carousel"].join(".").toLowerCase(),a.extend({relatedTarget:this},h,c));return this._supress[b]||(a.each(this._plugins,function(a,b){b.onTrigger&&b.onTrigger(j)}),this.register({type:e.Type.Event,name:b}),this.$element.trigger(j),this.settings&&"function"==typeof this.settings[i]&&this.settings[i].call(this,j)),j},e.prototype.enter=function(b){a.each([b].concat(this._states.tags[b]||[]),a.proxy(function(a,b){this._states.current[b]===d&&(this._states.current[b]=0),this._states.current[b]++},this))},e.prototype.leave=function(b){a.each([b].concat(this._states.tags[b]||[]),a.proxy(function(a,b){this._states.current[b]--},this))},e.prototype.register=function(b){if(b.type===e.Type.Event){if(a.event.special[b.name]||(a.event.special[b.name]={}),!a.event.special[b.name].owl){var c=a.event.special[b.name]._default;a.event.special[b.name]._default=function(a){return!c||!c.apply||a.namespace&&-1!==a.namespace.indexOf("owl")?a.namespace&&a.namespace.indexOf("owl")>-1:c.apply(this,arguments)},a.event.special[b.name].owl=!0}}else b.type===e.Type.State&&(this._states.tags[b.name]?this._states.tags[b.name]=this._states.tags[b.name].concat(b.tags):this._states.tags[b.name]=b.tags,this._states.tags[b.name]=a.grep(this._states.tags[b.name],a.proxy(function(c,d){return a.inArray(c,this._states.tags[b.name])===d},this)))},e.prototype.suppress=function(b){a.each(b,a.proxy(function(a,b){this._supress[b]=!0},this))},e.prototype.release=function(b){a.each(b,a.proxy(function(a,b){delete this._supress[b]},this))},e.prototype.pointer=function(a){var c={x:null,y:null};return a=a.originalEvent||a||b.event,a=a.touches&&a.touches.length?a.touches[0]:a.changedTouches&&a.changedTouches.length?a.changedTouches[0]:a,a.pageX?(c.x=a.pageX,c.y=a.pageY):(c.x=a.clientX,c.y=a.clientY),c},e.prototype.isNumeric=function(a){return!isNaN(parseFloat(a))},e.prototype.difference=function(a,b){return{x:a.x-b.x,y:a.y-b.y}},a.fn.owlCarousel=function(b){var c=Array.prototype.slice.call(arguments,1);return this.each(function(){var d=a(this),f=d.data("owl.carousel");f||(f=new e(this,"object"==typeof b&&b),d.data("owl.carousel",f),a.each(["next","prev","to","destroy","refresh","replace","add","remove"],function(b,c){f.register({type:e.Type.Event,name:c}),f.$element.on(c+".owl.carousel.core",a.proxy(function(a){a.namespace&&a.relatedTarget!==this&&(this.suppress([c]),f[c].apply(this,[].slice.call(arguments,1)),this.release([c]))},f))})),"string"==typeof b&&"_"!==b.charAt(0)&&f[b].apply(f,c)})},a.fn.owlCarousel.Constructor=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._interval=null,this._visible=null,this._handlers={"initialized.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoRefresh&&this.watch()},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers)};e.Defaults={autoRefresh:!0,autoRefreshInterval:500},e.prototype.watch=function(){this._interval||(this._visible=this._core.isVisible(),this._interval=b.setInterval(a.proxy(this.refresh,this),this._core.settings.autoRefreshInterval))},e.prototype.refresh=function(){this._core.isVisible()!==this._visible&&(this._visible=!this._visible,this._core.$element.toggleClass("owl-hidden",!this._visible),this._visible&&this._core.invalidate("width")&&this._core.refresh())},e.prototype.destroy=function(){var a,c;b.clearInterval(this._interval);for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(c in Object.getOwnPropertyNames(this))"function"!=typeof this[c]&&(this[c]=null)},a.fn.owlCarousel.Constructor.Plugins.AutoRefresh=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._loaded=[],this._handlers={"initialized.owl.carousel change.owl.carousel resized.owl.carousel":a.proxy(function(b){if(b.namespace&&this._core.settings&&this._core.settings.lazyLoad&&(b.property&&"position"==b.property.name||"initialized"==b.type)){var c=this._core.settings,e=c.center&&Math.ceil(c.items/2)||c.items,f=c.center&&-1*e||0,g=(b.property&&b.property.value!==d?b.property.value:this._core.current())+f,h=this._core.clones().length,i=a.proxy(function(a,b){this.load(b)},this);for(c.lazyLoadEager>0&&(e+=c.lazyLoadEager,c.loop&&(g-=c.lazyLoadEager,e++));f++-1||(e.each(a.proxy(function(c,d){var e,f=a(d),g=b.devicePixelRatio>1&&f.attr("data-src-retina")||f.attr("data-src")||f.attr("data-srcset");this._core.trigger("load",{element:f,url:g},"lazy"),f.is("img")?f.one("load.owl.lazy",a.proxy(function(){f.css("opacity",1),this._core.trigger("loaded",{element:f,url:g},"lazy")},this)).attr("src",g):f.is("source")?f.one("load.owl.lazy",a.proxy(function(){this._core.trigger("loaded",{element:f,url:g},"lazy")},this)).attr("srcset",g):(e=new Image,e.onload=a.proxy(function(){f.css({"background-image":'url("'+g+'")',opacity:"1"}),this._core.trigger("loaded",{element:f,url:g},"lazy")},this),e.src=g)},this)),this._loaded.push(d.get(0)))},e.prototype.destroy=function(){var a,b;for(a in this.handlers)this._core.$element.off(a,this.handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Lazy=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(c){this._core=c,this._previousHeight=null,this._handlers={"initialized.owl.carousel refreshed.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&this.update()},this),"changed.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&"position"===a.property.name&&this.update()},this),"loaded.owl.lazy":a.proxy(function(a){a.namespace&&this._core.settings.autoHeight&&a.element.closest("."+this._core.settings.itemClass).index()===this._core.current()&&this.update()},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers),this._intervalId=null;var d=this;a(b).on("load",function(){d._core.settings.autoHeight&&d.update()}),a(b).resize(function(){d._core.settings.autoHeight&&(null!=d._intervalId&&clearTimeout(d._intervalId),d._intervalId=setTimeout(function(){d.update()},250))})};e.Defaults={autoHeight:!1,autoHeightClass:"owl-height"},e.prototype.update=function(){var b=this._core._current,c=b+this._core.settings.items,d=this._core.settings.lazyLoad,e=this._core.$stage.children().toArray().slice(b,c),f=[],g=0;a.each(e,function(b,c){f.push(a(c).height())}),g=Math.max.apply(null,f),g<=1&&d&&this._previousHeight&&(g=this._previousHeight),this._previousHeight=g,this._core.$stage.parent().height(g).addClass(this._core.settings.autoHeightClass)},e.prototype.destroy=function(){var a,b;for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.AutoHeight=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._videos={},this._playing=null,this._handlers={"initialized.owl.carousel":a.proxy(function(a){a.namespace&&this._core.register({type:"state",name:"playing",tags:["interacting"]})},this),"resize.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.video&&this.isInFullScreen()&&a.preventDefault()},this),"refreshed.owl.carousel":a.proxy(function(a){a.namespace&&this._core.is("resizing")&&this._core.$stage.find(".cloned .owl-video-frame").remove()},this),"changed.owl.carousel":a.proxy(function(a){a.namespace&&"position"===a.property.name&&this._playing&&this.stop()},this),"prepared.owl.carousel":a.proxy(function(b){if(b.namespace){var c=a(b.content).find(".owl-video");c.length&&(c.css("display","none"),this.fetch(c,a(b.content)))}},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this._core.$element.on(this._handlers),this._core.$element.on("click.owl.video",".owl-video-play-icon",a.proxy(function(a){this.play(a)},this))};e.Defaults={video:!1,videoHeight:!1,videoWidth:!1},e.prototype.fetch=function(a,b){var c=function(){return a.attr("data-vimeo-id")?"vimeo":a.attr("data-vzaar-id")?"vzaar":"youtube"}(),d=a.attr("data-vimeo-id")||a.attr("data-youtube-id")||a.attr("data-vzaar-id"),e=a.attr("data-width")||this._core.settings.videoWidth,f=a.attr("data-height")||this._core.settings.videoHeight,g=a.attr("href");if(!g)throw new Error("Missing video URL.");if(d=g.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com|be\-nocookie\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/),d[3].indexOf("youtu")>-1)c="youtube";else if(d[3].indexOf("vimeo")>-1)c="vimeo";else{if(!(d[3].indexOf("vzaar")>-1))throw new Error("Video URL not supported.");c="vzaar"}d=d[6],this._videos[g]={type:c,id:d,width:e,height:f},b.attr("data-video",g),this.thumbnail(a,this._videos[g])},e.prototype.thumbnail=function(b,c){var d,e,f,g=c.width&&c.height?"width:"+c.width+"px;height:"+c.height+"px;":"",h=b.find("img"),i="src",j="",k=this._core.settings,l=function(c){e='
',d=k.lazyLoad?a("
",{class:"owl-video-tn "+j,srcType:c}):a("
",{class:"owl-video-tn",style:"opacity:1;background-image:url("+c+")"}),b.after(d),b.after(e)};if(b.wrap(a("
",{class:"owl-video-wrapper",style:g})),this._core.settings.lazyLoad&&(i="data-src",j="owl-lazy"),h.length)return l(h.attr(i)),h.remove(),!1;"youtube"===c.type?(f="//img.youtube.com/vi/"+c.id+"/hqdefault.jpg",l(f)):"vimeo"===c.type?a.ajax({type:"GET",url:"//vimeo.com/api/v2/video/"+c.id+".json",jsonp:"callback",dataType:"jsonp",success:function(a){f=a[0].thumbnail_large,l(f)}}):"vzaar"===c.type&&a.ajax({type:"GET",url:"//vzaar.com/api/videos/"+c.id+".json",jsonp:"callback",dataType:"jsonp",success:function(a){f=a.framegrab_url,l(f)}})},e.prototype.stop=function(){this._core.trigger("stop",null,"video"),this._playing.find(".owl-video-frame").remove(),this._playing.removeClass("owl-video-playing"),this._playing=null,this._core.leave("playing"),this._core.trigger("stopped",null,"video")},e.prototype.play=function(b){var c,d=a(b.target),e=d.closest("."+this._core.settings.itemClass),f=this._videos[e.attr("data-video")],g=f.width||"100%",h=f.height||this._core.$stage.height();this._playing||(this._core.enter("playing"),this._core.trigger("play",null,"video"),e=this._core.items(this._core.relative(e.index())),this._core.reset(e.index()),c=a(''),c.attr("height",h),c.attr("width",g),"youtube"===f.type?c.attr("src","//www.youtube.com/embed/"+f.id+"?autoplay=1&rel=0&v="+f.id):"vimeo"===f.type?c.attr("src","//player.vimeo.com/video/"+f.id+"?autoplay=1"):"vzaar"===f.type&&c.attr("src","//view.vzaar.com/"+f.id+"/player?autoplay=true"),a(c).wrap('
').insertAfter(e.find(".owl-video")),this._playing=e.addClass("owl-video-playing"))},e.prototype.isInFullScreen=function(){var b=c.fullscreenElement||c.mozFullScreenElement||c.webkitFullscreenElement;return b&&a(b).parent().hasClass("owl-video-frame")},e.prototype.destroy=function(){var a,b;this._core.$element.off("click.owl.video");for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Video=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this.core=b,this.core.options=a.extend({},e.Defaults,this.core.options),this.swapping=!0,this.previous=d,this.next=d,this.handlers={"change.owl.carousel":a.proxy(function(a){a.namespace&&"position"==a.property.name&&(this.previous=this.core.current(),this.next=a.property.value)},this),"drag.owl.carousel dragged.owl.carousel translated.owl.carousel":a.proxy(function(a){a.namespace&&(this.swapping="translated"==a.type)},this),"translate.owl.carousel":a.proxy(function(a){a.namespace&&this.swapping&&(this.core.options.animateOut||this.core.options.animateIn)&&this.swap()},this)},this.core.$element.on(this.handlers)};e.Defaults={animateOut:!1,
+animateIn:!1},e.prototype.swap=function(){if(1===this.core.settings.items&&a.support.animation&&a.support.transition){this.core.speed(0);var b,c=a.proxy(this.clear,this),d=this.core.$stage.children().eq(this.previous),e=this.core.$stage.children().eq(this.next),f=this.core.settings.animateIn,g=this.core.settings.animateOut;this.core.current()!==this.previous&&(g&&(b=this.core.coordinates(this.previous)-this.core.coordinates(this.next),d.one(a.support.animation.end,c).css({left:b+"px"}).addClass("animated owl-animated-out").addClass(g)),f&&e.one(a.support.animation.end,c).addClass("animated owl-animated-in").addClass(f))}},e.prototype.clear=function(b){a(b.target).css({left:""}).removeClass("animated owl-animated-out owl-animated-in").removeClass(this.core.settings.animateIn).removeClass(this.core.settings.animateOut),this.core.onTransitionEnd()},e.prototype.destroy=function(){var a,b;for(a in this.handlers)this.core.$element.off(a,this.handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.Animate=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){var e=function(b){this._core=b,this._call=null,this._time=0,this._timeout=0,this._paused=!0,this._handlers={"changed.owl.carousel":a.proxy(function(a){a.namespace&&"settings"===a.property.name?this._core.settings.autoplay?this.play():this.stop():a.namespace&&"position"===a.property.name&&this._paused&&(this._time=0)},this),"initialized.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.autoplay&&this.play()},this),"play.owl.autoplay":a.proxy(function(a,b,c){a.namespace&&this.play(b,c)},this),"stop.owl.autoplay":a.proxy(function(a){a.namespace&&this.stop()},this),"mouseover.owl.autoplay":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is("rotating")&&this.pause()},this),"mouseleave.owl.autoplay":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is("rotating")&&this.play()},this),"touchstart.owl.core":a.proxy(function(){this._core.settings.autoplayHoverPause&&this._core.is("rotating")&&this.pause()},this),"touchend.owl.core":a.proxy(function(){this._core.settings.autoplayHoverPause&&this.play()},this)},this._core.$element.on(this._handlers),this._core.options=a.extend({},e.Defaults,this._core.options)};e.Defaults={autoplay:!1,autoplayTimeout:5e3,autoplayHoverPause:!1,autoplaySpeed:!1},e.prototype._next=function(d){this._call=b.setTimeout(a.proxy(this._next,this,d),this._timeout*(Math.round(this.read()/this._timeout)+1)-this.read()),this._core.is("interacting")||c.hidden||this._core.next(d||this._core.settings.autoplaySpeed)},e.prototype.read=function(){return(new Date).getTime()-this._time},e.prototype.play=function(c,d){var e;this._core.is("rotating")||this._core.enter("rotating"),c=c||this._core.settings.autoplayTimeout,e=Math.min(this._time%(this._timeout||c),c),this._paused?(this._time=this.read(),this._paused=!1):b.clearTimeout(this._call),this._time+=this.read()%c-e,this._timeout=c,this._call=b.setTimeout(a.proxy(this._next,this,d),c-e)},e.prototype.stop=function(){this._core.is("rotating")&&(this._time=0,this._paused=!0,b.clearTimeout(this._call),this._core.leave("rotating"))},e.prototype.pause=function(){this._core.is("rotating")&&!this._paused&&(this._time=this.read(),this._paused=!0,b.clearTimeout(this._call))},e.prototype.destroy=function(){var a,b;this.stop();for(a in this._handlers)this._core.$element.off(a,this._handlers[a]);for(b in Object.getOwnPropertyNames(this))"function"!=typeof this[b]&&(this[b]=null)},a.fn.owlCarousel.Constructor.Plugins.autoplay=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){"use strict";var e=function(b){this._core=b,this._initialized=!1,this._pages=[],this._controls={},this._templates=[],this.$element=this._core.$element,this._overrides={next:this._core.next,prev:this._core.prev,to:this._core.to},this._handlers={"prepared.owl.carousel":a.proxy(function(b){b.namespace&&this._core.settings.dotsData&&this._templates.push(''+a(b.content).find("[data-dot]").addBack("[data-dot]").attr("data-dot")+"
")},this),"added.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.dotsData&&this._templates.splice(a.position,0,this._templates.pop())},this),"remove.owl.carousel":a.proxy(function(a){a.namespace&&this._core.settings.dotsData&&this._templates.splice(a.position,1)},this),"changed.owl.carousel":a.proxy(function(a){a.namespace&&"position"==a.property.name&&this.draw()},this),"initialized.owl.carousel":a.proxy(function(a){a.namespace&&!this._initialized&&(this._core.trigger("initialize",null,"navigation"),this.initialize(),this.update(),this.draw(),this._initialized=!0,this._core.trigger("initialized",null,"navigation"))},this),"refreshed.owl.carousel":a.proxy(function(a){a.namespace&&this._initialized&&(this._core.trigger("refresh",null,"navigation"),this.update(),this.draw(),this._core.trigger("refreshed",null,"navigation"))},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this.$element.on(this._handlers)};e.Defaults={nav:!1,navText:['‹ ','› '],navSpeed:!1,navElement:'button type="button" role="presentation"',navContainer:!1,navContainerClass:"owl-nav",navClass:["owl-prev","owl-next"],slideBy:1,dotClass:"owl-dot",dotsClass:"owl-dots",dots:!0,dotsEach:!1,dotsData:!1,dotsSpeed:!1,dotsContainer:!1},e.prototype.initialize=function(){var b,c=this._core.settings;this._controls.$relative=(c.navContainer?a(c.navContainer):a("").addClass(c.navContainerClass).appendTo(this.$element)).addClass("disabled"),this._controls.$previous=a("<"+c.navElement+">").addClass(c.navClass[0]).html(c.navText[0]).prependTo(this._controls.$relative).on("click",a.proxy(function(a){this.prev(c.navSpeed)},this)),this._controls.$next=a("<"+c.navElement+">").addClass(c.navClass[1]).html(c.navText[1]).appendTo(this._controls.$relative).on("click",a.proxy(function(a){this.next(c.navSpeed)},this)),c.dotsData||(this._templates=[a('
').addClass(c.dotClass).append(a("")).prop("outerHTML")]),this._controls.$absolute=(c.dotsContainer?a(c.dotsContainer):a("").addClass(c.dotsClass).appendTo(this.$element)).addClass("disabled"),this._controls.$absolute.on("click","button",a.proxy(function(b){var d=a(b.target).parent().is(this._controls.$absolute)?a(b.target).index():a(b.target).parent().index();b.preventDefault(),this.to(d,c.dotsSpeed)},this));for(b in this._overrides)this._core[b]=a.proxy(this[b],this)},e.prototype.destroy=function(){var a,b,c,d,e;e=this._core.settings;for(a in this._handlers)this.$element.off(a,this._handlers[a]);for(b in this._controls)"$relative"===b&&e.navContainer?this._controls[b].html(""):this._controls[b].remove();for(d in this.overides)this._core[d]=this._overrides[d];for(c in Object.getOwnPropertyNames(this))"function"!=typeof this[c]&&(this[c]=null)},e.prototype.update=function(){var a,b,c,d=this._core.clones().length/2,e=d+this._core.items().length,f=this._core.maximum(!0),g=this._core.settings,h=g.center||g.autoWidth||g.dotsData?1:g.dotsEach||g.items;if("page"!==g.slideBy&&(g.slideBy=Math.min(g.slideBy,g.items)),g.dots||"page"==g.slideBy)for(this._pages=[],a=d,b=0,c=0;a
=h||0===b){if(this._pages.push({start:Math.min(f,a-d),end:a-d+h-1}),Math.min(f,a-d)===f)break;b=0,++c}b+=this._core.mergers(this._core.relative(a))}},e.prototype.draw=function(){var b,c=this._core.settings,d=this._core.items().length<=c.items,e=this._core.relative(this._core.current()),f=c.loop||c.rewind;this._controls.$relative.toggleClass("disabled",!c.nav||d),c.nav&&(this._controls.$previous.toggleClass("disabled",!f&&e<=this._core.minimum(!0)),this._controls.$next.toggleClass("disabled",!f&&e>=this._core.maximum(!0))),this._controls.$absolute.toggleClass("disabled",!c.dots||d),c.dots&&(b=this._pages.length-this._controls.$absolute.children().length,c.dotsData&&0!==b?this._controls.$absolute.html(this._templates.join("")):b>0?this._controls.$absolute.append(new Array(b+1).join(this._templates[0])):b<0&&this._controls.$absolute.children().slice(b).remove(),this._controls.$absolute.find(".active").removeClass("active"),this._controls.$absolute.children().eq(a.inArray(this.current(),this._pages)).addClass("active"))},e.prototype.onTrigger=function(b){var c=this._core.settings;b.page={index:a.inArray(this.current(),this._pages),count:this._pages.length,size:c&&(c.center||c.autoWidth||c.dotsData?1:c.dotsEach||c.items)}},e.prototype.current=function(){var b=this._core.relative(this._core.current());return a.grep(this._pages,a.proxy(function(a,c){return a.start<=b&&a.end>=b},this)).pop()},e.prototype.getPosition=function(b){var c,d,e=this._core.settings;return"page"==e.slideBy?(c=a.inArray(this.current(),this._pages),d=this._pages.length,b?++c:--c,c=this._pages[(c%d+d)%d].start):(c=this._core.relative(this._core.current()),d=this._core.items().length,b?c+=e.slideBy:c-=e.slideBy),c},e.prototype.next=function(b){a.proxy(this._overrides.to,this._core)(this.getPosition(!0),b)},e.prototype.prev=function(b){a.proxy(this._overrides.to,this._core)(this.getPosition(!1),b)},e.prototype.to=function(b,c,d){var e;!d&&this._pages.length?(e=this._pages.length,a.proxy(this._overrides.to,this._core)(this._pages[(b%e+e)%e].start,c)):a.proxy(this._overrides.to,this._core)(b,c)},a.fn.owlCarousel.Constructor.Plugins.Navigation=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){"use strict";var e=function(c){this._core=c,this._hashes={},this.$element=this._core.$element,this._handlers={"initialized.owl.carousel":a.proxy(function(c){c.namespace&&"URLHash"===this._core.settings.startPosition&&a(b).trigger("hashchange.owl.navigation")},this),"prepared.owl.carousel":a.proxy(function(b){if(b.namespace){var c=a(b.content).find("[data-hash]").addBack("[data-hash]").attr("data-hash");if(!c)return;this._hashes[c]=b.content}},this),"changed.owl.carousel":a.proxy(function(c){if(c.namespace&&"position"===c.property.name){var d=this._core.items(this._core.relative(this._core.current())),e=a.map(this._hashes,function(a,b){return a===d?b:null}).join();if(!e||b.location.hash.slice(1)===e)return;b.location.hash=e}},this)},this._core.options=a.extend({},e.Defaults,this._core.options),this.$element.on(this._handlers),a(b).on("hashchange.owl.navigation",a.proxy(function(a){var c=b.location.hash.substring(1),e=this._core.$stage.children(),f=this._hashes[c]&&e.index(this._hashes[c]);f!==d&&f!==this._core.current()&&this._core.to(this._core.relative(f),!1,!0)},this))};e.Defaults={URLhashListener:!1},e.prototype.destroy=function(){var c,d;a(b).off("hashchange.owl.navigation");for(c in this._handlers)this._core.$element.off(c,this._handlers[c]);for(d in Object.getOwnPropertyNames(this))"function"!=typeof this[d]&&(this[d]=null)},a.fn.owlCarousel.Constructor.Plugins.Hash=e}(window.Zepto||window.jQuery,window,document),function(a,b,c,d){function e(b,c){var e=!1,f=b.charAt(0).toUpperCase()+b.slice(1);return a.each((b+" "+h.join(f+" ")+f).split(" "),function(a,b){if(g[b]!==d)return e=!c||b,!1}),e}function f(a){return e(a,!0)}var g=a("").get(0).style,h="Webkit Moz O ms".split(" "),i={transition:{end:{WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",transition:"transitionend"}},animation:{end:{WebkitAnimation:"webkitAnimationEnd",MozAnimation:"animationend",OAnimation:"oAnimationEnd",animation:"animationend"}}},j={csstransforms:function(){return!!e("transform")},csstransforms3d:function(){return!!e("perspective")},csstransitions:function(){return!!e("transition")},cssanimations:function(){return!!e("animation")}};j.csstransitions()&&(a.support.transition=new String(f("transition")),a.support.transition.end=i.transition.end[a.support.transition]),j.cssanimations()&&(a.support.animation=new String(f("animation")),a.support.animation.end=i.animation.end[a.support.animation]),j.csstransforms()&&(a.support.transform=new String(f("transform")),a.support.transform3d=j.csstransforms3d())}(window.Zepto||window.jQuery,window,document);
diff --git a/theme_levelup/static/src/js/service_slider.js b/theme_levelup/static/src/js/service_slider.js
new file mode 100644
index 0000000000..09ea606889
--- /dev/null
+++ b/theme_levelup/static/src/js/service_slider.js
@@ -0,0 +1,31 @@
+/** @odoo-module */
+import PublicWidget from "@web/legacy/js/public/public_widget"
+
+export const serviceSlider = PublicWidget.Widget.extend({
+ selector: "#wrapwrap",
+ /* Start function for calling slider function */
+ start() {
+ this.slider_2()
+ },
+ /* Function for carousel slider */
+ slider_2() {
+ if(this.$el.find('.test_slider2')){
+ var owl = this.$el.find('.test_slider2').owlCarousel({
+ loop: true,
+ margin: 10,
+ nav: false,
+ dots:false,
+ items: 3,
+ center:true,
+ })
+ this.$el.find('.custom-nav .prev').click(function () {
+ owl.trigger('prev.owl.carousel')
+ })
+ this.$el.find('.custom-nav .next').click(function () {
+ owl.trigger('next.owl.carousel')
+ });
+ }
+ },
+})
+
+PublicWidget.registry.serviceSlider = serviceSlider
diff --git a/theme_levelup/static/src/scss/_common.scss b/theme_levelup/static/src/scss/_common.scss
new file mode 100644
index 0000000000..2ad9a30746
--- /dev/null
+++ b/theme_levelup/static/src/scss/_common.scss
@@ -0,0 +1,82 @@
+*:focus {
+ outline: 0 !important;
+}
+*:hover {
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+}
+*:focus {
+ outline: 0 !important;
+ box-shadow: none !important;
+}
+*button:focus {
+ border: none;
+ outline: none;
+ box-shadow: none;
+}
+* {
+ list-style-type: none;
+ font-family:$font-default;
+ font-size: 16px;
+ &:focus,
+ &:active {
+ outline: none !important;
+ }
+}
+html.sr .load-hidden {
+ visibility: hidden;
+}
+*:hover {
+ -webkit-transition: 0.8s !important;
+ transition: 0.8s !important;
+}
+*::selection {
+ color: rgb(243, 235, 238);
+ background-color: black;
+}
+*a,
+a:visited {
+ color: #990000;
+ text-decoration: none;
+}
+body {
+ position: relative;
+}
+.affix {
+ top: 0;
+ width: 100%;
+ z-index: 9999 !important;
+}
+html {
+ scroll-behavior: smooth !important;
+}
+body {
+ scroll-behavior: smooth !important;
+}
+.main_heading{
+ text-align: center;
+ h3{
+color: var(--level-color-3);
+font-size: 40px;
+font-weight: 600;
+text-transform: capitalize;
+line-height: 1.3;
+
+@media screen and(max-width:576px) {
+ font-size: 25px;
+}
+ }
+ p{
+ color: var(--level-brand);
+ font-size: 14px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 1.4px;
+ }
+}
+.heading_c{
+ color: var(--eco-color-1);
+ font-size: 24px;
+ font-weight: 700;
+ text-transform:capitalize;
+}
diff --git a/theme_levelup/static/src/scss/_normalize.scss b/theme_levelup/static/src/scss/_normalize.scss
new file mode 100644
index 0000000000..10c5cbc915
--- /dev/null
+++ b/theme_levelup/static/src/scss/_normalize.scss
@@ -0,0 +1,349 @@
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+
+/* Document
+ ========================================================================== */
+
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+
+ html {
+ line-height: 1.15; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+ }
+
+ /* Sections
+ ========================================================================== */
+
+ /**
+ * Remove the margin in all browsers.
+ */
+
+ body {
+ margin: 0;
+ }
+
+ /**
+ * Render the `main` element consistently in IE.
+ */
+
+ main {
+ display: block;
+ }
+
+ /**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+
+ h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+ }
+
+ /* Grouping content
+ ========================================================================== */
+
+ /**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+
+ hr {
+ box-sizing: content-box; /* 1 */
+ height: 0; /* 1 */
+ overflow: visible; /* 2 */
+ }
+
+ /**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+ pre {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+ }
+
+ /* Text-level semantics
+ ========================================================================== */
+
+ /**
+ * Remove the gray background on active links in IE 10.
+ */
+
+ a {
+ background-color: transparent;
+ }
+
+ /**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+
+ abbr[title] {
+ border-bottom: none; /* 1 */
+ text-decoration: underline; /* 2 */
+ text-decoration: underline dotted; /* 2 */
+ }
+
+ /**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+
+ b,
+ strong {
+ font-weight: bolder;
+ }
+
+ /**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+ code,
+ kbd,
+ samp {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+ }
+
+ /**
+ * Add the correct font size in all browsers.
+ */
+
+ small {
+ font-size: 80%;
+ }
+
+ /**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+
+ sub,
+ sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+ }
+
+ sub {
+ bottom: -0.25em;
+ }
+
+ sup {
+ top: -0.5em;
+ }
+
+ /* Embedded content
+ ========================================================================== */
+
+ /**
+ * Remove the border on images inside links in IE 10.
+ */
+
+ img {
+ border-style: none;
+ }
+
+ /* Forms
+ ========================================================================== */
+
+ /**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+
+ button,
+ input,
+ optgroup,
+ select,
+ textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+ }
+
+ /**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+
+ button,
+ input { /* 1 */
+ overflow: visible;
+ }
+
+ /**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+
+ button,
+ select { /* 1 */
+ text-transform: none;
+ }
+
+ /**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+
+ button,
+ [type="button"],
+ [type="reset"],
+ [type="submit"] {
+ -webkit-appearance: button;
+ }
+
+ /**
+ * Remove the inner border and padding in Firefox.
+ */
+
+ button::-moz-focus-inner,
+ [type="button"]::-moz-focus-inner,
+ [type="reset"]::-moz-focus-inner,
+ [type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+ }
+
+ /**
+ * Restore the focus styles unset by the previous rule.
+ */
+
+ button:-moz-focusring,
+ [type="button"]:-moz-focusring,
+ [type="reset"]:-moz-focusring,
+ [type="submit"]:-moz-focusring {
+ outline: 1px dotted ButtonText;
+ }
+
+ /**
+ * Correct the padding in Firefox.
+ */
+
+ fieldset {
+ padding: 0.35em 0.75em 0.625em;
+ }
+
+ /**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ * `fieldset` elements in all browsers.
+ */
+
+ legend {
+ box-sizing: border-box; /* 1 */
+ color: inherit; /* 2 */
+ display: table; /* 1 */
+ max-width: 100%; /* 1 */
+ padding: 0; /* 3 */
+ white-space: normal; /* 1 */
+ }
+
+ /**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+
+ progress {
+ vertical-align: baseline;
+ }
+
+ /**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+
+ textarea {
+ overflow: auto;
+ }
+
+ /**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+
+ [type="checkbox"],
+ [type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+ }
+
+ /**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+
+ [type="number"]::-webkit-inner-spin-button,
+ [type="number"]::-webkit-outer-spin-button {
+ height: auto;
+ }
+
+ /**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+
+ [type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ outline-offset: -2px; /* 2 */
+ }
+
+ /**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+
+ [type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+ }
+
+ /**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+
+ ::-webkit-file-upload-button {
+ -webkit-appearance: button; /* 1 */
+ font: inherit; /* 2 */
+ }
+
+ /* Interactive
+ ========================================================================== */
+
+ /*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+
+ details {
+ display: block;
+ }
+
+ /*
+ * Add the correct display in all browsers.
+ */
+
+ summary {
+ display: list-item;
+ }
+
+ /* Misc
+ ========================================================================== */
+
+ /**
+ * Add the correct display in IE 10+.
+ */
+
+ template {
+ display: none;
+ }
+
+ /**
+ * Add the correct display in IE 10.
+ */
+
+ [hidden] {
+ display: none;
+ }
diff --git a/theme_levelup/static/src/scss/_variables.scss b/theme_levelup/static/src/scss/_variables.scss
new file mode 100644
index 0000000000..0fbd688946
--- /dev/null
+++ b/theme_levelup/static/src/scss/_variables.scss
@@ -0,0 +1,51 @@
+// Fonts
+$font-default: 'Poppins', sans-serif;
+
+$font-h1: 36px;
+$font-h2: 18px;
+$font-h3: 36px;
+$font-h4: 25px;
+$font-h5: 36px;
+$font-h6: 18px;
+$font-size-banner: 60px;
+$font-heading: 46px;
+$font-sub-heading: 28px;
+$font-text: 14px;
+$font-brand: 30px;
+
+$easing: cubic-bezier(0.25, 1.7, 0.35, 0.8);
+$duration: 0.5s;
+
+:root {
+ // --primar-gradient-color-one: rgba(95, 85, 157, 1);
+ // --primar-gradient-color-two: rgba(187, 180, 230, 1);
+ // --primar-gradient-color-three: #d5d1eb;
+ // --primar-color: #6b62a1;
+ // --secondary-color: #ffffff;
+ --level-brand:#fcb017;
+ --level-color-1: #253237;
+ --level-color-2: #000;
+ --level-color-3: #181818;
+ --section-bg: #f2f2f2;
+ --sub-color-1: #dc3545;
+ --sub-color-2: #2250fc;
+ --sub-color-3: #c52132;
+
+ --button-color: #50449c;
+ --p-color: #484848;
+ --p-color2: #777;
+ --p-color3: #eaeaea;
+--p-color4:#a2abb7;
+
+ --banner-title-bg: #f8f9fa;
+ --subhead-color: #000000;
+ --white-color: #ffffff;
+ --footer-main: #f3f3f3;
+
+ --footer-sub: #f8f9fa !important;
+ --border-color2: #eeecec;
+ --border-color: #dad6d6;
+
+}
+
+$form-select-bg: red !important;
diff --git a/theme_levelup/static/src/scss/components/_buttons.scss b/theme_levelup/static/src/scss/components/_buttons.scss
new file mode 100644
index 0000000000..7036f645af
--- /dev/null
+++ b/theme_levelup/static/src/scss/components/_buttons.scss
@@ -0,0 +1,135 @@
+.btn {
+ border: none !important;
+ outline: 0 !important;
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ &-primary {
+// border-radius: 25px 25px;
+ border: 2px solid var(--white-color) !important;
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.6px;
+ text-decoration: none;
+ padding: 15px 25px;
+ position: relative;
+ text-transform: uppercase;
+ background-color:transparent !important;
+ color: var(--white-color) !important;
+ transition: all 0.3s;
+
+ line-height: 14px;
+ &:hover {
+ background-color: var(--white-color) !important;
+ color: var(--level-color-1) !important;
+ }
+ }
+
+ &-secondary {
+ border-radius:0;
+ border: 2px solid var(--white-color) !important;
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.6px;
+ text-decoration: none;
+ padding: 15px 25px;
+ position: relative;
+ text-transform: uppercase;
+ background-color:transparent;
+ color: var(--white-color) !important;
+ transition: all 0.3s;
+
+ line-height: 14px;
+ &:hover {
+ background-color: var(--white-color) !important;
+ color: var(--level-color-1) !important;
+ }
+ }
+ &-service {
+ border-radius: 0px;
+ border: none imo !important;
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.6px;
+ text-decoration: none;
+ padding: 15px 25px;
+ position: relative;
+ text-transform: uppercase;
+ background: rgb(241, 104, 104);
+ background: linear-gradient(38deg, rgba(241, 104, 104, 1) 14%, rgba(252, 176, 23, 1) 60%, rgba(252, 176, 23, 1) 100%);
+
+ color: var(--white-color) !important;
+ transition: all 0.3s;
+
+ line-height: 14px;
+ &:hover {
+ transform: scale(1.1);
+ }
+ }
+ &-price {
+ border-radius: 0;
+ border: 2px solid var(--level-color-1) !important;
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.6px;
+ text-decoration: none;
+ padding: 15px 25px;
+ position: relative;
+ text-transform: uppercase;
+ background-color:transparent ;
+ color: var(--level-color-1) !important;
+ transition: all 0.3s;
+
+ line-height: 14px;
+ &:hover {
+ background-color:var(--level-color-1);
+ color: var(--white-color) !important;
+ border: none;
+
+ }
+ }
+ &-price_m {
+ border-radius: 0;
+ border: none;
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.6px;
+ text-decoration: none;
+ padding: 15px 25px;
+ position: relative;
+ text-transform: uppercase;
+ background-color:var(--level-color-1);
+ color: var(--white-color) !important;
+ transition: all 0.3s;
+
+ line-height: 14px;
+ &:hover {
+ background-color: transparent;
+ color: var(--level-color-1) !important;
+ border: 2px solid var(--level-color-1) !important;
+ }
+ }
+
+ &-join {
+ border-radius: 0;
+ border: none;
+ font-size: 12px;
+ font-weight: 600;
+ letter-spacing: 0.6px;
+ text-decoration: none;
+ padding: 15px 25px;
+ position: relative;
+ text-transform: uppercase;
+ background-color:var(--white-color);
+ color: var(--level-color-1) !important;
+ transition: all 0.3s;
+
+ line-height: 14px;
+ &:hover {
+ background-color:var(--level-color-1);
+ color: var(--white-color) !important;
+ border: none;
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/theme_levelup/static/src/scss/components/_components.scss b/theme_levelup/static/src/scss/components/_components.scss
new file mode 100644
index 0000000000..dd94ec3ac9
--- /dev/null
+++ b/theme_levelup/static/src/scss/components/_components.scss
@@ -0,0 +1 @@
+@import './buttons'
\ No newline at end of file
diff --git a/theme_levelup/static/src/scss/layouts/_banner.scss b/theme_levelup/static/src/scss/layouts/_banner.scss
new file mode 100644
index 0000000000..38e037d961
--- /dev/null
+++ b/theme_levelup/static/src/scss/layouts/_banner.scss
@@ -0,0 +1,171 @@
+.banner {
+ color: aliceblue;
+ .wrapper {
+ .banner_bg_1,
+ .banner_bg_2,
+ .banner_bg_3 {
+ background-image: url(./../images/banner/banner-1.jpg);
+ background-position: center;
+ background-size: cover;
+ height: 100vh;
+ position: relative;
+ &::after {
+ position: absolute;
+ content: " ";
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ background-color: rgba(0, 0, 0, 0.226);
+ }
+ .banner_content {
+ width: 100%;
+ height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 1;
+ text-align: center;
+ .c_wrapper {
+ position: absolute;
+ z-index: 999;
+ @media screen and(max-width:992px) {
+ padding-top: 30px;
+ }
+ @media screen and(max-width:768px) {
+ padding-top: 0px;
+ }
+ p {
+ color: var(--p-color3) !important;
+ font-size: 20px;
+ @media screen and(max-width:992px) {
+ font-size: 16px;
+ }
+ }
+ h1 {
+ font-size: 6em;
+ font-weight: 900;
+ text-transform: uppercase;
+ margin-top: 0;
+ @media screen and(max-width:1200px) {
+ font-size: 4em;
+ padding-top: 30px;
+ }
+ @media screen and(max-width:992px) {
+ font-size: 3em;
+ br {
+ display: none;
+ }
+ }
+ @media screen and(max-width:600px) {
+ br {
+ display: block;
+ }
+ }
+ }
+ }
+ }
+ }
+ .banner_bg_2 {
+ background-image: url(./../images/banner/banner-2.jpg) !important;
+ }
+ .banner_bg_3 {
+ background-image: url(./../images/banner/banner-3.jpg) !important;
+ }
+ .owl-carousel {
+ .owl-nav {
+ position: absolute;
+ top: 50%;
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ padding: 0px 30px;
+ button {
+ span {
+ font-size: 20px;
+ }
+ }
+ }
+ }
+ }
+}
+.banner_about {
+ background-image: url(./../images/banner/banner_about.jpg);
+ background-position: center;
+ background-size: cover;
+ position: relative;
+ &::after {
+ position: absolute;
+ content: " ";
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ background-color: rgba(0, 0, 0, 0.226);
+ }
+ .banner_content {
+ width: 100%;
+ height: 75vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 1;
+ text-align: center;
+ @media screen and(max-width:768px){
+ height: 60vh;
+ }
+ .c_wrapper {
+ position: absolute;
+ z-index: 999;
+ h1 {
+ font-size: 5em;
+ font-weight: 800;
+ text-transform: uppercase;
+ margin-top: 0;
+ color: var(--white-color);
+ padding-top: 30px;
+ @media screen and(max-width:992px){
+ font-size: 3.5em;
+ }
+ @media screen and(max-width:768px){
+ font-size: 2.5em;
+ font-weight: 700;
+ }
+ }
+ .breadcrumb {
+ background-color: transparent;
+ justify-content: center;
+ .breadcrumb-item {
+ text-transform: uppercase;
+ &:first-child {
+ &::before {
+ display: none !important;
+ }
+ }
+ &::before {
+ display: inline-block;
+ padding-right: 0.5rem;
+ padding-left: 0.5rem;
+ color: #ffffff;
+ content: ".";
+ }
+ a {
+ color: var(--white-color) !important;
+ &:hover {
+ text-decoration: none;
+ }
+ }
+ &.active {
+ color: var(--p-color4) !important;
+ }
+ }
+ }
+ }
+ }
+}
+.banner_portfolio {
+ background-image: url(./../images/banner/banner_portfolio.jpg) !important;
+}
+.banner_team {
+ background-image: url(./../images/banner/banner_team.jpg) !important;
+}
diff --git a/theme_levelup/static/src/scss/layouts/_footer.scss b/theme_levelup/static/src/scss/layouts/_footer.scss
new file mode 100644
index 0000000000..bbe0748932
--- /dev/null
+++ b/theme_levelup/static/src/scss/layouts/_footer.scss
@@ -0,0 +1,119 @@
+.footer {
+ background-color: var(--level-color-1);
+ padding: 100px 0px 50px 0px;
+ @media screen and(max-width:992px) {
+ padding: 100px 15px 50px 15px;
+ }
+ .wrapper {
+ .top {
+ margin-bottom: 50px;
+ }
+ .footer_c {
+ .footer_heading {
+ color: var(--white-color);
+ font-size: 18px;
+ font-weight: 600;
+ margin-bottom: 15px;
+ padding-bottom: 15px;
+ }
+ p {
+ color: var(--p-color4) !important;
+ font-size: 13px;
+ line-height: 1.9;
+ margin-right: 50px;
+ }
+ ul {
+ padding-left: 0;
+ li {
+ padding-bottom: 15px;
+ a {
+ color: var(--p-color4);
+ font-size: 13px;
+ line-height: 1.9;
+ &:hover {
+ color: var(--white-color) !important;
+ text-decoration: none;
+ }
+ }
+ }
+ }
+ .input-group {
+ .form-control {
+ box-shadow: none !important;
+ outline: none !important;
+ font-size: 12px !important;
+ padding: 10px 10px;
+ color: var(--p-color3);
+ border: none !important;
+ }
+ .input-group-append {
+ .btn-outline-secondary {
+ padding: 10px 20px;
+ background-color: var(--level-brand) !important;
+ i {
+ color: var(--white-color);
+ }
+ }
+ }
+ }
+ }
+ .bottom {
+ border: 1px solid;
+ border-color: transparent;
+ border-top-color: var(--p-color) !important;
+ padding-top: 50px;
+ @media screen and(max-width:768px) {
+ padding-top: 30px;
+ }
+ .footer_brand {
+ .brand {
+ font-size: 30px;
+ color: var(--white-color);
+ font-weight: 700;
+ display: block;
+ span {
+ max-width: 46px;
+ display: inline-block;
+ img {
+ width: 100%;
+ margin-top: -16px;
+ margin-left: 10px;
+ }
+ }
+ &:hover {
+ text-decoration: none;
+ }
+ @media screen and(max-width:992px) {
+ margin-bottom: 20px;
+ }
+ }
+ }
+ .credits {
+ p {
+ font-size: 14px;
+ color: var(--p-color3);
+ text-align: center;
+ margin-bottom: 0;
+ padding-top: 10px;
+ @media screen and(max-width:992px) {
+ text-align: start;
+ margin-bottom: 20px;
+ }
+ }
+ }
+ .footer_icon {
+ form {
+ span {
+ margin-right: 30px;
+ a {
+ color: var(--white-color);
+ }
+ }
+ :last-child {
+ margin-right: 0px !important;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/layouts/_layouts.scss b/theme_levelup/static/src/scss/layouts/_layouts.scss
new file mode 100644
index 0000000000..0624d44fa2
--- /dev/null
+++ b/theme_levelup/static/src/scss/layouts/_layouts.scss
@@ -0,0 +1,6 @@
+@import './banner';
+@import './footer';
+@import './forms';
+@import './header';
+@import './navigation';
+@import './sidebar';
diff --git a/theme_levelup/static/src/scss/layouts/_navigation.scss b/theme_levelup/static/src/scss/layouts/_navigation.scss
new file mode 100644
index 0000000000..3721056d6e
--- /dev/null
+++ b/theme_levelup/static/src/scss/layouts/_navigation.scss
@@ -0,0 +1,212 @@
+.header_modern_light {
+ .navigation {
+ transition: background-color 0.4s ease-out;
+ .navbar {
+ margin: 10px 50px 10px 50px;
+ @media screen and(max-width:1200px) {
+ margin: 0px;
+ padding: 15px 0px;
+ padding-bottom: 0;
+
+ }
+ .navbar-brand {
+ font-size: 30px;
+ color: var(--white-color);
+ font-weight: 700;
+
+ @media screen and(max-width:1200px) {
+ margin-right: auto;
+ padding-left: 15px;
+ }
+ span {
+ max-width: 46px;
+ display: inline-block;
+ img {
+ width: 100%;
+ margin-top: -16px;
+ margin-left: 10px;
+ }
+ }
+ }
+ .navbar-collapse {
+ @media screen and(max-width:1200px) {
+ background-color: var(--white-color);
+ padding: 15px 15px;
+ }
+ }
+ .navbar-nav {
+ margin: auto;
+ .nav-item {
+
+ @media screen and(max-width:1200px) {
+ padding: 5px 0;
+ }
+ .nav-link {
+ color: var(--white-color);
+ font-size: 14px;
+ margin: 0px 15px;
+ font-weight: 500;
+ &:hover {
+ color: var(--p-color3);
+ }
+ @media screen and(max-width:1200px) {
+ color: var(--p-color2);
+ &:hover {
+ color: var(--p-color1);
+ }
+ }
+ }
+ }
+ }
+ form {
+ margin-left: 15px;
+ padding-right: 15px;
+ margin-right: 15px;
+
+ span {
+ padding-right: 15px;
+ a {
+ color: var(--white-color);
+ margin-right: 15px;
+
+ @media screen and(max-width:1200px) {
+
+ }
+ }
+ }
+ :last-child {
+ padding-right: 0px !important;
+ a {
+ margin-right: 0;
+ }
+ }
+ }
+ }
+ }
+}
+.bg_white {
+ background-color: rgba(0, 0, 0, 0.57);
+ transition: background-color 0.4s ease-out;
+}
+.fadeInDown {
+ -webkit-animation-name: fadeInDown;
+ animation-name: fadeInDown;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+@-webkit-keyframes fadeInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+@keyframes fadeInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+.fadeInup {
+ -webkit-animation-name: fadeInup;
+ animation-name: fadeInup;
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ animation-direction: reverse;
+}
+@-webkit-keyframes fadeInup {
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+ 0% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+@keyframes fadeInup {
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+ 0% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+.b_shadow {
+ box-shadow: 0px 3px 6px 1px rgba(200, 187, 201, 0.48);
+}
+/* top line needs a little padding */
+.navbar-toggler span:nth-child(1) {
+ margin-top: 0.3em;
+}
+/**
+ * Animate collapse into X.
+ */
+/* top line rotates 45 degrees clockwise and moves up and in a bit to close the center of the X in the center of the button */
+.navbar-toggler:not(.collapsed) span:nth-child(1) {
+ transform: translate(15%, -33%) rotate(45deg);
+}
+/* center line goes transparent */
+.navbar-toggler:not(.collapsed) span:nth-child(2) {
+ opacity: 0;
+}
+/* bottom line rotates 45 degrees counter clockwise, in, and down a bit to close the center of the X in the center of the button */
+.navbar-toggler:not(.collapsed) span:nth-child(3) {
+ transform: translate(15%, 33%) rotate(-45deg);
+}
+/**
+ * Animate collapse open into hamburger menu
+ */
+/* top line moves back to initial position and rotates back to 0 degrees */
+.navbar-toggler span:nth-child(1) {
+ transform: translate(0%, 0%) rotate(0deg);
+}
+/* middle line goes back to regular color and opacity */
+.navbar-toggler span:nth-child(2) {
+ opacity: 1;
+}
+/* bottom line goes back to initial position and rotates back to 0 degrees */
+.navbar-toggler span:nth-child(3) {
+ transform: translate(0%, 0%) rotate(0deg);
+}
+.navbar-toggler span {
+ display: block;
+ background-color: var(--white-color);
+ height: 3px;
+ width: 25px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+ position: relative;
+ border-radius: 2px;
+ left: 0;
+ opacity: 1;
+ transition: all 0.35s ease-out;
+ transform-origin: center left;
+}
+.navbar-toggler{
+ @media screen and(max-width:992px) {
+ margin-right: 25px;
+
+}
+}
diff --git a/theme_levelup/static/src/scss/pages/_about.scss b/theme_levelup/static/src/scss/pages/_about.scss
new file mode 100644
index 0000000000..fbe93c84a2
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/_about.scss
@@ -0,0 +1,315 @@
+.about {
+ position: relative;
+ padding-top: 100px;
+ @media screen and(max-width:768px) {
+ padding-top: 70px;
+ }
+ .bg_img {
+ position: absolute;
+ position: absolute;
+ z-index: -1;
+ width: 375px;
+ top: -192px;
+ left: -171px;
+ }
+ .wrapper {
+ margin-top: 40px;
+ .intro {
+ .right {
+ @media screen and(max-width:992px) {
+ padding-top: 50px
+ }
+ h6 {
+ font-size: 16px;
+ font-weight: 500;
+ text-decoration: none;
+ color: var(--level-color-3);
+ }
+ p {
+ margin-top: 18px;
+ color: var(--p-color2);
+ font-size: 14px;
+ line-height: 1.9rem;
+ padding-bottom: 30px;
+ }
+ .next {
+ a {
+ display: flex;
+ align-items: center;
+ .arrow {
+ height: 32px;
+ width: 32px;
+ border-radius: 50%;
+ background-color: var(--level-brand);
+ display: inline-block;
+ padding-top: 4px;
+ position: relative;
+ i {
+ position: absolute;
+ top: -2px;
+ left: -5px;
+ color: var(--white-color);
+ font-size: 25px;
+ margin-left: 10px;
+ }
+ }
+ span {
+ padding-left: 10px;
+ color: var(--level-color-3);
+ font-weight: 600;
+ font-size: 16px;
+ }
+ }
+ }
+ }
+ }
+ .slider {
+ padding-top: 80px;
+ margin-bottom: 40px;
+ @media screen and(max-width:992px) {
+ padding-top: 30px;
+ }
+ .bg1 {
+ margin-top: 40px;
+ img {
+ width: 100%;
+ }
+ }
+ }
+ }
+ .socail_media {
+ padding-top: 80px;
+ position: relative;
+ @media screen and(max-width:992px) {
+ padding-top: 0;
+ }
+ .big_heading {
+ color: var(--section-bg);
+ font-size: 7em;
+ font-weight: 700;
+ text-align: center;
+ margin-bottom: -70px;
+ text-transform: capitalize;
+ @media screen and(max-width:992px) {
+ font-size: 4em;
+ margin-bottom: -40px;
+ }
+ @media screen and(max-width:768px) {
+ font-size: 3em;
+ margin-bottom: -30px;
+ }
+ @media screen and(max-width:576px) {
+ display: none;
+ }
+ }
+ .warpper_s {
+ // margin-top: 40px;
+ background-color: var(--section-bg);
+ padding-top: 100px;
+ padding-bottom: 80px;
+ .content {
+ padding-top: 70px;
+ @media screen and(max-width:768px) {
+ padding-left: 15px;
+ padding-right: 15px;
+ }
+ .card-deck {
+ padding-bottom: 40px;
+ .card {
+ margin-top: 20px;
+ border: none;
+ border-radius: 5px;
+ padding: 30px 30px 35px 30px;
+ -webkit-box-shadow: 0px 2px 8px -1px rgba(217, 217, 217, 1);
+ -moz-box-shadow: 0px 2px 8px -1px rgba(217, 217, 217, 1);
+ box-shadow: 0px 2px 8px -1px rgba(217, 217, 217, 1);
+ .card-body {
+ .icon_wrapper {
+ max-width: 100px;
+ margin: auto;
+ svg {
+ width: 50px;
+ height: 50px;
+ fill: var(--level-brand);
+ margin-bottom: 15px;
+ text-align: center;
+ padding-top: 15px;
+ }
+ }
+ .card-heading {
+ padding-top: 15px;
+ color: var(--level-color3);
+ font-size: 16px;
+ font-weight: 600;
+ text-align: center;
+ }
+ .card-text {
+ padding-top: 15px;
+ color: var(--p-color2);
+ font-size: 14px;
+ text-align: center;
+ line-height: 1.9rem;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ .skills {
+ padding-top: 100px;
+ @media screen and(max-width:768px) {
+ padding-top: 50px;
+ }
+ .wrapper {
+ .top {
+ padding: 0px 50px;
+ .s_info {
+ padding-top: 15px;
+ color: var(--p-color2);
+ font-size: 14px;
+ line-height: 1.9rem;
+ }
+ .right {
+ .progress_wrapp {
+ margin-top: 30px;
+ @media screen and(max-width:768px) {
+ padding-top: 20px;
+ }
+ .p_wrapper {
+ position: relative;
+ }
+ .progress_heading {
+ justify-content: space-between;
+ z-index: 999;
+ width: 92%;
+ left: 24px;
+ top: 4px;
+ position: absolute;
+ .name {
+ font-size: 12px;
+ font-weight: 600;
+ color: var(--white-color);
+ }
+ .percent {
+ font-size: 11px;
+ color: var(--p-color2);
+ }
+ }
+ .progress {
+ margin-bottom: 10px;
+ border-radius: 0;
+ }
+ .progress-bar {
+ width: 0;
+ color: var(--sub-color-2);
+ background-color: var(--level-brand);
+ }
+ }
+ }
+ }
+ .bottom {
+ padding-top: 70px;
+ margin-top: 30px;
+ .img_wrapper {
+ max-width: 550px;
+ img {
+ width: 100%;
+ border-radius: 5px;
+ }
+ }
+ .b_right {
+ background-color: var(--white-color);
+ margin-left: -130px;
+ margin-top: 100px;
+ border-radius: 5px;
+ padding: 70px;
+ @media screen and(max-width:768px) {
+ margin-left: 0px;
+ margin-top: 50px;
+ border-radius: 5px;
+ padding: 20px;
+ }
+ .b_info {
+ padding-top: 15px;
+ color: var(--p-color2);
+ font-size: 14px;
+ line-height: 1.9rem;
+ padding-bottom: 50px;
+ }
+ }
+ }
+ }
+ }
+ .abt_video {
+ margin-top: 40px;
+ padding-top: 80px;
+ margin-bottom: 40px;
+ .wrapper {
+ background-image: url(./../../images/about_page/jason-goodman-0K7GgiA8lVE-unsplash.jpg);
+ background-position: center;
+ background-size: cover;
+ height: 90vh;
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: rgba(0, 0, 0, 0.277);
+ .play {
+ a {
+ display: block;
+ max-width: 100px;
+ img {
+ width: 100%;
+ }
+ }
+ }
+ }
+ .asd {
+ background-color: var(--white-color);
+ padding: 60px 30px;
+ border-radius: 5px;
+ margin-top: -75px;
+ box-shadow: 0px 2px 8px -1px rgba(217, 217, 217, 1);
+ position: relative;
+ @media screen and(max-width:768px) {
+ padding-top: 50px;
+ }
+ .as {
+ text-align: center;
+ h6 {
+ color: var(--level-color3);
+ font-size: 16px;
+ font-weight: 600;
+ }
+ p {
+ color: var(--p-color2);
+ font-size: 14px;
+ text-align: center;
+ }
+ }
+ }
+ }
+}
+.subscribe {
+ position: relative;
+ padding-top: 100px;
+ background-color: #f2f2f27a;
+ .wrapper {
+ margin-top: 40px;
+ text-align: center;
+ height: 40vh;
+ .bg_sub {
+ position: absolute;
+ z-index: -1;
+ width: 600px;
+ left: 50%;
+ transform: translate(-50%, 15%);
+ }
+ .wrapper_sub {
+ width: 100%;
+ position: absolute;
+ z-index: 999;
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/_contact.scss b/theme_levelup/static/src/scss/pages/_contact.scss
new file mode 100644
index 0000000000..0cc01d9080
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/_contact.scss
@@ -0,0 +1,150 @@
+.contact {
+ padding-top: 80px;
+
+ .wrapper {
+ margin-top: 70px;
+
+ .contact_top {
+ .top_content {
+ text-align: center;
+
+ .c_icon {
+ svg {
+ width: 50px;
+ height: 50px;
+ fill: var(--level-brand);
+ margin-bottom: 15px;
+ text-align: center;
+ padding-top: 15px;
+ }
+ }
+
+ h6 {
+ text-transform: uppercase;
+ color: var(--level-color-3);
+ margin-bottom: 15px;
+ }
+
+ p {
+ font-size: 14px;
+ color: var(--p-color2);
+ }
+ }
+ }
+
+ .ct {
+
+
+ margin-top: 40px;
+ padding-top: 80px;
+ margin-bottom: 40px;
+
+ .wrapper {
+
+ background-image: url(./../../images/contact/c1.jpg);
+ background-position: center;
+ background-size: cover;
+ height: 90vh;
+ position: relative;
+
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+
+ &::after {
+ position: absolute;
+ content: " ";
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ background-color: rgba(252, 207, 95, 0.226);
+ }
+
+ .play {
+ position: absolute;
+ z-index: 999;
+
+ a {
+ display: block;
+ max-width: 100px;
+
+ img {
+ width: 100%;
+ }
+ }
+ }
+ }
+
+ .asd {
+ background-color: var(--white-color);
+ padding: 60px 30px;
+ border-radius: 0px;
+ margin-top: -75px;
+ box-shadow: 0px 2px 8px -1px rgba(217, 217, 217, 1);
+ position: relative;
+
+
+ .contact_form {
+ padding: 20px 30px 20px 30px;
+
+ margin: 0px 20px 0px 20px;
+ }
+
+ form {
+ padding-top: 30px;
+
+ .form-group {
+ margin-bottom: 20px;
+
+ .form-control {
+ display: block;
+ width: 100%;
+ padding: 0.375rem rem 0.75rem;
+ font-size: 1rem;
+ line-height: 2.5;
+ color: #a2a8ae;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid #ced4da;
+ border-radius: 0;
+ transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
+ }
+ }
+
+
+ }
+ }
+ }
+
+ .c_t_s {
+ padding-top: 100px;
+margin-bottom: 70px;
+ .social_media {
+ display:flex;
+ justify-content: center;
+ span{
+ color: var(--level-color-3);
+ font-size: 22px;
+ font-weight: 500;
+
+ }
+ ul {
+ display: flex;
+ li {
+ margin-left: 15px;
+ a{
+ display: block;
+ max-width: 30px;
+ img {
+ width: 100%;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/_page_blog.scss b/theme_levelup/static/src/scss/pages/_page_blog.scss
new file mode 100644
index 0000000000..aaa41348b0
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/_page_blog.scss
@@ -0,0 +1,81 @@
+.blog_page {
+
+ padding-top: 100px;
+ margin-bottom: 100px;
+
+ .wrapper {
+ .card {
+ border: none;
+ position: relative;
+ margin-bottom: 30px;
+ &:hover {
+ .card_image {
+ &::after {
+ opacity: 0 !important;
+ }
+ }
+ .card-body {
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ box-shadow: 0 0 11px rgba(24, 24, 24, 0.234) !important;
+ }
+ }
+ .type {
+ position: absolute;
+ background-color: rgba(0, 0, 0, 0.481);
+ color: var(--white-color);
+ font-size: 10px;
+ padding: 6px 15px;
+ letter-spacing: 1px;
+ top: 20px;
+ right: 20px;
+ z-index: 1000;
+ text-transform: uppercase;
+ }
+ }
+ .card_image {
+ position: relative;
+ display: block;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+ &::after {
+ content: " ";
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ width: 100%;
+ background-color: rgba(0, 0, 0, 0.271);
+ transition: all 1s ease;
+ opacity: 1;
+ z-index: 999;
+ }
+ .card-img-top {
+ border-radius: 0 !important;
+ }
+ }
+ .card-body {
+ box-shadow: 0 0 11px rgba(33, 33, 33, .2) !important;
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ text-align: start;
+ padding: 35px;
+ .card-title {
+ a {
+ font-size: 16px;
+ font-weight: 500;
+ margin-top: 15px;
+ text-decoration: none;
+ color: var(--level-color-3);
+ }
+ }
+
+ .card-text {
+ font-size: 14px;
+ color: var(--p-color2);
+ margin-bottom: 15px;
+ line-height: 2;
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/_page_team.scss b/theme_levelup/static/src/scss/pages/_page_team.scss
new file mode 100644
index 0000000000..4b9e3f1d67
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/_page_team.scss
@@ -0,0 +1,183 @@
+.page_team {
+ padding-top: 50px;
+ padding-bottom: 70px;
+ .wrapper {
+ margin-bottom: 50px;
+ .c_wrapper {
+ padding-top: 70px;
+ padding-bottom: 70px;
+ .c_img {
+ max-width: 300px;
+ overflow: hidden;
+ position: relative;
+ margin-bottom: 40px;
+ &:after {
+ position: absolute;
+ content: " ";
+ height: 100%;
+ width: 100%;
+ top: 0;
+ left: 0;
+ background: #00000054 !important;
+ opacity: 0;
+ transition: 0.5s ease;
+ }
+ img {
+ width: 100%;
+ border-radius: 5px;
+ transform: scale(1);
+ transition: 0.5s ease-in-out;
+ }
+ &:hover {
+ img {
+ transform: scale(1.3) !important;
+ }
+
+ &:after {
+ opacity: 1 !important;
+ }
+ .info {
+ display: block !important;
+ width: 100%;
+ height: 100%;
+ .i_wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+ .ss {
+ text-align: center;
+ color: var(--white-color) !important;
+ h5 {
+ font-size: 18px;
+ }
+ p {
+ font-size: 12px;
+ }
+ }
+ }
+ }
+ }
+ }
+ .info {
+ display: none;
+ position: absolute;
+ z-index: 3;
+ top: 0;
+ left: 0;
+ .i_wrapper {
+ .ss {}
+ }
+ }
+ }
+ .join_team {
+ padding: 100px 0px;
+ height: 90vh;
+ background: rgb(241, 104, 104);
+ background: linear-gradient(38deg, rgba(241, 104, 104, 1) 14%, rgba(252, 176, 23, 1) 60%, rgba(252, 176, 23, 1) 100%);
+
+ .wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin: 0;
+ height: 100%;
+
+ .join_us {
+ text-align: center;
+
+ h3 {
+ color: var(--white-color);
+ font-size: 40px;
+ font-weight: 600;
+ line-height: 1.1;
+ padding: 20px 0 30px 0;
+ margin-bottom: 25px;
+ }
+
+ p {
+ color: var(--white-color);
+ font-size: 14px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 1.4px;
+ }
+ }
+ }
+ }
+ .words {
+ padding-top: 80px;
+
+ .team_photo {
+ max-width: 400px;
+ img {
+ width: 100%;
+ }
+ }
+ .words_main {
+ background-color: var(--section-bg);
+ padding: 50px 30px;
+ .heading {
+ .p_color {
+ color: var(--level-brand);
+ font-weight: 600;
+ font-size: 14px;
+ letter-spacing: 1px;
+ }
+
+ h5 {
+ color: var(--level-color-3);
+ font-size: 24px;
+ font-weight: 600;
+ }
+ }
+ p {
+ color: var(--p-color2);
+ font-size: 14px;
+ line-height: 1.9;
+ padding-top: 15px;
+ }
+ .person {
+ display: flex;
+ align-items: center;
+ padding-top: 35px;
+ .p_img {
+ max-width: 60px;
+ img {
+ width: 100%;
+ border-radius: 50%;
+ }
+ }
+ .info {
+ margin-left: 15px;
+ h6 {
+ color: var(--level-color-3);
+ font-size: 16px;
+ font-weight: 600;
+ margin-bottom: 0;
+ }
+ p {
+ padding-top: 0;
+ color: var(--p-color2);
+ font-size: 14px;
+ margin-bottom: 0;
+ }
+ }
+ }
+ }
+ .creative_join{
+ margin-top: 70px;
+ padding-top: 30px;
+ .cj{
+ font-size: 28px;
+ font-weight:600 ;
+ span{
+ font-size: 30px;
+ font-weight:700 ;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/_pages.scss b/theme_levelup/static/src/scss/pages/_pages.scss
new file mode 100644
index 0000000000..45420f458d
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/_pages.scss
@@ -0,0 +1,7 @@
+@import './home/home';
+@import './about';
+@import './service';
+@import './contact';
+@import './portfolio';
+@import './page_team';
+@import './page_blog';
diff --git a/theme_levelup/static/src/scss/pages/_portfolio.scss b/theme_levelup/static/src/scss/pages/_portfolio.scss
new file mode 100644
index 0000000000..66839c1f4a
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/_portfolio.scss
@@ -0,0 +1,165 @@
+// Portfolio grid two coloumn
+.portfolio_grid {
+ padding-top: 100px;
+ margin-bottom: 80px;
+ .wrapper {
+ .portfolio_grid_wrapper {
+ .tab_portfolio {
+ padding-bottom: 40px;
+
+ .animated {
+ -webkit-animation-duration: 3s;
+ animation-duration: 3s;
+ -webkit-animation-delay: 500ms;
+ animation-delay: 500ms;
+ }
+ .animate-out {
+ -webkit-animation-delay: 0ms;
+ animation-delay: 0ms;
+ }
+ .wrapper_3 {
+ overflow: hidden;
+ .sliding_product {
+ .wrapper {
+ .img_wrapper {
+ position: relative;
+ margin: auto;
+ @media screen and(max-width:600px) {
+ max-width: 100%;
+ }
+ img {
+ min-height: 100%;
+ width: 100%;
+ }
+ .inner {
+ width: 100%;
+ height: 100%;
+ background-color: #00000300;
+ position: absolute;
+ top: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 3;
+ &:hover {
+ background-color: #0000038f;
+ }
+ }
+ }
+ .quick_view {
+ color: white;
+ font-size: 22px;
+ text-align: center;
+ padding: 8px 23px;
+ display: none;
+ text-decoration: none;
+ font-weight: 600 !important;
+ span {
+ font-weight: normal;
+ }
+ &:hover {}
+ }
+ &:hover {
+ .quick_view {
+ display: block;
+ }
+ }
+ }
+ }
+ }
+ .wrapper_3:hover .see {
+ transform: scale(1.3);
+ overflow: hidden;
+ }
+ /* default styles so shuffle doesn't have to set them (it will if they're missing) */
+ .my-shuffle {
+ position: relative;
+ overflow: hidden;
+ width: 100%;
+ }
+ [data-toggle="buttons"]>.btn input[type="checkbox"],
+ [data-toggle="buttons"]>.btn input[type="radio"],
+ [data-toggle="buttons"]>.btn-group>.btn input[type="checkbox"],
+ [data-toggle="buttons"]>.btn-group>.btn input[type="radio"] {
+ position: absolute;
+ clip: rect(0, 0, 0, 0);
+ pointer-events: none;
+ }
+ .port_grid {
+ // display: grid;
+ // grid-template-columns: 1fr 1fr 1fr;
+ // @media screen and(max-width:992px) {
+ // }
+ }
+ .masnory_grid_three>div {
+ width: 33% !important;
+ @media screen and(max-width:992px) {
+ width: 50% !important;
+ }
+ @media screen and(max-width:576px) {
+ width: 100% !important;
+ }
+ }
+ .masnory_grid_three>.m_s_3 {
+ width: 66% !important;
+ @media screen and(max-width:992px) {
+ width: 50% !important;
+ }
+ @media screen and(max-width:576px) {
+ width: 100% !important;
+ }
+ }
+ // Portfolio
+ .btn-group {
+ float: left;
+ }
+ .vossen-portfolio-filters {
+ padding: 0;
+ margin-bottom: 40px;
+
+ }
+ .vossen-portfolio-filters .btn {
+ display: inline-block;
+ cursor: pointer;
+ text-transform: capitalize;
+ font-weight: 600;
+ font-size: 11px;
+ letter-spacing: 0.5px;
+ line-height: 3;
+ text-transform: capitalize !important;
+ color: var(--level-color-1);
+ background-color: transparent;
+ padding: 0px 20px;
+ margin: 0 1.1px;
+ border-radius: 4px;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ box-shadow: none;
+ border: 2px solid !important;
+ border-color: transparent !important;
+ border-radius: 25px;
+ }
+ .vossen-portfolio-filters .btn.active {
+ cursor: default;
+ opacity: 1;
+ border: 2px solid !important;
+ border-color: var(--level-color-1) !important;
+ border-radius: 0px;
+ }
+ }
+ }
+ }
+}
+.my-shuffle>div {
+ opacity: 0;
+ transition: opacity 1s, padding-top 1s;
+ -moz-transition: opacity 1s, padding-top 1s;
+ -webkit-transition: opacity 1s, padding-top 1s;
+}
+.my-shuffle>div.reveal {
+ opacity: 1;
+}
diff --git a/theme_levelup/static/src/scss/pages/_service.scss b/theme_levelup/static/src/scss/pages/_service.scss
new file mode 100644
index 0000000000..fab7ba4ea6
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/_service.scss
@@ -0,0 +1,380 @@
+.service_page {
+ padding-top: 50px;
+
+ .wrapper {
+ margin-bottom: 100px;
+
+ .s_content {
+ padding-top: 70px;
+ margin-top: 30px;
+ padding-bottom: 70px;
+ margin-bottom: 70px;
+
+ .img_wrapper {
+ max-width: 550px;
+
+ .bg_wrapper {
+ background: linear-gradient(38deg,
+ rgb(241, 104, 104) 14%,
+ rgb(252, 176, 23) 60%,5
+ rgb(252, 176, 23) 100%) !important;
+ width: 100%;
+ height: 436px;
+ top: 20px;
+ position: absolute;
+ left: -5px;
+ border-radius: 5px;
+ }
+
+ img {
+ width: 100%;
+ border-radius: 5px;
+ position: absolute;
+ top: 0px;
+ z-index: 3;
+ }
+ }
+
+ .b_right {
+ border-radius: 5px;
+ padding: 0px 30px 0px 70px;
+
+ .b_info {
+ padding-top: 15px;
+ color: var(--p-color2);
+ font-size: 14px;
+ line-height: 1.9rem;
+ padding-bottom: 50px;
+ }
+ }
+ }
+
+ .our_services {
+ background-color: var(--section-bg);
+
+ padding: 100px 0px 100px 0px;
+
+ .wrapper {
+ margin-top: 30px;
+
+ .latest_content {
+ margin-top: 90px !important;
+ margin-bottom: 40px;
+
+ .card-deck {
+ padding-bottom: 20px;
+ margin-bottom: 20px;
+
+ .card {
+ border: none;
+
+ position: relative;
+ }
+
+ .card_image {
+ position: relative;
+ display: block;
+
+ overflow: hidden;
+
+ &::after {
+ content: " ";
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ width: 100%;
+ background-color: rgba(0, 0, 0, 0.271);
+
+ transition: all 1s ease;
+ opacity: 1;
+ z-index: 999;
+ }
+
+ .card-img-top {
+ border-radius: 0 !important;
+
+ transform: scale(1);
+
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ }
+ }
+
+ .card-body {
+ -webkit-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ -moz-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ text-align: start;
+
+ padding: 35px;
+
+ .card-title {
+ a {
+ font-size: 16px;
+ font-weight: 500;
+ margin-top: 15px;
+ text-decoration: none;
+ color: var(--level-color-3);
+ }
+ }
+
+ .card-text {
+ font-size: 14px;
+ color: var(--p-color2);
+ margin-bottom: 15px;
+ line-height: 2;
+ }
+ }
+
+ &:hover {
+ .card_image {
+ &::after {
+ opacity: 0 !important;
+ }
+
+ .card-img-top {
+ transform: scale(1.3) !important;
+ }
+ }
+
+ .card-body {
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ box-shadow: 0 0 11px rgba(33, 33, 33, 0.2) !important;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .icon_service {
+ margin-top: 70px;
+ padding-top: 40px;
+
+ .i_content {
+ padding-top: 20px;
+ padding-bottom: 20px;
+ margin-top: 20px;
+
+ .icon_wrapper {
+ svg {
+ fill: rgba(252, 176, 23, 1);
+ height: 45px;
+ width: 45px;
+ }
+ }
+
+ h5 {
+ padding-top: 15px;
+ color: var(--level-color3);
+ font-size: 16px;
+ font-weight: 600;
+ }
+
+ p {
+ padding-top: 15px;
+ color: var(--p-color2);
+ font-size: 14px;
+
+ line-height: 1.9rem;
+ }
+ }
+ }
+
+ .pricing {
+ background-color: var(--section-bg);
+
+ padding: 100px 0px 100px 0px;
+
+ .wrapper {
+ .p_content {
+ margin-top: 50px;
+
+ .cd {
+ margin: 30px 0;
+ }
+
+ .card {
+ padding: 20px 30px;
+ border: none;
+ box-shadow: 0px 2px 8px -1px rgba(217, 217, 217, 1);
+ border-radius: 0;
+
+ &:nth-child(2) {
+ box-shadow: none !important;
+ background-color: var(--level-brand);
+ margin: 0px 30px;
+
+ .p_card {
+ text-align: center;
+ margin: 50px 30px;
+ padding: 25px 0;
+
+ h6 {
+ color: var(--white-color);
+ font-size: 18px;
+ text-transform: uppercase;
+ }
+
+ .price {
+ padding-top: 20px;
+ color: var(--white-color);
+ font-size: 50px;
+ font-weight: 600;
+ }
+
+ .month {
+ margin-top: 15px;
+ font-size: 14px;
+ font-weight: 500;
+ color: var(--white-color);
+ }
+
+ ul {
+ padding-top: 20px;
+ padding-left: 0;
+
+ li {
+ color: var(--white-color);
+ font-size: 15px;
+ padding: 15px;
+ border: 1px solid;
+ border-color: transparent;
+ border-bottom-color: var(--border-color);
+ margin-bottom: 10px;
+
+ &:last-child {
+ border: none !important;
+ margin-bottom: 30px;
+ }
+ }
+ }
+ }
+ }
+
+ .p_card {
+ text-align: center;
+ margin: 30px 30px !important;
+ padding: 25px 0;
+
+ h6 {
+ color: var(--level-brand);
+ font-size: 18px;
+ text-transform: uppercase;
+ }
+
+ .price {
+ padding-top: 20px;
+ color: var(--level-color3);
+ font-size: 50px;
+ font-weight: 600;
+ }
+
+ .month {
+ margin-top: 15px;
+ font-size: 14px;
+ font-weight: 500;
+ color: var(--p-color2);
+ }
+
+ ul {
+ padding-top: 20px;
+ padding-left: 0;
+
+ li {
+ color: var(--p-color2);
+ font-size: 15px;
+ padding: 15px;
+ border: 1px solid;
+ border-color: transparent;
+ border-bottom-color: var(--border-color);
+ margin-bottom: 10px;
+
+ &:last-child {
+ border: none !important;
+ margin-bottom: 30px;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ .experience {
+ padding-top: 80px;
+ margin-top: 70px;
+
+ .wrapper {
+ margin-top: 50px;
+
+ .left {
+ .img_wrapper {
+ max-width: 400px;
+ padding-right: 50px;
+
+ img {
+ width: 100%;
+ }
+
+ img {
+ &:first-child {
+ margin-bottom: -55px;
+ max-width: 280px !important;
+ }
+
+ &:last-child {
+ margin-top: -375px;
+ margin-left: 150px;
+ }
+ }
+ }
+ }
+
+ .right {
+ .accordion {
+ margin-top: 30px;
+
+ .card {
+ border: none;
+
+ .card-header {
+ padding: 0.75rem 0rem;
+ margin-bottom: 0;
+ background-color: rgba(255, 255, 255, 0.03);
+ border-bottom: 1px solid rgba(0, 0, 0, .125);
+
+ h2 {
+ .btn-link {
+ font-size: 14x;
+ padding: 15px 0;
+ color: var(--level-color3);
+ font-weight: 500;
+
+ &:hover {
+ text-decoration: none;
+ }
+ }
+ }
+ }
+
+ .card-body {
+ font-size: 12px;
+ color: var(--p-color2);
+ line-height: 1.9;
+ padding: 0.75rem 0rem;
+
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/home/_about.scss b/theme_levelup/static/src/scss/pages/home/_about.scss
new file mode 100644
index 0000000000..40346d5bcf
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/home/_about.scss
@@ -0,0 +1,112 @@
+.index_about {
+ position: relative;
+ margin-top: -100px;
+ display: block;
+ z-index: 3;
+ margin-bottom: 40px;
+ // @media screen and(max-width:992px) {
+ // margin: 0px;
+ // }
+ .ss_wrapper {
+ padding-bottom: 100px;
+ @media screen and(max-width:768px) {
+ padding-bottom: 70px;
+ }
+ .main_c {
+ background: rgb(241, 104, 104);
+ background: linear-gradient(38deg, rgba(241, 104, 104, 1) 14%, rgba(252, 176, 23, 1) 60%, rgba(252, 176, 23, 1) 100%);
+ padding: 80px 70px 100px 70px;
+ position: relative;
+ .next {
+ width: 44px;
+ height: 44px;
+ border-radius: 50%;
+ transform: translate(-50%, 78px);
+ position: absolute;
+ left: 50%;
+ -webkit-box-shadow: 0px 0px 9px 0px rgba(0, 0, 0, 0.36);
+ -moz-box-shadow: 0px 0px 9px 0px rgba(0, 0, 0, 0.36);
+ box-shadow: 0px 0px 9px 0px rgba(0, 0, 0, 0.36);
+ @media screen and(max-width:768px) {
+ bottom: 56px;
+ }
+ a {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 44px;
+ width: 44px;
+ border-radius: 50%;
+ background-color: var(--white-color);
+ &:hover {
+ background-color: var(--level-color-3);
+ i {
+ color: var(--white-color);
+ }
+ }
+ }
+ i {
+ color: var(--level-brand);
+ font-size: 25px;
+ }
+ }
+ @media screen and(max-width:768px) {
+ padding: 60px 50px 60px 50px;
+ text-align: center;
+ }
+ .left {
+ p {
+ color: var(--level-color-3);
+ font-weight: 600;
+ text-transform: uppercase;
+ font-size: 16px;
+ }
+ .abt_c {
+ color: var(--white-color);
+ font-size: 36px;
+ font-weight: 700;
+ line-height: 1.4em;
+ }
+ @media screen and(max-width:768px) {
+ padding-bottom: 40px;
+ text-align: center;
+ }
+ }
+ .right {
+ .r_p {
+ color: var(--white-color);
+ font-size: 18px;
+ line-height: 1.8em;
+ @media screen and(max-width:768px) {
+ font-size: 16px;
+ }
+ }
+ }
+ }
+ .services_wrapper {
+ padding-top: 50px;
+ margin-top: 20px;
+ .s_services {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ @media screen and(max-width:992px) {
+ padding: 15px;
+ margin-bottom: 15px;
+ }
+ span {
+ margin-right: 15px;
+ i {
+ color: var(--p-color2);
+ font-size: 22px;
+ }
+ }
+ p {
+ margin-bottom: 0;
+ font-weight: 500;
+ color: var(--level-color-3);
+ }
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/home/_amazing.scss b/theme_levelup/static/src/scss/pages/home/_amazing.scss
new file mode 100644
index 0000000000..a57069f3af
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/home/_amazing.scss
@@ -0,0 +1,181 @@
+.amazing {
+ background-color: var(--section-bg);
+ padding-top: 90px;
+ padding-bottom: 70px;
+ margin-bottom: 70px;
+ .wrapper {
+ .rm_br {
+ @media screen and(max-width:768px) {
+ br {
+ display: none !important;
+ }
+ }
+ }
+ .amazing_content {
+ padding-top: 50px;
+ margin-top: 40px;
+ .card-deck {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+
+ @media screen and(max-width:768px) {
+ grid-template-columns: 1fr;
+ }
+ }
+ .card {
+ position: relative;
+ -webkit-backface-visibility: hidden;
+ background-color: transparent !important;
+ margin-bottom: 35px;
+ max-width: 100%;
+ border: none;
+ border-radius: 5px;
+ padding: 0;
+ }
+ .card-body {
+ -ms-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+ -webkit-transform-style: preserve-3d;
+ perspective: 1000px;
+ -webkit-perspective: 1000px;
+ padding: 0;
+ }
+ .flip-box-front {
+ .icon_wrapper {
+ margin-bottom: 15px;
+ text-align: center;
+ padding-top: 15px;
+ svg {
+ fill: rgba(252, 176, 23, 1);
+ height: 50px;
+ width: 50px;
+ }
+ }
+ .inner {
+ border-radius: 5px;
+ .card-heading {
+ padding-top: 15px;
+ color: var(--level-color3);
+ font-size: 16px;
+ font-weight: 600;
+ text-align: center;
+ }
+ .card-text {
+ padding-top: 15px;
+ color: var(--p-color2);
+ font-size: 14px;
+ text-align: center;
+ line-height: 1.9rem;
+ }
+ }
+ }
+ .flip-box-back {
+ background: rgb(241, 104, 104);
+ background: linear-gradient(38deg, rgba(241, 104, 104, 1) 14%, rgba(252, 176, 23, 1) 60%, rgba(252, 176, 23, 1) 100%);
+ border-radius: 5px;
+ .inner {
+ .card-heading {
+ padding-top: 15px;
+ color: var(--color-white) !important;
+ font-size: 16px;
+ font-weight: 600;
+ text-align: center;
+ }
+ .card-text {
+ padding-top: 15px;
+ color: var(--color-white) !important;
+ font-size: 14px;
+ text-align: center;
+ line-height: 1.9rem;
+ }
+ }
+ }
+ .flip-box-front,
+ .flip-box-back {
+ min-height: 300px;
+ -ms-transition: transform 0.7s cubic-bezier(.4, .2, .2, 1);
+ transition: transform 0.7s cubic-bezier(.4, .2, .2, 1);
+ -webkit-transition: transform 0.7s cubic-bezier(.4, .2, .2, 1);
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+ @media screen and(max-width:992px) {
+ min-height: 330px;
+ }
+ @media screen and(max-width:992px) {
+ min-height: 350px;
+ }
+ @media screen and(max-width:768px) {
+ min-height: 300px;
+ }
+ }
+ .flip-box-front {
+ -ms-transform: rotateY(0deg);
+ -webkit-transform: rotateY(0deg);
+ transform: rotateY(0deg);
+ -webkit-transform-style: preserve-3d;
+ -ms-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+ padding: 20px;
+ }
+ .card-body:hover .flip-box-front {
+ -ms-transform: rotateY(-180deg);
+ -webkit-transform: rotateY(-180deg);
+ transform: rotateY(-180deg);
+ -webkit-transform-style: preserve-3d;
+ -ms-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+ }
+ .flip-box-back {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ -ms-transform: rotateY(180deg);
+ -webkit-transform: rotateY(180deg);
+ transform: rotateY(180deg);
+ -webkit-transform-style: preserve-3d;
+ -ms-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+ .inner {
+ background-color: transparent !important;
+ padding: 40px !important;
+ }
+ }
+ .card-body:hover .flip-box-back {
+ -ms-transform: rotateY(0deg);
+ -webkit-transform: rotateY(0deg);
+ transform: rotateY(0deg);
+ -webkit-transform-style: preserve-3d;
+ -ms-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+ }
+ .card-body .inner {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ -webkit-perspective: inherit;
+ perspective: inherit;
+ z-index: 2;
+ background-color: rgb(255, 255, 255);
+ transform: translateY(-50%) translateZ(60px) scale(.94);
+ -webkit-transform: translateY(-50%) translateZ(60px) scale(.94);
+ -ms-transform: translateY(-50%) translateZ(60px) scale(.94);
+ top: 50%;
+ padding: 20px;
+ }
+ .flip-box-button {
+ background-color: transparent;
+ border: 2px solid #fff;
+ border-radius: 2px;
+ color: #fff;
+ cursor: pointer;
+ font-size: 20px;
+ font-weight: bold;
+ margin-top: 25px;
+ padding: 15px 20px;
+ text-transform: uppercase;
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/home/_awards.scss b/theme_levelup/static/src/scss/pages/home/_awards.scss
new file mode 100644
index 0000000000..b9be5a94e0
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/home/_awards.scss
@@ -0,0 +1,54 @@
+.awards {
+ padding-top: 50px;
+ margin-bottom: 70px;
+ @media screen and(max-width:992px) {
+ padding-top: 00px;
+ }
+ .wrapper {
+ .aw_wrapp {
+ display: flex;
+ justify-content: space-evenly;
+ align-items: center;
+ @media screen and(max-width:992px) {
+ padding-bottom: 30px;
+ }
+ .aw {
+ color: var(--level-color-3);
+ font-size: 40px;
+ font-weight: 600;
+ text-transform: capitalize;
+ display: inline;
+ }
+ .line {
+ height: 1px;
+ border: 1px solid;
+ display: inline-block;
+ border-color: transparent !important;
+ border-bottom-color: var(--border-color) !important;
+ border-bottom-width: 2px;
+ width: 50%;
+ @media screen and(max-width:992px) {
+ display: none;
+ }
+ }
+ }
+ .aw_sub {
+ @media screen and(max-width:992px) {
+ padding-bottom: 10px;
+ text-align: center;
+ }
+ }
+ .year {
+ font-weight: 600;
+ font-size: 16px;
+ color: var(--level-color-3);
+ @media screen and(max-width:992px) {
+ padding-bottom: 10px;
+ }
+ }
+ p {
+ color: var(--p-color2);
+ font-size: 14px;
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/home/_counter.scss b/theme_levelup/static/src/scss/pages/home/_counter.scss
new file mode 100644
index 0000000000..ce4134e1dd
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/home/_counter.scss
@@ -0,0 +1,66 @@
+.counter_main {
+ width: 100%;
+ background-color: var(--white-color);
+ position: relative;
+ height: 30vh;
+ overflow: hidden;
+ margin-top: 70px;
+ @media screen and(max-width:992px) {
+ margin-top: 40px;
+ }
+ @media screen and (max-width: 768px) {
+ height: 55vh;
+ }
+ @media screen and (max-width: 576px) {
+ height: 90vh;
+ }
+ .overlay {
+ width: 100%;
+ height: 100%;
+ background-color: #00000300;
+ position: absolute;
+ top: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 3;
+ #counter-section-container {
+ width: 100%;
+ text-align: center;
+ }
+ #counter-box-container {
+ /*border: 1px solid #999999;*/
+ overflow: hidden;
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr;
+ @media screen and (max-width: 768px) {
+ grid-template-columns: 2fr 2fr;
+ }
+ @media screen and (max-width: 576px) {
+ grid-template-columns: 1fr;
+ }
+ }
+ #counter-box {
+ /*width: 33.22%;*/
+ // width: 300px;
+ // min-width: 200px;
+ margin: 5px 5px 5px 5px;
+ padding: 5px 5px 5px 5px;
+ float: left;
+ text-align: center;
+ position: relative;
+ p {
+ padding-top: 10px;
+ text-transform: uppercase;
+ font-size: 14px;
+ color: var(--p-color2);
+ font-weight: 500;
+ }
+ }
+ .counter {
+ font-size: 40px;
+ font-weight: 600;
+ color: var(--level-color-3);
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/home/_creative.scss b/theme_levelup/static/src/scss/pages/home/_creative.scss
new file mode 100644
index 0000000000..61bc13c097
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/home/_creative.scss
@@ -0,0 +1,79 @@
+.creative {
+ padding-top: 50px;
+ padding-bottom: 70px;
+ .wrapper {
+ margin-top: 50px;
+ margin-bottom: 50px;
+ .c_wrapper {
+ padding-top: 70px;
+ .c_img {
+ max-width: 300px;
+ overflow: hidden;
+ position: relative;
+ margin-bottom: 40px;
+ @media screen and(max-width:576px) {
+ max-width: 450px;
+ margin: auto;
+ margin-bottom: 40px;
+ }
+ &:after {
+ position: absolute;
+ content: " ";
+ height: 100%;
+ width: 100%;
+ top: 0;
+ left: 0;
+ background: #00000054 !important;
+ opacity: 0;
+ transition: 0.5s ease;
+ }
+ img {
+ width: 100%;
+ border-radius: 5px;
+ transform: scale(1);
+ transition: 0.5s ease-in-out;
+ }
+ &:hover {
+ img {
+ transform: scale(1.3) !important;
+ }
+ &:after {
+ opacity: 1 !important;
+ }
+ .info {
+ display: block !important;
+ width: 100%;
+ height: 100%;
+ .i_wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+ .ss {
+ text-align: center;
+ color: var(--white-color) !important;
+ h5 {
+ font-size: 18px;
+ }
+ p {
+ font-size: 12px;
+ }
+ }
+ }
+ }
+ }
+ }
+ .info {
+ display: none;
+ position: absolute;
+ z-index: 3;
+ top: 0;
+ left: 0;
+ .i_wrapper {
+ .ss {}
+ }
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/home/_featured.scss b/theme_levelup/static/src/scss/pages/home/_featured.scss
new file mode 100644
index 0000000000..3521ce4c69
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/home/_featured.scss
@@ -0,0 +1,69 @@
+.featured {
+ background-color: var(--section-bg);
+ padding-top: 90px;
+ padding-bottom: 70px;
+ margin-bottom: 70px;
+ @media screen and(max-width:992px) {
+ padding-top: 50px;
+ padding-bottom: 40px;
+ }
+ .wrapper {
+ margin-top: 40px;
+ .featured_content {
+ padding-top: 70px;
+ .card-deck {
+ padding-bottom: 20px;
+ margin-bottom: 20px;
+ .card {
+ border: none;
+ position: relative;
+ @media screen and(max-width:992px) {
+ margin-bottom: 40px;
+ }
+ }
+ .card_image {
+ position: relative;
+ display: block;
+ &::after {
+ content: " ";
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ width: 100%;
+ background-color: rgba(0, 0, 0, 0.493);
+ transition: all 1s ease;
+ opacity: 0;
+ z-index: 999;
+ }
+ &:hover {
+ &::after {
+ opacity: 1 !important;
+ }
+ }
+ .card-img-top {
+ border-radius: 0 !important;
+ }
+ }
+ .card-body {
+ -webkit-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ -moz-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ text-align: center;
+ // margin-top: 15px;
+ // margin-bottom: 15px;
+ .card-title {
+ font-size: 16px;
+ font-weight: 500;
+ margin-top: 15px;
+ }
+ .card-text {
+ font-size: 14px;
+ color: var(--p-color2);
+ margin-bottom: 15px;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/home/_home.scss b/theme_levelup/static/src/scss/pages/home/_home.scss
new file mode 100644
index 0000000000..271b581367
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/home/_home.scss
@@ -0,0 +1,10 @@
+@import './about';
+@import './featured';
+@import './awards';
+@import './service';
+@import './amazing';
+@import './partners';
+@import './creative';
+@import './testimonial';
+@import './counter';
+@import './latest';
diff --git a/theme_levelup/static/src/scss/pages/home/_latest.scss b/theme_levelup/static/src/scss/pages/home/_latest.scss
new file mode 100644
index 0000000000..39f9395861
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/home/_latest.scss
@@ -0,0 +1,97 @@
+.latest {
+ background-color: var(--section-bg);
+ padding: 100px 0px 100px 0px;
+ @media screen and(max-width:768px) {
+ padding: 70px 0px 25px 0px;
+ }
+ .wrapper {
+ margin-top: 30px;
+ .latest_content {
+ margin-top: 90px !important;
+ margin-bottom: 40px;
+ .card-deck {
+ padding-bottom: 20px;
+ margin-bottom: 20px;
+ .card {
+ border: none;
+ position: relative;
+ @media screen and(max-width:768px) {
+ margin-bottom: 30px;
+ }
+ .type {
+ position: absolute;
+ background-color: rgba(0, 0, 0, 0.481);
+ color: var(--white-color);
+ font-size: 10px;
+ padding: 6px 15px;
+ letter-spacing: 1px;
+ top: 20px;
+ right: 20px;
+ z-index: 1000;
+ text-transform: uppercase;
+ }
+ .card_image {
+ position: relative;
+ display: block;
+ &::after {
+ content: " ";
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ width: 100%;
+ background-color: rgba(0, 0, 0, 0.271);
+ transition: all 1s ease;
+ opacity: 1;
+ z-index: 999;
+ }
+ .card-img-top {
+ border-radius: 0 !important;
+ }
+ }
+ .card-body {
+ -webkit-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ -moz-box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ box-shadow: 0px 4px 5px 5px rgba(247, 247, 247, 0.72);
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ text-align: start;
+ padding: 35px;
+ .card-title {
+ a {
+ font-size: 16px;
+ font-weight: 500;
+ margin-top: 15px;
+ text-decoration: none;
+ color: var(--level-color-3);
+ }
+ }
+ .card-text {
+ font-size: 14px;
+ color: var(--p-color2);
+ margin-bottom: 15px;
+ line-height: 2;
+ }
+ }
+ }
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ @media screen and(max-width:768px) {
+ grid-template-columns: 1fr;
+ }
+ }
+ &:hover {
+ .card_image {
+ &::after {
+ opacity: 0 !important;
+ }
+ }
+ .card-body {
+ -webkit-transition: 0.5s;
+ transition: 0.5s;
+ box-shadow: 0 0 11px rgba(33, 33, 33, .2) !important;
+ }
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/home/_partners.scss b/theme_levelup/static/src/scss/pages/home/_partners.scss
new file mode 100644
index 0000000000..c7bb51462d
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/home/_partners.scss
@@ -0,0 +1,26 @@
+.partners {
+ padding-bottom: 50px;
+ border: 1px solid;
+ border-color: transparent;
+ border-bottom-color: var(--border-color2) !important;
+ margin-bottom: 20px;
+ @media screen and(max-width:768px) {
+ padding-bottom: 20px;
+ }
+ .wrapper {
+ .p_img {
+ max-width: 200px;
+ margin: auto;
+ @media screen and(max-width:768px) {
+ margin-bottom: 30px;
+ }
+ img {
+ width: 100%;
+ filter: grayscale(1);
+ &:hover {
+ filter: grayscale(0);
+ }
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/home/_service.scss b/theme_levelup/static/src/scss/pages/home/_service.scss
new file mode 100644
index 0000000000..7f2d7569a9
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/home/_service.scss
@@ -0,0 +1,37 @@
+.service {
+ background-image: url(./../images/service/service-bg.jpg);
+ background-position: center;
+ background-size: cover;
+ padding-bottom: 50px;
+ @media screen and(max-width:992px) {
+ padding-bottom: 20px;
+ }
+ .wrapper {
+ padding-bottom: 70px;
+ @media screen and(max-width:992px) {
+ padding-bottom: 20px;
+ }
+ .service_left {
+ padding: 150px 100px 0px 100px;
+ @media screen and(max-width:1200px) {
+ padding: 50px 50px 0px 100px;
+ }
+ @media screen and(max-width:992px) {
+ padding: 70px 0px 70px 15px;
+ }
+ .s_p {
+ margin-top: 40px;
+ color: var(--p-color2);
+ font-size: 14px;
+ line-height: 1.9rem;
+ padding-bottom: 30px;
+ }
+ }
+ .service_right {
+ img {
+ width: 100%;
+ border-radius: 8px;
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/pages/home/_testimonial.scss b/theme_levelup/static/src/scss/pages/home/_testimonial.scss
new file mode 100644
index 0000000000..17d9c0e129
--- /dev/null
+++ b/theme_levelup/static/src/scss/pages/home/_testimonial.scss
@@ -0,0 +1,60 @@
+.testimonial {
+ background-image: url(../../../images/testimoinial/testimonial.jpg);
+ background-position: center;
+ background-size: cover;
+ height: auto;
+ position: relative;
+ .wrapper {
+ padding: 100px 0px 70px 0;
+ @media screen and(max-width:768px) {
+ padding-top: 80px;
+ }
+ .c_t {
+ .wrapper2 {
+ padding: 100px 0px 40px 0;
+ @media screen and(max-width:768px) {
+ padding-top: 50px;
+ padding-bottom: 0;
+ }
+ .comment {
+ background-color: var(--white-color);
+ color: var(--p-color2);
+ font-size: 14px;
+ line-height: 1.5rem;
+ padding: 40px 45px 40px 45px;
+ border-radius: 5px;
+ }
+ .p_info {
+ margin-top: 20px;
+ padding-top: 15px;
+ padding-left: 30px;
+ display: flex;
+ @media screen and(max-width:768px) {
+ justify-content: center;
+ padding-left: 0;
+ }
+ .img_wrapper {
+ max-width: 70px;
+ margin-right: 20px;
+ img {
+ width: 100%;
+ border-radius: 50%;
+ }
+ }
+ }
+ .detail {
+ h6 {
+ font-size: 16px;
+ font-weight: 500;
+ margin-top: 15px;
+ }
+ p {
+ font-size: 14px;
+ color: var(--p-color2);
+ margin-bottom: 15px;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/theme_levelup/static/src/scss/style.scss b/theme_levelup/static/src/scss/style.scss
new file mode 100644
index 0000000000..08840a85c0
--- /dev/null
+++ b/theme_levelup/static/src/scss/style.scss
@@ -0,0 +1,9 @@
+//Font
+@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700;800;900&display=swap');
+//Global
+@import './variables';
+@import './common';
+@import './normalize';
+@import './components/components';
+@import './layouts/layouts';
+@import './pages/pages';
diff --git a/theme_levelup/views/about_us_templates.xml b/theme_levelup/views/about_us_templates.xml
new file mode 100644
index 0000000000..bef88764b7
--- /dev/null
+++ b/theme_levelup/views/about_us_templates.xml
@@ -0,0 +1,580 @@
+
+
+
+
+
+
+
+
+
+ About us
+
+ About us
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ABOUT Levelup AGENCY
+
+ We help brands and companies
+ stand out in the digital age
+
+
+
+
+
+
+
Brand research and strategy
+
+ Lorem ipsum dolor sit amet
+ consectetur adipiscing elit do
+ eiusmod tempor incididunt ut labore
+ et dolore magna ut enim
+ ad minim veniam nostrud ullamco
+ laboris nisi ut aliquip ex
+ ea commodo incididunt ut labore et
+ dolore magna consequat.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2017
+
+
+ Best webdesign
+
+
+
+
+
+
+ 2019
+
+
+ Communication
+
+
+
+
+
+
+ 2022
+
+
+ Branding Service
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ACCOMPLISHED SKILLS
+
+
Our
+ special skills
+
+
+ Lorem ipsum is simply dummy
+ text of the printing and
+ typesetting industry. Lorem
+ ipsum has been the
+ industry’s standard dummy
+ text ever since.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CREATIVE CONCEPT DESIGNS
+
+
+ We make your
+ ideas became true
+
+
+ Lorem ipsum is simply dummy
+ text of the printing and
+ typesetting industry. Lorem
+ ipsum has been the
+ industry’s standard dummy
+ text ever since.
+
+
OUR
+ SERVICES
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
GRAPHIC DESIGN
+
Branding design
+
+
+
+
+
WEB DESIGN
+
Branding design
+
+
+
+
+
WEB DEVELOPMENT
+
Branding design
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
TALENTED PROFESSIONALS
+ Creative People
+
+
+
+
+
+
+
+
+
+
+
Stepheny Martin
+
Development head
+
+
+
+
+
+
+
+
+
+
+
+
Jhon Luther
+
Project manager
+
+
+
+
+
+
+
+
+
+
+
+
Steve Jobs
+
Financial Manager
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
UNLIMITED POWER
+ CUSTOMIZATION
+
+
+ Hando is meant to simplify
+
+ the website building
+
+
+
Get in touch
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/blog_templates.xml b/theme_levelup/views/blog_templates.xml
new file mode 100644
index 0000000000..d03fc4f7c5
--- /dev/null
+++ b/theme_levelup/views/blog_templates.xml
@@ -0,0 +1,212 @@
+
+
+
+
+
+
+
+
+
+
+ Latest Blog
+
+ Blog
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
×
+
+
Show:
+
+
This box will not be
+ visible to your visitors
+
+
+
+
+
+
+
No blog post yet.
+
+ Click on "New " in the top-right corner to
+ write your first blog post.
+
+
+
+
+
+
+
+
+ Article
+ Articles
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/contact_us_templates.xml b/theme_levelup/views/contact_us_templates.xml
new file mode 100644
index 0000000000..e9f3f567cb
--- /dev/null
+++ b/theme_levelup/views/contact_us_templates.xml
@@ -0,0 +1,513 @@
+
+
+
+
+
+
+
+
+
+
+ Contact us
+
+ Contact
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/footer_templates.xml b/theme_levelup/views/footer_templates.xml
new file mode 100644
index 0000000000..dd4586f459
--- /dev/null
+++ b/theme_levelup/views/footer_templates.xml
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/header_templates.xml b/theme_levelup/views/header_templates.xml
new file mode 100644
index 0000000000..80fadacc69
--- /dev/null
+++ b/theme_levelup/views/header_templates.xml
@@ -0,0 +1,132 @@
+
+
+
+
+
diff --git a/theme_levelup/views/layout_templates.xml b/theme_levelup/views/layout_templates.xml
new file mode 100644
index 0000000000..2d975f63f7
--- /dev/null
+++ b/theme_levelup/views/layout_templates.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+ Levelup
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/portfolio_templates.xml b/theme_levelup/views/portfolio_templates.xml
new file mode 100644
index 0000000000..e85710ac11
--- /dev/null
+++ b/theme_levelup/views/portfolio_templates.xml
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+ Creative Portfolio
+
+
+ Portfolio
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Illustration
+
+ Lorem ipsum is simply dummy text of
+ the printing and typesetting
+ industry.
+
+
+
+
+
+
+
+
+
+
+
+
Illustration
+
+ Lorem ipsum is simply dummy text of
+ the printing and typesetting
+ industry.
+
+
+
+
+
+
+
+
+
+
+
Illustration
+
+ Lorem ipsum is simply dummy text of
+ the printing and typesetting
+ industry.
+
+
+
+
+
+
+
+
+
+
+
+
Illustration
+
+ Lorem ipsum is simply dummy text of
+ the printing and typesetting
+ industry.
+
+
+
+
+
+
+
+
+
+
+
Illustration
+
+ Lorem ipsum is simply dummy text of
+ the printing and typesetting
+ industry.
+
+
+
+
+
+
+
+
+
+
+
Illustration
+
+ Lorem ipsum is simply dummy text of
+ the printing and typesetting
+ industry.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/service_templates.xml b/theme_levelup/views/service_templates.xml
new file mode 100644
index 0000000000..f347594096
--- /dev/null
+++ b/theme_levelup/views/service_templates.xml
@@ -0,0 +1,800 @@
+
+
+
+
+
+
+
+
+
+
+ EXPERTISE
+ SERVICES
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
FULLY
+ EXPERIENCE DESIGN AGENCY
+
+
+ We help our clients build value
+ digital web design
+ solutions
+
+
+ Lorem ipsum is simply dummy text
+ of the printing and
+ typesetting industry. Lorem
+ ipsum has been the industry’s
+ standard dummy text ever since.
+
+
+ About company
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UNLIMITED POSSIBILITIES
+
+
+ Our Services
+
+
+
+
+
+
+
+
+
Website design
+
+ Lorem ipsum is simply dummy text
+ the printing and
+ typesetting industry lorem has
+ been the standard text
+ since…
+
+
+
+
+
+
+
+
+
eCommerce solutions
+
+
+ Lorem ipsum is simply dummy text
+ the printing and
+ typesetting industry lorem has
+ been the standard text
+ since…
+
+
+
+
+
+
+
+
+
Web development
+
+ Lorem ipsum is simply dummy text
+ the printing and
+ typesetting industry lorem has
+ been the standard text
+ since…
+
+
+
+
+
+
+
+
+
Interactive design
+
+ Lorem ipsum is simply dummy text
+ the printing and
+ typesetting industry lorem has
+ been the standard text
+ since…
+
+
+
+
+
+
+
+
+
Digital marketing
+
+ Lorem ipsum is simply dummy text
+ the printing and
+ typesetting industry lorem has
+ been the standard text
+ since…
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Branding identity
+
+ Lorem ipsum is simply dummy text
+ the printing and
+ typesetting industry lorem has
+ been the standard text
+ since…
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SIMPLE PRICING PLAN
+
+
+ Amazing Package
+
+
+
+
+
+
+
Basic plan
+
$29
+
Monthly
+ billing
+
+
+ Marketing Strategy
+ Competitive work
+ analysis
+
+ Social media share
+ audit
+
+
+
Get
+ started
+
+
+
+
+
+
Basic plan
+
+
+
$29
+
Monthly
+ billing
+
+
+ Marketing Strategy
+
+ Competitive work
+ analysis
+
+ Social media share
+ audit
+
+
+
+
Get
+ started
+
+
+
+
+
+
Basic plan
+
$29
+
Monthly
+ billing
+
+
+ Marketing Strategy
+ Competitive work
+ analysis
+
+ Social media share
+ audit
+
+
+
Get
+ started
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAQ
+
+
+
+
+
+ FULLY EXPERIENCE DESIGN AGENCY
+
+
+ Get Creative DedicatedBranding
+ Services From
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum is simply
+ dummy text of the
+ printing and typesetting
+ industry of type and
+ scrambled
+ it to make a type book.
+
+
+
+
+
+
+
+ Lorem ipsum is simply
+ dummy text of the
+ printing and typesetting
+ industry of type and
+ scrambled
+ it to make a type book.
+
+
+
+
+
+
+
+ Lorem ipsum is simply
+ dummy text of the
+ printing and typesetting
+ industry of type and
+ scrambled
+ it to make a type book.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LOVED BY OUR CUSTOMERS
+
+
+ Clients Testimonial
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Luke jhon
+
+ Creative director
+
+
+
+
+
+ Lorem ipsum is simply dummy
+ text of the printing and typ
+ dummy text ever is simply
+ dummy text of
+ th since.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Luke jhon
+
+ Creative director
+
+
+
+
+
+ Lorem ipsum is simply dummy
+ text of the printing and typ
+ dummy text ever is simply
+ dummy text of
+ th since.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Luke jhon
+
+ Creative director
+
+
+
+ Lorem ipsum is simply dummy
+ text of the printing and typ
+ dummy text ever is simply
+ dummy text of
+ th since.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/snippets/s_about_templates.xml b/theme_levelup/views/snippets/s_about_templates.xml
new file mode 100644
index 0000000000..11ee9212a9
--- /dev/null
+++ b/theme_levelup/views/snippets/s_about_templates.xml
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+ About levelup
+
+
+
+
+
+ We’re more than an
+ agency of record,
+ we’re an agency of
+ progress.
+
+
+ “ With years of experience in the website
+ design and development industry ThemeZaa
+ pride
+ ourselves on creating unique, creative and
+ quality designs that are developed upon the
+ latest modern coding and developing
+ techniques "
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DIgital Branding
+
+
+
+
+
+
+
+ DIgital Branding
+
+
+
+
+
+
+
+ DIgital Branding
+
+
+
+
+
+
+
+ DIgital Branding
+
+
+
+
+
+
+
+
+
+
+
+
+
Information
+ technology
+
+
+ Enterprise website for a
+ cybersecurity market leader.
+
+
+
+
+
+
+
+
+
Information
+ technology
+
+
+ Enterprise website for a
+ cybersecurity market leader.
+
+
+
+
+
+
+
+
+
+
+
Information
+ technology
+
+
+ Enterprise website for a
+ cybersecurity market leader.
+
+
+
+
+
+
+
+
+
Information
+ technology
+
+
+ Enterprise website for a
+ cybersecurity market leader.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/snippets/s_awards_templates.xml b/theme_levelup/views/snippets/s_awards_templates.xml
new file mode 100644
index 0000000000..1ae6d20056
--- /dev/null
+++ b/theme_levelup/views/snippets/s_awards_templates.xml
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Awards
+
+
+
+
+
+ Award winning
+ creative agency.
+
+
+ “ Our work is regularly
+ recognized by prestigious
+ companies, organizations and
+ researchers locally, nationally
+ and internationally. "
+
+
+
+
+
+
+
+ 2019
+
+
+
+
+
+
+
+
+ #1 Web Designers
+
+
+ Do not rush into the house
+ He will criticize the pleasure he wants
+ let him run away from the pain of a hair
+ there is no mating.
+
+
+
+
+
+ 2020
+
+
+
+
+
+
+
+
+ #1 Web Designers
+
+
+ Do not rush into the house
+ He will criticize the pleasure he wants
+ let him run away from the pain of a hair
+ there is no mating.
+
+
+
+
+
+ 2021
+
+
+
+
+
+
+
+
+ #1 Web Designers
+
+
+ Do not rush into the house
+ He will criticize the pleasure he wants
+ let him run away from the pain of a hair
+ there is no mating.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/snippets/s_banner_templates.xml b/theme_levelup/views/snippets/s_banner_templates.xml
new file mode 100644
index 0000000000..608839364b
--- /dev/null
+++ b/theme_levelup/views/snippets/s_banner_templates.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A creative
+ agency
+ specialized in
+ brand strategy
+ creation.
+
+
+ “ Pride ourselves on creating
+ unique,
+ creative and quality designs that
+ are
+ developed upon the latest modern
+ coding and developing techniques ”
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/snippets/s_blog_templates.xml b/theme_levelup/views/snippets/s_blog_templates.xml
new file mode 100644
index 0000000000..90ec5314eb
--- /dev/null
+++ b/theme_levelup/views/snippets/s_blog_templates.xml
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+ Blog
+
+
+
+
+
+ We are curiosity-driven, inspired by good
+ design, innovative web technologies &
+ cool brands.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Featured
+
+ 01-12-2023
+
+
+
+
+
+
+
+
+
+
+
+
Featured
+
+ 01-12-2023
+
+
+
+
+
+
+
+
+
+
+
+
Featured
+
+ 01-12-2023
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/snippets/s_client_templates.xml b/theme_levelup/views/snippets/s_client_templates.xml
new file mode 100644
index 0000000000..eeb3323743
--- /dev/null
+++ b/theme_levelup/views/snippets/s_client_templates.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+ Our Client
+
+
+
+
+
+ Levelup has been identified as a creative
+ partner by
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/snippets/s_excited_templates.xml b/theme_levelup/views/snippets/s_excited_templates.xml
new file mode 100644
index 0000000000..04c6d17311
--- /dev/null
+++ b/theme_levelup/views/snippets/s_excited_templates.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+ Excited
+
+
+
+
+
+ Let’s
+ talk
+
+
+ “ build or improve your digital product."
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/snippets/s_feature_templates.xml b/theme_levelup/views/snippets/s_feature_templates.xml
new file mode 100644
index 0000000000..c4bd64bca7
--- /dev/null
+++ b/theme_levelup/views/snippets/s_feature_templates.xml
@@ -0,0 +1,209 @@
+
+
+
+
+
+
+
+
+
Features
+
+
+
+
+ We craft beautifully useful marketing and digital products.
+
+
+ " Minim veniam nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. "
+
+
+
+
+
+
+
+
+
+
+
+ Visual Identity
+ Brand Messaging
+ Publication Design
+
+
+
+
+ Minim veniam nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+
+
+
+
+
+
+
+
+
+
+
Content for Branding & Graphics section goes here.
+
+
+
+
+
+
+
+
+
+
+
+ Social Media Strategy
+ Content Marketing
+ SEO Optimization
+
+
+
+
+ Marketing solutions to help your business grow and reach your target audience effectively.
+
+
+
+
+
+
+
+
+
+
+
+
Full-stack web development services to bring your digital vision to life.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/theme_levelup/views/snippets/s_gallery_templates.xml b/theme_levelup/views/snippets/s_gallery_templates.xml
new file mode 100644
index 0000000000..138dbc8b0a
--- /dev/null
+++ b/theme_levelup/views/snippets/s_gallery_templates.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+ Product
+ photography
+
+
+
+
+
+
+
+
+
+ Hungry for more examples?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/snippets/s_service_templates.xml b/theme_levelup/views/snippets/s_service_templates.xml
new file mode 100644
index 0000000000..c3809382db
--- /dev/null
+++ b/theme_levelup/views/snippets/s_service_templates.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+ Services
+
+
+
+
+
+
+ A creative agency
+ specialized in brand
+ strategy creation.
+
+
+ “ Lorem ipsum dolor sit amet consectetur
+ adipiscing elit
+ do eiusmod tempor incididunt ut
+ labore et dolore magna ut enim ad minim
+ veniam nostrud
+ exercitation ullamco laboris nisi
+ ut aliquip ex ea commodo consequat. "
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/snippets/s_snippet_templates.xml b/theme_levelup/views/snippets/s_snippet_templates.xml
new file mode 100644
index 0000000000..962e8ad069
--- /dev/null
+++ b/theme_levelup/views/snippets/s_snippet_templates.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/theme_levelup/views/snippets/s_testimonial_templates.xml b/theme_levelup/views/snippets/s_testimonial_templates.xml
new file mode 100644
index 0000000000..71e486c911
--- /dev/null
+++ b/theme_levelup/views/snippets/s_testimonial_templates.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+ Testimonial
+
+
+
+
+
+ What customers
+ say.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Luke Jhon
+
+ CEO - Pepsico
+
+
+
+
+
+
+
+
+
+
+
+
Luke Jhon
+
+ CEO - Pepsico
+
+
+
+
+
+
+
+
+
+
+
+
Benny dop
+
+ Marketing - Pepsico
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/theme_levelup/views/team_templates.xml b/theme_levelup/views/team_templates.xml
new file mode 100644
index 0000000000..ac5b816024
--- /dev/null
+++ b/theme_levelup/views/team_templates.xml
@@ -0,0 +1,316 @@
+
+
+
+
+
+
+
+
+
+
+ CREATIVE
+ PEOPLE
+
+
+
+
+
+
+
+
+
+
+
+
+ MEET THE TEAM
+
+
+ Our Creative Team
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Jhon Luther
+
Project Manager
+
+ Lorem ipsum is simply dummy text
+ of the printing and typesetting
+ industry..
+
+
+
+
+
+
+
+
+
+
+
+
+
Jhon Doe
+
Marketing Director
+
+ Lorem ipsum is simply dummy text
+ of the printing and typesetting
+ industry..
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Luke Shaw
+
Web designer
+
+ Lorem ipsum is simply dummy text
+ of the printing and typesetting
+ industry..
+
+
+
+
+
+
+
+
+
+
+
+
+
Sara Lorence
+
HR Manager
+
+ Lorem ipsum is simply dummy text
+ of the printing and typesetting
+ industry..
+
+
+
+
+
+
+
+
+
+
+
+ MEET THE ALL TEAM BEHIND YOUR SUCCESS
+
+
+
+
+
+ We're a talented team of branding
+ experts who know how to build brands
+ that resonate with customers.
+
+
+
+
+
+
+ More than 50k people Trust on our Experts
+
+
+
+
+
+
+
+
+
+
+ MEET THE ALL TEAM BEHIND YOUR SUCCESS
+
+
+
+
+
+ We're a talented team of branding
+ experts who know how to build brands
+ that resonate with customers.
+
+
+
+
+
+
+ More than 50k people Trust on our Experts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
AWESOMENESS AND CREATIVE PEOPLE
+
+ We talk a lot about hope
+
+ helping and teamwork
+
+
JOIN THE TEAM
+
+
+
+
+
+
+
+
+
+
+
+
+
WORDS OF TEAM MEMBER
+
+ Teamwork is the ability work
+ together toward
+
+
+
+ "Lorem ipsum is simply dummy
+ text of the printing and typeing
+ industry. lorem ipsum has been
+ the
+ industry's standard dummy text
+ ever since."
+
+
+
+
Mike Bradford
+
Creative director
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/thermal_invoice_report/README.rst b/thermal_invoice_report/README.rst
new file mode 100644
index 0000000000..8deda2325d
--- /dev/null
+++ b/thermal_invoice_report/README.rst
@@ -0,0 +1,51 @@
+.. image:: https://img.shields.io/badge/license-LGPL--3-green.svg
+ :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html
+ :alt: License: LGPL-3
+
+Thermal Invoice Report
+======================
+* This app allows us to print thermal Invoices Report.
+
+Configuration
+=============
+* No additional configurations needed
+
+Company
+-------
+* `Cybrosys Techno Solutions `__
+
+License
+-------
+General Public License, Version 3 (LGPL v3).
+(https://www.gnu.org/licenses/lgpl-3.0-standalone.html)
+
+Credits
+-------
+* Developer: (V18) Nivedhya T,
+ (V17) Jumana Haseen,
+ (V16) Saleekha ,
+ (V15) Swaroop N P,
+
+Contact : odoo@cybrosys.com
+
+Contacts
+--------
+* Mail Contact : odoo@cybrosys.com
+* Website : https://cybrosys.com
+
+Bug Tracker
+-----------
+Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
+
+Maintainer
+==========
+.. image:: https://cybrosys.com/images/logo.png
+ :target: https://cybrosys.com
+
+This module is maintained by Cybrosys Technologies.
+
+For support and more information, please visit `Our Website `__
+
+Further information
+===================
+HTML Description: ``__
diff --git a/thermal_invoice_report/__init__.py b/thermal_invoice_report/__init__.py
new file mode 100644
index 0000000000..25732ed977
--- /dev/null
+++ b/thermal_invoice_report/__init__.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions()
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
diff --git a/thermal_invoice_report/__manifest__.py b/thermal_invoice_report/__manifest__.py
new file mode 100644
index 0000000000..fdc20a624b
--- /dev/null
+++ b/thermal_invoice_report/__manifest__.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions()
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+{
+ 'name': "Thermal Invoice Report",
+ 'version': '18.0.1.0.0',
+ 'summary': 'A Module For Printing Thermal Invoice',
+ 'description': 'The Thermal Invoice Printing app enhances the '
+ 'invoicing workflow in Odoo by enabling seamless '
+ 'printing of compact, receipt-style invoices',
+ 'category': 'Accounting',
+ 'author': 'Cybrosys Techno Solutions',
+ 'maintainer': 'Cybrosys Techno Solutions',
+ 'company': 'Cybrosys Techno Solutions',
+ 'website': 'https://www.cybrosys.com',
+ 'depends': ['base', 'account'],
+ 'data': [
+ 'data/account_move_data.xml',
+ 'report/account_move_reports.xml',
+ 'report/account_move_templates.xml',
+ ],
+ 'images': ['static/description/banner.jpg'],
+ 'license': 'LGPL-3',
+ 'installable': True,
+ 'application': False,
+ 'auto_install': False,
+}
diff --git a/thermal_invoice_report/data/account_move_data.xml b/thermal_invoice_report/data/account_move_data.xml
new file mode 100644
index 0000000000..94e424ff73
--- /dev/null
+++ b/thermal_invoice_report/data/account_move_data.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ Thermal Paper
+
+ custom
+ 75
+ 58
+ Portrait
+ 1
+ 0
+ 0
+ 0
+
+ 35
+ 96
+
+
+
diff --git a/thermal_invoice_report/doc/RELEASE_NOTES.md b/thermal_invoice_report/doc/RELEASE_NOTES.md
new file mode 100644
index 0000000000..7c387e552d
--- /dev/null
+++ b/thermal_invoice_report/doc/RELEASE_NOTES.md
@@ -0,0 +1,6 @@
+## Module
+
+#### 02.07.2025
+#### Version 18.0.1.0.0
+#### ADD
+- Initial commit for Thermal Invoice Report
diff --git a/thermal_invoice_report/report/account_move_reports.xml b/thermal_invoice_report/report/account_move_reports.xml
new file mode 100644
index 0000000000..689321e393
--- /dev/null
+++ b/thermal_invoice_report/report/account_move_reports.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ Thermal Invoice
+ account.move
+ qweb-pdf
+ thermal_invoice_report.report_thermal
+ thermal_invoice_report.report_thermal
+ (object._get_report_base_filename())
+
+
+ report
+
+
+
diff --git a/thermal_invoice_report/report/account_move_templates.xml b/thermal_invoice_report/report/account_move_templates.xml
new file mode 100644
index 0000000000..3c0feeb363
--- /dev/null
+++ b/thermal_invoice_report/report/account_move_templates.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ --------------------------------------------------------------------
+
+
+
+
+ Invoice No :
+
+
+
+ Customer :
+
+
+ invoice Date :
+
+
+
+ Date :
+
+
+ Time :
+
+
+
+
+
+ --------------------------------------------------------------------
+
+
+
+
+
+
+ PRODUCT
+
+
+ QUANTITY
+
+
+ PRICE
+
+
+
+
+
+
+ Discount :
+
+
+
+
+
+
+
+
+
+
+
+
+ --------------------------------------------------------------------
+
+
+
+
+
+
+ Taxes
+ :
+
+
+
+
+
+ Total
+ :
+
+
+
+
+
+
+
+
+ --------------------------------------------------------------------
+
+
+ Thank You For Shopping With Us
+ -- *** --
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/cybro-icon.png b/thermal_invoice_report/static/description/assets/cybro-icon.png
new file mode 100644
index 0000000000..06e73e11de
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/cybro-icon.png differ
diff --git a/thermal_invoice_report/static/description/assets/cybro-odoo.png b/thermal_invoice_report/static/description/assets/cybro-odoo.png
new file mode 100644
index 0000000000..ed02e07a48
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/cybro-odoo.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/arrows-repeat.svg b/thermal_invoice_report/static/description/assets/icons/arrows-repeat.svg
new file mode 100644
index 0000000000..1d7efabc52
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/arrows-repeat.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/banner-1.png b/thermal_invoice_report/static/description/assets/icons/banner-1.png
new file mode 100644
index 0000000000..c180db1729
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/banner-1.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/banner-2.svg b/thermal_invoice_report/static/description/assets/icons/banner-2.svg
new file mode 100644
index 0000000000..e606d97d98
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/banner-2.svg
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/banner-bg.png b/thermal_invoice_report/static/description/assets/icons/banner-bg.png
new file mode 100644
index 0000000000..a8238d3c09
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/banner-bg.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/banner-bg.svg b/thermal_invoice_report/static/description/assets/icons/banner-bg.svg
new file mode 100644
index 0000000000..b1378103e2
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/banner-bg.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/banner-call.svg b/thermal_invoice_report/static/description/assets/icons/banner-call.svg
new file mode 100644
index 0000000000..96c687e81f
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/banner-call.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/banner-mail.svg b/thermal_invoice_report/static/description/assets/icons/banner-mail.svg
new file mode 100644
index 0000000000..cbf0d158d2
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/banner-mail.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/banner-pattern.svg b/thermal_invoice_report/static/description/assets/icons/banner-pattern.svg
new file mode 100644
index 0000000000..9c1c7e101c
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/banner-pattern.svg
@@ -0,0 +1,343 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/banner-promo.svg b/thermal_invoice_report/static/description/assets/icons/banner-promo.svg
new file mode 100644
index 0000000000..d52791b11e
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/banner-promo.svg
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/brand-pair.svg b/thermal_invoice_report/static/description/assets/icons/brand-pair.svg
new file mode 100644
index 0000000000..d8db7fc1e7
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/brand-pair.svg
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/check.png b/thermal_invoice_report/static/description/assets/icons/check.png
new file mode 100644
index 0000000000..c8e85f51d6
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/check.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/chevron.png b/thermal_invoice_report/static/description/assets/icons/chevron.png
new file mode 100644
index 0000000000..2089293d6a
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/chevron.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/close-icon.svg b/thermal_invoice_report/static/description/assets/icons/close-icon.svg
new file mode 100644
index 0000000000..df8cce37a5
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/close-icon.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/cogs.png b/thermal_invoice_report/static/description/assets/icons/cogs.png
new file mode 100644
index 0000000000..95d0bad62c
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/cogs.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/collabarate-icon.svg b/thermal_invoice_report/static/description/assets/icons/collabarate-icon.svg
new file mode 100644
index 0000000000..dd4e105183
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/collabarate-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/consultation.png b/thermal_invoice_report/static/description/assets/icons/consultation.png
new file mode 100644
index 0000000000..8319d4baa0
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/consultation.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/cybro-logo.png b/thermal_invoice_report/static/description/assets/icons/cybro-logo.png
new file mode 100644
index 0000000000..ff4b782205
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/cybro-logo.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/down.svg b/thermal_invoice_report/static/description/assets/icons/down.svg
new file mode 100644
index 0000000000..f21c36271b
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/down.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thermal_invoice_report/static/description/assets/icons/ecom-black.png b/thermal_invoice_report/static/description/assets/icons/ecom-black.png
new file mode 100644
index 0000000000..a9385ff13f
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/ecom-black.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/education-black.png b/thermal_invoice_report/static/description/assets/icons/education-black.png
new file mode 100644
index 0000000000..3eb09b27b4
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/education-black.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/faq.png b/thermal_invoice_report/static/description/assets/icons/faq.png
new file mode 100644
index 0000000000..4250b5b817
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/faq.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/feature-icon.svg b/thermal_invoice_report/static/description/assets/icons/feature-icon.svg
new file mode 100644
index 0000000000..fa0ea6850a
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/feature-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/feature.png b/thermal_invoice_report/static/description/assets/icons/feature.png
new file mode 100644
index 0000000000..ac7a785c09
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/feature.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/gear.svg b/thermal_invoice_report/static/description/assets/icons/gear.svg
new file mode 100644
index 0000000000..0cc66b6ea7
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/gear.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/hero.gif b/thermal_invoice_report/static/description/assets/icons/hero.gif
new file mode 100644
index 0000000000..6896d4d7e1
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/hero.gif differ
diff --git a/thermal_invoice_report/static/description/assets/icons/hire-odoo.svg b/thermal_invoice_report/static/description/assets/icons/hire-odoo.svg
new file mode 100644
index 0000000000..e1ac089b04
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/hire-odoo.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/hotel-black.png b/thermal_invoice_report/static/description/assets/icons/hotel-black.png
new file mode 100644
index 0000000000..130f613be0
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/hotel-black.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/license.png b/thermal_invoice_report/static/description/assets/icons/license.png
new file mode 100644
index 0000000000..a5869797ec
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/license.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/life-ring-icon.svg b/thermal_invoice_report/static/description/assets/icons/life-ring-icon.svg
new file mode 100644
index 0000000000..3ae6e1d896
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/life-ring-icon.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/lifebuoy.png b/thermal_invoice_report/static/description/assets/icons/lifebuoy.png
new file mode 100644
index 0000000000..658d56cccf
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/lifebuoy.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/mail.svg b/thermal_invoice_report/static/description/assets/icons/mail.svg
new file mode 100644
index 0000000000..1eedde695b
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/mail.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/manufacturing-black.png b/thermal_invoice_report/static/description/assets/icons/manufacturing-black.png
new file mode 100644
index 0000000000..697eb0e9f2
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/manufacturing-black.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/notes.png b/thermal_invoice_report/static/description/assets/icons/notes.png
new file mode 100644
index 0000000000..ee5e954047
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/notes.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/notification icon.svg b/thermal_invoice_report/static/description/assets/icons/notification icon.svg
new file mode 100644
index 0000000000..0531899736
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/notification icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/odoo-consultancy.svg b/thermal_invoice_report/static/description/assets/icons/odoo-consultancy.svg
new file mode 100644
index 0000000000..e05f65bde4
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/odoo-consultancy.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/odoo-licencing.svg b/thermal_invoice_report/static/description/assets/icons/odoo-licencing.svg
new file mode 100644
index 0000000000..2606c88b04
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/odoo-licencing.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/odoo-logo.png b/thermal_invoice_report/static/description/assets/icons/odoo-logo.png
new file mode 100644
index 0000000000..0e4d0eb5a4
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/odoo-logo.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/patter.svg b/thermal_invoice_report/static/description/assets/icons/patter.svg
new file mode 100644
index 0000000000..25c9c0a8f1
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/patter.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/pattern1.png b/thermal_invoice_report/static/description/assets/icons/pattern1.png
new file mode 100644
index 0000000000..09ab0fb2d9
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/pattern1.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/pos-black.png b/thermal_invoice_report/static/description/assets/icons/pos-black.png
new file mode 100644
index 0000000000..97c0f90c10
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/pos-black.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/puzzle-piece-icon.svg b/thermal_invoice_report/static/description/assets/icons/puzzle-piece-icon.svg
new file mode 100644
index 0000000000..3e9ad93738
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/puzzle-piece-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/puzzle.png b/thermal_invoice_report/static/description/assets/icons/puzzle.png
new file mode 100644
index 0000000000..65cf854e7e
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/puzzle.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/replace-icon.svg b/thermal_invoice_report/static/description/assets/icons/replace-icon.svg
new file mode 100644
index 0000000000..d0e3a7af1a
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/replace-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/restaurant-black.png b/thermal_invoice_report/static/description/assets/icons/restaurant-black.png
new file mode 100644
index 0000000000..4a35eb939c
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/restaurant-black.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/screenshot-main.png b/thermal_invoice_report/static/description/assets/icons/screenshot-main.png
new file mode 100644
index 0000000000..575f8e676b
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/screenshot-main.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/screenshot.png b/thermal_invoice_report/static/description/assets/icons/screenshot.png
new file mode 100644
index 0000000000..cef272529d
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/screenshot.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/service-black.png b/thermal_invoice_report/static/description/assets/icons/service-black.png
new file mode 100644
index 0000000000..301ab51cb1
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/service-black.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/skype-fill.svg b/thermal_invoice_report/static/description/assets/icons/skype-fill.svg
new file mode 100644
index 0000000000..c174236393
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/skype-fill.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/skype.png b/thermal_invoice_report/static/description/assets/icons/skype.png
new file mode 100644
index 0000000000..51b409fb3f
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/skype.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/skype.svg b/thermal_invoice_report/static/description/assets/icons/skype.svg
new file mode 100644
index 0000000000..df3dad39b5
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/skype.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/star-1.svg b/thermal_invoice_report/static/description/assets/icons/star-1.svg
new file mode 100644
index 0000000000..7e55ab162e
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/star-1.svg
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/star-2.svg b/thermal_invoice_report/static/description/assets/icons/star-2.svg
new file mode 100644
index 0000000000..5ae9f507a1
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/star-2.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/support.png b/thermal_invoice_report/static/description/assets/icons/support.png
new file mode 100644
index 0000000000..4f18b8b820
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/support.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/test-1 - Copy.png b/thermal_invoice_report/static/description/assets/icons/test-1 - Copy.png
new file mode 100644
index 0000000000..f6a9026637
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/test-1 - Copy.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/test-1.png b/thermal_invoice_report/static/description/assets/icons/test-1.png
new file mode 100644
index 0000000000..0908add2b0
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/test-1.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/test-2.png b/thermal_invoice_report/static/description/assets/icons/test-2.png
new file mode 100644
index 0000000000..4671fe91e9
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/test-2.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/trading-black.png b/thermal_invoice_report/static/description/assets/icons/trading-black.png
new file mode 100644
index 0000000000..9398ba2f1a
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/trading-black.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/training.png b/thermal_invoice_report/static/description/assets/icons/training.png
new file mode 100644
index 0000000000..884ca024d7
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/training.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/translate.svg b/thermal_invoice_report/static/description/assets/icons/translate.svg
new file mode 100644
index 0000000000..af9c8a1aa8
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/translate.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/update.png b/thermal_invoice_report/static/description/assets/icons/update.png
new file mode 100644
index 0000000000..ecbc5a01a2
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/update.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/user.png b/thermal_invoice_report/static/description/assets/icons/user.png
new file mode 100644
index 0000000000..6ffb23d9f0
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/user.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/video.png b/thermal_invoice_report/static/description/assets/icons/video.png
new file mode 100644
index 0000000000..576705b172
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/video.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/whatsapp.png b/thermal_invoice_report/static/description/assets/icons/whatsapp.png
new file mode 100644
index 0000000000..d513a5356b
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/whatsapp.png differ
diff --git a/thermal_invoice_report/static/description/assets/icons/wrench-icon.svg b/thermal_invoice_report/static/description/assets/icons/wrench-icon.svg
new file mode 100644
index 0000000000..174b5a465e
--- /dev/null
+++ b/thermal_invoice_report/static/description/assets/icons/wrench-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/description/assets/icons/wrench.png b/thermal_invoice_report/static/description/assets/icons/wrench.png
new file mode 100644
index 0000000000..6c04dea0f4
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/icons/wrench.png differ
diff --git a/thermal_invoice_report/static/description/assets/modules/b1.jpg b/thermal_invoice_report/static/description/assets/modules/b1.jpg
new file mode 100644
index 0000000000..3cb15fe019
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/modules/b1.jpg differ
diff --git a/thermal_invoice_report/static/description/assets/modules/b2.jpg b/thermal_invoice_report/static/description/assets/modules/b2.jpg
new file mode 100644
index 0000000000..00ebf54ad7
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/modules/b2.jpg differ
diff --git a/thermal_invoice_report/static/description/assets/modules/b3.jpg b/thermal_invoice_report/static/description/assets/modules/b3.jpg
new file mode 100644
index 0000000000..0178d2964c
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/modules/b3.jpg differ
diff --git a/thermal_invoice_report/static/description/assets/modules/b4.jpg b/thermal_invoice_report/static/description/assets/modules/b4.jpg
new file mode 100644
index 0000000000..a83c58aacc
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/modules/b4.jpg differ
diff --git a/thermal_invoice_report/static/description/assets/modules/b5.jpg b/thermal_invoice_report/static/description/assets/modules/b5.jpg
new file mode 100644
index 0000000000..82a0247aa9
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/modules/b5.jpg differ
diff --git a/thermal_invoice_report/static/description/assets/modules/b6.jpg b/thermal_invoice_report/static/description/assets/modules/b6.jpg
new file mode 100644
index 0000000000..5f78ce6dac
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/modules/b6.jpg differ
diff --git a/thermal_invoice_report/static/description/assets/screenshots/screenshot1.png b/thermal_invoice_report/static/description/assets/screenshots/screenshot1.png
new file mode 100644
index 0000000000..284d7ef51f
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/screenshots/screenshot1.png differ
diff --git a/thermal_invoice_report/static/description/assets/screenshots/screenshot2.png b/thermal_invoice_report/static/description/assets/screenshots/screenshot2.png
new file mode 100644
index 0000000000..ede8f00812
Binary files /dev/null and b/thermal_invoice_report/static/description/assets/screenshots/screenshot2.png differ
diff --git a/thermal_invoice_report/static/description/banner.jpg b/thermal_invoice_report/static/description/banner.jpg
new file mode 100644
index 0000000000..225c1123b2
Binary files /dev/null and b/thermal_invoice_report/static/description/banner.jpg differ
diff --git a/thermal_invoice_report/static/description/icon.png b/thermal_invoice_report/static/description/icon.png
new file mode 100644
index 0000000000..870764899a
Binary files /dev/null and b/thermal_invoice_report/static/description/icon.png differ
diff --git a/thermal_invoice_report/static/description/index.html b/thermal_invoice_report/static/description/index.html
new file mode 100644
index 0000000000..f0ad3746b9
--- /dev/null
+++ b/thermal_invoice_report/static/description/index.html
@@ -0,0 +1,850 @@
+
+
+
+
+
+ Thermal Invoice Report
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Community
+
+
+ Enterprise
+
+
+ Odoo.sh
+
+
+
+
+
+
+
+
+
+ A Module For Printing Thermal Invoice.
+
+
Thermal Invoice Report
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Key
+ Highlights
+
+
+
+
+
+
+
+ Print Thermal Invoice.
+
+
+
+
+
+
+
+
+
+
+
+ Available in Odoo 18.0 Community and Enterprise.
+
+
+
+
+
+
+
+
+
+
+
+
Thermal Invoice Report
+
+ Are you ready to make your business more
+ organized?
+ Improve now!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Print
+
+ Thermal Invoice
+
+
+
+
+ We can Print Thermal Invoice form this action.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Thermal Invoice
+
+
+
+
+
+
+ The printed Thermal Invoice.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Available in Odoo 18.0 Community and Enterprise.
+
+
+
+
+
+
+
+
+
+
+
The Thermal Invoice Report App enables users to generate and print a
+ comprehensive Thermal Invoice report with ease.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This module enables the
+ printing of invoices in a
+ thermal printer-friendly format,
+ making it ideal for POS systems,
+ small bill receipts, or compact invoices.
+
+
+
+
+
+
+
+
+ No, it adds an additional
+ report layout specifically
+ optimized for thermal paper.
+ You can still access and use
+ the default A4 invoice.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latest Release 18.0.1.0.0
+
+
+ 02nd July, 2025
+
+
+
+
+
+
+
+
+
+
+
+
+ Related Products
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thermal_invoice_report/static/src/css/thermal_style.css b/thermal_invoice_report/static/src/css/thermal_style.css
new file mode 100644
index 0000000000..71ec0ffc43
--- /dev/null
+++ b/thermal_invoice_report/static/src/css/thermal_style.css
@@ -0,0 +1,46 @@
+@import url('https://fonts.googleapis.com/css2?family=VT323&display=swap');
+
+body {
+ font-family: 'VT323', monospace;
+}
+.my_container {
+ font-family: 'VT323', monospace;
+ font-size: 8px;
+}
+
+.my_table, .my_product_table {
+ width: 90%;
+ border: transparent;
+}
+
+.my_table,.my_product_table {
+ padding-left: 20px;
+ padding-right: 20px;
+}
+
+.my_product_table tr:first-child {
+ border-bottom: 1px;
+ border-style: dashed;
+}
+.cntr {
+ display: flex;
+ justify-content: center;
+ width: 100%;
+}
+.my_section{
+ width: 90%;
+ position: relative;
+ padding: 0 5px
+}
+.detail_section{
+ text-align:left;
+}
+.date_section{
+ position: absolute;
+ text-align: left;
+ right: 0;
+ top:10px;
+}
+.my_table tr td:nth-child(3n+3) {
+ text-align: right;
+}
diff --git a/user_warehouse_restriction/README.rst b/user_warehouse_restriction/README.rst
new file mode 100644
index 0000000000..3fddeddaee
--- /dev/null
+++ b/user_warehouse_restriction/README.rst
@@ -0,0 +1,48 @@
+.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg
+ :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+User Warehouse Restriction
+==========================
+This module helps you to restrict warehouse and stock location for the users.
+So that users can only access the allowed warehouse and locations.
+
+Configuration
+=============
+* Enable 'Restrict stock warehouse to users' from inventory configuration settings
+* Restrict warehouse and stock location for the users.
+
+License
+-------
+Affero General Public License v3.0 (AGPL v3)
+(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
+
+Company
+-------
+* `Cybrosys Techno Solutions `__
+
+Credits
+-------
+* Developer: (V18) Unnimaya CO, Contact: odoo@cybrosys.com
+
+Contacts
+--------
+* Mail Contact : odoo@cybrosys.com
+* Website : https://cybrosys.com
+
+Bug Tracker
+-----------
+Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
+
+Maintainer
+==========
+.. image:: https://cybrosys.com/images/logo.png
+ :target: https://cybrosys.com
+
+This module is maintained by Cybrosys Technologies.
+
+For support and more information, please visit `Our Website `__
+
+Further information
+===================
+HTML Description: ``__
diff --git a/user_warehouse_restriction/__init__.py b/user_warehouse_restriction/__init__.py
new file mode 100644
index 0000000000..bd31dde58c
--- /dev/null
+++ b/user_warehouse_restriction/__init__.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Unnimaya CO (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from . import models
diff --git a/user_warehouse_restriction/__manifest__.py b/user_warehouse_restriction/__manifest__.py
new file mode 100644
index 0000000000..6d3d3a25b6
--- /dev/null
+++ b/user_warehouse_restriction/__manifest__.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Unnimaya CO (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+{
+ 'name': "User Warehouse Restriction",
+ 'version': '18.0.1.0.0',
+ 'category': 'Warehouse',
+ 'summary': """Restrict Warehouses and location for users.""",
+ 'description': """This module helps you to restrict warehouse and stock
+ location for the specific users. So that users can only access the allowed
+ warehouse and locations.""",
+ 'author': 'Cybrosys Techno Solutions',
+ 'company': 'Cybrosys Techno Solutions',
+ 'maintainer': 'Cybrosys Techno Solutions',
+ 'website': "https://www.cybrosys.com",
+ 'depends': ['stock_sms'],
+ 'data': [
+ 'security/user_warehouse_restriction_groups.xml',
+ 'security/user_warehouse_restriction_security.xml',
+ 'views/res_config_settings_views.xml',
+ 'views/stock_warehouse_views.xml',
+ 'views/res_users_views.xml',
+ ],
+ 'images': ['static/description/banner.jpg'],
+ 'license': 'AGPL-3',
+ 'installable': True,
+ 'auto_install': False,
+ 'application': False,
+}
diff --git a/user_warehouse_restriction/doc/RELEASE_NOTES.md b/user_warehouse_restriction/doc/RELEASE_NOTES.md
new file mode 100644
index 0000000000..17a5c33a09
--- /dev/null
+++ b/user_warehouse_restriction/doc/RELEASE_NOTES.md
@@ -0,0 +1,7 @@
+## Module
+
+#### 04.08.2025
+#### Version 18.0.1.0.0
+#### ADD
+
+- Initial commit for User Warehouse Restriction
\ No newline at end of file
diff --git a/user_warehouse_restriction/models/__init__.py b/user_warehouse_restriction/models/__init__.py
new file mode 100644
index 0000000000..b6a4ec1fe5
--- /dev/null
+++ b/user_warehouse_restriction/models/__init__.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Unnimaya CO(odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from . import res_config_settings
+from . import res_users
+from . import stock_picking
+from . import stock_warehouse
diff --git a/user_warehouse_restriction/models/res_config_settings.py b/user_warehouse_restriction/models/res_config_settings.py
new file mode 100755
index 0000000000..e35af7a9be
--- /dev/null
+++ b/user_warehouse_restriction/models/res_config_settings.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Unnimaya CO (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+import logging
+from odoo import api, fields, models
+from odoo.exceptions import AccessError
+
+_logger = logging.getLogger(__name__)
+
+
+class ResConfigSettings(models.TransientModel):
+ """Add new fields to configuration settings to Restrict stock warehouse
+ for users."""
+ _inherit = 'res.config.settings'
+
+ group_user_warehouse_restriction = fields.Boolean(
+ string="Restrict Stock Warehouse",
+ implied_group='user_warehouse_restriction.'
+ 'user_warehouse_restriction_group_user',
+ help="Check if you want to restrict warehouse for users.")
+
+ @api.onchange('group_user_warehouse_restriction')
+ def _onchange_group_user_warehouse_restriction(self):
+ """This method is triggered when the 'group_user_warehouse_restriction'
+ field is changed. if it's true, assigns the current user as the
+ allowed user of all existing warehouses."""
+ rule = self.env.ref('user_warehouse_restriction.operation_type_rule_users', raise_if_not_found=False)
+ if rule:
+ rule.active = False
+ try:
+ warehouses = self.env['stock.warehouse'].search([])
+ for warehouse in warehouses:
+ if self.group_user_warehouse_restriction:
+ # Assign the current user to each warehouse
+ if not warehouse.user_ids:
+ warehouse.user_ids = [(6, 0, [self.env.user.id])]
+ else:
+ # Clear the allowed users for each warehouse
+ warehouse.user_ids = [(5, 0, 0)]
+ except AccessError as e:
+ _logger.warning(f"Access error occurred: {e}")
+ finally:
+ if rule:
+ rule.active = True
diff --git a/user_warehouse_restriction/models/res_users.py b/user_warehouse_restriction/models/res_users.py
new file mode 100644
index 0000000000..6ea390797f
--- /dev/null
+++ b/user_warehouse_restriction/models/res_users.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Unnimaya CO (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from odoo import fields, models
+
+
+class ResUsers(models.Model):
+ """This model adds additional fields to the `res.users` model to restrict
+ user access to certain locations and warehouses."""
+ _inherit = 'res.users'
+
+ restrict_location = fields.Boolean(string="Restrict Location",
+ help='Restrict location for the user.')
+ location_ids = fields.Many2many(comodel_name='stock.location',
+ string='Restricted Locations',
+ help='Restricted locations for users.')
+ allowed_warehouse_ids = fields.Many2many(
+ comodel_name='stock.warehouse', string='Allowed Warehouse',
+ help='Allowed Warehouse for user.')
+ check_user = fields.Boolean(string="Check", compute='_compute_check_user',
+ help="Indicates whether the user has warehouse"
+ " location restrictions.")
+
+ def _compute_check_user(self):
+ """To determine if the user has warehouse location restrictions.
+ Sets the check_user field accordingly."""
+ for record in self:
+ record.check_user = False
+ record.restrict_location = False
+ if self.env.user.has_group(
+ 'user_warehouse_restriction.user_warehouse_restriction_group_user'):
+ record.check_user = True
+ record.restrict_location = True
diff --git a/user_warehouse_restriction/models/stock_picking.py b/user_warehouse_restriction/models/stock_picking.py
new file mode 100644
index 0000000000..8e6c91800d
--- /dev/null
+++ b/user_warehouse_restriction/models/stock_picking.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Unnimaya CO (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+from odoo import api, models
+
+
+class StockPicking(models.Model):
+ """Extends stock picking to apply domain restrictions based on user's
+ assigned warehouses."""
+ _inherit = 'stock.picking'
+
+ @api.onchange('location_id', 'location_dest_id')
+ def _onchange_location_id(self):
+ """Domain for location_id and location_dest_id."""
+ if self.env['ir.config_parameter'].sudo().get_param('user_warehouse_restriction.group_user_warehouse_restriction'):
+ return {
+ 'domain': {'location_id': [
+ ('warehouse_id.user_ids', 'in', self.env.user.id)],
+ 'location_dest_id': [
+ ('warehouse_id.user_ids', 'in', self.env.user.id)]}}
diff --git a/user_warehouse_restriction/models/stock_warehouse.py b/user_warehouse_restriction/models/stock_warehouse.py
new file mode 100644
index 0000000000..c4304c55b5
--- /dev/null
+++ b/user_warehouse_restriction/models/stock_warehouse.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Unnimaya CO (odoo@cybrosys.com)
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from odoo import api, fields, models
+
+
+class StockWarehouse(models.Model):
+ """Extends the 'stock.warehouse' model to add functionality for restricting
+ stock location access to specific users within the system."""
+ _inherit = "stock.warehouse"
+
+ user_ids = fields.Many2many(
+ comodel_name='res.users', string='Allowed Users',
+ domain=lambda self: [
+ ('groups_id', 'in', self.env.ref('stock.group_stock_user').id)],
+ # default=lambda self: self.env.user,
+ help='Users who are allowed access to this warehouse.')
+ restrict_location = fields.Boolean(
+ string='Restrict Stock Location for this Warehouse',
+ help='Restrict stock location of this warehouse to the selected '
+ 'users.')
+
+ @api.onchange('restrict_location', 'user_ids')
+ def _onchange_restrict_location(self):
+ """Triggered when the 'restrict_location' or 'user_ids' fields
+ are modified. It updates the 'restrict_location' field for selected
+ users when restricting stock location access."""
+ for rec in self.user_ids:
+ if self.restrict_location:
+ rec._origin.write({'restrict_location': True,
+ 'allowed_warehouse_ids': [
+ (4, self._origin.id)]})
+ elif not self.restrict_location:
+ rec._origin.write({'restrict_location': True,
+ 'location_ids': False
+ })
+
+ def action_open_users_view(self):
+ """Return user basic form view to give restricted location for users"""
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': 'Users',
+ 'view_mode': 'list,form',
+ 'res_model': 'res.users',
+ 'domain': [('id', 'in', [user.id for user in self.user_ids]),
+ ('groups_id', 'not in',
+ [self.env.ref('base.group_system').id])]}
diff --git a/user_warehouse_restriction/security/user_warehouse_restriction_groups.xml b/user_warehouse_restriction/security/user_warehouse_restriction_groups.xml
new file mode 100644
index 0000000000..5a19c238d8
--- /dev/null
+++ b/user_warehouse_restriction/security/user_warehouse_restriction_groups.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ Restrict Warehouse for Users
+
+
+
diff --git a/user_warehouse_restriction/security/user_warehouse_restriction_security.xml b/user_warehouse_restriction/security/user_warehouse_restriction_security.xml
new file mode 100644
index 0000000000..f9bb080e19
--- /dev/null
+++ b/user_warehouse_restriction/security/user_warehouse_restriction_security.xml
@@ -0,0 +1,52 @@
+
+
+
+
+ Operation Type Restrict on Users
+
+ [('warehouse_id.user_ids','in', user.id)]
+
+
+
+
+
+
+
+
+
+ Stock Location Restrict on Users
+
+ [('id', 'not in', user.location_ids.ids)]
+
+
+
+
+
+
+
+
+
+ Warehouse Restrict on Users
+
+ [('user_ids','in', user.id)]
+
+
+
+
+
+
+
+
+
+ Warehouse Transfers Restrict on Users
+
+ [('picking_type_id.warehouse_id.user_ids','in', user.id)]
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/cybro-icon.png b/user_warehouse_restriction/static/description/assets/cybro-icon.png
new file mode 100755
index 0000000000..06e73e11de
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/cybro-icon.png differ
diff --git a/user_warehouse_restriction/static/description/assets/cybro-odoo.png b/user_warehouse_restriction/static/description/assets/cybro-odoo.png
new file mode 100755
index 0000000000..ed02e07a48
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/cybro-odoo.png differ
diff --git a/user_warehouse_restriction/static/description/assets/h2.png b/user_warehouse_restriction/static/description/assets/h2.png
new file mode 100755
index 0000000000..0bfc4707d8
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/h2.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/arrows-repeat.svg b/user_warehouse_restriction/static/description/assets/icons/arrows-repeat.svg
new file mode 100755
index 0000000000..1d7efabc52
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/arrows-repeat.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/banner-1.png b/user_warehouse_restriction/static/description/assets/icons/banner-1.png
new file mode 100755
index 0000000000..c180db1729
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/banner-1.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/banner-2.svg b/user_warehouse_restriction/static/description/assets/icons/banner-2.svg
new file mode 100755
index 0000000000..e606d97d98
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/banner-2.svg
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/banner-bg.png b/user_warehouse_restriction/static/description/assets/icons/banner-bg.png
new file mode 100755
index 0000000000..a8238d3c09
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/banner-bg.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/banner-bg.svg b/user_warehouse_restriction/static/description/assets/icons/banner-bg.svg
new file mode 100755
index 0000000000..b1378103e2
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/banner-bg.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/banner-call.svg b/user_warehouse_restriction/static/description/assets/icons/banner-call.svg
new file mode 100755
index 0000000000..96c687e81f
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/banner-call.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/banner-mail.svg b/user_warehouse_restriction/static/description/assets/icons/banner-mail.svg
new file mode 100755
index 0000000000..cbf0d158d2
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/banner-mail.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/banner-pattern.svg b/user_warehouse_restriction/static/description/assets/icons/banner-pattern.svg
new file mode 100755
index 0000000000..9c1c7e101c
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/banner-pattern.svg
@@ -0,0 +1,343 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/banner-promo.svg b/user_warehouse_restriction/static/description/assets/icons/banner-promo.svg
new file mode 100755
index 0000000000..d52791b11e
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/banner-promo.svg
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/brand-pair.svg b/user_warehouse_restriction/static/description/assets/icons/brand-pair.svg
new file mode 100755
index 0000000000..d8db7fc1e7
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/brand-pair.svg
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/check.png b/user_warehouse_restriction/static/description/assets/icons/check.png
new file mode 100755
index 0000000000..c8e85f51d6
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/check.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/chevron.png b/user_warehouse_restriction/static/description/assets/icons/chevron.png
new file mode 100755
index 0000000000..2089293d6a
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/chevron.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/close-icon.svg b/user_warehouse_restriction/static/description/assets/icons/close-icon.svg
new file mode 100755
index 0000000000..df8cce37a5
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/close-icon.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/cogs.png b/user_warehouse_restriction/static/description/assets/icons/cogs.png
new file mode 100755
index 0000000000..95d0bad62c
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/cogs.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/collabarate-icon.svg b/user_warehouse_restriction/static/description/assets/icons/collabarate-icon.svg
new file mode 100755
index 0000000000..dd4e105183
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/collabarate-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/consultation.png b/user_warehouse_restriction/static/description/assets/icons/consultation.png
new file mode 100755
index 0000000000..8319d4baa0
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/consultation.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/cybro-logo.png b/user_warehouse_restriction/static/description/assets/icons/cybro-logo.png
new file mode 100755
index 0000000000..ff4b782205
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/cybro-logo.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/down.svg b/user_warehouse_restriction/static/description/assets/icons/down.svg
new file mode 100755
index 0000000000..f21c36271b
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/down.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/user_warehouse_restriction/static/description/assets/icons/ecom-black.png b/user_warehouse_restriction/static/description/assets/icons/ecom-black.png
new file mode 100755
index 0000000000..a9385ff13f
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/ecom-black.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/education-black.png b/user_warehouse_restriction/static/description/assets/icons/education-black.png
new file mode 100755
index 0000000000..3eb09b27b4
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/education-black.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/faq.png b/user_warehouse_restriction/static/description/assets/icons/faq.png
new file mode 100755
index 0000000000..4250b5b817
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/faq.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/feature-icon.svg b/user_warehouse_restriction/static/description/assets/icons/feature-icon.svg
new file mode 100755
index 0000000000..fa0ea6850a
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/feature-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/feature.png b/user_warehouse_restriction/static/description/assets/icons/feature.png
new file mode 100755
index 0000000000..ac7a785c09
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/feature.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/gear.svg b/user_warehouse_restriction/static/description/assets/icons/gear.svg
new file mode 100755
index 0000000000..0cc66b6ea7
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/gear.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/hero.gif b/user_warehouse_restriction/static/description/assets/icons/hero.gif
new file mode 100755
index 0000000000..380654dfe7
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/hero.gif differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/hire-odoo.svg b/user_warehouse_restriction/static/description/assets/icons/hire-odoo.svg
new file mode 100755
index 0000000000..e1ac089b04
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/hire-odoo.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/hotel-black.png b/user_warehouse_restriction/static/description/assets/icons/hotel-black.png
new file mode 100755
index 0000000000..130f613be0
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/hotel-black.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/license.png b/user_warehouse_restriction/static/description/assets/icons/license.png
new file mode 100755
index 0000000000..a5869797ec
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/license.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/life-ring-icon.svg b/user_warehouse_restriction/static/description/assets/icons/life-ring-icon.svg
new file mode 100755
index 0000000000..3ae6e1d896
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/life-ring-icon.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/lifebuoy.png b/user_warehouse_restriction/static/description/assets/icons/lifebuoy.png
new file mode 100755
index 0000000000..658d56cccf
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/lifebuoy.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/mail.svg b/user_warehouse_restriction/static/description/assets/icons/mail.svg
new file mode 100755
index 0000000000..1eedde695b
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/mail.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/manufacturing-black.png b/user_warehouse_restriction/static/description/assets/icons/manufacturing-black.png
new file mode 100755
index 0000000000..697eb0e9f2
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/manufacturing-black.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/notes.png b/user_warehouse_restriction/static/description/assets/icons/notes.png
new file mode 100755
index 0000000000..ee5e954047
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/notes.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/notification icon.svg b/user_warehouse_restriction/static/description/assets/icons/notification icon.svg
new file mode 100755
index 0000000000..0531899736
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/notification icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/odoo-consultancy.svg b/user_warehouse_restriction/static/description/assets/icons/odoo-consultancy.svg
new file mode 100755
index 0000000000..e05f65bde4
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/odoo-consultancy.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/odoo-licencing.svg b/user_warehouse_restriction/static/description/assets/icons/odoo-licencing.svg
new file mode 100755
index 0000000000..2606c88b04
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/odoo-licencing.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/odoo-logo.png b/user_warehouse_restriction/static/description/assets/icons/odoo-logo.png
new file mode 100755
index 0000000000..0e4d0eb5a4
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/odoo-logo.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/patter.svg b/user_warehouse_restriction/static/description/assets/icons/patter.svg
new file mode 100755
index 0000000000..25c9c0a8f1
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/patter.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/pattern1.png b/user_warehouse_restriction/static/description/assets/icons/pattern1.png
new file mode 100755
index 0000000000..09ab0fb2d9
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/pattern1.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/pos-black.png b/user_warehouse_restriction/static/description/assets/icons/pos-black.png
new file mode 100755
index 0000000000..97c0f90c10
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/pos-black.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/puzzle-piece-icon.svg b/user_warehouse_restriction/static/description/assets/icons/puzzle-piece-icon.svg
new file mode 100755
index 0000000000..3e9ad93738
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/puzzle-piece-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/puzzle.png b/user_warehouse_restriction/static/description/assets/icons/puzzle.png
new file mode 100755
index 0000000000..65cf854e7e
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/puzzle.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/replace-icon.svg b/user_warehouse_restriction/static/description/assets/icons/replace-icon.svg
new file mode 100755
index 0000000000..d0e3a7af1a
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/replace-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/restaurant-black.png b/user_warehouse_restriction/static/description/assets/icons/restaurant-black.png
new file mode 100755
index 0000000000..4a35eb939c
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/restaurant-black.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/screenshot-main.png b/user_warehouse_restriction/static/description/assets/icons/screenshot-main.png
new file mode 100755
index 0000000000..575f8e676b
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/screenshot-main.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/screenshot.png b/user_warehouse_restriction/static/description/assets/icons/screenshot.png
new file mode 100755
index 0000000000..cef272529d
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/screenshot.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/service-black.png b/user_warehouse_restriction/static/description/assets/icons/service-black.png
new file mode 100755
index 0000000000..301ab51cb1
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/service-black.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/skype-fill.svg b/user_warehouse_restriction/static/description/assets/icons/skype-fill.svg
new file mode 100755
index 0000000000..c174236393
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/skype-fill.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/skype.png b/user_warehouse_restriction/static/description/assets/icons/skype.png
new file mode 100755
index 0000000000..51b409fb3f
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/skype.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/skype.svg b/user_warehouse_restriction/static/description/assets/icons/skype.svg
new file mode 100755
index 0000000000..df3dad39b5
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/skype.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/star-1.svg b/user_warehouse_restriction/static/description/assets/icons/star-1.svg
new file mode 100755
index 0000000000..7e55ab162e
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/star-1.svg
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/star-2.svg b/user_warehouse_restriction/static/description/assets/icons/star-2.svg
new file mode 100755
index 0000000000..5ae9f507a1
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/star-2.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/support.png b/user_warehouse_restriction/static/description/assets/icons/support.png
new file mode 100755
index 0000000000..4f18b8b820
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/support.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/test-1 - Copy.png b/user_warehouse_restriction/static/description/assets/icons/test-1 - Copy.png
new file mode 100755
index 0000000000..f6a9026637
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/test-1 - Copy.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/test-1.png b/user_warehouse_restriction/static/description/assets/icons/test-1.png
new file mode 100755
index 0000000000..0908add2b0
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/test-1.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/test-2.png b/user_warehouse_restriction/static/description/assets/icons/test-2.png
new file mode 100755
index 0000000000..4671fe91e9
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/test-2.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/trading-black.png b/user_warehouse_restriction/static/description/assets/icons/trading-black.png
new file mode 100755
index 0000000000..9398ba2f1a
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/trading-black.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/training.png b/user_warehouse_restriction/static/description/assets/icons/training.png
new file mode 100755
index 0000000000..884ca024d7
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/training.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/translate.svg b/user_warehouse_restriction/static/description/assets/icons/translate.svg
new file mode 100755
index 0000000000..af9c8a1aa8
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/translate.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/update.png b/user_warehouse_restriction/static/description/assets/icons/update.png
new file mode 100755
index 0000000000..ecbc5a01a2
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/update.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/user.png b/user_warehouse_restriction/static/description/assets/icons/user.png
new file mode 100755
index 0000000000..6ffb23d9f0
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/user.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/video.png b/user_warehouse_restriction/static/description/assets/icons/video.png
new file mode 100755
index 0000000000..576705b172
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/video.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/whatsapp.png b/user_warehouse_restriction/static/description/assets/icons/whatsapp.png
new file mode 100755
index 0000000000..d513a5356b
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/whatsapp.png differ
diff --git a/user_warehouse_restriction/static/description/assets/icons/wrench-icon.svg b/user_warehouse_restriction/static/description/assets/icons/wrench-icon.svg
new file mode 100755
index 0000000000..174b5a465e
--- /dev/null
+++ b/user_warehouse_restriction/static/description/assets/icons/wrench-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/static/description/assets/icons/wrench.png b/user_warehouse_restriction/static/description/assets/icons/wrench.png
new file mode 100755
index 0000000000..6c04dea0f4
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/icons/wrench.png differ
diff --git a/user_warehouse_restriction/static/description/assets/modules/1.png b/user_warehouse_restriction/static/description/assets/modules/1.png
new file mode 100644
index 0000000000..fc6165ec95
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/modules/1.png differ
diff --git a/user_warehouse_restriction/static/description/assets/modules/2.png b/user_warehouse_restriction/static/description/assets/modules/2.png
new file mode 100644
index 0000000000..26e942c4bc
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/modules/2.png differ
diff --git a/user_warehouse_restriction/static/description/assets/modules/3.png b/user_warehouse_restriction/static/description/assets/modules/3.png
new file mode 100644
index 0000000000..d099c618b7
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/modules/3.png differ
diff --git a/user_warehouse_restriction/static/description/assets/modules/4.png b/user_warehouse_restriction/static/description/assets/modules/4.png
new file mode 100644
index 0000000000..166cff41ef
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/modules/4.png differ
diff --git a/user_warehouse_restriction/static/description/assets/modules/5.png b/user_warehouse_restriction/static/description/assets/modules/5.png
new file mode 100644
index 0000000000..96516b79c2
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/modules/5.png differ
diff --git a/user_warehouse_restriction/static/description/assets/modules/6.png b/user_warehouse_restriction/static/description/assets/modules/6.png
new file mode 100644
index 0000000000..44c99a65bf
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/modules/6.png differ
diff --git a/user_warehouse_restriction/static/description/assets/screenshots/1.png b/user_warehouse_restriction/static/description/assets/screenshots/1.png
new file mode 100644
index 0000000000..c97277e87b
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/screenshots/1.png differ
diff --git a/user_warehouse_restriction/static/description/assets/screenshots/2.png b/user_warehouse_restriction/static/description/assets/screenshots/2.png
new file mode 100644
index 0000000000..7e54e2e469
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/screenshots/2.png differ
diff --git a/user_warehouse_restriction/static/description/assets/screenshots/3.png b/user_warehouse_restriction/static/description/assets/screenshots/3.png
new file mode 100644
index 0000000000..0a7953403d
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/screenshots/3.png differ
diff --git a/user_warehouse_restriction/static/description/assets/screenshots/4.png b/user_warehouse_restriction/static/description/assets/screenshots/4.png
new file mode 100644
index 0000000000..727e90c827
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/screenshots/4.png differ
diff --git a/user_warehouse_restriction/static/description/assets/screenshots/5.png b/user_warehouse_restriction/static/description/assets/screenshots/5.png
new file mode 100644
index 0000000000..64f4dc20c0
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/screenshots/5.png differ
diff --git a/user_warehouse_restriction/static/description/assets/screenshots/hero.gif b/user_warehouse_restriction/static/description/assets/screenshots/hero.gif
new file mode 100644
index 0000000000..4e28fcec2a
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/screenshots/hero.gif differ
diff --git a/user_warehouse_restriction/static/description/assets/y18.jpg b/user_warehouse_restriction/static/description/assets/y18.jpg
new file mode 100755
index 0000000000..eea1714f25
Binary files /dev/null and b/user_warehouse_restriction/static/description/assets/y18.jpg differ
diff --git a/user_warehouse_restriction/static/description/banner.jpg b/user_warehouse_restriction/static/description/banner.jpg
new file mode 100644
index 0000000000..6da1b549f8
Binary files /dev/null and b/user_warehouse_restriction/static/description/banner.jpg differ
diff --git a/user_warehouse_restriction/static/description/icon.png b/user_warehouse_restriction/static/description/icon.png
new file mode 100644
index 0000000000..034ad81f3c
Binary files /dev/null and b/user_warehouse_restriction/static/description/icon.png differ
diff --git a/user_warehouse_restriction/static/description/index.html b/user_warehouse_restriction/static/description/index.html
new file mode 100644
index 0000000000..690e22872f
--- /dev/null
+++ b/user_warehouse_restriction/static/description/index.html
@@ -0,0 +1,1013 @@
+
+
+
+
+
+ User Warehouse Restriction
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Community
+
+
+ Enterprise
+
+
+ Odoo.sh
+
+
+
+
+
+
+
+
+
+ This Module Restrict Warehouse And Stock Location For Users.
+
+
User Warehouse Restriction
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Key
+ Highlights
+
+
+
+
+
+
+
+ Restrict Warehouse for Users.
+
+
+ Module allows Users to set Restriction for the warehouse.
+
+
+
+
+
+
+
+
+ Restrict Location for Users.
+
+
+ Users to set Restriction for the Location.
+
+
+
+
+
+
+
+
+
+
User Warehouse Restriction
+
+ Are you ready to make your business more
+ organized?
+ Improve now!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Enable
+ Restrict Stock warehouse
+
+
+
+
+ Go to Inventory settings -> Click the Restrict Stock warehouse button followed by the storage location button.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ User Access Restriction per Warehouse
+
+
+
+ Set allowed users under the Warehouse Allowed Users tab to restrict access.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Restrict From User form page
+
+
+
+
+ Here we can set the Restricted Warehouse and Location.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Removed the
+
+ Location and Warehouse.
+
+
+
+
As per the User Restriction the Locations are Removed from the Selection.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
For This User There is
+ no Restriction for the Location.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Restrict Warehouse Access per User
+
+
+
+
+
+
+
+
+
+
+ Restrict Location Access per User
+
+
+
+
+
+
+
+
+
+
+ Assign restricted warehouses and locations directly from the user form.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Yes, the module allows you to restrict access to specific warehouses and their internal stock locations for each user.
+
+
+
+
+
+
+
+
+ You can configure allowed users under the “Warehouse Allowed Users” tab in the warehouse form and also set restricted warehouses and locations directly on the user form.
+
+
+
+
+
+
+
+
+ If a user has no warehouse or location restriction configured, they will have full access to all warehouses and stock locations.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latest Release 18.0.1.0.0
+
+
+ 4th August, 2025
+
+
+
+
+
+
+
+
+
+
+
+
+ Related Products
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/views/res_config_settings_views.xml b/user_warehouse_restriction/views/res_config_settings_views.xml
new file mode 100755
index 0000000000..7fb6327dd8
--- /dev/null
+++ b/user_warehouse_restriction/views/res_config_settings_views.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ res.config.settings.view.form.inherit.user.warehouse.restriction
+ res.config.settings
+
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/views/res_users_views.xml b/user_warehouse_restriction/views/res_users_views.xml
new file mode 100644
index 0000000000..fcd0ae6ce6
--- /dev/null
+++ b/user_warehouse_restriction/views/res_users_views.xml
@@ -0,0 +1,43 @@
+
+
+
+
+ res.users.view.form.inherit.user.warehouse.restriction
+
+ res.users
+ extension
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ res.users.view.form.user.warehouse.restriction
+
+ res.users
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/user_warehouse_restriction/views/stock_warehouse_views.xml b/user_warehouse_restriction/views/stock_warehouse_views.xml
new file mode 100644
index 0000000000..4baf9effd0
--- /dev/null
+++ b/user_warehouse_restriction/views/stock_warehouse_views.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+ stock.warehouse.view.form.inherit.user.warehouse.restriction
+
+ stock.warehouse
+
+
+
+
+
+ stock.group_adv_location,stock.group_stock_multi_warehouses,user_warehouse_restriction.user_warehouse_restriction_group_user
+
+
+
+
+ stock.group_adv_location,stock.group_stock_multi_warehouses
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/README.rst b/website_multi_product_return_management/README.rst
new file mode 100644
index 0000000000..8aa581579f
--- /dev/null
+++ b/website_multi_product_return_management/README.rst
@@ -0,0 +1,55 @@
+.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg
+ :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+Multi Product Return From Website
+======================
+This module allows to create and manage sale order return from website.
+The logged user can create multiple product return from website.
+The Authorize persons can manage the return orders.
+And allow the portal users can view their return orders
+from the account portal view.
+
+Configuration
+=============
+No additional configuration required
+
+Company
+-------
+* `Cybrosys Techno Solutions `__
+
+License
+-------
+GNU Affero General Public License v3.0 (AGPL v3)
+(http://www.gnu.org/licenses/agpl-3.0-standalone.html)
+
+Credits
+-------
+Developer: (V15) Bhagyadev,
+ (V16) Bhagyadev,
+ (V17) Ranjith R,
+ (V18) Safa Faheem PE,
+Contact: odoo@cybrosys.com
+
+Contacts
+--------
+* Mail Contact : odoo@cybrosys.com
+* Website : https://cybrosys.com
+
+Bug Tracker
+-----------
+Bugs are tracked on GitHub Issues. In case of trouble, please check there if
+your issue has already been reported.
+
+Maintainer
+==========
+.. image:: https://cybrosys.com/images/logo.png
+ :target: https://cybrosys.com
+
+This module is maintained by Cybrosys Technologies.
+
+For support and more information, please visit `Our Website `__
+
+Further information
+===================
+HTML Description: ``__
diff --git a/website_multi_product_return_management/__init__.py b/website_multi_product_return_management/__init__.py
new file mode 100644
index 0000000000..48ba581625
--- /dev/null
+++ b/website_multi_product_return_management/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from . import controllers
+from . import models
+from . import wizard
diff --git a/website_multi_product_return_management/__manifest__.py b/website_multi_product_return_management/__manifest__.py
new file mode 100644
index 0000000000..3e6f1dfbda
--- /dev/null
+++ b/website_multi_product_return_management/__manifest__.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+{
+ 'name': 'Multi Product Return From Website',
+ 'version': '18.0.1.0.0',
+ 'category': 'Website',
+ 'summary': 'Sale order multi product return management from website',
+ 'description': "Streamline your website with advanced Multi-product Return "
+ "Order Management. Easily manage returns, RMA, and order "
+ "return processes directly from your website.",
+ 'author': 'Cybrosys Techno Solutions',
+ 'company': 'Cybrosys Techno Solutions',
+ 'maintainer': 'Cybrosys Techno Solutions',
+ 'website': 'https://www.cybrosys.com',
+ 'depends': ['website_sale', 'stock', 'sale_management'],
+ 'data': [
+ 'security/ir.model.access.csv',
+ 'data/ir_sequence_data.xml',
+ 'views/website_thankyou_template.xml',
+ 'views/sale_order_portal_templates.xml',
+ 'views/sale_return_views.xml',
+ 'views/sale_order_views.xml',
+ 'views/res_partner_views.xml',
+ 'views/stock_picking_views.xml',
+ 'report/sale_return_templates.xml',
+ 'report/sale_return_reports.xml',
+ ],
+ 'assets': {
+ 'web.assets_frontend': [
+ 'website_multi_product_return_management/static/src/js/sale_return.js',
+ ],
+ },
+ 'images': ['static/description/banner.jpg'],
+ 'license': 'AGPL-3',
+ 'installable': True,
+ 'auto_install': False,
+ 'application': False,
+}
diff --git a/website_multi_product_return_management/controllers/__init__.py b/website_multi_product_return_management/controllers/__init__.py
new file mode 100644
index 0000000000..5e1a8c65ac
--- /dev/null
+++ b/website_multi_product_return_management/controllers/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from . import website_multi_product_return_management
+from . import portal
diff --git a/website_multi_product_return_management/controllers/portal.py b/website_multi_product_return_management/controllers/portal.py
new file mode 100644
index 0000000000..b80178b652
--- /dev/null
+++ b/website_multi_product_return_management/controllers/portal.py
@@ -0,0 +1,158 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+import base64
+from collections import OrderedDict
+from odoo import http
+from odoo.exceptions import AccessError, MissingError
+from odoo.http import request
+from odoo.tools import image_process
+from odoo.tools.translate import _
+from odoo.addons.portal.controllers.portal import CustomerPortal
+from odoo.addons.web.controllers.binary import Binary
+
+
+class ReturnCustomerPortal(CustomerPortal):
+ """Customized Customer Portal for managing sale returns."""
+
+ def _prepare_home_portal_values(self, counters):
+ """Prepare values for the home portal."""
+ values = super()._prepare_home_portal_values(counters)
+ partner = request.env.user.partner_id
+ if 'return_count' in counters:
+ if request.env.user.has_group('base.group_portal'):
+ values['return_count'] = request.env[
+ 'sale.return'].search_count(
+ [('state', 'in', ['draft', 'confirm', 'done', 'cancel']),
+ ('partner_id', '=', partner.id)])
+ elif request.env.user.has_group('base.group_system'):
+ values['return_count'] = request.env[
+ 'sale.return'].search_count(
+ [('state', 'in', ['draft', 'confirm', 'done', 'cancel'])])
+ else:
+ values['return_count'] = request.env[
+ 'sale.return'].search_count(
+ ['|', ('partner_id', '=', partner.id),
+ ('user_id', '=', request.env.user.id)])
+ return values
+
+ @http.route(['/my/return_orders', '/my/return_orders/page/'],
+ type='http', auth="user", website=True)
+ def portal_my_sale_return(self, page=1, date_begin=None, date_end=None,
+ sortby=None, filterby=None, **kw):
+ """Handle requests for displaying sale return orders in the portal."""
+ values = self._prepare_portal_layout_values()
+ sale_return = request.env['sale.return']
+ partner = request.env.user.partner_id
+ if request.env.user.has_group('base.group_portal'):
+ domain = [
+ ('partner_id', '=', partner.id)
+ ]
+ elif request.env.user.has_group('base.group_system'):
+ domain = []
+ else:
+ domain = ['|', ('partner_id', '=', partner.id),
+ ('user_id', '=', request.env.user.id)]
+ searchbar_sortings = {
+ 'date': {'label': _('Newest'), 'order': 'create_date desc'},
+ 'name': {'label': _('Name'), 'order': 'name'},
+ 'sale': {'label': _('Sale Order'), 'order': 'sale_order'},
+ }
+ if not sortby:
+ sortby = 'date'
+ order = searchbar_sortings[sortby]['order']
+ if date_begin and date_end:
+ domain += [('create_date', '>', date_begin),
+ ('create_date', '<=', date_end)]
+ searchbar_filters = {
+ 'all': {'label': _('All'), 'domain': [
+ ('state', 'in', ['draft', 'confirm', 'done', 'cancel'])]},
+ 'confirm': {'label': _('Confirmed'),
+ 'domain': [('state', '=', 'confirm')]},
+ 'cancel': {'label': _('Cancelled'),
+ 'domain': [('state', '=', 'cancel')]},
+ 'done': {'label': _('Done'), 'domain': [('state', '=', 'done')]},
+ }
+ if not filterby:
+ filterby = 'all'
+ domain += searchbar_filters[filterby]['domain']
+ return_count = sale_return.sudo().search_count(domain)
+ pager = request.website.pager(
+ url="/my/return_orders",
+ url_args={'date_begin': date_begin, 'date_end': date_end,
+ 'sortby': sortby},
+ total=return_count,
+ page=page,
+ step=self._items_per_page
+ )
+ orders = sale_return.sudo().search(domain, order=order,
+ limit=self._items_per_page,
+ offset=pager['offset'])
+ request.session['my_return_history'] = orders.ids[:100]
+ values.update({
+ 'date': date_begin,
+ 'orders': orders.sudo(),
+ 'page_name': 'Sale_Return',
+ 'default_url': '/my/return_orders',
+ 'pager': pager,
+ 'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
+ 'searchbar_sortings': searchbar_sortings,
+ 'sortby': sortby,
+ })
+ return request.render(
+ "website_multi_product_return_management.portal_my_returns", values)
+
+ @http.route(['/my/return_orders/'], type='http',
+ auth="public", website=True)
+ def portal_my_return_detail(self, order_id=None, access_token=None,
+ report_type=None, download=False, **kw):
+ """Handle requests for displaying details of a specific sale
+ return order."""
+ try:
+ order_sudo = self._document_check_access('sale.return', order_id,
+ access_token)
+ except (AccessError, MissingError):
+ return request.redirect('/my')
+ if report_type in ('html', 'pdf', 'text'):
+ return self._show_report(
+ model=order_sudo, report_type=report_type,
+ report_ref='website_multi_product_return_management.'
+ 'report_sale_returns',
+ download=download)
+ values = self._sale_return_get_page_view_values(order_sudo,
+ access_token, **kw)
+ return request.render(
+ "website_multi_product_return_management.portal_sale_return_page",
+ values)
+
+ def _sale_return_get_page_view_values(self, order, access_token, **kwargs):
+ """Get values for rendering the sale return page view."""
+ def resize_to_48(b64source):
+ """Resizing image as needed"""
+ if not b64source:
+ b64source = base64.b64encode(Binary.placeholder())
+ return image_process(b64source, size=(48, 48))
+ values = {
+ 'orders': order,
+ 'resize_to_48': resize_to_48,
+ }
+ return self._get_page_view_values(order, access_token, values,
+ 'my_return_history', False, **kwargs)
diff --git a/website_multi_product_return_management/controllers/website_multi_product_return_management.py b/website_multi_product_return_management/controllers/website_multi_product_return_management.py
new file mode 100644
index 0000000000..156270429b
--- /dev/null
+++ b/website_multi_product_return_management/controllers/website_multi_product_return_management.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from datetime import datetime
+from odoo import http
+from odoo.http import request
+
+
+class CustomerRegistration(http.Controller):
+ @http.route('/sale_return', type='json', csrf=False, auth="public",
+ website=True)
+ def sale_return(self, **kwargs, ):
+ """Controller to create return order"""
+ if kwargs.get('vals'):
+ lines = []
+ so_id = False
+ for line in kwargs.get('vals'):
+ so_id = request.env['sale.order'].sudo().browse(int(line['order_id']))
+ qty = int(line['quantity'])
+ d_qty = int(line['deli_qty'])
+ reason = line['reason']
+ if qty > 0:
+ lines.append((0, 0, {'product_id': line['product_id'],
+ 'received_qty': qty,
+ 'quantity': d_qty,
+ 'reason': reason
+ }))
+ if so_id:
+ values = {
+ 'partner_id': so_id.partner_id.id,
+ 'sale_order_id': so_id.id,
+ 'user_id': request.env.uid,
+ 'create_date': datetime.now(),
+ 'return_line_ids': lines
+ }
+ stock_picks = request.env['stock.picking'].sudo().search(
+ [('origin', '=', so_id.name)])
+ moves = stock_picks.mapped(
+ 'move_ids_without_package').sudo().filtered(
+ lambda p: p.product_id.id == line['product_id'])
+ if moves:
+ moves = moves.sorted('product_uom_qty', reverse=True)
+ values.update({'state': 'draft'})
+ ret_order = request.env['sale.return'].sudo().create(values)
+ moves[0].picking_id.return_order_id = ret_order.id
+ moves[0].picking_id.return_order_picking = False
+ return True
+ return False
+
+ @http.route('/my/request-thank-you', website=True, page=True,
+ auth='public', csrf=False)
+ def maintenance_request_thanks(self):
+ """Controller for return the thanks page for return confirmation."""
+ return request.render(
+ 'website_multi_product_return_management.'
+ 'customers_request_thank_page')
diff --git a/website_multi_product_return_management/data/ir_sequence_data.xml b/website_multi_product_return_management/data/ir_sequence_data.xml
new file mode 100644
index 0000000000..9b8e6f1e2c
--- /dev/null
+++ b/website_multi_product_return_management/data/ir_sequence_data.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ Sale Return
+ sale.return
+ RET
+ 5
+
+
+
+
\ No newline at end of file
diff --git a/website_multi_product_return_management/doc/RELEASE_NOTES.md b/website_multi_product_return_management/doc/RELEASE_NOTES.md
new file mode 100755
index 0000000000..fcc6f4b11c
--- /dev/null
+++ b/website_multi_product_return_management/doc/RELEASE_NOTES.md
@@ -0,0 +1,7 @@
+
+## Module
+
+#### 06.05.2025
+#### Version 18.0.1.0.0
+#### ADD
+- Initial Commit for Multi Product Return From Website
diff --git a/website_multi_product_return_management/models/__init__.py b/website_multi_product_return_management/models/__init__.py
new file mode 100644
index 0000000000..362e45c2f7
--- /dev/null
+++ b/website_multi_product_return_management/models/__init__.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from . import res_partner
+from . import sale_order
+from . import sale_return
+from . import stock_picking
diff --git a/website_multi_product_return_management/models/res_partner.py b/website_multi_product_return_management/models/res_partner.py
new file mode 100644
index 0000000000..7abb0a39f1
--- /dev/null
+++ b/website_multi_product_return_management/models/res_partner.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from odoo import fields, models
+
+
+class ResPartner(models.Model):
+ """
+ Extends the base 'res.partner' model to include additional fields
+ and functionality.
+ """
+ _inherit = 'res.partner'
+
+ return_order_count = fields.Integer(
+ compute="_compute_return_order_count", string='Return Orders',
+ help="Count of order returned by the customer")
+
+ def _compute_return_order_count(self):
+ """Function to calculate the return count"""
+ all_partners = self.with_context(active_test=False).sudo().search(
+ [('id', 'child_of', self.ids)])
+ all_partners.read(['parent_id'])
+ sale_return_groups = self.env['sale.return'].sudo().read_group(
+ domain=[('partner_id', 'in', all_partners.ids)],
+ fields=['partner_id'], groupby=['partner_id'])
+ for partner in self:
+ if sale_return_groups != []:
+ partner.return_order_count = int(
+ sale_return_groups[0]['partner_id_count'])
+ else:
+ partner.return_order_count = 0
+
+ def action_open_returns(self):
+ """This function returns an action that displays the sale return
+ orders from partner."""
+ action = self.env['ir.actions.act_window']._for_xml_id(
+ 'website_multi_product_return_management.sale_return_action')
+ domain = []
+ if self.is_company:
+ domain.append(('partner_id.commercial_partner_id.id', '=', self.id))
+ else:
+ domain.append(('partner_id.id', '=', self.id))
+ action['domain'] = domain
+ action['context'] = {'search_default_customer': 1}
+ return action
diff --git a/website_multi_product_return_management/models/sale_order.py b/website_multi_product_return_management/models/sale_order.py
new file mode 100644
index 0000000000..89089414ba
--- /dev/null
+++ b/website_multi_product_return_management/models/sale_order.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from odoo import fields, models
+
+
+class SaleOrder(models.Model):
+ _inherit = 'sale.order'
+
+ return_order_count = fields.Integer(
+ compute="_compute_return_order_count", string='Return Orders',
+ help="Count of product returned on this order")
+
+ def _compute_return_order_count(self):
+ """method to compute return count"""
+ sale_return_groups = self.env['sale.return'].sudo().read_group(
+ domain=[('sale_order_id', 'in', self.ids)],
+ fields=['sale_order_id'], groupby=['sale_order_id'])
+ orders = self.sudo().browse()
+ for group in sale_return_groups:
+ sale_order = self.sudo().browse(group['sale_order_id'][0])
+ while sale_order:
+ if sale_order in self:
+ print(group)
+ sale_order.return_order_count = 0
+ sale_order.return_order_count += group['sale_order_id_count']
+ orders |= sale_order
+ sale_order = False
+ (self - orders).return_order_count = 0
+
+ def action_open_returns(self):
+ """This function returns an action that displays the sale return
+ orders from sale order"""
+ action = self.env['ir.actions.act_window']._for_xml_id(
+ 'website_multi_product_return_management.sale_return_action')
+ domain = [('sale_order_id', '=', self.id)]
+ action['domain'] = domain
+ action['context'] = {'search_default_order': 1}
+ return action
+
+class SaleOrderLine(models.Model):
+ """Extend the Sale Order line model to include a new field."""
+ _inherit = 'sale.order.line'
+
+ return_order_line_count = fields.Integer(
+ string='Return Orders', default=0,
+ help="Count of product returned in this order line")
diff --git a/website_multi_product_return_management/models/sale_return.py b/website_multi_product_return_management/models/sale_return.py
new file mode 100644
index 0000000000..819494319d
--- /dev/null
+++ b/website_multi_product_return_management/models/sale_return.py
@@ -0,0 +1,321 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from odoo import api, fields, models
+
+
+class SaleReturn(models.Model):
+ """Model for managing return orders."""
+ _name = 'sale.return'
+ _inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin']
+ _order = "name"
+ _description = "Return Order"
+
+ @api.model
+ def _get_default_name(self):
+ """Get the default name for a new return order."""
+ return self.env['ir.sequence'].get('sale.return')
+
+ active = fields.Boolean(string='Active', default=True,
+ help="Indicates if the return order is active.")
+ name = fields.Char(string="Name", default=_get_default_name,
+ help="Name of the return order.")
+ sale_order_id = fields.Many2one(
+ 'sale.order', string="Sale Order",
+ required=True,
+ help="Reference to the original sale order.")
+ partner_id = fields.Many2one(
+ 'res.partner', string="Customer",
+ help="Customer associated with the return order.")
+ user_id = fields.Many2one('res.users', string="Responsible",
+ default=lambda self: self.env.user,
+ help="User responsible for the return order.")
+ create_date = fields.Datetime(
+ string="Create Date",
+ help="Date when the return order was created.")
+ stock_picking_ids = fields.One2many(
+ 'stock.picking', 'return_order_pick_id',
+ domain="[('return_order_id','=',False)]",
+ string="Return Picking",
+ help="Shows the return picking of the corresponding return order.")
+ picking_count = fields.Integer(compute="_compute_picking_count",
+ string='Picking Order', copy=False,
+ default=0, store=True,
+ help="Count of associated picking orders.")
+ delivery_count = fields.Integer(compute="_compute_delivery",
+ string='Delivery Order', copy=False,
+ default=0, store=True,
+ help="Count of associated delivery orders.")
+ state = fields.Selection(
+ [('draft', 'Draft'), ('confirm', 'Confirm'), ('done', 'Done'),
+ ('cancel', 'Canceled')], string='Status', readonly=True,
+ default='draft', help="Current state of the return order.")
+ source_pick_ids = fields.One2many(
+ 'stock.picking', 'return_order_id',
+ string="Source Delivery",
+ domain="[('return_order_pick_id','=',False)]",
+ help="Shows the delivery orders of the corresponding return order.")
+ note = fields.Text(
+ string="Note",
+ help="Additional notes or comments for the return order.")
+
+ return_line_ids = fields.One2many(
+ 'return.order.line', 'order_id',
+ string="Return Lines",
+ help="Lines associated with the return order.")
+
+ def action_return_confirm(self):
+ """Confirm the sale return"""
+ if not self.source_pick_ids:
+ stock_picks = self.env['stock.picking'].sudo().search(
+ [('origin', '=', self.sale_order_id.name)])
+ moves = stock_picks.mapped(
+ 'move_ids_without_package').sudo().filtered(
+ lambda p: p.product_id.id in self.return_line_ids.mapped(
+ 'product_id').ids)
+ else:
+ moves = self.source_pick_ids.mapped(
+ 'move_ids_without_package').sudo().filtered(
+ lambda p: p.product_id.id in self.return_line_ids.mapped(
+ 'product_id').ids)
+
+ if moves:
+ moves = moves.sorted('product_uom_qty', reverse=True)
+ pick = moves[0].picking_id
+ vals = {'picking_id': pick.id}
+ return_pick_wizard = self.env['stock.return.picking'].sudo().create(
+ vals)
+ return_pick_wizard._compute_moves_locations()
+ return_pick_wizard.product_return_moves.unlink()
+ lines = []
+ reason = ''
+ for line in self.return_line_ids:
+ so_line_id = self.sale_order_id.order_line.filtered(
+ lambda m: m.product_template_id ==
+ line.product_id.product_tmpl_id)
+ so_line_id.return_order_line_count = line.received_qty
+ move = moves.filtered(lambda m: m.product_id == line.product_id)
+ lines.append(
+ {'product_id': line.product_id.id,
+ "quantity": line.received_qty,
+ 'move_id': move.id, 'to_refund': line.to_refund})
+ reason = reason + '\n' + line.reason
+ lines = self.env['stock.return.picking.line'].create(lines)
+ return_pick_wizard.write({
+ 'product_return_moves': [(6, 0, lines.ids)]
+ })
+ return_pick = return_pick_wizard._create_return()
+ if return_pick:
+ return_pick = self.env['stock.picking'].sudo().browse(
+ return_pick[0].id)
+ return_pick.update({'note': reason})
+ return_pick.write(
+ {'return_order_id': False, 'return_order_pick_id': self.id,
+ 'return_order_picking': True})
+ self.write({'state': 'confirm'})
+
+ def action_return_cancel(self):
+ """Cancel the return"""
+ self.write({'state': 'cancel'})
+ if self.stock_picking_ids:
+ for rec in self.stock_picking_ids.sudo().filtered(
+ lambda s: s.state not in ['done', 'cancel']):
+ rec.action_cancel()
+
+ def _get_report_base_filename(self):
+ """Get the base filename for the return order report."""
+ self.ensure_one()
+ return 'Sale Return - %s' % (self.name)
+
+ def _compute_access_url(self):
+ """Compute the access URL for the return order."""
+ super(SaleReturn, self)._compute_access_url()
+ for order in self:
+ order.access_url = '/my/return_orders/%s' % order.id
+
+ @api.depends('stock_picking_ids', 'state')
+ def _compute_delivery(self):
+ """Function to compute picking and delivery counts"""
+ for rec in self:
+ rec.delivery_count = 0
+ rec.picking_count = 0
+ if rec.source_pick_ids:
+ rec.delivery_count = len(rec.source_pick_ids)
+ else:
+ rec.delivery_count = self.env[
+ 'stock.picking'].sudo().search_count(
+ [('return_order_id', 'in', self.ids),
+ ('return_order_picking', '=', False)])
+ if rec.stock_picking_ids:
+ rec.picking_count = len(rec.stock_picking_ids)
+ else:
+ rec.picking_count = self.env[
+ 'stock.picking'].sudo().search_count(
+ [('return_order_pick_id', 'in', self.ids),
+ ('return_order_picking', '=', True)])
+
+ def action_view_picking(self):
+ """Function to view the stock picking transfers"""
+ action = self.env["ir.actions.actions"]._for_xml_id(
+ "stock.action_picking_tree_all")
+
+ pickings = self.mapped('stock_picking_ids')
+ if not self.stock_picking_ids:
+ pickings = self.env['stock.picking'].sudo().search(
+ [('return_order_pick_id', '=', self.id),
+ ('return_order_picking', '=', True)])
+ if len(pickings) > 1:
+ action['domain'] = [('id', 'in', pickings.ids)]
+ elif pickings:
+ form_view = [(self.env.ref('stock.view_picking_form').id, 'form')]
+ if 'views' in action:
+ action['views'] = form_view + [(state, view) for state, view in
+ action['views'] if
+ view != 'form']
+ else:
+ action['views'] = form_view
+ action['res_id'] = pickings.id
+ # Prepare the context.
+ picking_id = pickings.sudo().filtered(
+ lambda l: l.picking_type_id.code == 'outgoing')
+ if picking_id:
+ picking_id = picking_id[0]
+ else:
+ picking_id = pickings[0]
+ action['context'] = dict(
+ self._context,
+ default_partner_id=self.partner_id.id,
+ default_picking_type_id=picking_id.picking_type_id.id)
+ return action
+
+ def action_view_delivery(self):
+ """Function to view the delivery transfers"""
+ action = self.env["ir.actions.actions"]._for_xml_id(
+ "stock.action_picking_tree_all")
+
+ pickings = self.mapped('source_pick_ids')
+ if not self.source_pick_ids:
+ pickings = self.env['stock.picking'].sudo().search(
+ [('return_order_id', '=', self.id),
+ ('return_order_picking', '=', False)])
+ if len(pickings) > 1:
+ action['domain'] = [('id', 'in', pickings.ids)]
+ elif pickings:
+ form_view = [(self.env.ref('stock.view_picking_form').id, 'form')]
+ if 'views' in action:
+ action['views'] = form_view + [(state, view) for state, view in
+ action['views'] if
+ view != 'form']
+ else:
+ action['views'] = form_view
+ action['res_id'] = pickings.id
+ # Prepare the context.
+ picking_id = pickings.filtered(
+ lambda l: l.picking_type_id.code == 'outgoing')
+ if picking_id:
+ picking_id = picking_id[0]
+ else:
+ picking_id = pickings[0]
+ action['context'] = dict(
+ self._context,
+ default_partner_id=self.partner_id.id,
+ default_picking_type_id=picking_id.picking_type_id.id)
+ return action
+
+ @api.onchange('sale_order_id', 'source_pick_ids')
+ def onchange_sale_order_id_source_pick_ids(self):
+ """All the fields are updated according to the sale order"""
+ delivery = None
+ if self.sale_order_id:
+ self.partner_id = self.sale_order_id.partner_id
+
+ delivery = self.env['stock.picking'].sudo().search(
+ [('origin', '=', self.sale_order_id.name)])
+ if self.source_pick_ids:
+ delivery = self.source_pick_ids
+ if delivery:
+ product_ids = delivery.move_ids_without_package.mapped(
+ 'product_id').ids
+ delivery = delivery.ids
+ else:
+ product_ids = self.sale_order_id.order_line.mapped('product_id').ids
+
+ return {'domain': {'source_pick_ids': [('id', 'in', delivery)],
+ 'product_id': [('id', 'in', product_ids)]}}
+
+ @api.onchange('product_id')
+ def onchange_product_id(self):
+ """Handle changes in the product ID field. and find received quantity"""
+ if self.product_id and self.source_pick_ids:
+ moves = self.source_pick_ids.mapped(
+ 'move_ids_without_package').sudo().filtered(
+ lambda p: p.product_id == self.product_id)
+ if moves:
+ self.received_qty = sum(moves.mapped('quantity_done'))
+
+
+class ReturnOrderLine(models.Model):
+ _name = 'return.order.line'
+ _description = "Return Products Details"
+
+ order_id = fields.Many2one(
+ "sale.return", string="Order",
+ help="Reference to the associated sale return order.")
+ product_id = fields.Many2one(
+ 'product.product', string="Product Variant",
+ required=True,
+ help="Defines the product variant that needs to be returned.")
+ product_tmpl_id = fields.Many2one('product.template',
+ related="product_id.product_tmpl_id",
+ store=True, string="Product")
+ quantity = fields.Float(
+ string="Delivered Quantity", store=True,
+ help="Quantity originally delivered in the associated sale order.")
+ received_qty = fields.Float(
+ string="Received Quantity",
+ help="Quantity received for the return order.")
+ reason = fields.Text(
+ "Reason", help="Reason for returning the product.")
+ to_refund = fields.Boolean(
+ string='Update SO/PO Quantity',
+ help='Trigger a decrease of the delivered/received quantity in the'
+ ' associated Sale Order/Purchase Order.')
+ sale_order_id = fields.Many2one(
+ "sale.order", string="Sale Order",
+ related="order_id.sale_order_id",
+ help="Reference to the associated sale order.")
+
+ @api.onchange('product_id')
+ def onchange_product_id(self):
+ """ setting up domain for products as per the products in the
+ vendor price list"""
+ self.ensure_one()
+ if self._context.get('order_id'):
+ order_id = self.env['sale.order'].browse(
+ self._context.get('order_id'))
+ products = order_id.order_line.mapped('product_id').ids
+ if self.product_id:
+ qty = sum(
+ order_id.order_line.filtered(
+ lambda p: p.product_id == self.product_id).mapped(
+ 'qty_delivered'))
+ self.quantity = qty
+ return {'domain': {'product_id': [('id', 'in', products)]}}
diff --git a/website_multi_product_return_management/models/stock_picking.py b/website_multi_product_return_management/models/stock_picking.py
new file mode 100644
index 0000000000..c042bf0183
--- /dev/null
+++ b/website_multi_product_return_management/models/stock_picking.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2025-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions ()
+#
+# You can modify it under the terms of the GNU AFFERO
+# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
+#
+# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+# (AGPL v3) along with this program.
+# If not, see .
+#
+###############################################################################
+from odoo import fields, models
+
+
+class StockPicking(models.Model):
+ """Extend the stock.picking model to include return order information."""
+
+ _inherit = 'stock.picking'
+
+ return_order_id = fields.Many2one(
+ 'sale.return', string='Return Order',
+ help="Shows the return order of the current transfer.")
+ return_order_pick_id = fields.Many2one(
+ 'sale.return',
+ string='Return Order Pick',
+ help="Shows the return order picking of the current return order.")
+ return_order_picking = fields.Boolean(
+ string='Return Order Picking',
+ help="Helps to identify delivery and return picking. If true, the "
+ "transfer is a return picking; else, it's a delivery.")
+
+ def button_validate(self):
+ """Override the button_validate method to update return order state."""
+ res = super(StockPicking, self).button_validate()
+ for rec in self:
+ if rec.return_order_pick_id:
+ if any(line.state != 'done' for line in
+ rec.return_order_pick_id.stock_picking_ids):
+ return res
+ else:
+ rec.return_order_pick_id.write({'state': 'done'})
+ return res
diff --git a/website_multi_product_return_management/report/sale_return_reports.xml b/website_multi_product_return_management/report/sale_return_reports.xml
new file mode 100644
index 0000000000..03b8f18fac
--- /dev/null
+++ b/website_multi_product_return_management/report/sale_return_reports.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ Sale Return
+ sale.return
+ qweb-pdf
+ website_multi_product_return_management.report_salereturn
+ website_multi_product_return_management.report_salereturn
+ 'Sale Retun - %s' % object.name
+
+ report
+
+
diff --git a/website_multi_product_return_management/report/sale_return_templates.xml b/website_multi_product_return_management/report/sale_return_templates.xml
new file mode 100644
index 0000000000..b86a3cc9d5
--- /dev/null
+++ b/website_multi_product_return_management/report/sale_return_templates.xml
@@ -0,0 +1,89 @@
+
+
+
+
+ Sale Return
+ sale.return
+ qweb-pdf
+ website_multi_product_return_management.report_salereturn
+ website_multi_product_return_management.report_salereturn
+ 'Sale Retun - %s' % object.name
+
+ report
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Return Order #
+
+
+
+
+
+
+
+
+ Product
+
+ Quantity
+
+ Reason
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/security/ir.model.access.csv b/website_multi_product_return_management/security/ir.model.access.csv
new file mode 100644
index 0000000000..74708dbb76
--- /dev/null
+++ b/website_multi_product_return_management/security/ir.model.access.csv
@@ -0,0 +1,3 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_sale_return,access.sale.return,model_sale_return,,1,1,1,1
+access_sale_return_line,access.sale.return.line,model_return_order_line,,1,1,1,1
diff --git a/website_multi_product_return_management/static/description/assets/cybro-icon.png b/website_multi_product_return_management/static/description/assets/cybro-icon.png
new file mode 100644
index 0000000000..06e73e11de
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/cybro-icon.png differ
diff --git a/website_multi_product_return_management/static/description/assets/cybro-odoo.png b/website_multi_product_return_management/static/description/assets/cybro-odoo.png
new file mode 100644
index 0000000000..ed02e07a48
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/cybro-odoo.png differ
diff --git a/website_multi_product_return_management/static/description/assets/h2.png b/website_multi_product_return_management/static/description/assets/h2.png
new file mode 100644
index 0000000000..0bfc4707d8
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/h2.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/arrows-repeat.svg b/website_multi_product_return_management/static/description/assets/icons/arrows-repeat.svg
new file mode 100644
index 0000000000..1d7efabc52
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/arrows-repeat.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/banner-1.png b/website_multi_product_return_management/static/description/assets/icons/banner-1.png
new file mode 100644
index 0000000000..c180db1729
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/banner-1.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/banner-2.svg b/website_multi_product_return_management/static/description/assets/icons/banner-2.svg
new file mode 100644
index 0000000000..e606d97d98
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/banner-2.svg
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/banner-bg.png b/website_multi_product_return_management/static/description/assets/icons/banner-bg.png
new file mode 100644
index 0000000000..a8238d3c09
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/banner-bg.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/banner-bg.svg b/website_multi_product_return_management/static/description/assets/icons/banner-bg.svg
new file mode 100644
index 0000000000..b1378103e2
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/banner-bg.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/banner-call.svg b/website_multi_product_return_management/static/description/assets/icons/banner-call.svg
new file mode 100644
index 0000000000..96c687e81f
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/banner-call.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/banner-mail.svg b/website_multi_product_return_management/static/description/assets/icons/banner-mail.svg
new file mode 100644
index 0000000000..cbf0d158d2
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/banner-mail.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/banner-pattern.svg b/website_multi_product_return_management/static/description/assets/icons/banner-pattern.svg
new file mode 100644
index 0000000000..9c1c7e101c
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/banner-pattern.svg
@@ -0,0 +1,343 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/banner-promo.svg b/website_multi_product_return_management/static/description/assets/icons/banner-promo.svg
new file mode 100644
index 0000000000..d52791b11e
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/banner-promo.svg
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/brand-pair.svg b/website_multi_product_return_management/static/description/assets/icons/brand-pair.svg
new file mode 100644
index 0000000000..d8db7fc1e7
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/brand-pair.svg
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/check.png b/website_multi_product_return_management/static/description/assets/icons/check.png
new file mode 100644
index 0000000000..c8e85f51d6
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/check.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/chevron.png b/website_multi_product_return_management/static/description/assets/icons/chevron.png
new file mode 100644
index 0000000000..2089293d6a
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/chevron.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/close-icon.svg b/website_multi_product_return_management/static/description/assets/icons/close-icon.svg
new file mode 100644
index 0000000000..df8cce37a5
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/close-icon.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/cogs.png b/website_multi_product_return_management/static/description/assets/icons/cogs.png
new file mode 100644
index 0000000000..95d0bad62c
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/cogs.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/collabarate-icon.svg b/website_multi_product_return_management/static/description/assets/icons/collabarate-icon.svg
new file mode 100644
index 0000000000..dd4e105183
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/collabarate-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/consultation.png b/website_multi_product_return_management/static/description/assets/icons/consultation.png
new file mode 100644
index 0000000000..8319d4baa0
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/consultation.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/cybro-logo.png b/website_multi_product_return_management/static/description/assets/icons/cybro-logo.png
new file mode 100644
index 0000000000..ff4b782205
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/cybro-logo.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/down.svg b/website_multi_product_return_management/static/description/assets/icons/down.svg
new file mode 100644
index 0000000000..f21c36271b
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/down.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/website_multi_product_return_management/static/description/assets/icons/ecom-black.png b/website_multi_product_return_management/static/description/assets/icons/ecom-black.png
new file mode 100644
index 0000000000..a9385ff13f
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/ecom-black.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/education-black.png b/website_multi_product_return_management/static/description/assets/icons/education-black.png
new file mode 100644
index 0000000000..3eb09b27b4
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/education-black.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/faq.png b/website_multi_product_return_management/static/description/assets/icons/faq.png
new file mode 100644
index 0000000000..4250b5b817
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/faq.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/feature-icon.svg b/website_multi_product_return_management/static/description/assets/icons/feature-icon.svg
new file mode 100644
index 0000000000..fa0ea6850a
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/feature-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/feature.png b/website_multi_product_return_management/static/description/assets/icons/feature.png
new file mode 100644
index 0000000000..ac7a785c09
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/feature.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/gear.svg b/website_multi_product_return_management/static/description/assets/icons/gear.svg
new file mode 100644
index 0000000000..0cc66b6ea7
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/gear.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/hero.gif b/website_multi_product_return_management/static/description/assets/icons/hero.gif
new file mode 100644
index 0000000000..6e6ee776b5
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/hero.gif differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/hire-odoo.svg b/website_multi_product_return_management/static/description/assets/icons/hire-odoo.svg
new file mode 100644
index 0000000000..e1ac089b04
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/hire-odoo.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/hotel-black.png b/website_multi_product_return_management/static/description/assets/icons/hotel-black.png
new file mode 100644
index 0000000000..130f613be0
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/hotel-black.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/license.png b/website_multi_product_return_management/static/description/assets/icons/license.png
new file mode 100644
index 0000000000..a5869797ec
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/license.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/life-ring-icon.svg b/website_multi_product_return_management/static/description/assets/icons/life-ring-icon.svg
new file mode 100644
index 0000000000..3ae6e1d896
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/life-ring-icon.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/lifebuoy.png b/website_multi_product_return_management/static/description/assets/icons/lifebuoy.png
new file mode 100644
index 0000000000..658d56cccf
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/lifebuoy.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/mail.svg b/website_multi_product_return_management/static/description/assets/icons/mail.svg
new file mode 100644
index 0000000000..1eedde695b
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/mail.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/manufacturing-black.png b/website_multi_product_return_management/static/description/assets/icons/manufacturing-black.png
new file mode 100644
index 0000000000..697eb0e9f2
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/manufacturing-black.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/notes.png b/website_multi_product_return_management/static/description/assets/icons/notes.png
new file mode 100644
index 0000000000..ee5e954047
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/notes.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/notification icon.svg b/website_multi_product_return_management/static/description/assets/icons/notification icon.svg
new file mode 100644
index 0000000000..0531899736
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/notification icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/odoo-consultancy.svg b/website_multi_product_return_management/static/description/assets/icons/odoo-consultancy.svg
new file mode 100644
index 0000000000..e05f65bde4
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/odoo-consultancy.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/odoo-licencing.svg b/website_multi_product_return_management/static/description/assets/icons/odoo-licencing.svg
new file mode 100644
index 0000000000..2606c88b04
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/odoo-licencing.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/odoo-logo.png b/website_multi_product_return_management/static/description/assets/icons/odoo-logo.png
new file mode 100644
index 0000000000..0e4d0eb5a4
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/odoo-logo.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/patter.svg b/website_multi_product_return_management/static/description/assets/icons/patter.svg
new file mode 100644
index 0000000000..25c9c0a8f1
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/patter.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/pattern1.png b/website_multi_product_return_management/static/description/assets/icons/pattern1.png
new file mode 100644
index 0000000000..09ab0fb2d9
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/pattern1.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/pos-black.png b/website_multi_product_return_management/static/description/assets/icons/pos-black.png
new file mode 100644
index 0000000000..97c0f90c10
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/pos-black.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/puzzle-piece-icon.svg b/website_multi_product_return_management/static/description/assets/icons/puzzle-piece-icon.svg
new file mode 100644
index 0000000000..3e9ad93738
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/puzzle-piece-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/puzzle.png b/website_multi_product_return_management/static/description/assets/icons/puzzle.png
new file mode 100644
index 0000000000..65cf854e7e
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/puzzle.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/replace-icon.svg b/website_multi_product_return_management/static/description/assets/icons/replace-icon.svg
new file mode 100644
index 0000000000..d0e3a7af1a
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/replace-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/restaurant-black.png b/website_multi_product_return_management/static/description/assets/icons/restaurant-black.png
new file mode 100644
index 0000000000..4a35eb939c
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/restaurant-black.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/screenshot-main.png b/website_multi_product_return_management/static/description/assets/icons/screenshot-main.png
new file mode 100644
index 0000000000..575f8e676b
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/screenshot-main.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/screenshot.png b/website_multi_product_return_management/static/description/assets/icons/screenshot.png
new file mode 100644
index 0000000000..cef272529d
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/screenshot.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/service-black.png b/website_multi_product_return_management/static/description/assets/icons/service-black.png
new file mode 100644
index 0000000000..301ab51cb1
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/service-black.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/skype-fill.svg b/website_multi_product_return_management/static/description/assets/icons/skype-fill.svg
new file mode 100644
index 0000000000..c174236393
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/skype-fill.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/skype.png b/website_multi_product_return_management/static/description/assets/icons/skype.png
new file mode 100644
index 0000000000..51b409fb3f
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/skype.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/skype.svg b/website_multi_product_return_management/static/description/assets/icons/skype.svg
new file mode 100644
index 0000000000..df3dad39b5
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/skype.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/star-1.svg b/website_multi_product_return_management/static/description/assets/icons/star-1.svg
new file mode 100644
index 0000000000..7e55ab162e
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/star-1.svg
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/star-2.svg b/website_multi_product_return_management/static/description/assets/icons/star-2.svg
new file mode 100644
index 0000000000..5ae9f507a1
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/star-2.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/support.png b/website_multi_product_return_management/static/description/assets/icons/support.png
new file mode 100644
index 0000000000..4f18b8b820
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/support.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/test-1 - Copy.png b/website_multi_product_return_management/static/description/assets/icons/test-1 - Copy.png
new file mode 100644
index 0000000000..f6a9026637
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/test-1 - Copy.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/test-1.png b/website_multi_product_return_management/static/description/assets/icons/test-1.png
new file mode 100644
index 0000000000..0908add2b0
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/test-1.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/test-2.png b/website_multi_product_return_management/static/description/assets/icons/test-2.png
new file mode 100644
index 0000000000..4671fe91e9
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/test-2.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/trading-black.png b/website_multi_product_return_management/static/description/assets/icons/trading-black.png
new file mode 100644
index 0000000000..9398ba2f1a
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/trading-black.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/training.png b/website_multi_product_return_management/static/description/assets/icons/training.png
new file mode 100644
index 0000000000..884ca024d7
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/training.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/translate.svg b/website_multi_product_return_management/static/description/assets/icons/translate.svg
new file mode 100644
index 0000000000..af9c8a1aa8
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/translate.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/update.png b/website_multi_product_return_management/static/description/assets/icons/update.png
new file mode 100644
index 0000000000..ecbc5a01a2
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/update.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/user.png b/website_multi_product_return_management/static/description/assets/icons/user.png
new file mode 100644
index 0000000000..6ffb23d9f0
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/user.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/video.png b/website_multi_product_return_management/static/description/assets/icons/video.png
new file mode 100644
index 0000000000..576705b172
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/video.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/whatsapp.png b/website_multi_product_return_management/static/description/assets/icons/whatsapp.png
new file mode 100644
index 0000000000..d513a5356b
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/whatsapp.png differ
diff --git a/website_multi_product_return_management/static/description/assets/icons/wrench-icon.svg b/website_multi_product_return_management/static/description/assets/icons/wrench-icon.svg
new file mode 100644
index 0000000000..174b5a465e
--- /dev/null
+++ b/website_multi_product_return_management/static/description/assets/icons/wrench-icon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/website_multi_product_return_management/static/description/assets/icons/wrench.png b/website_multi_product_return_management/static/description/assets/icons/wrench.png
new file mode 100644
index 0000000000..6c04dea0f4
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/icons/wrench.png differ
diff --git a/website_multi_product_return_management/static/description/assets/modules/cw_sale.png b/website_multi_product_return_management/static/description/assets/modules/cw_sale.png
new file mode 100644
index 0000000000..1b75c62d59
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/modules/cw_sale.png differ
diff --git a/website_multi_product_return_management/static/description/assets/modules/cw_stock.png b/website_multi_product_return_management/static/description/assets/modules/cw_stock.png
new file mode 100644
index 0000000000..62af09ec6e
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/modules/cw_stock.png differ
diff --git a/website_multi_product_return_management/static/description/assets/modules/delivery_split.jpg b/website_multi_product_return_management/static/description/assets/modules/delivery_split.jpg
new file mode 100644
index 0000000000..76724ebdaa
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/modules/delivery_split.jpg differ
diff --git a/website_multi_product_return_management/static/description/assets/modules/legal_case_management.jpg b/website_multi_product_return_management/static/description/assets/modules/legal_case_management.jpg
new file mode 100644
index 0000000000..9ed781988f
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/modules/legal_case_management.jpg differ
diff --git a/website_multi_product_return_management/static/description/assets/modules/purchase_history_of_product.jpg b/website_multi_product_return_management/static/description/assets/modules/purchase_history_of_product.jpg
new file mode 100644
index 0000000000..dab7b184c4
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/modules/purchase_history_of_product.jpg differ
diff --git a/website_multi_product_return_management/static/description/assets/modules/user_login_alert.png b/website_multi_product_return_management/static/description/assets/modules/user_login_alert.png
new file mode 100644
index 0000000000..e0b09a5a0b
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/modules/user_login_alert.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_01.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_01.png
new file mode 100644
index 0000000000..87951f543e
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_01.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_02.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_02.png
new file mode 100644
index 0000000000..33bcbd40a3
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_02.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_03.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_03.png
new file mode 100644
index 0000000000..d6f0ac69f3
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_03.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_04.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_04.png
new file mode 100644
index 0000000000..a1527e834f
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_04.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_05.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_05.png
new file mode 100644
index 0000000000..864e86a1f2
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_05.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_06.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_06.png
new file mode 100644
index 0000000000..b5d549b64e
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_06.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_07.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_07.png
new file mode 100644
index 0000000000..49acb68649
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_07.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_08.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_08.png
new file mode 100644
index 0000000000..7c1628c367
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_08.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_09.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_09.png
new file mode 100644
index 0000000000..d5a59d408e
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_09.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_10.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_10.png
new file mode 100644
index 0000000000..f79d65ee8e
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_10.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_11.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_11.png
new file mode 100644
index 0000000000..6c037b7a4a
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_11.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_12.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_12.png
new file mode 100644
index 0000000000..7c9956adde
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_12.png differ
diff --git a/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_13.png b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_13.png
new file mode 100644
index 0000000000..bb5ac74b43
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/screenshots/multi_product_return_13.png differ
diff --git a/website_multi_product_return_management/static/description/assets/y18.jpg b/website_multi_product_return_management/static/description/assets/y18.jpg
new file mode 100644
index 0000000000..eea1714f25
Binary files /dev/null and b/website_multi_product_return_management/static/description/assets/y18.jpg differ
diff --git a/website_multi_product_return_management/static/description/banner.jpg b/website_multi_product_return_management/static/description/banner.jpg
new file mode 100644
index 0000000000..7f2cc2ab50
Binary files /dev/null and b/website_multi_product_return_management/static/description/banner.jpg differ
diff --git a/website_multi_product_return_management/static/description/icon.png b/website_multi_product_return_management/static/description/icon.png
new file mode 100644
index 0000000000..cfa2bfa90c
Binary files /dev/null and b/website_multi_product_return_management/static/description/icon.png differ
diff --git a/website_multi_product_return_management/static/description/index.html b/website_multi_product_return_management/static/description/index.html
new file mode 100644
index 0000000000..f11d198075
--- /dev/null
+++ b/website_multi_product_return_management/static/description/index.html
@@ -0,0 +1,1373 @@
+
+
+
+
+
+ Multi Product Return From Website
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Community
+
+
+ Enterprise
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This Module Manage Sale Order Return From Website.
+
+
Multi Product Return From Website
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+