{"id":83317,"date":"2026-08-07T16:09:25","date_gmt":"2026-08-07T16:09:25","guid":{"rendered":"https:\/\/builders24.net\/?page_id=44848"},"modified":"2026-10-20T11:04:08","modified_gmt":"2026-10-20T11:04:08","slug":"vehicles","status":"publish","type":"page","link":"https:\/\/builders24.net\/zw\/vehicles\/","title":{"rendered":"Vehicles"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"83317\" class=\"elementor elementor-83317\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6ee5eff e-con e-atomic-element e-flexbox-base e-default-div e-cb0ceb1 \" data-id=\"6ee5eff\" data-element_type=\"e-flexbox\" data-e-type=\"e-flexbox\" data-interaction-id=\"6ee5eff\">\n    \t\t<div class=\"elementor-element elementor-element-2fb5d84 elementor-widget elementor-widget-html\" data-id=\"2fb5d84\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"UTF-8\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n<title>Vehicles For Sale \u2014 Trucks, Bakkies, Buses & Heavy Equipment | Builders24<\/title>\r\n<meta name=\"description\" content=\"Trucks, buses, trailers, machinery, vans, pickups and farm equipment for sale across Africa on Builders24.\">\r\n<link rel=\"canonical\" href=\"https:\/\/app.builders24.net\/vehicles.html\">\r\n<link rel=\"stylesheet\" href=\"https:\/\/app.builders24.net\/b24app.css\">\r\n<meta name=\"robots\" content=\"index, follow\">\r\n\r\n<meta property=\"og:type\" content=\"website\">\r\n<meta property=\"og:site_name\" content=\"Builders24\">\r\n<meta property=\"og:title\" content=\"Vehicles For Sale \u2014 Trucks, Bakkies, Buses & Heavy Equipment | Builders24\">\r\n<meta property=\"og:description\" content=\"Trucks, buses, trailers, machinery, vans, pickups and farm equipment for sale across Africa.\">\r\n<meta property=\"og:url\" content=\"https:\/\/app.builders24.net\/vehicles.html\">\r\n<meta property=\"og:image\" content=\"https:\/\/builders24.net\/wp-content\/uploads\/2026\/08\/Builders24-Auto.png\">\r\n<meta property=\"og:locale\" content=\"en_ZA\">\r\n\r\n<meta name=\"twitter:card\" content=\"summary_large_image\">\r\n<meta name=\"twitter:title\" content=\"Vehicles For Sale \u2014 Builders24\">\r\n<meta name=\"twitter:description\" content=\"Trucks, buses, trailers, machinery, vans, pickups and farm equipment for sale across Africa.\">\r\n<meta name=\"twitter:image\" content=\"https:\/\/builders24.net\/wp-content\/uploads\/2026\/08\/Builders24-Auto.png\">\r\n\r\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\r\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\r\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\r\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Archivo:wght@500;600;700;800&family=Archivo+Narrow:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">\r\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700;800;900&display=swap\" rel=\"stylesheet\">\r\n<link rel=\"stylesheet\" href=\"https:\/\/cdn.jsdelivr.net\/npm\/@tabler\/icons-webfont@latest\/tabler-icons.min.css\">\r\n\r\n<style>\r\n  :root{\r\n    --navy:#0D1B3E;\r\n    --navy-3:#091430;\r\n    --orange:#F0A500;\r\n    --gold:#F2B705;\r\n    --grey-bg:#EEF0F3;\r\n    --grey-text:#6B7280;\r\n    --grey-light:#9CA3AF;\r\n    --border:#E7E9EC;\r\n    --white:#FFFFFF;\r\n    --text:#0D1220;\r\n    --amber:#FBBF24;\r\n    --navy-2:#16295A; --blue:#2563EB; --blue-dark:#1D4ED8; --green:#16A34A; --muted:#6B7280; --bg:#F4F6FA;\r\n  }\r\n  *{box-sizing:border-box; margin:0; padding:0;}\r\n  html,body{height:100%;}\r\n  body{\r\n    font-family:'Inter', sans-serif;\r\n    background:#FFFFFF;\r\n    color:var(--text);\r\n    -webkit-font-smoothing:antialiased;\r\n  }\r\n\r\n  .vfilter-panel{ max-width:280px; background:var(--white); border-right:1px solid var(--border); padding:20px 18px; }\r\n  .filter-group{ margin-bottom:22px; }\r\n  .filter-group-head{ font-size:12.5px; font-weight:700; color:var(--text); margin-bottom:10px; }\r\n  .check-row{ font-size:12.5px; color:var(--grey-text); padding:4px 0; }\r\n  .check-row label{ display:flex; align-items:center; gap:7px; cursor:pointer; }\r\n  .show-more-link{ display:inline-flex; align-items:center; gap:4px; font-size:11.5px; color:var(--blue); font-weight:600; margin-top:6px; }\r\n  .clear-all{ background:none; border:none; font-size:11.5px; color:var(--blue); font-weight:600; cursor:pointer; }\r\n  .apply-btn{ width:100%; background:var(--navy); color:#fff; font-size:12.5px; font-weight:700; padding:11px; border-radius:9px; margin-top:6px; }\r\n  .sidebar-head{ display:flex; justify-content:space-between; align-items:center; margin-bottom:16px; }\r\n  .sidebar-head h4{ font-size:14px; font-weight:700; }\r\n  @media(max-width:900px){ .vfilter-panel{ max-width:none; border-right:none; border-bottom:1px solid var(--border); } }\r\n\r\n  \/* Checkbox filter lists (Vehicle Type \/ Currency \/ Seller Location) \u2014 2-col\r\n     grid on mobile so a long list doesn't stretch the page or force\r\n     horizontal scroll; single column on desktop where width isn't tight. *\/\r\n  .vm-checkbox-grid{ display:grid; grid-template-columns:1fr; gap:2px; min-width:0; }\r\n  @media(max-width:900px){ .vm-checkbox-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:2px 10px; } }\r\n  .vm-checkbox-grid .check-row, .vm-checkbox-grid .vm-check-row{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\r\n\r\n  \/* Global mobile overflow safety \u2014 nothing should be able to force\r\n     horizontal scroll on a phone screen. *\/\r\n  @media(max-width:768px){\r\n    html, body{ overflow-x:hidden; max-width:100vw; }\r\n    input, select{ max-width:100%; box-sizing:border-box; }\r\n  }\r\n\r\n\/* ===== Builders24_Auto_Listing design replica (bl- prefix) ===== *\/\r\n.bl-root, .bl-root *{font-family:'Archivo Narrow',Helvetica,Arial,sans-serif}\r\n.bl-brand-text,.bl-hero-inner h1,.bl-search-btn,.bl-tab,.bl-card-price,.bl-card-badge{font-family:'Archivo',sans-serif}\r\n.bl-hero{position:relative;background:#1E2A4A;overflow:hidden}\r\n.bl-hero-bg{position:absolute;inset:0;background:url('https:\/\/app.builders24.net\/assets\/builders24auto.png') center\/cover;z-index:0}\r\n.bl-hero-overlay{position:absolute;inset:0;background:linear-gradient(100deg,rgba(24,36,68,.96) 0%,rgba(24,36,68,.78) 38%,rgba(24,36,68,.15) 68%)}\r\n.bl-topbar{position:relative;z-index:1;display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid rgba(255,255,255,.15);gap:8px}\r\n.bl-brand{display:flex;align-items:center;gap:10px;min-width:0;flex-shrink:0}\r\n.bl-brand-text{font-family:'Archivo',sans-serif;font-weight:800;font-size:19px;color:#fff;line-height:1.1}\r\n.bl-brand-sub{font-size:12px;font-weight:700;color:#F5A623;letter-spacing:1px}\r\n.bl-nav{display:flex;align-items:center;gap:32px}\r\n.bl-nav a{color:#fff;font-size:14px;cursor:pointer}\r\n.bl-nav .bl-nav-active{color:#F5A623;font-weight:600}\r\n.bl-brand{display:flex;align-items:center;gap:10px;min-width:0;flex-shrink:0}\r\n.bl-brand-text{display:flex;flex-direction:column}\r\n.bl-brand-main{font-family:'Archivo',sans-serif;font-weight:800;font-size:19px;color:#fff;line-height:1.1;white-space:nowrap}\r\n.bl-brand-sub{font-size:10px;font-weight:700;color:#F5A623;letter-spacing:.5px;text-transform:uppercase;text-align:justify;text-align-last:justify;white-space:nowrap;width:100%}\r\n.bl-topbar-right{display:flex;align-items:center;gap:8px;flex-shrink:0}\r\n.bl-saved{display:none;align-items:center;gap:6px;color:#fff;font-size:14px;cursor:pointer}\r\n.bl-avatar{width:30px;height:30px;border-radius:50%;background:#EDEFF3;display:flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0}\r\n.bl-avatar img{width:100%;height:100%;object-fit:cover}\r\n.bl-login-link{color:#fff;font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap}\r\n.bl-util{display:flex;align-items:center;gap:4px}\r\n.bl-util-btn{display:flex;align-items:center;gap:4px;color:#fff;font-size:12px;background:rgba(255,255,255,.1);border-radius:7px;padding:6px 8px;cursor:pointer;position:relative}\r\n.bl-util-dropdown{display:none;position:absolute;top:calc(100% + 6px);right:0;background:#fff;border-radius:10px;box-shadow:0 12px 28px rgba(13,27,62,.25);padding:8px;min-width:180px;max-height:280px;overflow-y:auto;z-index:20}\r\n.bl-util-dropdown.open{display:block}\r\n.bl-util-item{padding:8px 10px;font-size:13px;color:#0D1B3E;border-radius:7px;cursor:pointer;display:flex;justify-content:space-between;gap:8px}\r\n.bl-util-item:hover{background:#F4F6FA}\r\n.bl-util-item.selected{font-weight:700;color:#F5A623}\r\n@media(min-width:900px){\r\n  .bl-topbar{padding:18px 40px}\r\n  .bl-saved{display:flex}\r\n  .bl-util{gap:6px}\r\n  .bl-util-btn{gap:5px;font-size:12.5px;padding:6px 10px}\r\n}\r\n.bl-hero-inner{position:relative;z-index:1;padding:60px 40px 0;max-width:720px}\r\n.bl-hero-inner h1{margin:0;font-family:'Archivo',sans-serif;font-weight:800;font-size:44px;line-height:1.1;color:#fff}\r\n.bl-hero-inner h1 span{color:#F5A623;display:block;margin-top:6px;font-size:.55em;line-height:1.2;font-weight:800}\r\n.bl-hero-inner p{margin:16px 0 0;font-size:15px;line-height:1.55;color:rgba(255,255,255,.92);max-width:560px}\r\n.bl-trust-row{display:flex;gap:18px 28px;margin-top:26px;flex-wrap:wrap}\r\n.bl-trust-chip{display:flex;align-items:center;gap:10px}\r\n.bl-trust-icon{width:34px;height:34px;border-radius:50%;background:rgba(255,255,255,.12);display:flex;align-items:center;justify-content:center;flex-shrink:0}\r\n.bl-trust-title{color:#fff;font-size:13px;font-weight:600;line-height:1.3}\r\n.bl-trust-sub{color:rgba(255,255,255,.82);font-size:12px}\r\n.bl-tabbar{position:relative;z-index:1;margin-top:52px;padding:0 40px;display:flex;gap:2px}\r\n.bl-tab{background:rgba(255,255,255,.1);color:rgba(255,255,255,.85);font-size:14px;padding:14px 28px;border-radius:10px 10px 0 0;cursor:pointer;text-decoration:none;display:inline-block;}\r\n.bl-tab-active{background:#141C33;color:#fff;font-weight:600}\r\n@media(max-width:900px){.bl-topbar,.bl-hero-inner,.bl-tabbar{padding-left:5vw;padding-right:5vw}.bl-nav{display:none}.bl-hero-inner h1{font-size:32px}}\r\n\r\n.bl-filtercard{position:relative;z-index:1;margin:0 40px -40px;background:#fff;border-radius:0 12px 12px 12px;box-shadow:0 8px 24px rgba(20,28,50,.15);padding:24px 28px}\r\n.bl-filter-grid{display:grid;grid-template-columns:1fr 1fr 1fr 1fr auto;gap:16px;align-items:end}\r\n.bl-filter-field{display:flex;flex-direction:column;gap:6px}\r\n.bl-filter-field span{font-size:13px;color:#767E90}\r\n.bl-select{border:1px solid #E1E4EA;border-radius:8px;padding:10px 12px;font-size:14px;color:#3A3F4D;font-family:inherit;background:#fff;width:100%}\r\n.bl-search-btn{background:#141C33;color:#fff;border:none;border-radius:8px;padding:12px 22px;font-size:14px;font-weight:600;font-family:'Archivo',sans-serif;cursor:pointer;display:flex;align-items:center;gap:8px;white-space:nowrap;transition:background .15s}\r\n.bl-search-btn:hover{background:#0D1424}\r\n.bl-filter-foot{display:flex;justify-content:space-between;margin-top:16px;font-size:13px;color:#8B93A7}\r\n.bl-adv-link{display:flex;align-items:center;gap:6px;cursor:pointer}\r\n@media(max-width:900px){.bl-filtercard{margin:0 5vw -30px;padding:18px}.bl-filter-grid{grid-template-columns:1fr 1fr;gap:12px}.bl-search-btn{grid-column:1\/-1}}\r\n\r\n.bl-main{padding:80px 40px 80px}\r\n@media(max-width:900px){.bl-main{padding:70px 5vw 60px}}\r\n.bl-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:24px}\r\n@media(max-width:1150px){.bl-grid{grid-template-columns:repeat(3,1fr)}}\r\n@media(max-width:760px){.bl-grid{grid-template-columns:repeat(2,1fr);gap:14px}}\r\n.bl-card{background:#fff;border:1px solid #E7E9EF;border-radius:12px;overflow:hidden;display:flex;flex-direction:column;transition:box-shadow .15s;text-decoration:none;color:inherit}\r\n.bl-card:hover{box-shadow:0 10px 24px rgba(20,28,50,.1)}\r\n.bl-card-img{position:relative;width:100%;aspect-ratio:4\/3;background:#F1F3F7;display:flex;align-items:center;justify-content:center}\r\n.bl-card-img img{width:100%;height:100%;object-fit:cover}\r\n.bl-card-img i{font-size:30px;color:#C9D0DE}\r\n.bl-card-badge{position:absolute;top:12px;left:12px;z-index:2;background:#2B5FBF;color:#fff;font-size:12px;font-weight:600;padding:4px 10px;border-radius:6px;font-family:'Archivo',sans-serif}\r\n.bl-fav-btn{position:absolute;top:10px;right:10px;z-index:2;width:32px;height:32px;border-radius:50%;background:#fff;border:1px solid #E7E9EF;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0}\r\n.bl-card-body{padding:14px 16px 18px;display:flex;flex-direction:column;gap:6px}\r\n.bl-card-title{font-size:14px;color:var(--navy)}\r\n.bl-card-price{font-size:17px;font-weight:700;font-family:'Archivo',sans-serif;color:#1A1D29}\r\n.bl-card-meta{display:flex;align-items:center;gap:14px;font-size:13px;color:#767E90;margin-top:2px}\r\n.bl-card-meta span{display:flex;align-items:center;gap:4px}\r\n.bl-card-flag{display:flex;align-items:center;gap:5px;margin-left:auto}\r\n.bl-flag-emoji{font-size:13px;line-height:1}\r\n\r\n\/* ===== Real vm- block, copied exactly from vehicles.html ===== *\/\r\n.vm-hero{position:relative;min-height:340px;display:flex;align-items:center;overflow:hidden;background:var(--navy)}\r\n.vm-hero-bg{position:absolute;inset:0;background-image:linear-gradient(100deg,rgba(9,20,48,.94) 10%,rgba(9,20,48,.55) 60%,rgba(9,20,48,.25) 100%),url('https:\/\/builders24.net\/wp-content\/uploads\/2026\/08\/Builders24-Auto.png');background-size:cover;background-position:center}\r\n.vm-hero-inner{position:relative;z-index:2;padding:56px 5vw 40px;width:100%}\r\n.vm-hero h1{font-size:clamp(28px,4.2vw,42px);font-weight:800;color:#fff;line-height:1.12;margin-bottom:14px}\r\n.vm-hero p{font-size:14.5px;color:#fff;opacity:.88;max-width:520px;margin-bottom:24px;line-height:1.6}\r\n.vm-search-row{display:flex;max-width:640px;border-radius:10px;overflow:hidden;box-shadow:0 8px 24px rgba(0,0,0,.25)}\r\n.vm-search-row input{flex:1;border:none;padding:15px 18px;font-size:13.5px;font-family:inherit}\r\n.vm-search-row input:focus{outline:none}\r\n.vm-search-btn{background:var(--orange);color:var(--navy-3);font-weight:700;font-size:13px;padding:0 26px;white-space:nowrap;transition:filter .15s}\r\n.vm-search-btn:hover{filter:brightness(1.08)}\r\n.vm-stats{display:flex;flex-wrap:wrap;gap:28px;margin-top:26px}\r\n.vm-stat{display:flex;align-items:center;gap:9px;color:#fff}\r\n.vm-stat i{font-size:18px;color:var(--orange)}\r\n.vm-stat-num{font-size:13.5px;font-weight:700}\r\n.vm-stat-label{font-size:11.5px;opacity:.8}\r\n\r\n.vm-filterbar{background:#fff;border-bottom:1px solid var(--border);position:sticky;top:0;z-index:20}\r\n@media(max-width:900px){.vm-filterbar{position:static;}}\r\n.vm-filterbar-inner{padding:0 5vw}\r\n.vm-tabs{display:flex;gap:26px;overflow-x:auto;border-bottom:1px solid var(--border);padding-top:14px}\r\n.vm-tab{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:600;color:var(--muted);padding-bottom:13px;white-space:nowrap;border-bottom:2px solid transparent;cursor:pointer}\r\n.vm-tab i{font-size:16px}\r\n.vm-tab.active{color:var(--blue);border-color:var(--blue)}\r\n.vm-filters{display:flex;gap:10px;align-items:center;padding:14px 0;flex-wrap:wrap}\r\n.vm-filters input,.vm-filters select{border:1px solid var(--border);border-radius:8px;padding:10px 12px;font-size:12.5px;font-family:inherit;color:var(--navy);background:#fff}\r\n.vm-filters input[type=text]{flex:1;min-width:180px}\r\n.vm-filters select{min-width:110px}\r\n.vm-search-main-btn{background:var(--blue);color:#fff;font-weight:700;font-size:12.5px;padding:10px 20px;border-radius:8px;white-space:nowrap;transition:background .15s}\r\n.vm-search-main-btn:hover{background:var(--blue-dark)}\r\n.vm-advanced-link{font-size:11.5px;color:var(--blue);font-weight:600;margin-left:auto;white-space:nowrap}\r\n.vm-filters-extra{display:contents;}\r\n@media(max-width:900px){.vm-filters{flex-direction:column;align-items:stretch}.vm-filters select,.vm-filters input{width:100%}.vm-advanced-link{margin-left:0}}\r\n\r\n\/* ---- Mobile filter collapse: search + button only by default, rest\r\n   tucked behind a \"Filters\" toggle. Desktop is completely unaffected. ---- *\/\r\n.vm-filters-toggle{display:none;}\r\n@media(max-width:900px){\r\n  .vm-filters-toggle{\r\n    display:flex;align-items:center;justify-content:center;gap:6px;\r\n    border:1px solid var(--border);border-radius:8px;padding:10px 12px;\r\n    font-size:12.5px;font-weight:600;color:var(--navy);background:#fff;width:100%;\r\n  }\r\n  .vm-filters-toggle i{font-size:15px;}\r\n  .vm-filters-extra{display:none;flex-direction:column;gap:10px;width:100%;}\r\n  .vm-filters-extra.open{display:flex;}\r\n}\r\n\r\n.vm-section{padding:26px 5vw}\r\n.vm-cat-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}\r\n.vm-cat-header h2{font-size:16px;font-weight:700}\r\n.vm-cat-header a{font-size:12px;color:var(--blue);font-weight:600}\r\n.vm-cat-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:14px}\r\n.vm-cat-card{background:#fff;border:1px solid var(--border);border-radius:12px;padding:14px 12px 16px;text-align:center;transition:border-color .15s,transform .15s;cursor:pointer;display:flex;flex-direction:column}\r\n.vm-cat-card:hover{border-color:var(--blue);transform:translateY(-2px)}\r\n.vm-cat-icon{width:38px;height:38px;background:var(--bg);border-radius:9px;display:flex;align-items:center;justify-content:center;margin:0 auto 9px}\r\n.vm-cat-icon i{font-size:19px;color:var(--navy)}\r\n.vm-cat-photo{width:100%;height:110px;border-radius:9px;background-size:contain;background-repeat:no-repeat;background-position:center;background-color:var(--bg);margin-bottom:10px}\r\n.vm-cat-name{font-size:12.5px;font-weight:700;margin-bottom:2px}\r\n.vm-cat-count{font-size:11px;color:var(--muted)}\r\n@media(max-width:900px){.vm-cat-grid{grid-template-columns:repeat(3,1fr)}}\r\n\r\n.vm-layout{padding:0 5vw 50px;display:grid;grid-template-columns:260px 1fr;gap:22px;align-items:start}\r\n@media(max-width:1150px){.vm-layout{grid-template-columns:1fr}}\r\n\r\n.vm-side{background:#fff;border:1px solid var(--border);border-radius:12px;padding:18px;min-width:0;box-sizing:border-box;}\r\n.vm-side-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}\r\n.vm-side-head h3{font-size:13.5px;font-weight:700}\r\n.vm-side-head button{font-size:11px;color:var(--blue);font-weight:600}\r\n.vm-side-group{margin-bottom:20px}\r\n.vm-side-group-title{font-size:12px;font-weight:700;margin-bottom:10px}\r\n.vm-check-row{display:flex;align-items:center;justify-content:space-between;font-size:12.5px;padding:5px 0;color:var(--navy)}\r\n.vm-check-row label{display:flex;align-items:center;gap:8px;cursor:pointer}\r\n.vm-check-row input{accent-color:var(--blue)}\r\n.vm-check-count{color:var(--muted);font-size:11.5px}\r\n.vm-range-row{display:flex;gap:8px}\r\n.vm-range-row select, .vm-range-row input{min-width:0;flex:1;}\r\n.vm-range-row input,.vm-range-row select{flex:1;border:1px solid var(--border);border-radius:7px;padding:8px 9px;font-size:12px;font-family:inherit}\r\n\r\n.vm-result-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;flex-wrap:wrap;gap:10px}\r\n.vm-result-count{font-size:15px;font-weight:700}\r\n.vm-result-sub{font-size:12px;color:var(--muted);margin-top:2px}\r\n.vm-result-actions{display:flex;align-items:center;gap:10px}\r\n.vm-result-actions select{border:1px solid var(--border);border-radius:7px;padding:8px 10px;font-size:12px;font-family:inherit}\r\n.vm-view-toggle{display:flex;border:1px solid var(--border);border-radius:7px;overflow:hidden}\r\n.vm-view-toggle button{padding:8px 10px;background:#fff}\r\n.vm-view-toggle button.active{background:var(--bg)}\r\n\r\n.vm-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:18px}\r\n@media(min-width:700px){.vm-grid{grid-template-columns:repeat(3,1fr);gap:20px}}\r\n@media(min-width:1150px){.vm-grid{grid-template-columns:repeat(4,1fr);gap:22px}}\r\n.vm-card{display:block;background:#fff;border:1px solid var(--border);border-radius:14px;overflow:hidden;transition:box-shadow .18s,transform .18s}\r\n.vm-card:hover{box-shadow:0 14px 30px rgba(13,27,62,.14);transform:translateY(-2px)}\r\n.vm-card-img{position:relative;height:190px;background:var(--bg);display:flex;align-items:center;justify-content:center;overflow:hidden}\r\n.vm-card-img img{width:100%;height:100%;object-fit:cover}\r\n.vm-card-img i{font-size:34px;color:#C9D0DE}\r\n.vm-badge{position:absolute;top:10px;left:10px;background:var(--green);color:#fff;font-size:9.5px;font-weight:700;padding:4px 10px;border-radius:6px;text-transform:uppercase;letter-spacing:.02em}\r\n.vm-card-body{padding:14px 15px 15px}\r\n.vm-card-price{font-size:19px;font-weight:800;color:var(--navy);margin-bottom:4px;letter-spacing:-.01em}\r\n.vm-card-title{font-size:13px;font-weight:600;color:var(--text);margin-bottom:3px}\r\n.vm-card-meta{font-size:11px;color:var(--muted);margin-bottom:8px}\r\n.vm-card-loc{font-size:11.5px;color:var(--muted);display:flex;align-items:center;gap:4px;margin-bottom:10px}\r\n.vm-buy-now-btn{width:100%;background:var(--orange);color:#0D1B3E;border:none;border-radius:9px;padding:11px;font-size:13px;font-weight:700;cursor:pointer;transition:filter .15s}\r\n.vm-buy-now-btn:hover{filter:brightness(1.06)}\r\n.vm-buy-now-btn:disabled{opacity:0.6;cursor:not-allowed}\r\n\r\n\/* ---- List view (real, wired) \u2014 toggled via #listingGrid.list-view ---- *\/\r\n#listingGrid.list-view{ grid-template-columns:1fr; }\r\n#listingGrid.list-view .vm-card{ display:flex; flex-direction:row; align-items:stretch; }\r\n#listingGrid.list-view .vm-card-img{ width:180px; height:auto; flex-shrink:0; }\r\n#listingGrid.list-view .vm-card-body{ flex:1; display:flex; flex-direction:column; justify-content:center; }\r\n@media(max-width:600px){\r\n  #listingGrid.list-view .vm-card{ flex-direction:column; }\r\n  #listingGrid.list-view .vm-card-img{ width:100%; height:150px; }\r\n}\r\n\r\n.vm-empty{background:#fff;border:1px solid var(--border);border-radius:14px;padding:56px 30px;text-align:center;grid-column:1\/-1}\r\n.vm-empty i{font-size:38px;color:#C9D0DE;margin-bottom:14px}\r\n.vm-empty h3{font-size:16px;font-weight:700;margin-bottom:8px}\r\n.vm-empty p{font-size:12.5px;color:var(--muted);max-width:380px;margin:0 auto 18px;line-height:1.6}\r\n.vm-empty a{display:inline-block;background:var(--blue);color:#fff;font-size:12.5px;font-weight:700;padding:11px 22px;border-radius:8px}\r\n\r\n.vm-insights{background:#fff;border:1px solid var(--border);border-radius:12px;padding:18px}\r\n.vm-insights-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}\r\n.vm-insights-head h3{font-size:13px;font-weight:700}\r\n.vm-insights-head a{font-size:11px;color:var(--blue);font-weight:600}\r\n.vm-insight-row{display:flex;justify-content:space-between;align-items:flex-start;padding:9px 0;border-bottom:1px solid var(--border);font-size:12px}\r\n.vm-insight-row:last-of-type{border-bottom:none}\r\n.vm-insight-label{color:var(--muted)}\r\n.vm-insight-value{font-weight:700;text-align:right}\r\n\r\n.vm-expert{background:#fff;border:1px solid var(--border);border-radius:12px;padding:16px 20px;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:14px;grid-column:1\/-1;margin-top:16px}\r\n.vm-expert-left{display:flex;align-items:center;gap:12px}\r\n.vm-expert-left i{font-size:24px;color:var(--blue)}\r\n.vm-expert-left strong{font-size:13px;display:block}\r\n.vm-expert-left span{font-size:11.5px;color:var(--muted)}\r\n.vm-expert a{background:var(--blue);color:#fff;font-size:12px;font-weight:700;padding:10px 18px;border-radius:8px;white-space:nowrap}\r\n\r\n.vm-trust{padding:0 5vw 44px;display:grid;grid-template-columns:repeat(5,1fr);gap:14px}\r\n.vm-trust-item{text-align:center;padding:14px 8px;display:block;}\r\na.vm-trust-item{cursor:pointer;border-radius:10px;transition:background .15s ease;}\r\na.vm-trust-item:hover{background:var(--grey-bg);}\r\n.vm-trust-item i{font-size:22px;color:var(--blue);margin-bottom:8px;display:block}\r\n.vm-trust-item strong{font-size:12px;display:block;margin-bottom:2px}\r\n.vm-trust-item span{font-size:10.5px;color:var(--muted)}\r\n@media(max-width:900px){.vm-trust{grid-template-columns:repeat(2,1fr)}}\r\n\r\n\r\n\r\n\/* ===== Shop-style listing layout (toolbar, chips, sidebar filters, tiles, pager) ===== *\/\r\n.shop-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:14px}\r\n.shop-search{flex:1 1 100%;display:flex;align-items:center;gap:8px;background:#fff;border:1.5px solid var(--border);border-radius:12px;padding:0 12px;min-height:46px;min-width:0}\r\n.shop-search:focus-within{border-color:var(--navy)}\r\n.shop-search input{flex:1;min-width:0;border:none;outline:none;background:transparent;font-size:14px;color:var(--text);padding:12px 0;font-family:inherit}\r\n.shop-search .s-clear{width:28px;height:28px;border-radius:50%;display:none;align-items:center;justify-content:center;color:var(--navy);font-size:18px;line-height:1}\r\n.shop-search .s-clear.show{display:flex}\r\n.shop-ctl{min-height:44px;display:flex;align-items:center;gap:8px;background:#fff;border:1.5px solid var(--border);border-radius:12px;padding:0 12px;font-size:13px;font-weight:700;color:var(--navy);min-width:0;font-family:inherit}\r\n.shop-filters-btn{flex:none;cursor:pointer}\r\n.shop-filters-btn .fcount{background:var(--orange);color:var(--navy);border-radius:999px;min-width:20px;height:20px;padding:0 6px;font-size:11.5px;display:none;align-items:center;justify-content:center}\r\n.shop-filters-btn .fcount.show{display:inline-flex}\r\n.shop-sort{flex:1 1 140px}\r\n.shop-sort select{flex:1;min-width:0;border:none;background:transparent;font:inherit;font-weight:700;color:var(--navy);outline:none;padding:10px 0;cursor:pointer}\r\n.shop-viewtoggle{display:flex;flex:none;border:1.5px solid var(--border);border-radius:12px;overflow:hidden;background:#fff}\r\n.shop-viewtoggle button{width:44px;height:41px;display:flex;align-items:center;justify-content:center;color:var(--navy);background:#fff;cursor:pointer}\r\n.shop-viewtoggle button.on{background:var(--navy);color:#fff}\r\n.shop-viewtoggle svg{stroke:currentColor}\r\n@media(min-width:900px){.shop-search{flex:1 1 380px}.shop-filters-btn{display:none}.shop-sort{flex:0 0 250px}}\r\n.dept-row{display:flex;gap:8px;overflow-x:auto;padding:2px 0 10px;margin-bottom:4px;-webkit-overflow-scrolling:touch}\r\n.chip{flex:none;border:1.5px solid var(--border);background:#fff;border-radius:999px;padding:9px 14px;font-size:12.5px;font-weight:700;color:var(--navy);white-space:nowrap;min-height:38px;cursor:pointer;font-family:inherit}\r\n.chip .n{font-weight:500;margin-left:6px}\r\n.chip.on{background:var(--navy);color:#fff;border-color:var(--navy)}\r\n.chip:active,.btn-primary:active,.btn-ghost:active,.pg:active{transform:translateY(1px)}\r\n.active-bar{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:12px}\r\n.active-bar:empty{display:none}\r\n.af-chip{background:#FFF4D6;border:1px solid var(--orange);color:var(--navy);border-radius:999px;padding:5px 6px 5px 12px;font-size:12px;font-weight:700;display:inline-flex;gap:6px;align-items:center}\r\n.af-chip button{width:22px;height:22px;border-radius:50%;background:#fff;color:var(--navy);font-size:15px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer}\r\n.af-clear{color:var(--navy);text-decoration:underline;font-weight:700;font-size:12.5px;padding:6px 4px;cursor:pointer;font-family:inherit}\r\n.shop-body{display:block}\r\n@media(min-width:900px){.shop-body{display:grid;grid-template-columns:280px minmax(0,1fr);gap:28px;align-items:start}}\r\n.shop-main{min-width:0}\r\n.sheet-overlay{position:fixed;inset:0;background:rgba(9,15,32,.55);z-index:300;opacity:0;pointer-events:none;transition:opacity .25s ease}\r\n.sheet-overlay.open{opacity:1;pointer-events:auto}\r\n.shop-side{position:fixed;left:0;right:0;bottom:0;z-index:301;background:#fff;border-radius:18px 18px 0 0;max-height:88vh;display:flex;flex-direction:column;transform:translateY(100%);transition:transform .28s ease}\r\n.shop-side.open{transform:translateY(0)}\r\n.side-head{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;border-bottom:1px solid var(--border);font-size:15px;font-weight:800;color:var(--navy)}\r\n.side-head .close{width:34px;height:34px;border-radius:50%;background:var(--grey-bg);color:var(--navy);font-size:20px;line-height:1;cursor:pointer}\r\n.side-scroll{overflow-y:auto;padding:0 16px 12px;flex:1;min-height:0}\r\n.side-foot{display:flex;gap:10px;padding:12px 16px calc(12px + env(safe-area-inset-bottom));border-top:1px solid var(--border)}\r\n.side-foot .btn-primary{flex:1}\r\n@media(min-width:900px){.sheet-overlay{display:none}.shop-side{position:sticky;top:12px;z-index:1;transform:none;border-radius:14px;border:1px solid var(--border);max-height:calc(100vh - 24px)}.side-head .close,.side-foot{display:none}.side-head{border-bottom:none;padding-bottom:2px}}\r\n.fs{border-bottom:1px solid var(--border);padding:4px 0 14px}\r\n.fs:last-of-type{border-bottom:none}\r\n.fs[hidden]{display:none}\r\n.fs summary{list-style:none;cursor:pointer;display:flex;justify-content:space-between;align-items:center;padding:12px 0 8px;font-size:14px;font-weight:800;color:var(--navy);min-height:44px}\r\n.fs summary::-webkit-details-marker{display:none}\r\n.fs summary::after{content:'+';font-size:18px;font-weight:700}\r\n.fs[open] summary::after{content:'\\2212'}\r\n.fs-input{width:100%;border:1px solid var(--border);border-radius:10px;padding:10px 12px;font-size:13px;color:var(--text);background:#fff;margin-bottom:8px;font-family:inherit}\r\n.cat-line{display:flex;align-items:center;gap:2px}\r\n.cat-tog{width:26px;height:30px;flex:none;display:flex;align-items:center;justify-content:center;color:var(--navy);cursor:pointer}\r\n.cat-tog svg{stroke:currentColor;transition:transform .15s ease}\r\n.cat-tog.open svg{transform:rotate(90deg)}\r\n.cat-tog.none{visibility:hidden}\r\n.cat-row{flex:1;min-width:0;display:flex;align-items:center;gap:8px;text-align:left;padding:7px 8px;border-radius:8px;font-size:13px;color:var(--navy);min-height:34px;cursor:pointer;font-family:inherit}\r\n.cat-row:hover{background:#F3F5F9}\r\n.cat-row.sel{background:#FFF4D6;font-weight:800}\r\n.cat-row>span:first-child{flex:1;min-width:0;overflow-wrap:anywhere}\r\n.cat-count{margin-left:auto;font-size:11.5px;font-weight:600;color:var(--navy);flex:none}\r\n.cat-kids{margin-left:12px;padding-left:6px;border-left:1px solid var(--border)}\r\n#catTree{max-height:360px;overflow-y:auto}\r\n.opt{display:flex;align-items:center;gap:10px;padding:6px 4px;font-size:13px;color:var(--navy);cursor:pointer;min-height:36px}\r\n.opt input{width:18px;height:18px;accent-color:#F0A500;flex:none}\r\n.opt .lbl{flex:1;min-width:0;overflow-wrap:anywhere}\r\n.fs-more{color:var(--navy);text-decoration:underline;font-weight:700;font-size:12.5px;padding:8px 4px;cursor:pointer;font-family:inherit}\r\n.price-inputs{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr) auto;gap:8px;align-items:end}\r\n.price-inputs label{display:block;font-size:11.5px;font-weight:700;color:var(--navy);margin-bottom:4px}\r\n.price-inputs input,.price-inputs select{width:100%;border:1px solid var(--border);border-radius:10px;padding:10px;font-size:13px;color:var(--text);font-family:inherit;background:#fff}\r\n.btn-go{background:var(--navy);color:#fff;border-radius:10px;padding:0 16px;height:40px;font-size:13px;font-weight:800;cursor:pointer}\r\n.budget-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}\r\n.budget-chips .chip{padding:7px 11px;min-height:34px;font-size:12px}\r\n.btn-primary{background:var(--orange);color:var(--navy);font-weight:800;border-radius:10px;padding:12px 16px;font-size:13.5px;min-height:44px;cursor:pointer;font-family:inherit}\r\n.btn-ghost{border:1.5px solid var(--navy);color:var(--navy);font-weight:800;border-radius:10px;padding:12px 16px;font-size:13.5px;background:#fff;min-height:44px;cursor:pointer;font-family:inherit}\r\n.shop-resulthead{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:10px;margin-bottom:14px}\r\n#resultCount{font-size:14px;font-weight:700;color:var(--navy)}\r\n.per-wrap{display:flex;align-items:center;gap:8px;font-size:12.5px;font-weight:700;color:var(--navy)}\r\n.per-wrap select{border:1px solid var(--border);border-radius:8px;padding:7px 8px;font:inherit;color:var(--navy);background:#fff}\r\n.shop-main .bl-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}\r\n@media(min-width:700px){.shop-main .bl-grid{grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}}\r\n@media(min-width:1500px){.shop-main .bl-grid{grid-template-columns:repeat(4,minmax(0,1fr))}}\r\n.shop-main .bl-grid.list-view{grid-template-columns:1fr}\r\n\/* ===== Vehicle card \u2014 same card as shop (.product-card), with Enquire \/ Buy for Me ===== *\/\r\n.vcard{border:1px solid var(--border);border-radius:14px;padding:12px;display:flex;flex-direction:column;position:relative;background:#fff;min-width:0;transition:box-shadow .25s ease,transform .25s ease}\r\n.vcard:hover{box-shadow:0 10px 22px rgba(13,27,61,.1);transform:translateY(-2px)}\r\n.vcard-badge{position:absolute;top:8px;left:8px;z-index:2;background:var(--navy);color:#fff;font-size:9px;font-weight:800;padding:3px 7px;border-radius:8px}\r\n.vcard-top{display:flex;align-items:flex-start;justify-content:flex-end;margin-bottom:6px}\r\n.vcard-fav{width:22px;height:22px;display:flex;align-items:center;justify-content:center;background:none;border:0;padding:0;cursor:pointer}\r\n.vcard-link{display:block;color:inherit;text-decoration:none;min-width:0}\r\n.vcard-img{width:100%;aspect-ratio:1;border-radius:10px;overflow:hidden;background:#EEF0F3;margin-bottom:9px;display:flex;align-items:center;justify-content:center}\r\n.vcard-img img{width:100%;height:100%;object-fit:cover;display:block}\r\n.vcard-img i{font-size:30px;color:#C9D0DE}\r\n.vcard-name{font-size:12.5px;font-weight:700;line-height:1.32;height:33px;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;margin-bottom:6px;color:var(--navy)}\r\n.vcard-meta{display:flex;align-items:center;flex-wrap:wrap;gap:4px 10px;font-size:11px;color:#767E90;margin-bottom:6px}\r\n.vcard-meta span{display:flex;align-items:center;gap:3px;white-space:nowrap}\r\n.vcard-pricebox{margin-bottom:10px}\r\n.vcard-price{font-size:15px;font-weight:800;color:#1A1D29}\r\n.vcard-listed{font-size:9.5px;color:#6B7280;margin-top:2px}\r\n@media(min-width:900px){.vcard-price{font-size:18px}}\r\n.vcard-actions{display:flex;flex-direction:row;gap:6px;margin-top:auto}\r\n.vcard-btn{flex:1 1 0;min-width:0;min-height:36px;border-radius:3px;font-size:11px;font-weight:600;display:flex;align-items:center;justify-content:center;gap:4px;padding:8px 4px;overflow:hidden;text-decoration:none;cursor:pointer;font-family:inherit;transition:background .15s;white-space:nowrap}\r\n.vcard-btn.navy{background:var(--navy);color:#fff;border:1.5px solid var(--navy)}\r\n.vcard-btn.navy:hover{background:#16295A;border-color:#16295A}\r\n.vcard-btn.orange{background:var(--orange);color:#fff;border:1.5px solid var(--orange)}\r\n.vcard-btn.orange:hover{background:#d99500;border-color:#d99500}\r\n.vcard-btn svg{flex:none}\r\n@media(min-width:900px){.vcard-btn{font-size:12px;gap:6px;padding:8px 8px}}\r\n#listingGrid.list-view .vcard{flex-direction:row;align-items:stretch;gap:14px}\r\n#listingGrid.list-view .vcard-top{position:absolute;top:10px;right:10px;margin:0;z-index:2}\r\n#listingGrid.list-view .vcard-link{display:flex;gap:14px;flex:1;min-width:0}\r\n#listingGrid.list-view .vcard-img{width:240px;aspect-ratio:auto;min-height:150px;flex:none;margin-bottom:0}\r\n#listingGrid.list-view .vcard-info{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}\r\n#listingGrid.list-view .vcard-name{height:auto}\r\n#listingGrid.list-view .vcard-actions{flex:none;width:250px;align-self:center;margin-top:0}\r\n@media(max-width:600px){\r\n  #listingGrid.list-view .vcard{flex-wrap:wrap}\r\n  #listingGrid.list-view .vcard-img{width:130px;min-height:120px}\r\n  #listingGrid.list-view .vcard-actions{width:100%}\r\n}\r\n\/* ===== Enquire \/ Buy for Me modal \u2014 same as the vehicle page contact modal ===== *\/\r\n.vq-overlay{position:fixed;inset:0;background:rgba(9,15,32,.55);z-index:400;display:flex;align-items:center;justify-content:center;padding:20px;opacity:0;pointer-events:none;transition:opacity .25s ease}\r\n.vq-overlay.open{opacity:1;pointer-events:auto}\r\n.vq-sheet{width:100%;max-width:460px;background:#fff;border-radius:16px;max-height:90vh;overflow-y:auto;transform:translateY(20px) scale(.97);transition:transform .25s ease;color:#0D1B3E}\r\n.vq-overlay.open .vq-sheet{transform:none}\r\n.vq-head{display:flex;align-items:center;justify-content:space-between;padding:18px 20px;border-bottom:1px solid var(--border)}\r\n.vq-head h3{font-size:15.5px;font-weight:800;margin:0}\r\n.vq-close{width:28px;height:28px;border-radius:50%;background:#EEF0F3;display:flex;align-items:center;justify-content:center;border:0;cursor:pointer}\r\n.vq-body{padding:18px 20px;font-size:13px}\r\n.vq-summary{display:flex;gap:10px;align-items:center;background:#EEF0F3;border-radius:10px;padding:10px 12px;margin-bottom:16px}\r\n.vq-summary img{width:52px;height:52px;border-radius:8px;object-fit:cover;flex:none}\r\n.vq-summary .n{font-size:12.5px;font-weight:700}\r\n.vq-summary .p{font-size:11.5px;color:#6B7280;margin-top:2px}\r\n.vq-tabs{display:flex;gap:8px;margin-bottom:16px}\r\n.vq-tab{flex:1;padding:9px;border-radius:9px;background:#EEF0F3;font-size:12.5px;font-weight:700;color:#6B7280;border:1.5px solid transparent;cursor:pointer;font-family:inherit}\r\n.vq-tab.active{background:rgba(240,165,0,.12);border-color:#F0A500;color:#0D1B3E}\r\n.vq-field{margin-bottom:12px}\r\n.vq-field label{display:block;font-size:12px;font-weight:600;margin-bottom:6px}\r\n.vq-field input,.vq-field textarea{width:100%;border:1.5px solid var(--border);border-radius:10px;padding:11px 12px;font-size:13px;font-family:inherit;outline:none;box-sizing:border-box}\r\n.vq-field input:focus,.vq-field textarea:focus{border-color:#F0A500}\r\n.vq-field textarea{resize:vertical;min-height:120px;line-height:1.5}\r\n.vq-row2{display:flex;gap:10px}\r\n.vq-row2 .vq-field{flex:1;min-width:0}\r\n.vq-err{font-size:12px;color:#D64535;margin-bottom:10px;display:none}\r\n.vq-submit{width:100%;background:#F0A500;color:#091430;border-radius:11px;padding:14px;font-size:14px;font-weight:800;border:0;cursor:pointer;font-family:inherit}\r\n.vq-submit:disabled{opacity:.6;cursor:not-allowed}\r\n.vq-success{text-align:center;padding:30px 10px}\r\n.vq-success svg{width:44px;height:44px;color:#1F9D55;margin:0 auto 12px;display:block}\r\n.vq-success h4{font-size:15px;font-weight:800;margin:0 0 6px 0}\r\n.vq-success p{font-size:12.5px;color:#6B7280;margin:0}\r\n#listingGrid.busy{opacity:.55;pointer-events:none}\r\n.landing-sec{margin-bottom:22px}\r\n.landing-sec h3,.grid-title{font-size:17px;font-weight:800;color:var(--navy);margin:4px 0 10px}\r\n.vc-tiles{display:grid;gap:10px;grid-template-columns:repeat(2,minmax(0,1fr))}\r\n@media(min-width:760px){.vc-tiles{grid-template-columns:repeat(auto-fill,minmax(210px,1fr))}}\r\n.vc-tile{background:#fff;border:1.5px solid var(--border);border-radius:12px;padding:10px;display:grid;grid-template-columns:44px minmax(0,1fr);grid-template-areas:\"im nm\" \"im mt\";column-gap:10px;row-gap:2px;align-items:center;text-align:left;min-height:64px;min-width:0;color:#0D1B3E;cursor:pointer;font-family:inherit;transition:transform .12s ease,border-color .2s}\r\n.vc-tile:active{transform:scale(.98)}\r\n.vc-tile:hover{border-color:#F0A500}\r\n.vc-img{grid-area:im;display:flex;align-items:center;justify-content:center;width:44px;height:44px;border-radius:10px;background:linear-gradient(135deg,#e9edf3,#dfe5ee);overflow:hidden;color:#9AA4B8;font-size:20px}\r\n.vc-img img{width:100%;height:100%;object-fit:cover;display:block}\r\n.vc-nm{grid-area:nm;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:13px;font-weight:700;line-height:1.2;align-self:end}\r\n.vc-n{grid-area:mt;font-size:12px;font-weight:600;align-self:start}\r\n.pager{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:8px;margin:30px 0 6px}\r\n.pg{min-width:42px;height:42px;padding:0 12px;border:1.5px solid var(--border);background:#fff;border-radius:10px;font-size:14px;font-weight:800;color:#0D1B3E;display:inline-flex;align-items:center;justify-content:center;gap:6px;cursor:pointer;font-family:inherit}\r\n.pg svg{stroke:currentColor}\r\n.pg.cur{background:#0D1B3E;color:#fff;border-color:#0D1B3E}\r\n.pg[disabled]{background:#EEF0F3;cursor:not-allowed}\r\n.pg[disabled] svg{stroke:#B8BFCC}\r\n.pg-ell{min-width:24px;text-align:center;font-weight:800;color:#0D1B3E}\r\n.pg-info{flex-basis:100%;text-align:center;font-size:12.5px;font-weight:600;color:#0D1B3E;margin-top:4px}\r\n@media(max-width:480px){.pg{min-width:38px;height:40px;padding:0 8px}.pg .pg-lbl{display:none}}\r\n.empty-state{grid-column:1\/-1;text-align:center;padding:48px 16px;color:var(--navy);background:#fff;border:1px solid var(--border);border-radius:14px}\r\n.empty-state h3{font-size:17px;font-weight:800;margin-bottom:6px}\r\n.empty-state p{font-size:13.5px;margin-bottom:16px}\r\n<\/style>\r\n<\/head>\r\n<body data-auto-page=\"vehicles\">\r\n\r\n  <!-- ================= VEHICLE SECTION \u2014 rebuilt to match Builders24_Auto_Listing design, real data wired ================= -->\r\n  <div style=\"width:100%;background:#F7F8FA;color:#1A1D29;font-family:'Archivo Narrow',Helvetica,Arial,sans-serif;\" class=\"bl-root\">\r\n\r\n<section class=\"bl-hero\">\r\n  <div class=\"bl-hero-bg\"><div class=\"bl-hero-overlay\"><\/div><\/div>\r\n\r\n  <div class=\"bl-hero-inner\">\r\n    <h1>Builders24 Auto<br><span>Buy, Sell, Source, Import, New And Used Vehicles.<\/span><\/h1>\r\n    <p>Buy new and used cars, trucks, buses and commercial vehicles across Africa, sold by local dealers and sourced from Japan, China, the UK and other international markets. Builders24 Auto provides vehicle sourcing, inspection, import and delivery across Africa.<\/p>\r\n    <div class=\"bl-trust-row\">\r\n      <div class=\"bl-trust-chip\"><div class=\"bl-trust-icon\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#F5A623\" stroke-width=\"2\"><path d=\"M12 2l8 4v6c0 5-3.5 8-8 10-4.5-2-8-5-8-10V6z\"><\/path><\/svg><\/div><div><div class=\"bl-trust-title\">Verified Sellers<\/div><div class=\"bl-trust-sub\">100% Verified<\/div><\/div><\/div>\r\n      <div class=\"bl-trust-chip\"><div class=\"bl-trust-icon\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#F5A623\" stroke-width=\"2\"><rect x=\"1\" y=\"10\" width=\"15\" height=\"8\" rx=\"1\"><\/rect><path d=\"M16 12h4l2 3v3h-6z\"><\/path><circle cx=\"6\" cy=\"20\" r=\"1.6\"><\/circle><circle cx=\"17\" cy=\"20\" r=\"1.6\"><\/circle><\/svg><\/div><div><div class=\"bl-trust-title\">Quality Vehicles<\/div><div class=\"bl-trust-sub\">Inspected &amp; Reliable<\/div><\/div><\/div>\r\n      <div class=\"bl-trust-chip\"><div class=\"bl-trust-icon\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#F5A623\" stroke-width=\"2\"><path d=\"M12 2l8 4v6c0 5-3.5 8-8 10-4.5-2-8-5-8-10V6z\"><\/path><\/svg><\/div><div><div class=\"bl-trust-title\">Secure Deals<\/div><div class=\"bl-trust-sub\">Safe &amp; Transparent<\/div><\/div><\/div>\r\n      <div class=\"bl-trust-chip\"><div class=\"bl-trust-icon\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#F5A623\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M2 20l2-6h16l2 6\"><\/path><path d=\"M12 14V4\"><\/path><path d=\"M12 5l6 5h-6\"><\/path><path d=\"M2 20c2 1.5 4 1.5 6 0 2 1.5 4 1.5 6 0 2 1.5 4 1.5 6 0\"><\/path><\/svg><\/div><div><div class=\"bl-trust-title\">Managed Shipping<\/div><div class=\"bl-trust-sub\">Deliveries across Africa<\/div><\/div><\/div>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div class=\"bl-tabbar\" id=\"vehicleTabs\">\r\n    <div class=\"bl-tab bl-tab-active\" data-tab=\"buy\">Buy Vehicles<\/div>\r\n    <a class=\"bl-tab\" href=\"https:\/\/app.builders24.net\/auto\/sell-your-vehicle\">Sell Your Vehicle<\/a>\r\n    <div class=\"bl-tab\" data-tab=\"ship\">Ship Your Vehicle<\/div>\r\n  <\/div>\r\n<\/section>\r\n\r\n<div class=\"bl-filtercard\" id=\"buyFilterCard\">\r\n  <div class=\"bl-filter-grid\">\r\n    <div class=\"bl-filter-field\">\r\n      <span>Vehicle Type<\/span>\r\n      <select id=\"filterVehicleType\" class=\"bl-select\">\r\n        <option value=\"\">All Types<\/option>\r\n        <option value=\"heavy_truck\">Trucks<\/option>\r\n        <option value=\"bus\">Buses<\/option>\r\n        <option value=\"trailer\">Trailers<\/option>\r\n        <option value=\"mining_equipment\">Machinery<\/option>\r\n        <option value=\"bakkie_van\">Vans &amp; Pickups<\/option>\r\n      <\/select>\r\n    <\/div>\r\n    <div class=\"bl-filter-field\">\r\n      <span>Category<\/span>\r\n      <select id=\"filterCategory\" class=\"bl-select\">\r\n        <option value=\"\">All Categories<\/option>\r\n        <optgroup label=\"Transmission\">\r\n          <option value=\"transmission:automatic\">Automatic<\/option>\r\n          <option value=\"transmission:manual\">Manual<\/option>\r\n        <\/optgroup>\r\n        <optgroup label=\"Steering\">\r\n          <option value=\"steering:rhd\">RHD<\/option>\r\n          <option value=\"steering:lhd\">LHD<\/option>\r\n        <\/optgroup>\r\n        <optgroup label=\"Fuel Type\">\r\n          <option value=\"fuel_type:hybrid\">Hybrid<\/option>\r\n          <option value=\"fuel_type:electric\">Electric<\/option>\r\n          <option value=\"fuel_type:petrol\">Petrol<\/option>\r\n          <option value=\"fuel_type:diesel\">Diesel<\/option>\r\n        <\/optgroup>\r\n        <optgroup label=\"Condition\">\r\n          <option value=\"condition:new\">New<\/option>\r\n          <option value=\"condition:used\">Used<\/option>\r\n        <\/optgroup>\r\n      <\/select>\r\n    <\/div>\r\n    <div class=\"bl-filter-field\">\r\n      <span>Make<\/span>\r\n      <select id=\"filterMake\" class=\"bl-select\"><option value=\"\">All Makes<\/option><\/select>\r\n    <\/div>\r\n    <div class=\"bl-filter-field\">\r\n      <span>Location<\/span>\r\n      <input type=\"text\" id=\"filterLocation\" class=\"bl-select\" list=\"countryList\" placeholder=\"All Locations\">\r\n    <\/div>\r\n    <button class=\"bl-search-btn\" id=\"filterSearchBtn\">\r\n      <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"7\"><\/circle><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"><\/line><\/svg>\r\n      Search Vehicles\r\n    <\/button>\r\n  <\/div>\r\n  <div class=\"bl-filter-foot\">\r\n    <span class=\"bl-adv-link\" id=\"advSearch\" role=\"button\" tabindex=\"0\" style=\"cursor:pointer\"><svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"4\" y1=\"6\" x2=\"20\" y2=\"6\"><\/line><line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\"><\/line><line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"><\/line><\/svg>Advanced Search<\/span>\r\n    <span class=\"bl-adv-link\" id=\"clearFilters\">Clear all<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"10\"><\/circle><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"><\/line><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"><\/line><\/svg><\/span>\r\n  <\/div>\r\n<\/div>\r\n\r\n<!-- Inline vehicle-shipping quote \u2014 reads vehicle_transport (via its views),\r\n     same source as the vehicle page's shipping calculator. -->\r\n<div class=\"bl-filtercard\" id=\"shipFilterCard\" style=\"display:none;\">\r\n  <div class=\"bl-filter-grid\" id=\"shipFilterFields\" style=\"grid-template-columns:1fr 1fr 1fr 1fr;\"><\/div>\r\n  <button class=\"bl-search-btn\" id=\"shipQuoteBtn\" style=\"width:100%;margin-top:14px;justify-content:center;\">Get Instant Quote<\/button>\r\n  <div id=\"shipQuoteResult\" style=\"display:none;margin-top:14px;padding:14px;border-radius:9px;background:#F4F6FA;font-size:13px;color:#0D1B3E;\"><\/div>\r\n<\/div>\r\n\r\n<main class=\"bl-main\" id=\"buyMain\">\r\n  <div class=\"shop-toolbar\">\r\n    <div class=\"shop-search\">\r\n      <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#0D1B3E\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\"><circle cx=\"11\" cy=\"11\" r=\"7\"\/><path d=\"M21 21l-4.3-4.3\"\/><\/svg>\r\n      <input type=\"search\" id=\"sSearch\" placeholder=\"Search make, model, year or stock number\" autocomplete=\"off\" aria-label=\"Search vehicles\">\r\n      <button type=\"button\" class=\"s-clear\" id=\"sClear\" aria-label=\"Clear search\">&times;<\/button>\r\n    <\/div>\r\n    <button type=\"button\" class=\"shop-ctl shop-filters-btn\" id=\"openFilters\" aria-haspopup=\"dialog\">\r\n      <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#0D1B3E\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M4 6h16M7 12h10M10 18h4\"\/><\/svg>\r\n      Filters <span class=\"fcount\" id=\"fCount\"><\/span>\r\n    <\/button>\r\n    <label class=\"shop-ctl shop-sort\" for=\"sSort\"><span>Sort by<\/span><select id=\"sSort\"><\/select><\/label>\r\n    <div class=\"shop-viewtoggle\" role=\"group\" aria-label=\"Vehicle view\">\r\n      <button type=\"button\" id=\"vGrid\" class=\"on\" aria-pressed=\"true\" aria-label=\"Default view\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke-width=\"2\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\"\/><rect x=\"14\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\"\/><rect x=\"3\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\"\/><rect x=\"14\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\"\/><\/svg><\/button>\r\n      <button type=\"button\" id=\"vList\" aria-pressed=\"false\" aria-label=\"List view\"><svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01\"\/><\/svg><\/button>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div class=\"dept-row\" id=\"deptRow\" aria-label=\"Quick filters\"><\/div>\r\n  <div class=\"active-bar\" id=\"activeBar\"><\/div>\r\n\r\n  <div class=\"shop-body\">\r\n    <div class=\"sheet-overlay\" id=\"sheetOverlay\"><\/div>\r\n    <aside class=\"shop-side\" id=\"shopSide\" aria-label=\"Filters\">\r\n      <div class=\"side-head\"><span>Filters<\/span><button type=\"button\" class=\"close\" id=\"sideClose\" aria-label=\"Close filters\">&times;<\/button><\/div>\r\n      <div class=\"side-scroll\">\r\n        <details class=\"fs\" open id=\"fsCat\"><summary>Categories<\/summary>\r\n          <input type=\"search\" id=\"catSearch\" class=\"fs-input\" placeholder=\"Find a category\" aria-label=\"Find a category\" autocomplete=\"off\">\r\n          <div id=\"catTree\"><\/div>\r\n        <\/details>\r\n        <details class=\"fs\" open id=\"fsPrice\"><summary>Price \/ Budget <span id=\"priceCur\"><\/span><\/summary>\r\n          <div class=\"price-inputs\">\r\n            <div><label for=\"pMin\">Min<\/label><input type=\"number\" id=\"pMin\" inputmode=\"decimal\" min=\"0\" placeholder=\"0\"><\/div>\r\n            <div><label for=\"pMax\">Max<\/label><input type=\"number\" id=\"pMax\" inputmode=\"decimal\" min=\"0\" placeholder=\"Any\"><\/div>\r\n            <button type=\"button\" class=\"btn-go\" id=\"pGo\">Go<\/button>\r\n          <\/div>\r\n          <div class=\"budget-chips\" id=\"priceChips\"><\/div>\r\n        <\/details>\r\n        <details class=\"fs\" open id=\"fsMake\" hidden><summary>Make<\/summary>\r\n          <input type=\"search\" id=\"makeSearch\" class=\"fs-input\" placeholder=\"Find a make\" aria-label=\"Find a make\" autocomplete=\"off\">\r\n          <div id=\"makeList\"><\/div>\r\n        <\/details>\r\n        <details class=\"fs\" open id=\"fsShip\" hidden><summary>Shipped from<\/summary><div id=\"shipList\"><\/div><\/details>\r\n        <details class=\"fs\" open id=\"fsYear\" hidden><summary>Year<\/summary>\r\n          <div class=\"price-inputs\" style=\"grid-template-columns:minmax(0,1fr) minmax(0,1fr)\">\r\n            <div><label for=\"yMin\">From<\/label><select id=\"yMin\"><\/select><\/div>\r\n            <div><label for=\"yMax\">To<\/label><select id=\"yMax\"><\/select><\/div>\r\n          <\/div>\r\n        <\/details>\r\n        <details class=\"fs\" open id=\"fsKm\" hidden><summary>Mileage<\/summary>\r\n          <div class=\"price-inputs\" style=\"grid-template-columns:minmax(0,1fr)\">\r\n            <div><label for=\"kmMax\">Up to (km)<\/label><input type=\"number\" id=\"kmMax\" inputmode=\"numeric\" min=\"0\" step=\"1000\" placeholder=\"Any\"><\/div>\r\n          <\/div>\r\n          <div class=\"budget-chips\" id=\"kmChips\"><\/div>\r\n        <\/details>\r\n        <details class=\"fs\" open id=\"fsCond\" hidden><summary>Condition<\/summary><div id=\"condList\"><\/div><\/details>\r\n        <details class=\"fs\" open id=\"fsFuel\" hidden><summary>Fuel type<\/summary><div id=\"fuelList\"><\/div><\/details>\r\n        <details class=\"fs\" open id=\"fsTrans\" hidden><summary>Transmission<\/summary><div id=\"transList\"><\/div><\/details>\r\n        <details class=\"fs\" open id=\"fsSteer\" hidden><summary>Steering<\/summary><div id=\"steerList\"><\/div><\/details>\r\n        <details class=\"fs\" id=\"fsLoc\"><summary>Vehicle location<\/summary>\r\n          <input type=\"search\" id=\"locInput\" class=\"fs-input\" placeholder=\"City or country\" aria-label=\"Vehicle location\" autocomplete=\"off\">\r\n        <\/details>\r\n      <\/div>\r\n      <div class=\"side-foot\">\r\n        <button type=\"button\" class=\"btn-ghost\" id=\"sideClear\">Clear all<\/button>\r\n        <button type=\"button\" class=\"btn-primary\" id=\"sideShow\">Show results<\/button>\r\n      <\/div>\r\n    <\/aside>\r\n\r\n    <section class=\"shop-main\" aria-label=\"Vehicles\">\r\n      <div class=\"shop-resulthead\">\r\n        <div id=\"resultCount\" aria-live=\"polite\">Loading&hellip;<\/div>\r\n        <label class=\"per-wrap\" for=\"sPer\">Show <select id=\"sPer\"><\/select> per page<\/label>\r\n      <\/div>\r\n      <div id=\"landing\"><\/div>\r\n      <h3 class=\"grid-title\" id=\"gridTitle\" hidden>All vehicles<\/h3>\r\n      <div class=\"bl-grid\" id=\"listingGrid\" aria-busy=\"true\"><div class=\"empty-state\"><p>Loading vehicles&hellip;<\/p><\/div><\/div>\r\n      <nav class=\"pager\" id=\"pager\" aria-label=\"Pagination\"><\/nav>\r\n    <\/section>\r\n  <\/div>\r\n<\/main>\r\n\r\n<\/div>\r\n\r\n\r\n\r\n<!-- ======== ENQUIRE \/ BUY FOR ME MODAL (same flow as the vehicle page) ======== -->\r\n<div class=\"vq-overlay\" id=\"vqOverlay\" data-mode=\"seller\" aria-hidden=\"true\">\r\n  <div class=\"vq-sheet\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"vqTitle\">\r\n    <div class=\"vq-head\">\r\n      <h3 id=\"vqTitle\">Enquire if still available<\/h3>\r\n      <button class=\"vq-close\" id=\"vqClose\" aria-label=\"Close\" type=\"button\"><svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#0D1220\" stroke-width=\"2.4\" stroke-linecap=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"\/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"\/><\/svg><\/button>\r\n    <\/div>\r\n    <div class=\"vq-body\" id=\"vqBody\">\r\n      <div class=\"vq-summary\"><img id=\"vqImg\" alt=\"\" hidden><div><div class=\"n\" id=\"vqName\"><\/div><div class=\"p\" id=\"vqPrice\"><\/div><\/div><\/div>\r\n      <div id=\"vqLoggedIn\" style=\"display:none\">\r\n        <div class=\"vq-field\"><label id=\"vqMsgLabel\">Your message<\/label><textarea id=\"vqMessage\"><\/textarea><\/div>\r\n        <div class=\"vq-err\" id=\"vqLoggedInErr\"><\/div>\r\n        <button class=\"vq-submit\" id=\"vqSend\" type=\"button\">Send Message<\/button>\r\n      <\/div>\r\n      <div id=\"vqGuest\">\r\n        <div class=\"vq-tabs\"><button class=\"vq-tab active\" id=\"vqTabLogin\" type=\"button\">Log In<\/button><button class=\"vq-tab\" id=\"vqTabReg\" type=\"button\">Create Account<\/button><\/div>\r\n        <div id=\"vqLoginForm\">\r\n          <div class=\"vq-field\"><label>Email<\/label><input type=\"text\" id=\"vqLiEmail\" placeholder=\"you@example.com\" autocomplete=\"email\"><\/div>\r\n          <div class=\"vq-field\"><label>Password<\/label><input type=\"password\" id=\"vqLiPass\" placeholder=\"Your password\" autocomplete=\"current-password\"><\/div>\r\n          <div class=\"vq-err\" id=\"vqLoginErr\"><\/div>\r\n          <button class=\"vq-submit\" id=\"vqLoginBtn\" type=\"button\">Log In &amp; Continue<\/button>\r\n        <\/div>\r\n        <div id=\"vqRegForm\" style=\"display:none\">\r\n          <div class=\"vq-row2\"><div class=\"vq-field\"><label>First Name<\/label><input type=\"text\" id=\"vqRgF\"><\/div><div class=\"vq-field\"><label>Last Name<\/label><input type=\"text\" id=\"vqRgL\"><\/div><\/div>\r\n          <div class=\"vq-field\"><label>Email<\/label><input type=\"text\" id=\"vqRgEmail\" placeholder=\"you@example.com\" autocomplete=\"email\"><\/div>\r\n          <div class=\"vq-field\"><label>Phone<\/label><input type=\"text\" id=\"vqRgPhone\"><\/div>\r\n          <div class=\"vq-field\"><label>City<\/label><input type=\"text\" id=\"vqRgCity\"><\/div>\r\n          <div class=\"vq-field\"><label>Password<\/label><input type=\"password\" id=\"vqRgPass\" placeholder=\"At least 8 characters\" autocomplete=\"new-password\"><\/div>\r\n          <div class=\"vq-err\" id=\"vqRegErr\"><\/div>\r\n          <button class=\"vq-submit\" id=\"vqRegBtn\" type=\"button\">Create Account &amp; Continue<\/button>\r\n        <\/div>\r\n      <\/div>\r\n      <div id=\"vqSuccess\" style=\"display:none\"><div class=\"vq-success\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"\/><\/svg><h4 id=\"vqOkTitle\">Message Sent<\/h4><p id=\"vqOkBody\">The seller will be in touch shortly.<\/p><\/div><\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@supabase\/supabase-js@2\"><\/script>\r\n<script src=\"https:\/\/app.builders24.net\/guest-cart.js\"><\/script>\r\n<script src=\"https:\/\/app.builders24.net\/b24app.js\"><\/script>\r\n<script>\r\n  function esc(s){ return (s||'').toString().replace(\/[&<>\"']\/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c])); }\r\n\r\n  const TYPE_META = {\r\n    heavy_truck: { label: 'Trucks' },\r\n    bus: { label: 'Buses' },\r\n    trailer: { label: 'Trailers' },\r\n    mining_equipment: { label: 'Machinery' },\r\n    bakkie_van: { label: 'Vans & Pickups' },\r\n    farm_equipment: { label: 'Farm Equipment' }\r\n  };\r\n\r\n\r\n  \/\/ Real flag rendering via Unicode regional-indicator emoji \u2014 no image\r\n  \/\/ assets needed. Covers the countries actually seen in location_country\r\n  \/\/ (Japan, UK) plus the wider source-country\/African-market set used\r\n  \/\/ elsewhere on this page (MAJOR_COUNTRIES-equivalent). Unmapped names\r\n  \/\/ fall back to a globe glyph rather than guessing a code.\r\n  const COUNTRY_TO_ISO2 = {\r\n    'japan':'JP','uk':'GB','united kingdom':'GB','china':'CN','germany':'DE',\r\n    'united states':'US','usa':'US','uae':'AE','united arab emirates':'AE',\r\n    'india':'IN','turkey':'TR','brazil':'BR','south africa':'ZA','nigeria':'NG',\r\n    'kenya':'KE','ghana':'GH','zimbabwe':'ZW','zambia':'ZM','tanzania':'TZ',\r\n    'uganda':'UG','mozambique':'MZ','angola':'AO','botswana':'BW','namibia':'NA',\r\n    'drc':'CD','democratic republic of congo':'CD','ethiopia':'ET',\r\n    'saudi arabia':'SA','oman':'OM'\r\n  };\r\n  const COUNTRY_ABBREV = {\r\n    'japan':'JP','uk':'UK','united kingdom':'UK','china':'CN','germany':'DE',\r\n    'united states':'US','usa':'US','uae':'UAE','united arab emirates':'UAE',\r\n    'india':'IN','turkey':'TR','brazil':'BR','south africa':'SA','nigeria':'NG',\r\n    'kenya':'KE','ghana':'GH','zimbabwe':'ZW','zambia':'ZM','tanzania':'TZ',\r\n    'uganda':'UG','mozambique':'MZ','angola':'AO','botswana':'BW','namibia':'NA',\r\n    'drc':'DRC','democratic republic of congo':'DRC','ethiopia':'ET',\r\n    'saudi arabia':'SA','oman':'OM'\r\n  };\r\n  function countryFlagEmoji(name) {\r\n    const iso2 = COUNTRY_TO_ISO2[(name || '').trim().toLowerCase()];\r\n    if (!iso2) return '\ud83c\udf0d';\r\n    return String.fromCodePoint(...[...iso2].map(c => 127397 + c.charCodeAt(0)));\r\n  }\r\n  function countryAbbrev(name) {\r\n    return COUNTRY_ABBREV[(name || '').trim().toLowerCase()] || (name || '');\r\n  }\r\n\r\n  function slugifyVehicle(name) {\r\n    return (name || 'vehicle').toString().toLowerCase().trim()\r\n      .replace(\/[^a-z0-9]+\/g, '-').replace(\/^-+|-+$\/g, '').slice(0, 60);\r\n  }\r\n\r\n  async function handleVehicleBuyNow(vehicleId, btn) {\r\n    btn.disabled = true;\r\n    const original = btn.textContent;\r\n    btn.textContent = 'Adding...';\r\n    try {\r\n      await addToGuestCart(vehicleId, 1, 'vehicle');\r\n      location.href = 'https:\/\/app.builders24.net\/retail\/cart.html';\r\n    } catch (e) {\r\n      btn.disabled = false;\r\n      btn.textContent = original;\r\n      alert('Could not add this vehicle to your cart. Please try again.');\r\n    }\r\n  }\r\n\r\n  function toggleFav(id, el) {\r\n    _favs[id] = !_favs[id];\r\n    const svg = el.querySelector('svg');\r\n    svg.setAttribute('fill', _favs[id] ? '#2B5FBF' : 'none');\r\n  }\r\n  window.toggleFav = toggleFav;\r\n  window.handleVehicleBuyNow = handleVehicleBuyNow;\r\n  \/\/ header.js's shared currency\/location modal calls window.renderPrices()\r\n  \/\/ after the customer changes currency or delivery location \u2014 without\r\n  \/\/ this, vehicle prices never refreshed to match (they already convert\r\n  \/\/ live via fmtConverted() inside renderListings(), so re-running it is\r\n  \/\/ all that's needed).\r\n\r\n  \/\/ ===================== Shop-style listing: live data, client-side facets, sort, pages =====================\r\n  const S = { q:'', cat:'', makes:new Set(), ship:new Set(), cond:new Set(), fuel:new Set(), trans:new Set(), steer:new Set(), minP:null, maxP:null, minY:'', maxY:'', maxKm:null, loc:'', sort:'newest', view:'default', per:24, page:1 };\r\n  const SORTS = { newest:'Latest uploads', oldest:'Oldest uploads', year_desc:'Year: newest first', year_asc:'Year: oldest first', price_asc:'Price: low to high', price_desc:'Price: high to low', km_asc:'Mileage: low to high' };\r\n  const PER_OPTIONS = [24, 48, 96];\r\n  const SHIP_LABEL = { japan:'Japanese cars', china:'Chinese cars' };\r\n  const byId = id => document.getElementById(id);\r\n  let ALL = [], VC = { cats:[], byId:{}, kids:{} }, _loaded = false, _dataP = null, _seq = 0;\r\n  const expanded = new Set();\r\n  const shipOf = l => (l.shipped_from || l.location_country || '').trim();\r\n  const shipLabel = c => SHIP_LABEL[String(c).toLowerCase()] || ('Shipped from ' + c);\r\n  const cap = x => String(x).replace(\/(^|[ _-])(\\w)\/g, (m, a, b) => (a ? ' ' : '') + b.toUpperCase());\r\n  const transLabel = v => v.length <= 3 ? v.toUpperCase() : cap(v);\r\n  const fmtN = n => Number(n).toLocaleString('en');\r\n  const debounce = (fn, ms) => { let t; return (...a) => { clearTimeout(t); t = setTimeout(() => fn(...a), ms); }; };\r\n  const numOrNull = v => { v = String(v).trim(); if (v === '') return null; const n = Number(v); return isFinite(n) && n >= 0 ? n : null; };\r\n  function toCur(amount, from){\r\n    const to = appState.currency;\r\n    if (!amount || from === to || typeof _ratesToUsd !== 'object' || !_ratesToUsd[from] || !_ratesToUsd[to]) return Number(amount) || 0;\r\n    return Number(amount) \/ _ratesToUsd[from] * _ratesToUsd[to];\r\n  }\r\n  function catPath(id){ const p = []; let c = VC.byId[id], g = 0; while (c && g++ < 10) { p.unshift(c.id); c = c.parent_id ? VC.byId[c.parent_id] : null; } return p; }\r\n  function prep(l){\r\n    const vm = l.vehicle_models || {}, mk = vm.vehicle_makes || {};\r\n    l._make = (mk.name || l.raw_make || '').trim(); l._mk = l._make.toLowerCase();\r\n    l._title = (`${mk.name || ''} ${vm.name || ''}`.trim()) || (`${l.raw_make || ''} ${l.raw_model || ''}`.trim()) || 'Vehicle';\r\n    l._ship = shipOf(l); l._cats = catPath(vm.category_id);\r\n    l._t = new Date(l.created_at).getTime() || 0;\r\n    l._q = [l._title, l.raw_make, l.raw_model, l.year, l.trim, l.color, l.fuel_type, l.transmission, l.b24_sku, l.source_sku, l.chassis_code, l.location_country, l.location_city].filter(Boolean).join(' ').toLowerCase();\r\n    l._px = toCur(l.price, l.currency);\r\n  }\r\n\r\n  \/\/ ---- filtering (one function; `skip` leaves a facet out so its own counts stay useful) ----\r\n  let _topMakeName = '';\r\n  function matches(l, skip){\r\n    const f = getActiveFilters();\r\n    if (f.vehicleType && l.vehicle_models?.vehicle_makes?.vehicle_type !== f.vehicleType) return false;\r\n    if (f.category) { const [cf, cv] = f.category.split(':'); if ((l[cf] || '').toLowerCase() !== cv) return false; }\r\n    if (f.make && !((l.vehicle_models?.vehicle_makes?.name || '').toLowerCase().includes(_topMakeName))) return false;\r\n    if (f.location && l.location_country !== f.location) return false;\r\n    if (skip !== 'q' && S.q) { for (const t of S.q.toLowerCase().split(\/\\s+\/).filter(Boolean)) if (!l._q.includes(t)) return false; }\r\n    if (skip !== 'cat' && S.cat && !l._cats.includes(S.cat)) return false;\r\n    if (skip !== 'make' && S.makes.size && !S.makes.has(l._mk)) return false;\r\n    if (skip !== 'ship' && S.ship.size && !S.ship.has(l._ship)) return false;\r\n    if (skip !== 'cond' && S.cond.size && !S.cond.has((l.condition || '').toLowerCase())) return false;\r\n    if (skip !== 'fuel' && S.fuel.size && !S.fuel.has((l.fuel_type || '').toLowerCase())) return false;\r\n    if (skip !== 'trans' && S.trans.size && !S.trans.has((l.transmission || '').toLowerCase())) return false;\r\n    if (skip !== 'steer' && S.steer.size && !S.steer.has((l.steering || '').toLowerCase())) return false;\r\n    if (skip !== 'price' && (S.minP != null || S.maxP != null)) { if (!(l._px > 0)) return false; if (S.minP != null && l._px < S.minP) return false; if (S.maxP != null && l._px > S.maxP) return false; }\r\n    if (skip !== 'year') { if (S.minY && !(l.year >= Number(S.minY))) return false; if (S.maxY && !(l.year <= Number(S.maxY))) return false; }\r\n    if (skip !== 'km' && S.maxKm != null && !(l.mileage_km != null && l.mileage_km <= S.maxKm)) return false;\r\n    if (skip !== 'loc' && S.loc) { const t = S.loc.toLowerCase(); if (!((l.location_country || '').toLowerCase().includes(t) || (l.location_city || '').toLowerCase().includes(t))) return false; }\r\n    return true;\r\n  }\r\n  function getActiveFilters() {\r\n    return {\r\n      vehicleType: byId('filterVehicleType').value,\r\n      category: byId('filterCategory').value,\r\n      make: byId('filterMake').value,\r\n      location: byId('filterLocation').value\r\n    };\r\n  }\r\n  function applyVehicleFilters(list){\r\n    const f = getActiveFilters();\r\n    _topMakeName = f.make ? (document.querySelector(`#filterMake option[value=\"${f.make}\"]`)?.textContent || '').toLowerCase() : '';\r\n    return list.filter(l => matches(l));\r\n  }\r\n  function sortList(list){\r\n    const out = list.slice(), num = (v, d) => (v == null ? d : Number(v)), px = l => (l._px > 0 ? l._px : null);\r\n    switch (S.sort) {\r\n      case 'oldest': out.sort((a, b) => a._t - b._t); break;\r\n      case 'year_desc': out.sort((a, b) => num(b.year, -1) - num(a.year, -1) || b._t - a._t); break;\r\n      case 'year_asc': out.sort((a, b) => num(a.year, 9999) - num(b.year, 9999) || b._t - a._t); break;\r\n      case 'price_asc': out.sort((a, b) => num(px(a), 1e15) - num(px(b), 1e15) || b._t - a._t); break;\r\n      case 'price_desc': out.sort((a, b) => num(px(b), -1) - num(px(a), -1) || b._t - a._t); break;\r\n      case 'km_asc': out.sort((a, b) => num(a.mileage_km, 1e12) - num(b.mileage_km, 1e12) || b._t - a._t); break;\r\n      default: out.sort((a, b) => b._t - a._t);\r\n    }\r\n    return out;\r\n  }\r\n\r\n  \/\/ ---- data ----\r\n  function ensureData(){\r\n    if (_dataP) return _dataP;\r\n    _dataP = (async () => {\r\n      const cats = await (async () => { const { data } = await sb.from('vehicle_categories').select('id,parent_id,name,slug,sort_order').eq('is_active', true).order('sort_order').range(0, 999); return data || []; })();\r\n      VC.cats = cats; VC.byId = {}; VC.kids = {};\r\n      cats.forEach(c => { VC.byId[c.id] = c; });\r\n      cats.forEach(c => { const k = c.parent_id && VC.byId[c.parent_id] ? c.parent_id : '__root'; (VC.kids[k] = VC.kids[k] || []).push(c); });\r\n      let rows = [];\r\n      for (let from = 0; ; from += 1000) {\r\n        const r = await sb.from('vehicle_listings')\r\n          .select('*, vehicle_models(name, body_type, category_id, vehicle_makes(name, vehicle_type))')\r\n          .eq('is_published', true).eq('status', 'available')\r\n          .order('created_at', { ascending: false }).order('id').range(from, from + 999);\r\n        if (r.error) throw r.error;\r\n        rows = rows.concat(r.data || []);\r\n        if (!r.data || r.data.length < 1000) break;\r\n      }\r\n      ALL = rows; ALL.forEach(prep);\r\n    })();\r\n    _dataP.catch(() => { _dataP = null; });\r\n    return _dataP;\r\n  }\r\n  async function loadListings(){\r\n    try { await ensureData(); }\r\n    catch (e) {\r\n      console.error('[vehicles] load failed:', e);\r\n      byId('listingGrid').innerHTML = '<div class=\"empty-state\"><h3>Couldn\\'t load vehicles<\/h3><p>Please check your connection and try again.<\/p><button type=\"button\" class=\"btn-primary\" id=\"emptyRetry\">Try again<\/button><\/div>';\r\n      byId('listingGrid').removeAttribute('aria-busy');\r\n      return;\r\n    }\r\n    if (S._pendingShip) { ALL.forEach(l => { if (l._ship.toLowerCase() === S._pendingShip) S.ship.add(l._ship); }); S._pendingShip = null; }\r\n    _loaded = true; S.page = 1; render();\r\n  }\r\n\r\n  \/\/ ---- facet renderers ----\r\n  function facet(skip, keyFn, labelFn){\r\n    const m = new Map();\r\n    ALL.forEach(l => { if (!matches(l, skip)) return; const k = keyFn(l); if (!k) return; const e = m.get(k) || { label: labelFn(l), n: 0 }; e.n++; m.set(k, e); });\r\n    return m;\r\n  }\r\n  function optList(id, secId, skip, set, keyFn, labelFn, limit){\r\n    const m = facet(skip, keyFn, labelFn);\r\n    set.forEach(k => { if (!m.has(k)) m.set(k, { label: labelFn({ _make:k, _ship:k }) || k, n: 0 }); });\r\n    const entries = [...m.entries()].sort((a, b) => b[1].n - a[1].n || String(a[1].label).localeCompare(String(b[1].label)));\r\n    byId(secId).hidden = !entries.length;\r\n    const showAll = optList._all[id];\r\n    const shown = limit && !showAll ? entries.filter((e, i) => i < limit || set.has(e[0])) : entries;\r\n    byId(id).innerHTML = shown.map(([k, e]) => `<label class=\"opt\"><input type=\"checkbox\" data-set=\"${skip}\" value=\"${esc(k)}\" ${set.has(k) ? 'checked' : ''}><span class=\"lbl\">${esc(e.label)}<\/span><span class=\"cat-count\">${fmtN(e.n)}<\/span><\/label>`).join('')\r\n      + (limit && entries.length > limit ? `<button type=\"button\" class=\"fs-more\" data-more=\"${id}\">${showAll ? 'Show less' : 'Show all ' + entries.length}<\/button>` : '');\r\n  }\r\n  optList._all = {};\r\n  function niceNum(n){ if (n <= 0) return 0; const p = Math.pow(10, Math.floor(Math.log10(n))); const step = p >= 1000 ? p \/ 2 : p; return Math.round(n \/ step) * step; }\r\n  function budgetBands(){\r\n    const px = ALL.map(l => l._px).filter(v => v > 0).sort((a, b) => a - b);\r\n    if (px.length < 8) return [];\r\n    const q = f => niceNum(px[Math.floor((px.length - 1) * f)]);\r\n    const cuts = [...new Set([q(.25), q(.5), q(.75)])].filter(v => v > 0);\r\n    if (!cuts.length) return [];\r\n    const out = [{ label: 'Under ' + fmtN(cuts[0]), min: null, max: cuts[0] }];\r\n    for (let i = 1; i < cuts.length; i++) out.push({ label: fmtN(cuts[i - 1]) + ' \u2013 ' + fmtN(cuts[i]), min: cuts[i - 1], max: cuts[i] });\r\n    out.push({ label: fmtN(cuts[cuts.length - 1]) + '+', min: cuts[cuts.length - 1], max: null });\r\n    return out;\r\n  }\r\n  function renderPrice(){\r\n    byId('priceCur').textContent = '(' + (appState.currency || 'USD') + ')';\r\n    byId('pMin').value = S.minP == null ? '' : S.minP; byId('pMax').value = S.maxP == null ? '' : S.maxP;\r\n    byId('priceChips').innerHTML = budgetBands().map((b, i) => `<button type=\"button\" class=\"chip${S.minP === b.min && S.maxP === b.max ? ' on' : ''}\" data-band=\"${i}\">${esc(b.label)}<\/button>`).join('');\r\n  }\r\n  function renderYear(){\r\n    const ys = ALL.map(l => l.year).filter(Boolean); byId('fsYear').hidden = !ys.length; if (!ys.length) return;\r\n    const lo = Math.min(...ys), hi = Math.max(...ys); let o = ''; for (let y = hi; y >= lo; y--) o += `<option value=\"${y}\">${y}<\/option>`;\r\n    byId('yMin').innerHTML = '<option value=\"\">Any<\/option>' + o; byId('yMax').innerHTML = '<option value=\"\">Any<\/option>' + o;\r\n    byId('yMin').value = S.minY; byId('yMax').value = S.maxY;\r\n  }\r\n  function renderKm(){\r\n    byId('fsKm').hidden = !ALL.some(l => l.mileage_km != null);\r\n    byId('kmMax').value = S.maxKm == null ? '' : S.maxKm;\r\n    byId('kmChips').innerHTML = [10000, 50000, 100000, 150000].map(v => `<button type=\"button\" class=\"chip${S.maxKm === v ? ' on' : ''}\" data-km=\"${v}\">Up to ${fmtN(v)} km<\/button>`).join('');\r\n  }\r\n  function categoryCounts(){ const c = {}; ALL.forEach(l => { if (matches(l, 'cat')) l._cats.forEach(id => { c[id] = (c[id] || 0) + 1; }); }); return c; }\r\n  const ARROW_R = '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 18l6-6-6-6\"\/><\/svg>';\r\n  const ARROW_L = '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 18l-6-6 6-6\"\/><\/svg>';\r\n  function catNode(c, term, counts){\r\n    const kids = (VC.kids[c.id] || []);\r\n    const kidHtml = kids.map(k => catNode(k, term, counts)).join('');\r\n    const self = (counts[c.id] || 0) > 0 || S.cat === c.id;\r\n    const nameHit = !term || c.name.toLowerCase().includes(term);\r\n    if (!self && !kidHtml) return '';\r\n    if (term && !nameHit && !kidHtml) return '';\r\n    const open = term ? !!kidHtml : expanded.has(c.id) || catPath(S.cat).includes(c.id) && S.cat !== c.id;\r\n    return `<div class=\"cat-node\"><div class=\"cat-line\"><button type=\"button\" class=\"cat-tog${kidHtml ? '' : ' none'}${open ? ' open' : ''}\" data-tog=\"${c.id}\" aria-label=\"Expand ${esc(c.name)}\">${ARROW_R}<\/button><button type=\"button\" class=\"cat-row${S.cat === c.id ? ' sel' : ''}\" data-cat=\"${c.id}\"><span>${esc(c.name)}<\/span><span class=\"cat-count\">${fmtN(counts[c.id] || 0)}<\/span><\/button><\/div>${kidHtml && open ? `<div class=\"cat-kids\">${kidHtml}<\/div>` : ''}<\/div>`;\r\n  }\r\n  function renderCategories(counts){\r\n    const term = byId('catSearch').value.trim().toLowerCase();\r\n    const html = (VC.kids['__root'] || []).map(c => catNode(c, term, counts)).join('');\r\n    byId('catTree').innerHTML = html || '<p style=\"font-size:13px;color:#0D1B3E;padding:6px 4px;\">No categories match.<\/p>';\r\n  }\r\n  function renderQuick(){\r\n    const m = facet('ship', l => l._ship, l => l._ship);\r\n    const total = ALL.filter(l => matches(l, 'ship')).length;\r\n    byId('deptRow').innerHTML = `<button type=\"button\" class=\"chip${!S.ship.size ? ' on' : ''}\" data-q=\"\">All<span class=\"n\">${fmtN(total)}<\/span><\/button>` +\r\n      [...m.entries()].sort((a, b) => b[1].n - a[1].n).map(([k, e]) => `<button type=\"button\" class=\"chip${S.ship.has(k) ? ' on' : ''}\" data-q=\"${esc(k)}\">${esc(shipLabel(k))}<span class=\"n\">${fmtN(e.n)}<\/span><\/button>`).join('');\r\n  }\r\n  function activeList(){\r\n    const out = [], add = (label, off) => out.push({ label, off });\r\n    if (S.q) add('Search: ' + S.q, () => { S.q = ''; byId('sSearch').value = ''; });\r\n    if (S.cat) add(catPath(S.cat).map(id => VC.byId[id]?.name).filter(Boolean).join(' \u203a '), () => { S.cat = ''; });\r\n    S.makes.forEach(k => add('Make: ' + (ALL.find(l => l._mk === k)?._make || k), () => S.makes.delete(k)));\r\n    S.ship.forEach(k => add(shipLabel(k), () => S.ship.delete(k)));\r\n    S.cond.forEach(k => add(cap(k), () => S.cond.delete(k)));\r\n    S.fuel.forEach(k => add(cap(k), () => S.fuel.delete(k)));\r\n    S.trans.forEach(k => add(transLabel(k), () => S.trans.delete(k)));\r\n    S.steer.forEach(k => add(k.toUpperCase(), () => S.steer.delete(k)));\r\n    if (S.minP != null || S.maxP != null) add('Price: ' + (S.minP != null ? fmtN(S.minP) : '0') + ' \u2013 ' + (S.maxP != null ? fmtN(S.maxP) : 'any') + ' ' + appState.currency, () => { S.minP = S.maxP = null; });\r\n    if (S.minY || S.maxY) add('Year: ' + (S.minY || 'any') + ' \u2013 ' + (S.maxY || 'any'), () => { S.minY = S.maxY = ''; });\r\n    if (S.maxKm != null) add('Up to ' + fmtN(S.maxKm) + ' km', () => { S.maxKm = null; });\r\n    if (S.loc) add('Location: ' + S.loc, () => { S.loc = ''; byId('locInput').value = ''; });\r\n    return out;\r\n  }\r\n  let _chips = [];\r\n  function renderActive(){\r\n    _chips = activeList();\r\n    byId('activeBar').innerHTML = _chips.map((c, i) => `<span class=\"af-chip\">${esc(c.label)}<button type=\"button\" data-af=\"${i}\" aria-label=\"Remove ${esc(c.label)}\">&times;<\/button><\/span>`).join('') + (_chips.length > 1 ? '<button type=\"button\" class=\"af-clear\" id=\"afClear\">Clear all<\/button>' : '');\r\n    byId('fCount').textContent = _chips.length || ''; byId('fCount').classList.toggle('show', !!_chips.length);\r\n  }\r\n  function resetAll(){\r\n    S.q = ''; S.cat = ''; S.minP = S.maxP = S.maxKm = null; S.minY = S.maxY = ''; S.loc = '';\r\n    ['makes','ship','cond','fuel','trans','steer'].forEach(k => S[k].clear());\r\n    byId('sSearch').value = ''; byId('locInput').value = ''; byId('catSearch').value = ''; byId('makeSearch').value = '';\r\n  }\r\n\r\n  \/\/ ---- landing tiles (category pills with a vehicle photo) ----\r\n  function tilesHtml(){\r\n    const byCat = {}; ALL.forEach(l => { const c = l.vehicle_models?.category_id; if (c) (byCat[c] = byCat[c] || []).push(l); });\r\n    const img = l => (Array.isArray(l.images) && l.images[0]) || '';\r\n    const pick = list => { const h = list.find(l => \/\\\/storage\\\/v1\\\/object\\\/public\\\/\/.test(img(l))) || list.find(img); return h ? img(h) : ''; };\r\n    return VC.cats.filter(c => (byCat[c.id] || []).length).map(c => {\r\n      const list = byCat[c.id], im = pick(list);\r\n      return `<button type=\"button\" class=\"vc-tile\" data-cat=\"${c.id}\"><span class=\"vc-img\">${im ? `<img src=\"${esc(im)}\" alt=\"\" loading=\"lazy\" decoding=\"async\" onerror=\"this.remove()\">` : '<i class=\"ti ti-car\"><\/i>'}<\/span><span class=\"vc-nm\">${esc(c.name)}<\/span><span class=\"vc-n\">${fmtN(list.length)} listed<\/span><\/button>`;\r\n    }).join('');\r\n  }\r\n\r\n  \/\/ ---- pager ----\r\n  function pageItems(cur, total){\r\n    if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);\r\n    const set = new Set([1, total, cur - 1, cur, cur + 1]);\r\n    if (cur <= 3) { set.add(2); set.add(3); set.add(4); }\r\n    if (cur >= total - 2) { set.add(total - 1); set.add(total - 2); set.add(total - 3); }\r\n    const nums = [...set].filter(n => n >= 1 && n <= total).sort((a, b) => a - b);\r\n    const out = []; nums.forEach((n, i) => { if (i && n - nums[i - 1] > 1) out.push('\u2026'); out.push(n); });\r\n    return out;\r\n  }\r\n  function renderPager(total){\r\n    const el = byId('pager'), pages = Math.max(1, Math.ceil(total \/ S.per));\r\n    if (!total) { el.innerHTML = ''; return; }\r\n    if (pages <= 1) { el.innerHTML = `<div class=\"pg-info\">Showing all ${fmtN(total)} vehicle${total === 1 ? '' : 's'}<\/div>`; return; }\r\n    const cur = S.page;\r\n    el.innerHTML =\r\n      `<button type=\"button\" class=\"pg\" data-pg=\"${cur - 1}\" ${cur === 1 ? 'disabled' : ''} aria-label=\"Previous page\">${ARROW_L}<span class=\"pg-lbl\">Prev<\/span><\/button>` +\r\n      pageItems(cur, pages).map(n => n === '\u2026' ? '<span class=\"pg-ell\" aria-hidden=\"true\">\u2026<\/span>' : `<button type=\"button\" class=\"pg${n === cur ? ' cur' : ''}\" data-pg=\"${n}\" ${n === cur ? 'aria-current=\"page\"' : ''} aria-label=\"Page ${n}\">${n}<\/button>`).join('') +\r\n      `<button type=\"button\" class=\"pg\" data-pg=\"${cur + 1}\" ${cur === pages ? 'disabled' : ''} aria-label=\"Next page\"><span class=\"pg-lbl\">Next<\/span>${ARROW_R}<\/button>` +\r\n      `<div class=\"pg-info\">Page ${cur} of ${pages}<\/div>`;\r\n  }\r\n\r\n  \/\/ ---- render ----\r\n  function renderListings(){\r\n    const grid = byId('listingGrid');\r\n    if (!_loaded) return;\r\n    grid.className = 'bl-grid' + (S.view === 'list' ? ' list-view' : '');\r\n    grid.removeAttribute('aria-busy');\r\n    if (!_currentListings.length) {\r\n      grid.innerHTML = `<div class=\"empty-state\"><h3>No vehicles match your filters<\/h3><p>Try removing a filter or widening your budget.<\/p>${_chips.length ? '<button type=\"button\" class=\"btn-primary\" id=\"emptyClear\">Clear all filters<\/button>' : ''}<\/div>`;\r\n      renderPager(0); return;\r\n    }\r\n    const pages = Math.max(1, Math.ceil(_currentListings.length \/ S.per));\r\n    if (S.page > pages) S.page = pages;\r\n    const pageRows = _currentListings.slice((S.page - 1) * S.per, S.page * S.per);\r\n    renderPager(_currentListings.length);\r\n    grid.innerHTML = pageRows.map(l => {\r\n      const img = Array.isArray(l.images) && l.images.length ? l.images[0] : null;\r\n      const title = l._title;\r\n      const isNew = (l.condition || '').toLowerCase() === 'new';\r\n      const priceLabel = l.price ? fmtConverted(l.price, l.currency, appState.currency) : 'Ask For Price';\r\n      const km = l.mileage_km != null ? `${Number(l.mileage_km).toLocaleString()} km` : '0 km';\r\n      const href = 'https:\/\/app.builders24.net\/auto\/vehicle\/' + l.slug;\r\n      return `\r\n      <div class=\"vcard\" data-id=\"${l.id}\">\r\n        ${isNew ? `<span class=\"vcard-badge\">Brand New<\/span>` : ''}\r\n        <div class=\"vcard-top\"><button type=\"button\" class=\"vcard-fav\" aria-label=\"Save vehicle\" onclick=\"event.preventDefault();event.stopPropagation();toggleFav('${l.id}', this);\">\r\n          <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"${_favs[l.id] ? '#2B5FBF' : 'none'}\" stroke=\"#0D1220\" stroke-width=\"1.8\"><path d=\"M12 21s-7-4.6-9.5-9C.8 8.3 2.4 5 6 5c2 0 3.3 1 6 3.4C14.7 6 16 5 18 5c3.6 0 5.2 3.3 3.5 7-2.5 4.4-9.5 9-9.5 9z\"><\/path><\/svg>\r\n        <\/button><\/div>\r\n        <a class=\"vcard-link\" href=\"${href}\">\r\n          <div class=\"vcard-img\">${img ? `<img src=\"${esc(img)}\" alt=\"${esc(title)}\" loading=\"lazy\" decoding=\"async\" onerror=\"this.remove()\">` : `<i class=\"ti ti-photo\"><\/i>`}<\/div>\r\n          <div class=\"vcard-info\">\r\n            <p class=\"vcard-name\">${esc(title)}<\/p>\r\n            <div class=\"vcard-meta\">\r\n              <span>${l.year || ''}<\/span>\r\n              <span>${km}<\/span>\r\n              <span>${countryFlagEmoji(l.location_country)} ${esc(countryAbbrev(l.location_country))}<\/span>\r\n            <\/div>\r\n            <div class=\"vcard-pricebox\"><div class=\"vcard-price\">${esc(priceLabel)}<\/div>${(l.price && l.currency && l.currency !== appState.currency && typeof fmtNative === 'function') ? `<div class=\"vcard-listed\">Listed at ${esc(fmtNative(l.price, l.currency))}<\/div>` : ''}<\/div>\r\n          <\/div>\r\n        <\/a>\r\n        <div class=\"vcard-actions\">\r\n          <button type=\"button\" class=\"vcard-btn navy\" data-act=\"enquire\" data-id=\"${l.id}\">Enquire<\/button>\r\n          <button type=\"button\" class=\"vcard-btn orange\" data-act=\"buy\" data-id=\"${l.id}\"><svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ffffff\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"9\" cy=\"21\" r=\"1\"\/><circle cx=\"20\" cy=\"21\" r=\"1\"\/><path d=\"M1 1h4l2.7 13.4a2 2 0 0 0 2 1.6h9.7a2 2 0 0 0 2-1.6L23 6H6\"\/><\/svg>Buy for Me<\/button>\r\n        <\/div>\r\n      <\/div>`;\r\n    }).join('');\r\n  }\r\n  let _currentListings = [];\r\n  const _favs = {};\r\n  function render(keepPage){\r\n    if (!_loaded) return;\r\n    const keep = keepPage ? S.page : 1;\r\n    _currentListings = sortList(applyVehicleFilters(ALL));\r\n    S.page = keep;\r\n    const counts = categoryCounts();\r\n    renderCategories(counts); renderQuick(); renderPrice(); renderYear(); renderKm();\r\n    optList('makeList', 'fsMake', 'make', S.makes, l => l._mk, l => l._make, 8);\r\n    optList('shipList', 'fsShip', 'ship', S.ship, l => l._ship, l => shipLabel(l._ship));\r\n    optList('condList', 'fsCond', 'cond', S.cond, l => (l.condition || '').toLowerCase(), l => cap(l.condition || ''));\r\n    optList('fuelList', 'fsFuel', 'fuel', S.fuel, l => (l.fuel_type || '').toLowerCase(), l => cap(l.fuel_type || ''));\r\n    optList('transList', 'fsTrans', 'trans', S.trans, l => (l.transmission || '').toLowerCase(), l => transLabel((l.transmission || '').toLowerCase()));\r\n    optList('steerList', 'fsSteer', 'steer', S.steer, l => (l.steering || '').toLowerCase(), l => (l.steering || '').toUpperCase());\r\n    renderActive();\r\n    const total = _currentListings.length, pages = Math.max(1, Math.ceil(total \/ S.per)); if (S.page > pages) S.page = pages;\r\n    const from = total ? (S.page - 1) * S.per + 1 : 0, to = Math.min(S.page * S.per, total);\r\n    byId('resultCount').textContent = total ? `Showing ${fmtN(from)}\u2013${fmtN(to)} of ${fmtN(total)} vehicle${total === 1 ? '' : 's'}${S.q ? ' for \u201c' + S.q + '\u201d' : ''}` : '0 vehicles';\r\n    byId('sideShow').textContent = `Show ${fmtN(total)} vehicle${total === 1 ? '' : 's'}`;\r\n    byId('sSort').value = S.sort; byId('sPer').value = String(S.per);\r\n    byId('vGrid').classList.toggle('on', S.view !== 'list'); byId('vGrid').setAttribute('aria-pressed', S.view !== 'list');\r\n    byId('vList').classList.toggle('on', S.view === 'list'); byId('vList').setAttribute('aria-pressed', S.view === 'list');\r\n    byId('sClear').classList.toggle('show', !!byId('sSearch').value);\r\n    const landing = !_chips.length && S.page === 1 && S.sort === 'newest' && !getActiveFilters().vehicleType && !getActiveFilters().category && !getActiveFilters().make && !getActiveFilters().location;\r\n    byId('gridTitle').hidden = !landing;\r\n    const tiles = landing ? tilesHtml() : '';\r\n    byId('landing').innerHTML = tiles ? `<div class=\"landing-sec\"><h3>Shop by category<\/h3><div class=\"vc-tiles\">${tiles}<\/div><\/div>` : '';\r\n    renderListings();\r\n  }\r\n  const goTop = () => { const t = byId('buyMain'); if (t) t.scrollIntoView({ behavior: 'smooth', block: 'start' }); };\r\n  window.renderPrices = () => { if (!_loaded) return; ALL.forEach(l => { l._px = toCur(l.price, l.currency); }); render(true); };\r\n\r\n  \/\/ ---- events ----\r\n  function openSheet(open){ byId('shopSide').classList.toggle('open', open); byId('sheetOverlay').classList.toggle('open', open); document.body.style.overflow = open ? 'hidden' : ''; }\r\n  \/\/ ---- Enquire \/ Buy for Me (same behaviour as the vehicle page contact modal) ----\r\n  const VQ = { l: null };\r\n  const vqEl = id => document.getElementById(id);\r\n  const vqNum = n => Number(n || 0).toLocaleString('en', { maximumFractionDigits: 0 });\r\n  function vqName(l){ return [l.year, l._title].filter(Boolean).join(' ').trim() || 'Vehicle'; }\r\n  function vqPriceLabel(l){ return l.price ? ((l.currency || 'USD').toUpperCase() + ' ' + vqNum(l.price)) : 'Ask For Price'; }\r\n  function vqSummary(l){\r\n    const lines = [vqName(l), 'Price: ' + vqPriceLabel(l)];\r\n    if (l.location_city || l.location_country) lines.push('Location: ' + [l.location_city, l.location_country].filter(Boolean).join(', '));\r\n    if (l.slug) lines.push('Listing: https:\/\/app.builders24.net\/auto\/vehicle\/' + l.slug);\r\n    return lines.join('\\n');\r\n  }\r\n  const vqSendLabel = m => m === 'import' ? 'Send to Builders24 Import Team' : 'Send Message to Seller';\r\n  function vqErr(id, msg){ const e = vqEl(id); if (!e) return; e.textContent = msg; e.style.display = msg ? 'block' : 'none'; }\r\n  function vqSetMode(mode){\r\n    const l = VQ.l, ov = vqEl('vqOverlay'); ov.dataset.mode = mode;\r\n    vqEl('vqTitle').textContent = mode === 'import' ? 'Use Our Import Services' : 'Contact Seller';\r\n    vqEl('vqMsgLabel').textContent = mode === 'import' ? \"Anything specific you'd like to know?\" : 'Message to seller';\r\n    vqEl('vqSend').textContent = vqSendLabel(mode);\r\n    vqEl('vqOkTitle').textContent = mode === 'import' ? 'Inquiry Sent' : 'Message Sent';\r\n    vqEl('vqOkBody').textContent = mode === 'import' ? \"Builders24's import team will reach out to you shortly about this vehicle.\" : 'The seller will be in touch shortly.';\r\n    const m = vqEl('vqMessage'), sum = vqSummary(l);\r\n    if (mode === 'import') { m.value = ''; m.placeholder = 'e.g. shipping cost, financing options, inspection report...\\n\\n' + sum; }\r\n    else { m.value = \"Hi, I'm interested in this vehicle:\\n\\n\" + sum + \"\\n\\nCould you share more details?\"; m.placeholder = 'Add a note to your message\u2026'; }\r\n  }\r\n  async function vqOpen(id, mode){\r\n    const l = ALL.find(x => String(x.id) === String(id)); if (!l) return;\r\n    VQ.l = l;\r\n    vqEl('vqName').textContent = vqName(l); vqEl('vqPrice').textContent = vqPriceLabel(l);\r\n    const img = Array.isArray(l.images) && l.images.length ? l.images[0] : null, im = vqEl('vqImg');\r\n    if (img) { im.src = img; im.hidden = false; } else { im.removeAttribute('src'); im.hidden = true; }\r\n    vqSetMode(mode);\r\n    ['vqSuccess'].forEach(i => vqEl(i).style.display = 'none');\r\n    vqErr('vqLoggedInErr', ''); vqErr('vqLoginErr', ''); vqErr('vqRegErr', '');\r\n    ['vqSend','vqLoginBtn','vqRegBtn'].forEach(i => vqEl(i).disabled = false);\r\n    const ov = vqEl('vqOverlay'); ov.classList.add('open'); ov.setAttribute('aria-hidden', 'false'); document.body.style.overflow = 'hidden';\r\n    let session = null; try { session = (await sb.auth.getSession()).data.session; } catch (e) {}\r\n    vqEl('vqLoggedIn').style.display = session ? 'block' : 'none';\r\n    vqEl('vqGuest').style.display = session ? 'none' : 'block';\r\n  }\r\n  function vqClose(){ const ov = vqEl('vqOverlay'); ov.classList.remove('open'); ov.setAttribute('aria-hidden', 'true'); document.body.style.overflow = ''; }\r\n  function vqTab(which){\r\n    vqEl('vqTabLogin').classList.toggle('active', which === 'login'); vqEl('vqTabReg').classList.toggle('active', which === 'register');\r\n    vqEl('vqLoginForm').style.display = which === 'login' ? 'block' : 'none'; vqEl('vqRegForm').style.display = which === 'register' ? 'block' : 'none';\r\n  }\r\n  async function vqSendMsg(){\r\n    const l = VQ.l, mode = vqEl('vqOverlay').dataset.mode || 'seller', btn = vqEl('vqSend'), note = vqEl('vqMessage').value.trim();\r\n    btn.disabled = true; btn.textContent = 'Sending...'; vqErr('vqLoggedInErr', '');\r\n    try {\r\n      const { data: { session } } = await sb.auth.getSession();\r\n      if (!session) throw new Error('Session expired \u2014 please log in again.');\r\n      const sum = vqSummary(l);\r\n      const payload = {\r\n        sender_role: 'customer', sender_customer_id: session.user.id,\r\n        recipient_role: mode === 'import' ? 'support' : (l.seller_org_id ? 'org' : 'customer'),\r\n        body: mode === 'import' ? ('Import services inquiry\\n\\n' + sum + (note ? '\\n\\nCustomer note:\\n' + note : '')) : (note || ('Interested in this vehicle:\\n\\n' + sum))\r\n      };\r\n      if (mode === 'seller') { if (l.seller_org_id) payload.recipient_org_id = l.seller_org_id; if (l.seller_customer_id) payload.recipient_customer_id = l.seller_customer_id; }\r\n      const { error } = await sb.from('messages').insert(payload);\r\n      if (error) throw error;\r\n      vqEl('vqLoggedIn').style.display = 'none'; vqEl('vqGuest').style.display = 'none'; vqEl('vqSuccess').style.display = 'block';\r\n    } catch (e) {\r\n      console.error('Failed to send message', e);\r\n      vqErr('vqLoggedInErr', (e && e.message) || 'Could not send your message \u2014 please try again.');\r\n      btn.disabled = false; btn.textContent = vqSendLabel(mode);\r\n    }\r\n  }\r\n  async function vqLogin(){\r\n    const email = vqEl('vqLiEmail').value.trim(), pass = vqEl('vqLiPass').value; vqErr('vqLoginErr', '');\r\n    if (!email || !pass) { vqErr('vqLoginErr', 'Enter your email and password.'); return; }\r\n    const btn = vqEl('vqLoginBtn'); btn.disabled = true; btn.textContent = 'Logging in...';\r\n    const { error } = await sb.auth.signInWithPassword({ email, password: pass });\r\n    if (error) { vqErr('vqLoginErr', 'Incorrect email or password.'); btn.disabled = false; btn.textContent = 'Log In & Continue'; return; }\r\n    vqEl('vqGuest').style.display = 'none'; vqEl('vqLoggedIn').style.display = 'block';\r\n    await vqSendMsg();\r\n  }\r\n  async function vqRegister(){\r\n    const f = vqEl('vqRgF').value.trim(), la = vqEl('vqRgL').value.trim(), email = vqEl('vqRgEmail').value.trim(), phone = vqEl('vqRgPhone').value.trim(), city = vqEl('vqRgCity').value.trim(), pass = vqEl('vqRgPass').value;\r\n    vqErr('vqRegErr', '');\r\n    if (!f || !la) { vqErr('vqRegErr', 'Enter your first and last name.'); return; }\r\n    if (!email || email.indexOf('@') < 0) { vqErr('vqRegErr', 'Enter a valid email address.'); return; }\r\n    if (!phone) { vqErr('vqRegErr', 'Enter your phone number.'); return; }\r\n    if (!city) { vqErr('vqRegErr', 'Enter your city.'); return; }\r\n    if (pass.length < 8) { vqErr('vqRegErr', 'Password must be at least 8 characters.'); return; }\r\n    const btn = vqEl('vqRegBtn'); btn.disabled = true; btn.textContent = 'Creating account...';\r\n    const { data, error } = await sb.auth.signUp({ email, password: pass });\r\n    if (error) { vqErr('vqRegErr', error.message); btn.disabled = false; btn.textContent = 'Create Account & Continue'; return; }\r\n    const uid = data && data.user && data.user.id;\r\n    if (uid) {\r\n      const { error: pErr } = await sb.from('app_users').insert({ id: uid, role: 'customer', full_name: f + ' ' + la, phone, city, email, status: 'active' });\r\n      if (pErr && pErr.message.indexOf('duplicate') < 0) { vqErr('vqRegErr', 'Account created but profile failed: ' + pErr.message); btn.disabled = false; btn.textContent = 'Create Account & Continue'; return; }\r\n    }\r\n    vqEl('vqGuest').style.display = 'none'; vqEl('vqLoggedIn').style.display = 'block';\r\n    await vqSendMsg();\r\n  }\r\n  function wireEnquire(){\r\n    byId('listingGrid').addEventListener('click', e => {\r\n      const b = e.target.closest('.vcard-btn[data-act]'); if (!b) return;\r\n      e.preventDefault(); e.stopPropagation();\r\n      vqOpen(b.dataset.id, b.dataset.act === 'buy' ? 'import' : 'seller');\r\n    });\r\n    vqEl('vqClose').addEventListener('click', vqClose);\r\n    vqEl('vqOverlay').addEventListener('click', e => { if (e.target.id === 'vqOverlay') vqClose(); });\r\n    document.addEventListener('keydown', e => { if (e.key === 'Escape' && vqEl('vqOverlay').classList.contains('open')) vqClose(); });\r\n    vqEl('vqTabLogin').addEventListener('click', () => vqTab('login'));\r\n    vqEl('vqTabReg').addEventListener('click', () => vqTab('register'));\r\n    vqEl('vqSend').addEventListener('click', vqSendMsg);\r\n    vqEl('vqLoginBtn').addEventListener('click', vqLogin);\r\n    vqEl('vqRegBtn').addEventListener('click', vqRegister);\r\n  }\r\n  function wireShop(){\r\n    wireEnquire();\r\n    byId('sSort').innerHTML = Object.entries(SORTS).map(([k, v]) => `<option value=\"${k}\">${v}<\/option>`).join('');\r\n    byId('sPer').innerHTML = PER_OPTIONS.map(n => `<option value=\"${n}\">${n}<\/option>`).join('');\r\n    try { if (localStorage.getItem('b24_veh_view') === 'list') S.view = 'list'; const p = Number(localStorage.getItem('b24_veh_per')); if (PER_OPTIONS.includes(p)) S.per = p; } catch (e) {}\r\n    const redo = () => { S.page = 1; render(); };\r\n    byId('sSort').addEventListener('change', e => { S.sort = e.target.value; redo(); });\r\n    byId('sPer').addEventListener('change', e => { S.per = Number(e.target.value); try { localStorage.setItem('b24_veh_per', String(S.per)); } catch (x) {} redo(); });\r\n    byId('vGrid').addEventListener('click', () => { S.view = 'default'; try { localStorage.setItem('b24_veh_view', 'default'); } catch (x) {} render(true); });\r\n    byId('vList').addEventListener('click', () => { S.view = 'list'; try { localStorage.setItem('b24_veh_view', 'list'); } catch (x) {} render(true); });\r\n    const onSearch = debounce(() => { S.q = byId('sSearch').value.trim(); redo(); }, 220);\r\n    byId('sSearch').addEventListener('input', () => { byId('sClear').classList.toggle('show', !!byId('sSearch').value); onSearch(); });\r\n    byId('sClear').addEventListener('click', () => { byId('sSearch').value = ''; S.q = ''; redo(); byId('sSearch').focus(); });\r\n    byId('catSearch').addEventListener('input', debounce(() => render(true), 150));\r\n    byId('makeSearch').addEventListener('input', debounce(() => { const t = byId('makeSearch').value.trim().toLowerCase(); optList._all.makeList = !!t; render(true); if (t) document.querySelectorAll('#makeList .opt').forEach(o => { o.style.display = o.textContent.toLowerCase().includes(t) ? '' : 'none'; }); }, 150));\r\n    byId('locInput').addEventListener('input', debounce(() => { S.loc = byId('locInput').value.trim(); redo(); }, 250));\r\n    const applyPrice = () => { S.minP = numOrNull(byId('pMin').value); S.maxP = numOrNull(byId('pMax').value); redo(); };\r\n    byId('pGo').addEventListener('click', applyPrice);\r\n    ['pMin', 'pMax'].forEach(id => byId(id).addEventListener('keydown', e => { if (e.key === 'Enter') applyPrice(); }));\r\n    byId('priceChips').addEventListener('click', e => { const b = e.target.closest('[data-band]'); if (!b) return; const band = budgetBands()[Number(b.dataset.band)]; if (!band) return; if (S.minP === band.min && S.maxP === band.max) { S.minP = S.maxP = null; } else { S.minP = band.min; S.maxP = band.max; } redo(); });\r\n    byId('yMin').addEventListener('change', () => { S.minY = byId('yMin').value; redo(); });\r\n    byId('yMax').addEventListener('change', () => { S.maxY = byId('yMax').value; redo(); });\r\n    byId('kmMax').addEventListener('input', debounce(() => { S.maxKm = numOrNull(byId('kmMax').value); redo(); }, 350));\r\n    byId('kmChips').addEventListener('click', e => { const b = e.target.closest('[data-km]'); if (!b) return; const v = Number(b.dataset.km); S.maxKm = S.maxKm === v ? null : v; redo(); });\r\n    byId('deptRow').addEventListener('click', e => { const b = e.target.closest('[data-q]'); if (!b) return; S.ship.clear(); if (b.dataset.q) S.ship.add(b.dataset.q); redo(); });\r\n    byId('shopSide').addEventListener('change', e => {\r\n      const i = e.target; if (i.type !== 'checkbox' || !i.dataset.set) return;\r\n      const k = { make:'makes', ship:'ship', cond:'cond', fuel:'fuel', trans:'trans', steer:'steer' }[i.dataset.set];\r\n      i.checked ? S[k].add(i.value) : S[k].delete(i.value); redo();\r\n    });\r\n    byId('shopSide').addEventListener('click', e => {\r\n      const more = e.target.closest('[data-more]'); if (more) { optList._all[more.dataset.more] = !optList._all[more.dataset.more]; render(true); return; }\r\n      const tog = e.target.closest('[data-tog]'); if (tog) { const id = tog.dataset.tog; expanded.has(id) ? expanded.delete(id) : expanded.add(id); render(true); return; }\r\n      const row = e.target.closest('[data-cat]'); if (row) { S.cat = S.cat === row.dataset.cat ? '' : row.dataset.cat; catPath(S.cat).forEach(id => { if (id !== S.cat) expanded.add(id); }); redo(); if (window.innerWidth < 900) openSheet(false); }\r\n    });\r\n    byId('landing').addEventListener('click', e => { const t = e.target.closest('[data-cat]'); if (!t) return; S.cat = t.dataset.cat; catPath(S.cat).forEach(id => expanded.add(id)); redo(); goTop(); });\r\n    byId('activeBar').addEventListener('click', e => {\r\n      if (e.target.closest('#afClear')) { byId('clearFilters').click(); return; }\r\n      const b = e.target.closest('[data-af]'); if (!b || !_chips[b.dataset.af]) return; _chips[b.dataset.af].off(); redo();\r\n    });\r\n    byId('listingGrid').addEventListener('click', e => { if (e.target.closest('#emptyClear')) byId('clearFilters').click(); else if (e.target.closest('#emptyRetry')) loadListings(); });\r\n    byId('pager').addEventListener('click', e => { const b = e.target.closest('[data-pg]'); if (!b || b.disabled) return; S.page = Number(b.dataset.pg); render(true); goTop(); });\r\n    byId('openFilters').addEventListener('click', () => openSheet(true));\r\n    byId('sideClose').addEventListener('click', () => openSheet(false));\r\n    byId('sheetOverlay').addEventListener('click', () => openSheet(false));\r\n    byId('sideShow').addEventListener('click', () => { openSheet(false); goTop(); });\r\n    byId('sideClear').addEventListener('click', () => byId('clearFilters').click());\r\n    document.addEventListener('keydown', e => { if (e.key === 'Escape') openSheet(false); });\r\n    \/\/ \"Advanced Search\" in the top card now opens the full filter panel\r\n    byId('advSearch').addEventListener('click', () => { if (window.innerWidth < 900) openSheet(true); else byId('shopSide').scrollIntoView({ behavior: 'smooth', block: 'start' }); });\r\n    \/\/ deep links (e.g. from the home page \/ header menus)\r\n    const sp = new URLSearchParams(location.search);\r\n    S.minP = numOrNull(sp.get('min_price') || ''); S.maxP = numOrNull(sp.get('max_price') || '');\r\n    if (sp.get('q')) { S.q = sp.get('q').trim(); byId('sSearch').value = S.q; }\r\n    const sh = (sp.get('shipped_from') || '').toLowerCase(); if (sh) S._pendingShip = sh;\r\n  }\r\n\r\n  \/\/ ---- Populate real filter dropdowns (makes only \u2014 vehicle type is a\r\n  \/\/ fixed real enum, location is a free-text field with a datalist) ----\r\n  async function populateFilters() {\r\n    try {\r\n      const { data: makes } = await sb.from('vehicle_makes').select('name, slug').eq('is_active', true).order('name');\r\n      const makeSelect = document.getElementById('filterMake');\r\n      (makes || []).forEach(m => {\r\n        const opt = document.createElement('option');\r\n        opt.value = m.slug; opt.textContent = m.name;\r\n        makeSelect.appendChild(opt);\r\n      });\r\n    } catch (e) { console.error('Make dropdown failed:', e); }\r\n  }\r\n\r\n  document.getElementById('filterSearchBtn').addEventListener('click', () => loadListings());\r\n  document.getElementById('filterVehicleType').addEventListener('change', () => loadListings());\r\n  document.getElementById('filterCategory').addEventListener('change', () => loadListings());\r\n  document.getElementById('filterMake').addEventListener('change', () => loadListings());\r\n  document.getElementById('filterLocation').addEventListener('keydown', (e) => { if (e.key === 'Enter') loadListings(); });\r\n  document.getElementById('clearFilters').addEventListener('click', (e) => {\r\n    e.preventDefault();\r\n    document.getElementById('filterVehicleType').value = '';\r\n    document.getElementById('filterCategory').value = '';\r\n    document.getElementById('filterMake').value = '';\r\n    document.getElementById('filterLocation').value = '';\r\n    resetAll();\r\n    loadListings();\r\n  });\r\n\r\n  \/\/ ===== Currency + Delivery \u2014 real data layer, same as index.html\/shop.html.\r\n  \/\/ Vehicle prices convert live via fmtConverted(l.price, l.currency,\r\n  \/\/ appState.currency) in renderListings() \u2014 changing currency here\r\n  \/\/ re-renders every card on screen from the cached _currentListings,\r\n  \/\/ no refetch needed. The picker UI itself now lives in the shared\r\n  \/\/ header (header.js) \u2014 no page-local dropdown markup\/handlers needed. =====\r\n  let appState = { currency: 'USD', locationIndex: 0 };\r\n  const LOCATIONS = window.B24_LOCATIONS || [];\r\n  \/\/ Single real source: header.js sets window.B24_LOCATIONS (all 54\r\n  \/\/ African countries), loaded before this script now runs. Local\r\n  \/\/ duplicate array removed \u2014 this page no longer keeps its own copy.\r\n\r\n  \/\/ Guest location detection is now shared, site-wide, in b24app.js\r\n  \/\/ (getCustomerDefaultAddress()\/detectGuestLocation()) \u2014 this wrapper\r\n  \/\/ just applies the shared function's result to this page's own appState.\r\n  async function detectGuestLocationForPage(){\r\n    const { matchIdx, isGuest } = await detectGuestLocation();\r\n    if (matchIdx !== -1) {\r\n      appState.locationIndex = matchIdx;\r\n      if (isGuest) appState.currency = LOCATIONS[matchIdx].currency;\r\n    }\r\n  }\r\n\r\n  function updateDeliverLabel(){\r\n    const loc = LOCATIONS[appState.locationIndex];\r\n    const label = _customerDefaultAddressLabel || (loc && loc.city);\r\n    if (!label) return;\r\n    document.querySelectorAll('.deliver-city-text').forEach(el => el.textContent = label);\r\n  }\r\n  \/\/ auto-header.js calls this once B24Nav.init() has actually injected the\r\n  \/\/ shared header into the DOM \u2014 this page's own boot below runs earlier\r\n  \/\/ (before that injection), so its own call to updateDeliverLabel() is a\r\n  \/\/ harmless best-effort that likely finds nothing yet.\r\n  window.__updateDeliverLabel = updateDeliverLabel;\r\n\r\n  (async () => {\r\n    await getCustomerDefaultAddress();\r\n    \/\/ The app header is not loaded on this page, so there is no deliver label or location list to update.\r\n    await loadExchangeRates();\r\n    const before = appState.currency;\r\n    appState.currency = await getCustomerCurrency();\r\n    document.getElementById('currencyBadgeText').textContent = appState.currency;\r\n    \/\/ Listings may already be on screen in the pre-settle currency, with prices\r\n    \/\/ (_px) used by the budget filter and price sorts \u2014 recompute and redraw.\r\n    \/\/ Same settle-then-re-render step shop.html does.\r\n    if (_loaded && typeof window.renderPrices === 'function') window.renderPrices();\r\n    if (typeof updateCartBadge === 'function') updateCartBadge();\r\n  })();\r\n\r\n  wireShop();\r\n  populateFilters();\r\n  \/\/ Pre-apply a vehicle-type filter when arriving via a real deep link\r\n  \/\/ (e.g. the Auto FAB's Pick Ups\/Trucks items: \/auto\/vehicles?type=...).\r\n  const urlType = new URLSearchParams(location.search).get('type');\r\n  if (urlType) document.getElementById('filterVehicleType').value = urlType;\r\n  loadListings();\r\n\r\n  \/\/ ===== \"Ship Your Vehicle\" tab \u2014 reads the central vehicle_transport table\r\n  \/\/ through its views (vehicle_transport_search \/ _origins \/ _destinations \/\r\n  \/\/ _types), the same source as the vehicle page's shipping calculator.\r\n  \/\/ Origins, destinations and vehicle types are loaded live \u2014 nothing is\r\n  \/\/ hard-coded here, so new lanes appear without a code change. =====\r\n  const VEHICLE_MODES = [ { value: 'roro', label: 'RoRo' }, { value: 'fcl_40hq', label: 'Container (FCL 40HQ)' } ];\r\n  const SHIP_KIND_PRIORITY = { freight_route: 1, delivery_lane: 2, full_lane: 3, sea_leg: 4, inland_leg: 5 };\r\n  const SHIP_REQ_URL = 'https:\/\/app.builders24.net\/build\/request-quote?category=Vehicle%20Shipping';\r\n  const SHIP_REQ = '<a href=\"' + SHIP_REQ_URL + '\" style=\"color:#F5A623;font-weight:700;\">request a quote<\/a>';\r\n\r\n  let _ship = null;\r\n  async function ensureShipVehicleOptions() {\r\n    if (_ship) return;\r\n    const [o, d, t] = await Promise.all([\r\n      sb.from('vehicle_transport_origins').select('origin_country,has_price').order('has_price', { ascending: false }).order('origin_country').range(0, 999),\r\n      sb.from('vehicle_transport_destinations').select('destination_country,destination_place,has_price').order('has_price', { ascending: false }).order('destination_place').range(0, 999),\r\n      sb.from('vehicle_transport_types').select('vehicle_type,shipping_mode').in('shipping_mode', ['roro', 'fcl_40hq']).order('vehicle_type').range(0, 999)\r\n    ]);\r\n    if (o.error) throw o.error; if (d.error) throw d.error; if (t.error) throw t.error;\r\n    _ship = {\r\n      origins: (o.data || []).map(r => r.origin_country).filter(Boolean),\r\n      dests: (d.data || []).filter(r => r.destination_place && r.destination_country).map(r => ({ label: r.destination_place + ', ' + r.destination_country, country: r.destination_country, place: r.destination_place })),\r\n      types: t.data || []\r\n    };\r\n  }\r\n  function shipTypeOptions(mode) {\r\n    const seen = {}, out = [];\r\n    _ship.types.forEach(r => { if (r.shipping_mode === mode && r.vehicle_type && !seen[r.vehicle_type]) { seen[r.vehicle_type] = 1; out.push(r.vehicle_type); } });\r\n    return '<option value=\"\">Any vehicle type<\/option>' + out.map(v => `<option value=\"${esc(v)}\">${esc(v)}<\/option>`).join('');\r\n  }\r\n\r\n  async function renderShipFields() {\r\n    const host = document.getElementById('shipFilterFields');\r\n    try { await ensureShipVehicleOptions(); }\r\n    catch (e) { console.error('[vehicles] ship options failed:', e); host.innerHTML = '<div style=\"grid-column:1\/-1;font-size:13px;\">Could not load shipping options \u2014 please try again.<\/div>'; return; }\r\n    if (host.dataset.ready) return;\r\n    host.dataset.ready = '1';\r\n    host.innerHTML = `\r\n      <div class=\"bl-filter-field\"><span>Vehicle Type<\/span><select id=\"shipVehicleType\" class=\"bl-select\">${shipTypeOptions(VEHICLE_MODES[0].value)}<\/select><\/div>\r\n      <div class=\"bl-filter-field\"><span>From<\/span><select id=\"shipFrom\" class=\"bl-select\"><option value=\"\">Select origin<\/option>${_ship.origins.map(c => `<option value=\"${esc(c)}\">${esc(c)}<\/option>`).join('')}<\/select><\/div>\r\n      <div class=\"bl-filter-field\"><span>Destination<\/span><input id=\"shipTo\" class=\"bl-select\" list=\"shipToList\" placeholder=\"Type a city or country\" autocomplete=\"off\"><datalist id=\"shipToList\">${_ship.dests.map(x => `<option value=\"${esc(x.label)}\"><\/option>`).join('')}<\/datalist><\/div>\r\n      <div class=\"bl-filter-field\"><span>Mode<\/span><select id=\"shipMode\" class=\"bl-select\">${VEHICLE_MODES.map(m => `<option value=\"${m.value}\">${esc(m.label)}<\/option>`).join('')}<\/select><\/div>\r\n    `;\r\n    document.getElementById('shipMode').addEventListener('change', e => { document.getElementById('shipVehicleType').innerHTML = shipTypeOptions(e.target.value); });\r\n  }\r\n\r\n  async function quoteShipVehicle() {\r\n    const resultEl = document.getElementById('shipQuoteResult');\r\n    resultEl.style.display = 'block';\r\n    if (!_ship || !document.getElementById('shipTo')) { resultEl.innerHTML = 'Shipping options are still loading \u2014 please try again in a moment.'; return; }\r\n    const vehicleType = document.getElementById('shipVehicleType').value;\r\n    const from = document.getElementById('shipFrom').value;\r\n    const toText = document.getElementById('shipTo').value.trim().toLowerCase();\r\n    const mode = document.getElementById('shipMode').value;\r\n    const dest = _ship.dests.find(x => x.label.toLowerCase() === toText);\r\n    if (!from || !dest) { resultEl.innerHTML = 'Choose where it ships from and pick a destination from the list, or ' + SHIP_REQ + ' instead.'; return; }\r\n    resultEl.textContent = 'Looking up rates...';\r\n    try {\r\n      let q = sb.from('vehicle_transport_search')\r\n        .select('lane_kind,vehicle_type,price,price_currency,transit_days_max')\r\n        .eq('origin_country', from).eq('destination_country', dest.country).eq('destination_place', dest.place)\r\n        .eq('shipping_mode', mode).not('price', 'is', null);\r\n      if (vehicleType) q = q.eq('vehicle_type', vehicleType);\r\n      const { data: rows, error } = await q;\r\n      if (error) throw error;\r\n      if (!rows || !rows.length) {\r\n        \/\/ No price on file: same flow as before \u2014 send them to request a quote.\r\n        resultEl.innerHTML = 'No price on file for that route yet \u2014 taking you to ' + SHIP_REQ + ' so our team can quote it\u2026';\r\n        setTimeout(() => { location.href = SHIP_REQ_URL; }, 1200);\r\n        return;\r\n      }\r\n      rows.sort((a, b) => (SHIP_KIND_PRIORITY[a.lane_kind] || 9) - (SHIP_KIND_PRIORITY[b.lane_kind] || 9) || Number(a.price) - Number(b.price));\r\n      const r = rows[0], cur = r.price_currency || 'USD';\r\n      resultEl.innerHTML = `<b>${esc(r.vehicle_type || vehicleType || 'Vehicle')}<\/b> \u2014 ${esc(from)} \u2192 ${esc(dest.label)}: <b>${esc(cur)} ${Number(r.price).toLocaleString('en', { maximumFractionDigits: 0 })}<\/b>${r.transit_days_max ? ' \u00b7 approx. ' + r.transit_days_max + ' days' : ''} <a href=\"\/shipping\/book-and-pay.html\" style=\"color:#F5A623;font-weight:700;display:block;margin-top:6px;\">Book &amp; pay on Shipping \u2192<\/a>`;\r\n    } catch (e) {\r\n      console.error('[vehicles] quoteShipVehicle failed:', e);\r\n      resultEl.textContent = 'Could not look up rates \u2014 please try again.';\r\n    }\r\n  }\r\n\r\n  document.getElementById('vehicleTabs').addEventListener('click', (e) => {\r\n    const t = e.target.closest('.bl-tab[data-tab]');\r\n    if (!t) return;\r\n    document.querySelectorAll('#vehicleTabs .bl-tab').forEach(x => x.classList.remove('bl-tab-active'));\r\n    t.classList.add('bl-tab-active');\r\n    const tab = t.dataset.tab;\r\n    if (tab === 'ship') {\r\n      document.getElementById('buyFilterCard').style.display = 'none';\r\n      document.getElementById('buyMain').style.display = 'none';\r\n      document.getElementById('shipFilterCard').style.display = 'block';\r\n      renderShipFields();\r\n    } else {\r\n      document.getElementById('shipFilterCard').style.display = 'none';\r\n      document.getElementById('buyFilterCard').style.display = 'block';\r\n      document.getElementById('buyMain').style.display = 'block';\r\n    }\r\n  });\r\n  document.getElementById('shipQuoteBtn').addEventListener('click', quoteShipVehicle);\r\n<\/script>\r\n\r\n<\/body>\r\n<\/html>\t\t\t\t<\/div>\n\t\t\n<\/div>\n\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Vehicles For Sale \u2014 Trucks, Bakkies, Buses &#038; Heavy Equipment | Builders24 Builders24 AutoBuy, Sell, Source, Import, New And Used Vehicles. Buy new and used cars, trucks, buses and commercial vehicles across Africa, sold by local dealers and sourced from Japan, China, the UK and other international markets. Builders24 Auto provides vehicle sourcing, inspection, import and delivery across Africa. Verified Sellers100% Verified Quality VehiclesInspected &amp; Reliable Secure DealsSafe &amp; Transparent Managed ShippingDeliveries across Africa Buy Vehicles Sell Your Vehicle Ship Your Vehicle Vehicle Type All TypesTrucksBusesTrailersMachineryVans &amp; Pickups Category All CategoriesAutomaticManual RHDLHD HybridElectricPetrolDiesel NewUsed Make All Makes Location Search Vehicles Advanced Search Clear all Get Instant Quote &times; Filters Sort by Filters&times; Categories Price \/ Budget Min Max Go Make Shipped from Year From To Mileage Up to (km) Condition Fuel type Transmission Steering Vehicle location Clear all Show results Loading&hellip; Show per page All vehicles Loading vehicles&hellip; Enquire if still available Your message Send Message Log InCreate Account Email Password Log In &amp; Continue First NameLast Name Email Phone City Password Create Account &amp; Continue Message Sent The seller will be in touch shortly.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":{"footnotes":""},"class_list":["post-83317","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/builders24.net\/zw\/wp-json\/wp\/v2\/pages\/83317","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/builders24.net\/zw\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/builders24.net\/zw\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/builders24.net\/zw\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/builders24.net\/zw\/wp-json\/wp\/v2\/comments?post=83317"}],"version-history":[{"count":6,"href":"https:\/\/builders24.net\/zw\/wp-json\/wp\/v2\/pages\/83317\/revisions"}],"predecessor-version":[{"id":153495,"href":"https:\/\/builders24.net\/zw\/wp-json\/wp\/v2\/pages\/83317\/revisions\/153495"}],"wp:attachment":[{"href":"https:\/\/builders24.net\/zw\/wp-json\/wp\/v2\/media?parent=83317"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}