Add sticky CTA bar, penalty warnings, lead capture to compliance checker

- Sticky bar fixed to bottom: "N issues found — your filing needs to be
  corrected" with "See How to Fix This" + "Call Us" buttons
- Per-filing penalty warnings on red/yellow cards: RMD removal from network,
  CPNI $239K/violation, 499-A Red Light blocks all FCC apps, CALEA $10K/day,
  CORES can't legally operate
- CTA copy changed: "Your filing is inaccurate" urgency box + "Fix My Filing"
  button with "no commitment until you pay" reassurance
- Lead capture form: "Get your compliance report emailed" for people not
  ready to buy — creates ticket + tracks lead-capture event in Umami

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
justin 2026-05-13 12:29:47 -05:00
parent 71d466c922
commit 54bdb9d480

View file

@ -93,6 +93,20 @@ import Base from "../../layouts/Base.astro";
<p id="error-message"></p>
</div>
<!-- Sticky CTA bar (shown when issues found, fixed to bottom) -->
<div id="sticky-cta" class="hidden" style="position:fixed;bottom:0;left:0;right:0;z-index:9999;background:linear-gradient(135deg,#1a2744 0%,#2d4e78 100%);padding:12px 16px;box-shadow:0 -4px 20px rgba(0,0,0,0.15);">
<div style="max-width:720px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;">
<div style="flex:1;min-width:200px;">
<p style="color:#fbbf24;font-size:13px;font-weight:700;margin:0;" id="sticky-issue-count">&#9888; Issues found in your filed certification</p>
<p style="color:#94a3b8;font-size:11px;margin:2px 0 0;">Your current filing doesn't meet 2026 FCC requirements &mdash; this needs to be corrected</p>
</div>
<div style="display:flex;gap:8px;flex-shrink:0;">
<a id="sticky-cta-btn" href="#cta-section" style="background:#f97316;color:#fff;font-weight:700;padding:10px 20px;border-radius:8px;text-decoration:none;font-size:13px;white-space:nowrap;">See How to Fix This &darr;</a>
<a href="tel:8884110383" style="background:rgba(255,255,255,0.15);color:#fff;font-weight:600;padding:10px 14px;border-radius:8px;text-decoration:none;font-size:12px;white-space:nowrap;">&#128222; Call Us</a>
</div>
</div>
</div>
<!-- Results -->
<div id="results" class="hidden space-y-6">
<!-- Entity Header -->
@ -570,6 +584,24 @@ import Base from "../../layouts/Base.astro";
if (check.due_date) inner += `<p class="text-xs ${c.textColor} opacity-75 mt-0.5">Due: ${check.due_date}</p>`;
if (check.detail) inner += `<p class="text-sm ${c.textColor} mt-1">${check.detail}</p>`;
// Add penalty warning for red/yellow items
if (status === "red" || status === "yellow") {
const penaltyMap: Record<string, string> = {
"rmd": "Carriers with inaccurate or missing RMD certifications face removal from the database — which blocks your calls from being completed on the US phone network. Penalties up to $500,000 per violation.",
"cpni": "Failure to file the annual CPNI certification triggers FCC enforcement proceedings. Penalties up to $239,071 per violation, $2.39M for continuing violations.",
"499a": "Non-filing results in USAC Red Light status, which blocks all FCC applications, license renewals, and equipment authorizations until resolved. Late fees and interest accrue.",
"499q": "Quarterly filing is required to maintain your USF contribution obligations. Missing quarterly filings can trigger USAC audit and retroactive assessments.",
"bdc": "BDC filing is mandatory for all broadband and voice providers. Non-compliance can result in FCC enforcement action and fines.",
"calea": "CALEA non-compliance carries court-enforced penalties up to $10,000 per day. Law enforcement intercept capability is a federal requirement.",
"cores": "Without a valid FCC registration, your company cannot legally operate as a telecommunications provider in the United States.",
};
const checkId = (check.id || "").toLowerCase();
const penalty = Object.entries(penaltyMap).find(([k]) => checkId.includes(k));
if (penalty) {
inner += `<p class="text-xs mt-2 italic" style="color:#991b1b;opacity:0.85;">${penalty[1]}</p>`;
}
}
// Entity name for contextual questions
const eName = (data.entity_name || "").toUpperCase() || "THIS ENTITY";
@ -853,7 +885,12 @@ import Base from "../../layouts/Base.astro";
const reminderCta = document.getElementById("reminder-cta");
if (services.length > 0) {
let html = `<h3 class="text-lg font-bold text-gray-900 mb-4">We can help fix these items</h3>`;
let html = `<div style="background:#fef2f2;border:2px solid #fca5a5;border-radius:10px;padding:16px;margin-bottom:16px;">
<p style="font-size:14px;color:#991b1b;font-weight:700;margin:0 0 6px;">&#9888; Your current FCC filing is inaccurate</p>
<p style="font-size:13px;color:#7f1d1d;margin:0;">The certification document on file with the FCC is missing required sections under 2026 enforcement standards. Until this is corrected, your company is exposed to enforcement action and potential fines.</p>
</div>`;
html += `<h3 class="text-lg font-bold text-gray-900 mb-1">Your Remediation Plan</h3>`;
html += `<p class="text-sm text-gray-600 mb-4">Select the filings that need to be corrected. We'll prepare updated documents, get your signature, and file them with the FCC.</p>`;
html += `<div class="space-y-2" id="service-list">`;
for (const svc of services) {
@ -871,11 +908,27 @@ import Base from "../../layouts/Base.astro";
html += `</div>`;
html += `<div id="total-row" class="hidden"></div>`;
html += `<div class="mt-4 text-center">
<a id="get-started-btn" href="#" style="background:#f97316;color:#fff;font-weight:700;padding:12px 32px;border-radius:8px;box-shadow:0 4px 6px rgba(0,0,0,0.1);display:inline-block;font-size:14px;text-decoration:none;">
Get Started &rarr;
<a id="get-started-btn" href="#" style="background:#f97316;color:#fff;font-weight:700;padding:14px 36px;border-radius:8px;box-shadow:0 4px 12px rgba(249,115,22,0.4);display:inline-block;font-size:15px;text-decoration:none;">
Fix My Filing &rarr;
</a>
<p style="font-size:11px;color:#6b7280;margin-top:8px;">You'll see itemized pricing on the next page. No commitment until you pay.</p>
</div>`;
// Lead capture for people not ready to buy
html += \`<div style="margin-top:24px;padding-top:20px;border-top:1px solid #e5e7eb;">
<div style="background:#f0f4f8;border-radius:10px;padding:16px;text-align:center;">
<p style="font-size:13px;font-weight:600;color:#1e3a5f;margin:0 0 4px;">Not ready yet? Get your compliance report emailed to you.</p>
<p style="font-size:11px;color:#64748b;margin:0 0 12px;">We'll send a detailed breakdown of what needs to be fixed — free, no obligation.</p>
<div style="display:flex;gap:8px;max-width:400px;margin:0 auto;">
<input type="email" id="lead-email" placeholder="Your email address" style="flex:1;border:1px solid #cbd5e1;border-radius:6px;padding:8px 12px;font-size:13px;" />
<button type="button" id="lead-submit-btn" style="background:#1e3a5f;color:#fff;font-weight:600;padding:8px 16px;border-radius:6px;border:none;cursor:pointer;font-size:12px;white-space:nowrap;">
Send Report
</button>
</div>
<p id="lead-status" style="font-size:11px;margin-top:6px;display:none;"></p>
</div>
</div>\``;
ctaContent.innerHTML = html;
paymentIcons.classList.remove("hidden");
reminderCta.classList.add("hidden");
@ -990,6 +1043,88 @@ import Base from "../../layouts/Base.astro";
}
}
// --- Sticky CTA bar: show after results with issues ---
(function() {
const stickyBar = document.getElementById("sticky-cta");
const resultsDiv = document.getElementById("results");
if (!stickyBar || !resultsDiv) return;
const observer = new MutationObserver(() => {
if (resultsDiv.classList.contains("hidden")) {
stickyBar.classList.add("hidden");
return;
}
const redCards = document.querySelectorAll("#checks-container .bg-red-50, #checks-container .bg-amber-50");
if (redCards.length > 0) {
const countEl = document.getElementById("sticky-issue-count");
if (countEl) countEl.textContent = `⚠ ${redCards.length} issue${redCards.length > 1 ? "s" : ""} found — your filing needs to be corrected`;
stickyBar.classList.remove("hidden");
// Add padding to body so content isn't hidden behind sticky bar
document.body.style.paddingBottom = "80px";
} else {
stickyBar.classList.add("hidden");
document.body.style.paddingBottom = "";
}
});
observer.observe(resultsDiv, { attributes: true, childList: true, subtree: true });
})();
// --- Lead capture: email compliance report ---
document.addEventListener("click", (e) => {
const btn = e.target.closest("#lead-submit-btn");
if (!btn) return;
const emailInput = document.getElementById("lead-email") as HTMLInputElement;
const statusEl = document.getElementById("lead-status");
if (!emailInput || !statusEl) return;
const email = emailInput.value.trim();
if (!email || !email.includes("@")) {
statusEl.textContent = "Please enter a valid email address.";
statusEl.style.color = "#dc2626";
statusEl.style.display = "block";
return;
}
btn.textContent = "Sending...";
btn.disabled = true;
const frn = (document.getElementById("entity-frn") as HTMLElement)?.textContent?.trim() || "";
const entity = (document.getElementById("entity-name") as HTMLElement)?.textContent?.trim() || "";
// Send lead to API
fetch(`${API}/api/v1/tickets`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
type: "compliance_lead",
subject: `Compliance Report Request — ${entity || frn}`,
name: "",
email: email,
message: [
`FRN: ${frn}`,
`Entity: ${entity}`,
`Source: compliance checker lead capture`,
`URL: ${window.location.href}`,
// Include check results
...Array.from(document.querySelectorAll("#checks-container > div")).map((card) => {
const label = card.querySelector("p.font-semibold")?.textContent || "";
const isRed = card.classList.contains("bg-red-50");
const isAmber = card.classList.contains("bg-amber-50");
return `${isRed ? "🔴" : isAmber ? "🟡" : "🟢"} ${label}`;
}),
].join("\n"),
}),
}).then(() => {
statusEl.textContent = "✓ Report sent! Check your email.";
statusEl.style.color = "#059669";
statusEl.style.display = "block";
btn.textContent = "Sent ✓";
if (window.pwTrack) window.pwTrack("lead-capture", { frn, entity, email: email.split("@")[1] });
}).catch(() => {
statusEl.textContent = "Something went wrong. Please try again or call (888) 411-0383.";
statusEl.style.color = "#dc2626";
statusEl.style.display = "block";
btn.textContent = "Send Report";
btn.disabled = false;
});
});
// --- Auto-fill from URL ---
(function init() {
const params = new URLSearchParams(window.location.search);