Compare commits
19 Commits
bharath-ho
...
09bfb957e6
| Author | SHA1 | Date | |
|---|---|---|---|
| 09bfb957e6 | |||
| 2fe7c0df76 | |||
| dd565e349a | |||
| 09082a12a5 | |||
| 1286045a21 | |||
| 23d9108436 | |||
| ddbf352b33 | |||
| 635bd4e7ba | |||
| 0560b86b87 | |||
| 205924e057 | |||
| 2bc01b5952 | |||
| ba34c80761 | |||
| f412b9f71e | |||
| 1e6653de96 | |||
| 10d73b6d31 | |||
| d56e710e28 | |||
| c4722a6c99 | |||
| 86207fee86 | |||
| 8c85a11698 |
@@ -1,6 +1,19 @@
|
||||
import type { NextConfig } from "next";
|
||||
import path from "path";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
async redirects() {
|
||||
return [
|
||||
{
|
||||
source: "/air-freight",
|
||||
destination: "/doormile-wings",
|
||||
permanent: true,
|
||||
},
|
||||
];
|
||||
},
|
||||
turbopack: {
|
||||
root: path.resolve(__dirname),
|
||||
},
|
||||
output: "export",
|
||||
// Required by the How It Works 3D experience. React StrictMode double-invokes
|
||||
// mount/effects in dev, which tears down and re-creates the WebGL context of
|
||||
|
||||
21
package-lock.json
generated
@@ -18,6 +18,7 @@
|
||||
"lenis": "^1.3.23",
|
||||
"maath": "^0.10.8",
|
||||
"next": "16.2.6",
|
||||
"nodemailer": "^9.0.0",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4",
|
||||
"react-leaflet": "^5.0.0",
|
||||
@@ -31,6 +32,7 @@
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/leaflet": "^1.9.21",
|
||||
"@types/node": "^20",
|
||||
"@types/nodemailer": "^8.0.1",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@types/three": "^0.184.0",
|
||||
@@ -3045,6 +3047,16 @@
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/nodemailer": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-8.0.1.tgz",
|
||||
"integrity": "sha512-PxpaInm8V1JQDd4j0ds5HfvWQk8JupS1C0Picb96QJsrrRDjBH+DlK7L4ZdNSqNULhiZRQHc40nLVShaGxXAMw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/offscreencanvas": {
|
||||
"version": "2019.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz",
|
||||
@@ -9018,6 +9030,15 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-9.0.0.tgz",
|
||||
"integrity": "sha512-tbPTid7d/p9jAA8CRZ3iomvrMaST0o6NYuY7v6JQZHpPRZ61mLFSPKYd7342NtOFuej9/+L48SOIxwfu2uDvtw==",
|
||||
"license": "MIT-0",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"lenis": "^1.3.23",
|
||||
"maath": "^0.10.8",
|
||||
"next": "16.2.6",
|
||||
"nodemailer": "^9.0.0",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4",
|
||||
"react-leaflet": "^5.0.0",
|
||||
@@ -36,6 +37,7 @@
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/leaflet": "^1.9.21",
|
||||
"@types/node": "^20",
|
||||
"@types/nodemailer": "^8.0.1",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@types/three": "^0.184.0",
|
||||
|
||||
@@ -507,7 +507,7 @@ body:not(.rtl) .elementor-element.elementor-element-13a7637 {
|
||||
}
|
||||
|
||||
.elementor-element.elementor-element-7da6646:not(.elementor-motion-effects-element-type-background) {
|
||||
background-image: url("/images/home4-banner-4.jpg");
|
||||
background-image: url("/images/bg-header-women.webp");
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@@ -5776,12 +5776,12 @@ body:not(.block-editor-page) .content-wrapper .widget p {
|
||||
@media (max-width: 1024px) {
|
||||
.elementor-element.elementor-element-99768ba .elementor-widget-container img.wp-image-4481 {
|
||||
width: 100% !important;
|
||||
max-width: 450px !important;
|
||||
max-width: 600px !important;
|
||||
/* Prevent oversized/zoomed appearance on tablets */
|
||||
height: auto !important;
|
||||
aspect-ratio: auto !important;
|
||||
/* Maintain original proportions */
|
||||
object-fit: contain !important;
|
||||
object-fit: cover !important;
|
||||
/* Ensure no cropping of important content */
|
||||
margin: 0 auto !important;
|
||||
/* Centering */
|
||||
@@ -5799,10 +5799,10 @@ body:not(.block-editor-page) .content-wrapper .widget p {
|
||||
/* Specific scaling for small mobile phones */
|
||||
@media (max-width: 767px) {
|
||||
.elementor-element.elementor-element-99768ba .elementor-widget-container img.wp-image-4481 {
|
||||
max-width: 90% !important;
|
||||
max-width: 100% !important;
|
||||
/* Reduce scale on small screens */
|
||||
margin: 0 auto !important;
|
||||
border-radius: 18px !important;
|
||||
border-radius: 25px !important;
|
||||
/* Consistent rounded edges */
|
||||
}
|
||||
}
|
||||
@@ -8650,7 +8650,7 @@ h1:where(.wp-block-heading).has-background,
|
||||
}
|
||||
|
||||
.elementor .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-3264830 {
|
||||
background-image: url("/images/home2-slide-1.jpg");
|
||||
background-image: url("/images/home2-slide-1.webp");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@@ -8710,7 +8710,7 @@ h1:where(.wp-block-heading).has-background,
|
||||
}
|
||||
|
||||
.elementor .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-6867061 {
|
||||
background-image: url("/images/home2-slide-2.jpg");
|
||||
background-image: url("/images/home2-slide-2.webp");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@@ -8833,7 +8833,7 @@ h1:where(.wp-block-heading).has-background,
|
||||
}
|
||||
|
||||
.elementor .elementor-element.elementor-element-ca6bc63:not(.elementor-motion-effects-element-type-background) {
|
||||
background-image: linear-gradient(to right, #00000080, #00000010), url("/images/home2-banner-1.jpg");
|
||||
background-image: linear-gradient(to right, #00000080, #00000010), url("/images/home2-banner-1.webp");
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@@ -8952,7 +8952,7 @@ h1:where(.wp-block-heading).has-background,
|
||||
}
|
||||
|
||||
.elementor .elementor-element.elementor-element-f003242:not(.elementor-motion-effects-element-type-background) {
|
||||
background-image: url("/images/home2-banner-3.jpg");
|
||||
background-image: url("/images/home2-banner-3.webp");
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@@ -10216,7 +10216,7 @@ h1:where(.wp-block-heading).has-background,
|
||||
}
|
||||
|
||||
#side-panel-2f31137:before {
|
||||
background-image: url("/images/bg-slide-sidebar.jpg");
|
||||
background-image: url("/images/bg-slide-sidebar.webp");
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@@ -11406,7 +11406,7 @@ h1:where(.wp-block-heading).has-background,
|
||||
}
|
||||
|
||||
.elementor-61 .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-3264830 {
|
||||
background-image: url("/images/home2-slide-1.jpg");
|
||||
background-image: url("/images/home2-slide-1.webp");
|
||||
background-position: bottom center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@@ -11458,7 +11458,7 @@ h1:where(.wp-block-heading).has-background,
|
||||
}
|
||||
|
||||
.elementor-61 .elementor-element.elementor-element-6c7cbcb .elementor-repeater-item-6867061 {
|
||||
background-image: url("/images/home2-slide-2.jpg");
|
||||
background-image: url("/images/home2-slide-2.webp");
|
||||
background-position: bottom center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@@ -11569,7 +11569,7 @@ h1:where(.wp-block-heading).has-background,
|
||||
}
|
||||
|
||||
.elementor-61 .elementor-element.elementor-element-ca6bc63:not(.elementor-motion-effects-element-type-background) {
|
||||
background-image: url("/images/home2-banner-1.jpg");
|
||||
background-image: url("/images/home2-banner-1.webp");
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@@ -11684,7 +11684,7 @@ h1:where(.wp-block-heading).has-background,
|
||||
}
|
||||
|
||||
.elementor-61 .elementor-element.elementor-element-f003242:not(.elementor-motion-effects-element-type-background) {
|
||||
background-image: url("/images/home2-banner-3.jpg");
|
||||
background-image: url("/images/home2-banner-3.webp");
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@@ -14856,7 +14856,7 @@ img:is([sizes=auto i]) {
|
||||
}
|
||||
|
||||
.elementor-element.elementor-element-7da6646:not(.elementor-motion-effects-element-type-background) {
|
||||
background-image: url("/images/bg-header-5.png");
|
||||
background-image: url("/images/bg-header-5.webp");
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
@@ -18143,14 +18143,97 @@ img:is([sizes=auto i]){contain-intrinsic-size:3000px 1500px}
|
||||
/* STYLE BLOCK 50 */
|
||||
.howits-hero-custom-bg.elementor-repeater-item-3264830,
|
||||
.howits-hero-custom-bg.elementor-repeater-item-6867061 {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-1.png') !important;
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-1.webp') !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: cover !important;
|
||||
}
|
||||
.howits-hero-custom-bg.elementor-repeater-item-6867061 {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-2.png') !important;
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-2.webp') !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: cover !important;
|
||||
}
|
||||
|
||||
/* STYLE BLOCK 51: unified mobile gutters for card/content sections */
|
||||
@media (max-width: 767px) {
|
||||
:root { --dm-mobile-gutter: 10px; }
|
||||
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-89a0ca1,
|
||||
.elementor.elementor-86 .elementor-element.elementor-element-c2c601a,
|
||||
.elementor.elementor-104 .elementor-element.elementor-element-c70681e {
|
||||
--padding-left: var(--dm-mobile-gutter) !important;
|
||||
--padding-right: var(--dm-mobile-gutter) !important;
|
||||
padding-left: var(--dm-mobile-gutter) !important;
|
||||
padding-right: var(--dm-mobile-gutter) !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-3b4a7cc {
|
||||
--padding-left: 0px !important;
|
||||
--padding-right: 0px !important;
|
||||
padding-left: 0px !important;
|
||||
padding-right: 0px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-89a0ca1 > .e-con-inner,
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-3b4a7cc > .e-con-inner,
|
||||
.elementor.elementor-86 .elementor-element.elementor-element-c2c601a > .e-con-inner,
|
||||
.elementor.elementor-104 .elementor-element.elementor-element-c70681e > .e-con-inner {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-89a0ca1 > .e-con-inner > .e-con,
|
||||
.elementor.elementor-86 .elementor-element.elementor-element-c2c601a > .e-con-inner > .e-con,
|
||||
.elementor.elementor-104 .elementor-element.elementor-element-c70681e > .e-con-inner > .e-con {
|
||||
--padding-left: 0px !important;
|
||||
--padding-right: 0px !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-6829276 {
|
||||
--e-con-grid-template-columns: minmax(0, 1fr) !important;
|
||||
--grid-justify-content: stretch !important;
|
||||
--justify-items: stretch !important;
|
||||
grid-template-columns: minmax(0, 1fr) !important;
|
||||
justify-content: stretch !important;
|
||||
justify-items: stretch !important;
|
||||
min-width: 0 !important;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .industry-solutions-grid,
|
||||
.elementor.elementor-61 .industry-card-link {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 0 !important;
|
||||
}
|
||||
|
||||
.comparison-section .container {
|
||||
width: calc(100% - (var(--dm-mobile-gutter) * 2)) !important;
|
||||
max-width: calc(100% - (var(--dm-mobile-gutter) * 2)) !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.wcd-inner {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
}
|
||||
|
||||
33
public/draco/draco_decoder.js
Normal file
BIN
public/draco/draco_decoder.wasm
Normal file
116
public/draco/draco_wasm_wrapper.js
Normal file
@@ -0,0 +1,116 @@
|
||||
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(h){var n=0;return function(){return n<h.length?{done:!1,value:h[n++]}:{done:!0}}};$jscomp.arrayIterator=function(h){return{next:$jscomp.arrayIteratorImpl(h)}};$jscomp.makeIterator=function(h){var n="undefined"!=typeof Symbol&&Symbol.iterator&&h[Symbol.iterator];return n?n.call(h):$jscomp.arrayIterator(h)};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;
|
||||
$jscomp.ISOLATE_POLYFILLS=!1;$jscomp.FORCE_POLYFILL_PROMISE=!1;$jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION=!1;$jscomp.getGlobal=function(h){h=["object"==typeof globalThis&&globalThis,h,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var n=0;n<h.length;++n){var k=h[n];if(k&&k.Math==Math)return k}throw Error("Cannot find global object");};$jscomp.global=$jscomp.getGlobal(this);
|
||||
$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(h,n,k){if(h==Array.prototype||h==Object.prototype)return h;h[n]=k.value;return h};$jscomp.IS_SYMBOL_NATIVE="function"===typeof Symbol&&"symbol"===typeof Symbol("x");$jscomp.TRUST_ES6_POLYFILLS=!$jscomp.ISOLATE_POLYFILLS||$jscomp.IS_SYMBOL_NATIVE;$jscomp.polyfills={};$jscomp.propertyToPolyfillSymbol={};$jscomp.POLYFILL_PREFIX="$jscp$";
|
||||
var $jscomp$lookupPolyfilledValue=function(h,n){var k=$jscomp.propertyToPolyfillSymbol[n];if(null==k)return h[n];k=h[k];return void 0!==k?k:h[n]};$jscomp.polyfill=function(h,n,k,p){n&&($jscomp.ISOLATE_POLYFILLS?$jscomp.polyfillIsolated(h,n,k,p):$jscomp.polyfillUnisolated(h,n,k,p))};
|
||||
$jscomp.polyfillUnisolated=function(h,n,k,p){k=$jscomp.global;h=h.split(".");for(p=0;p<h.length-1;p++){var l=h[p];if(!(l in k))return;k=k[l]}h=h[h.length-1];p=k[h];n=n(p);n!=p&&null!=n&&$jscomp.defineProperty(k,h,{configurable:!0,writable:!0,value:n})};
|
||||
$jscomp.polyfillIsolated=function(h,n,k,p){var l=h.split(".");h=1===l.length;p=l[0];p=!h&&p in $jscomp.polyfills?$jscomp.polyfills:$jscomp.global;for(var y=0;y<l.length-1;y++){var f=l[y];if(!(f in p))return;p=p[f]}l=l[l.length-1];k=$jscomp.IS_SYMBOL_NATIVE&&"es6"===k?p[l]:null;n=n(k);null!=n&&(h?$jscomp.defineProperty($jscomp.polyfills,l,{configurable:!0,writable:!0,value:n}):n!==k&&(void 0===$jscomp.propertyToPolyfillSymbol[l]&&(k=1E9*Math.random()>>>0,$jscomp.propertyToPolyfillSymbol[l]=$jscomp.IS_SYMBOL_NATIVE?
|
||||
$jscomp.global.Symbol(l):$jscomp.POLYFILL_PREFIX+k+"$"+l),$jscomp.defineProperty(p,$jscomp.propertyToPolyfillSymbol[l],{configurable:!0,writable:!0,value:n})))};
|
||||
$jscomp.polyfill("Promise",function(h){function n(){this.batch_=null}function k(f){return f instanceof l?f:new l(function(q,u){q(f)})}if(h&&(!($jscomp.FORCE_POLYFILL_PROMISE||$jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION&&"undefined"===typeof $jscomp.global.PromiseRejectionEvent)||!$jscomp.global.Promise||-1===$jscomp.global.Promise.toString().indexOf("[native code]")))return h;n.prototype.asyncExecute=function(f){if(null==this.batch_){this.batch_=[];var q=this;this.asyncExecuteFunction(function(){q.executeBatch_()})}this.batch_.push(f)};
|
||||
var p=$jscomp.global.setTimeout;n.prototype.asyncExecuteFunction=function(f){p(f,0)};n.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var f=this.batch_;this.batch_=[];for(var q=0;q<f.length;++q){var u=f[q];f[q]=null;try{u()}catch(A){this.asyncThrow_(A)}}}this.batch_=null};n.prototype.asyncThrow_=function(f){this.asyncExecuteFunction(function(){throw f;})};var l=function(f){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];this.isRejectionHandled_=!1;var q=this.createResolveAndReject_();
|
||||
try{f(q.resolve,q.reject)}catch(u){q.reject(u)}};l.prototype.createResolveAndReject_=function(){function f(A){return function(F){u||(u=!0,A.call(q,F))}}var q=this,u=!1;return{resolve:f(this.resolveTo_),reject:f(this.reject_)}};l.prototype.resolveTo_=function(f){if(f===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(f instanceof l)this.settleSameAsPromise_(f);else{a:switch(typeof f){case "object":var q=null!=f;break a;case "function":q=!0;break a;default:q=!1}q?this.resolveToNonPromiseObj_(f):
|
||||
this.fulfill_(f)}};l.prototype.resolveToNonPromiseObj_=function(f){var q=void 0;try{q=f.then}catch(u){this.reject_(u);return}"function"==typeof q?this.settleSameAsThenable_(q,f):this.fulfill_(f)};l.prototype.reject_=function(f){this.settle_(2,f)};l.prototype.fulfill_=function(f){this.settle_(1,f)};l.prototype.settle_=function(f,q){if(0!=this.state_)throw Error("Cannot settle("+f+", "+q+"): Promise already settled in state"+this.state_);this.state_=f;this.result_=q;2===this.state_&&this.scheduleUnhandledRejectionCheck_();
|
||||
this.executeOnSettledCallbacks_()};l.prototype.scheduleUnhandledRejectionCheck_=function(){var f=this;p(function(){if(f.notifyUnhandledRejection_()){var q=$jscomp.global.console;"undefined"!==typeof q&&q.error(f.result_)}},1)};l.prototype.notifyUnhandledRejection_=function(){if(this.isRejectionHandled_)return!1;var f=$jscomp.global.CustomEvent,q=$jscomp.global.Event,u=$jscomp.global.dispatchEvent;if("undefined"===typeof u)return!0;"function"===typeof f?f=new f("unhandledrejection",{cancelable:!0}):
|
||||
"function"===typeof q?f=new q("unhandledrejection",{cancelable:!0}):(f=$jscomp.global.document.createEvent("CustomEvent"),f.initCustomEvent("unhandledrejection",!1,!0,f));f.promise=this;f.reason=this.result_;return u(f)};l.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var f=0;f<this.onSettledCallbacks_.length;++f)y.asyncExecute(this.onSettledCallbacks_[f]);this.onSettledCallbacks_=null}};var y=new n;l.prototype.settleSameAsPromise_=function(f){var q=this.createResolveAndReject_();
|
||||
f.callWhenSettled_(q.resolve,q.reject)};l.prototype.settleSameAsThenable_=function(f,q){var u=this.createResolveAndReject_();try{f.call(q,u.resolve,u.reject)}catch(A){u.reject(A)}};l.prototype.then=function(f,q){function u(w,B){return"function"==typeof w?function(R){try{A(w(R))}catch(Z){F(Z)}}:B}var A,F,v=new l(function(w,B){A=w;F=B});this.callWhenSettled_(u(f,A),u(q,F));return v};l.prototype.catch=function(f){return this.then(void 0,f)};l.prototype.callWhenSettled_=function(f,q){function u(){switch(A.state_){case 1:f(A.result_);
|
||||
break;case 2:q(A.result_);break;default:throw Error("Unexpected state: "+A.state_);}}var A=this;null==this.onSettledCallbacks_?y.asyncExecute(u):this.onSettledCallbacks_.push(u);this.isRejectionHandled_=!0};l.resolve=k;l.reject=function(f){return new l(function(q,u){u(f)})};l.race=function(f){return new l(function(q,u){for(var A=$jscomp.makeIterator(f),F=A.next();!F.done;F=A.next())k(F.value).callWhenSettled_(q,u)})};l.all=function(f){var q=$jscomp.makeIterator(f),u=q.next();return u.done?k([]):new l(function(A,
|
||||
F){function v(R){return function(Z){w[R]=Z;B--;0==B&&A(w)}}var w=[],B=0;do w.push(void 0),B++,k(u.value).callWhenSettled_(v(w.length-1),F),u=q.next();while(!u.done)})};return l},"es6","es3");$jscomp.owns=function(h,n){return Object.prototype.hasOwnProperty.call(h,n)};$jscomp.assign=$jscomp.TRUST_ES6_POLYFILLS&&"function"==typeof Object.assign?Object.assign:function(h,n){for(var k=1;k<arguments.length;k++){var p=arguments[k];if(p)for(var l in p)$jscomp.owns(p,l)&&(h[l]=p[l])}return h};
|
||||
$jscomp.polyfill("Object.assign",function(h){return h||$jscomp.assign},"es6","es3");$jscomp.checkStringArgs=function(h,n,k){if(null==h)throw new TypeError("The 'this' value for String.prototype."+k+" must not be null or undefined");if(n instanceof RegExp)throw new TypeError("First argument to String.prototype."+k+" must not be a regular expression");return h+""};
|
||||
$jscomp.polyfill("String.prototype.startsWith",function(h){return h?h:function(n,k){var p=$jscomp.checkStringArgs(this,n,"startsWith");n+="";var l=p.length,y=n.length;k=Math.max(0,Math.min(k|0,p.length));for(var f=0;f<y&&k<l;)if(p[k++]!=n[f++])return!1;return f>=y}},"es6","es3");
|
||||
$jscomp.polyfill("Array.prototype.copyWithin",function(h){function n(k){k=Number(k);return Infinity===k||-Infinity===k?k:k|0}return h?h:function(k,p,l){var y=this.length;k=n(k);p=n(p);l=void 0===l?y:n(l);k=0>k?Math.max(y+k,0):Math.min(k,y);p=0>p?Math.max(y+p,0):Math.min(p,y);l=0>l?Math.max(y+l,0):Math.min(l,y);if(k<p)for(;p<l;)p in this?this[k++]=this[p++]:(delete this[k++],p++);else for(l=Math.min(l,y+p-k),k+=l-p;l>p;)--l in this?this[--k]=this[l]:delete this[--k];return this}},"es6","es3");
|
||||
$jscomp.typedArrayCopyWithin=function(h){return h?h:Array.prototype.copyWithin};$jscomp.polyfill("Int8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8ClampedArray.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");
|
||||
$jscomp.polyfill("Uint16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float64Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");
|
||||
var DracoDecoderModule=function(){var h="undefined"!==typeof document&&document.currentScript?document.currentScript.src:void 0;"undefined"!==typeof __filename&&(h=h||__filename);return function(n){function k(e){return a.locateFile?a.locateFile(e,U):U+e}function p(e,b){if(e){var c=ia;var d=e+b;for(b=e;c[b]&&!(b>=d);)++b;if(16<b-e&&c.buffer&&ra)c=ra.decode(c.subarray(e,b));else{for(d="";e<b;){var g=c[e++];if(g&128){var t=c[e++]&63;if(192==(g&224))d+=String.fromCharCode((g&31)<<6|t);else{var aa=c[e++]&
|
||||
63;g=224==(g&240)?(g&15)<<12|t<<6|aa:(g&7)<<18|t<<12|aa<<6|c[e++]&63;65536>g?d+=String.fromCharCode(g):(g-=65536,d+=String.fromCharCode(55296|g>>10,56320|g&1023))}}else d+=String.fromCharCode(g)}c=d}}else c="";return c}function l(){var e=ja.buffer;a.HEAP8=W=new Int8Array(e);a.HEAP16=new Int16Array(e);a.HEAP32=ca=new Int32Array(e);a.HEAPU8=ia=new Uint8Array(e);a.HEAPU16=new Uint16Array(e);a.HEAPU32=Y=new Uint32Array(e);a.HEAPF32=new Float32Array(e);a.HEAPF64=new Float64Array(e)}function y(e){if(a.onAbort)a.onAbort(e);
|
||||
e="Aborted("+e+")";da(e);sa=!0;e=new WebAssembly.RuntimeError(e+". Build with -sASSERTIONS for more info.");ka(e);throw e;}function f(e){try{if(e==P&&ea)return new Uint8Array(ea);if(ma)return ma(e);throw"both async and sync fetching of the wasm failed";}catch(b){y(b)}}function q(){if(!ea&&(ta||fa)){if("function"==typeof fetch&&!P.startsWith("file://"))return fetch(P,{credentials:"same-origin"}).then(function(e){if(!e.ok)throw"failed to load wasm binary file at '"+P+"'";return e.arrayBuffer()}).catch(function(){return f(P)});
|
||||
if(na)return new Promise(function(e,b){na(P,function(c){e(new Uint8Array(c))},b)})}return Promise.resolve().then(function(){return f(P)})}function u(e){for(;0<e.length;)e.shift()(a)}function A(e){this.excPtr=e;this.ptr=e-24;this.set_type=function(b){Y[this.ptr+4>>2]=b};this.get_type=function(){return Y[this.ptr+4>>2]};this.set_destructor=function(b){Y[this.ptr+8>>2]=b};this.get_destructor=function(){return Y[this.ptr+8>>2]};this.set_refcount=function(b){ca[this.ptr>>2]=b};this.set_caught=function(b){W[this.ptr+
|
||||
12>>0]=b?1:0};this.get_caught=function(){return 0!=W[this.ptr+12>>0]};this.set_rethrown=function(b){W[this.ptr+13>>0]=b?1:0};this.get_rethrown=function(){return 0!=W[this.ptr+13>>0]};this.init=function(b,c){this.set_adjusted_ptr(0);this.set_type(b);this.set_destructor(c);this.set_refcount(0);this.set_caught(!1);this.set_rethrown(!1)};this.add_ref=function(){ca[this.ptr>>2]+=1};this.release_ref=function(){var b=ca[this.ptr>>2];ca[this.ptr>>2]=b-1;return 1===b};this.set_adjusted_ptr=function(b){Y[this.ptr+
|
||||
16>>2]=b};this.get_adjusted_ptr=function(){return Y[this.ptr+16>>2]};this.get_exception_ptr=function(){if(ua(this.get_type()))return Y[this.excPtr>>2];var b=this.get_adjusted_ptr();return 0!==b?b:this.excPtr}}function F(){function e(){if(!la&&(la=!0,a.calledRun=!0,!sa)){va=!0;u(oa);wa(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)xa.unshift(a.postRun.shift());u(xa)}}if(!(0<ba)){if(a.preRun)for("function"==
|
||||
typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)ya.unshift(a.preRun.shift());u(ya);0<ba||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);e()},1)):e())}}function v(){}function w(e){return(e||v).__cache__}function B(e,b){var c=w(b),d=c[e];if(d)return d;d=Object.create((b||v).prototype);d.ptr=e;return c[e]=d}function R(e){if("string"===typeof e){for(var b=0,c=0;c<e.length;++c){var d=e.charCodeAt(c);127>=d?b++:2047>=d?b+=2:55296<=d&&57343>=
|
||||
d?(b+=4,++c):b+=3}b=Array(b+1);c=0;d=b.length;if(0<d){d=c+d-1;for(var g=0;g<e.length;++g){var t=e.charCodeAt(g);if(55296<=t&&57343>=t){var aa=e.charCodeAt(++g);t=65536+((t&1023)<<10)|aa&1023}if(127>=t){if(c>=d)break;b[c++]=t}else{if(2047>=t){if(c+1>=d)break;b[c++]=192|t>>6}else{if(65535>=t){if(c+2>=d)break;b[c++]=224|t>>12}else{if(c+3>=d)break;b[c++]=240|t>>18;b[c++]=128|t>>12&63}b[c++]=128|t>>6&63}b[c++]=128|t&63}}b[c]=0}e=r.alloc(b,W);r.copy(b,W,e);return e}return e}function Z(e){if("object"===
|
||||
typeof e){var b=r.alloc(e,W);r.copy(e,W,b);return b}return e}function X(){throw"cannot construct a VoidPtr, no constructor in IDL";}function S(){this.ptr=za();w(S)[this.ptr]=this}function Q(){this.ptr=Aa();w(Q)[this.ptr]=this}function V(){this.ptr=Ba();w(V)[this.ptr]=this}function x(){this.ptr=Ca();w(x)[this.ptr]=this}function D(){this.ptr=Da();w(D)[this.ptr]=this}function G(){this.ptr=Ea();w(G)[this.ptr]=this}function H(){this.ptr=Fa();w(H)[this.ptr]=this}function E(){this.ptr=Ga();w(E)[this.ptr]=
|
||||
this}function T(){this.ptr=Ha();w(T)[this.ptr]=this}function C(){throw"cannot construct a Status, no constructor in IDL";}function I(){this.ptr=Ia();w(I)[this.ptr]=this}function J(){this.ptr=Ja();w(J)[this.ptr]=this}function K(){this.ptr=Ka();w(K)[this.ptr]=this}function L(){this.ptr=La();w(L)[this.ptr]=this}function M(){this.ptr=Ma();w(M)[this.ptr]=this}function N(){this.ptr=Na();w(N)[this.ptr]=this}function O(){this.ptr=Oa();w(O)[this.ptr]=this}function z(){this.ptr=Pa();w(z)[this.ptr]=this}function m(){this.ptr=
|
||||
Qa();w(m)[this.ptr]=this}n=void 0===n?{}:n;var a="undefined"!=typeof n?n:{},wa,ka;a.ready=new Promise(function(e,b){wa=e;ka=b});var Ra=!1,Sa=!1;a.onRuntimeInitialized=function(){Ra=!0;if(Sa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Sa=!0;if(Ra&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=function(e){if("string"!==typeof e)return!1;e=e.split(".");return 2>e.length||3<e.length?!1:1==e[0]&&0<=e[1]&&5>=e[1]?!0:0!=e[0]||10<
|
||||
e[1]?!1:!0};var Ta=Object.assign({},a),ta="object"==typeof window,fa="function"==typeof importScripts,Ua="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,U="";if(Ua){var Va=require("fs"),pa=require("path");U=fa?pa.dirname(U)+"/":__dirname+"/";var Wa=function(e,b){e=e.startsWith("file://")?new URL(e):pa.normalize(e);return Va.readFileSync(e,b?void 0:"utf8")};var ma=function(e){e=Wa(e,!0);e.buffer||(e=new Uint8Array(e));return e};var na=function(e,
|
||||
b,c){e=e.startsWith("file://")?new URL(e):pa.normalize(e);Va.readFile(e,function(d,g){d?c(d):b(g.buffer)})};1<process.argv.length&&process.argv[1].replace(/\\/g,"/");process.argv.slice(2);a.inspect=function(){return"[Emscripten Module object]"}}else if(ta||fa)fa?U=self.location.href:"undefined"!=typeof document&&document.currentScript&&(U=document.currentScript.src),h&&(U=h),U=0!==U.indexOf("blob:")?U.substr(0,U.replace(/[?#].*/,"").lastIndexOf("/")+1):"",Wa=function(e){var b=new XMLHttpRequest;b.open("GET",
|
||||
e,!1);b.send(null);return b.responseText},fa&&(ma=function(e){var b=new XMLHttpRequest;b.open("GET",e,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),na=function(e,b,c){var d=new XMLHttpRequest;d.open("GET",e,!0);d.responseType="arraybuffer";d.onload=function(){200==d.status||0==d.status&&d.response?b(d.response):c()};d.onerror=c;d.send(null)};a.print||console.log.bind(console);var da=a.printErr||console.warn.bind(console);Object.assign(a,Ta);Ta=null;var ea;a.wasmBinary&&
|
||||
(ea=a.wasmBinary);"object"!=typeof WebAssembly&&y("no native wasm support detected");var ja,sa=!1,ra="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0,W,ia,ca,Y,ya=[],oa=[],xa=[],va=!1,ba=0,qa=null,ha=null;var P="draco_decoder_gltf.wasm";P.startsWith("data:application/octet-stream;base64,")||(P=k(P));var pd=0,qd={b:function(e,b,c){(new A(e)).init(b,c);pd++;throw e;},a:function(){y("")},d:function(e,b,c){ia.copyWithin(e,b,b+c)},c:function(e){var b=ia.length;e>>>=0;if(2147483648<e)return!1;
|
||||
for(var c=1;4>=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,e+100663296);var g=Math;d=Math.max(e,d);g=g.min.call(g,2147483648,d+(65536-d%65536)%65536);a:{d=ja.buffer;try{ja.grow(g-d.byteLength+65535>>>16);l();var t=1;break a}catch(aa){}t=void 0}if(t)return!0}return!1}};(function(){function e(g,t){a.asm=g.exports;ja=a.asm.e;l();oa.unshift(a.asm.f);ba--;a.monitorRunDependencies&&a.monitorRunDependencies(ba);0==ba&&(null!==qa&&(clearInterval(qa),qa=null),ha&&(g=ha,ha=null,g()))}function b(g){e(g.instance)}
|
||||
function c(g){return q().then(function(t){return WebAssembly.instantiate(t,d)}).then(function(t){return t}).then(g,function(t){da("failed to asynchronously prepare wasm: "+t);y(t)})}var d={a:qd};ba++;a.monitorRunDependencies&&a.monitorRunDependencies(ba);if(a.instantiateWasm)try{return a.instantiateWasm(d,e)}catch(g){da("Module.instantiateWasm callback failed with error: "+g),ka(g)}(function(){return ea||"function"!=typeof WebAssembly.instantiateStreaming||P.startsWith("data:application/octet-stream;base64,")||
|
||||
P.startsWith("file://")||Ua||"function"!=typeof fetch?c(b):fetch(P,{credentials:"same-origin"}).then(function(g){return WebAssembly.instantiateStreaming(g,d).then(b,function(t){da("wasm streaming compile failed: "+t);da("falling back to ArrayBuffer instantiation");return c(b)})})})().catch(ka);return{}})();var Xa=a._emscripten_bind_VoidPtr___destroy___0=function(){return(Xa=a._emscripten_bind_VoidPtr___destroy___0=a.asm.h).apply(null,arguments)},za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=
|
||||
function(){return(za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=a.asm.i).apply(null,arguments)},Ya=a._emscripten_bind_DecoderBuffer_Init_2=function(){return(Ya=a._emscripten_bind_DecoderBuffer_Init_2=a.asm.j).apply(null,arguments)},Za=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return(Za=a._emscripten_bind_DecoderBuffer___destroy___0=a.asm.k).apply(null,arguments)},Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=function(){return(Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=
|
||||
a.asm.l).apply(null,arguments)},$a=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return($a=a._emscripten_bind_AttributeTransformData_transform_type_0=a.asm.m).apply(null,arguments)},ab=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return(ab=a._emscripten_bind_AttributeTransformData___destroy___0=a.asm.n).apply(null,arguments)},Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return(Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=
|
||||
a.asm.o).apply(null,arguments)},bb=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return(bb=a._emscripten_bind_GeometryAttribute___destroy___0=a.asm.p).apply(null,arguments)},Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=function(){return(Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=a.asm.q).apply(null,arguments)},cb=a._emscripten_bind_PointAttribute_size_0=function(){return(cb=a._emscripten_bind_PointAttribute_size_0=a.asm.r).apply(null,arguments)},db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=
|
||||
function(){return(db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=a.asm.s).apply(null,arguments)},eb=a._emscripten_bind_PointAttribute_attribute_type_0=function(){return(eb=a._emscripten_bind_PointAttribute_attribute_type_0=a.asm.t).apply(null,arguments)},fb=a._emscripten_bind_PointAttribute_data_type_0=function(){return(fb=a._emscripten_bind_PointAttribute_data_type_0=a.asm.u).apply(null,arguments)},gb=a._emscripten_bind_PointAttribute_num_components_0=function(){return(gb=a._emscripten_bind_PointAttribute_num_components_0=
|
||||
a.asm.v).apply(null,arguments)},hb=a._emscripten_bind_PointAttribute_normalized_0=function(){return(hb=a._emscripten_bind_PointAttribute_normalized_0=a.asm.w).apply(null,arguments)},ib=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return(ib=a._emscripten_bind_PointAttribute_byte_stride_0=a.asm.x).apply(null,arguments)},jb=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return(jb=a._emscripten_bind_PointAttribute_byte_offset_0=a.asm.y).apply(null,arguments)},kb=a._emscripten_bind_PointAttribute_unique_id_0=
|
||||
function(){return(kb=a._emscripten_bind_PointAttribute_unique_id_0=a.asm.z).apply(null,arguments)},lb=a._emscripten_bind_PointAttribute___destroy___0=function(){return(lb=a._emscripten_bind_PointAttribute___destroy___0=a.asm.A).apply(null,arguments)},Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=function(){return(Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=a.asm.B).apply(null,arguments)},mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=
|
||||
function(){return(mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=a.asm.C).apply(null,arguments)},nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return(nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=a.asm.D).apply(null,arguments)},ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return(ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=a.asm.E).apply(null,arguments)},pb=
|
||||
a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return(pb=a._emscripten_bind_AttributeQuantizationTransform_range_0=a.asm.F).apply(null,arguments)},qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return(qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=a.asm.G).apply(null,arguments)},Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return(Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=
|
||||
a.asm.H).apply(null,arguments)},rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=function(){return(rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=a.asm.I).apply(null,arguments)},sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return(sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=a.asm.J).apply(null,arguments)},tb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return(tb=
|
||||
a._emscripten_bind_AttributeOctahedronTransform___destroy___0=a.asm.K).apply(null,arguments)},Fa=a._emscripten_bind_PointCloud_PointCloud_0=function(){return(Fa=a._emscripten_bind_PointCloud_PointCloud_0=a.asm.L).apply(null,arguments)},ub=a._emscripten_bind_PointCloud_num_attributes_0=function(){return(ub=a._emscripten_bind_PointCloud_num_attributes_0=a.asm.M).apply(null,arguments)},vb=a._emscripten_bind_PointCloud_num_points_0=function(){return(vb=a._emscripten_bind_PointCloud_num_points_0=a.asm.N).apply(null,
|
||||
arguments)},wb=a._emscripten_bind_PointCloud___destroy___0=function(){return(wb=a._emscripten_bind_PointCloud___destroy___0=a.asm.O).apply(null,arguments)},Ga=a._emscripten_bind_Mesh_Mesh_0=function(){return(Ga=a._emscripten_bind_Mesh_Mesh_0=a.asm.P).apply(null,arguments)},xb=a._emscripten_bind_Mesh_num_faces_0=function(){return(xb=a._emscripten_bind_Mesh_num_faces_0=a.asm.Q).apply(null,arguments)},yb=a._emscripten_bind_Mesh_num_attributes_0=function(){return(yb=a._emscripten_bind_Mesh_num_attributes_0=
|
||||
a.asm.R).apply(null,arguments)},zb=a._emscripten_bind_Mesh_num_points_0=function(){return(zb=a._emscripten_bind_Mesh_num_points_0=a.asm.S).apply(null,arguments)},Ab=a._emscripten_bind_Mesh___destroy___0=function(){return(Ab=a._emscripten_bind_Mesh___destroy___0=a.asm.T).apply(null,arguments)},Ha=a._emscripten_bind_Metadata_Metadata_0=function(){return(Ha=a._emscripten_bind_Metadata_Metadata_0=a.asm.U).apply(null,arguments)},Bb=a._emscripten_bind_Metadata___destroy___0=function(){return(Bb=a._emscripten_bind_Metadata___destroy___0=
|
||||
a.asm.V).apply(null,arguments)},Cb=a._emscripten_bind_Status_code_0=function(){return(Cb=a._emscripten_bind_Status_code_0=a.asm.W).apply(null,arguments)},Db=a._emscripten_bind_Status_ok_0=function(){return(Db=a._emscripten_bind_Status_ok_0=a.asm.X).apply(null,arguments)},Eb=a._emscripten_bind_Status_error_msg_0=function(){return(Eb=a._emscripten_bind_Status_error_msg_0=a.asm.Y).apply(null,arguments)},Fb=a._emscripten_bind_Status___destroy___0=function(){return(Fb=a._emscripten_bind_Status___destroy___0=
|
||||
a.asm.Z).apply(null,arguments)},Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return(Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=a.asm._).apply(null,arguments)},Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=function(){return(Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=a.asm.$).apply(null,arguments)},Hb=a._emscripten_bind_DracoFloat32Array_size_0=function(){return(Hb=a._emscripten_bind_DracoFloat32Array_size_0=a.asm.aa).apply(null,arguments)},Ib=
|
||||
a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return(Ib=a._emscripten_bind_DracoFloat32Array___destroy___0=a.asm.ba).apply(null,arguments)},Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=function(){return(Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=a.asm.ca).apply(null,arguments)},Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return(Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=a.asm.da).apply(null,arguments)},Kb=a._emscripten_bind_DracoInt8Array_size_0=
|
||||
function(){return(Kb=a._emscripten_bind_DracoInt8Array_size_0=a.asm.ea).apply(null,arguments)},Lb=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return(Lb=a._emscripten_bind_DracoInt8Array___destroy___0=a.asm.fa).apply(null,arguments)},Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return(Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=a.asm.ga).apply(null,arguments)},Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return(Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1=
|
||||
a.asm.ha).apply(null,arguments)},Nb=a._emscripten_bind_DracoUInt8Array_size_0=function(){return(Nb=a._emscripten_bind_DracoUInt8Array_size_0=a.asm.ia).apply(null,arguments)},Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=function(){return(Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=a.asm.ja).apply(null,arguments)},La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return(La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=a.asm.ka).apply(null,arguments)},Pb=a._emscripten_bind_DracoInt16Array_GetValue_1=
|
||||
function(){return(Pb=a._emscripten_bind_DracoInt16Array_GetValue_1=a.asm.la).apply(null,arguments)},Qb=a._emscripten_bind_DracoInt16Array_size_0=function(){return(Qb=a._emscripten_bind_DracoInt16Array_size_0=a.asm.ma).apply(null,arguments)},Rb=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return(Rb=a._emscripten_bind_DracoInt16Array___destroy___0=a.asm.na).apply(null,arguments)},Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return(Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=
|
||||
a.asm.oa).apply(null,arguments)},Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return(Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=a.asm.pa).apply(null,arguments)},Tb=a._emscripten_bind_DracoUInt16Array_size_0=function(){return(Tb=a._emscripten_bind_DracoUInt16Array_size_0=a.asm.qa).apply(null,arguments)},Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return(Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=a.asm.ra).apply(null,arguments)},Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=
|
||||
function(){return(Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=a.asm.sa).apply(null,arguments)},Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return(Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=a.asm.ta).apply(null,arguments)},Wb=a._emscripten_bind_DracoInt32Array_size_0=function(){return(Wb=a._emscripten_bind_DracoInt32Array_size_0=a.asm.ua).apply(null,arguments)},Xb=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return(Xb=a._emscripten_bind_DracoInt32Array___destroy___0=
|
||||
a.asm.va).apply(null,arguments)},Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return(Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=a.asm.wa).apply(null,arguments)},Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return(Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=a.asm.xa).apply(null,arguments)},Zb=a._emscripten_bind_DracoUInt32Array_size_0=function(){return(Zb=a._emscripten_bind_DracoUInt32Array_size_0=a.asm.ya).apply(null,arguments)},$b=a._emscripten_bind_DracoUInt32Array___destroy___0=
|
||||
function(){return($b=a._emscripten_bind_DracoUInt32Array___destroy___0=a.asm.za).apply(null,arguments)},Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return(Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=a.asm.Aa).apply(null,arguments)},ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=function(){return(ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=a.asm.Ba).apply(null,arguments)},bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return(bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=
|
||||
a.asm.Ca).apply(null,arguments)},cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=function(){return(cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=a.asm.Da).apply(null,arguments)},dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return(dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=a.asm.Ea).apply(null,arguments)},ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return(ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=a.asm.Fa).apply(null,
|
||||
arguments)},fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return(fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=a.asm.Ga).apply(null,arguments)},gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return(gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=a.asm.Ha).apply(null,arguments)},hc=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return(hc=a._emscripten_bind_MetadataQuerier___destroy___0=a.asm.Ia).apply(null,arguments)},Qa=a._emscripten_bind_Decoder_Decoder_0=
|
||||
function(){return(Qa=a._emscripten_bind_Decoder_Decoder_0=a.asm.Ja).apply(null,arguments)},ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=function(){return(ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=a.asm.Ka).apply(null,arguments)},jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=function(){return(jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=a.asm.La).apply(null,arguments)},kc=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return(kc=a._emscripten_bind_Decoder_GetAttributeId_2=
|
||||
a.asm.Ma).apply(null,arguments)},lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return(lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=a.asm.Na).apply(null,arguments)},mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return(mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=a.asm.Oa).apply(null,arguments)},nc=a._emscripten_bind_Decoder_GetAttribute_2=function(){return(nc=a._emscripten_bind_Decoder_GetAttribute_2=a.asm.Pa).apply(null,arguments)},
|
||||
oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return(oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=a.asm.Qa).apply(null,arguments)},pc=a._emscripten_bind_Decoder_GetMetadata_1=function(){return(pc=a._emscripten_bind_Decoder_GetMetadata_1=a.asm.Ra).apply(null,arguments)},qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return(qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=a.asm.Sa).apply(null,arguments)},rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=
|
||||
function(){return(rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=a.asm.Ta).apply(null,arguments)},sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return(sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=a.asm.Ua).apply(null,arguments)},tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=function(){return(tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=a.asm.Va).apply(null,arguments)},uc=a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=function(){return(uc=
|
||||
a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=a.asm.Wa).apply(null,arguments)},vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return(vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=a.asm.Xa).apply(null,arguments)},wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=function(){return(wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=a.asm.Ya).apply(null,arguments)},xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return(xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=
|
||||
a.asm.Za).apply(null,arguments)},yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=function(){return(yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=a.asm._a).apply(null,arguments)},zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return(zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=a.asm.$a).apply(null,arguments)},Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return(Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=
|
||||
a.asm.ab).apply(null,arguments)},Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=function(){return(Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=a.asm.bb).apply(null,arguments)},Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return(Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=a.asm.cb).apply(null,arguments)},Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return(Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=
|
||||
a.asm.db).apply(null,arguments)},Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=function(){return(Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=a.asm.eb).apply(null,arguments)},Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return(Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=a.asm.fb).apply(null,arguments)},Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1=function(){return(Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1=
|
||||
a.asm.gb).apply(null,arguments)},Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return(Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=a.asm.hb).apply(null,arguments)},Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return(Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=a.asm.ib).apply(null,arguments)},Jc=a._emscripten_bind_Decoder___destroy___0=function(){return(Jc=a._emscripten_bind_Decoder___destroy___0=a.asm.jb).apply(null,arguments)},Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=
|
||||
function(){return(Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=a.asm.kb).apply(null,arguments)},Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return(Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=a.asm.lb).apply(null,arguments)},Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return(Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=
|
||||
a.asm.mb).apply(null,arguments)},Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=function(){return(Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=a.asm.nb).apply(null,arguments)},Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return(Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=a.asm.ob).apply(null,arguments)},Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=function(){return(Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=
|
||||
a.asm.pb).apply(null,arguments)},Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return(Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=a.asm.qb).apply(null,arguments)},Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=function(){return(Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=a.asm.rb).apply(null,arguments)},Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return(Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=
|
||||
a.asm.sb).apply(null,arguments)},Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return(Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=a.asm.tb).apply(null,arguments)},Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return(Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=a.asm.ub).apply(null,arguments)},Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return(Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=
|
||||
a.asm.vb).apply(null,arguments)},Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return(Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=a.asm.wb).apply(null,arguments)},Xc=a._emscripten_enum_draco_DataType_DT_INVALID=function(){return(Xc=a._emscripten_enum_draco_DataType_DT_INVALID=a.asm.xb).apply(null,arguments)},Yc=a._emscripten_enum_draco_DataType_DT_INT8=function(){return(Yc=a._emscripten_enum_draco_DataType_DT_INT8=a.asm.yb).apply(null,arguments)},Zc=
|
||||
a._emscripten_enum_draco_DataType_DT_UINT8=function(){return(Zc=a._emscripten_enum_draco_DataType_DT_UINT8=a.asm.zb).apply(null,arguments)},$c=a._emscripten_enum_draco_DataType_DT_INT16=function(){return($c=a._emscripten_enum_draco_DataType_DT_INT16=a.asm.Ab).apply(null,arguments)},ad=a._emscripten_enum_draco_DataType_DT_UINT16=function(){return(ad=a._emscripten_enum_draco_DataType_DT_UINT16=a.asm.Bb).apply(null,arguments)},bd=a._emscripten_enum_draco_DataType_DT_INT32=function(){return(bd=a._emscripten_enum_draco_DataType_DT_INT32=
|
||||
a.asm.Cb).apply(null,arguments)},cd=a._emscripten_enum_draco_DataType_DT_UINT32=function(){return(cd=a._emscripten_enum_draco_DataType_DT_UINT32=a.asm.Db).apply(null,arguments)},dd=a._emscripten_enum_draco_DataType_DT_INT64=function(){return(dd=a._emscripten_enum_draco_DataType_DT_INT64=a.asm.Eb).apply(null,arguments)},ed=a._emscripten_enum_draco_DataType_DT_UINT64=function(){return(ed=a._emscripten_enum_draco_DataType_DT_UINT64=a.asm.Fb).apply(null,arguments)},fd=a._emscripten_enum_draco_DataType_DT_FLOAT32=
|
||||
function(){return(fd=a._emscripten_enum_draco_DataType_DT_FLOAT32=a.asm.Gb).apply(null,arguments)},gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=function(){return(gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=a.asm.Hb).apply(null,arguments)},hd=a._emscripten_enum_draco_DataType_DT_BOOL=function(){return(hd=a._emscripten_enum_draco_DataType_DT_BOOL=a.asm.Ib).apply(null,arguments)},id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=function(){return(id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=
|
||||
a.asm.Jb).apply(null,arguments)},jd=a._emscripten_enum_draco_StatusCode_OK=function(){return(jd=a._emscripten_enum_draco_StatusCode_OK=a.asm.Kb).apply(null,arguments)},kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=function(){return(kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=a.asm.Lb).apply(null,arguments)},ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return(ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=a.asm.Mb).apply(null,arguments)},md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=
|
||||
function(){return(md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=a.asm.Nb).apply(null,arguments)},nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=function(){return(nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=a.asm.Ob).apply(null,arguments)},od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return(od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=a.asm.Pb).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.Qb).apply(null,arguments)};
|
||||
a._free=function(){return(a._free=a.asm.Rb).apply(null,arguments)};var ua=function(){return(ua=a.asm.Sb).apply(null,arguments)};a.___start_em_js=11660;a.___stop_em_js=11758;var la;ha=function b(){la||F();la||(ha=b)};if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();F();v.prototype=Object.create(v.prototype);v.prototype.constructor=v;v.prototype.__class__=v;v.__cache__={};a.WrapperObject=v;a.getCache=w;a.wrapPointer=B;a.castObject=function(b,
|
||||
c){return B(b.ptr,c)};a.NULL=B(0);a.destroy=function(b){if(!b.__destroy__)throw"Error: Cannot destroy object. (Did you create it yourself?)";b.__destroy__();delete w(b.__class__)[b.ptr]};a.compare=function(b,c){return b.ptr===c.ptr};a.getPointer=function(b){return b.ptr};a.getClass=function(b){return b.__class__};var r={buffer:0,size:0,pos:0,temps:[],needed:0,prepare:function(){if(r.needed){for(var b=0;b<r.temps.length;b++)a._free(r.temps[b]);r.temps.length=0;a._free(r.buffer);r.buffer=0;r.size+=
|
||||
r.needed;r.needed=0}r.buffer||(r.size+=128,r.buffer=a._malloc(r.size),r.buffer||y(void 0));r.pos=0},alloc:function(b,c){r.buffer||y(void 0);b=b.length*c.BYTES_PER_ELEMENT;b=b+7&-8;r.pos+b>=r.size?(0<b||y(void 0),r.needed+=b,c=a._malloc(b),r.temps.push(c)):(c=r.buffer+r.pos,r.pos+=b);return c},copy:function(b,c,d){d>>>=0;switch(c.BYTES_PER_ELEMENT){case 2:d>>>=1;break;case 4:d>>>=2;break;case 8:d>>>=3}for(var g=0;g<b.length;g++)c[d+g]=b[g]}};X.prototype=Object.create(v.prototype);X.prototype.constructor=
|
||||
X;X.prototype.__class__=X;X.__cache__={};a.VoidPtr=X;X.prototype.__destroy__=X.prototype.__destroy__=function(){Xa(this.ptr)};S.prototype=Object.create(v.prototype);S.prototype.constructor=S;S.prototype.__class__=S;S.__cache__={};a.DecoderBuffer=S;S.prototype.Init=S.prototype.Init=function(b,c){var d=this.ptr;r.prepare();"object"==typeof b&&(b=Z(b));c&&"object"===typeof c&&(c=c.ptr);Ya(d,b,c)};S.prototype.__destroy__=S.prototype.__destroy__=function(){Za(this.ptr)};Q.prototype=Object.create(v.prototype);
|
||||
Q.prototype.constructor=Q;Q.prototype.__class__=Q;Q.__cache__={};a.AttributeTransformData=Q;Q.prototype.transform_type=Q.prototype.transform_type=function(){return $a(this.ptr)};Q.prototype.__destroy__=Q.prototype.__destroy__=function(){ab(this.ptr)};V.prototype=Object.create(v.prototype);V.prototype.constructor=V;V.prototype.__class__=V;V.__cache__={};a.GeometryAttribute=V;V.prototype.__destroy__=V.prototype.__destroy__=function(){bb(this.ptr)};x.prototype=Object.create(v.prototype);x.prototype.constructor=
|
||||
x;x.prototype.__class__=x;x.__cache__={};a.PointAttribute=x;x.prototype.size=x.prototype.size=function(){return cb(this.ptr)};x.prototype.GetAttributeTransformData=x.prototype.GetAttributeTransformData=function(){return B(db(this.ptr),Q)};x.prototype.attribute_type=x.prototype.attribute_type=function(){return eb(this.ptr)};x.prototype.data_type=x.prototype.data_type=function(){return fb(this.ptr)};x.prototype.num_components=x.prototype.num_components=function(){return gb(this.ptr)};x.prototype.normalized=
|
||||
x.prototype.normalized=function(){return!!hb(this.ptr)};x.prototype.byte_stride=x.prototype.byte_stride=function(){return ib(this.ptr)};x.prototype.byte_offset=x.prototype.byte_offset=function(){return jb(this.ptr)};x.prototype.unique_id=x.prototype.unique_id=function(){return kb(this.ptr)};x.prototype.__destroy__=x.prototype.__destroy__=function(){lb(this.ptr)};D.prototype=Object.create(v.prototype);D.prototype.constructor=D;D.prototype.__class__=D;D.__cache__={};a.AttributeQuantizationTransform=
|
||||
D;D.prototype.InitFromAttribute=D.prototype.InitFromAttribute=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return!!mb(c,b)};D.prototype.quantization_bits=D.prototype.quantization_bits=function(){return nb(this.ptr)};D.prototype.min_value=D.prototype.min_value=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return ob(c,b)};D.prototype.range=D.prototype.range=function(){return pb(this.ptr)};D.prototype.__destroy__=D.prototype.__destroy__=function(){qb(this.ptr)};G.prototype=
|
||||
Object.create(v.prototype);G.prototype.constructor=G;G.prototype.__class__=G;G.__cache__={};a.AttributeOctahedronTransform=G;G.prototype.InitFromAttribute=G.prototype.InitFromAttribute=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return!!rb(c,b)};G.prototype.quantization_bits=G.prototype.quantization_bits=function(){return sb(this.ptr)};G.prototype.__destroy__=G.prototype.__destroy__=function(){tb(this.ptr)};H.prototype=Object.create(v.prototype);H.prototype.constructor=H;H.prototype.__class__=
|
||||
H;H.__cache__={};a.PointCloud=H;H.prototype.num_attributes=H.prototype.num_attributes=function(){return ub(this.ptr)};H.prototype.num_points=H.prototype.num_points=function(){return vb(this.ptr)};H.prototype.__destroy__=H.prototype.__destroy__=function(){wb(this.ptr)};E.prototype=Object.create(v.prototype);E.prototype.constructor=E;E.prototype.__class__=E;E.__cache__={};a.Mesh=E;E.prototype.num_faces=E.prototype.num_faces=function(){return xb(this.ptr)};E.prototype.num_attributes=E.prototype.num_attributes=
|
||||
function(){return yb(this.ptr)};E.prototype.num_points=E.prototype.num_points=function(){return zb(this.ptr)};E.prototype.__destroy__=E.prototype.__destroy__=function(){Ab(this.ptr)};T.prototype=Object.create(v.prototype);T.prototype.constructor=T;T.prototype.__class__=T;T.__cache__={};a.Metadata=T;T.prototype.__destroy__=T.prototype.__destroy__=function(){Bb(this.ptr)};C.prototype=Object.create(v.prototype);C.prototype.constructor=C;C.prototype.__class__=C;C.__cache__={};a.Status=C;C.prototype.code=
|
||||
C.prototype.code=function(){return Cb(this.ptr)};C.prototype.ok=C.prototype.ok=function(){return!!Db(this.ptr)};C.prototype.error_msg=C.prototype.error_msg=function(){return p(Eb(this.ptr))};C.prototype.__destroy__=C.prototype.__destroy__=function(){Fb(this.ptr)};I.prototype=Object.create(v.prototype);I.prototype.constructor=I;I.prototype.__class__=I;I.__cache__={};a.DracoFloat32Array=I;I.prototype.GetValue=I.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Gb(c,
|
||||
b)};I.prototype.size=I.prototype.size=function(){return Hb(this.ptr)};I.prototype.__destroy__=I.prototype.__destroy__=function(){Ib(this.ptr)};J.prototype=Object.create(v.prototype);J.prototype.constructor=J;J.prototype.__class__=J;J.__cache__={};a.DracoInt8Array=J;J.prototype.GetValue=J.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Jb(c,b)};J.prototype.size=J.prototype.size=function(){return Kb(this.ptr)};J.prototype.__destroy__=J.prototype.__destroy__=function(){Lb(this.ptr)};
|
||||
K.prototype=Object.create(v.prototype);K.prototype.constructor=K;K.prototype.__class__=K;K.__cache__={};a.DracoUInt8Array=K;K.prototype.GetValue=K.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Mb(c,b)};K.prototype.size=K.prototype.size=function(){return Nb(this.ptr)};K.prototype.__destroy__=K.prototype.__destroy__=function(){Ob(this.ptr)};L.prototype=Object.create(v.prototype);L.prototype.constructor=L;L.prototype.__class__=L;L.__cache__={};a.DracoInt16Array=
|
||||
L;L.prototype.GetValue=L.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Pb(c,b)};L.prototype.size=L.prototype.size=function(){return Qb(this.ptr)};L.prototype.__destroy__=L.prototype.__destroy__=function(){Rb(this.ptr)};M.prototype=Object.create(v.prototype);M.prototype.constructor=M;M.prototype.__class__=M;M.__cache__={};a.DracoUInt16Array=M;M.prototype.GetValue=M.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Sb(c,b)};
|
||||
M.prototype.size=M.prototype.size=function(){return Tb(this.ptr)};M.prototype.__destroy__=M.prototype.__destroy__=function(){Ub(this.ptr)};N.prototype=Object.create(v.prototype);N.prototype.constructor=N;N.prototype.__class__=N;N.__cache__={};a.DracoInt32Array=N;N.prototype.GetValue=N.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Vb(c,b)};N.prototype.size=N.prototype.size=function(){return Wb(this.ptr)};N.prototype.__destroy__=N.prototype.__destroy__=function(){Xb(this.ptr)};
|
||||
O.prototype=Object.create(v.prototype);O.prototype.constructor=O;O.prototype.__class__=O;O.__cache__={};a.DracoUInt32Array=O;O.prototype.GetValue=O.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Yb(c,b)};O.prototype.size=O.prototype.size=function(){return Zb(this.ptr)};O.prototype.__destroy__=O.prototype.__destroy__=function(){$b(this.ptr)};z.prototype=Object.create(v.prototype);z.prototype.constructor=z;z.prototype.__class__=z;z.__cache__={};a.MetadataQuerier=
|
||||
z;z.prototype.HasEntry=z.prototype.HasEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return!!ac(d,b,c)};z.prototype.GetIntEntry=z.prototype.GetIntEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return bc(d,b,c)};z.prototype.GetIntEntryArray=z.prototype.GetIntEntryArray=function(b,c,d){var g=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===
|
||||
typeof c?c.ptr:R(c);d&&"object"===typeof d&&(d=d.ptr);cc(g,b,c,d)};z.prototype.GetDoubleEntry=z.prototype.GetDoubleEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return dc(d,b,c)};z.prototype.GetStringEntry=z.prototype.GetStringEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return p(ec(d,b,c))};z.prototype.NumEntries=z.prototype.NumEntries=function(b){var c=this.ptr;
|
||||
b&&"object"===typeof b&&(b=b.ptr);return fc(c,b)};z.prototype.GetEntryName=z.prototype.GetEntryName=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return p(gc(d,b,c))};z.prototype.__destroy__=z.prototype.__destroy__=function(){hc(this.ptr)};m.prototype=Object.create(v.prototype);m.prototype.constructor=m;m.prototype.__class__=m;m.__cache__={};a.Decoder=m;m.prototype.DecodeArrayToPointCloud=m.prototype.DecodeArrayToPointCloud=function(b,c,d){var g=
|
||||
this.ptr;r.prepare();"object"==typeof b&&(b=Z(b));c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return B(ic(g,b,c,d),C)};m.prototype.DecodeArrayToMesh=m.prototype.DecodeArrayToMesh=function(b,c,d){var g=this.ptr;r.prepare();"object"==typeof b&&(b=Z(b));c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return B(jc(g,b,c,d),C)};m.prototype.GetAttributeId=m.prototype.GetAttributeId=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&
|
||||
(c=c.ptr);return kc(d,b,c)};m.prototype.GetAttributeIdByName=m.prototype.GetAttributeIdByName=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return lc(d,b,c)};m.prototype.GetAttributeIdByMetadataEntry=m.prototype.GetAttributeIdByMetadataEntry=function(b,c,d){var g=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);d=d&&"object"===typeof d?d.ptr:R(d);return mc(g,b,c,d)};m.prototype.GetAttribute=
|
||||
m.prototype.GetAttribute=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(nc(d,b,c),x)};m.prototype.GetAttributeByUniqueId=m.prototype.GetAttributeByUniqueId=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(oc(d,b,c),x)};m.prototype.GetMetadata=m.prototype.GetMetadata=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return B(pc(c,b),T)};m.prototype.GetAttributeMetadata=m.prototype.GetAttributeMetadata=
|
||||
function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(qc(d,b,c),T)};m.prototype.GetFaceFromMesh=m.prototype.GetFaceFromMesh=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!rc(g,b,c,d)};m.prototype.GetTriangleStripsFromMesh=m.prototype.GetTriangleStripsFromMesh=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);
|
||||
return sc(d,b,c)};m.prototype.GetTrianglesUInt16Array=m.prototype.GetTrianglesUInt16Array=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!tc(g,b,c,d)};m.prototype.GetTrianglesUInt32Array=m.prototype.GetTrianglesUInt32Array=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!uc(g,b,c,d)};m.prototype.GetAttributeFloat=m.prototype.GetAttributeFloat=
|
||||
function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!vc(g,b,c,d)};m.prototype.GetAttributeFloatForAllPoints=m.prototype.GetAttributeFloatForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!wc(g,b,c,d)};m.prototype.GetAttributeIntForAllPoints=m.prototype.GetAttributeIntForAllPoints=function(b,c,d){var g=this.ptr;
|
||||
b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!xc(g,b,c,d)};m.prototype.GetAttributeInt8ForAllPoints=m.prototype.GetAttributeInt8ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!yc(g,b,c,d)};m.prototype.GetAttributeUInt8ForAllPoints=m.prototype.GetAttributeUInt8ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=
|
||||
b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!zc(g,b,c,d)};m.prototype.GetAttributeInt16ForAllPoints=m.prototype.GetAttributeInt16ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Ac(g,b,c,d)};m.prototype.GetAttributeUInt16ForAllPoints=m.prototype.GetAttributeUInt16ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&
|
||||
(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Bc(g,b,c,d)};m.prototype.GetAttributeInt32ForAllPoints=m.prototype.GetAttributeInt32ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Cc(g,b,c,d)};m.prototype.GetAttributeUInt32ForAllPoints=m.prototype.GetAttributeUInt32ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===
|
||||
typeof d&&(d=d.ptr);return!!Dc(g,b,c,d)};m.prototype.GetAttributeDataArrayForAllPoints=m.prototype.GetAttributeDataArrayForAllPoints=function(b,c,d,g,t){var aa=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);g&&"object"===typeof g&&(g=g.ptr);t&&"object"===typeof t&&(t=t.ptr);return!!Ec(aa,b,c,d,g,t)};m.prototype.SkipAttributeTransform=m.prototype.SkipAttributeTransform=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);Fc(c,
|
||||
b)};m.prototype.GetEncodedGeometryType_Deprecated=m.prototype.GetEncodedGeometryType_Deprecated=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Gc(c,b)};m.prototype.DecodeBufferToPointCloud=m.prototype.DecodeBufferToPointCloud=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(Hc(d,b,c),C)};m.prototype.DecodeBufferToMesh=m.prototype.DecodeBufferToMesh=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===
|
||||
typeof c&&(c=c.ptr);return B(Ic(d,b,c),C)};m.prototype.__destroy__=m.prototype.__destroy__=function(){Jc(this.ptr)};(function(){function b(){a.ATTRIBUTE_INVALID_TRANSFORM=Kc();a.ATTRIBUTE_NO_TRANSFORM=Lc();a.ATTRIBUTE_QUANTIZATION_TRANSFORM=Mc();a.ATTRIBUTE_OCTAHEDRON_TRANSFORM=Nc();a.INVALID=Oc();a.POSITION=Pc();a.NORMAL=Qc();a.COLOR=Rc();a.TEX_COORD=Sc();a.GENERIC=Tc();a.INVALID_GEOMETRY_TYPE=Uc();a.POINT_CLOUD=Vc();a.TRIANGULAR_MESH=Wc();a.DT_INVALID=Xc();a.DT_INT8=Yc();a.DT_UINT8=Zc();a.DT_INT16=
|
||||
$c();a.DT_UINT16=ad();a.DT_INT32=bd();a.DT_UINT32=cd();a.DT_INT64=dd();a.DT_UINT64=ed();a.DT_FLOAT32=fd();a.DT_FLOAT64=gd();a.DT_BOOL=hd();a.DT_TYPES_COUNT=id();a.OK=jd();a.DRACO_ERROR=kd();a.IO_ERROR=ld();a.INVALID_PARAMETER=md();a.UNSUPPORTED_VERSION=nd();a.UNKNOWN_VERSION=od()}va?b():oa.unshift(b)})();if("function"===typeof a.onModuleParsed)a.onModuleParsed();a.Decoder.prototype.GetEncodedGeometryType=function(b){if(b.__class__&&b.__class__===a.DecoderBuffer)return a.Decoder.prototype.GetEncodedGeometryType_Deprecated(b);
|
||||
if(8>b.byteLength)return a.INVALID_GEOMETRY_TYPE;switch(b[7]){case 0:return a.POINT_CLOUD;case 1:return a.TRIANGULAR_MESH;default:return a.INVALID_GEOMETRY_TYPE}};return n.ready}}();"object"===typeof exports&&"object"===typeof module?module.exports=DracoDecoderModule:"function"===typeof define&&define.amd?define([],function(){return DracoDecoderModule}):"object"===typeof exports&&(exports.DracoDecoderModule=DracoDecoderModule);
|
||||
BIN
public/images/Aravinth.webp
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
public/images/Fazul.webp
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
public/images/Investor.webp
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
public/images/Parthi.webp
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
public/images/Suriya.webp
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/images/about-bg.webp
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
public/images/air-freight-pic-1.jpg
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
public/images/air-freight-slide-1.jpg
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
public/images/air-freight-slide-2.jpg
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
public/images/b5b560fe-aab0-4fe6-9f8c-4b187c2f0e99.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
public/images/b5b560fe-aab0-4fe6-9f8c-4b187c2f0e99.webp
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
public/images/bg-header-5.webp
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
public/images/bg-header-women.webp
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
public/images/bg-map-women.webp
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
public/images/bg-slide-sidebar.webp
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
public/images/blog-post-pic-14.webp
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
public/images/blog-post-pic-15.webp
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
public/images/blog-post-pic-17.webp
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
public/images/blog-post-pic-3.webp
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
public/images/blog-post-pic-31.webp
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
public/images/blog-post-pic-6.webp
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
public/images/blog-post-pic-8.webp
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
public/images/ev-paradox.webp
Normal file
|
After Width: | Height: | Size: 176 KiB |
BIN
public/images/ev.webp
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
public/images/first-mile-approach.webp
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
public/images/home-bg-1.webp
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
public/images/home1-slide-1.webp
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
public/images/home1-slide-2.webp
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
public/images/home2-banner-1.webp
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
public/images/home2-banner-3.webp
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
public/images/home2-pic-3.webp
Normal file
|
After Width: | Height: | Size: 141 KiB |
BIN
public/images/home2-slide-1.webp
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
public/images/home2-slide-2.webp
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
public/images/last-mile-approach.webp
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
public/images/mid-mile-approach.webp
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
public/images/mile-1.png
Normal file
|
After Width: | Height: | Size: 8.0 MiB |
BIN
public/images/mile-1.webp
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
public/images/miletruth-bg.webp
Normal file
|
After Width: | Height: | Size: 187 KiB |
BIN
public/images/premium-ev-van.webp
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
public/images/tab-pic-1-solution.webp
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
public/images/tab-pic-1.webp
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
public/images/tab-pic-2-solution.webp
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
public/images/tab-pic-2.webp
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
public/images/tab-pic-3-solution.webp
Normal file
|
After Width: | Height: | Size: 157 KiB |
BIN
public/images/tab-pic-3.webp
Normal file
|
After Width: | Height: | Size: 155 KiB |
BIN
public/videos/workflow-2-routing.mp4
Normal file
53
src/actions/sendEmail.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
"use server";
|
||||
|
||||
import nodemailer from "nodemailer";
|
||||
|
||||
export async function sendContactEmail(data: {
|
||||
fullName: string;
|
||||
email: string;
|
||||
subject: string;
|
||||
message: string;
|
||||
}) {
|
||||
const { fullName, email, subject, message } = data;
|
||||
|
||||
if (!fullName || !email || !subject || !message) {
|
||||
return { success: false, error: "All fields are required." };
|
||||
}
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: Number(process.env.SMTP_PORT) || 465,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASSWORD,
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
await transporter.sendMail({
|
||||
from: `"${fullName}" <${process.env.SMTP_USER}>`,
|
||||
to: process.env.CONTACT_RECEIVER,
|
||||
replyTo: email,
|
||||
subject: `New Contact Form Submission: ${subject}`,
|
||||
html: `
|
||||
<div style="font-family: sans-serif; color: #333; max-width: 600px; margin: 0 auto; border: 1px solid #eee; padding: 20px; border-radius: 8px;">
|
||||
<h2 style="color: #c01227; border-bottom: 2px solid #c01227; padding-bottom: 10px; margin-top: 0;">New Contact Form Submission</h2>
|
||||
<p><strong>Name:</strong> ${fullName}</p>
|
||||
<p><strong>Email:</strong> ${email}</p>
|
||||
<p><strong>Subject:</strong> ${subject}</p>
|
||||
<p><strong>Message:</strong></p>
|
||||
<blockquote style="background: #f9f9f9; padding: 15px; border-left: 4px solid #c01227; margin: 0; font-style: italic;">
|
||||
${message.replace(/\n/g, "<br />")}
|
||||
</blockquote>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error("Email send error:", error);
|
||||
const errorMessage = error instanceof Error ? error.message : "Failed to send the email. Please try again later.";
|
||||
return { success: false, error: errorMessage };
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ export const metadata = {
|
||||
|
||||
export default function AboutUsPage() {
|
||||
return (
|
||||
<div className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div id="about" className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div className="content">
|
||||
<div className="content-inner">
|
||||
<div data-elementor-type="wp-page" data-elementor-id="86" className="elementor elementor-86 elementor-59">
|
||||
|
||||
15
src/app/air-freight/page.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { permanentRedirect } from "next/navigation";
|
||||
|
||||
export const metadata = {
|
||||
alternates: {
|
||||
canonical: "https://doormile.com/doormile-wings",
|
||||
},
|
||||
robots: {
|
||||
index: false,
|
||||
follow: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default function AirFreightRedirectPage() {
|
||||
permanentRedirect("/doormile-wings");
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { getPostBySlug, getAllSlugs, SITE_URL } from "@/data/blog";
|
||||
|
||||
type Params = { slug: string };
|
||||
|
||||
// Required for `output: "export"` — prerender every post at build time.
|
||||
// Required for `output: "export"`: prerender every post at build time.
|
||||
export function generateStaticParams(): Params[] {
|
||||
return getAllSlugs().map((slug) => ({ slug }));
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@ import BlogGrid from "@/components/sections/BlogGrid";
|
||||
|
||||
export const metadata = {
|
||||
title: "Blog – Doormile",
|
||||
description: "Insights and logistics intelligence from the team behind Doormile. Learn how AI is transforming EV planning and last-mile operations.",
|
||||
description: "Practical notes on delivery planning, EV fleet operations, route optimisation, charging, and last-mile performance from the Doormile team.",
|
||||
};
|
||||
|
||||
export default function BlogPage() {
|
||||
return (
|
||||
<div className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div id="blogs" className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div className="content">
|
||||
<div className="content-inner">
|
||||
<div data-elementor-type="wp-page" data-elementor-id="104" className="elementor elementor-104">
|
||||
|
||||
62
src/app/doormile-wings/page.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import AirFreightHero from "@/components/sections/AirFreightHero";
|
||||
import AirFreightServices from "@/components/sections/AirFreightServices";
|
||||
import AirFreightAdvantages from "@/components/sections/AirFreightAdvantages";
|
||||
import AirFreightCoverage from "@/components/sections/AirFreightCoverage";
|
||||
import AirFreightWorkflow from "@/components/sections/AirFreightWorkflow";
|
||||
import AirFreightFleet from "@/components/sections/AirFreightFleet";
|
||||
import AirFreightBenefits from "@/components/sections/AirFreightBenefits";
|
||||
import AirFreightBanner from "@/components/sections/AirFreightBanner";
|
||||
import AirFreightFAQ from "@/components/sections/AirFreightFAQ";
|
||||
import AirFreightCTA from "@/components/sections/AirFreightCTA";
|
||||
|
||||
export const metadata = {
|
||||
title: "Doormile Wings – Doormile",
|
||||
description: "Doormile Wings delivers precision cargo solutions — express air cargo, charter capacity, cold chain, and customs clearance — across domestic and international trade lanes.",
|
||||
alternates: {
|
||||
canonical: "https://doormile.com/doormile-wings",
|
||||
},
|
||||
openGraph: {
|
||||
title: "Doormile Wings – Doormile",
|
||||
description: "Precision air cargo solutions across India and 60+ countries. Guaranteed transit times, real-time tracking, and full customs management from a single partner.",
|
||||
url: "https://doormile.com/doormile-wings",
|
||||
siteName: "Doormile",
|
||||
type: "website",
|
||||
images: [
|
||||
{
|
||||
url: "https://doormile.com/images/air-freight-slide-1.jpg",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: "Doormile Wings precision cargo solutions",
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "Doormile Wings – Doormile",
|
||||
description: "Precision air cargo solutions across India and 60+ countries. Guaranteed transit times, real-time tracking, full customs management.",
|
||||
images: ["https://doormile.com/images/air-freight-slide-1.jpg"],
|
||||
},
|
||||
};
|
||||
|
||||
export default function AirFreightPage() {
|
||||
return (
|
||||
<div id="doormile-wings" className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div className="content">
|
||||
<div className="content-inner">
|
||||
<div data-elementor-type="wp-page" data-elementor-id="95" className="elementor elementor-95 elementor-59">
|
||||
<AirFreightHero />
|
||||
<AirFreightServices />
|
||||
<AirFreightAdvantages />
|
||||
<AirFreightCoverage />
|
||||
<AirFreightWorkflow />
|
||||
<AirFreightFleet />
|
||||
<AirFreightBenefits />
|
||||
<AirFreightBanner />
|
||||
<AirFreightFAQ />
|
||||
<AirFreightCTA />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
133
src/app/express/page.tsx
Normal file
@@ -0,0 +1,133 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Express – Doormile",
|
||||
description: "Doormile Express — a fast-lane logistics service for time-critical shipments. Coming soon.",
|
||||
alternates: {
|
||||
canonical: "https://doormile.com/express",
|
||||
},
|
||||
robots: {
|
||||
index: false,
|
||||
follow: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default function ExpressPage() {
|
||||
return (
|
||||
<div id="express" className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div className="content">
|
||||
<div className="content-inner">
|
||||
<section className="express-coming-soon">
|
||||
<div className="express-coming-soon-inner">
|
||||
<span className="express-coming-soon-eyebrow">Solutions / Express</span>
|
||||
<h1 className="express-coming-soon-heading">
|
||||
Doormile Express is <span className="express-coming-soon-accent">on its way</span>
|
||||
</h1>
|
||||
<p className="express-coming-soon-text">
|
||||
We're building a fast-lane logistics service for time-critical shipments.
|
||||
Check back soon, or explore what Doormile already delivers today.
|
||||
</p>
|
||||
<div className="express-coming-soon-actions">
|
||||
<Link href="/doormile-wings" prefetch className="logico-alter-button">
|
||||
Explore Doormile Wings
|
||||
</Link>
|
||||
<Link href="/contact" className="express-coming-soon-link">
|
||||
Get notified when we launch →
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Self-contained placeholder styling, scoped to .express-coming-soon.
|
||||
Re-declares --logico-dark-text-color/--logico-light-text-color/
|
||||
--logico-accent-color locally: the sitewide :root fallback is the
|
||||
light-theme value (dark text on white), which would render near-
|
||||
black text on this dark section without the override. */}
|
||||
<style
|
||||
suppressHydrationWarning
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
.express-coming-soon {
|
||||
--logico-dark-text-color: #ffffff;
|
||||
--logico-light-text-color: #bebebe;
|
||||
--logico-accent-color: #C01227;
|
||||
min-height: calc(100vh - 160px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: clamp(48px, 8vw, 120px) 24px;
|
||||
background: radial-gradient(120% 120% at 50% 0%, rgba(192, 18, 39, 0.18) 0%, rgba(26, 26, 26, 0.98) 55%, #111111 100%);
|
||||
}
|
||||
.express-coming-soon-inner {
|
||||
max-width: 720px;
|
||||
text-align: center;
|
||||
}
|
||||
.express-coming-soon-eyebrow {
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
color: var(--logico-accent-color);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.express-coming-soon-heading {
|
||||
font-family: 'Manrope', sans-serif;
|
||||
font-size: clamp(32px, 5vw, 56px);
|
||||
line-height: 1.15em;
|
||||
font-weight: 700;
|
||||
color: var(--logico-dark-text-color);
|
||||
margin: 0 0 20px;
|
||||
}
|
||||
.express-coming-soon-accent {
|
||||
color: var(--logico-accent-color);
|
||||
}
|
||||
.express-coming-soon-text {
|
||||
font-size: 16px;
|
||||
line-height: 1.75em;
|
||||
color: var(--logico-light-text-color);
|
||||
margin: 0 auto 36px;
|
||||
max-width: 520px;
|
||||
}
|
||||
.express-coming-soon-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
}
|
||||
.express-coming-soon .logico-alter-button {
|
||||
color: #ffffff !important;
|
||||
border-color: rgba(255, 255, 255, 0.45) !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
.express-coming-soon .logico-alter-button:hover {
|
||||
background: #ffffff !important;
|
||||
color: #1a1a1a !important;
|
||||
border-color: #ffffff !important;
|
||||
}
|
||||
.express-coming-soon-link {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--logico-light-text-color);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
.express-coming-soon-link:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.express-coming-soon-actions {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -25,6 +25,7 @@ html {
|
||||
--space-section: clamp(40px, 5vw, 64px);
|
||||
--space-section-lg: clamp(52px, 6vw, 80px);
|
||||
--space-hero-gap: clamp(36px, 4.5vw, 64px);
|
||||
--dm-mobile-gutter: 10px;
|
||||
}
|
||||
|
||||
.dm-section {
|
||||
@@ -460,7 +461,7 @@ body {
|
||||
@media (max-width: 720px) {
|
||||
.dm-contact-left {
|
||||
min-height: auto;
|
||||
padding: 42px 22px 58px;
|
||||
padding: 42px 20px 58px;
|
||||
}
|
||||
|
||||
.dm-contact-title {
|
||||
@@ -478,43 +479,43 @@ body {
|
||||
}
|
||||
|
||||
.dm-contact-card {
|
||||
margin: 0 16px 32px;
|
||||
padding: 44px 22px 34px;
|
||||
border-radius: 24px;
|
||||
margin: 0 20px 28px;
|
||||
padding: 28px 20px 24px;
|
||||
border-radius: 28px;
|
||||
}
|
||||
|
||||
.dm-contact-card h3 {
|
||||
margin-bottom: 34px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.dm-contact-form {
|
||||
gap: 20px;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.dm-contact-form input {
|
||||
height: 60px;
|
||||
padding: 0 20px;
|
||||
height: 56px;
|
||||
padding: 0 18px;
|
||||
}
|
||||
|
||||
.dm-contact-form textarea {
|
||||
min-height: 190px;
|
||||
padding: 20px;
|
||||
min-height: 170px;
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.dm-contact-submit {
|
||||
width: 100%;
|
||||
height: 64px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.dm-contact-submit span:first-child {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
padding: 0 22px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.dm-contact-submit-icon {
|
||||
width: 64px;
|
||||
min-width: 64px;
|
||||
width: 60px;
|
||||
min-width: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,7 +538,139 @@ body {
|
||||
.industry-solutions-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}.industry-card-link {
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-3b4a7cc {
|
||||
--padding-left: 0px !important;
|
||||
--padding-right: 0px !important;
|
||||
padding-left: 0px !important;
|
||||
padding-right: 0px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-3b4a7cc > .e-con-inner {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-3b4a7cc > .e-con-inner {
|
||||
max-width: 100% !important;
|
||||
width: 100% !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-d602f7f {
|
||||
--padding-left: 20px !important;
|
||||
--padding-right: 20px !important;
|
||||
padding-left: 20px !important;
|
||||
padding-right: 20px !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin-left: 0 !important;
|
||||
margin-right: 0 !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-f64bd88,
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-5ed2dbb,
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-6829276 {
|
||||
--padding-left: 0px !important;
|
||||
--padding-right: 0px !important;
|
||||
--margin-left: 0px !important;
|
||||
--margin-right: 0px !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin-left: 0 !important;
|
||||
margin-right: 0 !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-6829276 {
|
||||
--e-con-grid-template-columns: minmax(0, 1fr) !important;
|
||||
--grid-justify-content: stretch !important;
|
||||
--justify-items: stretch !important;
|
||||
grid-template-columns: minmax(0, 1fr) !important;
|
||||
justify-content: stretch !important;
|
||||
justify-items: stretch !important;
|
||||
min-width: 0 !important;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .industry-solutions-grid,
|
||||
.elementor.elementor-61 .industry-card-link {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .industry-solutions-grid {
|
||||
margin-left: 0 !important;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-89a0ca1,
|
||||
.elementor.elementor-86 .elementor-element.elementor-element-c2c601a,
|
||||
.elementor.elementor-104 .elementor-element.elementor-element-c70681e {
|
||||
--padding-left: var(--dm-mobile-gutter) !important;
|
||||
--padding-right: var(--dm-mobile-gutter) !important;
|
||||
padding-left: var(--dm-mobile-gutter) !important;
|
||||
padding-right: var(--dm-mobile-gutter) !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-89a0ca1 > .e-con-inner,
|
||||
.elementor.elementor-86 .elementor-element.elementor-element-c2c601a > .e-con-inner,
|
||||
.elementor.elementor-104 .elementor-element.elementor-element-c70681e > .e-con-inner {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.elementor.elementor-61 .elementor-element.elementor-element-89a0ca1 > .e-con-inner > .e-con,
|
||||
.elementor.elementor-86 .elementor-element.elementor-element-c2c601a > .e-con-inner > .e-con,
|
||||
.elementor.elementor-104 .elementor-element.elementor-element-c70681e > .e-con-inner > .e-con {
|
||||
--padding-left: 0px !important;
|
||||
--padding-right: 0px !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.comparison-section .container {
|
||||
width: calc(100% - (var(--dm-mobile-gutter) * 2)) !important;
|
||||
max-width: calc(100% - (var(--dm-mobile-gutter) * 2)) !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.wcd-inner {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
}
|
||||
|
||||
.industry-card-link {
|
||||
position: relative;
|
||||
height: 600px;
|
||||
border-radius: 30px;
|
||||
@@ -831,6 +964,36 @@ body {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
SHARED PAGE CONTENT CONTAINER
|
||||
Mirrors the site's e-con-boxed > e-con-inner system: 1480px
|
||||
max-width centred with fluid horizontal padding identical to the
|
||||
Industry Solutions / OurTeam override above. Apply this class to
|
||||
any section's inner container div to guarantee that content edges
|
||||
line up with every other page section (Home, About, Solutions…).
|
||||
============================================================ */
|
||||
.dm-section-container {
|
||||
max-width: 1480px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Doormile Wings hero frame: the generic vendor CSS assigns 32px padding to
|
||||
.elementor-element-741f56c on all pages; Home's frame is 20px (scoped
|
||||
to .elementor-61). Scope the same 20px frame to the Doormile Wings hero so
|
||||
the card alignment matches Home and Solutions exactly. */
|
||||
@media (min-width: 1025px) {
|
||||
.af-hero-page.elementor-element-741f56c {
|
||||
--padding-top: 20px;
|
||||
--padding-right: 20px;
|
||||
--padding-bottom: 20px;
|
||||
--padding-left: 20px;
|
||||
padding: 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom premium animations keyframes */
|
||||
@keyframes shimmer-sweep {
|
||||
0% {
|
||||
@@ -899,12 +1062,14 @@ body {
|
||||
to 600px at <= 840px. Earlier this card shrank at <= 1536px, which is why the
|
||||
About hero looked smaller than Home on MacBook M1/Pro (their ~1440-1512px logical
|
||||
width falls below 1536px). Match the home breakpoint instead. */
|
||||
@media (max-width: 840px) {
|
||||
@media (max-width: 1024px) {
|
||||
.custom-standard-hero-container {
|
||||
/* No top gap on mobile: the hero card sits flush to the top so the floating
|
||||
/* No top gap on mobile/tablet: the hero card sits flush to the top so the floating
|
||||
navbar rests directly on the hero instead of leaving a band above it. */
|
||||
padding: 0 10px 10px 10px !important;
|
||||
}
|
||||
}
|
||||
@media (max-width: 840px) {
|
||||
.custom-standard-hero-card {
|
||||
height: 600px !important;
|
||||
min-height: 600px !important;
|
||||
@@ -912,6 +1077,81 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile hero/header normalization
|
||||
Home is the reference: at phone width the hero wrapper is full-width with
|
||||
10px side gutters, the visible hero card is 370px wide, starts 7px from the
|
||||
viewport top, and the first section begins immediately after the hero wrapper.
|
||||
Apply those same computed values to every hero template instead of carrying
|
||||
separate page-level mobile overrides. */
|
||||
@media (max-width: 840px) {
|
||||
body .elementor .elementor-element.elementor-element-741f56c,
|
||||
body .custom-standard-hero-container,
|
||||
body .miletruth-hero .elementor-element.elementor-element-86f3204 {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
padding: 0 var(--dm-mobile-gutter) var(--dm-mobile-gutter) var(--dm-mobile-gutter) !important;
|
||||
--padding-top: 0px !important;
|
||||
--padding-right: var(--dm-mobile-gutter) !important;
|
||||
--padding-bottom: var(--dm-mobile-gutter) !important;
|
||||
--padding-left: var(--dm-mobile-gutter) !important;
|
||||
--padding-block-start: 0px !important;
|
||||
box-sizing: border-box !important;
|
||||
border-radius: 0 !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
body .elementor .elementor-element.elementor-element-6c7cbcb .owl-stage-outer,
|
||||
body .custom-standard-hero-card,
|
||||
body .miletruth-hero .miletruth-hero-container {
|
||||
width: 100% !important;
|
||||
height: 600px !important;
|
||||
min-height: 600px !important;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
border-radius: 25px !important;
|
||||
overflow: hidden !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
body .elementor .elementor-element.elementor-element-6c7cbcb .owl-carousel.owl-theme .content-item,
|
||||
body .elementor .elementor-element.elementor-element-6c7cbcb .content-item,
|
||||
body .miletruth-hero .slide-content {
|
||||
height: 600px !important;
|
||||
min-height: 600px !important;
|
||||
}
|
||||
|
||||
body .elementor .elementor-element.elementor-element-741f56c + *,
|
||||
body .custom-standard-hero-container + *,
|
||||
body .elementor-63.miletruth-hero + * {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
body .elementor .elementor-element.elementor-element-6c7cbcb .owl-stage-outer,
|
||||
body .custom-standard-hero-card,
|
||||
body .miletruth-hero .miletruth-hero-container {
|
||||
height: 520px !important;
|
||||
min-height: 520px !important;
|
||||
margin-top: 7px !important;
|
||||
border-radius: 25px !important;
|
||||
}
|
||||
|
||||
body .elementor .elementor-element.elementor-element-6c7cbcb .owl-carousel.owl-theme .content-item,
|
||||
body .elementor .elementor-element.elementor-element-6c7cbcb .content-item,
|
||||
body .miletruth-hero .slide-content {
|
||||
height: 520px !important;
|
||||
min-height: 520px !important;
|
||||
}
|
||||
|
||||
body .miletruth-hero .miletruth-hero-container {
|
||||
padding-top: 60px !important;
|
||||
padding-bottom: 60px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Consistent flush hero across every page on mobile/tablet — the floating navbar
|
||||
(position:absolute; top:5px) should rest directly on the hero with no band
|
||||
above it. Home / How It Works / Solutions share .elementor-element-741f56c;
|
||||
@@ -929,5 +1169,30 @@ body {
|
||||
.miletruth-hero-container {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Audit & align section rhythm on mobile/tablet across all content pages */
|
||||
.elementor-86 #women-entrepreneurship.elementor-element-bbc6760,
|
||||
.elementor-86 .comparison-section,
|
||||
.elementor-86 .elementor-element.elementor-element-bbc6760:not(#women-entrepreneurship),
|
||||
.elementor-86 .elementor-element.elementor-element-c2c601a,
|
||||
.elementor-59 .elementor-element.elementor-element-bbc6760,
|
||||
.elementor-104 .elementor-element.elementor-element-c70681e {
|
||||
margin-top: var(--space-section) !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* Solutions page: First section under Solutions Hero gets the hero gap */
|
||||
.elementor-59 .elementor-element.elementor-element-3b4a7cc {
|
||||
margin-top: var(--space-hero-gap) !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* About page: First section under About Hero gets the hero gap */
|
||||
.elementor-86 .elementor-element.elementor-element-88745f4:first-of-type {
|
||||
margin-top: var(--space-hero-gap) !important;
|
||||
}
|
||||
/* About page: Subsequent sections get standard section spacing */
|
||||
.elementor-86 .elementor-element.elementor-element-88745f4 ~ .elementor-element.elementor-element-88745f4 {
|
||||
margin-top: var(--space-section) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export const metadata = {
|
||||
|
||||
export default function HowItWorksPage() {
|
||||
return (
|
||||
<div className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div id="how-it-works" className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div className="content">
|
||||
<div className="content-inner">
|
||||
<div data-elementor-type="wp-page" data-elementor-id="59" className="elementor elementor-59">
|
||||
|
||||
@@ -90,7 +90,7 @@ export default function RootLayout({
|
||||
│ └─ footer
|
||||
SSR ships body with shared WP/Elementor classes; BodyClasses (client) refines per route.
|
||||
*/}
|
||||
<body className={SHARED_BODY_CLASSES}>
|
||||
<body className={SHARED_BODY_CLASSES} suppressHydrationWarning>
|
||||
<BodyClasses />
|
||||
<LoadingScreen />
|
||||
<AnimationProvider>
|
||||
|
||||
@@ -11,7 +11,7 @@ export const metadata = {
|
||||
|
||||
export default function MileTruthPage() {
|
||||
return (
|
||||
<div className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div id="miletruth" className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div className="content">
|
||||
<div className="content-inner">
|
||||
<div data-elementor-type="wp-page" data-elementor-id="59" className="elementor elementor-59">
|
||||
|
||||
@@ -17,7 +17,7 @@ export const metadata: Metadata = {
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div id="home" className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div className="content">
|
||||
<div className="content-inner">
|
||||
<div data-elementor-type="wp-page" data-elementor-id="61" className="elementor elementor-61">
|
||||
|
||||
80
src/app/sitemap.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
export const dynamic = "force-static";
|
||||
|
||||
const BASE_URL = "https://doormile.com";
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
const now = new Date();
|
||||
|
||||
const staticRoutes: MetadataRoute.Sitemap = [
|
||||
{
|
||||
url: `${BASE_URL}/`,
|
||||
lastModified: now,
|
||||
changeFrequency: "weekly",
|
||||
priority: 1.0,
|
||||
},
|
||||
{
|
||||
url: `${BASE_URL}/how-it-works`,
|
||||
lastModified: now,
|
||||
changeFrequency: "monthly",
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${BASE_URL}/miletruth`,
|
||||
lastModified: now,
|
||||
changeFrequency: "monthly",
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${BASE_URL}/solutions`,
|
||||
lastModified: now,
|
||||
changeFrequency: "monthly",
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${BASE_URL}/doormile-wings`,
|
||||
lastModified: now,
|
||||
changeFrequency: "monthly",
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${BASE_URL}/about-us`,
|
||||
lastModified: now,
|
||||
changeFrequency: "monthly",
|
||||
priority: 0.7,
|
||||
},
|
||||
{
|
||||
url: `${BASE_URL}/blog`,
|
||||
lastModified: now,
|
||||
changeFrequency: "weekly",
|
||||
priority: 0.7,
|
||||
},
|
||||
{
|
||||
url: `${BASE_URL}/contact`,
|
||||
lastModified: now,
|
||||
changeFrequency: "yearly",
|
||||
priority: 0.6,
|
||||
},
|
||||
{
|
||||
url: `${BASE_URL}/privacy-policy`,
|
||||
lastModified: now,
|
||||
changeFrequency: "yearly",
|
||||
priority: 0.3,
|
||||
},
|
||||
{
|
||||
url: `${BASE_URL}/terms-of-service`,
|
||||
lastModified: now,
|
||||
changeFrequency: "yearly",
|
||||
priority: 0.3,
|
||||
},
|
||||
{
|
||||
url: `${BASE_URL}/cookie-policy`,
|
||||
lastModified: now,
|
||||
changeFrequency: "yearly",
|
||||
priority: 0.3,
|
||||
},
|
||||
];
|
||||
|
||||
return staticRoutes;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ export default function SolutionsPage() {
|
||||
}
|
||||
`}} />
|
||||
|
||||
<div className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div id="solutions" className="content-wrapper content-wrapper-may-contain-elementor-code content-wrapper-sidebar-position-none">
|
||||
<div className="content">
|
||||
<div className="content-inner">
|
||||
<div data-elementor-type="wp-page" data-elementor-id="59" className="elementor elementor-59">
|
||||
|
||||
@@ -6,7 +6,7 @@ import { blogPosts } from "@/data/blog";
|
||||
|
||||
/**
|
||||
* Client-side blog search. The site is a static export, so there is no search
|
||||
* server — we filter the known posts in the browser and link straight to the
|
||||
* server. We filter the known posts in the browser and link straight to the
|
||||
* matching /blog/[slug] routes.
|
||||
*/
|
||||
export default function BlogSearch() {
|
||||
|
||||
@@ -72,10 +72,10 @@ export default function BlogSidebar({ current }: { current?: BlogPost }) {
|
||||
|
||||
{/* CTA Card */}
|
||||
<section className="dm-blog-widget dm-blog-cta-card">
|
||||
<h2 className="dm-blog-cta-title">Ready to optimise your fleet?</h2>
|
||||
<h2 className="dm-blog-cta-title">Planning delivery routes?</h2>
|
||||
<p className="dm-blog-cta-text">
|
||||
See how MileTruth™ AI cuts distance, vehicles and emissions — without
|
||||
missing an SLA.
|
||||
Talk to us about reducing wasted distance, missed windows, and avoidable
|
||||
vehicle time.
|
||||
</p>
|
||||
<Link href="/contact" className="dm-blog-cta-btn">
|
||||
Contact Us
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import emailjs from "@emailjs/browser";
|
||||
import { submitContactForm } from "@/lib/contactForm";
|
||||
import { ScrollReveal } from "@/animations/Reveal";
|
||||
|
||||
export default function Footer() {
|
||||
@@ -53,40 +53,44 @@ export default function Footer() {
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
// EmailJS is fully client-side — only the public-safe credentials are used
|
||||
// (Service ID, Template ID, Public Key). No private/secret key, no backend route.
|
||||
const serviceId = process.env.NEXT_PUBLIC_EMAILJS_SERVICE_ID;
|
||||
const templateId = process.env.NEXT_PUBLIC_EMAILJS_TEMPLATE_ID;
|
||||
const publicKey = process.env.NEXT_PUBLIC_EMAILJS_PUBLIC_KEY;
|
||||
if (!serviceId || !templateId || !publicKey) {
|
||||
console.error("EmailJS env vars are missing — set NEXT_PUBLIC_EMAILJS_* in .env.local");
|
||||
setFormStatus("error");
|
||||
return;
|
||||
}
|
||||
|
||||
setFormStatus("submitting");
|
||||
try {
|
||||
await emailjs.send(
|
||||
serviceId,
|
||||
templateId,
|
||||
{
|
||||
name: formData.fullName,
|
||||
email: formData.email,
|
||||
subject: formData.subject,
|
||||
message: formData.message,
|
||||
},
|
||||
publicKey,
|
||||
);
|
||||
setFormStatus("success");
|
||||
setFormData({ fullName: "", email: "", subject: "", message: "" });
|
||||
const res = await submitContactForm(formData);
|
||||
|
||||
if (res.success) {
|
||||
setFormStatus("success");
|
||||
setFormData({ fullName: "", email: "", subject: "", message: "" });
|
||||
} else {
|
||||
console.error("Failed to submit contact form");
|
||||
setFormStatus("error");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
console.error("Error submitting contact form:", err);
|
||||
setFormStatus("error");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Floating-label fix: the theme only lifts the label on :focus-within, so a
|
||||
filled-but-blurred field drops its label back onto the typed value and the
|
||||
two overlap. Keep the label lifted (and the notch in the top border open)
|
||||
whenever the field carries a value, via the .dm-field-filled class below. */}
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.logico-form-field.dm-field-filled .logico-label-wrapper>label {
|
||||
font-size: 14px;
|
||||
top: -14px;
|
||||
color: var(--logico-dark-text-color);
|
||||
}
|
||||
.logico-form-field.dm-field-filled .logico-label-placeholder .logico-label-placeholder-text:before {
|
||||
right: 100%;
|
||||
left: initial;
|
||||
}
|
||||
.logico-form-field.dm-field-filled .logico-label-placeholder .logico-label-placeholder-text:after {
|
||||
left: 100%;
|
||||
right: initial;
|
||||
}
|
||||
` }} />
|
||||
<footer
|
||||
data-rocket-location-hash="1eeca93394c4fc14089e9d12a2a92e22"
|
||||
itemScope
|
||||
@@ -134,7 +138,7 @@ export default function Footer() {
|
||||
<svg className="dm-foot-ic" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
||||
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z" />
|
||||
</svg>
|
||||
<span>Call Center</span>
|
||||
<span>Contect</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -152,7 +156,7 @@ export default function Footer() {
|
||||
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
|
||||
<circle cx="12" cy="10" r="3" />
|
||||
</svg>
|
||||
<span>Our Location</span>
|
||||
<span>Address</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -197,14 +201,14 @@ export default function Footer() {
|
||||
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49" />
|
||||
<line x1="15.41" y1="6.51" x2="8.59" y2="10.49" />
|
||||
</svg>
|
||||
<span>Social network</span>
|
||||
<span>Social</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="elementor-element elementor-element-a6bccba elementor-shape-square elementor-grid-0 elementor-widget elementor-widget-social-icons" data-id="a6bccba" data-element_type="widget" data-e-type="widget" data-widget_type="social-icons.default">
|
||||
<div className="elementor-widget-container">
|
||||
<div className="elementor-social-icons-wrapper elementor-grid" role="list" style={socialIconSpacing}>
|
||||
<span className="elementor-grid-item" role="listitem" style={{padding:"0 15px"}}>
|
||||
{/* <span className="elementor-grid-item" role="listitem" style={{padding:"0 15px"}}>
|
||||
<a className="elementor-icon elementor-social-icon elementor-social-icon-facebook-f elementor-repeater-item-3fbe893" href="https://www.facebook.com" target="_blank" rel="noopener noreferrer">
|
||||
<span className="elementor-screen-only">Facebook</span>
|
||||
<svg aria-hidden="true" className="e-font-icon-svg e-fab-facebook-f" viewBox="0 0 320 512" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -219,7 +223,7 @@ export default function Footer() {
|
||||
<path d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</span>
|
||||
</span> */}
|
||||
<span className="elementor-grid-item" role="listitem"style={{padding:"0 15px"}}>
|
||||
<a className="elementor-icon elementor-social-icon elementor-social-icon-linkedin-in elementor-repeater-item-38e1bcc" href="https://www.linkedin.com" target="_blank" rel="noopener noreferrer">
|
||||
<span className="elementor-screen-only">LinkedIn</span>
|
||||
@@ -255,7 +259,7 @@ export default function Footer() {
|
||||
<div className="wpforms-container wpforms-render-modern" id="wpforms-369">
|
||||
<form id="wpforms-form-369" className="wpforms-validate wpforms-form" onSubmit={handleSubmit}>
|
||||
<div className="wpforms-field-container">
|
||||
<div className="wpforms-field-wrapper logico-form-field">
|
||||
<div className={`wpforms-field-wrapper logico-form-field${formData.fullName ? " dm-field-filled" : ""}`}>
|
||||
<div className="logico-label-wrapper" style={{marginBottom:"12px"}}>
|
||||
<div className="logico-label-placeholder">
|
||||
<div className="logico-label-placeholder-text">Full name</div>
|
||||
@@ -272,7 +276,7 @@ export default function Footer() {
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="wpforms-field-wrapper logico-form-field">
|
||||
<div className={`wpforms-field-wrapper logico-form-field${formData.email ? " dm-field-filled" : ""}`}>
|
||||
<div className="logico-label-wrapper" style={{marginBottom:"12px"}}>
|
||||
<div className="logico-label-placeholder">
|
||||
<div className="logico-label-placeholder-text">Email</div>
|
||||
@@ -289,7 +293,7 @@ export default function Footer() {
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="wpforms-field-wrapper logico-form-field">
|
||||
<div className={`wpforms-field-wrapper logico-form-field${formData.subject ? " dm-field-filled" : ""}`}>
|
||||
<div className="logico-label-wrapper" style={{marginBottom:"12px"}}>
|
||||
<div className="logico-label-placeholder">
|
||||
<div className="logico-label-placeholder-text">Subject</div>
|
||||
@@ -306,7 +310,7 @@ export default function Footer() {
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="wpforms-field-wrapper logico-form-field">
|
||||
<div className={`wpforms-field-wrapper logico-form-field${formData.message ? " dm-field-filled" : ""}`}>
|
||||
<div className="logico-label-wrapper" style={{marginBottom:"12px"}}>
|
||||
<div className="logico-label-placeholder">
|
||||
<div className="logico-label-placeholder-text">Message</div>
|
||||
@@ -384,7 +388,7 @@ export default function Footer() {
|
||||
<div className="elementor-element elementor-element-e4e6486 elementor-shape-square elementor-grid-0 elementor-widget elementor-widget-social-icons" data-id="e4e6486" data-element_type="widget" data-e-type="widget" data-widget_type="social-icons.default">
|
||||
<div className="elementor-widget-container">
|
||||
<div className="elementor-social-icons-wrapper elementor-grid" role="list" style={socialIconSpacing}>
|
||||
<span className="elementor-grid-item" role="listitem" style={{padding:"0 15px"}}>
|
||||
{/* <span className="elementor-grid-item" role="listitem" style={{padding:"0 15px"}}>
|
||||
<a className="elementor-icon elementor-social-icon elementor-social-icon-facebook-f" href="https://www.facebook.com" target="_blank" rel="noopener noreferrer">
|
||||
<span className="elementor-screen-only">Facebook</span>
|
||||
<svg aria-hidden="true" className="e-font-icon-svg e-fab-facebook-f" viewBox="0 0 320 512" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -399,7 +403,7 @@ export default function Footer() {
|
||||
<path d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</span>
|
||||
</span> */}
|
||||
<span className="elementor-grid-item" role="listitem" style={{padding:"0 15px"}}>
|
||||
<a className="elementor-icon elementor-social-icon elementor-social-icon-linkedin-in" href="https://www.linkedin.com" target="_blank" rel="noopener noreferrer">
|
||||
<span className="elementor-screen-only">LinkedIn</span>
|
||||
@@ -454,6 +458,9 @@ export default function Footer() {
|
||||
<div className="elementor-element elementor-element-a219b7d elementor-widget elementor-widget-logico_custom_navigation_menu" data-id="a219b7d" data-element_type="widget" data-e-type="widget" data-widget_type="logico_custom_navigation_menu.default">
|
||||
<div className="elementor-widget-container">
|
||||
<ul className="logico-custom-menu-widget">
|
||||
<li>
|
||||
<Link href="/doormile-wings">Doormile Wings</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/about-us">About Us</Link>
|
||||
</li>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Menu open/close + sidebar state is read from HeaderUIProvider so BodyOverlay (sibling at body level) can react.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { KeyboardEvent, FocusEvent, MouseEvent, useEffect, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { usePathname } from "next/navigation";
|
||||
@@ -19,6 +19,8 @@ const CURRENT_PAGE_MAP: Record<string, string> = {
|
||||
"/how-it-works": "how-it-works",
|
||||
"/miletruth": "miletruth",
|
||||
"/solutions": "solutions",
|
||||
"/doormile-wings": "doormile-wings",
|
||||
"/express": "express",
|
||||
"/about-us": "about",
|
||||
"/blog": "blogs",
|
||||
};
|
||||
@@ -28,7 +30,9 @@ const CURRENT_PAGE_ALIASES: Record<string, string[]> = {
|
||||
home: ["home"],
|
||||
"how-it-works": ["how-it-works", "how-its-works"],
|
||||
miletruth: ["miletruth"],
|
||||
solutions: ["solutions"],
|
||||
// Solutions is a normal nav page and also owns the Wings/Express dropdown.
|
||||
solutions: ["solutions", "doormile-wings", "express"],
|
||||
"doormile-wings": ["doormile-wings"],
|
||||
about: ["about", "about-us", "women"],
|
||||
blogs: ["blogs"],
|
||||
};
|
||||
@@ -44,12 +48,57 @@ export default function Header() {
|
||||
const dmHeaderActive = (key: string) =>
|
||||
(CURRENT_PAGE_ALIASES[key] ?? []).includes(currentPage) ? " active" : "";
|
||||
|
||||
const scrollToNavTarget = (targetId: string) => {
|
||||
const target = document.getElementById(targetId);
|
||||
if (target) {
|
||||
target.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
return;
|
||||
}
|
||||
|
||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||
};
|
||||
|
||||
const handleNavClick = (
|
||||
event: MouseEvent<HTMLAnchorElement>,
|
||||
targetPath: string,
|
||||
targetId: string,
|
||||
shouldCloseMenu = false,
|
||||
) => {
|
||||
if (shouldCloseMenu) closeMobileMenu();
|
||||
|
||||
if (pathname !== targetPath) return;
|
||||
|
||||
event.preventDefault();
|
||||
const targetUrl = `${targetPath}#${targetId}`;
|
||||
if (`${window.location.pathname}${window.location.hash}` !== targetUrl) {
|
||||
window.history.pushState(null, "", targetUrl);
|
||||
}
|
||||
requestAnimationFrame(() => scrollToNavTarget(targetId));
|
||||
};
|
||||
|
||||
// Mirror of header.php <script> block (lines 628-660):
|
||||
// - on doc.ready: $('.header-hide-until-scroll').addClass('header-visible-scrolled')
|
||||
// - on scroll: toggleClass('dm-header-scrolled', scrollTop > 50)
|
||||
const [visibleScrolled, setVisibleScrolled] = useState(false);
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
|
||||
// Solutions dropdown (desktop) / accordion (mobile). Local to Header —
|
||||
// unlike isMenuOpen/isSidebarOpen (HeaderUIProvider), no sibling component
|
||||
// needs to read this.
|
||||
const [isDesktopSolutionsOpen, setDesktopSolutionsOpen] = useState(false);
|
||||
const [isMobileSolutionsOpen, setMobileSolutionsOpen] = useState(false);
|
||||
|
||||
// Collapse the accordion whenever the off-canvas menu closes, so it isn't
|
||||
// left expanded the next time the menu opens.
|
||||
const closeMobileMenu = () => {
|
||||
setMobileSolutionsOpen(false);
|
||||
closeAll();
|
||||
};
|
||||
const toggleMobileMenu = () => {
|
||||
setMobileSolutionsOpen(false);
|
||||
toggleMenu();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handle = requestAnimationFrame(() => {
|
||||
setVisibleScrolled(true);
|
||||
@@ -142,23 +191,26 @@ export default function Header() {
|
||||
>
|
||||
<div className="slide-sidebar-close" onClick={closeAll}></div>
|
||||
<div className="slide-sidebar">
|
||||
<div className="slide-sidebar-content">
|
||||
{/* Header — does not scroll. */}
|
||||
<div className="slide-sidebar-header">
|
||||
<figure className="wp-block-image size-full is-resized">
|
||||
<Image
|
||||
width={305}
|
||||
height={58}
|
||||
src="/images/doormile-logo.png"
|
||||
alt="Doormile logo"
|
||||
className="wp-image-5851"
|
||||
style={{ width: "210px", height: "auto" }}
|
||||
sizes="(max-width: 305px) 100vw, 305px"
|
||||
/>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
{/* Scrollable content — tabIndex makes it keyboard-scrollable. */}
|
||||
<div className="slide-sidebar-content" tabIndex={0} role="region" aria-label="Menu content">
|
||||
<div id="block-37" className="widget widget_block">
|
||||
<div className="widget-wrapper">
|
||||
<div className="dm-block-group is-layout-constrained dm-block-group-is-layout-constrained">
|
||||
<figure className="wp-block-image size-full is-resized">
|
||||
<Image
|
||||
width={305}
|
||||
height={58}
|
||||
src="/images/doormile-logo.png"
|
||||
alt="Doormile logo"
|
||||
className="wp-image-5851"
|
||||
style={{ width: "150px", height: "auto" }}
|
||||
sizes="(max-width: 305px) 100vw, 305px"
|
||||
/>
|
||||
</figure>
|
||||
|
||||
<div style={{ height: "46px" }} aria-hidden="true" className="wp-block-spacer"></div>
|
||||
|
||||
<div className="wp-block-title">
|
||||
<h6
|
||||
@@ -171,11 +223,87 @@ export default function Header() {
|
||||
textTransform: "none",
|
||||
}}
|
||||
>
|
||||
Our Location
|
||||
Address
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
<p>5th Floor, Vision Ultima, Street No.3, Jayabheri Enclave, Gachibowli, Hyderabad, Telangana 500032.</p>
|
||||
<h6
|
||||
className="wp-block-heading has-text-font-font-family"
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
fontStyle: "normal",
|
||||
fontWeight: 700,
|
||||
letterSpacing: "0px",
|
||||
textTransform: "none",
|
||||
}}
|
||||
>
|
||||
Hyderabad
|
||||
</h6>
|
||||
<p>
|
||||
5th Floor, Vision Ultima,
|
||||
<br />
|
||||
Street No.3, Jayabheri Enclave,
|
||||
<br />
|
||||
Gachibowli, Hyderabad,
|
||||
<br />
|
||||
Telangana 500032.
|
||||
</p>
|
||||
|
||||
<div style={{ height: "12px" }} aria-hidden="true" className="wp-block-spacer"></div>
|
||||
|
||||
<h6
|
||||
className="wp-block-heading has-text-font-font-family"
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
fontStyle: "normal",
|
||||
fontWeight: 700,
|
||||
letterSpacing: "0px",
|
||||
textTransform: "none",
|
||||
}}
|
||||
>
|
||||
Coimbatore
|
||||
</h6>
|
||||
<p>
|
||||
Mayflower Valencia,
|
||||
<br />
|
||||
Near Nava India Bus Stop,
|
||||
<br />
|
||||
Avinashi Road,
|
||||
<br />
|
||||
Udayampalayam,
|
||||
<br />
|
||||
Tamil Nadu 641037.
|
||||
</p>
|
||||
|
||||
<div style={{ height: "12px" }} aria-hidden="true" className="wp-block-spacer"></div>
|
||||
|
||||
<h6
|
||||
className="wp-block-heading has-text-font-font-family"
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
fontStyle: "normal",
|
||||
fontWeight: 700,
|
||||
letterSpacing: "0px",
|
||||
textTransform: "none",
|
||||
}}
|
||||
>
|
||||
Bengaluru
|
||||
</h6>
|
||||
<p>
|
||||
C612, 6th Floor,
|
||||
<br />
|
||||
Trifecta Starlight,
|
||||
<br />
|
||||
ITPL Road,
|
||||
<br />
|
||||
Garudacharapalya,
|
||||
<br />
|
||||
Mahadevapura,
|
||||
<br />
|
||||
Bangalore 560048,
|
||||
<br />
|
||||
Karnataka, India.
|
||||
</p>
|
||||
|
||||
<div style={{ height: "3px" }} aria-hidden="true" className="wp-block-spacer"></div>
|
||||
|
||||
@@ -272,19 +400,21 @@ export default function Header() {
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div style={{ height: "137px" }} aria-hidden="true" className="wp-block-spacer"></div>
|
||||
|
||||
<div className="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
|
||||
<div className="wp-block-button is-style-simple is-style-theme">
|
||||
<Link href="/contact" className="wp-block-button__link wp-element-button" style={{ borderRadius: "10px" }}>
|
||||
Get in touch
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CTA — pinned at the bottom; never scrolls away. */}
|
||||
<div className="slide-sidebar-cta">
|
||||
<div className="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
|
||||
<div className="wp-block-button is-style-simple is-style-theme">
|
||||
<Link href="/contact" className="wp-block-button__link wp-element-button" style={{ borderRadius: "10px" }}>
|
||||
Get in touch
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -325,27 +455,63 @@ export default function Header() {
|
||||
<nav>
|
||||
<ul id="menu-main-menu" className="main-menu">
|
||||
<li id="menu-item-10508" className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10508${dmHeaderActive("home")}`}>
|
||||
<Link href="/">Home</Link>
|
||||
<Link href="/#home" onClick={(event) => handleNavClick(event, "/", "home")}>Home</Link>
|
||||
</li>
|
||||
<li id="menu-item-10509" className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10509${dmHeaderActive("how-it-works")}`}>
|
||||
<Link href="/how-it-works">How It Works</Link>
|
||||
<Link href="/how-it-works#how-it-works" onClick={(event) => handleNavClick(event, "/how-it-works", "how-it-works")}>How It Works</Link>
|
||||
</li>
|
||||
<li id="menu-item-10510" className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10510${dmHeaderActive("miletruth")}`}>
|
||||
<Link href="/miletruth">MileTruth™ AI</Link>
|
||||
<Link href="/miletruth#miletruth" onClick={(event) => handleNavClick(event, "/miletruth", "miletruth")}>MileTruth™ AI</Link>
|
||||
</li>
|
||||
<li id="menu-item-10511" className={`menu-item menu-item-type-custom menu-item-10511${dmHeaderActive("solutions")}`}>
|
||||
<Link href="/solutions">Solutions</Link>
|
||||
<li
|
||||
id="menu-item-10511"
|
||||
className={`menu-item menu-item-type-custom menu-item-has-children menu-item-10511${dmHeaderActive("solutions")}`}
|
||||
onMouseEnter={() => setDesktopSolutionsOpen(true)}
|
||||
onMouseLeave={() => setDesktopSolutionsOpen(false)}
|
||||
onKeyDown={(event: KeyboardEvent<HTMLLIElement>) => {
|
||||
if (event.key !== "Escape") return;
|
||||
setDesktopSolutionsOpen(false);
|
||||
event.currentTarget.querySelector<HTMLAnchorElement>(":scope > a")?.focus();
|
||||
}}
|
||||
onBlur={(event: FocusEvent<HTMLLIElement>) => {
|
||||
if (!event.currentTarget.contains(event.relatedTarget as Node)) {
|
||||
setDesktopSolutionsOpen(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
href="/solutions"
|
||||
prefetch
|
||||
aria-haspopup="true"
|
||||
aria-expanded={isDesktopSolutionsOpen}
|
||||
onFocus={() => setDesktopSolutionsOpen(true)}
|
||||
onClick={() => setDesktopSolutionsOpen(false)}
|
||||
>
|
||||
Solutions
|
||||
</Link>
|
||||
<ul className="dm-solutions-dropdown">
|
||||
<li className={currentPage === "doormile-wings" ? "dm-child-active" : ""}>
|
||||
<Link href="/doormile-wings" prefetch onClick={() => setDesktopSolutionsOpen(false)}>
|
||||
Doormile Wings
|
||||
</Link>
|
||||
</li>
|
||||
<li className={currentPage === "express" ? "dm-child-active" : ""}>
|
||||
<Link href="/express" prefetch onClick={() => setDesktopSolutionsOpen(false)}>
|
||||
Express
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="menu-item-10512" className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10512${dmHeaderActive("about")}`}>
|
||||
<Link href="/about-us">About</Link>
|
||||
<Link href="/about-us#about" onClick={(event) => handleNavClick(event, "/about-us", "about")}>About</Link>
|
||||
</li>
|
||||
<li id="menu-item-10535" className={`menu-item menu-item-type-post_type menu-item-object-page menu-item-10535${dmHeaderActive("blogs")}`}>
|
||||
<Link href="/blog">Blogs</Link>
|
||||
<Link href="/blog#blogs" onClick={(event) => handleNavClick(event, "/blog", "blogs")}>Blogs</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div className="menu-trigger" data-id="0b7bf6f" onClick={toggleMenu}>
|
||||
<div className="menu-trigger" data-id="0b7bf6f" onClick={toggleMobileMenu}>
|
||||
<span className="menu-trigger-icon">
|
||||
<span className="hamburger">
|
||||
<span></span>
|
||||
@@ -362,18 +528,10 @@ export default function Header() {
|
||||
>
|
||||
<div className="mobile-header-row">
|
||||
<div className="header-icons-container">
|
||||
<div className="header-icon mini-cart">
|
||||
<a href="#" className="mini-cart-trigger">
|
||||
<i className="mini-cart-count"></i>
|
||||
</a>
|
||||
</div>
|
||||
<a className="header-icon search-link" href="#">
|
||||
<span className="search-trigger-icon"></span>
|
||||
</a>
|
||||
<div className="header-icon login-logout">
|
||||
<a href="#" title="Login/Register" className="link-login"></a>
|
||||
</div>
|
||||
<div className="header-icon menu-close" onClick={closeAll}>
|
||||
<div className="header-icon menu-close" onClick={closeMobileMenu}>
|
||||
<span className="menu-close-icon"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -381,22 +539,46 @@ export default function Header() {
|
||||
<nav>
|
||||
<ul id="menu-main-menu-1" className="main-menu">
|
||||
<li className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10508${dmHeaderActive("home")}`}>
|
||||
<Link href="/" onClick={closeAll}>Home</Link>
|
||||
<Link href="/#home" onClick={(event) => handleNavClick(event, "/", "home", true)}>Home</Link>
|
||||
</li>
|
||||
<li className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10509${dmHeaderActive("how-it-works")}`}>
|
||||
<Link href="/how-it-works" onClick={closeAll}>How It Works</Link>
|
||||
<Link href="/how-it-works#how-it-works" onClick={(event) => handleNavClick(event, "/how-it-works", "how-it-works", true)}>How It Works</Link>
|
||||
</li>
|
||||
<li className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-10510${dmHeaderActive("miletruth")}`}>
|
||||
<Link href="/miletruth" onClick={closeAll}>MileTruth™ AI</Link>
|
||||
<Link href="/miletruth#miletruth" onClick={(event) => handleNavClick(event, "/miletruth", "miletruth", true)}>MileTruth™ AI</Link>
|
||||
</li>
|
||||
<li className={`menu-item menu-item-type-custom menu-item-10511${dmHeaderActive("solutions")}`}>
|
||||
<Link href="/solutions" onClick={closeAll}>Solutions</Link>
|
||||
<li
|
||||
className={`menu-item menu-item-type-custom menu-item-10511 dm-mobile-solutions${dmHeaderActive("solutions")}${isMobileSolutionsOpen ? " dm-accordion-open" : ""}`}
|
||||
>
|
||||
<div className="dm-mobile-solutions-row">
|
||||
<Link href="/solutions" prefetch onClick={closeMobileMenu}>
|
||||
Solutions
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
className="dm-mobile-solutions-toggle"
|
||||
aria-label={isMobileSolutionsOpen ? "Close Solutions menu" : "Open Solutions menu"}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={isMobileSolutionsOpen}
|
||||
onClick={() => setMobileSolutionsOpen((open) => !open)}
|
||||
>
|
||||
<span className="dm-accordion-chevron" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
<ul className="dm-mobile-solutions-panel">
|
||||
<li className={currentPage === "doormile-wings" ? "dm-child-active" : ""}>
|
||||
<Link href="/doormile-wings" prefetch onClick={closeMobileMenu}>Doormile Wings</Link>
|
||||
</li>
|
||||
<li className={currentPage === "express" ? "dm-child-active" : ""}>
|
||||
<Link href="/express" prefetch onClick={closeMobileMenu}>Express</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li className={`menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-10512${dmHeaderActive("about")}`}>
|
||||
<Link href="/about-us" onClick={closeAll}>About</Link>
|
||||
<Link href="/about-us#about" onClick={(event) => handleNavClick(event, "/about-us", "about", true)}>About</Link>
|
||||
</li>
|
||||
<li className={`menu-item menu-item-type-post_type menu-item-object-page menu-item-10535${dmHeaderActive("blogs")}`}>
|
||||
<Link href="/blog" onClick={closeAll}>Blogs</Link>
|
||||
<Link href="/blog#blogs" onClick={(event) => handleNavClick(event, "/blog", "blogs", true)}>Blogs</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -491,6 +673,69 @@ export default function Header() {
|
||||
suppressHydrationWarning
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
/* ── Off-canvas menu: full-height flex column ──
|
||||
Header (logo) at top, scrollable content in the middle, and the
|
||||
"Get in touch" CTA pinned at the bottom — so the panel stays
|
||||
usable however much content (e.g. multiple office addresses) it
|
||||
holds. Scoped to #side-panel-2f31137; no other sidebar is touched.
|
||||
Width, colors, the slide-in animation, and open/close behaviour
|
||||
(driven by the .active class on the wrapper) are all unchanged. */
|
||||
#side-panel-2f31137 .slide-sidebar {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
height: 100% !important;
|
||||
padding: 0 !important; /* the three sections own their padding */
|
||||
overflow: hidden !important; /* scrolling lives on the content area */
|
||||
}
|
||||
/* Fit the *visible* viewport. The panel height is calc(100vh - 20px),
|
||||
but on mobile 100vh is the larger, URL-bar-inclusive height, which
|
||||
pushed the bottom of the scroll list + the CTA below the fold and
|
||||
made scrolling appear broken. dvh tracks the actually-visible area;
|
||||
vh is kept as a fallback for older browsers. */
|
||||
#side-panel-2f31137.slide-sidebar-wrapper {
|
||||
height: calc(100vh - 20px);
|
||||
height: calc(100dvh - 20px) !important;
|
||||
}
|
||||
#side-panel-2f31137 .slide-sidebar-header {
|
||||
flex: 0 0 auto;
|
||||
padding: 52px 36px 18px; /* top clears the floating close button */
|
||||
text-align: center; /* centre the logo */
|
||||
}
|
||||
#side-panel-2f31137 .slide-sidebar-header figure {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
#side-panel-2f31137 .slide-sidebar-header img {
|
||||
display: inline-block; /* centred by the header's text-align */
|
||||
}
|
||||
#side-panel-2f31137 .slide-sidebar-content {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0; /* let the flex child shrink so it can scroll */
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
-webkit-overflow-scrolling: touch; /* momentum scroll on iOS */
|
||||
overscroll-behavior: contain; /* don't chain scroll to the page */
|
||||
padding: 18px 60px 8px; /* top gap below the logo header */
|
||||
}
|
||||
#side-panel-2f31137 .slide-sidebar-content:focus-visible {
|
||||
outline: none; /* container is scroll-focusable, not a control */
|
||||
}
|
||||
#side-panel-2f31137 .slide-sidebar-cta {
|
||||
flex: 0 0 auto;
|
||||
padding: 16px 60px 36px;
|
||||
}
|
||||
/* Compact, readable address blocks (tighter line + lead-in than the
|
||||
default 1.75em body spacing). */
|
||||
#side-panel-2f31137 .slide-sidebar-content p {
|
||||
line-height: 1.5;
|
||||
margin-top: 4px;
|
||||
}
|
||||
/* Larger social icons — the logos-only block style renders them at 18px. */
|
||||
#side-panel-2f31137 .wp-block-social-links.is-style-logos-only .wp-block-social-link a svg {
|
||||
width: 26px !important;
|
||||
height: 26px !important;
|
||||
}
|
||||
|
||||
#masthead .elementor-element.elementor-element-466de1b {
|
||||
position: absolute !important;
|
||||
top: 5px !important;
|
||||
@@ -594,6 +839,22 @@ export default function Header() {
|
||||
}
|
||||
}
|
||||
|
||||
/* Compact nav items at middle desktop widths (8 items fit without overflow).
|
||||
Slightly tighter letter-spacing keeps the active underline animation intact. */
|
||||
@media (min-width: 1025px) and (max-width: 1400px) {
|
||||
#masthead .header-menu-container .main-menu > li > a {
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1025px) and (max-width: 1200px) {
|
||||
#masthead .header-menu-container .main-menu {
|
||||
gap: clamp(4px, 0.8vw, 12px) !important;
|
||||
}
|
||||
#masthead .header-menu-container .main-menu > li > a {
|
||||
font-size: clamp(12px, 0.95vw, 14px);
|
||||
}
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.active > a:before {
|
||||
background-color: #ffffff !important;
|
||||
opacity: 1 !important;
|
||||
@@ -611,6 +872,9 @@ export default function Header() {
|
||||
|
||||
/* Responsive logo adjustment on mobile/tablet */
|
||||
@media (max-width: 1024px) {
|
||||
#masthead .elementor-element.elementor-element-466de1b {
|
||||
top: 18px !important;
|
||||
}
|
||||
#masthead .elementor-element.elementor-element-846e53d .hfe-site-logo .hfe-site-logo-container img {
|
||||
width: 150px !important;
|
||||
height: auto !important;
|
||||
@@ -629,16 +893,22 @@ export default function Header() {
|
||||
to the top once scrolled past 50px, matching desktop behaviour. */
|
||||
#masthead .elementor-element.elementor-element-466de1b.dm-header-scrolled {
|
||||
position: fixed !important;
|
||||
top: 0 !important;
|
||||
top: 18px !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
}
|
||||
|
||||
#masthead .elementor-element.elementor-element-e052838 {
|
||||
margin-left: 0px !important;
|
||||
margin-right: 0px !important;
|
||||
border-radius: 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
#masthead .elementor-element.elementor-element-846e53d .hfe-site-logo .hfe-site-logo-container img {
|
||||
width: 130px !important;
|
||||
margin-left: 10px !important;
|
||||
width: 150px !important;
|
||||
margin-left: 8px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,6 +952,282 @@ export default function Header() {
|
||||
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cline x1='5' y1='5' x2='19' y2='19'/%3E%3Cline x1='19' y1='5' x2='5' y2='19'/%3E%3C/svg%3E");
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cline x1='5' y1='5' x2='19' y2='19'/%3E%3Cline x1='19' y1='5' x2='5' y2='19'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
/* ── Solutions dropdown (desktop) / accordion (mobile) ──
|
||||
Solutions remains linked to /solutions while the nested menu opens
|
||||
independently. It reuses site.css's dead .menu-item-has-children chevron (fontello
|
||||
glyph, already coloured white for this exact header widget) instead
|
||||
of inventing a new arrow, so it matches the site's existing premium
|
||||
nav styling. Desktop opens on hover/focus; mobile is a
|
||||
height-collapsing accordion controlled by the chevron button. */
|
||||
@media (min-width: 1025px) {
|
||||
#masthead .header-menu-container nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu {
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
gap: 16px !important;
|
||||
margin: 0 !important;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li > a {
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-top: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
min-height: 48px;
|
||||
line-height: 1.2 !important;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
min-width: 360px;
|
||||
height: 24px;
|
||||
transform: translateX(-50%);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children .dm-solutions-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 34px);
|
||||
width: 380px;
|
||||
min-width: 380px;
|
||||
margin: 0;
|
||||
padding: 24px 22px;
|
||||
list-style: none;
|
||||
background: linear-gradient(180deg, rgba(31, 31, 31, 0.98) 0%, rgba(18, 18, 18, 0.98) 100%);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
backdrop-filter: blur(20px);
|
||||
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.38), inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.09);
|
||||
border-radius: 18px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
/* .main-menu li:not(:last-of-type) (site.css) is a descendant
|
||||
selector that also matches these nested <li>s, pushing every
|
||||
row but the last 12px to the right. Cancel it here. */
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children .dm-solutions-dropdown li {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children .dm-solutions-dropdown li + li {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children .dm-solutions-dropdown li > a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 12px;
|
||||
height: 76px;
|
||||
padding: 0 34px;
|
||||
border-radius: 12px;
|
||||
/* Hardcoded rather than var(--logico-dark-text-color): that
|
||||
variable is only overridden to white inside a few unrelated
|
||||
scoped contexts (e.g. #side-panel-2f31137) and otherwise
|
||||
falls back to the sitewide light-theme value (#111111),
|
||||
which would be invisible on this dark glass panel. */
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
letter-spacing: normal;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
transition: background-color 0.25s ease, color 0.25s ease, padding-left 0.25s ease;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children .dm-solutions-dropdown li > a:before {
|
||||
content: "";
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
margin-left: -23px;
|
||||
flex: 0 0 11px;
|
||||
background-color: #c01227;
|
||||
opacity: 0;
|
||||
transform: translateX(-10px);
|
||||
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12 12 4'/%3E%3Cpath d='M5 4h7v7'/%3E%3C/svg%3E");
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12 12 4'/%3E%3Cpath d='M5 4h7v7'/%3E%3C/svg%3E");
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-position: center;
|
||||
mask-position: center;
|
||||
-webkit-mask-size: contain;
|
||||
mask-size: contain;
|
||||
transition: opacity 0.25s ease-in-out, transform 0.25s ease-in-out, background-color 0.25s ease-in-out;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children .dm-solutions-dropdown li > a:hover,
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children .dm-solutions-dropdown li > a:focus-visible {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
color: #ffffff;
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children .dm-solutions-dropdown li > a:hover:before,
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children .dm-solutions-dropdown li > a:focus-visible:before {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
background-color: #c01227;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children .dm-solutions-dropdown li.dm-child-active > a {
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children:hover .dm-solutions-dropdown,
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children:focus-within .dm-solutions-dropdown,
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children > a[aria-expanded="true"] ~ .dm-solutions-dropdown {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
pointer-events: auto;
|
||||
transform: translate(-50%, 24px);
|
||||
}
|
||||
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children:hover > a:after,
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children:focus-within > a:after,
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children > a[aria-expanded="true"]:after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* Outlines are globally suppressed for .main-menu>li>a above;
|
||||
restore a visible focus ring scoped only to this trigger. */
|
||||
#masthead .header-menu-container .main-menu > li.menu-item-has-children > a:focus-visible {
|
||||
outline: 2px solid var(--logico-dark-text-color, #ffffff);
|
||||
outline-offset: 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions-row {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions-row > a {
|
||||
display: block;
|
||||
flex: 1 1 auto;
|
||||
padding: 0.75em 0;
|
||||
color: var(--logico-default-text-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
flex: 0 0 44px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--logico-default-text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions-toggle:focus-visible {
|
||||
outline: 2px solid currentColor;
|
||||
outline-offset: 2px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#masthead .mobile-header-menu-container .dm-accordion-chevron {
|
||||
display: inline-block;
|
||||
width: 0.7em;
|
||||
height: 0.7em;
|
||||
flex: 0 0 auto;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-position: center;
|
||||
mask-position: center;
|
||||
-webkit-mask-size: contain;
|
||||
mask-size: contain;
|
||||
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions.dm-accordion-open .dm-accordion-chevron {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions-panel {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-left: 18px;
|
||||
transition: max-height 0.3s ease;
|
||||
}
|
||||
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions.dm-accordion-open .dm-mobile-solutions-panel {
|
||||
max-height: 160px;
|
||||
}
|
||||
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions-panel > li {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* .mobile-header-menu-container ul.main-menu>li>a (site.css) only
|
||||
matches direct children of .main-menu, so these nested links
|
||||
fall through to the sitewide generic underlined-anchor default.
|
||||
Restore the plain sibling-item look explicitly. */
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions-panel > li > a {
|
||||
display: block;
|
||||
padding: 0.35em 0;
|
||||
color: var(--logico-default-text-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* A vendor li:before rule (checkmark bullet, likely intended for a
|
||||
feature-list style elsewhere) leaks through here since the reset
|
||||
at .mobile-header-menu-container ul.main-menu>li:before only
|
||||
matches direct children of .main-menu, not this nested li.
|
||||
Suppress it on both the <li> and <a> — these child rows aren't
|
||||
top-level nav items and shouldn't carry any bullet/indicator. */
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions-panel > li:before,
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions-panel > li > a:before {
|
||||
content: none !important;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#masthead .mobile-header-menu-container .dm-mobile-solutions-panel > li.dm-child-active > a {
|
||||
color: var(--logico-light-text-color);
|
||||
text-decoration: underline;
|
||||
}
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,69 +1,170 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useEffect, useRef, useState, type MutableRefObject } from "react";
|
||||
import Image from "next/image";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
/**
|
||||
* LoadingScreen
|
||||
* ---------------------------------------------------------------------------
|
||||
* Native reimplementation of the legacy WordPress page-loader: a black
|
||||
* full-screen overlay with a centered, pulsing Doormile logo that fades out.
|
||||
* Route-transition loader only: a black full-screen overlay with a centered,
|
||||
* pulsing Doormile logo. It intentionally does not run on initial page render,
|
||||
* image loading, lazy component loading, API requests, or scroll.
|
||||
*
|
||||
* Shows on initial load (until the window finishes loading, min ~450ms to avoid
|
||||
* a flash, capped at 2.5s so it never blocks) and again briefly on each route
|
||||
* navigation. CWV-safe: fixed/out-of-flow (no layout shift), logo is priority,
|
||||
* and it never delays hydration.
|
||||
* The App Router does not expose the old `next/router` routeChangeStart /
|
||||
* routeChangeComplete event API. This component provides the same behavior by
|
||||
* detecting internal route-link starts and completing when `usePathname()`
|
||||
* reports the committed route.
|
||||
*/
|
||||
type Phase = "visible" | "hiding" | "gone";
|
||||
type Phase = "hidden" | "visible" | "hiding";
|
||||
|
||||
const MIN_SHOW_MS = 450;
|
||||
const MAX_SHOW_MS = 2500;
|
||||
const NAV_SHOW_MS = 520;
|
||||
const MIN_VISIBLE_MS = 420;
|
||||
const MAX_VISIBLE_MS = 800;
|
||||
|
||||
function getRoutePath(url: URL) {
|
||||
return `${url.pathname}${url.search}`;
|
||||
}
|
||||
|
||||
export default function LoadingScreen() {
|
||||
const pathname = usePathname();
|
||||
const [phase, setPhase] = useState<Phase>("visible");
|
||||
const isFirstRender = useRef(true);
|
||||
const [phase, setPhase] = useState<Phase>("hidden");
|
||||
const phaseRef = useRef<Phase>("hidden");
|
||||
const visibleSince = useRef(0);
|
||||
const pendingPath = useRef<string | null>(null);
|
||||
const currentRoutePath = useRef<string | null>(null);
|
||||
const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const safetyTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
const setLoaderPhase = (nextPhase: Phase) => {
|
||||
phaseRef.current = nextPhase;
|
||||
setPhase(nextPhase);
|
||||
};
|
||||
|
||||
const clearTimer = (timer: MutableRefObject<ReturnType<typeof setTimeout> | null>) => {
|
||||
if (!timer.current) return;
|
||||
clearTimeout(timer.current);
|
||||
timer.current = null;
|
||||
};
|
||||
|
||||
const completeTransition = () => {
|
||||
pendingPath.current = null;
|
||||
clearTimer(safetyTimer);
|
||||
|
||||
if (phaseRef.current === "hidden" || phaseRef.current === "hiding") return;
|
||||
|
||||
const elapsed = performance.now() - visibleSince.current;
|
||||
const wait = Math.max(0, MIN_VISIBLE_MS - elapsed);
|
||||
clearTimer(hideTimer);
|
||||
hideTimer.current = setTimeout(() => {
|
||||
setLoaderPhase("hiding");
|
||||
hideTimer.current = setTimeout(() => setLoaderPhase("hidden"), 360);
|
||||
}, wait);
|
||||
};
|
||||
|
||||
// Initial load: hide once the page is ready.
|
||||
useEffect(() => {
|
||||
const start = performance.now();
|
||||
let began = false;
|
||||
let fadeTimer: ReturnType<typeof setTimeout>;
|
||||
|
||||
const begin = () => {
|
||||
if (began) return;
|
||||
began = true;
|
||||
const wait = Math.max(0, MIN_SHOW_MS - (performance.now() - start));
|
||||
fadeTimer = setTimeout(() => setPhase("hiding"), wait);
|
||||
};
|
||||
|
||||
const cap = setTimeout(begin, MAX_SHOW_MS);
|
||||
const onReady = () => begin();
|
||||
|
||||
if (document.readyState === "complete") begin();
|
||||
else window.addEventListener("load", onReady, { once: true });
|
||||
|
||||
return () => {
|
||||
clearTimeout(cap);
|
||||
clearTimeout(fadeTimer);
|
||||
window.removeEventListener("load", onReady);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Route navigations: flash the loader briefly for an app-like transition.
|
||||
useEffect(() => {
|
||||
if (isFirstRender.current) {
|
||||
isFirstRender.current = false;
|
||||
return;
|
||||
}
|
||||
setPhase("visible");
|
||||
const t = setTimeout(() => setPhase("hiding"), NAV_SHOW_MS);
|
||||
return () => clearTimeout(t);
|
||||
currentRoutePath.current = `${pathname}${window.location.search}`;
|
||||
completeTransition();
|
||||
// `phase` intentionally stays out of this dependency list. The route commit
|
||||
// is the completion signal; phase changes should not repeatedly restart hide.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pathname]);
|
||||
|
||||
if (phase === "gone") return null;
|
||||
useEffect(() => {
|
||||
const startTransition = (targetPath: string, force = false) => {
|
||||
if (!force && targetPath === getRoutePath(new URL(window.location.href))) return;
|
||||
if (pendingPath.current === targetPath && phaseRef.current === "visible") return;
|
||||
|
||||
pendingPath.current = targetPath;
|
||||
clearTimer(hideTimer);
|
||||
clearTimer(safetyTimer);
|
||||
|
||||
visibleSince.current = performance.now();
|
||||
setLoaderPhase("visible");
|
||||
|
||||
safetyTimer.current = setTimeout(() => {
|
||||
completeTransition();
|
||||
}, MAX_VISIBLE_MS);
|
||||
};
|
||||
|
||||
const getInternalRouteTarget = (anchor: HTMLAnchorElement) => {
|
||||
const rawHref = anchor.getAttribute("href");
|
||||
if (!rawHref || rawHref.startsWith("#")) return null;
|
||||
if (anchor.target && anchor.target !== "_self") return null;
|
||||
if (anchor.hasAttribute("download")) return null;
|
||||
if (/^(mailto:|tel:|sms:|javascript:)/i.test(rawHref)) return null;
|
||||
|
||||
const url = new URL(rawHref, window.location.href);
|
||||
if (url.origin !== window.location.origin) return null;
|
||||
|
||||
const current = new URL(window.location.href);
|
||||
const sameRoute = url.pathname === current.pathname && url.search === current.search;
|
||||
if (sameRoute) return null;
|
||||
|
||||
return getRoutePath(url);
|
||||
};
|
||||
|
||||
const handleDocumentClick = (event: MouseEvent) => {
|
||||
if (event.defaultPrevented) return;
|
||||
if (event.button !== 0) return;
|
||||
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
||||
|
||||
const anchor = (event.target as Element | null)?.closest("a[href]");
|
||||
if (!anchor || !(anchor instanceof HTMLAnchorElement)) return;
|
||||
|
||||
const targetPath = getInternalRouteTarget(anchor);
|
||||
if (targetPath) startTransition(targetPath);
|
||||
};
|
||||
|
||||
const originalPushState = window.history.pushState;
|
||||
const originalReplaceState = window.history.replaceState;
|
||||
|
||||
const scheduleHistoryTransition = (targetPath: string) => {
|
||||
const currentPath = getRoutePath(new URL(window.location.href));
|
||||
if (targetPath === currentPath) return;
|
||||
|
||||
window.setTimeout(() => {
|
||||
startTransition(targetPath, true);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
window.history.pushState = function patchedPushState(...args) {
|
||||
const urlArg = args[2];
|
||||
if (typeof urlArg === "string" || urlArg instanceof URL) {
|
||||
const url = new URL(urlArg, window.location.href);
|
||||
if (url.origin === window.location.origin) scheduleHistoryTransition(getRoutePath(url));
|
||||
}
|
||||
return originalPushState.apply(this, args);
|
||||
};
|
||||
|
||||
window.history.replaceState = function patchedReplaceState(...args) {
|
||||
const urlArg = args[2];
|
||||
if (typeof urlArg === "string" || urlArg instanceof URL) {
|
||||
const url = new URL(urlArg, window.location.href);
|
||||
if (url.origin === window.location.origin) scheduleHistoryTransition(getRoutePath(url));
|
||||
}
|
||||
return originalReplaceState.apply(this, args);
|
||||
};
|
||||
|
||||
const handlePopState = () => {
|
||||
const targetPath = getRoutePath(new URL(window.location.href));
|
||||
if (targetPath !== currentRoutePath.current) startTransition(targetPath, true);
|
||||
};
|
||||
|
||||
document.addEventListener("click", handleDocumentClick, true);
|
||||
window.addEventListener("popstate", handlePopState);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("click", handleDocumentClick, true);
|
||||
window.removeEventListener("popstate", handlePopState);
|
||||
window.history.pushState = originalPushState;
|
||||
window.history.replaceState = originalReplaceState;
|
||||
clearTimer(hideTimer);
|
||||
clearTimer(safetyTimer);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
if (phase === "hidden") return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -72,7 +173,10 @@ export default function LoadingScreen() {
|
||||
aria-live="polite"
|
||||
aria-label="Loading"
|
||||
onTransitionEnd={(e) => {
|
||||
if (e.propertyName === "opacity" && phase === "hiding") setPhase("gone");
|
||||
if (e.propertyName === "opacity" && phase === "hiding") {
|
||||
setPhase("hidden");
|
||||
phaseRef.current = "hidden";
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="dm-loader__pulse">
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* ContactMapEmbed
|
||||
* ---------------------------------------------------------------------------
|
||||
* Client boundary that lazy-loads the Leaflet map. `ssr: false` keeps Leaflet
|
||||
* out of the server bundle and off the critical render path; the skeleton fills
|
||||
* the host container's fixed height so there is zero layout shift (CLS) while
|
||||
* the map chunk loads.
|
||||
* out of the server bundle and off the critical render path. The host container
|
||||
* already owns the fixed height, so the loading state stays invisible before
|
||||
* the interactive map is ready.
|
||||
*/
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
@@ -14,7 +14,7 @@ import styles from "./OfficeMap.module.css";
|
||||
|
||||
const OfficeMap = dynamic(() => import("./OfficeMap"), {
|
||||
ssr: false,
|
||||
loading: () => <div className={styles.skeleton} role="presentation" aria-hidden="true" />,
|
||||
loading: () => <div className={styles.mapMountReserve} role="presentation" aria-hidden="true" />,
|
||||
});
|
||||
|
||||
export default function ContactMapEmbed() {
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
/* ===========================================================================
|
||||
Office satellite map — scoped styles.
|
||||
All Leaflet global classes are namespaced under `.root` via :global() so this
|
||||
module cannot leak into the rest of the app and vice-versa.
|
||||
Colours/radii reference the app's theme (dark surface, #C01227 brand red).
|
||||
The map fills its container 100% — no hard-coded layout values live here.
|
||||
=========================================================================== */
|
||||
|
||||
.root {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* inherit the host container's rounded corners so tiles/controls clip cleanly */
|
||||
border-radius: inherit;
|
||||
overflow: hidden;
|
||||
background: #0b0b0b;
|
||||
@@ -34,10 +29,6 @@
|
||||
.controls {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
/* Span the full width (with side insets) instead of left:50%+auto-width:
|
||||
an absolutely-positioned auto-width box anchored at left:50% can only grow
|
||||
to 50% of the map, which on a narrow phone forced the city buttons to stack
|
||||
vertically. With left/right insets the row uses the full width and centres. */
|
||||
left: 12px;
|
||||
right: 12px;
|
||||
z-index: 600; /* above tiles + markers; popups open lower so they never collide */
|
||||
@@ -47,6 +38,7 @@
|
||||
gap: 8px;
|
||||
pointer-events: none; /* let the row be transparent to drags; buttons re-enable */
|
||||
}
|
||||
|
||||
.controlBtn {
|
||||
pointer-events: auto;
|
||||
appearance: none;
|
||||
@@ -68,15 +60,18 @@
|
||||
transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease,
|
||||
transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.controlBtn:hover {
|
||||
background: rgba(192, 18, 39, 0.9);
|
||||
border-color: #c01227;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.controlBtn:focus-visible {
|
||||
outline: 2px solid #ffffff;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.controlBtnActive,
|
||||
.controlBtnActive:hover {
|
||||
background: #c01227;
|
||||
@@ -85,12 +80,20 @@
|
||||
box-shadow: 0 6px 18px rgba(192, 18, 39, 0.45);
|
||||
}
|
||||
|
||||
/* Headquarters button — subtly elevated so it reads as the primary location. */
|
||||
.controlBtnHq {
|
||||
border-color: rgba(192, 18, 39, 0.55);
|
||||
box-shadow: 0 0 0 1px rgba(192, 18, 39, 0.25), 0 4px 14px rgba(192, 18, 39, 0.2);
|
||||
}
|
||||
|
||||
.controlBtnHq.controlBtnActive {
|
||||
box-shadow: 0 6px 20px rgba(192, 18, 39, 0.55);
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.controls {
|
||||
top: 12px;
|
||||
gap: 5px;
|
||||
/* Keep all three city buttons on a single line — shrink them (below) so the
|
||||
row fits instead of wrapping to two lines on narrow phones. */
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.controlBtn {
|
||||
@@ -101,37 +104,88 @@
|
||||
|
||||
/* ---- Branded marker pin ---- */
|
||||
.markerIcon {
|
||||
/* divIcon resets — keep only the pin's own drop shadow */
|
||||
background: transparent;
|
||||
border: 0;
|
||||
filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.55));
|
||||
transition: transform 0.18s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
.markerIcon:hover,
|
||||
.markerIcon:focus-visible {
|
||||
transform: translateY(-3px) scale(1.06);
|
||||
}
|
||||
|
||||
/* ---- Themed Leaflet internals (scoped to this map only) ---- */
|
||||
/* ---- Headquarters pin — larger, glowing, pulsing, always on top ---- */
|
||||
.markerIconHq {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
filter: drop-shadow(0 0 9px rgba(192, 18, 39, 0.85))
|
||||
drop-shadow(0 5px 7px rgba(0, 0, 0, 0.55));
|
||||
transition: transform 0.18s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
.markerIconHq svg {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.markerIconHq:hover,
|
||||
.markerIconHq:focus-visible {
|
||||
transform: translateY(-3px) scale(1.05);
|
||||
}
|
||||
|
||||
/* Soft expanding ring radiating from the HQ pin head. */
|
||||
.pinPulse {
|
||||
position: absolute;
|
||||
top: 19px;
|
||||
left: 20px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin: -9px 0 0 -9px;
|
||||
border-radius: 50%;
|
||||
background: rgba(192, 18, 39, 0.5);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
animation: hqPulse 2.2s ease-out infinite;
|
||||
}
|
||||
|
||||
@keyframes hqPulse {
|
||||
0% {
|
||||
transform: scale(0.6);
|
||||
opacity: 0.75;
|
||||
}
|
||||
70% {
|
||||
transform: scale(3);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: scale(3);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Leaflet Branded Elements ---- */
|
||||
.root :global(.leaflet-container) {
|
||||
background: #0b0b0b;
|
||||
}
|
||||
|
||||
/* Zoom + attribution controls — dark, on-theme */
|
||||
.root :global(.leaflet-bar) {
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.root :global(.leaflet-bar a) {
|
||||
background: rgba(15, 15, 17, 0.92);
|
||||
color: #f5f5f5;
|
||||
border-bottom-color: rgba(255, 255, 255, 0.12);
|
||||
transition: background-color 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
|
||||
.root :global(.leaflet-bar a:hover) {
|
||||
background: #c01227;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.root :global(.leaflet-bar a:focus-visible) {
|
||||
outline: 2px solid #c01227;
|
||||
outline-offset: 2px;
|
||||
@@ -146,71 +200,132 @@
|
||||
border-radius: 6px 0 0 0;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
.root :global(.leaflet-control-attribution a) {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
/* Popup — dark card matching the app surfaces */
|
||||
.root :global(.leaflet-popup-content-wrapper) {
|
||||
background: #141416;
|
||||
color: #ffffff;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
.root :global(.leaflet-popup-content) {
|
||||
margin: 12px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.01em;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.root :global(.leaflet-popup-tip) {
|
||||
background: #141416;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.root :global(.leaflet-popup-close-button) {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
.root :global(.leaflet-popup-close-button:hover) {
|
||||
color: #ffffff;
|
||||
}
|
||||
.root :global(.leaflet-popup-content .office-popup__name) {
|
||||
display: block;
|
||||
}
|
||||
.root :global(.leaflet-popup-content .office-popup__dot) {
|
||||
display: inline-block;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
margin-right: 8px;
|
||||
border-radius: 50%;
|
||||
background: #c01227;
|
||||
vertical-align: middle;
|
||||
/* ---- Floating Popup overlays ---- */
|
||||
.root :global(.leaflet-popup) {
|
||||
animation: popupFade 0.2s ease-out forwards;
|
||||
}
|
||||
|
||||
/* ---- Loading skeleton (prevents CLS — fills the fixed-height host) ---- */
|
||||
.skeleton {
|
||||
.root :global(.leaflet-popup-content-wrapper) {
|
||||
background: #0f0f11;
|
||||
color: #ffffff;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 8px; /* Clean business card rounded corners */
|
||||
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.6);
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
animation: popupScale 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
||||
transform-origin: bottom center;
|
||||
}
|
||||
|
||||
.root :global(.leaflet-popup-content) {
|
||||
margin: 0 !important;
|
||||
width: auto !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.root :global(.leaflet-popup-tip) {
|
||||
background: #0f0f11;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
@keyframes popupFade {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes popupScale {
|
||||
from { transform: scale(0.92); }
|
||||
to { transform: scale(1); }
|
||||
}
|
||||
|
||||
/* Compact Details Card inside Popup */
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 12px 16px;
|
||||
min-width: 230px;
|
||||
max-width: 280px;
|
||||
box-sizing: border-box;
|
||||
font-family: var(--font-manrope), system-ui, -apple-system, sans-serif;
|
||||
border-top: 2px solid #c01227; /* Thinner brand accent line */
|
||||
background: #0f0f11;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.cardHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 8px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.cardIcon {
|
||||
font-size: 15px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cardTitle {
|
||||
font-size: 17px !important;
|
||||
font-weight: 800 !important;
|
||||
color: #ffffff !important; /* Force white header text */
|
||||
margin: 0 !important;
|
||||
letter-spacing: -0.01em !important;
|
||||
}
|
||||
|
||||
.cardBody {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.addressLine {
|
||||
font-size: 14px !important;
|
||||
line-height: 1.5 !important;
|
||||
color: rgba(255, 255, 255, 0.75) !important;
|
||||
margin: 0 0 6px 0 !important;
|
||||
padding: 0 !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
.addressLine:last-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.card {
|
||||
padding: 9px 12px;
|
||||
min-width: 200px;
|
||||
max-width: 230px;
|
||||
}
|
||||
.cardTitle {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
.addressLine {
|
||||
font-size: 12px !important;
|
||||
margin-bottom: 3px !important;
|
||||
line-height: 1.4 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Invisible lazy mount reserve ---- */
|
||||
.mapMountReserve {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
background:
|
||||
linear-gradient(
|
||||
100deg,
|
||||
rgba(255, 255, 255, 0) 30%,
|
||||
rgba(255, 255, 255, 0.05) 50%,
|
||||
rgba(255, 255, 255, 0) 70%
|
||||
),
|
||||
#101012;
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.4s ease-in-out infinite;
|
||||
}
|
||||
@keyframes shimmer {
|
||||
from { background-position: 200% 0; }
|
||||
to { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.skeleton { animation: none; }
|
||||
.markerIcon { transition: none; }
|
||||
.markerIcon,
|
||||
.markerIconHq { transition: none; }
|
||||
.pinPulse { animation: none; opacity: 0.45; }
|
||||
}
|
||||
|
||||
/* ---- Graceful error fallback ---- */
|
||||
@@ -229,12 +344,14 @@
|
||||
color: rgba(255, 255, 255, 0.82);
|
||||
font-family: var(--font-manrope), system-ui, sans-serif;
|
||||
}
|
||||
|
||||
.errorTitle {
|
||||
font-size: clamp(15px, 2.4vw, 18px);
|
||||
font-weight: 800;
|
||||
color: #ffffff;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.errorText {
|
||||
font-size: 13px;
|
||||
max-width: 38ch;
|
||||
@@ -242,6 +359,7 @@
|
||||
line-height: 1.55;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.errorList {
|
||||
list-style: none;
|
||||
margin: 4px 0 0;
|
||||
@@ -251,6 +369,7 @@
|
||||
gap: 8px 12px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.errorList li {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -259,6 +378,7 @@
|
||||
font-weight: 700;
|
||||
color: #f1f1f1;
|
||||
}
|
||||
|
||||
.errorList li::before {
|
||||
content: "";
|
||||
width: 7px;
|
||||
@@ -267,7 +387,7 @@
|
||||
background: #c01227;
|
||||
}
|
||||
|
||||
/* ---- Screen-reader-only office list (semantic fallback) ---- */
|
||||
/* ---- Screen-reader-only office list ---- */
|
||||
.srOnly {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
* Doormile office markers, plus a row of "jump to office" buttons that fly the
|
||||
* map to a selected office's coordinates and open its popup.
|
||||
*
|
||||
* Loaded via a `ssr:false` dynamic import so Leaflet (which touches `window`)
|
||||
* never runs on the server and cannot cause hydration mismatches. Layout/spacing
|
||||
* is owned by the host container (see ContactMap).
|
||||
* The map centers with a North latitude offset to keep markers lower in the viewport,
|
||||
* avoiding collisions with the navigation tabs. Popups are compact and styled like
|
||||
* clean business cards.
|
||||
*/
|
||||
|
||||
import "leaflet/dist/leaflet.css";
|
||||
@@ -20,14 +20,13 @@ import L from "leaflet";
|
||||
import { MapContainer, Marker, Popup, TileLayer, ZoomControl, useMap } from "react-leaflet";
|
||||
|
||||
import {
|
||||
LatLng,
|
||||
ESRI_WORLD_IMAGERY,
|
||||
MAP_FIT_MAX_ZOOM,
|
||||
MAP_FIT_PADDING,
|
||||
HQ_OFFICE,
|
||||
MAP_FOCUS_ZOOM,
|
||||
MAP_INITIAL_CENTER,
|
||||
MAP_INITIAL_ZOOM,
|
||||
OFFICE_LOCATIONS,
|
||||
type LatLng,
|
||||
} from "./offices";
|
||||
|
||||
type MapStatus = "loading" | "ready" | "error";
|
||||
@@ -35,8 +34,28 @@ type MapStatus = "loading" | "ready" | "error";
|
||||
/** A request to focus a specific office. `nonce` lets the same office be re-selected. */
|
||||
type FocusTarget = { id: string; nonce: number };
|
||||
|
||||
/** Build the branded SVG pin once (module scope is fine — this file is client-only). */
|
||||
function createMarkerIcon(): L.DivIcon {
|
||||
/**
|
||||
* Build a branded SVG pin. The headquarters pin is larger, carries a red glow
|
||||
* and a soft pulse ring, and sits above every other marker.
|
||||
*/
|
||||
function createMarkerIcon(isHeadquarters: boolean): L.DivIcon {
|
||||
if (isHeadquarters) {
|
||||
return L.divIcon({
|
||||
className: styles.markerIconHq,
|
||||
html: `
|
||||
<span class="${styles.pinPulse}" aria-hidden="true"></span>
|
||||
<svg width="40" height="52" viewBox="0 0 30 40" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
|
||||
<path d="M15 0C6.72 0 0 6.72 0 15c0 10.5 13.06 23.86 13.62 24.42a1.95 1.95 0 0 0 2.76 0C16.94 38.86 30 25.5 30 15 30 6.72 23.28 0 15 0Z" fill="#C01227"/>
|
||||
<path d="M15 1.5C7.54 1.5 1.5 7.54 1.5 15c0 9.6 12.3 22.4 12.83 22.94a.95.95 0 0 0 1.34 0C16.2 37.4 28.5 24.6 28.5 15 28.5 7.54 22.46 1.5 15 1.5Z" fill="none" stroke="#ffffff" stroke-width="1.2" stroke-opacity="0.9"/>
|
||||
<circle cx="15" cy="15" r="5.4" fill="#ffffff"/>
|
||||
</svg>
|
||||
`,
|
||||
iconSize: [40, 52],
|
||||
iconAnchor: [20, 52],
|
||||
popupAnchor: [0, -52], // Anchored to top tip of pin
|
||||
});
|
||||
}
|
||||
|
||||
return L.divIcon({
|
||||
className: styles.markerIcon,
|
||||
html: `
|
||||
@@ -48,83 +67,62 @@ function createMarkerIcon(): L.DivIcon {
|
||||
`,
|
||||
iconSize: [30, 40],
|
||||
iconAnchor: [15, 40],
|
||||
popupAnchor: [0, -36],
|
||||
popupAnchor: [0, -40], // Anchored to top tip of pin
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Imperative map effects that need the Leaflet instance:
|
||||
* - fit the viewport to every marker (with edge padding)
|
||||
* - keep that framing correct across resizes / lazy reveals
|
||||
* - fly to a single office when one is selected via the buttons
|
||||
* - keep the viewport sized correctly across resizes / lazy reveals
|
||||
* - snap to the offset HQ on first paint, fly thereafter and open popups.
|
||||
*/
|
||||
function MapController({
|
||||
positions,
|
||||
focus,
|
||||
markerRefs,
|
||||
}: {
|
||||
positions: LatLng[];
|
||||
focus: FocusTarget | null;
|
||||
markerRefs: React.RefObject<Record<string, L.Marker>>;
|
||||
}) {
|
||||
const map = useMap();
|
||||
const didInit = useRef(false);
|
||||
|
||||
// Latest focus, read inside the (stable) resize handler without resubscribing.
|
||||
const focusRef = useRef(focus);
|
||||
useEffect(() => {
|
||||
focusRef.current = focus;
|
||||
}, [focus]);
|
||||
|
||||
const fitAll = useCallback(() => {
|
||||
if (positions.length === 0) return;
|
||||
map.invalidateSize();
|
||||
map.fitBounds(L.latLngBounds(positions), {
|
||||
padding: MAP_FIT_PADDING,
|
||||
maxZoom: MAP_FIT_MAX_ZOOM,
|
||||
});
|
||||
}, [map, positions]);
|
||||
|
||||
// Initial fit, after the container has its final size.
|
||||
useEffect(() => {
|
||||
const raf = requestAnimationFrame(fitAll);
|
||||
return () => cancelAnimationFrame(raf);
|
||||
}, [fitAll]);
|
||||
|
||||
// Re-measure on container resize; only re-frame all markers when nothing is
|
||||
// focused, so resizing while zoomed into one office doesn't jump the view away.
|
||||
// Keep the map correctly sized on container resize / lazy reveal.
|
||||
useEffect(() => {
|
||||
const container = map.getContainer();
|
||||
let raf = 0;
|
||||
const observer = new ResizeObserver(() => {
|
||||
cancelAnimationFrame(raf);
|
||||
raf = requestAnimationFrame(() => {
|
||||
map.invalidateSize();
|
||||
if (!focusRef.current) {
|
||||
map.fitBounds(L.latLngBounds(positions), {
|
||||
padding: MAP_FIT_PADDING,
|
||||
maxZoom: MAP_FIT_MAX_ZOOM,
|
||||
});
|
||||
}
|
||||
});
|
||||
raf = requestAnimationFrame(() => map.invalidateSize());
|
||||
});
|
||||
observer.observe(container);
|
||||
return () => {
|
||||
cancelAnimationFrame(raf);
|
||||
observer.disconnect();
|
||||
};
|
||||
}, [map, positions]);
|
||||
}, [map]);
|
||||
|
||||
// Fly to the selected office, then open its popup once movement settles.
|
||||
// React to the focused office: snap on first paint, fly thereafter.
|
||||
useEffect(() => {
|
||||
if (!focus) return;
|
||||
const office = OFFICE_LOCATIONS.find((item) => item.id === focus.id);
|
||||
if (!office) return;
|
||||
|
||||
map.flyTo(office.position, MAP_FOCUS_ZOOM, { duration: 1.1 });
|
||||
const openPopup = () => markerRefs.current[office.id]?.openPopup();
|
||||
|
||||
const marker = markerRefs.current[office.id];
|
||||
if (!marker) return;
|
||||
const openPopup = () => marker.openPopup();
|
||||
// Offset the center slightly North so the marker sits lower in the viewport,
|
||||
// preventing the popup card from colliding with the top controls.
|
||||
const offsetLatitude = 0.022;
|
||||
const centeredPosition: LatLng = [office.position[0] + offsetLatitude, office.position[1]];
|
||||
|
||||
if (!didInit.current) {
|
||||
didInit.current = true;
|
||||
map.invalidateSize();
|
||||
map.setView(centeredPosition, MAP_FOCUS_ZOOM, { animate: false });
|
||||
const raf = requestAnimationFrame(openPopup);
|
||||
return () => cancelAnimationFrame(raf);
|
||||
}
|
||||
|
||||
map.flyTo(centeredPosition, MAP_FOCUS_ZOOM, { duration: 1.1 });
|
||||
map.once("moveend", openPopup);
|
||||
return () => {
|
||||
map.off("moveend", openPopup);
|
||||
@@ -135,18 +133,25 @@ function MapController({
|
||||
}
|
||||
|
||||
export default function OfficeMap() {
|
||||
const icon = useMemo(() => createMarkerIcon(), []);
|
||||
const positions = useMemo<LatLng[]>(
|
||||
() => OFFICE_LOCATIONS.map((office) => office.position),
|
||||
[],
|
||||
);
|
||||
const icon = useMemo(() => createMarkerIcon(false), []);
|
||||
const hqIcon = useMemo(() => createMarkerIcon(true), []);
|
||||
const markerRefs = useRef<Record<string, L.Marker>>({});
|
||||
|
||||
const [focus, setFocus] = useState<FocusTarget | null>(null);
|
||||
// Default to the headquarters.
|
||||
const [focus, setFocus] = useState<FocusTarget | null>({ id: HQ_OFFICE.id, nonce: 0 });
|
||||
const focusOffice = useCallback((id: string) => {
|
||||
setFocus((prev) => ({ id, nonce: (prev?.nonce ?? 0) + 1 }));
|
||||
}, []);
|
||||
|
||||
const [hoveredOfficeId, setHoveredOfficeId] = useState<string | null>(null);
|
||||
|
||||
// Restore the focused office popup when mouse leaves other markers.
|
||||
useEffect(() => {
|
||||
if (hoveredOfficeId === null && focus?.id) {
|
||||
markerRefs.current[focus.id]?.openPopup();
|
||||
}
|
||||
}, [hoveredOfficeId, focus]);
|
||||
|
||||
const [status, setStatus] = useState<MapStatus>("loading");
|
||||
const loadedRef = useRef(false);
|
||||
const errorCountRef = useRef(0);
|
||||
@@ -156,8 +161,6 @@ export default function OfficeMap() {
|
||||
setStatus("ready");
|
||||
}, []);
|
||||
|
||||
// Only surface an error if tiles never render (network/CORS/down). Once any
|
||||
// tile load succeeds the map is considered healthy and stays that way.
|
||||
const handleTileError = useCallback(() => {
|
||||
errorCountRef.current += 1;
|
||||
if (!loadedRef.current && errorCountRef.current >= 6) setStatus("error");
|
||||
@@ -189,7 +192,9 @@ export default function OfficeMap() {
|
||||
<button
|
||||
key={office.id}
|
||||
type="button"
|
||||
className={`${styles.controlBtn} ${isActive ? styles.controlBtnActive : ""}`}
|
||||
className={`${styles.controlBtn} ${isActive ? styles.controlBtnActive : ""} ${
|
||||
office.isHeadquarters ? styles.controlBtnHq : ""
|
||||
}`}
|
||||
aria-pressed={isActive}
|
||||
aria-label={`Show ${office.name} on the map`}
|
||||
onClick={() => focusOffice(office.id)}
|
||||
@@ -221,29 +226,63 @@ export default function OfficeMap() {
|
||||
eventHandlers={{ load: handleTileLoad, tileerror: handleTileError }}
|
||||
/>
|
||||
|
||||
{OFFICE_LOCATIONS.map((office) => (
|
||||
<Marker
|
||||
key={office.id}
|
||||
position={office.position}
|
||||
icon={icon}
|
||||
keyboard
|
||||
title={office.name}
|
||||
alt={office.name}
|
||||
eventHandlers={{ click: () => focusOffice(office.id) }}
|
||||
ref={(instance) => {
|
||||
if (instance) markerRefs.current[office.id] = instance;
|
||||
}}
|
||||
>
|
||||
<Popup>
|
||||
<span className="office-popup__name">
|
||||
<span className="office-popup__dot" aria-hidden="true" />
|
||||
{office.name}
|
||||
</span>
|
||||
</Popup>
|
||||
</Marker>
|
||||
))}
|
||||
{OFFICE_LOCATIONS.map((office) => {
|
||||
const isFocused = focus?.id === office.id;
|
||||
const isHovered = hoveredOfficeId === office.id;
|
||||
|
||||
<MapController positions={positions} focus={focus} markerRefs={markerRefs} />
|
||||
return (
|
||||
<Marker
|
||||
key={office.id}
|
||||
position={office.position}
|
||||
icon={office.isHeadquarters ? hqIcon : icon}
|
||||
zIndexOffset={office.isHeadquarters ? 1000 : 0}
|
||||
keyboard
|
||||
title={office.name}
|
||||
alt={office.name}
|
||||
eventHandlers={{
|
||||
click: () => focusOffice(office.id),
|
||||
mouseover: (event) => {
|
||||
setHoveredOfficeId(office.id);
|
||||
event.target.openPopup();
|
||||
},
|
||||
mouseout: (event) => {
|
||||
setHoveredOfficeId(null);
|
||||
if (focus?.id !== office.id) {
|
||||
event.target.closePopup();
|
||||
}
|
||||
},
|
||||
}}
|
||||
ref={(instance) => {
|
||||
if (instance) markerRefs.current[office.id] = instance;
|
||||
}}
|
||||
>
|
||||
<Popup
|
||||
className={styles.popup}
|
||||
autoPan={isFocused}
|
||||
autoPanPadding={[25, 25]}
|
||||
closeButton={false}
|
||||
minWidth={240}
|
||||
maxWidth={290}
|
||||
>
|
||||
<div className={styles.card}>
|
||||
<div className={styles.cardHeader}>
|
||||
<span className={styles.cardIcon} aria-hidden="true">📍</span>
|
||||
<h4 className={styles.cardTitle}>{office.city} Office</h4>
|
||||
</div>
|
||||
<div className={styles.cardBody}>
|
||||
{office.address.map((line, idx) => (
|
||||
<p key={idx} className={styles.addressLine}>
|
||||
{line}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Popup>
|
||||
</Marker>
|
||||
);
|
||||
})}
|
||||
|
||||
<MapController focus={focus} markerRefs={markerRefs} />
|
||||
</MapContainer>
|
||||
|
||||
{status === "error" && (
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
* Kept dependency-free (no Leaflet runtime import) so it can be safely consumed
|
||||
* by both server and client modules. Types model `[lat, lng]` tuples that are
|
||||
* directly compatible with Leaflet's `LatLngExpression`.
|
||||
*
|
||||
* Coordinates are the real Doormile operational sites, verified against
|
||||
* satellite view — not generic city-centre points.
|
||||
*/
|
||||
|
||||
/** A `[latitude, longitude]` coordinate pair. */
|
||||
@@ -12,21 +15,77 @@ export type LatLng = [number, number];
|
||||
export interface OfficeLocation {
|
||||
/** Stable, unique key (used for React keys + analytics). */
|
||||
readonly id: string;
|
||||
/** Short city label, shown on the navigation buttons. */
|
||||
/** Short city label, shown on the navigation button. */
|
||||
readonly city: string;
|
||||
/** Human-readable label shown in the marker popup + a11y fallback. */
|
||||
/** Human-readable label shown in the a11y fallback + marker title. */
|
||||
readonly name: string;
|
||||
/** Compact heading shown in the marker tooltip/popup (e.g. "Hyderabad HQ"). */
|
||||
readonly shortLabel: string;
|
||||
/** `[latitude, longitude]`. */
|
||||
readonly position: LatLng;
|
||||
/** Headquarters gets the largest, glowing, default-active marker. */
|
||||
readonly isHeadquarters?: boolean;
|
||||
/** Full office address lines. */
|
||||
readonly address: readonly string[];
|
||||
}
|
||||
|
||||
/** The three permanent office markers, ordered north-to-south is irrelevant — bounds are auto-fit. */
|
||||
/**
|
||||
* The three permanent office markers, ordered for the navigation row by
|
||||
* operational hierarchy: Hyderabad (HQ) → Bengaluru → Coimbatore. The
|
||||
* headquarters is conveyed purely through styling (active state + border +
|
||||
* glow), not through icons or label text.
|
||||
*/
|
||||
export const OFFICE_LOCATIONS: readonly OfficeLocation[] = [
|
||||
{ id: "coimbatore", city: "Coimbatore", name: "Coimbatore Office", position: [11.0168, 76.9558] },
|
||||
{ id: "bengaluru", city: "Bengaluru", name: "Bengaluru Office", position: [12.9716, 77.5946] },
|
||||
{ id: "hyderabad", city: "Hyderabad", name: "Hyderabad Office", position: [17.385, 78.4867] },
|
||||
{
|
||||
id: "hyderabad",
|
||||
city: "Hyderabad",
|
||||
name: "Doormile Headquarters",
|
||||
shortLabel: "Hyderabad HQ",
|
||||
// Vision Ultima, Jayabheri Enclave, Gachibowli — verified on satellite.
|
||||
position: [17.4484, 78.3573],
|
||||
isHeadquarters: true,
|
||||
address: [
|
||||
"5th Floor, Vision Ultima,",
|
||||
"Street No.3, Jayabheri Enclave,",
|
||||
"Gachibowli, Hyderabad,",
|
||||
"Telangana 500032"
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "bengaluru",
|
||||
city: "Bengaluru",
|
||||
name: "Bengaluru Hub",
|
||||
shortLabel: "Bengaluru Hub",
|
||||
// Resolved from the supplied Google Maps share link — verified on satellite.
|
||||
position: [12.9929351, 77.6988599],
|
||||
address: [
|
||||
"C612, 6th Floor,",
|
||||
"Trifecta Starlight, ITPL Road,",
|
||||
"Garudacharapalya, Mahadevapura,",
|
||||
"Bangalore 560048,",
|
||||
"Karnataka, India"
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "coimbatore",
|
||||
city: "Coimbatore",
|
||||
name: "Coimbatore Hub",
|
||||
shortLabel: "Coimbatore Hub",
|
||||
// Mayflower Valencia, Coimbatore — verified against satellite view.
|
||||
position: [11.0191, 76.9883],
|
||||
address: [
|
||||
"Mayflower Valencia,",
|
||||
"Near Nava India Bus Stop,",
|
||||
"Avinashi Road, Udayampalayam,",
|
||||
"Tamil Nadu 641003"
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
/** The headquarters office — focused by default on load. Falls back to the first office. */
|
||||
export const HQ_OFFICE: OfficeLocation =
|
||||
OFFICE_LOCATIONS.find((office) => office.isHeadquarters) ?? OFFICE_LOCATIONS[0];
|
||||
|
||||
export interface TileLayerConfig {
|
||||
readonly url: string;
|
||||
readonly attribution: string;
|
||||
@@ -45,15 +104,12 @@ export const ESRI_WORLD_IMAGERY: TileLayerConfig = {
|
||||
maxZoom: 19,
|
||||
};
|
||||
|
||||
/** Padding (in px) applied when auto-fitting bounds so markers never touch the edges. */
|
||||
export const MAP_FIT_PADDING: LatLng = [50, 50];
|
||||
|
||||
/** Cap the auto-fit zoom so two close offices don't zoom the map in too far. */
|
||||
export const MAP_FIT_MAX_ZOOM = 7;
|
||||
|
||||
/** City-level zoom used when a single office is selected via the nav buttons. */
|
||||
/** City-level zoom used when an office is selected (and for the initial HQ view). */
|
||||
export const MAP_FOCUS_ZOOM = 13;
|
||||
|
||||
/** Initial center/zoom (roughly the centroid of the offices) used before bounds are fit. */
|
||||
export const MAP_INITIAL_CENTER: LatLng = [14.0, 77.7];
|
||||
export const MAP_INITIAL_ZOOM = 5;
|
||||
/**
|
||||
* Initial center/zoom: the experience opens focused on the Hyderabad HQ so the
|
||||
* command-centre reads as the heart of the network the instant the map paints.
|
||||
*/
|
||||
export const MAP_INITIAL_CENTER: LatLng = HQ_OFFICE.position;
|
||||
export const MAP_INITIAL_ZOOM = MAP_FOCUS_ZOOM;
|
||||
|
||||
@@ -3,7 +3,31 @@ import Link from "next/link";
|
||||
|
||||
export default function AboutCTA() {
|
||||
return (
|
||||
<div className="we-container">
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
@media (max-width: 768px) {
|
||||
.we-container {
|
||||
margin-top: 40px !important;
|
||||
margin-bottom: 40px !important;
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
.we-cta {
|
||||
padding: 48px 20px !important;
|
||||
border-radius: 22px !important;
|
||||
}
|
||||
.we-cta-title {
|
||||
font-size: clamp(28px, 6vw, 38px) !important;
|
||||
line-height: 1.25 !important;
|
||||
margin-bottom: 16px !important;
|
||||
}
|
||||
.we-cta-sub {
|
||||
font-size: 15px !important;
|
||||
line-height: 1.5 !important;
|
||||
margin-bottom: 24px !important;
|
||||
}
|
||||
}
|
||||
`}} />
|
||||
<div className="we-container">
|
||||
<div className="we-cta reveal">
|
||||
<div className="we-cta-inner">
|
||||
<h2 className="we-cta-title">
|
||||
@@ -26,5 +50,6 @@ export default function AboutCTA() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@ import React from "react";
|
||||
export default function AboutHero() {
|
||||
return (
|
||||
<>
|
||||
<link rel="preload" as="image" href="/images/about-bg.webp" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.about-us-hero-content {
|
||||
width: 100% !important;
|
||||
text-align: center !important;
|
||||
color: #fff !important;
|
||||
padding: 40px !important;
|
||||
padding: 0 15px !important;
|
||||
z-index: 2;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
@@ -33,7 +34,7 @@ export default function AboutHero() {
|
||||
<div className="custom-standard-hero-container">
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: "url('/images/about-bg.png')",
|
||||
backgroundImage: "url('/images/about-bg.webp')",
|
||||
"--hero-overlay": "linear-gradient(to bottom, rgba(0, 0, 0, 0.85) 0%, rgba(0, 0, 0, 0.92) 60%, rgba(0, 0, 0, 0.98) 100%)"
|
||||
} as React.CSSProperties}
|
||||
className="custom-standard-hero-card"
|
||||
@@ -48,4 +49,3 @@ export default function AboutHero() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
180
src/components/sections/AirFreightAdvantages.tsx
Normal file
@@ -0,0 +1,180 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import Link from "next/link";
|
||||
import gsap from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
import { ScrollReveal } from "@/animations/Reveal";
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
}
|
||||
|
||||
export default function AirFreightAdvantages() {
|
||||
const counterRef = useRef<HTMLSpanElement>(null);
|
||||
const sectionRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const counter = counterRef.current;
|
||||
const section = sectionRef.current;
|
||||
if (!counter || !section) return;
|
||||
|
||||
const trigger = ScrollTrigger.create({
|
||||
trigger: section,
|
||||
start: "top 75%",
|
||||
once: true,
|
||||
onEnter: () => {
|
||||
const obj = { val: 200000 };
|
||||
gsap.to(obj, {
|
||||
val: 250000,
|
||||
duration: 2.2,
|
||||
ease: "power2.out",
|
||||
onUpdate: () => {
|
||||
if (counter) counter.textContent = Math.round(obj.val).toLocaleString("en-IN");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return () => { trigger.kill(); };
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.afa-about-label {
|
||||
text-align: center;
|
||||
padding: 60px 20px 0;
|
||||
background: #ffffff;
|
||||
}
|
||||
.afa-about-label .logico-title {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(17,17,17,0.45);
|
||||
display: inline-block;
|
||||
}
|
||||
.afa-counter-section {
|
||||
background: #ffffff;
|
||||
padding: 60px 20px 80px;
|
||||
}
|
||||
.afa-counter-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 40px;
|
||||
}
|
||||
.afa-counter-number {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: clamp(80px, 12vw, 180px);
|
||||
font-weight: 800;
|
||||
color: #1F1F1F;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.04em;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.afa-counter-suffix {
|
||||
color: #c01227;
|
||||
}
|
||||
.afa-counter-label {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(17,17,17,0.45);
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: mixed;
|
||||
transform: rotate(180deg);
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.afa-feature-section {
|
||||
background: #ffffff;
|
||||
padding: 0 20px 80px;
|
||||
}
|
||||
.afa-feature-inner {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 80px;
|
||||
align-items: start;
|
||||
}
|
||||
.logico-front-end .afa-feature-section h3.afa-feature-heading {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: clamp(28px, 3.5vw, 52px);
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.03em;
|
||||
text-transform: uppercase;
|
||||
color: #1F1F1F;
|
||||
-webkit-text-fill-color: #1F1F1F;
|
||||
margin: 0;
|
||||
}
|
||||
.afa-feature-text {
|
||||
font-size: 15px;
|
||||
line-height: 1.75;
|
||||
color: rgba(17,17,17,0.65);
|
||||
margin: 0 0 28px;
|
||||
}
|
||||
.afa-feature-text strong {
|
||||
color: #1F1F1F;
|
||||
font-weight: 700;
|
||||
}
|
||||
@media (max-width: 1020px) {
|
||||
.afa-feature-inner { grid-template-columns: 1fr; gap: 40px; }
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.afa-counter-number { font-size: clamp(60px, 15vw, 100px); }
|
||||
.afa-counter-inner { gap: 20px; flex-wrap: wrap; }
|
||||
.afa-counter-label { writing-mode: horizontal-tb; transform: none; }
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.afa-counter-section { padding: 40px 20px 60px; }
|
||||
.afa-feature-section { padding: 0 20px 60px; }
|
||||
}
|
||||
`}} />
|
||||
|
||||
{/* About Us label */}
|
||||
<div className="afa-about-label">
|
||||
<ScrollReveal delay={0.05}>
|
||||
<span className="logico-title">/ about us /</span>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
|
||||
{/* Big counter */}
|
||||
<section className="afa-counter-section" ref={sectionRef}>
|
||||
<div className="afa-counter-inner dm-section-container">
|
||||
<div className="afa-counter-number">
|
||||
<span ref={counterRef}>200,000</span>
|
||||
<span className="afa-counter-suffix">+</span>
|
||||
</div>
|
||||
<div className="afa-counter-label">Delivered tonnes of cargo</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Feature heading */}
|
||||
<section className="afa-feature-section">
|
||||
<div className="afa-feature-inner dm-section-container">
|
||||
<ScrollReveal delay={0.05} yOffset={40}>
|
||||
<h3 className="afa-feature-heading">
|
||||
Doormile Wings is India's leading air cargo partner
|
||||
</h3>
|
||||
</ScrollReveal>
|
||||
<ScrollReveal delay={0.15} yOffset={40}>
|
||||
<div>
|
||||
<p className="afa-feature-text">
|
||||
<strong>Our integrated air and ground network delivers cargo from major Indian airports to final destinations — domestic or international — without subcontractor gaps or tracking blind spots.</strong>
|
||||
<br /><br />
|
||||
Every Doormile Wings booking comes with binding SLA commitments, real-time milestone tracking, and in-house customs management — eliminating the need for third-party brokers and reducing total transit risk.
|
||||
</p>
|
||||
<Link href="/about-us" className="logico-alter-button" style={{ textDecoration: "none", display: "inline-block" }}>
|
||||
More About Us
|
||||
</Link>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
127
src/components/sections/AirFreightBanner.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import Link from "next/link";
|
||||
import { ScrollReveal } from "@/animations/Reveal";
|
||||
|
||||
export default function AirFreightBanner() {
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.afb-section {
|
||||
padding: 0 20px;
|
||||
background: transparent;
|
||||
}
|
||||
.afb-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.afb-image {
|
||||
min-height: 600px;
|
||||
border-radius: 25px;
|
||||
background-image: url('/images/air-freight-slide-1.jpg');
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
}
|
||||
.afb-card-anchor {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.afb-card {
|
||||
background: #1F1F1F;
|
||||
border-radius: 25px 25px 0 0;
|
||||
padding: 64px 40px 73px 38px;
|
||||
width: 363px;
|
||||
margin-top: -220px;
|
||||
margin-right: 30px;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.afb-card-num {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
color: rgba(255,255,255,0.35);
|
||||
text-transform: uppercase;
|
||||
margin: 0 0 18px;
|
||||
display: block;
|
||||
}
|
||||
.logico-front-end .afb-section h5.afb-card-title {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: clamp(22px, 2vw, 28px);
|
||||
font-weight: 800;
|
||||
line-height: 1.2;
|
||||
letter-spacing: -0.02em;
|
||||
color: #FFFFFF;
|
||||
-webkit-text-fill-color: #FFFFFF;
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
.afb-card-desc {
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
color: rgba(255,255,255,0.55);
|
||||
margin: 0 0 32px;
|
||||
}
|
||||
.logico-front-end .afb-section .logico-small-button {
|
||||
color: #FFFFFF !important;
|
||||
border-color: rgba(255,255,255,0.3) !important;
|
||||
}
|
||||
.logico-front-end .afb-section .logico-small-button:hover {
|
||||
color: #c01227 !important;
|
||||
border-color: #c01227 !important;
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.afb-image { min-height: 500px; }
|
||||
.afb-card { width: 340px; margin-right: 20px; padding: 48px 32px 56px 32px; }
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.afb-image { min-height: 420px; }
|
||||
.afb-card { width: 300px; margin-top: -160px; }
|
||||
}
|
||||
@media (max-width: 700px) {
|
||||
.afb-image { min-height: 320px; margin-bottom: 0; }
|
||||
.afb-card-anchor { justify-content: stretch; }
|
||||
.afb-card {
|
||||
width: 100%;
|
||||
margin-top: 0;
|
||||
margin-right: 0;
|
||||
border-radius: 0 0 0 0;
|
||||
padding: 40px 30px 48px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.afb-image { min-height: 260px; }
|
||||
.afb-card { padding: 32px 20px 40px; }
|
||||
}
|
||||
`}} />
|
||||
|
||||
<section className="afb-section">
|
||||
<div className="afb-wrap dm-section-container">
|
||||
<div className="afb-image" role="img" aria-label="Doormile Wings cargo terminal" />
|
||||
<div className="afb-card-anchor">
|
||||
<ScrollReveal delay={0.1} yOffset={30}>
|
||||
<div className="afb-card">
|
||||
<span className="afb-card-num">01 / Doormile Wings</span>
|
||||
<h5 className="afb-card-title">Specialized air cargo services for every shipment type</h5>
|
||||
<p className="afb-card-desc">From express next-flight-out bookings to full-aircraft charters — Doormile handles every air cargo requirement under one SLA with full visibility and in-house customs.</p>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="logico-small-button"
|
||||
style={{ textDecoration: "none", display: "inline-flex", alignItems: "center", gap: "8px" }}
|
||||
>
|
||||
Explore More
|
||||
<svg viewBox="0 0 13 20" width="8" height="13" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<polyline points="0.5 19.5 3 19.5 12.5 10 3 0.5" />
|
||||
</svg>
|
||||
</Link>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
297
src/components/sections/AirFreightBenefits.tsx
Normal file
@@ -0,0 +1,297 @@
|
||||
import Link from "next/link";
|
||||
import { ScrollReveal, StaggerChildren } from "@/animations/Reveal";
|
||||
|
||||
const PLANS = [
|
||||
{
|
||||
price: "On Quote",
|
||||
priceNote: "per shipment",
|
||||
name: "Starter Air",
|
||||
features: [
|
||||
{ active: true, text: "Standard air cargo booking" },
|
||||
{ active: true, text: "Real-time milestone tracking" },
|
||||
{ active: false, text: "Priority customs clearance" },
|
||||
{ active: false, text: "Temperature-controlled handling" },
|
||||
{ active: false, text: "Dedicated account manager" },
|
||||
],
|
||||
},
|
||||
{
|
||||
price: "On Quote",
|
||||
priceNote: "per shipment",
|
||||
name: "Express Air",
|
||||
features: [
|
||||
{ active: true, text: "Next-flight-out scheduling" },
|
||||
{ active: true, text: "Real-time milestone tracking" },
|
||||
{ active: true, text: "Priority customs clearance" },
|
||||
{ active: false, text: "Temperature-controlled handling" },
|
||||
{ active: false, text: "Dedicated account manager" },
|
||||
],
|
||||
},
|
||||
{
|
||||
price: "On Quote",
|
||||
priceNote: "per shipment",
|
||||
name: "Cold Chain",
|
||||
features: [
|
||||
{ active: true, text: "Next-flight-out scheduling" },
|
||||
{ active: true, text: "Real-time milestone tracking" },
|
||||
{ active: true, text: "Priority customs clearance" },
|
||||
{ active: true, text: "Temperature-controlled handling" },
|
||||
{ active: false, text: "Dedicated account manager" },
|
||||
],
|
||||
},
|
||||
{
|
||||
price: "Custom",
|
||||
priceNote: "enterprise pricing",
|
||||
name: "Charter & Enterprise",
|
||||
featured: true,
|
||||
features: [
|
||||
{ active: true, text: "Full-aircraft charter allocation" },
|
||||
{ active: true, text: "Real-time milestone tracking" },
|
||||
{ active: true, text: "Priority customs clearance" },
|
||||
{ active: true, text: "Temperature-controlled handling" },
|
||||
{ active: true, text: "Dedicated account manager" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default function AirFreightBenefits() {
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.afpr-section {
|
||||
background: #ffffff;
|
||||
padding: 80px 20px;
|
||||
}
|
||||
.afpr-inner {
|
||||
}
|
||||
.afpr-header {
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
.afpr-eyebrow {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(17,17,17,0.4);
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
.logico-front-end .afpr-section h3.afpr-heading {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: clamp(28px, 3.5vw, 52px);
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.03em;
|
||||
text-transform: uppercase;
|
||||
color: #1F1F1F;
|
||||
-webkit-text-fill-color: #1F1F1F;
|
||||
margin: 0;
|
||||
max-width: 560px;
|
||||
}
|
||||
.afpr-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20px;
|
||||
}
|
||||
.afpr-card {
|
||||
background: #ffffff;
|
||||
border: 1px solid rgba(17,17,17,0.1);
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: border-color 0.35s ease, box-shadow 0.35s ease, transform 0.35s cubic-bezier(0.165,0.84,0.44,1);
|
||||
}
|
||||
.afpr-card:hover {
|
||||
border-color: #c01227;
|
||||
box-shadow: 0 20px 40px rgba(192,18,39,0.08);
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
.afpr-card.afpr-featured {
|
||||
background: #1F1F1F;
|
||||
border-color: #1F1F1F;
|
||||
}
|
||||
.afpr-card.afpr-featured:hover {
|
||||
border-color: #c01227;
|
||||
box-shadow: 0 20px 40px rgba(192,18,39,0.2);
|
||||
}
|
||||
.afpr-card-top {
|
||||
padding: 32px 28px 20px;
|
||||
border-bottom: 1px solid rgba(17,17,17,0.08);
|
||||
}
|
||||
.afpr-card.afpr-featured .afpr-card-top {
|
||||
border-color: rgba(255,255,255,0.1);
|
||||
}
|
||||
.afpr-price {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: clamp(28px, 2.5vw, 42px);
|
||||
font-weight: 800;
|
||||
color: #1F1F1F;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
.afpr-card.afpr-featured .afpr-price {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.afpr-price-note {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: rgba(17,17,17,0.4);
|
||||
margin-top: 4px;
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.afpr-card.afpr-featured .afpr-price-note {
|
||||
color: rgba(255,255,255,0.4);
|
||||
}
|
||||
.afpr-plan-name {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(17,17,17,0.45);
|
||||
margin: 16px 0 0;
|
||||
display: block;
|
||||
}
|
||||
.afpr-card.afpr-featured .afpr-plan-name {
|
||||
color: rgba(255,255,255,0.4);
|
||||
}
|
||||
.afpr-card-body {
|
||||
padding: 24px 28px 28px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.afpr-features {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 28px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
}
|
||||
.afpr-section .afpr-features li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: rgba(17,17,17,0.65);
|
||||
line-height: 1.4;
|
||||
}
|
||||
.afpr-section .afpr-features li::before {
|
||||
content: none;
|
||||
}
|
||||
.afpr-card.afpr-featured .afpr-features li {
|
||||
color: rgba(255,255,255,0.55);
|
||||
}
|
||||
.afpr-feat-active {
|
||||
color: rgba(17,17,17,0.85) !important;
|
||||
}
|
||||
.afpr-card.afpr-featured .afpr-feat-active {
|
||||
color: rgba(255,255,255,0.9) !important;
|
||||
}
|
||||
.afpr-feat-dot {
|
||||
flex: 0 0 auto;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.afpr-feat-dot.on {
|
||||
background: rgba(192,18,39,0.1);
|
||||
border: 1px solid rgba(192,18,39,0.3);
|
||||
color: #c01227;
|
||||
}
|
||||
.afpr-feat-dot.off {
|
||||
background: rgba(17,17,17,0.04);
|
||||
border: 1px solid rgba(17,17,17,0.1);
|
||||
color: rgba(17,17,17,0.2);
|
||||
}
|
||||
.afpr-card.afpr-featured .afpr-feat-dot.off {
|
||||
background: rgba(255,255,255,0.04);
|
||||
border-color: rgba(255,255,255,0.1);
|
||||
color: rgba(255,255,255,0.2);
|
||||
}
|
||||
.afpr-feat-dot svg {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
}
|
||||
.logico-front-end .afpr-section .logico-alter-button {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
}
|
||||
.logico-front-end .afpr-card.afpr-featured .logico-alter-button {
|
||||
color: #FFFFFF !important;
|
||||
border-color: rgba(255,255,255,0.3) !important;
|
||||
}
|
||||
.logico-front-end .afpr-card.afpr-featured .logico-alter-button:hover {
|
||||
background: #FFFFFF !important;
|
||||
color: #1F1F1F !important;
|
||||
border-color: #FFFFFF !important;
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.afpr-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.afpr-grid { grid-template-columns: 1fr; }
|
||||
.afpr-section { padding: 60px 20px; }
|
||||
}
|
||||
`}} />
|
||||
|
||||
<section className="afpr-section">
|
||||
<div className="afpr-inner dm-section-container">
|
||||
<ScrollReveal delay={0.05}>
|
||||
<div className="afpr-header">
|
||||
<div className="afpr-eyebrow">/ Pricing Plans /</div>
|
||||
<h3 className="afpr-heading">Transparent pricing for every cargo need</h3>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
<StaggerChildren stagger={0.1} duration={0.75} yOffset={40} className="afpr-grid">
|
||||
{PLANS.map((plan) => (
|
||||
<div key={plan.name} className={`afpr-card${plan.featured ? " afpr-featured" : ""}`}>
|
||||
<div className="afpr-card-top">
|
||||
<div className="afpr-price">{plan.price}</div>
|
||||
<span className="afpr-price-note">{plan.priceNote}</span>
|
||||
<span className="afpr-plan-name">{plan.name}</span>
|
||||
</div>
|
||||
<div className="afpr-card-body">
|
||||
<ul className="afpr-features">
|
||||
{plan.features.map((feat) => (
|
||||
<li key={feat.text} className={feat.active ? "afpr-feat-active" : ""}>
|
||||
<span className={`afpr-feat-dot ${feat.active ? "on" : "off"}`} aria-hidden="true">
|
||||
{feat.active ? (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
|
||||
<polyline points="20 6 9 17 4 12" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
||||
<line x1="18" y1="6" x2="6" y2="18" />
|
||||
<line x1="6" y1="6" x2="18" y2="18" />
|
||||
</svg>
|
||||
)}
|
||||
</span>
|
||||
{feat.text}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Link href="/contact" className="logico-alter-button">
|
||||
Get started
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</StaggerChildren>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
55
src/components/sections/AirFreightCTA.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function AirFreightCTA() {
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
@media (max-width: 768px) {
|
||||
.afcta-container {
|
||||
margin-top: 40px !important;
|
||||
margin-bottom: 40px !important;
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
.afcta-box {
|
||||
padding: 48px 20px !important;
|
||||
border-radius: 22px !important;
|
||||
}
|
||||
.afcta-title {
|
||||
font-size: clamp(28px, 6vw, 38px) !important;
|
||||
line-height: 1.25 !important;
|
||||
margin-bottom: 16px !important;
|
||||
}
|
||||
.afcta-sub {
|
||||
font-size: 15px !important;
|
||||
line-height: 1.5 !important;
|
||||
margin-bottom: 24px !important;
|
||||
}
|
||||
}
|
||||
`}} />
|
||||
<div className="we-container afcta-container">
|
||||
<div className="we-cta reveal afcta-box">
|
||||
<div className="we-cta-inner">
|
||||
<h2 className="we-cta-title afcta-title">
|
||||
Ready to move your<br />
|
||||
<em>cargo by air?</em>
|
||||
</h2>
|
||||
<p className="we-cta-sub afcta-sub">
|
||||
Get a binding Doormile Wings quote within the hour. Our logistics team<br />
|
||||
is available 24/7 across all major Indian airports and trade lanes.
|
||||
</p>
|
||||
<div className="we-cta-btns">
|
||||
<Link href="/contact" className="btn-we-primary" style={{ textDecoration: "none" }}>
|
||||
Get a Quote
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginLeft: "8px", display: "inline-block", verticalAlign: "middle" }}>
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
<polyline points="12 5 19 12 12 19" />
|
||||
</svg>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
128
src/components/sections/AirFreightCoverage.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import gsap from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
}
|
||||
|
||||
const STATS = [
|
||||
{ prefix: "", from: 7000, to: 7500, suffix: "", label: "Delivered packages" },
|
||||
{ prefix: "2.", from: 1, to: 6, suffix: " bil", label: "Tonnes of goods" },
|
||||
{ prefix: "", from: 10, to: 100, suffix: "+", label: "Countries covered" },
|
||||
{ prefix: "", from: 100, to: 550, suffix: "+", label: "Warehouses" },
|
||||
];
|
||||
|
||||
export default function AirFreightCoverage() {
|
||||
const sectionRef = useRef<HTMLDivElement>(null);
|
||||
const countersRef = useRef<(HTMLSpanElement | null)[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const section = sectionRef.current;
|
||||
if (!section) return;
|
||||
|
||||
const trigger = ScrollTrigger.create({
|
||||
trigger: section,
|
||||
start: "top 75%",
|
||||
once: true,
|
||||
onEnter: () => {
|
||||
STATS.forEach((stat, i) => {
|
||||
const el = countersRef.current[i];
|
||||
if (!el) return;
|
||||
const obj = { val: stat.from };
|
||||
gsap.to(obj, {
|
||||
val: stat.to,
|
||||
duration: 2,
|
||||
ease: "power2.out",
|
||||
delay: i * 0.12,
|
||||
onUpdate: () => {
|
||||
if (el) {
|
||||
el.textContent = Math.round(obj.val).toLocaleString("en-IN");
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return () => { trigger.kill(); };
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.afc4-section {
|
||||
background: #1F1F1F;
|
||||
padding: 80px 20px;
|
||||
}
|
||||
.afc4-inner {
|
||||
}
|
||||
.afc4-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 2px;
|
||||
}
|
||||
.afc4-item {
|
||||
padding: 50px 40px;
|
||||
background: rgba(255,255,255,0.03);
|
||||
border: 1px solid rgba(255,255,255,0.07);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
transition: background 0.35s ease, border-color 0.35s ease;
|
||||
}
|
||||
.afc4-item:hover {
|
||||
background: rgba(192,18,39,0.05);
|
||||
border-color: rgba(192,18,39,0.25);
|
||||
}
|
||||
.afc4-number {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: clamp(48px, 5vw, 80px);
|
||||
font-weight: 800;
|
||||
color: #FFFFFF;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
.afc4-number-suffix {
|
||||
color: #c01227;
|
||||
}
|
||||
.afc4-label {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: rgba(255,255,255,0.45);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
margin-top: 4px;
|
||||
}
|
||||
@media (max-width: 1020px) {
|
||||
.afc4-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
.afc4-section { padding: 60px 20px; }
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.afc4-item { padding: 30px 24px; }
|
||||
.afc4-section { padding: 40px 20px; }
|
||||
}
|
||||
`}} />
|
||||
|
||||
<section className="afc4-section" ref={sectionRef}>
|
||||
<div className="afc4-inner dm-section-container">
|
||||
<div className="afc4-grid">
|
||||
{STATS.map((stat, i) => (
|
||||
<div key={stat.label} className="afc4-item">
|
||||
<div className="afc4-number">
|
||||
{stat.prefix && <span>{stat.prefix}</span>}
|
||||
<span ref={(el) => { countersRef.current[i] = el; }}>{stat.from.toLocaleString("en-IN")}</span>
|
||||
{stat.suffix && <span className="afc4-number-suffix">{stat.suffix}</span>}
|
||||
</div>
|
||||
<div className="afc4-label">{stat.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
219
src/components/sections/AirFreightFAQ.tsx
Normal file
@@ -0,0 +1,219 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { ScrollReveal } from "@/animations/Reveal";
|
||||
|
||||
const FAQS = [
|
||||
{
|
||||
q: "How can we work with Doormile Wings?",
|
||||
a: "Getting started with Doormile Wings is straightforward — contact our ops team or use our online quote form. We'll assess your cargo requirements, recommend the right service tier, and handle all documentation, booking, and customs coordination from a single point of contact.",
|
||||
},
|
||||
{
|
||||
q: "What types of cargo can Doormile move by air?",
|
||||
a: "We handle general cargo, express parcels, perishables, pharmaceuticals, dangerous goods (IATA-classified), oversized freight, and high-value shipments. Our IATA-certified team manages special commodity requirements including temperature control, security packaging, and regulatory documentation.",
|
||||
},
|
||||
{
|
||||
q: "Does Doormile handle customs clearance on both ends?",
|
||||
a: "Yes. Doormile provides end-to-end customs management for both import and export lanes. We handle HS code classification, duty calculations, export and import declarations, and liaison with customs authorities at origin and destination. Our in-house compliance team eliminates the need for separate customs brokers.",
|
||||
},
|
||||
{
|
||||
q: "Do you do transportation using air internationally?",
|
||||
a: "Doormile connects India to 60+ countries via our partner airline network. We manage full export documentation, origin customs, air transport, destination customs, and ground delivery at the other end — under one SLA, with end-to-end visibility from our tracking platform.",
|
||||
},
|
||||
{
|
||||
q: "How much cargo can you handle and how quickly?",
|
||||
a: "We handle shipments from a single kilogram to full charter allocations. For express bookings on standard lanes, same-day confirmation is standard. Charter requests are assessed within 2 hours. Our network handles over 500 tonnes of cargo monthly across all service types.",
|
||||
},
|
||||
];
|
||||
|
||||
export default function AirFreightFAQ() {
|
||||
const [openIndex, setOpenIndex] = useState<number | null>(0);
|
||||
|
||||
const toggle = (index: number) => {
|
||||
setOpenIndex((prev) => (prev === index ? null : index));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.affaq-section {
|
||||
background: #ffffff;
|
||||
padding: 80px 20px;
|
||||
}
|
||||
.affaq-inner {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.6fr;
|
||||
gap: 80px;
|
||||
align-items: start;
|
||||
}
|
||||
.affaq-left {
|
||||
position: sticky;
|
||||
top: 120px;
|
||||
}
|
||||
.affaq-eyebrow {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(17,17,17,0.4);
|
||||
margin: 0 0 18px;
|
||||
display: block;
|
||||
}
|
||||
.logico-front-end .affaq-section h3.affaq-heading {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: clamp(26px, 3vw, 44px);
|
||||
font-weight: 800;
|
||||
line-height: 1.15;
|
||||
letter-spacing: -0.03em;
|
||||
text-transform: uppercase;
|
||||
color: #1F1F1F;
|
||||
-webkit-text-fill-color: #1F1F1F;
|
||||
margin: 0 0 32px;
|
||||
}
|
||||
.logico-front-end .affaq-section .logico-alter-button {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
}
|
||||
.affaq-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.affaq-item {
|
||||
border-bottom: 1px solid rgba(17,17,17,0.1);
|
||||
}
|
||||
.affaq-item:first-child {
|
||||
border-top: 1px solid rgba(17,17,17,0.1);
|
||||
}
|
||||
.affaq-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
padding: 26px 0;
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: none;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
.affaq-trigger:focus-visible {
|
||||
outline: 2px solid #c01227;
|
||||
outline-offset: 2px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.logico-front-end .affaq-section .affaq-trigger-text {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #111111;
|
||||
-webkit-text-fill-color: #111111;
|
||||
line-height: 1.4;
|
||||
text-align: left;
|
||||
transition: color 0.3s ease;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.affaq-item.open .affaq-trigger-text {
|
||||
color: #c01227 !important;
|
||||
-webkit-text-fill-color: #c01227 !important;
|
||||
}
|
||||
.affaq-icon {
|
||||
flex: 0 0 28px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
border: 1.5px solid rgba(17,17,17,0.15);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #111111;
|
||||
transition: border-color 0.3s ease, background 0.3s ease, transform 0.4s cubic-bezier(0.165,0.84,0.44,1), color 0.3s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.affaq-item.open .affaq-icon {
|
||||
border-color: #c01227;
|
||||
background: #c01227;
|
||||
color: #ffffff;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.affaq-icon svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
stroke: currentColor;
|
||||
}
|
||||
.affaq-answer {
|
||||
overflow: hidden;
|
||||
max-height: 0;
|
||||
transition: max-height 0.45s cubic-bezier(0.165,0.84,0.44,1);
|
||||
}
|
||||
.affaq-item.open .affaq-answer {
|
||||
max-height: 400px;
|
||||
}
|
||||
.affaq-answer-inner {
|
||||
padding: 0 0 28px;
|
||||
font-size: 15px;
|
||||
font-weight: 400;
|
||||
color: rgba(17,17,17,0.6);
|
||||
line-height: 1.7;
|
||||
}
|
||||
@media (max-width: 1020px) {
|
||||
.affaq-inner {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 40px;
|
||||
}
|
||||
.affaq-left { position: static; }
|
||||
.affaq-section { padding: 60px 20px; }
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.affaq-section { padding: 40px 20px; }
|
||||
.logico-front-end .affaq-section .affaq-trigger-text { font-size: 14px; }
|
||||
.affaq-trigger { padding: 20px 0; }
|
||||
}
|
||||
`}} />
|
||||
|
||||
<section className="affaq-section">
|
||||
<div className="affaq-inner dm-section-container">
|
||||
{/* Left column */}
|
||||
<ScrollReveal delay={0.05} yOffset={30}>
|
||||
<div className="affaq-left">
|
||||
<span className="affaq-eyebrow">/ FAQ /</span>
|
||||
<h3 className="affaq-heading">Find answers before working with us</h3>
|
||||
<Link href="/contact" className="logico-alter-button">
|
||||
Explore More
|
||||
</Link>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
{/* Right column — accordion */}
|
||||
<ScrollReveal delay={0.15} yOffset={30}>
|
||||
<div className="affaq-list">
|
||||
{FAQS.map((faq, index) => (
|
||||
<div key={index} className={`affaq-item${openIndex === index ? " open" : ""}`}>
|
||||
<button
|
||||
type="button"
|
||||
className="affaq-trigger"
|
||||
onClick={() => toggle(index)}
|
||||
aria-expanded={openIndex === index}
|
||||
>
|
||||
<span className="affaq-trigger-text">{faq.q}</span>
|
||||
<span className="affaq-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
||||
<line x1="12" y1="5" x2="12" y2="19" />
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<div className="affaq-answer" aria-hidden={openIndex !== index}>
|
||||
<div className="affaq-answer-inner">{faq.a}</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
109
src/components/sections/AirFreightFleet.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import { ScrollReveal } from "@/animations/Reveal";
|
||||
|
||||
const CLIENTS = [
|
||||
{ name: "DHL Express", abbr: "DHL" },
|
||||
{ name: "FedEx India", abbr: "FEDEX" },
|
||||
{ name: "Blue Dart", abbr: "BDART" },
|
||||
{ name: "Mahindra Logistics", abbr: "MLG" },
|
||||
{ name: "GATI-KWE", abbr: "GATI" },
|
||||
{ name: "Allcargo Group", abbr: "ACG" },
|
||||
];
|
||||
|
||||
export default function AirFreightFleet() {
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.afcl-section {
|
||||
background: #ffffff;
|
||||
padding: 60px 20px;
|
||||
border-top: 1px solid rgba(17,17,17,0.06);
|
||||
border-bottom: 1px solid rgba(17,17,17,0.06);
|
||||
}
|
||||
.afcl-inner {
|
||||
}
|
||||
.afcl-label {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(17,17,17,0.35);
|
||||
text-align: center;
|
||||
margin: 0 0 36px;
|
||||
}
|
||||
.afcl-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
gap: 2px;
|
||||
}
|
||||
.afcl-logo-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 28px 20px;
|
||||
border: 1px solid rgba(17,17,17,0.07);
|
||||
transition: border-color 0.3s ease, background 0.3s ease;
|
||||
cursor: default;
|
||||
}
|
||||
.afcl-logo-cell:hover {
|
||||
border-color: rgba(192,18,39,0.2);
|
||||
background: rgba(192,18,39,0.02);
|
||||
}
|
||||
.afcl-logo-text {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(17,17,17,0.3);
|
||||
transition: color 0.3s ease;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.afcl-logo-cell:hover .afcl-logo-text {
|
||||
color: rgba(17,17,17,0.7);
|
||||
}
|
||||
.afcl-logo-fullname {
|
||||
font-size: 9px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(17,17,17,0.2);
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
.afcl-logo-cell:hover .afcl-logo-fullname {
|
||||
color: rgba(17,17,17,0.4);
|
||||
}
|
||||
@media (max-width: 1020px) {
|
||||
.afcl-grid { grid-template-columns: repeat(3, 1fr); }
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.afcl-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
.afcl-section { padding: 40px 20px; }
|
||||
}
|
||||
`}} />
|
||||
|
||||
<section className="afcl-section">
|
||||
<div className="afcl-inner dm-section-container">
|
||||
<ScrollReveal delay={0.05}>
|
||||
<div className="afcl-label">Trusted by logistics partners across India</div>
|
||||
</ScrollReveal>
|
||||
<ScrollReveal delay={0.1} yOffset={20}>
|
||||
<div className="afcl-grid">
|
||||
{CLIENTS.map((client) => (
|
||||
<div key={client.name} className="afcl-logo-cell">
|
||||
<div>
|
||||
<span className="afcl-logo-text">{client.abbr}</span>
|
||||
<span className="afcl-logo-fullname">{client.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
251
src/components/sections/AirFreightHero.tsx
Normal file
@@ -0,0 +1,251 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import Link from "next/link";
|
||||
import gsap from "gsap";
|
||||
import { ShimmerText } from "@/animations/Reveal";
|
||||
|
||||
export default function AirFreightHero() {
|
||||
const [activeSlide, setActiveSlide] = useState(0);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setActiveSlide((prev) => (prev === 0 ? 1 : 0));
|
||||
}, 7000);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return;
|
||||
const activeItem = containerRef.current.querySelector(".owl-item.active");
|
||||
if (!activeItem) return;
|
||||
const heading = activeItem.querySelector(".heading-content");
|
||||
const text = activeItem.querySelector(".text-content");
|
||||
const btn = activeItem.querySelector(".content-slider-item-buttons");
|
||||
if (heading) {
|
||||
gsap.killTweensOf(heading);
|
||||
gsap.fromTo(heading, { y: 60, opacity: 0 }, { y: 0, opacity: 1, duration: 1.1, ease: "power4.out" });
|
||||
}
|
||||
if (text) {
|
||||
gsap.killTweensOf(text);
|
||||
gsap.fromTo(text, { y: 30, opacity: 0 }, { y: 0, opacity: 1, duration: 0.95, ease: "power3.out", delay: 0.22 });
|
||||
}
|
||||
if (btn) {
|
||||
gsap.killTweensOf(btn);
|
||||
gsap.fromTo(btn, { y: 20, opacity: 0 }, { y: 0, opacity: 1, duration: 0.8, ease: "power3.out", delay: 0.42 });
|
||||
}
|
||||
}, [activeSlide]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<link rel="preload" as="image" href="/images/air-freight-slide-1.jpg" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.af-hero-bg.slide-1 {
|
||||
background-image: linear-gradient(166deg, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0.2) 100%), url('/images/air-freight-slide-1.jpg');
|
||||
background-position: bottom center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
.af-hero-bg.slide-2 {
|
||||
background-image: linear-gradient(166deg, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0.2) 100%), url('/images/air-freight-slide-2.jpg');
|
||||
background-position: bottom center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
.af-hero-slide .slide-content {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 20px 70px !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.af-hero-slide .slide-content-inner {
|
||||
width: 100%;
|
||||
max-width: 1000px;
|
||||
margin: 58px auto 0 auto;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.af-hero-slide .content-slider-item-heading,
|
||||
.af-hero-slide .content-slider-item-heading .heading-content {
|
||||
font-size: clamp(36px, 5.5vw, 80px) !important;
|
||||
line-height: 1.125em !important;
|
||||
word-spacing: -0.03em;
|
||||
color: #FFFFFF !important;
|
||||
text-align: center !important;
|
||||
width: 100%;
|
||||
}
|
||||
.af-hero-slide .content-slider-item-text {
|
||||
color: #FFFFFF;
|
||||
text-align: center !important;
|
||||
font-size: clamp(18px, 1.5vw, 24px) !important;
|
||||
line-height: 1.65 !important;
|
||||
margin-top: 23px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.af-hero-slide .content-slider-item-text .text-content {
|
||||
max-width: 780px;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.af-hero-slide .content-slider-item-buttons {
|
||||
margin-top: 32px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.logico-front-end .af-hero-slide .logico-alter-button {
|
||||
display: inline-block;
|
||||
color: #FFFFFF !important;
|
||||
border-color: rgba(255,255,255,0.45) !important;
|
||||
background: transparent !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.logico-front-end .af-hero-slide .logico-alter-button:hover {
|
||||
background: #FFFFFF !important;
|
||||
color: #1F1F1F !important;
|
||||
border-color: #FFFFFF !important;
|
||||
}
|
||||
.logico-content-slider-widget .owl-stage-outer {
|
||||
height: 800px !important;
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.af-hero-slide .slide-content-inner { max-width: 90%; }
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
.af-hero-slide .slide-content { padding: 0 30px 50px !important; }
|
||||
.af-hero-slide .slide-content-inner { max-width: 95%; }
|
||||
.logico-content-slider-widget .owl-stage-outer { height: 640px !important; }
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.af-hero-slide .slide-content { padding: 0 20px 40px !important; }
|
||||
.af-hero-slide .slide-content-inner { max-width: 100%; margin: 0 auto; }
|
||||
.logico-content-slider-widget .owl-stage-outer { height: 580px !important; }
|
||||
.af-hero-page .owl-nav { display: none !important; }
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.af-hero-slide .content-slider-item-heading { font-size: clamp(28px, 8vw, 42px) !important; }
|
||||
.logico-content-slider-widget .owl-stage-outer { height: 520px !important; }
|
||||
}
|
||||
`}} />
|
||||
|
||||
<div className="af-hero-page elementor-element elementor-element-741f56c e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="741f56c" data-element_type="container" data-e-type="container">
|
||||
<div className="elementor-element elementor-element-6c7cbcb elementor-widget elementor-widget-logico_content_slider" data-id="6c7cbcb" data-element_type="widget" data-e-type="widget" data-widget_type="logico_content_slider.default">
|
||||
<div className="elementor-widget-container">
|
||||
<div className="logico-content-slider-widget">
|
||||
<div className="content-slider-wrapper">
|
||||
<div className="content-slider-container">
|
||||
<div className="content-slider owl-carousel owl-theme nav-view-vertical nav-h-position-right nav-v-position-bottom owl-loaded owl-drag" ref={containerRef}>
|
||||
<div className="owl-stage-outer" style={{ position: "relative", overflow: "hidden" }}>
|
||||
<div className="owl-stage" style={{ position: "relative", width: "100%", height: "100%" }}>
|
||||
|
||||
{/* Slide 1 */}
|
||||
<div
|
||||
className={`owl-item af-hero-slide ${activeSlide === 0 ? "active" : ""}`}
|
||||
style={{
|
||||
position: "relative", width: "100%",
|
||||
opacity: activeSlide === 0 ? 1 : 0,
|
||||
visibility: activeSlide === 0 ? "visible" : "hidden",
|
||||
transition: "opacity 0.85s ease-in-out, visibility 0.85s ease-in-out",
|
||||
zIndex: activeSlide === 0 ? 2 : 1,
|
||||
}}
|
||||
>
|
||||
<div className="content-item slider-item slide-style-standard af-hero-bg slide-1">
|
||||
<div className="slide-content">
|
||||
<div className="slide-content-inner">
|
||||
<h1 className="content-slider-item-heading logico-content-wrapper-1">
|
||||
<span className="heading-content block">
|
||||
The Fastest Way<br />
|
||||
<ShimmerText>To Transport Goods</ShimmerText>
|
||||
</span>
|
||||
</h1>
|
||||
<div className="content-slider-item-text logico-content-wrapper-2">
|
||||
<div className="text-content">
|
||||
<p>Doormile Wings delivers precision cargo solutions across domestic and international trade lanes — guaranteed transit times, real-time tracking, full customs management.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Slide 2 */}
|
||||
<div
|
||||
className={`owl-item af-hero-slide ${activeSlide === 1 ? "active" : ""}`}
|
||||
style={{
|
||||
position: "absolute", top: 0, left: 0, width: "100%",
|
||||
opacity: activeSlide === 1 ? 1 : 0,
|
||||
visibility: activeSlide === 1 ? "visible" : "hidden",
|
||||
transition: "opacity 0.85s ease-in-out, visibility 0.85s ease-in-out",
|
||||
zIndex: activeSlide === 1 ? 2 : 1,
|
||||
}}
|
||||
>
|
||||
<div className="content-item slider-item slide-style-standard af-hero-bg slide-2">
|
||||
<div className="slide-content">
|
||||
<div className="slide-content-inner">
|
||||
<h1 className="content-slider-item-heading logico-content-wrapper-1">
|
||||
<span className="heading-content block">
|
||||
A New Freight<br />
|
||||
<ShimmerText>Shipping Experience</ShimmerText>
|
||||
</span>
|
||||
</h1>
|
||||
<div className="content-slider-item-text logico-content-wrapper-2">
|
||||
<div className="text-content">
|
||||
<p>From runway to doorstep — seamless air-to-ground handoffs powered by our integrated logistics network across India and global destinations.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="owl-nav">
|
||||
<button type="button" className="owl-next" onClick={() => setActiveSlide((prev) => (prev === 0 ? 1 : 0))} aria-label="Next" />
|
||||
<button type="button" className="owl-prev" onClick={() => setActiveSlide((prev) => (prev === 0 ? 1 : 0))} aria-label="Previous" />
|
||||
</div>
|
||||
|
||||
<div className="slider-footer slider-footer-position-after slider-footer-width-full slider-footer-view-inside">
|
||||
<div className="slider-footer-content">
|
||||
<div className="slider-pagination" style={{ display: "flex", justifyContent: "flex-end", alignItems: "center" }}>
|
||||
<div className="slider-progress-wrapper" style={{ marginRight: "35px", display: "flex", flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<div style={{ fontSize: "16px", fontWeight: 600, color: "#FFFFFF", marginBottom: "4px" }}>
|
||||
<span className="slider-progress-current">{activeSlide === 0 ? "01" : "02"}</span>
|
||||
{" / "}
|
||||
<span className="slider-progress-all" style={{ opacity: 0.6 }}>02</span>
|
||||
</div>
|
||||
<div style={{ width: "80px", height: "2px", background: "rgba(255,255,255,0.2)", position: "relative", borderRadius: "1px", overflow: "hidden" }}>
|
||||
<div style={{
|
||||
position: "absolute",
|
||||
left: activeSlide === 0 ? "0" : "50%",
|
||||
width: "50%", height: "100%",
|
||||
background: "#c01227",
|
||||
transition: "left 0.35s ease",
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="owl-dots" style={{ display: "none" }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
208
src/components/sections/AirFreightServices.tsx
Normal file
@@ -0,0 +1,208 @@
|
||||
"use client";
|
||||
|
||||
import { StaggerChildren } from "@/animations/Reveal";
|
||||
|
||||
const SERVICE_LIST = [
|
||||
"Doormile Wings",
|
||||
"Express Cargo",
|
||||
"Cold Chain Logistics",
|
||||
"Customs Clearance",
|
||||
"Charter Solutions",
|
||||
"Door-to-Door Delivery",
|
||||
];
|
||||
|
||||
export default function AirFreightServices() {
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.af3-section {
|
||||
background: #1F1F1F;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
.af3-inner {
|
||||
max-width: 1480px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.af3-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 0;
|
||||
}
|
||||
.af3-col {
|
||||
padding: 72px 50px 60px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-right: 1px solid rgba(255,255,255,0.08);
|
||||
min-height: 505px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.af3-col:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
.af3-label {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: #c01227;
|
||||
margin: 0 0 14px;
|
||||
}
|
||||
.af3-heading {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: clamp(20px, 1.8vw, 26px);
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
color: #ffffff;
|
||||
margin: 0 0 14px;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.af3-divider {
|
||||
height: 1px;
|
||||
background: rgba(255,255,255,0.1);
|
||||
margin: 45px 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.af3-desc {
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
color: rgba(255,255,255,0.55);
|
||||
margin: 0;
|
||||
padding-right: 20px;
|
||||
}
|
||||
.af3-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.af3-section .af3-list li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 0;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: rgba(255,255,255,0.75);
|
||||
border-bottom: 1px solid rgba(255,255,255,0.06);
|
||||
transition: color 0.3s ease;
|
||||
cursor: default;
|
||||
}
|
||||
.af3-section .af3-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.af3-section .af3-list li:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
.af3-section .af3-list li::before {
|
||||
content: none;
|
||||
}
|
||||
.af3-list-arrow {
|
||||
flex: 0 0 auto;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-right: 2px solid #c01227;
|
||||
border-top: 2px solid #c01227;
|
||||
transform: rotate(45deg);
|
||||
margin-top: 1px;
|
||||
}
|
||||
.af3-stat-wrap {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 14px;
|
||||
margin-top: auto;
|
||||
}
|
||||
.af3-stat-number {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: clamp(42px, 4vw, 64px);
|
||||
font-weight: 800;
|
||||
color: #ffffff;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
.af3-stat-label {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: rgba(255,255,255,0.5);
|
||||
line-height: 1.4;
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
.af3-col {
|
||||
padding: 40px 30px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.af3-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.af3-col {
|
||||
border-right: none;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.08);
|
||||
padding: 40px 20px;
|
||||
min-height: unset;
|
||||
}
|
||||
.af3-col:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.af3-divider {
|
||||
margin: 30px 0;
|
||||
}
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.af3-col {
|
||||
padding: 30px 20px;
|
||||
}
|
||||
}
|
||||
`}} />
|
||||
|
||||
<div className="af3-section">
|
||||
<div className="af3-inner">
|
||||
<StaggerChildren className="af3-grid" stagger={0.1} yOffset={30} triggerOnce>
|
||||
|
||||
{/* Column 1 – Products & Services */}
|
||||
<div className="af3-col">
|
||||
<div className="af3-label">/ Products & Services /</div>
|
||||
<h5 className="af3-heading">Products & Services</h5>
|
||||
<p className="af3-desc">Comprehensive air cargo and logistics solutions built for businesses that demand speed, reliability, and complete cargo visibility.</p>
|
||||
<div className="af3-divider" />
|
||||
<ul className="af3-list">
|
||||
{SERVICE_LIST.map((item) => (
|
||||
<li key={item}>
|
||||
<span className="af3-list-arrow" aria-hidden="true" />
|
||||
{item}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Column 2 – Our Specialty */}
|
||||
<div className="af3-col">
|
||||
<div className="af3-label">/ Our Specialty /</div>
|
||||
<h5 className="af3-heading">Doormile Wings</h5>
|
||||
<p className="af3-desc">Time-critical shipments handled with the highest priority. Guaranteed next-flight-out scheduling, same-day airport handoff, and binding SLA commitments on every air cargo booking.</p>
|
||||
<div className="af3-divider" />
|
||||
<p className="af3-desc">Our IATA-certified team manages special commodity requirements including temperature control, security packaging, and regulatory documentation for every cargo category.</p>
|
||||
</div>
|
||||
|
||||
{/* Column 3 – Our Reach */}
|
||||
<div className="af3-col">
|
||||
<div className="af3-label">/ Our Reach /</div>
|
||||
<h5 className="af3-heading">Global Network</h5>
|
||||
<p className="af3-desc">Doormile operates an integrated air and ground logistics network spanning domestic hubs and international trade lanes — giving your cargo a direct path to any destination.</p>
|
||||
<div className="af3-divider" />
|
||||
<div className="af3-stat-wrap">
|
||||
<div className="af3-stat-number">500+</div>
|
||||
<div className="af3-stat-label">Tonnes<br />monthly</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</StaggerChildren>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
250
src/components/sections/AirFreightWorkflow.tsx
Normal file
@@ -0,0 +1,250 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { ScrollReveal } from "@/animations/Reveal";
|
||||
|
||||
const ICON_BOXES = [
|
||||
{
|
||||
title: "Doormile Wings Express",
|
||||
desc: "Time-critical shipments handled with next-flight-out scheduling and binding SLA commitments. Priority customs processing at every origin and destination airport.",
|
||||
},
|
||||
{
|
||||
title: "Ground Handoff Network",
|
||||
desc: "Seamless air-to-ground integration ensures your cargo transitions from the airport terminal to last-mile delivery without gaps, delays, or visibility breaks.",
|
||||
},
|
||||
{
|
||||
title: "Temperature Cargo",
|
||||
desc: "End-to-end cold chain management for pharmaceuticals, perishables, and biological cargo — IATA CEIV Pharma compliant with continuous temperature logging.",
|
||||
},
|
||||
];
|
||||
|
||||
export default function AirFreightWorkflow() {
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.afw-section {
|
||||
background: #1F1F1F;
|
||||
padding: 0 20px;
|
||||
border-radius: 0 0 25px 25px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.afw-inner {
|
||||
padding-top: 120px;
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
.afw-label {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(255,255,255,0.4);
|
||||
margin: 0;
|
||||
}
|
||||
.afw-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
margin-top: 60px;
|
||||
}
|
||||
.afw-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.logico-front-end .afw-section h3.afw-heading {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: clamp(24px, 2.8vw, 44px);
|
||||
font-weight: 800;
|
||||
line-height: 1.15;
|
||||
letter-spacing: -0.03em;
|
||||
text-transform: uppercase;
|
||||
color: #FFFFFF;
|
||||
-webkit-text-fill-color: #FFFFFF;
|
||||
margin: 0;
|
||||
max-width: 420px;
|
||||
}
|
||||
.afw-left-img {
|
||||
margin-top: 67px;
|
||||
border-radius: 25px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
aspect-ratio: 626 / 692;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.afw-right {
|
||||
padding-left: 100px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.afw-map {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
object-position: center;
|
||||
opacity: 0.05;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
.afw-boxes {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.afw-icon-box {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 20px;
|
||||
}
|
||||
.afw-icon-wrap {
|
||||
flex-shrink: 0;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 50%;
|
||||
background: #c01227;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.afw-icon-wrap svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
stroke: currentColor;
|
||||
}
|
||||
.afw-icon-content {
|
||||
flex: 1;
|
||||
}
|
||||
.logico-front-end .afw-section h4.afw-box-title {
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
color: #FFFFFF;
|
||||
-webkit-text-fill-color: #FFFFFF;
|
||||
margin: 0 0 5px;
|
||||
}
|
||||
.afw-box-desc {
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
color: rgba(255,255,255,0.6);
|
||||
margin: 0;
|
||||
}
|
||||
.afw-divider {
|
||||
border: none;
|
||||
border-top: 1px solid rgba(255,255,255,0.12);
|
||||
margin: 38px 0;
|
||||
}
|
||||
.afw-cta-wrap {
|
||||
margin-top: 8px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.logico-front-end .afw-section .logico-alter-button {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
color: #FFFFFF !important;
|
||||
border-color: rgba(255,255,255,0.3) !important;
|
||||
}
|
||||
.logico-front-end .afw-section .logico-alter-button:hover {
|
||||
background: #FFFFFF !important;
|
||||
color: #1F1F1F !important;
|
||||
border-color: #FFFFFF !important;
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.afw-right { padding-left: 60px; }
|
||||
}
|
||||
@media (max-width: 1020px) {
|
||||
.afw-grid { grid-template-columns: 1fr; gap: 60px; }
|
||||
.afw-right { padding-left: 0; }
|
||||
.afw-left-img { max-width: 500px; margin-top: 40px; }
|
||||
.afw-inner { padding-top: 80px; padding-bottom: 70px; }
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.afw-inner { padding-top: 60px; padding-bottom: 60px; }
|
||||
.afw-left-img { aspect-ratio: 16 / 9; }
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.afw-section { padding: 0 20px; border-radius: 0 0 16px 16px; }
|
||||
.afw-inner { padding-top: 40px; padding-bottom: 50px; }
|
||||
.afw-icon-box { gap: 14px; }
|
||||
.logico-front-end .afw-section h4.afw-box-title { font-size: 17px; }
|
||||
}
|
||||
`}} />
|
||||
|
||||
<section className="afw-section">
|
||||
<div className="afw-inner dm-section-container">
|
||||
<ScrollReveal delay={0.05} yOffset={20}>
|
||||
<div className="afw-label">/ Special Things /</div>
|
||||
</ScrollReveal>
|
||||
|
||||
<div className="afw-grid">
|
||||
{/* Left column: heading + image */}
|
||||
<ScrollReveal delay={0.08} yOffset={40}>
|
||||
<div className="afw-left">
|
||||
<h3 className="afw-heading">
|
||||
Special things which we do for our clients
|
||||
</h3>
|
||||
<div className="afw-left-img">
|
||||
<Image
|
||||
src="/images/air-freight-pic-1.jpg"
|
||||
alt="Doormile Wings cargo operations"
|
||||
fill
|
||||
style={{ objectFit: "cover", objectPosition: "center" }}
|
||||
sizes="(max-width: 768px) 100vw, 45vw"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
{/* Right column: world map bg + icon boxes + button */}
|
||||
<ScrollReveal delay={0.18} yOffset={40}>
|
||||
<div className="afw-right">
|
||||
{/* World map background */}
|
||||
<Image
|
||||
src="/images/bg-map.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
fill={false}
|
||||
width={965}
|
||||
height={474}
|
||||
className="afw-map"
|
||||
/>
|
||||
|
||||
<div className="afw-boxes">
|
||||
{ICON_BOXES.map((box, i) => (
|
||||
<div key={box.title}>
|
||||
<div className="afw-icon-box">
|
||||
<div className="afw-icon-wrap" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
||||
<polyline points="5 12 12 5 19 12" />
|
||||
<polyline points="5 19 12 12 19 19" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="afw-icon-content">
|
||||
<h4 className="afw-box-title">{box.title}</h4>
|
||||
<p className="afw-box-desc">{box.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
{i < ICON_BOXES.length - 1 && (
|
||||
<hr className="afw-divider" />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="afw-cta-wrap" style={{ marginTop: "48px" }}>
|
||||
<Link href="/contact" className="logico-alter-button">
|
||||
Explore More
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -26,9 +26,40 @@ export default function BlogGrid() {
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.elementor-104 .elementor-element.elementor-element-c70681e {
|
||||
margin-top: var(--space-section) !important;
|
||||
margin-bottom: 16px !important;
|
||||
}
|
||||
.custom-blog-grid {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 48px !important;
|
||||
gap: 28px !important;
|
||||
padding: 24px 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.elementor-104 .elementor-element.elementor-element-c70681e {
|
||||
--padding-left: 10px !important;
|
||||
--padding-right: 10px !important;
|
||||
padding-left: 10px !important;
|
||||
padding-right: 10px !important;
|
||||
}
|
||||
.elementor-104 .elementor-element.elementor-element-3dec5cf {
|
||||
--padding-left: 0px !important;
|
||||
--padding-right: 0px !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
.elementor-104 .elementor-element.elementor-element-aa12479,
|
||||
.elementor-104 .elementor-element.elementor-element-aa12479 > .elementor-widget-container,
|
||||
.elementor-104 .archive-listing,
|
||||
.elementor-104 .custom-blog-grid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
.elementor-104 .custom-blog-grid {
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +113,7 @@ export default function BlogGrid() {
|
||||
font-family: var(--font-manrope), sans-serif !important;
|
||||
}
|
||||
|
||||
/* Bottom block pinned to the card base — keeps Read More + image at the
|
||||
/* Bottom block pinned to the card base. Keeps Read More + image at the
|
||||
same vertical position across cards with different text lengths. */
|
||||
.custom-blog-bottom {
|
||||
display: flex !important;
|
||||
|
||||
@@ -147,6 +147,12 @@ const STYLES = `
|
||||
padding: clamp(24px, 3vw, 32px) clamp(20px, 4vw, 40px) clamp(8px, 1.5vw, 16px);
|
||||
display: flex; flex-direction: column; gap: clamp(32px, 4vw, 48px);
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.dm-blog-footer-inner {
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Prev / Next */
|
||||
.dm-prevnext {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function BlogsHero() {
|
||||
return (
|
||||
<>
|
||||
<link rel="preload" as="image" href="/images/home2-banner-1.webp" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.blogs-hero-title {
|
||||
color: #ffffff !important;
|
||||
@@ -15,18 +15,31 @@ export default function BlogsHero() {
|
||||
letter-spacing: -1.5px !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
.blogs-hero-content {
|
||||
position: relative !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
flex-direction: column !important;
|
||||
max-width: 1000px !important;
|
||||
margin: 0 auto !important;
|
||||
padding: 0 15px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
`}} />
|
||||
<div className="custom-standard-hero-container">
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: "url(/images/home2-banner-1.jpg)",
|
||||
backgroundImage: "url(/images/home2-banner-1.webp)",
|
||||
backgroundPosition: "center center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "cover"
|
||||
}}
|
||||
className="custom-standard-hero-card"
|
||||
>
|
||||
<div className="e-con-inner" style={{ position: "relative", width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column" }}>
|
||||
<div className="blogs-hero-content">
|
||||
|
||||
{/* Title / Heading for Blogs */}
|
||||
<div style={{ textAlign: "center", color: "#fff", zIndex: 5 }}>
|
||||
@@ -43,4 +56,3 @@ export default function BlogsHero() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -492,7 +492,11 @@ export default function CompetitiveEdge() {
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.comparison-section {
|
||||
padding: 80px 0;
|
||||
padding: 56px 0;
|
||||
}
|
||||
|
||||
.comparison-section .container {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.moat-heading {
|
||||
|
||||
@@ -33,6 +33,25 @@ export default function ConnectedLogistics() {
|
||||
max-width: min(526px, 100%) !important;
|
||||
}
|
||||
|
||||
/* Sizing and identical padding on all 4 sides for Connected Logistics Image container */
|
||||
.elementor-element-99768ba .elementor-widget-container {
|
||||
display: flex !important;
|
||||
justify-content: center !important;
|
||||
align-items: center !important;
|
||||
padding: 40px !important; /* Identical gap on left, right, top, and bottom */
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.elementor-element-99768ba img.wp-image-4481 {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important; /* Allow natural responsive scaling on desktop */
|
||||
height: auto !important;
|
||||
object-fit: cover !important;
|
||||
border-radius: 25px !important; /* Preserve 25px border radius */
|
||||
margin: 0 auto !important;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/* Desktop/Laptop (min-width: 1025px) column width and flex rules */
|
||||
@media (min-width: 1025px) {
|
||||
.elementor-element-9ffed33 {
|
||||
@@ -67,9 +86,20 @@ export default function ConnectedLogistics() {
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
/* Force ScrollReveal wrapper div to span full width */
|
||||
.elementor-element-96343ba > div {
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
/* Show image at the bottom or top depending on order */
|
||||
.elementor-element-96343ba {
|
||||
margin-top: 30px !important;
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
|
||||
/* Reduce padding bottom of the content section on tablet */
|
||||
.elementor-element-71c3e1d {
|
||||
padding-bottom: 24px !important;
|
||||
}
|
||||
|
||||
/* Override desktop fixed widths on mobile/tablet */
|
||||
@@ -78,6 +108,52 @@ export default function ConnectedLogistics() {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
/* Allow widget container to take 100% width on mobile/tablet */
|
||||
.elementor-element-99768ba {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
/* Tablet overrides */
|
||||
.elementor-element-99768ba .elementor-widget-container {
|
||||
padding: 10px !important;
|
||||
display: block !important; /* Disable flex centering layout on mobile/tablet */
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.elementor-element.elementor-element-99768ba .elementor-widget-container img.wp-image-4481 {
|
||||
width: 100% !important;
|
||||
max-width: 600px !important; /* allow up to 600px on tablet */
|
||||
border-radius: 25px !important; /* Explicitly keep 25px */
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
/* Mobile overrides: let container take 100% width and image fill it */
|
||||
.elementor-element-99768ba {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
/* Eliminate extra gap under the content column on mobile */
|
||||
.elementor-element-71c3e1d {
|
||||
padding-bottom: 12px !important;
|
||||
}
|
||||
|
||||
.elementor-element-99768ba .elementor-widget-container {
|
||||
padding: 0px !important; /* Eliminate padding to maximize image width/height */
|
||||
display: block !important; /* Disable flex centering layout on mobile/tablet */
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.elementor-element.elementor-element-99768ba .elementor-widget-container img.wp-image-4481 {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
object-fit: cover !important;
|
||||
border-radius: 25px !important; /* Explicitly keep 25px */
|
||||
}
|
||||
}
|
||||
`}} />
|
||||
<div className="elementor-element elementor-element-9ffed33 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="9ffed33" data-element_type="container" data-e-type="container" data-settings="{"background_background":"classic"}">
|
||||
@@ -92,7 +168,7 @@ export default function ConnectedLogistics() {
|
||||
priority
|
||||
width={578}
|
||||
height={790}
|
||||
src="/images/home2-pic-3.png"
|
||||
src="/images/home2-pic-3.webp"
|
||||
className="attachment-full size-full wp-image-4481"
|
||||
alt="Connected Logistics"
|
||||
style={{
|
||||
|
||||
@@ -41,7 +41,7 @@ export default function ContactMap() {
|
||||
(bottom was square before, leaving a hard edge above the footer gap). */
|
||||
border-radius: 25px;
|
||||
overflow: hidden;
|
||||
background: #0b0b0b;
|
||||
background: transparent;
|
||||
line-height: 0;
|
||||
}
|
||||
@media (max-width: 840px) {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function ContactsHero() {
|
||||
return (
|
||||
<>
|
||||
<link rel="preload" as="image" href="/images/home2-banner-3.webp" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
.contacts-hero-custom {
|
||||
background-color: #0b0b0b !important;
|
||||
background-image: url('/images/home2-banner-3.jpg') !important;
|
||||
background-image: url('/images/home2-banner-3.webp') !important;
|
||||
background-size: cover !important;
|
||||
background-position: center !important;
|
||||
}
|
||||
@@ -82,9 +82,9 @@ export default function ContactsHero() {
|
||||
-webkit-backdrop-filter: none !important;
|
||||
border: none !important;
|
||||
border-radius: 0 !important;
|
||||
padding: 0 16px !important;
|
||||
max-width: 820px !important;
|
||||
width: 90% !important;
|
||||
padding: 0 24px !important;
|
||||
max-width: 1500px !important;
|
||||
width: 92% !important;
|
||||
box-shadow: none !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
@@ -95,60 +95,53 @@ export default function ContactsHero() {
|
||||
border-color: transparent !important;
|
||||
}
|
||||
|
||||
/* Spaced kicker */
|
||||
.contacts-hero-kicker {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
gap: 12px !important;
|
||||
margin-bottom: 24px !important;
|
||||
}
|
||||
|
||||
.contacts-hero-kicker-line {
|
||||
display: block !important;
|
||||
width: 24px !important;
|
||||
height: 1.5px !important;
|
||||
background: #C01227 !important;
|
||||
border-radius: 1px !important;
|
||||
}
|
||||
|
||||
.contacts-hero-kicker-text {
|
||||
font-size: 13px !important;
|
||||
font-weight: 850 !important;
|
||||
letter-spacing: 4px !important;
|
||||
color: #C01227 !important;
|
||||
text-transform: uppercase !important;
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif !important;
|
||||
}
|
||||
|
||||
/* Bold modern typography */
|
||||
/* Hero headline — large, light, reference-matched display type.
|
||||
Size scales with the viewport so the line-to-container width ratio
|
||||
stays constant; the cap keeps the longest line inside the 1500px
|
||||
container (with nowrap on desktop) so it can never overflow/clip. */
|
||||
.contacts-hero-title {
|
||||
font-size: clamp(34px, 5.2vw, 62px) !important;
|
||||
font-weight: 850 !important;
|
||||
line-height: 1.15 !important;
|
||||
font-size: clamp(34px, 5.9vw, 98px) !important;
|
||||
font-weight: 400 !important;
|
||||
line-height: 0.95 !important;
|
||||
color: #ffffff !important;
|
||||
text-transform: uppercase !important;
|
||||
letter-spacing: -1.8px !important;
|
||||
margin: 0 0 20px 0 !important;
|
||||
letter-spacing: -0.02em !important;
|
||||
margin: 0 0 28px 0 !important;
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif !important;
|
||||
}
|
||||
|
||||
.contacts-hero-title-line {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/* Keep each line intact on desktop — never split SYSTEM or PROMISE/KEPT */
|
||||
@media (min-width: 1024px) {
|
||||
.contacts-hero-title-line {
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
}
|
||||
|
||||
.contacts-hero-title-highlight {
|
||||
background: linear-gradient(135deg, #ffffff 40%, #c01227 100%) !important;
|
||||
-webkit-background-clip: text !important;
|
||||
-webkit-text-fill-color: transparent !important;
|
||||
color: #c01227 !important;
|
||||
}
|
||||
|
||||
/* Description text */
|
||||
.contacts-hero-desc {
|
||||
font-size: clamp(15px, 1.22vw, 18px) !important;
|
||||
font-size: clamp(15px, 1.3vw, 19px) !important;
|
||||
line-height: 1.6 !important;
|
||||
color: rgba(255, 255, 255, 0.75) !important;
|
||||
max-width: 600px !important;
|
||||
margin: 0 auto 36px auto !important;
|
||||
color: rgba(255, 255, 255, 0.82) !important;
|
||||
max-width: 640px !important;
|
||||
margin: 0 auto 24px auto !important;
|
||||
font-weight: 500 !important;
|
||||
font-family: var(--font-manrope), "Manrope", sans-serif !important;
|
||||
}
|
||||
|
||||
.contacts-hero-desc-trademark {
|
||||
color: #ffffff !important;
|
||||
font-weight: 700 !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
/* Breadcrumb capsule */
|
||||
.contacts-hero-breadcrumbs {
|
||||
display: inline-flex !important;
|
||||
@@ -201,6 +194,9 @@ export default function ContactsHero() {
|
||||
padding: 0 16px !important;
|
||||
width: 95% !important;
|
||||
}
|
||||
.contacts-hero-title {
|
||||
letter-spacing: -1px !important;
|
||||
}
|
||||
}
|
||||
`}} />
|
||||
<div className="custom-standard-hero-container">
|
||||
@@ -212,20 +208,12 @@ export default function ContactsHero() {
|
||||
<div className="contacts-hero-glow-blue"></div>
|
||||
|
||||
<div className="contacts-hero-glass-card">
|
||||
<div className="contacts-hero-kicker">
|
||||
<span className="contacts-hero-kicker-line"></span>
|
||||
<span className="contacts-hero-kicker-text">24/7 support & sales</span>
|
||||
<span className="contacts-hero-kicker-line"></span>
|
||||
</div>
|
||||
|
||||
<h1 className="contacts-hero-title">
|
||||
Get In <span className="contacts-hero-title-highlight">Touch</span>
|
||||
<span className="contacts-hero-title-line">Delivering Trust.</span>
|
||||
<span className="contacts-hero-title-line">
|
||||
Beyond <span className="contacts-hero-title-highlight">Boundaries.</span>
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p className="contacts-hero-desc">
|
||||
Have questions about our smart delivery network, pricing plans, or partner ecosystem? Let's build the future of logistics together.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -234,4 +222,3 @@ export default function ContactsHero() {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import Image from "next/image";
|
||||
import gsap from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
@@ -9,43 +9,61 @@ if (typeof window !== "undefined") {
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
}
|
||||
|
||||
const ACCORDION_DATA = [
|
||||
const CARDS_DATA = [
|
||||
{
|
||||
index: 1,
|
||||
num: "01",
|
||||
title: "Battery-First Planning",
|
||||
desc: "Routes are optimized around battery levels and charging windows, not retrofitted as an afterthought."
|
||||
title: "Operational Visibility",
|
||||
desc: "Real-time tracking and centralized control provide complete visibility across every shipment, vehicle, and delivery milestone.",
|
||||
icon: (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<rect x="2" y="7" width="16" height="10" rx="2" ry="2" />
|
||||
<line x1="22" y1="11" x2="22" y2="13" />
|
||||
<line x1="6" y1="11" x2="10" y2="11" />
|
||||
<line x1="6" y1="13" x2="12" y2="13" />
|
||||
</svg>
|
||||
)
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
num: "02",
|
||||
title: "Energy-Aware Routing",
|
||||
desc: "Our algorithms factor in terrain, traffic, and payload weight to maximize range efficiency."
|
||||
title: "Intelligent Routing",
|
||||
desc: "AI-powered route optimization reduces travel time, improves delivery accuracy, and maximizes fleet utilization.",
|
||||
icon: (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
|
||||
</svg>
|
||||
)
|
||||
},
|
||||
{
|
||||
index: 3,
|
||||
num: "03",
|
||||
title: "Smart Charging Integration",
|
||||
desc: "Seamless coordination with charging infrastructure to eliminate range anxiety for drivers."
|
||||
title: "EV-First Logistics",
|
||||
desc: "Purpose-built workflows for electric fleets improve battery efficiency, charging management, and sustainable operations.",
|
||||
icon: (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M12 2v10" />
|
||||
<path d="M18 8V6a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v2a4 4 0 0 0 4 4h4a4 4 0 0 0 4-4Z" />
|
||||
<path d="M10 22v-6" />
|
||||
<path d="M14 22v-6" />
|
||||
</svg>
|
||||
)
|
||||
},
|
||||
{
|
||||
index: 4,
|
||||
num: "04",
|
||||
title: "Carbon Footprint Tracking",
|
||||
desc: "Real-time emissions monitoring and sustainability reports for every delivery."
|
||||
title: "Scalable Network",
|
||||
desc: "Flexible logistics infrastructure supports growth across cities, regions, and high-volume delivery operations without disruption.",
|
||||
icon: (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 3.5 2 5.5a7 7 0 0 1-7 7h-3" />
|
||||
<path d="M12 22V12" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
export default function EVLogisticSection() {
|
||||
const [openIndex, setOpenIndex] = useState<number | null>(4); // Default to item 4 open to match user's screenshot layout
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const imageWrapperRef = useRef<HTMLDivElement>(null);
|
||||
const imageRef = useRef<HTMLImageElement>(null);
|
||||
|
||||
const toggleAccordion = (index: number) => {
|
||||
setOpenIndex((prev) => (prev === index ? null : index));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
const img = imageRef.current;
|
||||
@@ -71,21 +89,19 @@ export default function EVLogisticSection() {
|
||||
});
|
||||
|
||||
entryTl
|
||||
.to(container.querySelector(".ev-logistic-kicker"), {
|
||||
.to(container.querySelector(".ev-logistic-kicker-widget"), {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
letterSpacing: "3px", // Kinetic letter-spacing track expand effect!
|
||||
duration: 0.8,
|
||||
ease: "power3.out",
|
||||
})
|
||||
.to(container.querySelectorAll(".ev-char"), {
|
||||
y: "0%",
|
||||
.to(container.querySelector(".ev-logistic-title-widget"), {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
duration: 0.95,
|
||||
stagger: 0.02, // Rapid letter-by-letter wave reveal!
|
||||
duration: 0.85,
|
||||
ease: "power4.out",
|
||||
}, "-=0.45")
|
||||
.to(container.querySelectorAll(".ev-logistic-accordion-item"), {
|
||||
.to(container.querySelectorAll(".ev-feature-card"), {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
duration: 0.6,
|
||||
@@ -107,20 +123,11 @@ export default function EVLogisticSection() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const headingText = "LOGISTICS BUILT FOR ELECTRIC VEHICLES";
|
||||
const headingWords = headingText.split(" ");
|
||||
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
/* Custom CSS Scoped to EV Logistics Section - New Premium Look */
|
||||
/* Custom CSS Scoped to EV Logistics Section */
|
||||
.ev-logistic-section {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
width: 100% !important;
|
||||
max-width: 1320px !important;
|
||||
margin: 10px auto 120px auto !important; /* Centered horizontally with auto margins */
|
||||
padding: 80px 60px !important; /* Restored original balanced left/right paddings */
|
||||
box-sizing: border-box !important;
|
||||
background: #ffffff !important;
|
||||
font-family: 'Manrope', sans-serif !important;
|
||||
@@ -131,8 +138,6 @@ export default function EVLogisticSection() {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
align-self: stretch !important;
|
||||
border-bottom: 2px solid rgba(17, 17, 17, 0.09) !important;
|
||||
padding-bottom: 16px !important;
|
||||
margin-bottom: 48px !important;
|
||||
display: block !important;
|
||||
text-align: left !important;
|
||||
@@ -144,13 +149,13 @@ export default function EVLogisticSection() {
|
||||
align-items: center !important;
|
||||
justify-content: space-between !important;
|
||||
width: 100% !important;
|
||||
gap: 40px !important;
|
||||
gap: 3% !important;
|
||||
}
|
||||
|
||||
/* Balanced Left Column - Image column takes up 58% */
|
||||
/* Left Column - Image column takes up 45% */
|
||||
.ev-logistic-image-col {
|
||||
flex: 1 1 58% !important;
|
||||
max-width: 58% !important;
|
||||
flex: 0 0 45% !important;
|
||||
max-width: 45% !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: flex-start !important;
|
||||
@@ -182,235 +187,139 @@ export default function EVLogisticSection() {
|
||||
justify-content: flex-start !important;
|
||||
overflow: visible !important;
|
||||
position: relative !important;
|
||||
transform: scale(1.15) !important; /* Scale up image to make it larger and more dominant */
|
||||
transform: scale(1.15) !important;
|
||||
transform-origin: left center !important;
|
||||
margin-left: -80px !important; /* Offset image to the left to anchor it to the container edge */
|
||||
margin-left: -80px !important;
|
||||
}
|
||||
|
||||
.ev-logistic-image-wrapper img {
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
object-fit: contain !important;
|
||||
filter: none !important; /* Blends solid white JPEG edges seamlessly into pure white background */
|
||||
filter: none !important;
|
||||
will-change: transform !important;
|
||||
}
|
||||
|
||||
/* Balanced right column - takes up 42% for crisp textual reading */
|
||||
/* Right column - takes up 52% for grid cards */
|
||||
.ev-logistic-content-col {
|
||||
flex: 1 1 42% !important;
|
||||
max-width: 42% !important;
|
||||
flex: 0 0 52% !important;
|
||||
max-width: 52% !important;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
justify-content: center !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.ev-logistic-kicker {
|
||||
font-size: 14px !important;
|
||||
font-weight: 400 !important;
|
||||
line-height: 2.1429em !important;
|
||||
letter-spacing: 0px !important; /* Expands to 3px on scroll */
|
||||
text-transform: lowercase !important;
|
||||
color: #111111 !important;
|
||||
margin: 0 !important;
|
||||
.ev-logistic-kicker-widget {
|
||||
opacity: 0;
|
||||
transform: translateY(-12px);
|
||||
will-change: transform, opacity, letter-spacing;
|
||||
text-align: left !important;
|
||||
display: inline-block !important;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
.ev-logistic-title-wrapper {
|
||||
margin-bottom: 48px;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/* Expanded clean headings look from the screenshot */
|
||||
.ev-logistic-title {
|
||||
font-size: clamp(45px, 6.2vw, 96px);
|
||||
font-weight: 500;
|
||||
line-height: 0.95;
|
||||
text-transform: uppercase;
|
||||
color: #111111;
|
||||
margin: 0 10px 0 0; /* Clean margin-right to shift title away from borders */
|
||||
letter-spacing: -1.8px;
|
||||
}
|
||||
|
||||
/* CSS for robust letter-by-letter animation wrapping */
|
||||
.ev-word-inline {
|
||||
display: inline-block;
|
||||
white-space: nowrap; /* Prevents awkward character line breaks */
|
||||
}
|
||||
|
||||
.ev-char-wrapper {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.ev-char {
|
||||
display: inline-block;
|
||||
transform: translateY(110%);
|
||||
.ev-logistic-title-widget {
|
||||
opacity: 0;
|
||||
transform: translateY(24px);
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
.ev-char-space {
|
||||
display: inline-block;
|
||||
.ev-logistic-title-widget > .elementor-widget-container {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
.ev-logistic-title-widget .logico-title {
|
||||
margin: 0 !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
/* Sleek horizontal grid borders */
|
||||
.ev-logistic-accordion-item {
|
||||
width: 100%;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
/* Card Grid Layout */
|
||||
.ev-feature-grid {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(2, 1fr) !important;
|
||||
gap: 24px !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
/* Premium Theme White Card */
|
||||
.ev-feature-card {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
background: #ffffff !important;
|
||||
border: 1px solid rgba(17, 17, 17, 0.09) !important;
|
||||
border-radius: 20px !important;
|
||||
padding: 30px !important;
|
||||
color: #555555 !important;
|
||||
height: 100% !important;
|
||||
box-sizing: border-box !important;
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
will-change: transform, opacity;
|
||||
transition: background-color 0.4s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
transition: border-color 0.4s cubic-bezier(0.165, 0.84, 0.44, 1),
|
||||
box-shadow 0.4s cubic-bezier(0.165, 0.84, 0.44, 1),
|
||||
transform 0.4s cubic-bezier(0.165, 0.84, 0.44, 1) !important;
|
||||
box-shadow: 0 4px 24px rgba(17, 17, 17, 0.02) !important;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-item:last-child {
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
.ev-feature-card:hover {
|
||||
border-color: #c01227 !important;
|
||||
box-shadow: 0 20px 40px rgba(192, 18, 39, 0.08), 0 4px 12px rgba(17, 17, 17, 0.03) !important;
|
||||
transform: translateY(-8px) !important;
|
||||
}
|
||||
|
||||
/* Soft highlight on row hover */
|
||||
.ev-logistic-accordion-item:hover {
|
||||
background: rgba(192, 18, 39, 0.015);
|
||||
/* Red Icon Wrapper */
|
||||
.ev-feature-icon-wrapper {
|
||||
margin-bottom: 24px !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
width: 54px !important;
|
||||
height: 54px !important;
|
||||
background: rgba(192, 18, 39, 0.06) !important;
|
||||
border: 1px solid rgba(192, 18, 39, 0.18) !important;
|
||||
border-radius: 50% !important;
|
||||
color: #c01227 !important;
|
||||
transition: all 0.3s ease !important;
|
||||
}
|
||||
|
||||
/* Spacious row padding for luxurious design - INCREASED font size for headers */
|
||||
.ev-logistic-accordion-header {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 28px 16px;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: none;
|
||||
text-align: left;
|
||||
outline: none;
|
||||
font-family: 'Manrope', sans-serif;
|
||||
font-size: clamp(24px, 2.2vw, 30px); /* Increased to clamp up to 30px! */
|
||||
font-weight: 700;
|
||||
color: #111111;
|
||||
transition: color 0.3s ease;
|
||||
.ev-feature-card:hover .ev-feature-icon-wrapper {
|
||||
background: rgba(192, 18, 39, 0.12) !important;
|
||||
border-color: #c01227 !important;
|
||||
transform: scale(1.1) !important;
|
||||
box-shadow: 0 0 12px rgba(192, 18, 39, 0.15) !important;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-header span:first-child {
|
||||
transition: transform 0.35s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
display: inline-block;
|
||||
.ev-feature-icon-wrapper svg {
|
||||
width: 24px !important;
|
||||
height: 24px !important;
|
||||
stroke: currentColor !important;
|
||||
}
|
||||
|
||||
/* Row text horizontal slide nudge */
|
||||
.ev-logistic-accordion-header:hover {
|
||||
color: #c01227;
|
||||
/* Title & Description Inside Cards */
|
||||
.ev-feature-card-title {
|
||||
font-family: 'Manrope', sans-serif !important;
|
||||
font-size: 20px !important;
|
||||
font-weight: 700 !important;
|
||||
line-height: 1.3em !important;
|
||||
color: #c01227 !important;
|
||||
margin: 0 0 12px 0 !important;
|
||||
text-transform: none !important;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-header:hover span:first-child {
|
||||
transform: translateX(10px);
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-item.active .ev-logistic-accordion-header {
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-arrow-container {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1), color 0.3s ease;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-arrow-container svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
stroke-width: 2.5;
|
||||
}
|
||||
|
||||
/* Inactive arrows: point down-right ↘ */
|
||||
.ev-logistic-accordion-item:not(.active) .ev-logistic-accordion-arrow-container {
|
||||
transform: rotate(90deg);
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
/* Active arrows: point up-right ↗ in brand red */
|
||||
.ev-logistic-accordion-item.active .ev-logistic-accordion-arrow-container {
|
||||
transform: rotate(0deg);
|
||||
color: #c01227;
|
||||
}
|
||||
|
||||
/* Hover: rotate smooth to diagonal up-right */
|
||||
.ev-logistic-accordion-header:hover .ev-logistic-accordion-arrow-container {
|
||||
transform: rotate(0deg);
|
||||
color: #c01227;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-content {
|
||||
overflow: hidden;
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
transition: max-height 0.45s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.45s ease;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-item.active .ev-logistic-accordion-content {
|
||||
max-height: 160px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Balanced text spacing inside descriptions - INCREASED font size for descriptions */
|
||||
.ev-logistic-accordion-content-inner {
|
||||
padding: 0 16px 28px 16px;
|
||||
font-size: clamp(18px, 1.5vw, 20px); /* Increased to clamp up to 20px! */
|
||||
line-height: 1.6;
|
||||
color: #555555;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Underline track & sweeping active red bar */
|
||||
.ev-logistic-accordion-progress-track {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 1.5px;
|
||||
background: transparent;
|
||||
margin-top: -1.5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-progress-bar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: #c01227;
|
||||
transform: scaleX(0);
|
||||
transform-origin: left center;
|
||||
transition: transform 0.6s cubic-bezier(0.25, 1, 0.5, 1);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-item.active .ev-logistic-accordion-progress-bar {
|
||||
transform: scaleX(1);
|
||||
.ev-feature-card-desc {
|
||||
font-family: 'Manrope', sans-serif !important;
|
||||
font-size: 14px !important;
|
||||
font-weight: 500 !important;
|
||||
line-height: 1.6 !important;
|
||||
color: #555555 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/* Responsiveness constraints */
|
||||
@media (max-width: 1024px) {
|
||||
.ev-logistic-section {
|
||||
padding: 60px 24px;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
/* Base rules above use !important (flex-direction:row, the 58/42%
|
||||
column widths), so these overrides MUST also use !important or the
|
||||
grid never stacks and the image/text stay squished side-by-side. */
|
||||
.ev-logistic-body-grid {
|
||||
flex-direction: column !important;
|
||||
gap: 50px !important;
|
||||
@@ -420,13 +329,13 @@ export default function EVLogisticSection() {
|
||||
flex: 1 1 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-height: auto !important;
|
||||
justify-content: center !important; /* Center layout on mobile */
|
||||
justify-content: center !important;
|
||||
}
|
||||
|
||||
.ev-logistic-image-wrapper {
|
||||
max-width: 580px !important;
|
||||
transform: none !important; /* Reset scale transform on mobile/tablet */
|
||||
margin-left: 0 !important; /* Reset left margin offset on mobile/tablet */
|
||||
transform: none !important;
|
||||
margin: 0 auto !important;
|
||||
justify-content: center !important;
|
||||
}
|
||||
|
||||
@@ -435,123 +344,133 @@ export default function EVLogisticSection() {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.ev-logistic-title {
|
||||
font-size: 38px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.ev-logistic-section {
|
||||
padding: 40px 16px;
|
||||
--padding-left: 0px !important;
|
||||
--padding-right: 0px !important;
|
||||
padding-left: 0px !important;
|
||||
padding-right: 0px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.ev-logistic-title {
|
||||
font-size: 32px;
|
||||
.ev-logistic-section > .e-con-inner {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-header {
|
||||
font-size: 19px;
|
||||
padding: 22px 8px;
|
||||
.ev-logistic-section .elementor-element-343b363 {
|
||||
--padding-left: 20px !important;
|
||||
--padding-right: 20px !important;
|
||||
padding-left: 20px !important;
|
||||
padding-right: 20px !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.ev-logistic-accordion-content-inner {
|
||||
padding: 0;
|
||||
font-size: 15.5px;
|
||||
|
||||
.ev-logistic-body-grid {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
align-items: stretch !important;
|
||||
}
|
||||
|
||||
.ev-logistic-content-col {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
align-self: center !important;
|
||||
}
|
||||
|
||||
.ev-feature-grid {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 20px !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.ev-feature-card {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
}
|
||||
`}} />
|
||||
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="ev-logistic-section"
|
||||
>
|
||||
{/* Top Header Row with / features / kicker */}
|
||||
<div className="ev-logistic-header">
|
||||
<div className="ev-logistic-kicker">/ Build Electric Vehicles /</div>
|
||||
</div>
|
||||
|
||||
<div className="ev-logistic-body-grid">
|
||||
{/* Left Column: Enlarged Floating Wrapper & Ambient glow */}
|
||||
<div className="ev-logistic-image-col">
|
||||
<div className="ev-logistic-image-glow"></div>
|
||||
|
||||
<div ref={imageWrapperRef} className="ev-logistic-image-wrapper">
|
||||
<Image
|
||||
ref={imageRef}
|
||||
src="/images/ev.jpeg"
|
||||
alt="EV Logistics"
|
||||
width={1050}
|
||||
height={854}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column: Refined Accordion list with letter-by-letter animation */}
|
||||
<div className="ev-logistic-content-col">
|
||||
{/* Character-by-character masked entrance wave reveal on scroll */}
|
||||
<div className="ev-logistic-title-wrapper">
|
||||
<h3 className="ev-logistic-title">
|
||||
{headingWords.map((word, wordIndex) => (
|
||||
<span key={wordIndex} className="ev-word-inline">
|
||||
{word.split("").map((letter, letterIndex) => (
|
||||
<span key={letterIndex} className="ev-char-wrapper">
|
||||
<span className="ev-char">{letter}</span>
|
||||
</span>
|
||||
))}
|
||||
<span className="ev-char-space"> </span>
|
||||
</span>
|
||||
))}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="ev-logistic-accordion">
|
||||
{ACCORDION_DATA.map((item) => (
|
||||
<div
|
||||
key={item.index}
|
||||
className={`ev-logistic-accordion-item ${openIndex === item.index ? "active" : ""}`}
|
||||
>
|
||||
<button
|
||||
className="ev-logistic-accordion-header"
|
||||
onClick={() => toggleAccordion(item.index)}
|
||||
aria-expanded={openIndex === item.index}
|
||||
>
|
||||
<span>{item.num}. {item.title}</span>
|
||||
<span className="ev-logistic-accordion-arrow-container">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<line x1="7" y1="17" x2="17" y2="7"></line>
|
||||
<polyline points="7 7 17 7 17 17"></polyline>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div className="ev-logistic-accordion-content">
|
||||
<div className="ev-logistic-accordion-content-inner">
|
||||
{/* Kinetic slide-up and fade subtitle reveal */}
|
||||
<p style={{
|
||||
transform: openIndex === item.index ? "translateY(0)" : "translateY(12px)",
|
||||
opacity: openIndex === item.index ? 1 : 0,
|
||||
transition: "transform 0.5s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.5s ease",
|
||||
transitionDelay: "0.08s",
|
||||
margin: 0
|
||||
}}>
|
||||
{item.desc}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Underline track & sweep animated red bar */}
|
||||
<div className="ev-logistic-accordion-progress-track">
|
||||
<div className="ev-logistic-accordion-progress-bar"></div>
|
||||
<div className="elementor-61">
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="elementor-element elementor-element-88745f4 e-flex e-con-boxed cut-corner-no sticky-container-off e-con e-parent ev-logistic-section"
|
||||
data-id="88745f4"
|
||||
data-element_type="container"
|
||||
data-e-type="container"
|
||||
>
|
||||
<div className="e-con-inner">
|
||||
<div className="elementor-element elementor-element-343b363 e-con-full e-flex cut-corner-no sticky-container-off e-con e-child" data-id="343b363" data-element_type="container" data-e-type="container">
|
||||
{/* Same header hierarchy and container structure as "The Doormile Way". */}
|
||||
<div className="ev-logistic-header">
|
||||
<div className="elementor-element elementor-element-7afb238 elementor-widget elementor-widget-logico_heading ev-logistic-kicker-widget" data-id="7afb238" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
|
||||
<div className="elementor-widget-container">
|
||||
<div className="logico-title ev-logistic-kicker">/ Built for Electric Vehicles /</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div className="ev-logistic-title-wrapper">
|
||||
<div className="elementor-element elementor-element-1cc335a elementor-widget elementor-widget-logico_heading ev-logistic-title-widget" data-id="1cc335a" data-element_type="widget" data-e-type="widget" data-widget_type="logico_heading.default">
|
||||
<div className="elementor-widget-container">
|
||||
<div
|
||||
className="logico-title"
|
||||
style={{
|
||||
WebkitTextStroke: "4px #c01227",
|
||||
color: "#fff",
|
||||
fontWeight: 800,
|
||||
}}
|
||||
>
|
||||
Logistics Built for EV Vehicles
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ev-logistic-body-grid">
|
||||
{/* Left Column: Enlarged Floating Wrapper & Ambient glow */}
|
||||
<div className="ev-logistic-image-col">
|
||||
<div className="ev-logistic-image-glow"></div>
|
||||
|
||||
<div ref={imageWrapperRef} className="ev-logistic-image-wrapper">
|
||||
<Image
|
||||
ref={imageRef}
|
||||
src="/images/ev.webp"
|
||||
alt="EV Logistics"
|
||||
width={1050}
|
||||
height={854}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Column: 2x2 Grid of Feature Cards */}
|
||||
<div className="ev-logistic-content-col">
|
||||
<div className="ev-feature-grid">
|
||||
{CARDS_DATA.map((item) => (
|
||||
<div
|
||||
key={item.index}
|
||||
className="ev-feature-card"
|
||||
>
|
||||
<div className="ev-feature-icon-wrapper">
|
||||
{item.icon}
|
||||
</div>
|
||||
<h4 className="ev-feature-card-title">{item.title}</h4>
|
||||
<p className="ev-feature-card-desc">{item.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,19 +19,20 @@ export default function HowItWorksHero() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<link rel="preload" as="image" href="/images/home2-banner-1.webp" />
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
.howits-hero-custom-bg.elementor-repeater-item-3264830,
|
||||
.howits-hero-custom-bg.elementor-repeater-item-6867061 {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-1.png') !important;
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home2-banner-1.webp') !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: cover !important;
|
||||
}
|
||||
|
||||
.howits-hero-custom-bg.elementor-repeater-item-6867061 {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-2.png') !important;
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.1)), url('/images/home1-slide-2.webp') !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: cover !important;
|
||||
@@ -46,7 +47,7 @@ export default function HowItWorksHero() {
|
||||
text-align: center !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
padding: 0 40px !important;
|
||||
padding: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
@@ -72,6 +73,8 @@ export default function HowItWorksHero() {
|
||||
width: 100% !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
padding-left: 15px !important;
|
||||
padding-right: 15px !important;
|
||||
}
|
||||
|
||||
.elementor-element.elementor-element-6c7cbcb .content-slider-item-text {
|
||||
@@ -85,6 +88,8 @@ export default function HowItWorksHero() {
|
||||
text-align: center !important;
|
||||
max-width: 820px !important;
|
||||
margin: 0 auto !important;
|
||||
padding-left: 15px !important;
|
||||
padding-right: 15px !important;
|
||||
}
|
||||
|
||||
/* Larger, more readable hero subtitle on large/4K screens */
|
||||
@@ -108,10 +113,13 @@ export default function HowItWorksHero() {
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.elementor-element.elementor-element-741f56c {
|
||||
width: calc(100% - 40px) !important;
|
||||
max-width: none !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
--padding-top: 0px !important;
|
||||
--padding-block-start: 0px !important;
|
||||
padding: 0 10px 10px 10px !important;
|
||||
overflow: hidden !important;
|
||||
border-radius: 25px !important;
|
||||
}
|
||||
@@ -133,15 +141,19 @@ export default function HowItWorksHero() {
|
||||
.elementor-element.elementor-element-6c7cbcb .slide-content {
|
||||
width: 100% !important;
|
||||
min-height: 620px !important;
|
||||
padding-left: 48px !important;
|
||||
padding-right: 48px !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.elementor-element.elementor-element-741f56c {
|
||||
width: calc(100% - 24px) !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
--padding-top: 0px !important;
|
||||
--padding-block-start: 0px !important;
|
||||
padding: 0 10px 10px 10px !important;
|
||||
border-radius: 22px !important;
|
||||
}
|
||||
|
||||
@@ -161,8 +173,8 @@ export default function HowItWorksHero() {
|
||||
asymmetric top margin). */
|
||||
.elementor .elementor-element.elementor-element-6c7cbcb .slide-content {
|
||||
min-height: 560px !important;
|
||||
padding-left: 22px !important;
|
||||
padding-right: 22px !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
text-align: center !important;
|
||||
|
||||
@@ -52,6 +52,7 @@ export default function IndexHero() {
|
||||
|
||||
return (
|
||||
<div className="elementor-element elementor-element-741f56c e-con-full e-flex cut-corner-no sticky-container-off e-con e-parent" data-id="741f56c" data-element_type="container" data-e-type="container">
|
||||
<link rel="preload" as="image" href="/images/home-bg-1.webp" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
/* Fluid responsive font size override for hero headings */
|
||||
.logico-content-slider-widget .content-slider-item-heading {
|
||||
@@ -120,6 +121,7 @@ export default function IndexHero() {
|
||||
@media (max-width: 480px) {
|
||||
.logico-content-slider-widget .owl-stage-outer {
|
||||
height: 520px !important;
|
||||
margin-top: 7px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +179,7 @@ export default function IndexHero() {
|
||||
<div
|
||||
className="content-item slider-item elementor-repeater-item-3264830 slide-style-standard"
|
||||
style={{
|
||||
backgroundImage: "url('/images/home-bg-1.png')",
|
||||
backgroundImage: "url('/images/home-bg-1.webp')",
|
||||
backgroundPosition: "center center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "cover"
|
||||
@@ -218,7 +220,7 @@ export default function IndexHero() {
|
||||
<div
|
||||
className="content-item slider-item elementor-repeater-item-6867061 slide-style-standard"
|
||||
style={{
|
||||
backgroundImage: "url('/images/home-bg-1.png')",
|
||||
backgroundImage: "url('/images/home-bg-1.webp')",
|
||||
backgroundPosition: "center center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: "cover"
|
||||
|
||||