{"id":11,"date":"2026-09-24T11:56:30","date_gmt":"2026-09-24T11:56:30","guid":{"rendered":"https:\/\/globalintfrieight.com\/?page_id=11"},"modified":"2026-09-24T11:56:30","modified_gmt":"2026-09-24T11:56:30","slug":"track-and-trace","status":"publish","type":"page","link":"https:\/\/globalintfrieight.com\/?page_id=11","title":{"rendered":"Track and Trace"},"content":{"rendered":"<div class=\"tracking-map-container-ff01\">\n    <div class=\"controls-ff01\">\n        <h3 class=\"h3-ff01\">Track Your Order<\/h3>\n        <label class=\"label-ff01\">\n            <span class=\"label-text\">Tracking Number:<\/span>\n            <input type=\"text\" id=\"tracking-number\" class=\"input-text-ff01\" placeholder=\"Enter Tracking Number\" maxlength=\"255\">\n            <span id=\"tracking-number-error\" class=\"error-message\" style=\"display: none; color: #e63946; font-size: 0.85rem;\">\n                Please enter a valid tracking number (max 255 characters).\n            <\/span>\n        <\/label>\n        <button class=\"button-ff01\" onclick=\"userTrackingMap.showTracking()\">Show Tracking<\/button>\n        <div id=\"loading-indicator\" class=\"loading-indicator\" style=\"display: none; text-align: center; padding: 1rem; margin-top: 1rem;\">\n            <div class=\"spinner\"><\/div>\n            <span id=\"loading-message\">Loading...<\/span>\n        <\/div>\n        <div id=\"tracking-info\" class=\"info-ff01\"><\/div>\n        <div id=\"progress-controls\" style=\"margin-top: 1rem; display: none;\">\n            <div id=\"progress-bar-container\" style=\"margin-top: 1rem; position: relative; height: 40px; background: #e0e6ed; border-radius: 4px; overflow: hidden;\">\n                <div id=\"progress-bar\" style=\"width: 0%; height: 100%; position: absolute; top: 0; left: 0; z-index: 1;\"><\/div>\n                <div id=\"progress-segments\" style=\"position: relative; width: 100%; height: 100%; z-index: 2;\"><\/div>\n            <\/div>\n            <p id=\"time-remaining\" style=\"font-size: 0.875rem; color: #1d3557; margin-top: 0.5rem;\"><\/p>\n        <\/div>\n    <\/div>\n    <div id=\"map\"><\/div>\n<\/div>\n\n<style>\n\/* Reset and Base Styles *\/\n* { box-sizing: border-box; margin: 0; padding: 0; }\n.body-ff01 { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f7fa; color: #2d3748; line-height: 1.5; }\n\n\/* Container *\/\n.tracking-map-container-ff01 {\n    max-width: 1200px;\n    margin: 1rem auto;\n    background: #ffffff;\n    border-radius: 16px;\n    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);\n    overflow: hidden;\n    transition: all 0.3s ease;\n    opacity: 0;\n    transform: translateY(20px);\n    animation: fadeInView 0.5s ease-out 0.1s forwards;\n}\n\n\/* Animation for the entire view *\/\n@keyframes fadeInView {\n    0% { opacity: 0; transform: translateY(20px); }\n    100% { opacity: 1; transform: translateY(0); }\n}\n\n\/* Controls Section *\/\n.controls-ff01 {\n    padding: 1.5rem;\n    background: linear-gradient(135deg, #ffffff, #f8fafc);\n    border-bottom: 1px solid #e2e8f0;\n}\n\n\/* Heading *\/\n.h3-ff01 {\n    color: #2b6cb0;\n    font-size: 1.75rem;\n    font-weight: 700;\n    margin-bottom: 1.25rem;\n    text-align: center;\n}\n\n\/* Label and Input *\/\n.label-ff01 {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    font-size: 0.875rem;\n    color: #4a5568;\n    font-weight: 500;\n    margin-bottom: 1rem;\n}\n.label-text {\n    margin-bottom: 0.5rem;\n}\n.input-text-ff01 {\n    width: 100%;\n    max-width: 250px;\n    padding: 0.5rem;\n    border: 1px solid #e2e8f0;\n    border-radius: 8px;\n    font-size: 0.8125rem;\n    background: #fff;\n    transition: all 0.2s ease;\n    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05);\n}\n.input-text-ff01:focus {\n    border-color: #4299e1;\n    outline: none;\n    box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.2);\n}\n.error-message { margin-top: 0.25rem; font-size: 0.75rem; text-align: center; }\n\n\/* Button *\/\n.button-ff01 {\n    padding: 0.525rem 1rem;\n    font-size: 0.875rem;\n    font-weight: 600;\n    color: #fff;\n    background: #2b6cb0;\n    border: none;\n    border-radius: 8px;\n    cursor: pointer;\n    transition: all 0.2s ease;\n    box-shadow: 0 2px 6px rgba(43, 108, 176, 0.4);\n    max-width: 150px;\n    margin: 0 auto;\n    display: block;\n}\n.button-ff01:hover {\n    background: #2c5282;\n    transform: translateY(-2px);\n    box-shadow: 0 4px 12px rgba(43, 108, 176, 0.6);\n}\n.button-ff01:active { transform: translateY(0); box-shadow: 0 2px 6px rgba(43, 108, 176, 0.4); }\n\n\/* Loading Indicator *\/\n.loading-indicator {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    gap: 0.5rem;\n    color: #4299e1;\n    font-size: 0.875rem;\n    opacity: 0;\n    transition: opacity 0.3s ease;\n}\n.loading-indicator.active { opacity: 1; }\n.spinner {\n    width: 1.25rem;\n    height: 1.25rem;\n    border: 3px solid #4299e1;\n    border-top: 3px solid transparent;\n    border-radius: 50%;\n    animation: spin 1s linear infinite;\n}\n\n\/* Tracking Info *\/\n.info-ff01 {\n    margin: 1rem 1.5rem;\n    font-size: 0.75rem;\n    color: #4a5568;\n    max-height: 50vh;\n    overflow-y: auto;\n}\n.status-card {\n    background: linear-gradient(135deg, #f7fafc, #edf2f7);\n    border: 1px solid #e2e8f0;\n    border-radius: 12px;\n    padding: 1rem;\n    margin: 0 auto 1rem;\n    width: 90%;\n    max-width: 400px;\n    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);\n    display: flex;\n    flex-direction: column;\n    gap: 0.5rem;\n    animation: slideUp 0.5s ease-out;\n}\n.status-card .status-container {\n    display: flex;\n    align-items: center;\n    gap: 0.75rem;\n    font-size: 0.875rem;\n    font-weight: 600;\n    color: #1a202c;\n}\n.status-card .status-ball {\n    width: 0.75rem;\n    height: 0.75rem;\n    background: #34c759;\n    border-radius: 50%;\n    animation: blink 1s infinite;\n}\n.status-card .expected-delivery {\n    font-size: 0.75rem;\n    color: #4a5568;\n    font-style: italic;\n}\n.info-section { margin-bottom: 1rem; }\n.section-title {\n    color: #2d3748;\n    font-size: 0.875rem;\n    font-weight: 600;\n    margin-bottom: 0.5rem;\n    padding-bottom: 0.25rem;\n    border-bottom: 1px solid #e2e8f0;\n}\n.info-ff01 table {\n    width: 100%;\n    border-collapse: collapse;\n}\n.info-ff01 th, .info-ff01 td {\n    padding: 0.5rem 0.25rem;\n    text-align: left;\n}\n.info-ff01 th {\n    font-weight: 600;\n    color: #2d3748;\n    width: 40%;\n}\n.info-ff01 td { color: #718096; }\n\n\/* Shipment Details Table Specific Styling *\/\n.info-section:nth-child(1) table {\n    font-size: 0.6875rem;\n    width: 80%;\n    margin: 0 auto;\n}\n.info-section:nth-child(1) table thead th {\n    text-align: left;\n    font-size: 0.75rem;\n    font-weight: 700;\n    color: #2b6cb0;\n    background: #f8fafc;\n    padding: 0.4rem;\n    border-bottom: 2px solid #e2e8f0;\n}\n.info-section:nth-child(1) table th, .info-section:nth-child(1) table td {\n    padding: 0.3rem 0.2rem;\n    text-align: left;\n}\n.info-section:nth-child(1) table th {\n    border-right: 2px solid #e2e8f0;\n}\n.info-section:nth-child(1) table tr:nth-child(1) { \n    background: #e6f0fa; \n    border: 1px solid #4299e1; \n}\n.info-section:nth-child(1) table tr:nth-child(2) { \n    background: #fefcbf; \n    border: 1px solid #ecc94b; \n}\n.info-section:nth-child(1) table tr:nth-child(3) { \n    background: #d4f4e2; \n    border: 1px solid #38a169; \n}\n.info-section:nth-child(1) table tr:nth-child(4) { \n    background: #fed7e2; \n    border: 1px solid #f687b3; \n}\n.info-section:nth-child(1) table tr:nth-child(5) { \n    background: #e9d8fd; \n    border: 1px solid #9f7aea; \n}\n.info-section:nth-child(1) table tr:nth-child(6) { \n    background: #c3e6cb; \n    border: 1px solid #68d391; \n}\n.info-section:nth-child(1) table tr:nth-child(7) { \n    background: #bee3f8; \n    border: 1px solid #63b3ed; \n}\n.info-section:nth-child(1) table tr:nth-child(8) { \n    background: #fddede; \n    border: 1px solid #f56565; \n}\n.info-section:nth-child(1) table tr:hover {\n    background: #edf2f7;\n    transition: background 0.2s ease;\n}\n\n\/* Package Details Table Specific Styling *\/\n.info-section:nth-child(2) table {\n    font-size: 0.6875rem;\n    width: 80%;\n    margin: 0 auto;\n}\n.info-section:nth-child(2) table thead th {\n    text-align: left;\n    font-size: 0.75rem;\n    font-weight: 700;\n    color: #2b6cb0;\n    background: #f8fafc;\n    padding: 0.4rem;\n    border-bottom: 2px solid #e2e8f0;\n}\n.info-section:nth-child(2) table th, .info-section:nth-child(2) table td {\n    padding: 0.3rem 0.2rem;\n    text-align: left;\n}\n.info-section:nth-child(2) table th {\n    border-right: 2px solid #e2e8f0;\n}\n.info-section:nth-child(2) table tr:nth-child(1) { \n    background: #e6f0fa; \n    border: 1px solid #4299e1; \n}\n.info-section:nth-child(2) table tr:nth-child(2) { \n    background: #fefcbf; \n    border: 1px solid #ecc94b; \n}\n.info-section:nth-child(2) table tr:nth-child(3) { \n    background: #d4f4e2; \n    border: 1px solid #38a169; \n}\n.info-section:nth-child(2) table tr:nth-child(4) { \n    background: #fed7e2; \n    border: 1px solid #f687b3; \n}\n.info-section:nth-child(2) table tr:hover {\n    background: #edf2f7;\n    transition: background 0.2s ease;\n}\n\n\/* Additional Information Table Specific Styling *\/\n.info-section:nth-child(3) table {\n    font-size: 0.6875rem;\n    width: 80%;\n    margin: 0 auto;\n}\n.info-section:nth-child(3) table thead th {\n    text-align: left;\n    font-size: 0.75rem;\n    font-weight: 700;\n    color: #2b6cb0;\n    background: #f8fafc;\n    padding: 0.4rem;\n    border-bottom: 2px solid #e2e8f0;\n}\n.info-section:nth-child(3) table th, .info-section:nth-child(3) table td {\n    padding: 0.3rem 0.2rem;\n    text-align: left;\n}\n.info-section:nth-child(3) table th {\n    border-right: 2px solid #e2e8f0;\n}\n.info-section:nth-child(3) table tr:nth-child(1) { \n    background: #e6f0fa; \n    border: 1px solid #4299e1; \n}\n.info-section:nth-child(3) table tr:nth-child(2) { \n    background: #fefcbf; \n    border: 1px solid #ecc94b; \n}\n.info-section:nth-child(3) table tr:nth-child(3) { \n    background: #d4f4e2; \n    border: 1px solid #38a169; \n}\n.info-section:nth-child(3) table tr:nth-child(4) { \n    background: #fed7e2; \n    border: 1px solid #f687b3; \n}\n.info-section:nth-child(3) table tr:nth-child(5) { \n    background: #e9d8fd; \n    border: 1px solid #9f7aea; \n}\n.info-section:nth-child(3) table tr:hover {\n    background: #edf2f7;\n    transition: background 0.2s ease;\n}\n\n\/* Scheduled Stops Table Specific Styling *\/\n#scheduled-stops-table {\n    font-size: 0.6875rem;\n    width: 80%;\n    margin: 0 auto;\n}\n#scheduled-stops-table thead th {\n    text-align: left;\n    font-size: 0.75rem;\n    font-weight: 700;\n    color: #2b6cb0;\n    background: #f8fafc;\n    padding: 0.4rem;\n    border-bottom: 2px solid #e2e8f0;\n}\n#scheduled-stops-table tbody th, #scheduled-stops-table tbody td {\n    padding: 0.3rem 0.2rem;\n    text-align: left;\n}\n#scheduled-stops-table tbody th {\n    border-right: 2px solid #e2e8f0;\n}\n#scheduled-stops-table tbody tr:nth-child(odd) { \n    background: #e6f0fa; \n    border: 1px solid #4299e1; \n}\n#scheduled-stops-table tbody tr:nth-child(even) { \n    background: #fefcbf; \n    border: 1px solid #ecc94b; \n}\n#scheduled-stops-table tbody tr:hover {\n    background: #edf2f7;\n    transition: background 0.2s ease;\n}\n\n\/* Comments Table Specific Styling *\/\n#comments-table {\n    font-size: 0.6875rem;\n    width: 80%;\n    margin: 0.75rem auto;\n}\n#comments-table thead th {\n    text-align: left;\n    font-size: 0.75rem;\n    font-weight: 700;\n    color: #ffffff;\n    background: linear-gradient(135deg, #ed8936, #2b6cb0);\n    padding: 0.4rem;\n    border-bottom: 2px solid #ed8936;\n}\n#comments-table tbody td {\n    padding: 0.3rem 0.2rem;\n    text-align: left;\n    font-style: italic;\n    position: relative;\n    background: #fffaf0;\n}\n#comments-table tbody td::before {\n    content: '\"';\n    position: absolute;\n    left: 0.1rem;\n    color: #718096;\n}\n#comments-table tbody td::after {\n    content: '\"';\n    position: absolute;\n    color: #718096;\n}\n#comments-table tbody tr:nth-child(odd) { \n    background: #fffaf0;\n    border: 1px solid #ed8936;\n}\n#comments-table tbody tr:nth-child(even) { \n    background: #fefcbf;\n    border: 1px solid #ecc94b;\n}\n#comments-table tbody tr:hover {\n    background: #edf2f7;\n    transition: background 0.2s ease;\n}\n\n\/* Progress Bar *\/\n#progress-controls { padding: 0 1.5rem 1.5rem; }\n#progress-bar-container {\n    width: 100%;\n    background: #edf2f7;\n    border-radius: 8px;\n    overflow: hidden;\n    position: relative;\n    height: 2rem;\n    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05);\n}\n.progress-segment {\n    height: 100%;\n    float: left;\n    position: relative;\n    text-align: center;\n    font-size: 0.6875rem;\n    color: #2d3748;\n    padding: 0 0.5rem;\n    overflow: hidden;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n    line-height: 2rem;\n    border-right: 2px solid #fff;\n    transition: background-color 0.3s ease;\n}\n.progress-segment:last-child { border-right: none; }\n#progress-bar {\n    transition: width 0.3s ease, left 0.3s ease, background-color 0.3s ease;\n    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);\n}\n#time-remaining { font-size: 0.75rem; text-align: center; color: #2b6cb0; }\n\n\/* Map *\/\n#map { \n    height: 400px; \n    width: 100%; \n    border-top: 1px solid #e2e8f0; \n    position: relative;\n    padding: 0;\n}\n\n\/* Package Icon *\/\n.package-icon-9274 {\n    background: #e53e3e;\n    width: 1.5rem;\n    height: 1.5rem;\n    border-radius: 50%;\n    border: 3px solid #fff;\n    box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);\n    position: absolute;\n    animation: blink-package 1.2s ease-in-out infinite;\n}\n\n\/* Animations *\/\n@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }\n@keyframes blink { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } }\n@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(229, 62, 62, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(229, 62, 62, 0); } 100% { box-shadow: 0 0 0 0 rgba(229, 62, 62, 0); } }\n@keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } }\n@keyframes blink-package {\n    0% { transform: scale(1); opacity: 1; }\n    50% { transform: scale(1.2); opacity: 0.7; }\n    100% { transform: scale(1); opacity: 1; }\n}\n@keyframes slideUp {\n    0% { transform: translateY(20px); opacity: 0; }\n    100% { transform: translateY(0); opacity: 1; }\n}\n\n\/* Responsive Design *\/\n@media (max-width: 768px) {\n    .tracking-map-container-ff01 { margin: 0.5rem; border-radius: 12px; }\n    .controls-ff01 { padding: 1rem; }\n    .h3-ff01 { font-size: 1.5rem; }\n    .input-text-ff01 { max-width: 200px; }\n    .button-ff01 { max-width: 120px; }\n    .info-ff01 { margin: 0.75rem 1rem; font-size: 0.6875rem; }\n    .status-card {\n        padding: 0.75rem;\n        width: 95%;\n        max-width: 350px;\n        font-size: 0.8125rem;\n    }\n    .status-card .status-container { gap: 0.5rem; font-size: 0.75rem; }\n    .status-card .status-ball { width: 0.625rem; height: 0.625rem; }\n    .section-title { font-size: 0.8125rem; }\n    .info-section:nth-child(1) table, .info-section:nth-child(2) table, .info-section:nth-child(3) table, \n    #scheduled-stops-table, #comments-table {\n        width: 90%;\n        margin: 0 auto;\n    }\n    .info-section:nth-child(1) table thead th, .info-section:nth-child(2) table thead th, \n    .info-section:nth-child(3) table thead th, #scheduled-stops-table thead th, #comments-table thead th {\n        font-size: 0.6875rem;\n    }\n    .info-section:nth-child(1) table th, .info-section:nth-child(1) table td,\n    .info-section:nth-child(2) table th, .info-section:nth-child(2) table td,\n    .info-section:nth-child(3) table th, .info-section:nth-child(3) table td,\n    #scheduled-stops-table th, #scheduled-stops-table td,\n    #comments-table td {\n        padding: 0.25rem 0.15rem;\n        font-size: 0.625rem;\n    }\n    #comments-table tbody td::before, #comments-table tbody td::after {\n        font-size: 0.625rem;\n    }\n    #progress-controls { padding: 0 1rem 1rem; }\n    .progress-segment { font-size: 0.625rem; padding: 0 0.25rem; }\n    #map { height: 300px; }\n    .package-icon-9274 { width: 1.25rem; height: 1.25rem; }\n}\n\n@media (max-width: 480px) {\n    .h3-ff01 { font-size: 1.25rem; }\n    .controls-ff01 { padding: 0.75rem; }\n    .label-ff01 { font-size: 0.75rem; }\n    .input-text-ff01 { max-width: 180px; padding: 0.375rem; font-size: 0.75rem; }\n    .button-ff01 { max-width: 100px; padding: 0.4rem 0.8rem; font-size: 0.55rem; }\n    .info-ff01 { margin: 0.5rem; }\n    .info-ff01 th, .info-ff01 td { padding: 0.375rem 0.25rem; }\n    .info-ff01 th { width: 50%; }\n    .status-card {\n        padding: 0.5rem;\n        width: 95%;\n        max-width: 300px;\n        font-size: 0.75rem;\n    }\n    .status-card .status-container { gap: 0.375rem; font-size: 0.6875rem; }\n    .status-card .status-ball { width: 0.5625rem; height: 0.5625rem; }\n    .info-section:nth-child(1) table, .info-section:nth-child(2) table, .info-section:nth-child(3) table, \n    #scheduled-stops-table, #comments-table {\n        width: 95%;\n        margin: 0 auto;\n    }\n    .info-section:nth-child(1) table thead th, .info-section:nth-child(2) table thead th, \n    .info-section:nth-child(3) table thead th, #scheduled-stops-table thead th, #comments-table thead th {\n        font-size: 0.625rem;\n    }\n    .info-section:nth-child(1) table th, .info-section:nth-child(1) table td,\n    .info-section:nth-child(2) table th, .info-section:nth-child(2) table td,\n    .info-section:nth-child(3) table th, .info-section:nth-child(3) table td,\n    #scheduled-stops-table th, #scheduled-stops-table td,\n    #comments-table td {\n        padding: 0.2rem 0.1rem;\n        font-size: 0.5625rem;\n    }\n    #comments-table tbody td::before, #comments-table tbody td::after {\n        font-size: 0.5625rem;\n    }\n    #progress-bar-container { height: 1.75rem; }\n    .progress-segment { line-height: 1.75rem; font-size: 0.5625rem; }\n    #time-remaining { font-size: 0.6875rem; }\n    #map { height: 250px; }\n    .package-icon-9274 { width: 1rem; height: 1rem; }\n}\n<\/style>\n\n<script>\nconst userTrackingMap = {\n    map: null,\n    markers: [],\n    fullPath: null,\n    progressPath: null,\n    packageMarker: null,\n    lastLocationCircle: null,\n    animationFrame: null,\n    trackingNumber: null,\n    route: null,\n    segmentColors: ['#34c759', '#f39c12', '#e74c3c', '#9b59b6', '#3498db'],\n\n    initMap: function() {\n        this.map = L.map('map', { \n            center: [39.8283, -98.5795], \n            zoom: 4,\n            scrollWheelZoom: false \n        });\n        L.tileLayer('https:\/\/{s}.tile.openstreetmap.org\/{z}\/{x}\/{y}.png', {\n            attribution: '\u00a9 <a href=\\\"https:\/\/www.openstreetmap.org\/copyright\\\">OpenStreetMap<\/a>',\n            maxZoom: 18\n        }).addTo(this.map);\n        this.setupValidationListeners();\n        setTimeout(() => this.map.invalidateSize(), 100);\n    },\n\n    setupValidationListeners: function() {\n        const trackingInput = document.getElementById('tracking-number');\n        const button = document.querySelector('.button-ff01');\n        trackingInput.addEventListener('input', () => {\n            const error = document.getElementById('tracking-number-error');\n            const value = trackingInput.value.trim();\n            const isValid = value && value.length <= 255;\n            error.style.display = isValid ? 'none' : 'block';\n            button.disabled = !isValid;\n        });\n    },\n\n    showLoading: function(message) {\n        document.getElementById('loading-message').textContent = message;\n        const loading = document.getElementById('loading-indicator');\n        loading.style.display = 'flex';\n        loading.classList.add('active');\n    },\n\n    hideLoading: function() {\n        const loading = document.getElementById('loading-indicator');\n        loading.classList.remove('active');\n        setTimeout(() => loading.style.display = 'none', 300);\n    },\n\n    clearMap: function() {\n        this.markers.forEach(marker => marker.remove());\n        this.markers = [];\n        if (this.fullPath) this.fullPath.remove();\n        if (this.progressPath) this.progressPath.remove();\n        if (this.packageMarker) this.packageMarker.remove();\n        if (this.lastLocationCircle) this.lastLocationCircle.remove();\n        if (this.animationFrame) clearTimeout(this.animationFrame);\n\n        this.route = null;\n        const trackingInfo = document.getElementById('tracking-info');\n        trackingInfo.style.opacity = '0';\n        setTimeout(() => trackingInfo.innerHTML = '', 300);\n        document.getElementById('progress-controls').style.display = 'none';\n        document.getElementById('progress-bar').style.width = '0%';\n        document.getElementById('progress-segments').innerHTML = '';\n        document.getElementById('time-remaining').textContent = '';\n    },\n\n    async showTracking() {\n        const trackingNumber = document.getElementById('tracking-number').value.trim();\n        if (!trackingNumber || trackingNumber.length > 255) {\n            document.getElementById('tracking-number-error').style.display = 'block';\n            return;\n        }\n\n        this.showLoading('Fetching tracking data...');\n        this.clearMap();\n        this.trackingNumber = trackingNumber;\n\n        try {\n            const response = await fetch('https:\/\/globalintfrieight.com\/index.php?rest_route=\/tms\/v1\/tracking\/' + trackingNumber, {\n                method: 'GET',\n                headers: {\n                    \/\/ Note: If you restrict the GET endpoint in api.php to require authentication,\n                    \/\/ uncomment the following lines and provide the username and appPassword.\n                    \/\/ 'Authorization': 'Basic ' + btoa(username + ':' + appPassword)\n                }\n            });\n\n            if (!response.ok) {\n                const errorData = await response.json();\n                let errorMessage = errorData.message || 'Failed to fetch tracking data';\n                if (response.status === 404) {\n                    errorMessage = 'Tracking number not found. Please check the number and try again.';\n                } else if (response.status === 500) {\n                    errorMessage = 'Server error. Please try again later or contact support.';\n                }\n                throw new Error(errorMessage);\n            }\n\n            const result = await response.json();\n            this.renderTrackingInfo(result);\n            this.renderMap(result.data.points, result.data.currentStatus);\n            this.renderProgress(result.data.points);\n            this.animatePackage(result.data.points);\n        } catch (err) {\n            console.error('Error fetching tracking data:', err);\n            const trackingInfo = document.getElementById('tracking-info');\n            trackingInfo.innerHTML = \n                `<p style=\"color:#e63946; padding:1rem;\">Error: ${err.message}<\/p>`;\n            trackingInfo.style.opacity = '0';\n            trackingInfo.style.animation = 'fadeIn 0.3s ease forwards';\n        } finally {\n            this.hideLoading();\n        }\n    },\n\n    renderTrackingInfo: function(response) {\n        const data = response.data;\n        const trackingInfo = document.getElementById('tracking-info');\n\n        trackingInfo.innerHTML = `\n            <div class=\"status-card\">\n                <div class=\"status-container\">\n                    <span>Status: Out for delivery<\/span>\n                    <span class=\"status-ball\"><\/span>\n                <\/div>\n                <div class=\"expected-delivery\">\n                    Expected Delivery: 2025-07-02\n                <\/div>\n            <\/div>\n            <div class=\"tracking-details\">\n                <div class=\"info-section\" style=\"margin-bottom:1rem;\">\n                    <table>\n                        <thead>\n                            <tr>\n                                <th colspan=\"2\">Shipment Details<\/th>\n                            <\/tr>\n                        <\/thead>\n                        <tbody>\n                            <tr><th>Tracking Number<\/th><td>${response.tracking_number}<\/td><\/tr>\n                            <tr><th>Shipper Name<\/th><td>${data.shipperName || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Receiver Name<\/th><td>${data.receiverName || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Receiver Address<\/th><td>${data.receiverAddress || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Origin<\/th><td>${data.origin || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Carrier<\/th><td>${data.carrier || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Shipment Type<\/th><td>${data.shipmentType || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Total Freight<\/th><td>${data.totalFreight || 'N\/A'}<\/td><\/tr>\n                        <\/tbody>\n                    <\/table>\n                <\/div>\n                <div class=\"info-section\" style=\"margin-bottom:1rem;\">\n                    <table>\n                        <thead>\n                            <tr>\n                                <th colspan=\"2\">Package Details<\/th>\n                            <\/tr>\n                        <\/thead>\n                        <tbody>\n                            <tr><th>Number of Packages<\/th><td>${data.numPackages || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Piece Type<\/th><td>${data.pieceType || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Weight<\/th><td>${data.weight ? data.weight + ' g' : 'N\/A'}<\/td><\/tr>\n                            <tr><th>Dimensions<\/th><td>${(data.length && data.width && data.height) \n                                ? `${data.length} x ${data.width} x ${data.height} cm` : 'N\/A'}<\/td><\/tr>\n                        <\/tbody>\n                    <\/table>\n                <\/div>\n                <div class=\"info-section\" style=\"margin-bottom:1rem;\">\n                    <table>\n                        <thead>\n                            <tr>\n                                <th colspan=\"2\">Additional Information<\/th>\n                            <\/tr>\n                        <\/thead>\n                        <tbody>\n                            <tr><th>Pickup Date<\/th><td>${data.pickupDate || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Departure Time<\/th><td>${data.departureTime || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Pickup Time<\/th><td>${data.pickupTime || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Payment Mode<\/th><td>${data.paymentMode || 'N\/A'}<\/td><\/tr>\n                            <tr><th>Description<\/th><td>${data.description || 'N\/A'}<\/td><\/tr>\n                        <\/tbody>\n                    <\/table>\n                <\/div>\n            <\/div>\n        `;\n\n        \/\/ Comments Section as a Table\n        const commentsSection = document.createElement('div');\n        commentsSection.className = 'info-section';\n        commentsSection.innerHTML = `\n            <table id=\"comments-table\">\n                <thead>\n                    <tr>\n                        <th>Comments<\/th>\n                    <\/tr>\n                <\/thead>\n                <tbody><\/tbody>\n            <\/table>\n        `;\n        const commentsTbody = commentsSection.querySelector('tbody');\n\n        let comments = data.comments || 'No comments available';\n        if (typeof comments === 'string') {\n            comments = comments.split(';').map(c => c.trim()).filter(c => c);\n        }\n        if (!Array.isArray(comments)) {\n            comments = [comments];\n        }\n\n        if (comments.length > 0 && comments[0] !== 'No comments available') {\n            comments.forEach(comment => {\n                const tr = document.createElement('tr');\n                tr.innerHTML = `<td>${comment}<\/td>`;\n                commentsTbody.appendChild(tr);\n            });\n        } else {\n            commentsTbody.innerHTML = `\n                <tr><td style=\"color:#e63946;\">No comments available<\/td><\/tr>\n            `;\n        }\n        trackingInfo.querySelector('.tracking-details').appendChild(commentsSection);\n\n        \/\/ Scheduled Stops Section\n        const scheduleSection = document.createElement('div');\n        scheduleSection.className = 'info-section';\n        scheduleSection.innerHTML = `\n            <table id=\"scheduled-stops-table\">\n                <thead>\n                    <tr>\n                        <th colspan=\"3\">Scheduled Stops<\/th>\n                    <\/tr>\n                    <tr>\n                        <th>Stop<\/th>\n                        <th>Address<\/th>\n                        <th>Scheduled Time<\/th>\n                    <\/tr>\n                <\/thead>\n                <tbody><\/tbody>\n            <\/table>\n        `;\n        const stopsTbody = scheduleSection.querySelector('tbody');\n\n        if (data.points && data.points.length > 0) {\n            data.points.forEach((pt, idx) => {\n                const scheduledDate = pt.createdAt ? new Date(pt.createdAt).toLocaleString() : 'N\/A';\n                const tr = document.createElement('tr');\n                tr.innerHTML = `\n                    <th>Stop ${idx + 1}<\/th>\n                    <td>${pt.address || 'N\/A'}<\/td>\n                    <td>${scheduledDate}<\/td>\n                `;\n                stopsTbody.appendChild(tr);\n            });\n        } else {\n            stopsTbody.innerHTML = `\n                <tr><td colspan=\"3\" style=\"color:#e63946;\">No scheduled stops found<\/td><\/tr>\n            `;\n        }\n        trackingInfo.querySelector('.tracking-details').appendChild(scheduleSection);\n\n        trackingInfo.style.opacity = '0';\n        trackingInfo.style.animation = 'fadeIn 0.5s ease forwards';\n    },\n\n    renderMap: function(points, currentStatus) {\n        if (!points || points.length === 0) {\n            document.getElementById('tracking-info').innerHTML += \n                '<p style=\"color: #e63946; padding: 1rem;\">Error: No tracking points available<\/p>';\n            return;\n        }\n\n        const valid = p => Number.isFinite(parseFloat(p.lat)) && Number.isFinite(parseFloat(p.lng));\n        const coords = points.filter(valid).map(p => [parseFloat(p.lat), parseFloat(p.lng)]);\n        if (coords.length === 0) {\n            document.getElementById('tracking-info').innerHTML += \n                '<p style=\"color: #e63946; padding: 1rem;\">Error: No valid coordinates<\/p>';\n            return;\n        }\n\n        points.forEach((p, i) => {\n            if (valid(p)) {\n                const marker = L.marker([p.lat, p.lng], { draggable: false })\n                    .addTo(this.map)\n                    .bindPopup(p.address || `Stop ${i+1}`);\n                this.markers.push(marker);\n            }\n        });\n\n        this.packageMarker = L.marker(coords[0], {\n            icon: L.divIcon({\n                className: 'package-icon-9274',\n                html: '<div class=\"package-icon-9274\"><\/div>',\n                iconSize: [24, 24],\n                iconAnchor: [12, 12]\n            })\n        }).addTo(this.map);\n\n        if (coords.length > 1) {\n            this.fullPath = L.polyline(coords, { color: '#1d3557', weight: 4, opacity: 0.5 }).addTo(this.map);\n            this.progressPath = L.polyline([coords[0]], { color: '#34c759', weight: 4, opacity: 0.8 }).addTo(this.map);\n            this.lastLocationCircle = L.circle(coords[coords.length - 1], {\n                radius: 500,\n                color: '#34c759',\n                fillColor: '#34c759',\n                fillOpacity: 0.15\n            }).addTo(this.map);\n        }\n        this.map.fitBounds(L.latLngBounds(coords));\n    },\n\n    renderProgress: function(points) {\n        if (!points || points.length < 2) {\n            document.getElementById('time-remaining').textContent = 'Estimated Time Remaining: N\/A';\n            return;\n        }\n\n        const totalDurationMinutes = points.slice(1).reduce((sum, pt) => sum + (parseFloat(pt.duration) || 0), 0);\n        if (totalDurationMinutes <= 0) {\n            \/\/ Every stop shares the same date\/time, so there is nothing to count down.\n            document.getElementById('time-remaining').textContent = 'Estimated Time Remaining: N\/A';\n        }\n\n        const progressControls = document.getElementById('progress-controls');\n        const progressSegments = document.getElementById('progress-segments');\n        const segmentWidth = 100 \/ points.length;\n\n        progressControls.style.display = 'block';\n        progressControls.style.opacity = '0';\n        progressControls.style.animation = 'fadeIn 0.5s ease forwards 0.2s';\n        progressSegments.innerHTML = points.map((pt, i) => {\n            const durMin = parseFloat(pt.duration) || 0;\n            const segmentColor = this.segmentColors[i % this.segmentColors.length];\n            return `<div class=\"progress-segment\" style=\"width: ${segmentWidth}%; background-color: ${segmentColor}20;\" data-index=\"${i}\">${pt.address || `Stop ${i + 1}`} (${durMin.toFixed(1)}m)<\/div>`;\n        }).join('');\n\n        this.route = points\n            .filter(pt => Number.isFinite(parseFloat(pt.lat)) && Number.isFinite(parseFloat(pt.lng)))\n            .map((pt, i) => ({\n                address: pt.address || `Stop ${i + 1}`,\n                coords: [parseFloat(pt.lat), parseFloat(pt.lng)],\n                duration: parseFloat(pt.duration) || 0,\n                color: this.segmentColors[i % this.segmentColors.length]\n            }));\n    },\n\n    animatePackage: function(points) {\n        if (!points || points.length < 2 || !this.packageMarker || !this.route) return;\n\n        const src = this.route;               \/\/ already filtered to stops with coordinates\n        if (src.length < 2) return;\n        const coords = src.map(r => r.coords);\n\n        const firstWithCoords = points.find(p => Number.isFinite(parseFloat(p.lat)) && Number.isFinite(parseFloat(p.lng)));\n        let startTime = new Date((firstWithCoords || points[0]).createdAt).getTime();\n        if (isNaN(startTime)) startTime = Date.now();\n\n        const route = [{ coords: coords[0], startTime: startTime, duration: 0, color: src[0].color }];\n\n        for (let i = 1; i < src.length; i++) {\n            const duration = Math.max(parseFloat(src[i].duration) || 0, 0);\n            const endTime = route[i - 1].startTime + (duration * 60000);\n            route.push({\n                coords: coords[i],\n                startTime: endTime,\n                duration: duration * 60000,\n                color: src[i].color\n            });\n        }\n\n        const totalDurationMs = route[route.length - 1].startTime - route[0].startTime;\n        const progressBar = document.getElementById('progress-bar');\n        const timeRemain = document.getElementById('time-remaining');\n\n        const animate = () => {\n            const now = Date.now();\n\n            let currentSegment = 0;\n            for (let i = 0; i < route.length - 1; i++) {\n                if (now >= route[i].startTime && now <= route[i+1].startTime) {\n                    currentSegment = i;\n                    break;\n                }\n                if (now > route[route.length - 1].startTime) {\n                    currentSegment = route.length - 2;\n                }\n            }\n\n            const segStartTime = route[currentSegment].startTime;\n            const segEndTime = route[currentSegment + 1].startTime;\n            const segDuration = segEndTime - segStartTime;\n            const segProgress = segDuration ? Math.min(Math.max((now - segStartTime) \/ segDuration, 0), 1) : 1;\n\n            const startCoord = route[currentSegment].coords;\n            const endCoord = route[currentSegment + 1].coords;\n            const lat = startCoord[0] + (endCoord[0] - startCoord[0]) * segProgress;\n            const lng = startCoord[1] + (endCoord[1] - startCoord[1]) * segProgress;\n            this.packageMarker.setLatLng([lat, lng]);\n\n            const icon = this.packageMarker._icon;\n            if (icon && icon.style.animation !== 'pulse 1s infinite') {\n                icon.style.animation = 'pulse 1s infinite';\n            }\n\n            const progressCoords = route.slice(0, currentSegment + 1).map(r => r.coords);\n            if (segProgress > 0 && currentSegment < route.length - 1) {\n                progressCoords.push([lat, lng]);\n            }\n            this.progressPath.setLatLngs(progressCoords);\n\n            const segmentWidthPercent = 100 \/ (route.length);\n            const activeSegmentLeft = currentSegment * segmentWidthPercent;\n            progressBar.style.left = `${activeSegmentLeft}%`;\n            progressBar.style.width = `${segProgress * segmentWidthPercent}%`;\n            progressBar.style.backgroundColor = route[currentSegment].color;\n\n            const remainingMs = Math.max(route[route.length - 1].startTime - now, 0);\n            const remainingMin = Math.round(remainingMs \/ 60000);\n            timeRemain.textContent = `Estimated Time Remaining: ${remainingMin} minutes`;\n\n            if (now < route[route.length - 1].startTime || remainingMs > 0) {\n                this.animationFrame = setTimeout(animate, 1000);\n            } else {\n                this.packageMarker.setLatLng(coords[coords.length - 1]);\n                progressBar.style.left = `${(route.length - 1) * segmentWidthPercent}%`;\n                progressBar.style.width = `${segmentWidthPercent}%`;\n                progressBar.style.backgroundColor = route[route.length - 1].color;\n                timeRemain.textContent = 'Estimated Time Remaining: 0 minutes';\n                this.progressPath.setLatLngs(coords);\n            }\n        };\n\n        animate();\n    }\n};\n\nwindow.userTrackingMap = userTrackingMap;\nif (document.readyState === 'loading') {\n    document.addEventListener('DOMContentLoaded', () => userTrackingMap.initMap());\n} else {\n    userTrackingMap.initMap();\n}\n<\/script>\n<!-- Last updated: July 01, 2025, 07:50 PM WAT -->\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-11","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/globalintfrieight.com\/index.php?rest_route=\/wp\/v2\/pages\/11","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/globalintfrieight.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/globalintfrieight.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/globalintfrieight.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/globalintfrieight.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=11"}],"version-history":[{"count":1,"href":"https:\/\/globalintfrieight.com\/index.php?rest_route=\/wp\/v2\/pages\/11\/revisions"}],"predecessor-version":[{"id":12,"href":"https:\/\/globalintfrieight.com\/index.php?rest_route=\/wp\/v2\/pages\/11\/revisions\/12"}],"wp:attachment":[{"href":"https:\/\/globalintfrieight.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=11"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}