clia: new CLIA certificate renewal service, order page, email template + harvest

Set up the CLIA recurring-renewal vein (every clinical lab renews its CLIA cert
on a 2-year cycle; CMS publishes the full lab file with expiration dates):
- service-catalog: clia-renewal ($449, discountable) + order page (npi-intake
  steps) + intake manifest entry.
- harvest_clia_renewals.py: parse the CMS Provider-of-Services CLIA file, filter
  to labs expiring within a window (default 120d), emit name/address/phone/expiry.
  676k labs -> ~70k expiring in the next ~4 months.
- match_clia_to_nppes.py: CLIA has no NPI/email, so bridge to emailable NPPES
  orgs by normalized name+zip to recover NPI+email (yield TBD; labs that do not
  match still have clean phone+postal for a phone/mail channel).
- hc_clia_renewal.html: warm turnover-safety-net email with the striped official-
  record card (CLIA #, expiry, status), verify-on-CMS-QCOR, founder guarantee
  card, full CAN-SPAM address.
This commit is contained in:
justin 2026-06-13 22:10:51 -05:00
parent d1a9260854
commit 9c7a08f5c9
7 changed files with 398 additions and 0 deletions

View file

@ -522,6 +522,12 @@ export const COMPLIANCE_SERVICES: Record<string, ComplianceService> = {
erpnext_item: "NPPES-UPDATE", erpnext_item: "NPPES-UPDATE",
discountable: true, discountable: true,
}, },
"clia-renewal": {
name: "CLIA Certificate Renewal",
price_cents: 44900,
erpnext_item: "CLIA-RENEWAL",
discountable: true,
},
"medicare-enrollment": { "medicare-enrollment": {
name: "Medicare Enrollment (PECOS)", name: "Medicare Enrollment (PECOS)",
price_cents: 69900, price_cents: 69900,

View file

@ -0,0 +1,117 @@
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>@media only screen and (max-width:600px){.pw-wrap{width:100%!important;border-radius:0!important;}.pw-pad{padding:24px 16px!important;}}body,table,td,p,a{-webkit-text-size-adjust:100%;}table{border-collapse:collapse!important;}img{border:0;}</style></head><body style="margin:0;padding:0;background:#eef0f3;">
<center>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:#eef0f3;"><tr><td style="padding:24px 10px;">
<table role="presentation" class="pw-wrap" width="620" cellpadding="0" cellspacing="0" style="margin:0 auto;border-radius:10px;overflow:hidden;background:#fff;">
<!-- Header -->
<tr><td style="background-color:#0f766e;background:linear-gradient(135deg,#0f766e 0%,#14b8a6 100%);padding:26px 28px;">
<img src="https://performancewest.net/images/logo-white.png" alt="Performance West" style="height:44px;margin-bottom:10px;display:block" />
<h1 style="color:#fff;margin:0;font-size:21px;font-weight:700;font-family:Inter,system-ui,sans-serif;">Your CLIA certificate is coming up for renewal</h1>
<p style="color:#ccfbf1;margin:6px 0 0;font-size:13px;font-family:Inter,system-ui,sans-serif;">Let's get it filed before it lapses</p>
</td></tr>
<!-- Body -->
<tr><td class="pw-pad" style="padding:28px;font-family:Inter,system-ui,sans-serif;color:#1f2937;">
<p style="font-size:15px;margin:0 0 16px;line-height:1.6;">Hi {{ .Subscriber.Name }},</p>
<p style="font-size:14px;line-height:1.75;margin:0 0 16px;">Whoever last handled the lab certification for <strong>{{ .Subscriber.Attribs.practice }}</strong> may have moved on &mdash; CLIA certificates run on a 2-year cycle, and renewal deadlines are easy to miss when staff change.</p>
<p style="font-size:14px;line-height:1.75;margin:0 0 18px;">That is exactly what we keep an eye on, so it does not become your problem. Here is where your certificate stands:</p>
<!-- Official-record card: CLIA data is from the public CMS POS file. -->
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:6px 0 22px;">
<tr><td style="border:1px solid #cbd5e1;border-radius:10px;overflow:hidden;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0">
<tr><td style="background:#2563eb;background-image:repeating-linear-gradient(45deg,#ef4444 0,#ef4444 14px,#ffffff 14px,#ffffff 28px,#2563eb 28px,#2563eb 42px,#ffffff 42px,#ffffff 56px);padding:0;">
<p style="margin:0;padding:11px 16px;background:rgba(15,23,42,0.58);font-size:11px;letter-spacing:.4px;text-transform:uppercase;color:#ffffff;font-weight:700;text-align:center;">Official record &middot; CMS CLIA Laboratory File</p>
</td></tr>
<tr><td style="background:#f8fafc;padding:6px 16px 14px;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="font-size:13px;">
<tr style="border-bottom:1px solid #e5e7eb;"><td style="padding:9px 0;color:#64748b;">CLIA number</td><td style="padding:9px 0;font-weight:700;text-align:right;color:#0f172a;">{{ .Subscriber.Attribs.clia }}</td></tr>
<tr style="border-bottom:1px solid #e5e7eb;"><td style="padding:9px 0;color:#64748b;">Laboratory</td><td style="padding:9px 0;font-weight:600;text-align:right;color:#0f172a;">{{ .Subscriber.Attribs.practice }}</td></tr>
<tr style="border-bottom:1px solid #e5e7eb;"><td style="padding:9px 0;color:#64748b;">Certificate expires</td><td style="padding:9px 0;font-weight:700;text-align:right;color:#b91c1c;">{{ .Subscriber.Attribs.clia_expiry }}</td></tr>
<tr><td style="padding:9px 0;color:#64748b;">Status</td><td style="padding:9px 0;font-weight:700;text-align:right;color:#b91c1c;">{{ .Subscriber.Attribs.clia_status }}</td></tr>
</table>
<p style="margin:10px 0 0;font-size:11px;color:#94a3b8;line-height:1.5;">Source: CMS Provider of Services File - Clinical Laboratories (data.cms.gov), refreshed quarterly.</p>
</td></tr>
</table>
</td></tr>
</table>
<p style="font-size:14px;line-height:1.75;margin:0 0 18px;">If a CLIA certificate lapses, you cannot legally perform or bill for laboratory testing until it is reinstated &mdash; which can interrupt patient care and revenue. <strong>Starting now is the best way to make sure your renewal is filed and processed in time</strong> &mdash; CMS can take several weeks to process, so the earlier we begin, the more buffer you have against government processing delays.</p>
<!-- How it works -->
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:18px 0;"><tr><td style="background:#f0fdfa;border:1px solid #99f6e4;border-radius:10px;padding:18px;">
<h3 style="margin:0 0 10px;font-size:15px;color:#0f766e;font-weight:700;">We do the work &mdash; you barely lift a finger</h3>
<p style="font-size:13px;color:#134e4a;line-height:1.7;margin:0 0 10px;">We prepare and file your CLIA renewal (CMS Form 116) and track it through to confirmation. <strong>You never share a password and you never have to chase a government portal.</strong> The only thing we may need is a one-minute e-signature on a secure link.</p>
<p style="font-size:13px;color:#134e4a;line-height:1.7;margin:0;">No matter who handled it before, we will make sure it gets done right.</p>
</td></tr></table>
<!-- Verify-it-yourself -->
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:14px 0 18px;"><tr><td style="background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:16px;">
<p style="margin:0 0 6px;font-size:13px;color:#1e3a8a;font-weight:700;">Want to confirm it yourself?</p>
<p style="margin:0 0 12px;font-size:13px;color:#1e40af;line-height:1.6;">Look up CLIA number <strong>{{ .Subscriber.Attribs.clia }}</strong> on the public CMS QCOR laboratory lookup and you will see the same expiration date shown above.</p>
<a href="https://qcor.cms.gov/main.jsp" style="display:inline-block;padding:10px 22px;background:#fff;border:1px solid #1d4ed8;color:#1d4ed8;font-weight:700;border-radius:8px;text-decoration:none;font-size:13px;">Verify on CMS QCOR &#8599;</a>
</td></tr></table>
<!-- CTA -->
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:22px 0;"><tr><td style="background:#ecfdf5;border:2px solid #10b981;border-radius:10px;padding:18px;text-align:center;">
<p style="font-size:14px;color:#065f46;margin:0 0 6px;font-weight:600;">Let us take the CLIA renewal off your plate &mdash; the sooner we start, the better.</p>
<p style="font-size:12px;color:#047857;margin:0 0 14px;">We submit most filings within 1-2 business days, then track it through CMS processing to confirmation.</p>
<a href="https://performancewest.net/order/clia-renewal?clia={{ .Subscriber.Attribs.clia }}" style="display:inline-block;padding:14px 40px;background:#10b981;color:#fff;font-weight:700;border-radius:8px;text-decoration:none;font-size:15px;">Renew my CLIA certificate &rarr;</a>
</td></tr></table>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:18px 0;"><tr><td style="background:#f0f4f8;border-radius:8px;padding:16px;font-size:13px;color:#374151;line-height:1.6;">
<strong>Questions, or want to hand off your lab filings going forward?</strong> Just reply to this email or call <strong>(888) 411-0383</strong>. We are a dedicated healthcare compliance firm and we are happy to be the people who keep track of this for you.
</td></tr></table>
<!-- Personal guarantee from the founder: photo links to the About page so
readers can confirm a real person stands behind the work. -->
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:22px 0;"><tr><td style="background:#f8fafc;border:1px solid #e2e8f0;border-left:4px solid #0f766e;border-radius:10px;padding:20px;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td width="92" valign="top" style="padding-right:16px;">
<a href="https://performancewest.net/about">
<img src="https://performancewest.net/images/justin-hannah.jpg" alt="Justin Hannah, Founder of Performance West" width="76" height="76" style="width:76px;height:76px;border-radius:50%;display:block;border:2px solid #0f766e;" />
</a>
</td>
<td valign="top">
<p style="margin:0 0 10px;font-size:14px;color:#1f2937;line-height:1.7;font-style:italic;">&ldquo;If we handle this for you and you are not completely satisfied, I will personally make it right. You will not pay billable hours, and you will not be left chasing a government portal on your own. That is my promise.&rdquo;</p>
<p style="margin:0;">
<a href="https://performancewest.net/about" style="text-decoration:none;">
<img src="https://performancewest.net/images/justin-signature-v2.png" alt="Justin Hannah" width="150" style="width:150px;height:auto;display:block;margin:0 0 2px;" />
</a>
<span style="font-size:13px;font-weight:700;color:#0f172a;">Justin Hannah</span><br>
<span style="font-size:12px;color:#64748b;">Founder &amp; Principal Consultant, Performance West Inc.</span>
</p>
</td>
</tr>
</table>
</td></tr></table>
<!-- Trust signals + true social proof -->
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:20px 0 6px;border-top:1px solid #e5e7eb;padding-top:14px;">
<tr>
<td align="center" style="padding:10px 4px;font-family:Inter,system-ui,sans-serif;">
<span style="display:inline-block;margin:0 8px;font-size:11px;font-weight:600;color:#0f766e;">&#128737;&#65039; SOC 2 Type II hosting</span>
<span style="display:inline-block;margin:0 8px;font-size:11px;font-weight:600;color:#0f766e;">&#9989; HIPAA &amp; PCI compliant</span>
<span style="display:inline-block;margin:0 8px;font-size:11px;font-weight:600;color:#0f766e;">&#128274; 256-bit TLS encrypted</span>
<span style="display:inline-block;margin:0 8px;font-size:11px;font-weight:600;color:#0f766e;">&#128179; Secure payment by Stripe</span>
</td>
</tr>
<tr>
<td align="center" style="padding:4px;font-family:Inter,system-ui,sans-serif;font-size:12px;color:#4b5563;">
<strong style="color:#047857;">100% satisfaction guarantee</strong> &middot; fixed pricing, no billable hours &middot; trusted by providers nationwide
</td>
</tr>
</table>
</td></tr>
<!-- Footer -->
<tr><td style="padding:16px 28px;background:#f8fafc;border-top:1px solid #e5e7eb;font-size:11px;color:#9ca3af;text-align:center;">
<p style="margin:0 0 8px;">Performance West is an independent compliance firm, not affiliated with CMS or Medicare.</p>
<p style="margin:0;">Performance West Inc. &middot; 525 Randall Ave Ste 100-1195, Cheyenne, WY 82001 &middot; <a href="https://performancewest.net" style="color:#6b7280;">performancewest.net</a></p>
<p style="margin:6px 0 0;"><a href="{{ UnsubscribeURL }}" style="color:#6b7280;">Unsubscribe</a></p>
</td></tr>
</table></td></tr></table></center></body></html>

View file

@ -0,0 +1,138 @@
#!/usr/bin/env python3
"""Harvest active CLIA labs with an upcoming certificate expiration.
Reads the CMS "Provider of Services File - Clinical Laboratories" CSV
(clia.DATA.Qx_YYYY.csv from data.cms.gov) and writes the labs whose CLIA
certificate expires within a configurable window. CLIA certificates run on a
2-year cycle, so the expiration date (TRMNTN_EXPRTN_DT) is the recurring
reminder trigger.
The POS/CLIA file has NO NPI and NO email -- only facility name, mailing
address and phone. So this harvest emits the matchable identity columns
(name + city/state/zip + phone) plus the cert dates; a separate matcher joins
to NPPES (by name+zip) to recover an emailable NPI where possible. Labs that
never match still have a clean phone + postal address for a phone/mail channel.
Usage:
python3 scripts/harvest_clia_renewals.py CLIA_INPUT.csv OUT.csv [--window-days 120]
"""
from __future__ import annotations
import argparse
import csv
import sys
from collections import Counter
from datetime import date, datetime, timedelta
# Columns we need from the POS CLIA file (by header name; robust to reordering).
WANT = {
"clia": "PRVDR_NUM",
"name": "FAC_NAME",
"addr": "ST_ADR",
"city": "CITY_NAME",
"state": "STATE_CD",
"zip": "ZIP_CD",
"phone": "PHNE_NUM",
"expiry": "TRMNTN_EXPRTN_DT",
"effective": "CRTFCT_EFCTV_DT",
"cert_type": "CRTFCT_TYPE_CD",
"compliance": "CMPLNC_STUS_CD",
}
# CLIA certificate types worth reminding (all are renewable 2yr certs):
# 1 = Registration, 2 = Compliance, 3 = Accreditation,
# 4 = PPM (Provider-Performed Microscopy), 9 = Waiver
# We keep all of them; the expiry window is the real filter.
def parse_yyyymmdd(s: str):
s = (s or "").strip()
if len(s) == 8 and s.isdigit():
try:
return datetime.strptime(s, "%Y%m%d").date()
except ValueError:
return None
return None
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("infile")
ap.add_argument("outfile")
ap.add_argument("--window-days", type=int, default=120,
help="emit labs expiring within this many days from today (default 120)")
ap.add_argument("--include-recently-expired-days", type=int, default=30,
help="also include labs that expired up to N days ago (lapsed, still renewable)")
args = ap.parse_args()
today = date.today()
horizon = today + timedelta(days=args.window_days)
grace = today - timedelta(days=args.include_recently_expired_days)
with open(args.infile, newline="", encoding="latin-1") as f:
reader = csv.reader(f)
header = next(reader)
idx = {c: i for i, c in enumerate(header)}
missing = [k for k, col in WANT.items() if col not in idx]
if missing:
print(f"ERROR: input missing columns: {[WANT[m] for m in missing]}", file=sys.stderr)
return 2
stats = Counter()
rows_out = []
for row in reader:
stats["total"] += 1
if len(row) <= max(idx[c] for c in WANT.values()):
stats["short_row"] += 1
continue
exp = parse_yyyymmdd(row[idx[WANT["expiry"]]])
if not exp:
stats["no_expiry"] += 1
continue
if not (grace <= exp <= horizon):
stats["outside_window"] += 1
continue
name = row[idx[WANT["name"]]].strip()
state = row[idx[WANT["state"]]].strip()
zipc = row[idx[WANT["zip"]]].strip()[:5]
if not name or not state:
stats["no_name_state"] += 1
continue
days_until = (exp - today).days
rows_out.append({
"clia": row[idx[WANT["clia"]]].strip(),
"name": name,
"addr": row[idx[WANT["addr"]]].strip(),
"city": row[idx[WANT["city"]]].strip(),
"state": state,
"zip": zipc,
"phone": row[idx[WANT["phone"]]].strip(),
"expiry_date": exp.isoformat(),
"days_until": days_until,
"cert_type": row[idx[WANT["cert_type"]]].strip(),
"status": "lapsed" if days_until < 0 else "upcoming",
})
stats["emitted"] += 1
rows_out.sort(key=lambda r: r["days_until"]) # most urgent first
with open(args.outfile, "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=list(rows_out[0].keys()) if rows_out else
["clia", "name", "addr", "city", "state", "zip", "phone",
"expiry_date", "days_until", "cert_type", "status"])
w.writeheader()
w.writerows(rows_out)
print(f"CLIA harvest: {stats['total']:,} rows scanned")
for k in ("no_expiry", "outside_window", "no_name_state", "short_row"):
if stats[k]:
print(f" skipped {k}: {stats[k]:,}")
print(f" EMITTED (expiring in [-{args.include_recently_expired_days}d, "
f"+{args.window_days}d]): {stats['emitted']:,} -> {args.outfile}")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -0,0 +1,100 @@
#!/usr/bin/env python3
"""Match CLIA labs to an emailable NPPES org by (normalized name + zip5).
CLIA POS files have no NPI/email; our NPPES verified set is keyed by NPI. This
bridges them: it streams the big NPPES npidata_pfile, keeps ONLY the orgs whose
NPI already has a verified email (so the scan stays cheap), indexes them by
normalized org-name + zip5, then matches each CLIA lab to recover its NPI+email.
Outputs the CLIA renewal rows that got an emailable match, with email +
mx_provider appended (ready to feed the HC campaign builder as a CLIA segment).
Usage:
python3 scripts/match_clia_to_nppes.py \
CLIA_RENEWALS.csv NPPES_VERIFIED.csv NPIDATA_PFILE.csv OUT.csv
"""
from __future__ import annotations
import csv
import re
import sys
csv.field_size_limit(10_000_000)
# npidata_pfile column names we use (stable header names in the NPPES file).
COL_NPI = "NPI"
COL_ORG = "Provider Organization Name (Legal Business Name)"
COL_ZIP_PRACTICE = "Provider Business Practice Location Address Postal Code"
COL_ENTITY = "Entity Type Code" # 2 = organization
def norm_name(s: str) -> str:
s = (s or "").upper()
s = re.sub(r"[^A-Z0-9 ]", " ", s)
# drop common suffixes/noise that differ between CLIA and NPPES spellings
s = re.sub(r"\b(LLC|INC|PC|PLLC|PA|LTD|CORP|CO|LP|LLP|THE|DBA)\b", " ", s)
s = re.sub(r"\s+", " ", s).strip()
return s
def main() -> int:
clia_f, nppes_verified_f, npidata_f, out_f = sys.argv[1:5]
# 1) emailable NPIs -> (email, mx_provider)
email_by_npi: dict[str, tuple[str, str]] = {}
with open(nppes_verified_f, newline="", encoding="utf-8") as f:
for r in csv.DictReader(f):
npi = (r.get("npi") or "").strip()
email = (r.get("email") or "").strip()
if npi and email and (r.get("verify_ok", "Y") in ("Y", "", "true", "True")):
email_by_npi[npi] = (email, r.get("mx_provider", ""))
print(f"emailable NPIs: {len(email_by_npi):,}", file=sys.stderr)
# 2) stream npidata_pfile, keep only those NPIs -> index by (name, zip5)
idx: dict[tuple[str, str], str] = {}
with open(npidata_f, newline="", encoding="latin-1") as f:
reader = csv.DictReader(f)
seen = 0
for row in reader:
npi = (row.get(COL_NPI) or "").strip()
if npi not in email_by_npi:
continue
org = norm_name(row.get(COL_ORG, ""))
zip5 = (row.get(COL_ZIP_PRACTICE) or "").strip()[:5]
if org and zip5:
idx[(org, zip5)] = npi
seen += 1
if seen == len(email_by_npi):
break
print(f"indexed emailable orgs by name+zip: {len(idx):,}", file=sys.stderr)
# 3) match CLIA -> index
matched = 0
total = 0
with open(clia_f, newline="", encoding="utf-8") as fin, \
open(out_f, "w", newline="", encoding="utf-8") as fout:
reader = csv.DictReader(fin)
fieldnames = reader.fieldnames + ["npi", "email", "mx_provider"]
w = csv.DictWriter(fout, fieldnames=fieldnames)
w.writeheader()
for row in reader:
total += 1
key = (norm_name(row["name"]), (row["zip"] or "")[:5])
npi = idx.get(key)
if not npi:
continue
email, mx = email_by_npi[npi]
row["npi"] = npi
row["email"] = email
row["mx_provider"] = mx
w.writerow(row)
matched += 1
print(f"CLIA labs: {total:,} | matched to emailable NPPES org: {matched:,} "
f"({100*matched/max(total,1):.1f}%)")
print(f" -> {out_f}")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -150,6 +150,7 @@ export const INTAKE_MANIFEST: Record<string, IntakeStep[]> = {
"npi-revalidation": ["npi-intake", "review", "payment"], "npi-revalidation": ["npi-intake", "review", "payment"],
"npi-reactivation": ["npi-intake", "review", "payment"], "npi-reactivation": ["npi-intake", "review", "payment"],
"nppes-update": ["npi-intake", "review", "payment"], "nppes-update": ["npi-intake", "review", "payment"],
"clia-renewal": ["npi-intake", "review", "payment"],
"medicare-enrollment": ["npi-intake", "review", "payment"], "medicare-enrollment": ["npi-intake", "review", "payment"],
"oig-sam-screening": ["npi-intake", "review", "payment"], "oig-sam-screening": ["npi-intake", "review", "payment"],
"provider-compliance-bundle": ["npi-intake", "review", "payment"], "provider-compliance-bundle": ["npi-intake", "review", "payment"],

View file

@ -27,6 +27,7 @@ export const SERVICE_META: Record<string, ServiceMeta> = {
"cdr-storage-tier1": { name: "CDR Storage Tier 1 (50 GB / 50M calls)", price_cents: 9900 }, "cdr-storage-tier1": { name: "CDR Storage Tier 1 (50 GB / 50M calls)", price_cents: 9900 },
"cdr-storage-tier2": { name: "CDR Storage Tier 2 (250 GB / 250M calls)", price_cents: 29900 }, "cdr-storage-tier2": { name: "CDR Storage Tier 2 (250 GB / 250M calls)", price_cents: 29900 },
"cdr-storage-tier3": { name: "CDR Storage Tier 3 (1 TB / 1B calls)", price_cents: 79900 }, "cdr-storage-tier3": { name: "CDR Storage Tier 3 (1 TB / 1B calls)", price_cents: 79900 },
"clia-renewal": { name: "CLIA Certificate Renewal", price_cents: 44900 },
"cores-frn-registration": { name: "CORES / FRN Registration", price_cents: 14900 }, "cores-frn-registration": { name: "CORES / FRN Registration", price_cents: 14900 },
"corp-formation": { name: "Corporation Formation", price_cents: 24900 }, "corp-formation": { name: "Corporation Formation", price_cents: 24900 },
"cpni-certification": { name: "CPNI Annual Certification", price_cents: 19900 }, "cpni-certification": { name: "CPNI Annual Certification", price_cents: 19900 },

View file

@ -0,0 +1,35 @@
---
import Base from "../../layouts/Base.astro";
import VerticalOrderHeader from "../../components/VerticalOrderHeader.astro";
import Wizard from "../../components/intake/Wizard.astro";
import OrderPriceBanner from "../../components/OrderPriceBanner.astro";
import { INTAKE_MANIFEST, SERVICE_META } from "../../lib/intake_manifest";
const slug = "clia-renewal";
const steps = INTAKE_MANIFEST[slug];
const meta = SERVICE_META[slug];
const title = meta ? `Order ${meta.name}` : "Order";
const description = "Renew your CLIA laboratory certificate with CMS before it expires. CLIA certificates run on a 2-year cycle; an expired certificate stops you from legally performing or billing for lab testing.";
---
<Base title={title} description={description}>
<main>
<section class="pw-order-intro">
<h1>{meta?.name}</h1>
<p class="pw-desc">{description}</p>
</section>
<VerticalOrderHeader vertical="healthcare" />
<OrderPriceBanner priceCents={meta?.price_cents} govFeeLabel={meta?.gov_fee_label} serviceSlug={slug} note="Choose card, ACH, or PayPal at payment." />
<Wizard service_slug={slug} steps={steps ?? ["npi-intake", "review", "payment"]} title={meta?.name ?? slug} />
</main>
</Base>
<style>
main { max-width: 900px; margin: 0 auto; padding: 2rem 1.25rem 4rem; }
.pw-order-intro { margin-bottom: 1.5rem; }
.pw-order-intro h1 { margin: 0 0 0.25rem; color: var(--pw-navy, #1a2744); }
.pw-desc { color: var(--pw-muted, #64748b); max-width: 48rem; }
</style>