/** * SWDG Remote Popup v1 (STABLE) * - Motor único (popup.js) + um JSON por cliente. */ (function () { "use strict"; // ========= Utils ========= const $ = (sel, root = document) => root.querySelector(sel); const $$ = (sel, root = document) => Array.from(root.querySelectorAll(sel)); let SWDG_FLOW_HISTORY = []; let SWDG_FLOW_DATA = {}; let SWDG_FLOW_ORIGINAL_FORM_HTML = ""; let SWDG_FLOW_CURRENT_STEP = ""; // ========= Retorno de visitante (Nível 1) ========= const SWDG_VISITOR_KEY = "swdg_vid"; const SWDG_VISITOR_META_KEY = "swdg_vid_meta"; const SWDG_VISITOR_NAME_KEY = "swdg_known_name"; const SWDG_LEAD_DATA_KEY = "swdg_known_lead"; const SWDG_VISITOR_WINDOW_DAYS = 90; function swdgNowIso() { try { return new Date().toISOString(); } catch (_) { return ""; } } function swdgCreateVisitorId() { return "vid_" + Date.now() + "_" + Math.random().toString(36).slice(2, 10); } function swdgReadStorage(key) { try { return localStorage.getItem(key); } catch (_) { return null; } } function swdgWriteStorage(key, value) { try { localStorage.setItem(key, value); } catch (_) { } } function swdgReadVisitorMeta() { try { const raw = swdgReadStorage(SWDG_VISITOR_META_KEY); if (!raw) return null; const parsed = JSON.parse(raw); return (parsed && typeof parsed === "object") ? parsed : null; } catch (_) { return null; } } function swdgPersistKnownName(name) { const finalName = sanitizeNameFinal ? sanitizeNameFinal(name) : String(name || "").trim(); if (!finalName) return; swdgWriteStorage(SWDG_VISITOR_NAME_KEY, finalName); try { if (window.SWDG_VISITOR && typeof window.SWDG_VISITOR === "object") { window.SWDG_VISITOR.knownName = finalName; } } catch (_) { } } function swdgReadKnownLead() { try { const raw = swdgReadStorage(SWDG_LEAD_DATA_KEY); if (!raw) return null; const parsed = JSON.parse(raw); return (parsed && typeof parsed === "object") ? parsed : null; } catch (_) { return null; } } function swdgNormalizeKnownWhats(value) { return String(value || "").replace(/\D+/g, ""); } function swdgPersistKnownLead(name, whats) { try { const finalName = sanitizeNameFinal ? sanitizeNameFinal(name) : String(name || "").trim(); const finalWhats = swdgNormalizeKnownWhats(whats); if (!finalWhats) return null; const current = swdgReadKnownLead() || null; const sameLead = !!(current && String(current.whats || "") === finalWhats); const lead = { name: finalName || String((current && current.name) || "").trim() || "", whats: finalWhats, contactCount: sameLead ? Math.max(1, Number(current.contactCount || 0) + 1) : 1, firstContactAt: sameLead ? (current.firstContactAt || swdgNowIso()) : swdgNowIso(), lastContactAt: swdgNowIso() }; swdgWriteStorage(SWDG_LEAD_DATA_KEY, JSON.stringify(lead)); try { if (window.SWDG_VISITOR && typeof window.SWDG_VISITOR === "object") { window.SWDG_VISITOR.knownLeadName = lead.name || null; window.SWDG_VISITOR.knownLeadWhats = lead.whats || null; window.SWDG_VISITOR.leadContactCount = lead.contactCount || 0; } } catch (_) { } return lead; } catch (_) { return null; } } function swdgGetKnownLeadData() { const lead = swdgReadKnownLead(); return { known_name: String((lead && lead.name) || "").trim(), known_whats: String((lead && lead.whats) || "").trim(), lead_contact_count: Math.max(0, Number(lead && lead.contactCount ? lead.contactCount : 0)) }; } function swdgInitVisitorTracker() { let vid = swdgReadStorage(SWDG_VISITOR_KEY); let meta = swdgReadVisitorMeta(); const now = new Date(); const nowIso = swdgNowIso(); if (!vid) { vid = swdgCreateVisitorId(); swdgWriteStorage(SWDG_VISITOR_KEY, vid); } const hadSeenBefore = !!(meta && meta.lastSeenAt); const lastSeenMs = hadSeenBefore ? Date.parse(meta.lastSeenAt) : NaN; const windowMs = SWDG_VISITOR_WINDOW_DAYS * 24 * 60 * 60 * 1000; const withinWindow = hadSeenBefore && Number.isFinite(lastSeenMs) && ((now.getTime() - lastSeenMs) <= windowMs); const visitCount = Math.max(1, Number(meta && meta.visitCount ? meta.visitCount : 0) + (hadSeenBefore ? 1 : 0)); const firstSeenAt = (meta && meta.firstSeenAt) ? meta.firstSeenAt : nowIso; const nextMeta = { firstSeenAt, lastSeenAt: nowIso, visitCount }; try { swdgWriteStorage(SWDG_VISITOR_META_KEY, JSON.stringify(nextMeta)); } catch (_) { } const knownName = String(swdgReadStorage(SWDG_VISITOR_NAME_KEY) || "").trim() || null; const knownLead = swdgGetKnownLeadData(); window.SWDG_VISITOR = { vid, isReturning: hadSeenBefore, withinWindow, visitCount, firstSeenAt, lastSeenAt: nowIso, knownName, knownLeadName: knownLead.known_name || null, knownLeadWhats: knownLead.known_whats || null, leadContactCount: knownLead.lead_contact_count || 0 }; } function swdgVisitorShouldShowWelcome() { try { return !!(window.SWDG_VISITOR && window.SWDG_VISITOR.isReturning === true && window.SWDG_VISITOR.withinWindow === true); } catch (_) { return false; } } function swdgGetReturningWelcomeText(fallback) { try { if (!(window.SWDG_VISITOR && window.SWDG_VISITOR.isReturning === true && window.SWDG_VISITOR.withinWindow === true)) { return String(fallback || ""); } const visitCount = Number(window.SWDG_VISITOR.visitCount || 0); if (visitCount >= 4) return "Ainda com dúvidas? Posso te ajudar por aqui 😊"; if (visitCount === 3) return "Vamos continuar seu atendimento?"; if (visitCount === 2) return "Que bom ter você de volta 😊"; return "Que bom ter você de volta 😊"; } catch (_) { return String(fallback || ""); } } function swdgGetReturningContinueText(fallback) { return swdgVisitorShouldShowWelcome() ? "Que bom ter você de volta 😊 Vamos continuar?" : String(fallback || ""); } swdgInitVisitorTracker(); // ========= Randomização (JSON: string OU array) ========= // Permite configurar no JSON: "brandName": "X" OU ["X","Y"], e idem para brandSub/title. function swdgToArray(v) { if (v == null) return []; return Array.isArray(v) ? v.filter((x) => x != null && String(x).trim() !== "") : [v]; } function swdgPickOne(v) { const arr = swdgToArray(v).map((x) => String(x)); if (!arr.length) return ""; return arr[Math.floor(Math.random() * arr.length)]; } // ========= Business Hours (JSON opcional) ========= function swdgParseHHMM(s) { const m = String(s || "").trim().match(/^(\d{1,2}):(\d{2})$/); if (!m) return null; const hh = Math.max(0, Math.min(23, parseInt(m[1], 10))); const mm = Math.max(0, Math.min(59, parseInt(m[2], 10))); return hh * 60 + mm; } function swdgGetBusinessContext(cfg) { // Retorna { mode: "open"|"weekend"|"night"|"closed", message, buttonText } const bh = cfg && cfg.businessHours ? cfg.businessHours : null; if (!bh || bh.enabled !== true) return { mode: "open" }; const now = new Date(); const day = now.getDay(); // 0 dom ... 6 sab const isWeekend = (day === 0 || day === 6); const startMin = swdgParseHHMM(bh.start || "08:00"); const endMin = swdgParseHHMM(bh.end || "18:00"); const nowMin = now.getHours() * 60 + now.getMinutes(); let isOpen = true; if (startMin != null && endMin != null) { // janela no mesmo dia (ex.: 08:00-18:00) isOpen = (nowMin >= startMin && nowMin <= endMin); } if (isWeekend) { return { mode: "weekend", message: bh.weekendMessage || bh.closedMessage || "", closedMessage: bh.closedMessage || "", buttonText: bh.closedButton || "" }; } if (!isOpen) { // Fora do horário em dias úteis: "nightMessage" (ou closedMessage) return { mode: "night", message: bh.nightMessage || bh.closedMessage || "", closedMessage: bh.closedMessage || "", buttonText: bh.closedButton || "" }; } return { mode: "open" }; } // ========= Theme (JSON opcional) ========= // Ex.: "theme": { "primary":"#0c2c46", "secondary":"#ffd400", "button":"#1fd25c", "buttonHover":"#12a243", "pulse": true } function swdgIsHexColor(v) { const s = String(v || "").trim(); return /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(s); } function swdgHexToRgb(hex) { const h = String(hex || "").trim().replace("#", ""); const full = (h.length === 3) ? (h[0] + h[0] + h[1] + h[1] + h[2] + h[2]) : h; if (!/^[0-9a-fA-F]{6}$/.test(full)) return null; const r = parseInt(full.slice(0, 2), 16); const g = parseInt(full.slice(2, 4), 16); const b = parseInt(full.slice(4, 6), 16); return { r, g, b }; } function swdgDarkenHex(hex, amount) { const rgb = swdgHexToRgb(hex); if (!rgb) return ""; const clamp = (n) => Math.max(0, Math.min(255, n)); const r = clamp(Math.round(rgb.r * (1 - amount))); const g = clamp(Math.round(rgb.g * (1 - amount))); const b = clamp(Math.round(rgb.b * (1 - amount))); return "#" + [r, g, b].map(x => x.toString(16).padStart(2, "0")).join(""); } function swdgBuildThemeBackground(mode, c1, c2, angle, split) { const color1 = swdgIsHexColor(c1) ? c1 : "#062033"; const color2 = swdgIsHexColor(c2) ? c2 : swdgDarkenHex(color1, 0.22) || "#072235"; const a = Number.isFinite(+angle) ? +angle : 135; const s = Number.isFinite(+split) ? Math.max(0, Math.min(90, +split)) : 36; const m = String(mode || "").toLowerCase(); if (m === "radial") { return `radial-gradient(circle at 18% 10%, ${color1} 0%, ${color1} ${s}%, ${color2} 100%)`; } if (m === "solid") { return color1; } return `linear-gradient(${a}deg, ${color1} 0%, ${color1} ${s}%, ${color2} 100%)`; } function swdgBuildTopBar(mode, c1, c2) { const color1 = swdgIsHexColor(c1) ? c1 : "#ffd400"; const color2 = swdgIsHexColor(c2) ? c2 : "#fff2a8"; const m = String(mode || "").toLowerCase(); if (m === "solid") return color1; if (m === "none" || m === "off" || m === "disabled") return "transparent"; return `linear-gradient(90deg, rgba(255,255,255,0), ${color1}, ${color2}, rgba(255,255,255,0))`; } function swdgApplyTheme(root, cfg) { const t = (cfg && cfg.theme) ? cfg.theme : null; if (!t) return; const primary = swdgIsHexColor(t.primary) ? t.primary : "#0c2c46"; const textPrimary = swdgIsHexColor(t.textPrimary) ? t.textPrimary : (swdgIsHexColor(t.textOnPrimary) ? t.textOnPrimary : "#ffffff"); const textAccent = swdgIsHexColor(t.textAccent) ? t.textAccent : (swdgIsHexColor(t.secondary) ? t.secondary : "#ffd400"); const button = swdgIsHexColor(t.button) ? t.button : "#1fd25c"; const bgColor1 = swdgIsHexColor(t.bgColor1) ? t.bgColor1 : primary; const bgColor2 = swdgIsHexColor(t.bgColor2) ? t.bgColor2 : (swdgIsHexColor(t.secondary) ? swdgDarkenHex(primary, 0.18) || primary : swdgDarkenHex(primary, 0.18) || primary); const topBarColor1 = swdgIsHexColor(t.topBarColor1) ? t.topBarColor1 : textAccent; const topBarColor2 = swdgIsHexColor(t.topBarColor2) ? t.topBarColor2 : "#fff2a8"; const inputBorderColor = swdgIsHexColor(t.inputBorderColor) ? t.inputBorderColor : textAccent; root.style.setProperty("--swdg-primary", primary); root.style.setProperty("--swdg-primaryDark", swdgDarkenHex(primary, 0.20) || primary); root.style.setProperty("--swdg-primaryDarker", swdgDarkenHex(primary, 0.35) || primary); root.style.setProperty("--swdg-secondary", textAccent); root.style.setProperty("--swdg-button", button); if (swdgIsHexColor(t.buttonHover)) root.style.setProperty("--swdg-buttonHover", t.buttonHover); root.style.setProperty("--swdg-textOnPrimary", textPrimary); root.style.setProperty("--swdg-textAccent", textAccent); root.style.setProperty("--swdg-inputBorderColor", inputBorderColor); root.style.setProperty("--swdg-bg", swdgBuildThemeBackground(t.bgMode, bgColor1, bgColor2, parseInt(t.bgAngle || 135, 10), parseInt(t.bgSplit ?? 36, 10))); root.style.setProperty("--swdg-topbar", swdgBuildTopBar(t.topBarMode, topBarColor1, topBarColor2)); const pulseRgb = swdgHexToRgb(button); if (pulseRgb) root.style.setProperty("--swdg-pulseRgb", `${pulseRgb.r}, ${pulseRgb.g}, ${pulseRgb.b}`); const pulse = (t.pulse === true); root.setAttribute("data-swdg-pulse", pulse ? "1" : "0"); root.setAttribute("data-swdg-glow", t.cardGlow === false ? "0" : "1"); root.setAttribute("data-swdg-whats-icon", t.whatsIcon === false ? "0" : "1"); } // ========= IP (public) ========= // Captura IP público via ipify (frontend não tem acesso direto ao IP real). // - Prefetch em background (não atrasa Whats/GTM) // - Cache em memória para reutilizar nas próximas aberturas/envios let SWDG_CACHED_IP = ""; let SWDG_IP_PROMISE = null; function swdgPrefetchIP() { if (SWDG_CACHED_IP) return Promise.resolve(SWDG_CACHED_IP); if (SWDG_IP_PROMISE) return SWDG_IP_PROMISE; SWDG_IP_PROMISE = fetch("https://api.ipify.org?format=json", { cache: "no-store", credentials: "omit" }) .then((r) => (r && r.ok ? r.json() : null)) .then((j) => (j && j.ip ? String(j.ip) : "")) .catch(() => "") .then((ip) => { SWDG_CACHED_IP = ip || ""; return SWDG_CACHED_IP; }) .finally(() => { // mantém promise para evitar múltiplas chamadas em curto intervalo // (não reseta aqui) }); return SWDG_IP_PROMISE; } // ========= GEO/DDD (sugestão opcional) ========= // IMPORTANTE: nunca força nada. Apenas sugere e o usuário escolhe. let SWDG_GEO_CACHE = null; // { country, region, city } let SWDG_GEO_PROMISE = null; let SWDG_SUGGESTED_DDD = ""; // "41", "11", etc. let SWDG_DDD_HINT_DISMISSED = false; // por sessão (memória) function swdgStripAccents(str) { try { return String(str || "").normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } catch (_) { return String(str || ""); } } function swdgPrefetchGeo() { if (SWDG_GEO_CACHE) return Promise.resolve(SWDG_GEO_CACHE); if (SWDG_GEO_PROMISE) return SWDG_GEO_PROMISE; SWDG_GEO_PROMISE = swdgPrefetchIP() .then((ip) => { // ipapi.co aceita /json/ (auto) ou /{ip}/json/ const url = ip ? ("https://ipapi.co/" + encodeURIComponent(ip) + "/json/") : "https://ipapi.co/json/"; return fetch(url, { cache: "no-store", credentials: "omit" }).then(r => (r && r.ok ? r.json() : null)).catch(() => null); }) .then((j) => { if (!j) return null; const country = (j.country || j.country_code || "").toString().toUpperCase(); const region = (j.region_code || j.region || j.state || "").toString(); const city = (j.city || "").toString(); return { country, region, city }; }) .catch(() => null) .then((geo) => { SWDG_GEO_CACHE = geo; return geo; }); return SWDG_GEO_PROMISE; } function swdgComputeSuggestedDDD(geo) { if (!geo || geo.country !== "BR") return ""; // 1) Mapa por cidade (mais preciso) const cityKey = swdgStripAccents((geo.city || "").trim().toLowerCase()); const cityDDD = { "curitiba": "41", "sao paulo": "11", "saopaulo": "11", "rio de janeiro": "21", "riodejaneiro": "21", "porto alegre": "51", "portoalegre": "51", "ijui": "55", "ijuí": "55", "santa maria": "55", "santamaria": "55", "uruguaiana": "55", "santa rosa": "55", "santarosa": "55", "passo fundo": "54", "passofundo": "54" }; if (cityKey && cityDDD[cityKey]) return cityDDD[cityKey]; // 2) Fallback por UF (chute conservador, capital) — sempre opcional const uf = (geo.region || "").toString().trim().toUpperCase(); const ufDefault = { "PR": "41", "SP": "11", "RJ": "21", "RS": "51", "SC": "48", "MG": "31", "BA": "71", "DF": "61", "GO": "62", "PE": "81", "CE": "85" }; return ufDefault[uf] || ""; } function swdgPrefetchSuggestedDDD() { if (SWDG_SUGGESTED_DDD) return Promise.resolve(SWDG_SUGGESTED_DDD); return swdgPrefetchGeo().then((geo) => { SWDG_SUGGESTED_DDD = swdgComputeSuggestedDDD(geo) || ""; return SWDG_SUGGESTED_DDD; }); } // tenta pegar o IP já no carregamento (fire-and-forget) try { swdgPrefetchIP(); swdgPrefetchGeo(); swdgPrefetchSuggestedDDD(); } catch (_) { } function findThisScript() { const scripts = $$("script[data-swdg-client]"); return scripts[scripts.length - 1] || null; } function qsAny(keys) { try { const url = String(location.href || ""); const search = String(location.search || ""); const params = new URLSearchParams(search); // case-insensitive lookup (URLSearchParams is case-sensitive) const lowerMap = {}; for (const [k, v] of params.entries()) lowerMap[String(k).toLowerCase()] = v; for (const k of keys) { const kk = String(k).trim(); if (!kk) continue; let v = params.get(kk); if (v == null) v = lowerMap[kk.toLowerCase()]; if (v && String(v).trim() !== "") return String(v).trim(); } // fallback: sometimes params appear after # or in full URL copies for (const k of keys) { const kk = String(k).trim(); if (!kk) continue; const re1 = new RegExp(`[?&#]${kk}=([^&#]+)`, "i"); const m = url.match(re1); if (m && m[1]) { try { return decodeURIComponent(m[1].replace(/\+/g, "%20")).trim(); } catch { return String(m[1]).trim(); } } } } catch (_) { } return ""; } function swdgNormalizeCourseParamValue(value) { try { let v = String(value || "").trim(); if (!v) return ""; v = v.replace(/[\r\n\t]+/g, " ").replace(/\s{2,}/g, " ").trim(); if (!v) return ""; if (String(v).includes("────")) return ""; if (/^[a-z0-9]+(?:[-_][a-z0-9]+)+$/i.test(v)) { v = v .replace(/[-_]+/g, " ") .replace(/\s{2,}/g, " ") .trim() .replace(/\b\w/g, (m) => m.toUpperCase()); } return v; } catch (_) { return ""; } } function swdgGetCourseFromUrl() { const raw = qsAny(["curso_nome", "cursolista", "curso", "cursointeresse"]); return swdgNormalizeCourseParamValue(raw); } function deviceLabel() { return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent) ? "Mobile" : "Desktop"; } function nowBR() { const d = new Date(); const p = (n) => String(n).padStart(2, "0"); return `${p(d.getDate())}/${p(d.getMonth() + 1)}/${d.getFullYear()} ${p(d.getHours())}:${p( d.getMinutes() )}:${p(d.getSeconds())}`; } function digitsOnly(s) { return String(s || "").replace(/\D/g, ""); } // Normaliza telefone vindo de autofill (ex.: +55DD9XXXXXXXX) e evita truncar o final. function normalizePhoneDigits(raw) { let d = digitsOnly(raw); // Autofill costuma vir em formato internacional: +55 + DDD + número (13 dígitos) // Mantemos apenas DDD + número (11 dígitos) if (d.length > 11 && d.startsWith("55")) d = d.slice(2); // Alguns teclados colocam um 0 na frente if (d.length > 11 && d.startsWith("0")) d = d.slice(1); // Se ainda vier maior, pega os últimos 11 (mais seguro que cortar o final) if (d.length > 11) d = d.slice(-11); return d; } function applyPhoneMask(input) { let v = normalizePhoneDigits(input.value).slice(0, 11); if (v.length <= 2) input.value = v ? `(${v}` : ""; else if (v.length <= 7) input.value = `(${v.slice(0, 2)}) ${v.slice(2)}`; else input.value = `(${v.slice(0, 2)}) ${v.slice(2, 7)}-${v.slice(7)}`; } function isValidFullBRPhoneMasked(v) { const s = String(v || "").trim(); if (!/^\(\d{2}\)\s\d{5}-\d{4}$/.test(s)) return false; // Regra Whats Brasil: DDD (2) + celular (9 + 8 dígitos) = 11 const d = digitsOnly(s); if (d.length !== 11) return false; // Todo celular BR (Whats) começa com 9 após o DDD → bloqueia casos tipo (55) 47999-9065 if (d[2] !== "9") return false; return true; } function isValidEmail(v) { const s = String(v || "").trim(); if (!s) return false; // validação simples (suficiente p/ captura de lead) return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(s); } // Nome: letras + espaço + hífen + apóstrofo (permite espaço ao vivo) function sanitizeNameLive(raw) { let s = String(raw || ""); s = s.replace(/[^A-Za-zÀ-ÖØ-öø-ÿ\s'-]/g, ""); s = s.replace(/\s{2,}/g, " "); return s; } function sanitizeNameFinal(raw) { return sanitizeNameLive(raw).replace(/\s+/g, " ").trim(); } function buildInfo() { const pairs = [ ["utm_source", qsAny(["utm_source"])], ["utm_medium", qsAny(["utm_medium"])], ["utm_campaign", qsAny(["utm_campaign", "campaign", "campanha"])], ["utm_term", qsAny(["utm_term", "keyword", "termo", "palavra"])], ["utm_content", qsAny(["utm_content"])], ["gclid", qsAny(["gclid"])], ["wbraid", qsAny(["wbraid"])], ["gbraid", qsAny(["gbraid"])], ]; return pairs.map(([k, v]) => `${k}=${v || ""}`).join(" | ") + ` | ua=${navigator.userAgent}`; } async function safeJsonFetch(url) { const res = await fetch(url, { cache: "no-store", credentials: "omit" }); if (!res.ok) throw new Error(`Config HTTP ${res.status}`); return await res.json(); } // ========= Bootstrap: script e config ========= const scriptEl = findThisScript(); if (!scriptEl) return; const clientId = (scriptEl.getAttribute("data-swdg-client") || "").trim(); if (!clientId) return; const scriptSrc = scriptEl.src; const baseUrl = scriptSrc.substring(0, scriptSrc.lastIndexOf("/") + 1); const configUrl = `${baseUrl}config/${encodeURIComponent(clientId)}.json`; let CONFIG = null; let mounted = false; let SWDG_OPEN_MODE = "default"; // "default" | "entry" // ========= UI ========= const STYLE_ID = "swdg-popup-style-v1"; const ROOT_ID = "swdg-popup-root-v1"; let SWDG_POPUP_HOST = null; let SWDG_POPUP_SHADOW = null; function getPopupHost() { return SWDG_POPUP_HOST || document.getElementById(ROOT_ID); } function getPopupShadow() { const host = getPopupHost(); return SWDG_POPUP_SHADOW || (host && host.shadowRoot) || null; } function getPopupRoot() { const shadow = getPopupShadow(); return shadow ? shadow.getElementById(ROOT_ID) : null; } function injectStyles(scope) { if (!scope) return; if (scope.getElementById && scope.getElementById(STYLE_ID)) return; const css = ` :host{ all: initial; font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif; color: initial; } :host, :host *{ box-sizing: border-box; } /* ====== PREMIUM SKIN (substitua o CSS do injectStyles por este) ====== */ .swdg-overlay{ position:fixed; inset:0; display:none; align-items:center; justify-content:center; z-index:999999; font-family:Inter,system-ui,Arial; padding:16px; } .swdg-overlay[aria-hidden="false"]{ display:flex; } .swdg-overlay::before{ content:""; position:absolute; inset:0; background: radial-gradient(circle at 20% 10%, rgba(255,255,255,.10), transparent 34%), radial-gradient(circle at 80% 0%, rgba(255,212,0,.08), transparent 28%), rgba(3,8,16,.68); backdrop-filter: blur(14px) saturate(120%); -webkit-backdrop-filter: blur(14px) saturate(120%); } /* animação suave */ .swdg-modal{ position:relative; width:min(440px, calc(100vw - 32px)); max-width:calc(100vw - 32px); box-sizing:border-box; border-radius:22px; overflow:visible; max-height:92vh; display:flex; flex-direction:column; margin:0 auto; border:1px solid rgba(255,255,255,.10); background: radial-gradient(circle at 14% 0%, rgba(255,255,255,.10), transparent 32%), radial-gradient(circle at 86% 8%, rgba(255,255,255,.06), transparent 36%), var(--swdg-bg, linear-gradient(180deg, var(--swdg-primaryDarker, #062033) 0%, var(--swdg-primaryDark, #072235) 100% )); backdrop-filter:blur(20px) saturate(130%); -webkit-backdrop-filter:blur(20px) saturate(130%); box-shadow: 0 36px 100px rgba(0,0,0,.62), 0 10px 28px rgba(0,0,0,.28), 0 0 0 1px rgba(255,255,255,.03); transform: translateY(8px) scale(.982); opacity:0; transition: transform .22s ease, opacity .22s ease, box-shadow .22s ease; } .swdg-overlay[aria-hidden="false"] .swdg-modal{ transform: translateY(0) scale(1); opacity:1; } #swdg-popup-root-v1[data-swdg-glow="1"] .swdg-modal{ box-shadow: 0 36px 100px rgba(0,0,0,.62), 0 10px 28px rgba(0,0,0,.28), 0 0 38px rgba(255,255,255,.06); } /* barra “premium” no topo */ .swdg-modal::before{ content:""; position:absolute; left:14px; right:14px; top:0; height:3px; background: var(--swdg-topbar, linear-gradient(90deg, rgba(255,212,0,0), rgba(255,212,0,.95), rgba(255,255,255,.35), rgba(255,212,0,0))); opacity:.95; border-radius:999px; } .swdg-modal::after{ content:""; position:absolute; inset:1px; border-radius:23px; pointer-events:none; box-shadow: inset 0 1px 0 rgba(255,255,255,.08); } .swdg-close{ position:absolute; top:14px; right:14px; width:40px; height:40px; border-radius:13px; display:flex; align-items:center; justify-content:center; line-height:1; border:1px solid rgba(255,255,255,.16); background:linear-gradient(180deg, rgba(255,255,255,.12), rgba(255,255,255,.06)); color: var(--swdg-textOnPrimary, #fff); font-size:22px; cursor:pointer; box-shadow: 0 10px 22px rgba(0,0,0,.18); transition: transform .12s ease, background .18s ease, border-color .18s ease, box-shadow .18s ease; } .swdg-close:hover{ background:linear-gradient(180deg, rgba(255,255,255,.18), rgba(255,255,255,.09)); border-color:rgba(255,255,255,.28); box-shadow: 0 14px 28px rgba(0,0,0,.24); } .swdg-close:active{ transform: scale(.96); } /* ========================= BADGE (imagem/selo) — JSON: badge{enabled,mode,src,alt,position,size} ========================= */ .swdg-badge{ position:absolute; width: var(--swdg-badge-size, 156px); height: var(--swdg-badge-size, 156px); z-index: 6; pointer-events:none; filter: drop-shadow(0 18px 30px rgba(0,0,0,.42)); } .swdg-badge img{ width:100%; height:100%; display:block; object-fit:contain; } .swdg-badge--top-left{ top: var(--swdg-badge-offset, -18px); left: var(--swdg-badge-offset, -18px); } .swdg-badge--top-right{ top: var(--swdg-badge-offset, -18px); right: var(--swdg-badge-offset, -18px); } .swdg-badge--bottom-left{ bottom: var(--swdg-badge-offset, -18px); left: var(--swdg-badge-offset, -18px); } .swdg-badge--bottom-right{ bottom: var(--swdg-badge-offset, -18px); right: var(--swdg-badge-offset, -18px); } @media (max-width:520px){ .swdg-badge{ width: min(var(--swdg-badge-size, 156px), 142px); height: min(var(--swdg-badge-size, 156px), 142px); } .swdg-badge--top-left, .swdg-badge--top-right, .swdg-badge--bottom-left, .swdg-badge--bottom-right{ --swdg-badge-offset: -12px; } } /* ========================= FASE 2 — Reset interno + header premium consistente ========================= */ :host{ color-scheme: light; } #swdg-popup-root-v1, #swdg-popup-root-v1 *, #swdg-popup-root-v1 *::before, #swdg-popup-root-v1 *::after{ box-sizing:border-box; } #swdg-popup-root-v1{ font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif; line-height:1.35; text-size-adjust:100%; -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale; } #swdg-popup-root-v1 h1, #swdg-popup-root-v1 h2, #swdg-popup-root-v1 h3, #swdg-popup-root-v1 h4, #swdg-popup-root-v1 h5, #swdg-popup-root-v1 h6, #swdg-popup-root-v1 p, #swdg-popup-root-v1 figure, #swdg-popup-root-v1 blockquote{ margin:0; } #swdg-popup-root-v1 img, #swdg-popup-root-v1 svg{ display:block; max-width:100%; height:auto; } #swdg-popup-root-v1 button, #swdg-popup-root-v1 input, #swdg-popup-root-v1 select, #swdg-popup-root-v1 textarea{ font:inherit; letter-spacing:normal; } /* header mais “marca”, com estrutura previsível */ .swdg-header{ padding:26px 22px 18px; text-align:center; background: linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,0)); border-bottom: 1px solid rgba(255,255,255,.08); } .swdg-headerBlock{ width:100%; display:flex; flex-direction:column; align-items:center; justify-content:flex-start; gap:9px; } .swdg-logoRow{ width:100%; display:flex; justify-content:center; align-items:center; padding:0 48px; margin:0; min-height:90px; } .swdg-logoImg{ height:84px !important; max-height:124px !important; width:auto !important; max-width:min(230px, 74vw) !important; object-fit:contain !important; filter: drop-shadow(0 12px 26px rgba(0,0,0,.26)); margin:0 !important; } .swdg-headings{ width:100%; max-width:430px; display:flex; flex-direction:column; align-items:center; justify-content:flex-start; gap:5px; text-align:center; } .swdg-brandName, .swdg-sub, .swdg-title{ display:block; width:100%; text-align:center; margin:0; float:none !important; text-wrap:balance; } .swdg-brandName{ color: var(--swdg-textOnPrimary, #fff); font-weight:900; font-size:21px; line-height:1.04; letter-spacing:.18px; text-shadow: 0 2px 12px rgba(0,0,0,.18); } .swdg-sub{ color: var(--swdg-textAccent, #ffd84d) !important; font-weight:800; font-size:12.5px; line-height:1.2; letter-spacing:.6px; text-transform:uppercase; text-shadow: 0 2px 10px rgba(0,0,0,.15); } .swdg-title{ color: var(--swdg-textOnPrimary, #fff); font-size:19px; font-weight:850; line-height:1.13; letter-spacing:.18px; max-width:410px; text-shadow: 0 4px 16px rgba(0,0,0,.18); } /* blindagem extra contra CSS global do tema / page builder */ #swdg-popup-root-v1 .swdg-header{ text-align:center !important; } #swdg-popup-root-v1 .swdg-headerBlock, #swdg-popup-root-v1 .swdg-logoRow, #swdg-popup-root-v1 .swdg-headings{ display:flex !important; flex-direction:column !important; justify-content:flex-start !important; align-items:center !important; align-content:center !important; text-align:center !important; width:100% !important; } #swdg-popup-root-v1 .swdg-logoRow{ padding-left:52px !important; padding-right:52px !important; gap:0 !important; } #swdg-popup-root-v1 .swdg-logoRow > *{ margin-left:auto !important; margin-right:auto !important; } #swdg-popup-root-v1 .swdg-logoImg{ display:block !important; float:none !important; } #swdg-popup-root-v1 .swdg-brandName, #swdg-popup-root-v1 .swdg-sub, #swdg-popup-root-v1 .swdg-title{ margin-left:auto !important; margin-right:auto !important; } #swdg-popup-root-v1 .swdg-header h1, #swdg-popup-root-v1 .swdg-header h2, #swdg-popup-root-v1 .swdg-header h3, #swdg-popup-root-v1 .swdg-header p, #swdg-popup-root-v1 .swdg-header div{ text-align:center !important; } /* form mais claro (como seu exemplo) */ .swdg-form{ padding:18px 20px 20px; display:grid; gap:13px; /* mantém o fundo contínuo do modal (sem “bloco” separado aqui) */ background: transparent; flex:1 1 auto; overflow:auto; -webkit-overflow-scrolling: touch; } .swdg-header{ flex:0 0 auto; } .swdg-form input[type="text"], .swdg-form input[type="tel"], .swdg-form input[type="email"], .swdg-form select{ width:100%; min-height:50px; padding:14px 14px; border-radius:15px; border:1.5px solid color-mix(in srgb, var(--swdg-inputBorderColor, var(--swdg-textAccent, #ffd84d)) 72%, rgba(11,25,38,.18) 28%); background: linear-gradient(180deg, rgba(255,255,255,.985), rgba(255,255,255,.955)); outline:none; font-size:14px; font-weight:600; color:#0b2233; box-shadow: 0 14px 30px rgba(0,0,0,.14); transition: transform .12s ease, border-color .18s ease, box-shadow .18s ease, background .18s ease; } .swdg-form input:focus, .swdg-form select:focus{ border-color: color-mix(in srgb, var(--swdg-inputBorderColor, var(--swdg-textAccent, #ffd84d)) 72%, white 28%); box-shadow: 0 18px 40px rgba(0,0,0,.20), 0 0 0 4px color-mix(in srgb, var(--swdg-inputBorderColor, var(--swdg-textAccent, #ffd84d)) 18%, transparent); transform: translateY(-1px); background: rgba(255,255,255,1); } .swdg-form input::placeholder{ color:rgba(11,34,51,.46); font-weight:500; } /* consent mais elegante */ /* DDD hint (sugestão opcional) */ .swdg-ddd-hint{ margin-top: -25px; padding: 10px 12px; border-radius: 12px; border: 1px solid rgba(255,255,255,.10); background: rgba(255,255,255,.06); color: rgba(255,255,255,.92); font-size: 11px; line-height: 1.25; display: flex; align-items: center; justify-content: space-between; gap: 10px; } .swdg-ddd-hint-text{ flex: 1; } .swdg-ddd-hint-actions{ display:flex; gap:8px; } .swdg-ddd-btn{ appearance:none; border: 1px solid rgba(255,255,255,.14); background: rgba(0,0,0,.18); color: rgba(255,255,255,.92); border-radius: 10px; padding: 8px 10px; font-weight: 700; font-size: 12px; cursor: pointer; transition: transform .12s ease, filter .12s ease; } .swdg-ddd-btn:hover{ filter: brightness(1.08); transform: translateY(-1px); } .swdg-ddd-btn:active{ transform: translateY(0px) scale(.99); } .swdg-consent{ display:flex; align-items:center; gap:12px; padding:11px 13px; border-radius:15px; background: linear-gradient(180deg, rgba(255,255,255,.085), rgba(255,255,255,.05)); border:1px solid rgba(255,255,255,.11); box-shadow: inset 0 1px 0 rgba(255,255,255,.04); color: rgba(255,255,255,.92); font-size:12px; line-height:1.3; cursor:pointer; user-select:none; } .swdg-consent > span:not(.swdg-checkWrap){ flex:1 1 auto; min-width:0; } .swdg-checkWrap{ position:relative; width:46px; height:26px; flex:0 0 46px; margin-left:auto; } .swdg-checkWrap input{ position:absolute; inset:0; opacity:0; cursor:pointer; z-index:2; } .swdg-checkUi{ position:absolute; inset:0; border-radius:999px; background: rgba(255,255,255,.12); border:1px solid rgba(255,255,255,.22); box-shadow: inset 0 1px 2px rgba(0,0,0,.22); transition: background .22s ease, border-color .22s ease, box-shadow .22s ease; } .swdg-checkUi::after{ content:""; position:absolute; left:3px; top:3px; width:18px; height:18px; border-radius:50%; background: #ffffff; box-shadow: 0 2px 8px rgba(0,0,0,.28); transition: transform .22s ease; } .swdg-checkWrap input:checked + .swdg-checkUi{ background: linear-gradient(180deg, #25d366, #18b955); border-color: rgba(37,211,102,.95); box-shadow: 0 0 0 3px rgba(37,211,102,.12), inset 0 1px 0 rgba(255,255,255,.16); } .swdg-checkWrap input:checked + .swdg-checkUi::after{ transform: translateX(20px); } /* CTA mais “premium” */ .swdg-btn{ margin-top:8px; min-height:50px; padding:16px 18px; border-radius:17px; border:0; cursor:pointer; position:relative; overflow:hidden; background: linear-gradient(180deg, var(--swdg-button, var(--swdg-button, #22e36a)) 0%, var(--swdg-button, var(--swdg-button, #22e36a)) 18%, var(--swdg-buttonHover, var(--swdg-buttonHover, #10b455)) 100%); color: var(--swdg-textOnPrimary, #fff); font-weight:900; letter-spacing:.72px; font-size:14px; text-transform:uppercase; box-shadow: 0 22px 50px rgba(0,0,0,.34), inset 0 1px 0 rgba(255,255,255,.18); transition: transform .12s ease, filter .18s ease, box-shadow .18s ease; display:inline-flex; align-items:center; justify-content:center; gap:10px; } .swdg-btn::before{ content:""; position:absolute; inset:0 auto 0 -22%; width:42%; background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.16), rgba(255,255,255,0)); transform: skewX(-22deg); opacity:.75; } .swdg-btn .swdg-btn-icon{ width:18px; height:18px; display:inline-block; flex:0 0 18px; } #swdg-popup-root-v1[data-swdg-whats-icon="0"] .swdg-btn .swdg-btn-icon{ display:none; } .swdg-btn:hover{ filter: brightness(1.03); transform: translateY(-1px); box-shadow: 0 26px 58px rgba(0,0,0,.36), inset 0 1px 0 rgba(255,255,255,.2); } .swdg-btn:active{ transform: translateY(0) scale(.988); } .swdg-btn:focus-visible{ outline:none; box-shadow: 0 0 0 4px color-mix(in srgb, var(--swdg-textAccent, #ffd84d) 18%, transparent), 0 22px 50px rgba(0,0,0,.34), inset 0 1px 0 rgba(255,255,255,.18); } /* ===== FLOW BUTTON STYLES ===== */ .swdg-flow-btn-primary{ background: linear-gradient(180deg, var(--swdg-button, #22e36a) 0%, var(--swdg-button, #22e36a) 18%, var(--swdg-buttonHover, #10b455) 100%) !important; color: var(--swdg-textOnPrimary, #fff) !important; border: 1px solid rgba(255,255,255,.08) !important; box-shadow: 0 20px 46px rgba(0,0,0,.34), inset 0 1px 0 rgba(255,255,255,.18) !important; } .swdg-flow-btn-primary:hover{ filter: brightness(1.04) !important; transform: translateY(-1px); } .swdg-btn-secondary{ background: linear-gradient(180deg, rgba(255,255,255,.11) 0%, rgba(255,255,255,.08) 100%) !important; border: 1px solid rgba(255,255,255,.18) !important; color: rgba(255,255,255,.92) !important; box-shadow: inset 0 1px 0 rgba(255,255,255,.08), 0 10px 24px rgba(0,0,0,.18) !important; } .swdg-btn-secondary::before{ opacity: .28 !important; } .swdg-btn-secondary:hover{ filter: brightness(1.02) !important; box-shadow: inset 0 1px 0 rgba(255,255,255,.10), 0 14px 28px rgba(0,0,0,.22) !important; } .swdg-flow-actions .swdg-btn + .swdg-btn{ margin-top: 12px; } /* ===== FLOW PREMIUM SAFE ===== */ .swdg-btn-ghost{ appearance:none; border:none; background:transparent !important; box-shadow:none !important; color:rgba(255,255,255,.82) !important; font-weight:700; font-size:14px; letter-spacing:.01em; padding:6px 4px 0; margin:8px auto 0; min-height:auto; width:auto; display:inline-flex; align-items:center; justify-content:center; gap:6px; text-transform:none; } .swdg-btn-ghost::before{ display:none !important; } .swdg-btn-ghost:hover{ transform:none !important; filter:none !important; box-shadow:none !important; color:#fff !important; opacity:.96; } .swdg-btn-ghost:focus-visible{ outline:none; box-shadow:none !important; text-decoration:underline; } .swdg-card{ animation:swdgFlowFade .20s ease; } @keyframes swdgFlowFade{ from{ opacity:.0; transform:translateY(6px); } to{ opacity:1; transform:translateY(0); } } .swdg-card .swdg-title{ font-size: clamp(28px, 4.2vw, 34px); line-height:1.12; letter-spacing:-.02em; } .swdg-card .swdg-sub{ opacity:.92; max-width: 34ch; margin-left:auto; margin-right:auto; } /* ===== FLOW PREMIUM PLUS ===== */ #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-headings .swdg-brandName, #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-headings .swdg-sub, #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-headings .swdg-title{ display:none !important; } #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-header{ padding-bottom:8px; } #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-headerBlock{ gap:8px; } #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-logoRow{ margin-bottom:0; } #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-logoImg{ max-height:54px; width:auto; object-fit:contain; } #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-form{ gap:12px; } .swdg-flow-step{ display:grid; gap:12px; animation:swdgFlowPremiumIn .24s ease; } @keyframes swdgFlowPremiumIn{ from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:translateY(0); } } .swdg-flow-meta{ display:grid; gap:10px; } .swdg-flow-progress{ display:grid; gap:7px; } .swdg-flow-progressTop{ display:flex; align-items:center; justify-content:space-between; gap:10px; } .swdg-flow-kicker{ color: color-mix(in srgb, var(--swdg-textAccent, #ffd84d) 82%, white 18%); font-size:11px; font-weight:900; text-transform:uppercase; letter-spacing:.08em; } .swdg-flow-stepCount{ color:rgba(255,255,255,.72); font-size:11px; font-weight:700; } .swdg-flow-progressBar{ position:relative; height:6px; border-radius:999px; overflow:hidden; background:rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.08); } .swdg-flow-progressFill{ position:absolute; inset:0 auto 0 0; border-radius:999px; background:linear-gradient(90deg, color-mix(in srgb, var(--swdg-textAccent, #ffd84d) 88%, white 12%), color-mix(in srgb, var(--swdg-button, #25d366) 78%, white 22%)); box-shadow:0 0 20px color-mix(in srgb, var(--swdg-textAccent, #ffd84d) 22%, transparent); } .swdg-flow-question{ margin:2px 0 0; color:var(--swdg-textOnPrimary, #fff); font-size:clamp(24px, 4.2vw, 24px); font-weight:900; line-height:1.08; letter-spacing:-.03em; text-align:center; text-wrap:balance; } .swdg-flow-copy{ color:rgba(255,255,255,.82); font-size:13px; line-height:1.6; text-align:center; max-width:100%; margin:-10px auto 14px; text-wrap:normal; } .swdg-flow-actions{ display:grid; gap:10px; margin-top:4px; } .swdg-flow-actions .swdg-btn{ width:100%; margin-top:0; } .swdg-btn-ghost{ margin:2px auto 0; font-size:12.5px; color:rgba(255,255,255,.72) !important; } .swdg-btn-ghost:hover{ color:#fff !important; } #whatsPopupForm.swdg-flow-form-active{ gap:12px; } #whatsPopupForm.swdg-flow-form-active input, #whatsPopupForm.swdg-flow-form-active select{ min-height:50px; border-radius:16px; border:1px solid rgba(255,255,255,.16); background:linear-gradient(180deg, rgba(255,255,255,.18), rgba(255,255,255,.10)); backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px); box-shadow:inset 0 1px 0 rgba(255,255,255,.10), 0 10px 24px rgba(0,0,0,.10); } #whatsPopupForm.swdg-flow-form-active input::placeholder{ color:rgba(255,255,255,.66); } #whatsPopupForm.swdg-flow-form-active select{ color:var(--swdg-textOnPrimary, #fff); } #whatsPopupForm.swdg-flow-form-active select option{ color:#111; } #whatsPopupForm.swdg-flow-form-active input:focus, #whatsPopupForm.swdg-flow-form-active select:focus{ border-color:color-mix(in srgb, var(--swdg-textAccent, #ffd84d) 70%, white 30%); box-shadow:0 0 0 4px color-mix(in srgb, var(--swdg-textAccent, #ffd84d) 18%, transparent), inset 0 1px 0 rgba(255,255,255,.15), 0 14px 28px rgba(0,0,0,.14); } #whatsPopupForm.swdg-flow-form-active .swdg-consent{ border:1px solid rgba(255,255,255,.10); background:linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,.06)); border-radius:16px; padding:12px 14px; } #whatsPopupForm.swdg-flow-form-active .swdg-btn{ width:100%; } .swdg-status{ color: var(--swdg-textOnPrimary, #fff); font-size:12.5px; text-align:center; min-height:18px; margin-top:2px; opacity:.92; } .swdg-error{ border:2px solid rgba(255, 80, 80, .95) !important; } @media (max-width:520px){ .swdg-modal{ width:min(520px, 96vw); max-height:92vh; display:flex; flex-direction:column; border-radius:20px; } .swdg-modal::after{ border-radius:19px; } .swdg-header{ padding:20px 15px 13px; } .swdg-headerBlock{ gap:7px; } .swdg-logoRow{ min-height:76px; padding:0 38px; } .swdg-logoImg{ height:70px !important; max-height:70px !important; } .swdg-headings{ max-width:100%; gap:4px; } .swdg-brandName{ font-size:18px; line-height:1.08; } .swdg-sub{ font-size:10.5px; line-height:1.18; letter-spacing:.5px; } .swdg-title{ font-size:16.5px; line-height:1.1; max-width:320px; } .swdg-form{ padding:12px 14px 16px; gap:10px; overflow:auto; -webkit-overflow-scrolling: touch; } .swdg-form input[type="text"], .swdg-form input[type="tel"], .swdg-form input[type="email"], .swdg-form select{ min-height:48px; padding:13px 12px; border-radius:14px; font-size:14px; box-shadow: 0 10px 22px rgba(0,0,0,.12); } .swdg-consent{ padding:10px 10px; border-radius:14px; gap:10px; font-size:11px; } .swdg-btn{ margin-top:3px; min-height:50px; padding:14px 14px; border-radius:16px; font-size:13px; letter-spacing:.56px; } .swdg-close{ top:10px; right:10px; width:36px; height:36px; border-radius:12px; font-size:20px; } /* ===== FLOW PREMIUM PLUS ===== */ #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-headings .swdg-brandName, #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-headings .swdg-sub, #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-headings .swdg-title{ display:none !important; } #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-header{ padding-bottom:8px; } #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-headerBlock{ gap:8px; } #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-logoRow{ margin-bottom:0; } #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-logoImg{ max-height:54px; width:auto; object-fit:contain; } #swdg-popup-root-v1[data-swdg-ui-mode="flow"] .swdg-form{ gap:12px; } .swdg-flow-step{ display:grid; gap:12px; animation:swdgFlowPremiumIn .24s ease; } @keyframes swdgFlowPremiumIn{ from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:translateY(0); } } .swdg-flow-meta{ display:grid; gap:10px; } .swdg-flow-progress{ display:grid; gap:7px; } .swdg-flow-progressTop{ display:flex; align-items:center; justify-content:space-between; gap:10px; } .swdg-flow-kicker{ color: color-mix(in srgb, var(--swdg-textAccent, #ffd84d) 82%, white 18%); font-size:11px; font-weight:900; text-transform:uppercase; letter-spacing:.08em; } .swdg-flow-stepCount{ color:rgba(255,255,255,.72); font-size:11px; font-weight:700; } .swdg-flow-progressBar{ position:relative; height:6px; border-radius:999px; overflow:hidden; background:rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.08); } .swdg-flow-progressFill{ position:absolute; inset:0 auto 0 0; border-radius:999px; background:linear-gradient(90deg, color-mix(in srgb, var(--swdg-textAccent, #ffd84d) 88%, white 12%), color-mix(in srgb, var(--swdg-button, #25d366) 78%, white 22%)); box-shadow:0 0 20px color-mix(in srgb, var(--swdg-textAccent, #ffd84d) 22%, transparent); } .swdg-flow-question{ margin:2px 0 0; color:var(--swdg-textOnPrimary, #fff); font-size:clamp(24px, 4.2vw, 24px); font-weight:900; line-height:1.08; letter-spacing:-.03em; text-align:center; text-wrap:balance; } .swdg-flow-copy{ color:rgba(255,255,255,.82); font-size:12.5px; line-height:1.6; text-align:center; max-width:100%; margin:-10px auto 14px; text-wrap:normal; } .swdg-flow-actions{ display:grid; gap:10px; margin-top:4px; } .swdg-flow-actions .swdg-btn{ width:100%; margin-top:0; } .swdg-btn-ghost{ margin:2px auto 0; font-size:12.5px; color:rgba(255,255,255,.72) !important; } .swdg-btn-ghost:hover{ color:#fff !important; } #whatsPopupForm.swdg-flow-form-active{ gap:12px; } #whatsPopupForm.swdg-flow-form-active input, #whatsPopupForm.swdg-flow-form-active select{ min-height:50px; border-radius:16px; border:1px solid rgba(255,255,255,.16); background:linear-gradient(180deg, rgba(255,255,255,.18), rgba(255,255,255,.10)); backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px); box-shadow:inset 0 1px 0 rgba(255,255,255,.10), 0 10px 24px rgba(0,0,0,.10); } #whatsPopupForm.swdg-flow-form-active input::placeholder{ color:rgba(255,255,255,.66); } #whatsPopupForm.swdg-flow-form-active select{ color:var(--swdg-textOnPrimary, #fff); } #whatsPopupForm.swdg-flow-form-active select option{ color:#111; } #whatsPopupForm.swdg-flow-form-active input:focus, #whatsPopupForm.swdg-flow-form-active select:focus{ border-color:color-mix(in srgb, var(--swdg-textAccent, #ffd84d) 70%, white 30%); box-shadow:0 0 0 4px color-mix(in srgb, var(--swdg-textAccent, #ffd84d) 18%, transparent), inset 0 1px 0 rgba(255,255,255,.15), 0 14px 28px rgba(0,0,0,.14); } #whatsPopupForm.swdg-flow-form-active .swdg-consent{ border:1px solid rgba(255,255,255,.10); background:linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,.06)); border-radius:16px; padding:12px 14px; } #whatsPopupForm.swdg-flow-form-active .swdg-btn{ width:100%; } .swdg-status{ font-size:10px; } } @media (max-width:360px){ .swdg-header{ padding:16px 12px 10px; } .swdg-logoRow{ min-height:66px; padding:0 40px; } .swdg-logoImg{ height:60px !important; max-height:60px !important; } .swdg-brandName{ font-size:17px; } .swdg-sub{ font-size:10px; } .swdg-title{ font-size:15px; } .swdg-form{ padding:10px 12px 12px; gap:9px; } .swdg-form input[type="text"], .swdg-form input[type="tel"], .swdg-form input[type="email"], .swdg-form select{ padding:12px 12px; font-size:13.5px; } .swdg-btn{ padding:13px 12px; font-size:12.5px; } } .swdg-devNotice{ margin-top:10px; padding:10px 12px; border-radius:12px; border:1px solid rgba(255,212,0,.35); background:rgba(255,212,0,.10); color:rgba(255,255,255,.92); font-size:12px; line-height:1.25; } /* ====== Pulse (opcional) ====== */ #swdg-popup-root-v1[data-swdg-pulse="1"] .swdg-btn{ animation: swdgPulse 1.6s ease-out infinite; } @keyframes swdgPulse{ 0%{ box-shadow: 0 0 0 0 rgba(var(--swdg-pulseRgb, 34,227,106), .55); } 70%{ box-shadow: 0 0 0 14px rgba(var(--swdg-pulseRgb, 34,227,106), 0); } 100%{ box-shadow: 0 0 0 0 rgba(var(--swdg-pulseRgb, 34,227,106), 0); } } #swdg-popup-root-v1[data-swdg-pulse="1"] .swdg-btn{ /* sincroniza a cor do pulse com o botão */ --_pulse: var(--swdg-button, var(--swdg-button, #22e36a)); } #swdg-popup-root-v1[data-swdg-pulse="1"] .swdg-btn{ /* substitui o rgba fixo acima em browsers modernos via shadow color */ } /* ====== Theme extras ====== */ #swdg-popup-root-v1 input:focus, #swdg-popup-root-v1 select:focus{ outline:none; border-color: rgba(255,212,0,.72); box-shadow: 0 0 0 4px rgba(255,216,77,.14), 0 18px 40px rgba(0,0,0,.20); } #swdg-popup-root-v1 input:focus-visible, #swdg-popup-root-v1 select:focus-visible, #swdg-popup-root-v1 button:focus-visible{ outline:none; } /* ====== Mobile refinado (consolidado na Fase 2) ====== */ /* Quando o teclado abre no iOS, evita “estourar” */ @supports (-webkit-touch-callout: none){ @media (max-width:520px){ .swdg-modal{ max-height:88vh; } } } /* ========================= THEME-PROOF (Elementor/WP) - impede tema de "sumir" com texto do `); const value = await new Promise((resolve) => { const btn = box.querySelector("#" + CSS.escape(btnId)); const inp = box.querySelector("#" + CSS.escape(inputId)); if (inp && typeof meta.onInput === "function") { inp.addEventListener("input", meta.onInput, { passive: true }); } const go = () => { const raw = String(inp && inp.value || ""); const formatted = typeof meta.format === "function" ? meta.format(raw) : String(raw || "").trim(); const valid = typeof meta.validate === "function" ? meta.validate(formatted) : true; if (!valid) { showInlineError(box, meta.error || "Preencha este campo 🙂"); return; } if (inp) inp.value = formatted; clearInlineError(box); resolve(formatted); }; if (inp) inp.addEventListener("keydown", (e) => { if (e.key === "Enter") go(); }); if (btn) btn.addEventListener("click", go); if (inp) setTimeout(() => { try { inp.focus(); } catch (_) { } }, 10); }); vars[meta.key] = value; if (meta.key === "whats" || meta.key === "whatsapp") { vars.whats = value; vars.whats_formatado = value; vars.whats_digits = normDigits(value); } appendMsg("out", escapeHtml(value)); } currentIndex = getExplicitNextIndex(step, defaultNextIndex); continue; } if (type === "redirect") { await renderRedirectStep(step, varsForTemplate); currentIndex = getExplicitNextIndex(step, defaultNextIndex); continue; } if (type === "cta") { const t = await showTyping(cfg); t.remove(); const label = step.label || "Iniciar atendimento no WhatsApp"; const tpl = step.messageTemplate || ""; const msg = fillTemplate(tpl, varsForTemplate); vars.__cta_message = msg; const destinoRaw = step.whatsDestino || step.phone || step.whatsapp || (cfg && cfg.whatsDestino) || ""; const destino = String(destinoRaw).replace(/\D+/g, ""); const wa = destino ? `https://wa.me/${destino}?text=${encodeURIComponent(msg)}` : ""; const ctaIntro = fillTemplate(step.text || "Perfeito. Clique no botão abaixo para iniciar o atendimento no WhatsApp com tudo preenchido:", varsForTemplate); const ctaWrap = document.createElement("div"); ctaWrap.innerHTML = `
${mdLiteToHtml(ctaIntro)}
` + (wa ? `
` : ""); const ctaLog = document.getElementById("swdg_chat_log"); const ctaMsgDiv = document.createElement("div"); ctaMsgDiv.className = "swdg_msg in"; ctaMsgDiv.appendChild(ctaWrap); if (ctaLog) { ctaLog.appendChild(ctaMsgDiv); ctaLog.scrollTop = ctaLog.scrollHeight; } requestAnimationFrame(() => ctaMsgDiv.classList.add("show")); if (wa) { const ctaBtn = ctaWrap.querySelector(".swdg_cta_btn"); if (ctaBtn) { await new Promise((resolve) => { ctaBtn.addEventListener("click", async (e) => { e.stopPropagation(); ctaBtn.disabled = true; try { if (!vars.__webhook_sent) { vars.__webhook_sent = true; await sendChatWebhook(cfg, vars); } } catch (_) { } try { swdgOpenWhatsPreferApp(wa); } catch (_) { location.href = wa; } resolve(); }, { once: true }); }); } } currentIndex = getExplicitNextIndex(step, defaultNextIndex); continue; } if (type === "submit") { if (String(step.to || "").toLowerCase() === "webhook") { const hasCta = flow.some(s => s && s.type === "cta"); if (!hasCta && !vars.__webhook_sent) { vars.__webhook_sent = true; await sendChatWebhook(cfg, vars); } } currentIndex = getExplicitNextIndex(step, defaultNextIndex); continue; } currentIndex = defaultNextIndex; } } const SWDG_UNIFIED_LEAD_EVENT = "swdg_lead_enviado"; function swdgNormalizePhoneForAds(value) { const digits = (typeof digitsOnly !== "undefined") ? digitsOnly(value || "") : String(value || "").replace(/\D+/g, ""); if (!digits) return ""; if (digits.startsWith("55") && digits.length >= 12) return digits; if (digits.length === 11) return "55" + digits; return digits; } function swdgPushLeadEvent(payload) { try { const safe = payload || {}; const phone = swdgNormalizePhoneForAds(safe.whats || safe.phone_number || ""); const firstName = String(safe.nome || safe.first_name || "").trim(); if (!phone || phone.length < 12) return false; const mode = String(safe.mode || safe.popup_mode || "default").trim() || "default"; const source = String(safe.source || "popup_system").trim() || "popup_system"; const dedupeKey = [phone, mode, String(location.pathname || "")].join("|"); const now = Date.now(); window.__SWDG_LEAD_EVENT_CACHE__ = window.__SWDG_LEAD_EVENT_CACHE__ || {}; const lastSent = Number(window.__SWDG_LEAD_EVENT_CACHE__[dedupeKey] || 0); if (lastSent && (now - lastSent) < 10000) return false; window.__SWDG_LEAD_EVENT_CACHE__[dedupeKey] = now; window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: SWDG_UNIFIED_LEAD_EVENT, user_data: { phone_number: phone, first_name: firstName || undefined }, clientId, popup_mode: mode, lead_source: source, origem_site: location.hostname, page_url: location.href }); return true; } catch (_) { return false; } } async function swdgSendWebhook(cfg, data, mode = "default") { try { const wh = cfg && cfg.webhook ? cfg.webhook : null; if (!(wh && wh.enabled === true && wh.url)) return; const bhCtx = (typeof swdgGetBusinessContext !== "undefined") ? swdgGetBusinessContext(cfg) : null; const notify = (cfg && cfg.notifyEmail) ? cfg.notifyEmail : null; const notify_enabled = (notify && typeof notify.enabled === "boolean") ? notify.enabled : true; const email_to_prod = (notify && notify.toProd) ? String(notify.toProd) : ""; const email_to_test = (notify && notify.toTest) ? String(notify.toTest) : ""; const email_bcc = (notify && notify.bcc) ? String(notify.bcc) : ""; const email_to = (notify_enabled ? email_to_prod : email_to_test) || email_to_test || email_to_prod || ""; // Fallbacks para cliques const gclid = data.origem_clique || (typeof qsAny !== "undefined" ? qsAny(["gclid"]) : ""); const gbraid = data.origem_clique_tipo === "gbraid" ? data.origem_clique : (typeof qsAny !== "undefined" ? qsAny(["gbraid"]) : ""); const wbraid = data.origem_clique_tipo === "wbraid" ? data.origem_clique : (typeof qsAny !== "undefined" ? qsAny(["wbraid"]) : ""); let final_clique = data.origem_clique || gclid || gbraid || wbraid || ""; let final_tipo = data.origem_clique_tipo || (gclid ? "gclid" : (gbraid ? "gbraid" : (wbraid ? "wbraid" : ""))); const extraData = Object.fromEntries( Object.entries(data || {}).filter(([k]) => !String(k || "").startsWith("__")) ); const payload = { clientId, notify_enabled, email_to, email_bcc, business_context: (bhCtx && bhCtx.mode) ? bhCtx.mode : "open", ip_publico: SWDG_CACHED_IP, ip_fonte: SWDG_CACHED_IP ? "ipify" : "", ...extraData, nome: data.nome || "", whats: (typeof digitsOnly !== "undefined" ? digitsOnly(data.whats || "") : String(data.whats || "").replace(/\D/g, "")), whats_formatado: data.whats || "", email: data.email || "", accepted: true, origem_site: location.hostname, page_url: location.href, referrer: document.referrer || "", device: (typeof deviceLabel !== "undefined" ? deviceLabel() : ""), datahora: (typeof nowBR !== "undefined" ? nowBR() : ""), campanha: data.campanha || (typeof qsAny !== "undefined" ? qsAny(["utm_campaign", "campaign", "campanha", "g_campaignid", "gad_campaignid", "gad_campaign_id"]) : ""), palavra: data.palavra || (typeof qsAny !== "undefined" ? qsAny(["utm_term", "keyword", "palavra"]) : ""), cidade: data.cidade || (typeof qsAny !== "undefined" ? qsAny(["locality", "cidade", "city"]) : ""), polo: (cfg && cfg.polo) ? String(cfg.polo) : "", popup_mode: mode, origem_clique: final_clique, origem_clique_tipo: final_tipo, info: (typeof buildInfo !== "undefined" ? buildInfo() : ""), flow: data.flow || data, quero_desconto: !!data.quero_desconto, ir_whats_agora: !!data.ir_whats_agora }; swdgPushLeadEvent({ nome: payload.nome, whats: payload.whats, mode: mode, source: "webhook", }); return fetch(wh.url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), keepalive: true, }).catch(() => { }); } catch (err) { console.warn("SWDG Webhook Error:", err); } } async function sendChatWebhook(cfg, vars) { return swdgSendWebhook(cfg, vars, "chat"); } // ========= Badge (imagem/selo) ========= function swdgMountBadge(root, cfg) { try { const b = cfg && cfg.badge ? cfg.badge : null; if (!b || b.enabled !== true) return; const mode = String(b.mode || "image").toLowerCase(); const src = String(b.src || "").trim(); if (mode !== "image" || !src) return; const modal = root.querySelector(".swdg-modal"); if (!modal) return; // evita duplicar if (modal.querySelector(".swdg-badge")) return; const pos = String(b.position || "top-left").toLowerCase(); const sizeKey = String(b.size || "lg").toLowerCase(); const sizeMap = { xs: 88, sm: 108, md: 128, lg: 156, xl: 184 }; const px = sizeMap[sizeKey] || 156; const wrap = document.createElement("div"); wrap.className = "swdg-badge swdg-badge--" + (["top-left", "top-right", "bottom-left", "bottom-right"].includes(pos) ? pos : "top-left"); wrap.style.setProperty("--swdg-badge-size", px + "px"); wrap.style.setProperty("--swdg-badge-offset", "-18px"); const img = document.createElement("img"); img.src = src; img.alt = String(b.alt || "").trim() || "Selo"; img.loading = "lazy"; wrap.appendChild(img); modal.appendChild(wrap); } catch (_) { } } const SWDG_FLOW_V22_CSS = ` .swdg-flow-intro-consent{ display:flex !important; align-items:flex-start !important; gap:10px !important; margin: 10px 0 4px !important; padding: 12px 14px !important; border-radius: 16px !important; border:1px solid rgba(255,255,255,.12) !important; background: linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,.045)) !important; color: rgba(245,250,255,.92) !important; font-size: 14px !important; line-height: 1.45 !important; } .swdg-flow-intro-consent > span:last-child{ color: rgba(245,250,255,.92) !important; } .swdg-flow-intro-consent.is-error{ border-color: rgba(255,120,120,.55) !important; background: linear-gradient(180deg, rgba(255,100,100,.18), rgba(255,100,100,.10)) !important; box-shadow: 0 0 0 3px rgba(255,100,100,.10) !important; } .swdg-flow-consent-alert{ margin-top: 8px !important; font-size: 12px !important; line-height: 1.35 !important; color: rgba(255,214,214,.96) !important; display:none; } .swdg-flow-consent-alert.is-visible{ display:block !important; } .swdg-btn-ghost{ background: transparent !important; border: 0 !important; box-shadow: none !important; color: rgba(255,255,255,.82) !important; padding: 0 !important; min-height: auto !important; height: auto !important; margin: 14px auto 0 !important; display:block !important; width: auto !important; } .swdg-btn-ghost:hover{ background: transparent !important; color: #fff !important; transform: none !important; box-shadow: none !important; } #whatsPopupForm.swdg-flow-form-active{ display:flex !important; flex-direction:column !important; gap: 0 !important; } #whatsPopupForm.swdg-flow-form-active .swdg-flow-form-shell{ display:flex !important; flex-direction:column !important; gap: 14px !important; } #whatsPopupForm.swdg-flow-form-active .swdg-flow-form-shell > *{ margin: 0 !important; } #whatsPopupForm.swdg-flow-form-active input, #whatsPopupForm.swdg-flow-form-active textarea{ color: rgba(245,250,255,.96) !important; -webkit-text-fill-color: rgba(245,250,255,.96) !important; caret-color: rgba(245,250,255,.96) !important; background: linear-gradient(180deg, rgba(255,255,255,.15), rgba(255,255,255,.09)) !important; border-color: rgba(255,255,255,.20) !important; font-size: 15px !important; } #whatsPopupForm.swdg-flow-form-active input::placeholder, #whatsPopupForm.swdg-flow-form-active textarea::placeholder{ color: rgba(245,250,255,.56) !important; -webkit-text-fill-color: rgba(245,250,255,.56) !important; } #whatsPopupForm.swdg-flow-form-active input:focus, #whatsPopupForm.swdg-flow-form-active textarea:focus{ color: rgba(255,255,255,.98) !important; -webkit-text-fill-color: rgba(255,255,255,.98) !important; } #whatsPopupForm.swdg-flow-form-active .swdg-liveConfirm{ margin-top: 0 !important; } #whatsPopupForm.swdg-flow-form-active .swdg-btn[type="submit"]{ margin-top: 6px !important; } @media (max-width:560px){ .swdg-flow-intro-consent{ font-size: 13px !important; padding: 11px 12px !important; } } `; function mountUI() { if (mounted) return; // [IP] tenta aquecer o cache do IP o quanto antes try { swdgPrefetchIP(); } catch (_) { } const host = document.createElement("div"); host.id = ROOT_ID; host.setAttribute("data-swdg-host", "1"); const shadow = host.attachShadow({ mode: "open" }); const root = document.createElement("div"); root.id = ROOT_ID; SWDG_POPUP_HOST = host; SWDG_POPUP_SHADOW = shadow; injectStyles(shadow); try { const __flowV22Style = document.createElement('style'); __flowV22Style.id = 'swdg-flow-v22-shadow'; __flowV22Style.textContent = SWDG_FLOW_V22_CSS; shadow.appendChild(__flowV22Style); } catch (_) { } // Theme via JSON (opcional) try { swdgApplyTheme(host, CONFIG); } catch (_) { } // ✅ FORM REAL com names form_fields[...] (GTM/planilha reconhece) root.innerHTML = ` `; if (!SWDG_FLOW_ORIGINAL_FORM_HTML) { const __f = $("#whatsPopupForm", root); if (__f) SWDG_FLOW_ORIGINAL_FORM_HTML = __f.innerHTML; } // Badge (opcional via JSON) try { swdgMountBadge(root, CONFIG); } catch (_) { } shadow.appendChild(root); document.body.appendChild(host); mounted = true; // Fechar const overlay = $(".swdg-overlay", root); const closeBtn = $(".swdg-close", root); closeBtn.addEventListener("click", () => closePopup()); overlay.addEventListener("click", (e) => { if (e.target === overlay) closePopup(); }); document.addEventListener("keydown", (e) => { if (e.key === "Escape" && overlay.getAttribute("aria-hidden") === "false") closePopup(); }); // Inputs const elNome = $("#swdg_nome", root); const elWhats = $("#swdg_whats", root); const elEmailLive = $("#swdg_email", root); const elLiveConfirm = $("#swdg_liveConfirm", root); const elLiveConfirmValue = $("#swdg_liveConfirm_value", root); const elLiveConfirmStudentLink = $("#swdg_liveConfirm_studentLink", root); function updateLiveConfirm() { if (!elLiveConfirm || !elLiveConfirmValue) return; const nome = sanitizeNameFinal(elNome ? elNome.value : ""); const whats = String(elWhats && elWhats.value ? elWhats.value : "").trim(); const email = String(elEmailLive && elEmailLive.value ? elEmailLive.value : "").trim(); const parts = []; if (nome) parts.push(nome); if (whats) parts.push(whats); if (email) parts.push(email); const alunoDestino = String((CONFIG && (CONFIG.whatsAlunoDestino || CONFIG.studentWhatsDestino || CONFIG.whatsPedagogicoDestino)) || "").replace(/\D+/g, ""); const alunoLabel = String((CONFIG && (CONFIG.whatsAlunoLabel || CONFIG.studentWhatsLabel || CONFIG.whatsPedagogicoLabel)) || "Se você já é aluno, clique aqui.").trim(); if (!parts.length) { elLiveConfirm.style.display = "none"; elLiveConfirmValue.textContent = ""; if (elLiveConfirmStudentLink) { elLiveConfirmStudentLink.hidden = true; elLiveConfirmStudentLink.removeAttribute("href"); } return; } elLiveConfirmValue.textContent = parts.join(" • "); elLiveConfirm.style.display = "block"; if (elLiveConfirmStudentLink) { if (alunoDestino) { const emailLinha = email ? `\nE-mail: ${email}` : ""; const whatsLinha = whats ? `\nWhats: ${whats}` : ""; const nomeLinha = nome ? `\nNome: ${nome}` : ""; const msgAluno = encodeURIComponent(`Olá! Já sou aluno e preciso de atendimento.${nomeLinha}${whatsLinha}${emailLinha}\nSite: ${location.hostname}`); elLiveConfirmStudentLink.href = `https://wa.me/${alunoDestino}?text=${msgAluno}`; elLiveConfirmStudentLink.textContent = alunoLabel || "Se você já é aluno, clique aqui."; elLiveConfirmStudentLink.hidden = false; } else { elLiveConfirmStudentLink.hidden = true; elLiveConfirmStudentLink.removeAttribute("href"); } } } elNome.addEventListener("input", () => { const fixed = sanitizeNameLive(elNome.value); if (fixed !== elNome.value) { const pos = elNome.selectionStart || 0; elNome.value = fixed; try { elNome.setSelectionRange(pos, pos); } catch (_) { } } updateLiveConfirm(); }); elWhats.addEventListener("input", () => { applyPhoneMask(elWhats); updateLiveConfirm(); }); elEmailLive && elEmailLive.addEventListener("input", updateLiveConfirm); updateLiveConfirm(); const elDDDHint = $("#swdg_ddd_hint", root); const elDDDHintText = $("#swdg_ddd_hint_text", root); const btnKeep = $("#swdg_ddd_keep", root); const btnSwap = $("#swdg_ddd_swap", root); function hideDDDHints() { if (elDDDHint) elDDDHint.style.display = "none"; } function showDDDHints(currentDDD, suggestedDDD, geo) { if (!elDDDHint || !elDDDHintText || SWDG_DDD_HINT_DISMISSED) return; const city = (geo && geo.city) ? String(geo.city) : ""; const uf = (geo && geo.region) ? String(geo.region) : ""; const loc = (city && uf) ? (city + "/" + uf) : (city || uf || "sua região"); elDDDHintText.textContent = `Você está em ${loc}? O DDD aí costuma ser (${suggestedDDD}).`; btnKeep.textContent = `Manter (${currentDDD})`; btnSwap.textContent = `Trocar para (${suggestedDDD})`; elDDDHint.style.display = "flex"; } function updateDDDHints() { if (SWDG_DDD_HINT_DISMISSED) return; const digits = normalizePhoneDigits(elWhats.value); if (digits.length !== 11) { hideDDDHints(); return; } const currentDDD = digits.slice(0, 2); swdgPrefetchSuggestedDDD().then((suggested) => { if (!suggested || suggested.length !== 2) { hideDDDHints(); return; } if (currentDDD === suggested) { hideDDDHints(); return; } return swdgPrefetchGeo().then((geo) => { showDDDHints(currentDDD, suggested, geo); }); }); } btnKeep && btnKeep.addEventListener("click", () => { SWDG_DDD_HINT_DISMISSED = true; hideDDDHints(); }); btnSwap && btnSwap.addEventListener("click", () => { const suggested = SWDG_SUGGESTED_DDD; if (!suggested || suggested.length !== 2) return; const digits = normalizePhoneDigits(elWhats.value); if (digits.length !== 11) return; const swapped = suggested + digits.slice(2); elWhats.value = swapped; applyPhoneMask(elWhats); SWDG_DDD_HINT_DISMISSED = true; hideDDDHints(); }); elWhats.addEventListener("input", () => updateDDDHints()); // ✅ Blindagem em CAPTURE: no Shadow DOM o listener precisa ficar no próprio form const form = $("#whatsPopupForm", root); form && form.addEventListener("submit", onSubmitCapture, true); } function closePopup() { const root = getPopupRoot(); if (!root) return; $(".swdg-overlay", root).setAttribute("aria-hidden", "true"); try { document.activeElement && document.activeElement.blur && document.activeElement.blur(); } catch (_) { } try { const h = String(location.hash || "").toLowerCase(); if (h === "#swdg-popup" || h.indexOf("#swdg-popup=") === 0 || h === "#swdg-flow" || h.indexOf("#swdg-flow=") === 0 || h === "#swdg-chat") { history.replaceState({}, "", location.pathname + location.search); } } catch (_) { } } function clearErrors(root) { ["#swdg_nome", "#swdg_whats", "#swdg_email", "#swdg_curso"].forEach((id) => { const el = $(id, root); el && el.classList.remove("swdg-error"); }); } function setError(el) { el && el.classList.add("swdg-error"); } function setField(root, name, value) { const el = root.querySelector(`[name="${name}"]`); if (!el) return; // vazio se vier null/undefined/"undefined"/"-" el.value = (value == null || value === "-" || value === "undefined") ? "" : String(value); } function swdgFlowEscape(v) { return String(v == null ? "" : v) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function swdgResolveFlowStep(flowCfg, stepId) { const steps = Array.isArray(flowCfg && flowCfg.steps) ? flowCfg.steps : []; return steps.find((s) => s && s.id === stepId) || null; } function swdgFlowResolveWhats(value) { const key = String(value || "").trim().toLowerCase(); const direct = String(value || "").replace(/\D+/g, ""); if (direct) return direct; const map = { pedagogico: (CONFIG && (CONFIG.whatsPedagogicoDestino || CONFIG.studentWhatsDestino || CONFIG.whatsAlunoDestino)) || "", financeiro: (CONFIG && (CONFIG.whatsFinanceiroDestino || CONFIG.financeiroWhatsDestino)) || "", comercial: (CONFIG && (CONFIG.whatsDestino || CONFIG.whatsapp || CONFIG.phone)) || "", default: (CONFIG && (CONFIG.whatsDestino || CONFIG.whatsapp || CONFIG.phone)) || "" }; return String(map[key] || map.default || "").replace(/\D+/g, ""); } function swdgAttachCurrentFormEnhancements(root) { const elNome = $("#swdg_nome", root); const elWhats = $("#swdg_whats", root); const elEmailLive = $("#swdg_email", root); const elLiveConfirm = $("#swdg_liveConfirm", root); const elLiveConfirmValue = $("#swdg_liveConfirm_value", root); const elLiveConfirmStudentLink = $("#swdg_liveConfirm_studentLink", root); const emailWrap = $("#swdg_email_wrap", root); const courseWrap = $("#swdg_course_wrap", root); const courseSel = $("#swdg_curso", root); // Reaplica a lógica real do formulário tradicional dentro do Flow const emailCfg = (CONFIG && CONFIG.email) ? CONFIG.email : null; const emailEnabled = !!(emailCfg && emailCfg.enabled === true); if (emailWrap && elEmailLive) { if (emailEnabled) { emailWrap.style.display = "block"; elEmailLive.required = !!emailCfg.required; elEmailLive.placeholder = emailCfg.placeholder || "Seu e-mail (opcional)"; } else { emailWrap.style.display = "none"; elEmailLive.required = false; elEmailLive.value = ""; } } const hasCourses = Array.isArray(CONFIG && CONFIG.courses) && CONFIG.courses.length > 0; const mustChooseCourse = (CONFIG && CONFIG.courseRequired !== false) && hasCourses; const courseFromUrl = swdgGetCourseFromUrl(); if (courseSel) { if (!hasCourses) { if (courseWrap) courseWrap.style.display = "none"; if (courseSel) courseSel.required = false; if (courseSel) { const fallbackCourse = courseFromUrl || ""; const fallbackLabel = fallbackCourse || "Curso (não informado)"; courseSel.innerHTML = ``; courseSel.value = fallbackCourse; } } else { if (courseWrap) courseWrap.style.display = "block"; if (courseSel) courseSel.required = mustChooseCourse; if (courseSel) courseSel.innerHTML = ``; (CONFIG.courses || []).forEach((c) => { const opt = document.createElement("option"); opt.textContent = c; if (String(c).includes("────")) { opt.value = ""; opt.disabled = true; opt.style.fontWeight = "800"; opt.style.backgroundColor = "#f3f3f3"; } else { opt.value = c; } if (courseSel) courseSel.appendChild(opt); }); if (courseSel) courseSel.value = ""; } } if (!elNome || !elWhats) return; function updateLiveConfirm() { if (!elLiveConfirm || !elLiveConfirmValue) return; const nome = sanitizeNameFinal(elNome ? elNome.value : ""); const whats = String(elWhats && elWhats.value ? elWhats.value : "").trim(); const email = String(elEmailLive && elEmailLive.value ? elEmailLive.value : "").trim(); const parts = []; if (nome) parts.push(nome); if (whats) parts.push(whats); if (email) parts.push(email); const alunoDestino = String((CONFIG && (CONFIG.whatsAlunoDestino || CONFIG.studentWhatsDestino || CONFIG.whatsPedagogicoDestino)) || "").replace(/\D+/g, ""); const alunoLabel = String((CONFIG && (CONFIG.whatsAlunoLabel || CONFIG.studentWhatsLabel || CONFIG.whatsPedagogicoLabel)) || "Se você já é aluno, clique aqui.").trim(); if (!parts.length) { elLiveConfirm.style.display = "none"; elLiveConfirmValue.textContent = ""; if (elLiveConfirmStudentLink) { elLiveConfirmStudentLink.hidden = true; elLiveConfirmStudentLink.removeAttribute("href"); } return; } elLiveConfirmValue.textContent = parts.join(" • "); elLiveConfirm.style.display = "block"; if (elLiveConfirmStudentLink) { if (alunoDestino) { const emailLinha = email ? `\nE-mail: ${email}` : ""; const whatsLinha = whats ? `\nWhats: ${whats}` : ""; const nomeLinha = nome ? `\nNome: ${nome}` : ""; const msgAluno = encodeURIComponent(`Olá! Já sou aluno e preciso de atendimento.${nomeLinha}${whatsLinha}${emailLinha}\nSite: ${location.hostname}`); elLiveConfirmStudentLink.href = `https://wa.me/${alunoDestino}?text=${msgAluno}`; elLiveConfirmStudentLink.textContent = alunoLabel || "Se você já é aluno, clique aqui."; elLiveConfirmStudentLink.hidden = false; } else { elLiveConfirmStudentLink.hidden = true; elLiveConfirmStudentLink.removeAttribute("href"); } } } if (!elNome.dataset.swdgBound) { elNome.addEventListener("input", () => { const fixed = sanitizeNameLive(elNome.value); if (fixed !== elNome.value) { const pos = elNome.selectionStart || 0; elNome.value = fixed; try { elNome.setSelectionRange(pos, pos); } catch (_) { } } updateLiveConfirm(); }); elNome.dataset.swdgBound = "1"; } if (!elWhats.dataset.swdgBound) { elWhats.addEventListener("input", () => { applyPhoneMask(elWhats); updateLiveConfirm(); }); elWhats.dataset.swdgBound = "1"; } if (elEmailLive && !elEmailLive.dataset.swdgBound) { elEmailLive.addEventListener("input", updateLiveConfirm); elEmailLive.dataset.swdgBound = "1"; } updateLiveConfirm(); } function swdgGetFlowSteps(flowCfg) { return (flowCfg && Array.isArray(flowCfg.steps)) ? flowCfg.steps : []; } function swdgGetFlowStepIndex(flowCfg, stepId) { const steps = swdgGetFlowSteps(flowCfg); return Math.max(0, steps.findIndex((s) => String((s && s.id) || "") === String(stepId || ""))); } function swdgGetFlowProgressMeta(flowCfg, stepId) { const steps = swdgGetFlowSteps(flowCfg); const visualSteps = steps.filter((s) => String((s && s.type) || "") !== "message"); const current = swdgResolveFlowStep(flowCfg, stepId); const currentId = String((current && current.id) || stepId || ""); let idx = visualSteps.findIndex((s) => String((s && s.id) || "") === currentId); if (idx < 0) idx = 0; const total = Math.max(visualSteps.length, 1); const currentNumber = Math.min(idx + 1, total); const percent = Math.max(12, Math.min(100, Math.round((currentNumber / total) * 100))); return { currentNumber, total, percent }; } function swdgFlowPreferredOptionIndex(step, opts) { const list = Array.isArray(opts) ? opts : []; if (!list.length) return 0; if (typeof step.primaryIndex === "number" && list[step.primaryIndex]) return step.primaryIndex; const key = String(step.key || step.id || "").toLowerCase(); const score = (opt) => { const txt = String((opt && (opt.value || opt.label)) || "").toLowerCase(); if (key.includes("ja_e_aluno")) { if (txt.includes("nao") || txt.includes("não")) return 10; if (txt.includes("sim")) return 1; } if (key.includes("modalidade") || key.includes("ead") || key.includes("presencial")) { if (txt.includes("continuar") || txt.includes("prosseguir") || txt.includes("entendo") || txt == 'sim' || txt.startsWith('sim,')) return 10; if (txt.includes("não") || txt.includes("nao")) return 1; } return 0; }; let best = 0, bestScore = -1; list.forEach((opt, idx) => { const s = score(opt); if (s > bestScore) { bestScore = s; best = idx; } }); return best; } function swdgFlowButtonClass(step, btn, idx, preferredIdx) { const mode = String((btn && btn.style) || "").toLowerCase(); if (mode === "primary") return "swdg-btn swdg-flow-btn-primary"; if (mode === "secondary" || mode === "ghost") return "swdg-btn swdg-btn-secondary"; if (typeof preferredIdx === "number") return `swdg-btn ${idx === preferredIdx ? 'swdg-flow-btn-primary' : 'swdg-btn-secondary'}`; return "swdg-btn"; } function swdgRenderFlowMeta(flowCfg, step) { const meta = swdgGetFlowProgressMeta(flowCfg, step && step.id); const kicker = swdgFlowEscape(step && step.kicker ? step.kicker : 'Atendimento via WhatsApp'); return `
${kicker}
Etapa ${meta.currentNumber} de ${meta.total}
`; } function swdgRenderFlowStep(root, flowCfg, stepId) { const form = $("#whatsPopupForm", root); const statusEl = $(".swdg-status", root); if (!form) return; if (statusEl) statusEl.textContent = ""; const step = swdgResolveFlowStep(flowCfg, stepId); if (!step) { form.innerHTML = `
Etapa do fluxo não encontrada.
`; return; } SWDG_FLOW_CURRENT_STEP = step.id || ""; form.classList.add("swdg-flow-mode"); const showBack = SWDG_FLOW_HISTORY.length > 0 && step.type !== "intro" && step.type !== "form"; const backHtml = showBack ? `` : ""; const cardOpen = '
'; const cardClose = `${backHtml}
`; const metaHtml = swdgRenderFlowMeta(flowCfg, step); const titleHtml = `

${swdgFlowEscape(step.question || step.title || "Atendimento")}

`; const stepCopyText = (() => { if (step.type === "intro" && swdgVisitorShouldShowWelcome()) return "Que bom ter você de volta 😊"; return String(step.text || ""); })(); const textHtml = stepCopyText ? `
${swdgFlowEscape(stepCopyText)}
` : ""; if (step.type === "form") { form.classList.add("swdg-flow-form-active"); const formIntroText = "Preencha seus dados para continuar no WhatsApp."; const formIntro = `${cardOpen}${metaHtml}

Vamos começar

${swdgFlowEscape(formIntroText)}
`; const originalMarkup = SWDG_FLOW_ORIGINAL_FORM_HTML || form.innerHTML; const hiddenAcceptance = ``; const cleanedMarkup = originalMarkup.replace(/