Full commercial and residential HVAC — installation, repair, and maintenance for offices, retail, warehouses, and multi-unit properties across Florida.
🏢 Commercial & Residential · All Florida · 24/7 Support
Add Photo
Click to upload a photo from our gallery
Add Photo
Click to upload a photo from our gallery
We schedule a free on-site assessment to understand your building's layout, load requirements, and existing systems.
We design a tailored HVAC solution with equipment specs, timeline, and transparent pricing — no cookie-cutter quotes.
Our commercial crew installs your system with minimal disruption to your operations, on schedule and on budget.
We offer maintenance contracts, priority emergency service, and annual reviews to keep your system performing year-round.
en cualquier sitio: * <" + "script src="aaj-widget.js">" + "script> * * No requiere frameworks. Vanilla JS. Preferencias guardadas en localStorage. */ (function () { "use strict"; const STORAGE_KEY = "aaj-web-prefs"; /** * Configuración por sitio. Cada cliente define esto ANTES de cargar * aaj-widget.js, por ejemplo: * * window.AAJ_CONFIG = { * siteId: "cliente-001", * simplifyEndpoint: "https://us-central1-TU-PROYECTO.cloudfunctions.net/aajSimplify" * }; * (luego cargar aaj-widget.js) * * Si no se define simplifyEndpoint, el botón "Simplificar" se oculta. */ const config = Object.assign( { siteId: null, simplifyEndpoint: null }, window.AAJ_CONFIG || {} ); const defaultPrefs = { fontScale: 1, // 1 = 100% lineSpacing: 1, // 1 = normal, 1.5 / 2 = aumentado dyslexiaFont: false, highContrast: false, mode: "default", // "default" | "zen" | "gamer" }; let prefs = loadPrefs(); // ---------- Persistencia ---------- function loadPrefs() { try { const raw = localStorage.getItem(STORAGE_KEY); if (!raw) return { ...defaultPrefs }; return { ...defaultPrefs, ...JSON.parse(raw) }; } catch (e) { return { ...defaultPrefs }; } } function savePrefs() { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(prefs)); } catch (e) { /* almacenamiento no disponible, continuar sin persistencia */ } } // ---------- Estilos ---------- function injectStyles() { const style = document.createElement("style"); style.id = "aaj-web-styles"; style.textContent = ` #aaj-toggle { position: fixed; bottom: 20px; left: 20px; /* CAMBIO 5: Widget A11y movido de right a left */ width: 56px; height: 56px; border-radius: 50%; background: linear-gradient(135deg, #8aff5e, #5ec6ff); border: none; box-shadow: 0 4px 14px rgba(0,0,0,0.25); cursor: pointer; z-index: 2147483000; display: flex; align-items: center; justify-content: center; font-size: 26px; line-height: 1; transition: transform 0.2s ease; } #aaj-toggle:hover { transform: scale(1.08); } #aaj-toggle:focus-visible { outline: 3px solid #222; outline-offset: 2px; } #aaj-panel { position: fixed; bottom: 86px; left: 20px; /* CAMBIO 5: Widget A11y movido de right a left */ width: 300px; max-width: calc(100vw - 40px); max-height: 70vh; overflow-y: auto; background: #14171c; color: #f2f2f2; border-radius: 14px; box-shadow: 0 8px 30px rgba(0,0,0,0.35); font-family: Arial, Helvetica, sans-serif; font-size: 15px; padding: 16px; z-index: 2147483000; display: none; } #aaj-panel.aaj-open { display: block; } #aaj-panel h2 { font-size: 16px; margin: 0 0 12px 0; display: flex; align-items: center; gap: 8px; } #aaj-panel .aaj-section { margin-bottom: 14px; padding-bottom: 14px; border-bottom: 1px solid rgba(255,255,255,0.08); } #aaj-panel .aaj-section:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; } #aaj-panel label { display: block; margin-bottom: 6px; font-weight: bold; } #aaj-panel .aaj-row { display: flex; gap: 8px; flex-wrap: wrap; } #aaj-panel button.aaj-btn { flex: 1; min-width: 60px; padding: 8px 10px; border-radius: 8px; border: 1px solid rgba(255,255,255,0.15); background: #20252d; color: #f2f2f2; cursor: pointer; font-size: 14px; } #aaj-panel button.aaj-btn:hover { background: #2c333d; } #aaj-panel button.aaj-btn.aaj-active { background: #5ec6ff; color: #0a0a0a; border-color: #5ec6ff; font-weight: bold; } #aaj-panel .aaj-toggle-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; } #aaj-panel .aaj-footer { font-size: 11px; opacity: 0.6; text-align: center; margin-top: 4px; } /* ---- Estados aplicados al sitio ---- */ html.aaj-dyslexia-font, html.aaj-dyslexia-font * { font-family: "OpenDyslexic", "Comic Sans MS", Arial, sans-serif !important; } html.aaj-high-contrast, html.aaj-high-contrast body { background: #000 !important; color: #fff !important; } html.aaj-high-contrast a { color: #ffd400 !important; } html.aaj-high-contrast img { filter: grayscale(40%) contrast(1.1); } /* Modo Zen (filtro Franz): tonos suaves, baja saturación */ html.aaj-mode-zen { filter: saturate(0.75) brightness(0.97); } html.aaj-mode-zen, html.aaj-mode-zen body { background-color: #f4f1ec !important; } /* Modo Gamer (filtro Kalman): contraste y saturación elevados */ html.aaj-mode-gamer { filter: saturate(1.25) contrast(1.05); } #aaj-reading-highlight { outline: 2px solid #5ec6ff; outline-offset: 2px; border-radius: 3px; } `; document.head.appendChild(style); } // ---------- UI ---------- function buildUI() { // Botón flotante const toggle = document.createElement("button"); toggle.id = "aaj-toggle"; toggle.type = "button"; toggle.setAttribute("aria-label", "Abrir opciones de accesibilidad AimAndJoy"); toggle.setAttribute("aria-expanded", "false"); toggle.innerHTML = "♿"; // Panel const panel = document.createElement("div"); panel.id = "aaj-panel"; panel.setAttribute("role", "dialog"); panel.setAttribute("aria-label", "Opciones de accesibilidad AimAndJoy"); panel.innerHTML = `
`;
document.body.appendChild(toggle);
document.body.appendChild(panel);
toggle.addEventListener("click", () => {
const isOpen = panel.classList.toggle("aaj-open");
toggle.setAttribute("aria-expanded", String(isOpen));
});
panel.addEventListener("click", handlePanelClick);
return { toggle, panel };
}
// ---------- Lógica de acciones ----------
function handlePanelClick(e) {
const btn = e.target.closest("button[data-action]");
if (!btn) return;
const action = btn.dataset.action;
switch (action) {
case "font-inc":
prefs.fontScale = Math.min(2, +(prefs.fontScale + 0.1).toFixed(2));
break;
case "font-dec":
prefs.fontScale = Math.max(0.8, +(prefs.fontScale - 0.1).toFixed(2));
break;
case "font-reset":
prefs.fontScale = 1;
break;
case "spacing-normal":
prefs.lineSpacing = 1;
break;
case "spacing-comfortable":
prefs.lineSpacing = 1.5;
break;
case "spacing-wide":
prefs.lineSpacing = 2;
break;
case "toggle-dyslexia":
prefs.dyslexiaFont = !prefs.dyslexiaFont;
break;
case "toggle-contrast":
prefs.highContrast = !prefs.highContrast;
break;
case "mode-default":
prefs.mode = "default";
break;
case "mode-zen":
prefs.mode = "zen";
break;
case "mode-gamer":
prefs.mode = "gamer";
break;
case "read-page":
readPageAloud();
return; // no necesita re-render del panel
case "stop-read":
stopReadingAloud();
return;
case "simplify":
simplifyPage(btn);
return;
}
savePrefs();
applyPrefs();
syncPanelState();
}
function applyPrefs() {
const html = document.documentElement;
// Tamaño de texto
html.style.fontSize = (prefs.fontScale * 100) + "%";
// Espaciado de línea
if (prefs.lineSpacing === 1) {
html.style.removeProperty("--aaj-line-height");
document.body.style.removeProperty("line-height");
} else {
document.body.style.lineHeight = String(prefs.lineSpacing);
}
// Fuente para dislexia
html.classList.toggle("aaj-dyslexia-font", !!prefs.dyslexiaFont);
// Alto contraste
html.classList.toggle("aaj-high-contrast", !!prefs.highContrast);
// Modo visual (Zen / Gamer / Original)
html.classList.remove("aaj-mode-zen", "aaj-mode-gamer");
if (prefs.mode === "zen") html.classList.add("aaj-mode-zen");
if (prefs.mode === "gamer") html.classList.add("aaj-mode-gamer");
}
function syncPanelState() {
const panel = document.getElementById("aaj-panel");
if (!panel) return;
const dyslexiaBtn = panel.querySelector("#aaj-dyslexia");
dyslexiaBtn.classList.toggle("aaj-active", !!prefs.dyslexiaFont);
dyslexiaBtn.textContent = prefs.dyslexiaFont ? "Desactivar" : "Activar";
const contrastBtn = panel.querySelector("#aaj-contrast");
contrastBtn.classList.toggle("aaj-active", !!prefs.highContrast);
contrastBtn.textContent = prefs.highContrast ? "Desactivar" : "Activar";
const spacingMap = { 1: "spacing-normal", 1.5: "spacing-comfortable", 2: "spacing-wide" };
highlightGroup(panel, ["spacing-normal", "spacing-comfortable", "spacing-wide"], spacingMap[prefs.lineSpacing]);
const modeMap = { default: "mode-default", zen: "mode-zen", gamer: "mode-gamer" };
highlightGroup(panel, ["mode-default", "mode-zen", "mode-gamer"], modeMap[prefs.mode]);
}
function highlightGroup(panel, actions, activeAction) {
actions.forEach((action) => {
const btn = panel.querySelector(`[data-action="${action}"]`);
if (btn) btn.classList.toggle("aaj-active", action === activeAction);
});
}
// ---------- Lectura en voz alta ----------
function readPageAloud() {
if (!("speechSynthesis" in window)) {
alert("Tu navegador no soporta lectura en voz alta.");
return;
}
stopReadingAloud();
const text = getReadableText();
if (!text.trim()) return;
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = document.documentElement.lang || "es-ES";
window.speechSynthesis.speak(utterance);
}
function stopReadingAloud() {
if ("speechSynthesis" in window) {
window.speechSynthesis.cancel();
}
}
function getReadableText() {
// Extrae texto visible del