Serving families and businesses across all of Florida with 25+ years of experience, honest pricing, and ice-cold results.
We deliver reliable, affordable service with dedicated support — because your comfort is our business.
We honor our commitments. When we say we'll be there, we mean it — every time, without exception.
Honest diagnostics, transparent pricing. We never upsell what you don't need.
We use top-brand parts and follow best practices on every job, big or small.
We don't just fix AC — we optimize comfort. Every visit leaves your system better than we found it.
One Air Solutions HVAC was founded with one goal: give Florida families and businesses fast, honest AC service they can actually count on.
From a single technician to a full team serving all of South Florida, we've grown by doing one thing right — showing up, being honest, and delivering results.
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: botón A11y a la izquierda */ 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; right: 20px; 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