// HM Veículos — componentes compartilhados v2
const { useState, useEffect, useRef, useCallback } = React;

// Helpers
const fmtBRL = (n) => {
  const num = typeof n === "number" ? n : parseFloat(n);
  if (!Number.isFinite(num)) return "0";
  return num.toLocaleString("pt-BR", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
};
const fmtKM = (n) => {
  const num = typeof n === "number" ? n : parseFloat(n);
  if (!Number.isFinite(num)) return "0 km";
  return num.toLocaleString("pt-BR") + " km";
};

// ----- Icons -----
const Icon = {
  Whatsapp: ({ size = 20 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51l-.57-.01c-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.247-.694.247-1.289.173-1.413-.074-.124-.272-.198-.57-.347zM12.04 2.003C6.583 2.003 2.13 6.456 2.13 11.913c0 1.745.456 3.453 1.323 4.953L2 22l5.252-1.378c1.448.79 3.078 1.207 4.738 1.207h.005c5.46 0 9.91-4.452 9.91-9.91 0-2.647-1.03-5.135-2.901-7.005-1.871-1.871-4.358-2.911-7.005-2.911z"/>
    </svg>
  ),
  Phone: ({ size = 18 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.79 19.79 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.37 1.9.72 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.35 1.85.59 2.81.72A2 2 0 0 1 22 16.92z"/></svg>),
  Menu: ({ size = 22 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><line x1="4" y1="8" x2="20" y2="8"/><line x1="4" y1="16" x2="20" y2="16"/></svg>),
  Close: ({ size = 22 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="6" y1="18" x2="18" y2="6"/></svg>),
  ArrowLeft: ({ size = 18 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>),
  ArrowRight: ({ size = 18 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>),
  ArrowUpRight: ({ size = 18 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><line x1="7" y1="17" x2="17" y2="7"/><polyline points="7 7 17 7 17 17"/></svg>),
  Instagram: ({ size = 18 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="2" y="2" width="20" height="20" rx="5"/><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"/><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"/></svg>),
  Facebook: ({ size = 18 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"/></svg>),
  Pin: ({ size = 18 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>),
  Clock: ({ size = 18 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>),
  Shield: ({ size = 24 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="m9 12 2 2 4-4"/></svg>),
  Search: ({ size = 24 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>),
  Hand: ({ size = 24 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M9 11V6a2 2 0 1 1 4 0v5"/><path d="M13 11V4a2 2 0 1 1 4 0v9"/><path d="M17 13V8a2 2 0 1 1 4 0v8a6 6 0 0 1-6 6h-3a6 6 0 0 1-5.66-4L4 14a2 2 0 0 1 3.5-2L9 13"/></svg>),
  Sparkle: ({ size = 24 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2 2M16.4 16.4l2 2M5.6 18.4l2-2M16.4 7.6l2-2"/></svg>),
  ChevDouble: ({ size = 18 }) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="7 17 12 12 7 7"/><polyline points="13 17 18 12 13 7"/></svg>),
};

// ----- WhatsApp Picker -----
// Botão de WhatsApp que abre um seletor quando há mais de um contato
// configurado em site_settings (contato.whatsapp_contatos). Se houver só
// um, abre o WhatsApp direto sem modal.
function WAPicker({ message, children, className, ariaLabel, onSelect }) {
  const [open, setOpen] = useState(false);
  const contacts = (window.getWAContacts ? window.getWAContacts() : []) || [];
  const msg = message || "Olá! Vim através do site da HM Veículos e gostaria de atendimento.";

  const directLink = (c) => {
    const num = (c && c.numero) || "";
    const t = `?text=${encodeURIComponent(msg)}`;
    if (!num) return `https://wa.me/${t}`;
    return `https://wa.me/${num}${t}`;
  };
  const fireSelect = (c) => { if (typeof onSelect === "function") onSelect(c); };

  // Sem contatos cadastrados — degrade gracioso: link de fallback
  if (contacts.length === 0) {
    return (
      <a className={className} href={`https://wa.me/?text=${encodeURIComponent(msg)}`} target="_blank" rel="noopener" aria-label={ariaLabel} onClick={() => fireSelect(null)}>
        {children}
      </a>
    );
  }

  // Apenas 1 contato — link direto sem modal
  if (contacts.length === 1) {
    return (
      <a className={className} href={directLink(contacts[0])} target="_blank" rel="noopener" aria-label={ariaLabel} onClick={() => fireSelect(contacts[0])}>
        {children}
      </a>
    );
  }

  // Múltiplos contatos — abre modal de seleção (portal no body para evitar z-index/stacking-context)
  const modal = open ? (
    <div className="wa-modal-backdrop" onClick={() => setOpen(false)} role="dialog" aria-modal="true">
      <div className="wa-modal" onClick={(e) => e.stopPropagation()}>
        <div className="wa-modal-head">
          <div>
            <div className="wa-modal-eyebrow">WhatsApp</div>
            <h3 className="wa-modal-title">Com quem você quer falar?</h3>
          </div>
          <button type="button" className="wa-modal-close" onClick={() => setOpen(false)} aria-label="Fechar">
            <Icon.Close size={18}/>
          </button>
        </div>
        <ul className="wa-modal-list">
          {contacts.map((c, i) => (
            <li key={i}>
              <a
                className="wa-modal-item"
                href={directLink(c)}
                target="_blank"
                rel="noopener"
                onClick={() => { fireSelect(c); setOpen(false); }}
              >
                <div className="wa-modal-item-info">
                  <div className="wa-modal-item-name">{c.nome}</div>
                </div>
                <span className="wa-modal-item-icon"><Icon.Whatsapp size={20}/></span>
              </a>
            </li>
          ))}
        </ul>
      </div>
    </div>
  ) : null;

  return (
    <React.Fragment>
      <button type="button" className={className} onClick={() => setOpen(true)} aria-label={ariaLabel}>
        {children}
      </button>
      {ReactDOM.createPortal(modal, document.body)}
    </React.Fragment>
  );
}

// ----- Logo -----
function Logo({ onClick, dark, size = 24 }) {
  return (
    <a href="#" onClick={(e) => { e.preventDefault(); onClick && onClick(); }} className={"logo" + (dark ? " dark" : "")}>
      <img src="../assets/logo-hm.png" alt="HM Veículos" height={size * 1.25} style={{ display: "block", width: "auto" }}/>
    </a>
  );
}

// ----- Scroll Progress bar -----
function ScrollProgress() {
  const ref = useRef(null);
  useEffect(() => {
    const onScroll = () => {
      const max = document.documentElement.scrollHeight - window.innerHeight;
      const p = max > 0 ? window.scrollY / max : 0;
      if (ref.current) ref.current.style.transform = `scaleX(${p})`;
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return <div className="scroll-progress" ref={ref}></div>;
}

// ----- Header -----
function Header({ onNav, route }) {
  const [scrolled, setScrolled] = useState(false);
  const [mobileOpen, setMobileOpen] = useState(false);

  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 12);
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  useEffect(() => { setMobileOpen(false); }, [route]);

  const links = [
    { label: "Início", href: "#top", onClick: () => onNav("home") },
    { label: "Estoque", href: "#estoque", onClick: () => onNav("home", "estoque") },
    { label: "Sobre", href: "#sobre", onClick: () => onNav("home", "sobre") },
    { label: "Consignação", href: "#consignacao", onClick: () => onNav("home", "consignacao") },
    { label: "Contato", href: "#contato", onClick: () => onNav("home", "contato") },
  ];

  return (
    <React.Fragment>
      <header className={"header" + (scrolled ? " scrolled" : "")}>
        <div className="container header-inner">
          <Logo onClick={() => onNav("home")} />
          <nav className="nav" aria-label="Navegação">
            {links.map((l) => (
              <a key={l.label} href={l.href} onClick={(e) => { e.preventDefault(); l.onClick(); }}>{l.label}</a>
            ))}
          </nav>
          <div className="header-actions">
            <WAPicker className="btn btn-primary desktop-only" ariaLabel="Falar pelo WhatsApp">
              <Icon.Whatsapp size={16} /> WhatsApp
            </WAPicker>
            <button className="hamburger" aria-label="Menu" onClick={() => setMobileOpen((v) => !v)}>
              {mobileOpen ? <Icon.Close /> : <Icon.Menu />}
            </button>
          </div>
        </div>
      </header>
      <div className={"mobile-menu" + (mobileOpen ? " open" : "")}>
        {links.map((l) => (
          <a key={l.label} href={l.href} onClick={(e) => { e.preventDefault(); l.onClick(); setMobileOpen(false); }}>{l.label}</a>
        ))}
        <WAPicker className="btn btn-primary btn-block" ariaLabel="Falar pelo WhatsApp">
          <Icon.Whatsapp size={18} /> Falar pelo WhatsApp
        </WAPicker>
      </div>
    </React.Fragment>
  );
}

// ----- Footer -----
function fmtPhone(raw) {
  // 5537999074004 → "(37) 99907-4004"  ·  3730151575 → "(37) 3015-1575"
  const d = String(raw || "").replace(/[^0-9]/g, "");
  if (!d) return "";
  const local = d.length > 11 ? d.slice(d.length - 11) : d; // tira o 55 do começo se tiver
  if (local.length === 11) return `(${local.slice(0,2)}) ${local.slice(2,7)}-${local.slice(7)}`;
  if (local.length === 10) return `(${local.slice(0,2)}) ${local.slice(2,6)}-${local.slice(6)}`;
  return d;
}

function Footer() {
  const get = (k, fb) => (window.getSetting ? window.getSetting(k, fb) : fb);
  const nome = get("loja.nome", "HM Veículos");
  const endereco = get("loja.endereco", "Rua Rio de Janeiro, 1215 — Centro, Divinópolis/MG");
  const horario = get("loja.horario", "Seg–Sex 8h–18h · Sáb 8h–12h");
  const fixo = get("contato.fixo", "3730151575");
  const email = get("contato.email", "");
  const ig = get("social.instagram", "https://instagram.com/loja.hmveiculos");
  const fb = get("social.facebook", "https://facebook.com/lojahmveiculos");
  const igHandle = (ig || "").replace(/^https?:\/\/(www\.)?instagram\.com\//, "@").replace(/\/$/, "");
  const fbHandle = (fb || "").replace(/^https?:\/\/(www\.)?facebook\.com\//, "/").replace(/\/$/, "");
  const waContacts = (window.getWAContacts ? window.getWAContacts() : []) || [];
  return (
    <footer className="footer" id="contato">
      <div className="container">
        <h2 className="footer-mega">
          <span>vem para</span>&nbsp;<span className="red">HM</span>.
        </h2>
        <div className="footer-grid">
          <div className="footer-col">
            <h4>{nome}</h4>
            <p style={{ color: "rgba(255,255,255,0.65)", margin: 0, maxWidth: 320 }}>
              Loja de seminovos em Divinópolis-MG. Mais de 20 anos cuidando do que importa: o seu próximo carro.
            </p>
          </div>
          <div className="footer-col">
            <h4>Endereço</h4>
            <ul>
              <li><Icon.Pin size={15} /> {endereco}</li>
              <li><Icon.Clock size={15} /> {horario}</li>
            </ul>
          </div>
          <div className="footer-col">
            <h4>Atendimento</h4>
            <ul>
              {waContacts.map((c, i) => (
                <React.Fragment key={i}>
                  <li><a href={`https://wa.me/${c.numero}`} target="_blank" rel="noopener"><Icon.Whatsapp size={15} /> {c.nome}</a></li>
                  <li>{fmtPhone(c.numero)}</li>
                </React.Fragment>
              ))}
              {fixo && <li><a href={`tel:+55${String(fixo).replace(/[^0-9]/g, "")}`}><Icon.Phone size={15} /> {fmtPhone(fixo)}</a></li>}
            </ul>
          </div>
          <div className="footer-col">
            <h4>Siga</h4>
            <ul>
              {ig && <li><a href={ig} target="_blank" rel="noopener"><Icon.Instagram size={15} /> {igHandle || "Instagram"}</a></li>}
              {fb && <li><a href={fb} target="_blank" rel="noopener"><Icon.Facebook size={15} /> {fbHandle || "Facebook"}</a></li>}
              {email && <li><a href={`mailto:${email}`}>{email}</a></li>}
            </ul>
          </div>
        </div>
        <div className="footer-bottom">
          {(() => {
            const fachada = get("loja.foto_fachada_url", "") || "../assets/fachada.jpeg";
            return (
              <div className="footer-fachada">
                <img src={fachada} alt="Fachada HM Veículos" loading="lazy"/>
              </div>
            );
          })()}
          <div className="footer-map" aria-label="Mapa">
            <iframe
              src="https://maps.google.com/maps?q=HM+Ve%C3%ADculos+Rua+Rio+de+Janeiro+1215+Divin%C3%B3polis+MG&output=embed&z=16&hl=pt-BR"
              width="100%" height="100%" loading="lazy" allowFullScreen
              style={{ border: 0, display: "block" }}
              title="Localização HM Veículos"
            />
          </div>
        </div>
      </div>
      <div className="container">
        <div className="footer-legal">
          <span>© 2026 HM Garage e Veículos Ltda · CNPJ 35.487.031/0001</span>
          <span>Divinópolis–MG · Brasil</span>
        </div>
      </div>
    </footer>
  );
}

// ----- WhatsApp Float -----
function WhatsAppFloat() {
  return (
    <WAPicker className="wa-float" ariaLabel="Falar pelo WhatsApp">
      <Icon.Whatsapp size={28} />
    </WAPicker>
  );
}

// ----- Price Block (preço normal + promocional empilhado) -----
function PriceBlock({ vehicle, variant }) {
  const { preco, precoPromocional } = vehicle;
  const hasPromo = precoPromocional && precoPromocional > 0 && precoPromocional < preco;
  const discount = hasPromo ? Math.round((1 - precoPromocional / preco) * 100) : 0;
  const finalPrice = hasPromo ? precoPromocional : preco;

  if (variant === "detail") {
    return (
      <React.Fragment>
        <div className="detail-price-label">
          {hasPromo ? "Oferta especial" : "Por apenas"}
        </div>
        {hasPromo && (
          <div className="detail-price-old tabular">
            <span className="detail-price-old-strike">
              <span className="moeda">R$</span>{fmtBRL(preco)}
            </span>
            <span className="detail-discount-badge">−{discount}%</span>
          </div>
        )}
        <div className={"detail-price tabular" + (hasPromo ? " is-promo" : "")}>
          <span className="moeda">R$</span>{fmtBRL(finalPrice)}
        </div>
      </React.Fragment>
    );
  }

  return (
    <div className={"vcard-price-wrap" + (hasPromo ? " has-promo" : "")}>
      {hasPromo && (
        <div className="vcard-price-old tabular">
          <span className="moeda">R$</span>{fmtBRL(preco)}
        </div>
      )}
      <div className={"vcard-price tabular" + (hasPromo ? " is-promo" : "")}>
        <span className="moeda">R$</span>{fmtBRL(finalPrice)}
        {hasPromo && <span className="vcard-discount-badge">−{discount}%</span>}
      </div>
    </div>
  );
}

// ----- Vehicle Card v2 -----
function VehicleCard({ vehicle, onClick, featured }) {
  const rawCover = Array.isArray(vehicle.fotos) ? vehicle.fotos[0] : vehicle.fotos;
  const cover = window.optimizeImg ? window.optimizeImg(rawCover, 600, 70) : rawCover;
  const ref = useRef(null);

  // Tilt sutil
  const onMove = (e) => {
    if (!ref.current) return;
    const r = ref.current.getBoundingClientRect();
    const x = (e.clientX - r.left) / r.width - 0.5;
    const y = (e.clientY - r.top) / r.height - 0.5;
    ref.current.style.transform = `translateY(-6px) perspective(1000px) rotateX(${-y * 3}deg) rotateY(${x * 3}deg)`;
  };
  const onLeave = () => { if (ref.current) ref.current.style.transform = ""; };

  return (
    <div className={"vcard" + (featured ? " vcard--featured" : "")} onClick={() => onClick(vehicle)} onMouseMove={onMove} onMouseLeave={onLeave} ref={ref} role="button" tabIndex={0}>
      <div className={"vcard-photo" + (vehicle.status === "vendido" ? " is-sold" : "")}>
        <img src={cover} alt={`${vehicle.marca} ${vehicle.modelo}`} loading="lazy" onError={window.handleImgError} />
        {vehicle.status === "reservado" && (
          <span className="vcard-status-badge is-reserved">Reservado</span>
        )}
        {vehicle.status === "vendido" && (
          <span className="vcard-status-badge is-sold">Vendido</span>
        )}
        {vehicle.novo && vehicle.status === "disponivel" && <span className="vcard-badge">Novo</span>}
        <div className="vcard-cta">
          <span>Ver detalhes</span>
          <Icon.ArrowUpRight size={14} />
        </div>
      </div>
      <div className="vcard-body">
        <div className="vcard-make">{vehicle.marca}</div>
        <div className="vcard-model">{vehicle.modelo}</div>
        <div className="vcard-version">{vehicle.versao}</div>
        <div className="vcard-specs">
          <span className="vcard-spec tabular">{vehicle.ano}</span>
          <span className="vcard-spec tabular">{(vehicle.km/1000).toFixed(0)}k km</span>
          <span className="vcard-spec">{vehicle.cambio}</span>
        </div>
        <div className="vcard-foot">
          <PriceBlock vehicle={vehicle} variant="card" />
          <div className="vcard-go"><Icon.ArrowUpRight size={14} /></div>
        </div>
      </div>
    </div>
  );
}

// ----- Hooks -----
function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll(".reveal:not(.visible), .clip-reveal:not(.visible)");
    if (!els.length) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          e.target.classList.add("visible");
          io.unobserve(e.target);
        }
      });
    }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" });
    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
  });
}

function useCountUp(target, trigger, duration = 1600) {
  const [val, setVal] = useState(0);
  useEffect(() => {
    if (!trigger) return;
    let raf;
    const start = performance.now();
    const num = parseFloat(String(target).replace(/[^\d.]/g, "")) || 0;
    const step = (now) => {
      const t = Math.min(1, (now - start) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      setVal(num * eased);
      if (t < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [target, trigger]);
  return val;
}

// Magnetic hover for buttons
function magnetize(el, strength = 0.3) {
  if (!el || el.dataset.mag) return;
  el.dataset.mag = "1";
  const move = (e) => {
    const r = el.getBoundingClientRect();
    const x = e.clientX - (r.left + r.width / 2);
    const y = e.clientY - (r.top + r.height / 2);
    el.style.transform = `translate(${x * strength}px, ${y * strength}px)`;
  };
  const leave = () => { el.style.transform = ""; };
  el.addEventListener("mousemove", move);
  el.addEventListener("mouseleave", leave);
}

Object.assign(window, { Icon, Logo, Header, Footer, WhatsAppFloat, WAPicker, VehicleCard, PriceBlock, ScrollProgress, fmtBRL, fmtKM, useReveal, useCountUp, magnetize });
