const PHONE_DISPLAY="866-291-9125",PHONE_TEL="+18662919125";
const CALCOM_BASE="https://cal.com/team/tangelo/ny-naviga";
const LEAD_ENDPOINT="https://script.google.com/a/macros/jointangelo.com/s/AKfycbz8qItQdFELrpP2WXwxIrFcg48r7UZVRX0NgVO3TF9mGWRUnsF2ol9Qs9XpsEqk7EMj/exec";
const GEO_ENDPOINT="https://ipapi.co/json/";
function readKioskRef(){try{const u=new URL(window.location.href);const r=(u.searchParams.get("ref")||"").trim();if(r){try{localStorage.setItem("tgl_kiosk_ref",r)}catch(e){}return r}return localStorage.getItem("tgl_kiosk_ref")||null}catch(e){return null}}
function readGclid(){return (window.TANGELO_READ_GCLID||function(){return null})()}
function kioskHomeUrl(){const r=lead.kioskRef||readKioskRef();const params=[];if(r)params.push("ref="+encodeURIComponent(r));try{const cur=new URL(window.location.href);const d=cur.searchParams.get("deflang");if(d)params.push("deflang="+encodeURIComponent(d))}catch(e){}return "/eligibility"+(params.length?"?"+params.join("&"):"")}
function makeRefId(){const d=new Date();const ymd=d.getFullYear().toString().slice(2)+String(d.getMonth()+1).padStart(2,"0")+String(d.getDate()).padStart(2,"0");const rand=Math.random().toString(36).slice(2,7).toUpperCase();return"TGL-"+ymd+"-"+rand}
function nyTimestamp(){try{const f=new Intl.DateTimeFormat("en-US",{timeZone:"America/New_York",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:false});const p={};f.formatToParts(new Date()).forEach(x=>p[x.type]=x.value);return p.year+"-"+p.month+"-"+p.day+" "+p.hour+":"+p.minute+":"+p.second+" ET"}catch(e){return new Date().toISOString()}}
function fetchGeo(){try{fetch(GEO_ENDPOINT,{cache:"no-store"}).then(r=>r.ok?r.json():null).then(j=>{if(!j)return;lead.geo={ip:j.ip||null,city:j.city||null,region:j.region||null,country:j.country_name||j.country||null,postal:j.postal||null,org:j.org||null}}).catch(()=>{})}catch(e){}}
function fmtPhoneDisp(v){const d=(v||"").replace(/\D/g,"").slice(0,10);if(!d)return "";if(d.length<=3)return "("+d;if(d.length<=6)return "("+d.slice(0,3)+")"+d.slice(3);return "("+d.slice(0,3)+")"+d.slice(3,6)+"-"+d.slice(6)}
function fmtPhoneStore(v){const d=(v||"").replace(/\D/g,"").slice(0,10);return d.length===10?d.slice(0,3)+"-"+d.slice(3,6)+"-"+d.slice(6):d}
function fmtDob(v){return (window.TANGELO_FMT_DOB||function(x){return String(x||"")})(v)}
/* Shared DOB validator — used by the cin_or_dob branch step (CA) and by any required
type:"text" step with id "dob" (NY/PHS). Accepts 1-2 digit month/day because
TANGELO_FMT_DOB emits "1/1/2000", not "01/01/2000". Uses a real Date round-trip so
02/30 and 04/31 are rejected while leap days are accepted. */
function isValidDob(s){
var m=String(s||"").trim().match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
if(!m)return false;
var mo=+m[1],da=+m[2],yr=+m[3];
if(mo<1||mo>12||da<1||yr<1900||yr>(new Date()).getFullYear())return false;
var dt=new Date(yr,mo-1,da);
return dt.getFullYear()===yr&&dt.getMonth()===(mo-1)&&dt.getDate()===da;
}
/* Normalize to mm/dd/yyyy for storage regardless of how it was typed. */
function padDob(s){var m=String(s||"").match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);if(!m)return String(s||"");return ("0"+m[1]).slice(-2)+"/"+("0"+m[2]).slice(-2)+"/"+m[3]}
const _TZ=(window.TANGELO_ZIPS||{nyc:{},hvcc:{},ha:{},somos:{},si_pps:{},heali:{},care_compass:{},fl_ipa:{},wny_icc:{}});
const ZIPS=_TZ.nyc,HVCC_SET=_TZ.hvcc,HA_SET=_TZ.ha,SOMOS_SET=_TZ.somos,SI_PPS_SET=_TZ.si_pps,HEALI_SET=_TZ.heali,CARE_COMPASS_SET=_TZ.care_compass,FL_IPA_SET=_TZ.fl_ipa,WNY_ICC_SET=_TZ.wny_icc;
/* SIPPS carve-out (2026-08-30). These ZIPs are present in the PHS/nyc set in tangelo-zips.txt,
so before this override they resolved to path:"nyc" and were offered PHS navigator booking.
They are actually covered by Staten Island PPS, and are not eligible under PHS.
Checked BEFORE the ZIPS lookup because that lookup would otherwise win.
These are Brooklyn (11209/11219/11220/11228) and Queens (11355/11368/11373/11377) ZIPs —
SCN coverage areas do not follow borough boundaries, so this is expected, but if a ZIP is
ever added here in error the symptom is a lead being redirected away from PHS booking. */
const SIPPS_OVERRIDE={"11209":1,"11219":1,"11220":1,"11228":1,"11355":1,"11368":1,"11373":1,"11377":1};
function zipPath(zip){zip=(zip||"").trim();if(!/^\d{5}$/.test(zip))return{path:"invalid"};if(SIPPS_OVERRIDE[zip])return{path:"ny",region:"ny_si_pps"};if(ZIPS[zip])return{path:"nyc",region:"nyc",borough:ZIPS[zip]};if(SOMOS_SET[zip])return{path:"ny",region:"ny_somos"};if(SI_PPS_SET[zip])return{path:"ny",region:"ny_si_pps"};if(HEALI_SET[zip])return{path:"ny",region:"ny_heali"};if(HVCC_SET[zip])return{path:"ny",region:"ny_hvcc"};if(HA_SET[zip])return{path:"ny",region:"ny_ha"};if(CARE_COMPASS_SET[zip])return{path:"ny",region:"ny_care_compass"};if(FL_IPA_SET[zip])return{path:"ny",region:"ny_fl_ipa"};if(WNY_ICC_SET[zip])return{path:"ny",region:"ny_wny_icc"};const n=parseInt(zip,10);if(n>=90001&&n<=96199)return n<=93599?{path:"ca",region:"ca_south"}:{path:"ca",region:"ca_north"};return{path:"other",region:"none"}}
const NYC_PLANS=window.TANGELO_NYC_PLANS||[];
function lkEW(){return card("https://cdn.prod.website-files.com/66edff10d2c53b8e1eaf4daa/6a1c88f0b939ef8e36c39a31_engagewell%20logo.png","EngageWell IPA")}
function card(src,alt){return''}
function textCard(t){return''+t+''}
function partnersFor(region){if(region==="nyc")return lkEW();if(region==="ny_up")return "";if(region==="ca_south")return textCard("Blue Shield of CA Promise")+textCard("IEHP");if(region==="ca_north")return textCard("Contra Costa Health Plan");return""}
const PARTNERSHIP_LBL={en:"in partnership with",es:"en colaboración con",ko:"파트너십을 통해",ru:"в партнёрстве с",zh:"合作伙伴:"};
function setCoBrand(region){const band=document.getElementById("cobrandBand");const inner=partnersFor(region);if(!inner){band.classList.remove("show");band.innerHTML="";return}band.innerHTML=''+(PARTNERSHIP_LBL[lang]||PARTNERSHIP_LBL.en)+''+inner;band.classList.add("show")}
const SUPPORTED_LANGS=["en","es","ko","ru","zh"];
function detectLang(){try{var u=new URL(window.location.href);var d=(u.searchParams.get("deflang")||"").toLowerCase();if(SUPPORTED_LANGS.indexOf(d)>=0)return d;var s=(localStorage.getItem("tgl_lang")||"").toLowerCase();if(SUPPORTED_LANGS.indexOf(s)>=0)return s;var b=(navigator.language||navigator.userLanguage||"en").toLowerCase();if(b.startsWith("ko"))return "ko";if(b.startsWith("ru"))return "ru";if(b.startsWith("zh"))return "zh";if(b.startsWith("es"))return "es";return "en"}catch(e){return "en"}}
let lang=detectLang();
const I18N=window.TANGELO_I18N||{};
function L(k){return(I18N[k]&&I18N[k][lang])||(I18N[k]&&I18N[k].en)||k}
const _S=window.TANGELO_STEPS||{};
const T=_S.T,YN=_S.YN,STEP_ZIP=_S.STEP_ZIP,RISK_OPTIONS=_S.RISK_OPTIONS,NYC_STEPS=_S.NYC_STEPS,CAPTURE_STEPS=_S.CAPTURE_STEPS,makeCapPlanStep=_S.makeCapPlanStep;
let FLOW=NYC_STEPS;let current=0;const answers={};
const lead={source:"prospective-member-questionnaire",refId:makeRefId(),kioskRef:readKioskRef(),gclid:readGclid(),createdAt:new Date().toISOString(),createdAtNY:nyTimestamp(),geo:null,device:(window.TANGELO_DEVICE&&window.TANGELO_DEVICE())||{type:"unknown",smsCapable:false}};
window.__TGL_KIOSK_MODE=!!lead.kioskRef;
function normalizePlanExp(raw){var s=String(raw||"").trim();if(!s)return "";var m=s.match(/^(0?[1-9]|1[0-2])\/(\d{2}|\d{4})$/);if(!m)return null;var mo=m[1].length===1?"0"+m[1]:m[1];var yr=m[2].length===2?"20"+m[2]:m[2];return mo+"/"+yr}
const stepsEl=document.getElementById("steps");
function isVisible(s){return!s.showIf||s.showIf(answers)}
function firstVisibleFrom(i){for(let j=i;j{if(!isVisible(step))return;visNum++;const div=document.createElement("div");div.className="step "+(icurrent?"locked collapsed ":"");div.id="step-"+step.id;const head=document.createElement("div");head.className="step-head";head.innerHTML='
'+(_isDob?''+(step.dobErr?step.dobErr[lang]:"Please enter a valid date (MM/DD/YYYY).")+'':'')+'
';const _req=!!step.required;
/* A required DOB must be a REAL date, not just non-empty — otherwise "1" satisfies the gate and
we store garbage in the field the team uses to verify Medicaid eligibility. Other required
text steps keep the original non-empty check. */
const _okText=function(x){return _isDob?isValidDob(x):!!String(x||"").trim()};
const _btn=contBtn(()=>{answers[step.id]=(_isDob&&isValidDob(val(step.id)))?padDob(val(step.id)):val(step.id);commit(step.id)},_req?step.id:null,_req&&!_okText(v));box.appendChild(_btn);if(_req||_isDob){setTimeout(()=>{const _inp=document.getElementById("in-"+step.id);if(!_inp)return;const _err=document.getElementById("dobfmt-err");_inp.addEventListener("input",e=>{if(_isDob)e.target.value=fmtDob(e.target.value);const _v=e.target.value.trim();answers[step.id]=(_isDob&&isValidDob(_v))?padDob(_v):_v;if(_isDob&&_err){_err.style.display=(_v.length===10&&!isValidDob(_v))?"block":"none"}if(_req)enableCont(step.id,_okText(_v))})},50)}return box}if(step.type==="text2"){box.innerHTML='';box.appendChild(contBtn(()=>{answers[step.id]={a:val(step.id+"-1"),b:val(step.id+"-2")};commit(step.id)}));return box}if(step.type==="cin_or_dob"){
/* 2026-08-30: replaces the old optional two-field cin_dob step. DOB is now REQUIRED for
eligibility verification, but many members don't have their Medi-Cal card handy — so we ask
which they have and require exactly one. Storage keys stay answers.cin / answers.dob, so
everything downstream (identifierLine_ in Apps Script, the sheet columns) is unchanged. */
var _m=answers.cinDobMode||"";
var _optHTML=function(mode,label){return '
'
/* DOB is shown in BOTH modes (2026-08-30): required when they don't have a CIN, optional
alongside it when they do. Two identifiers verify faster than one, and asking for the DOB
costs a member almost nothing once they're already on this step. */
+'
';
var _validCin=function(s){return /^\d{8}[A-Z]$/.test(String(s||"").toUpperCase())};
/* Accepts 1-2 digit month/day — TANGELO_FMT_DOB deliberately emits "1/1/2000", not "01/01/2000",
so requiring two digits left Continue permanently disabled for anyone born in Jan-Sep on a
single-digit day. Uses a real Date round-trip so 02/30 and 04/31 are rejected too. */
var _validDob=isValidDob,_padDob=padDob; /* hoisted to module scope — shared with the NY/PHS dob step */
/* "cin" mode: CIN required. DOB optional in self-serve — but if they started typing one it must
be a real date before we continue, otherwise we'd silently store garbage.
"dob" mode: DOB required.
KIOSK MODE (2026-08-30): DOB is required in BOTH modes. At a kiosk a staff member is present
to help, so the friction is low, and DOB is what the team verifies enrollment against. This
matches the NY kiosk cin_dob step, which also requires DOB. */
var _kioskDobRequired=!!window.__TGL_KIOSK_MODE;
var _ok=function(){
if(answers.cinDobMode==="cin"){
if(!_validCin(answers.cin))return false;
var raw=String(answers.dob||"").trim();
if(_kioskDobRequired)return _validDob(raw);
return raw===""||_validDob(raw);
}
if(answers.cinDobMode==="dob")return _validDob(answers.dob);
return false;
};
box.appendChild(contBtn(function(){commit(step.id)},step.id,!_ok()));
setTimeout(function(){
var wrapC=document.getElementById("cd-cin-wrap"),wrapD=document.getElementById("cd-dob-wrap");
var c=document.getElementById("in-cin"),d=document.getElementById("in-dob");
var errC=document.getElementById("cin-err"),errD=document.getElementById("dob-err");
Array.prototype.forEach.call(box.querySelectorAll("[data-cdm]"),function(el){
el.addEventListener("click",function(){
var mode=el.getAttribute("data-cdm");
answers.cinDobMode=mode;
Array.prototype.forEach.call(box.querySelectorAll("[data-cdm]"),function(o){o.classList.toggle("sel",o===el)});
if(wrapC)wrapC.style.display=(mode==="cin"?"":"none");
if(wrapD)wrapD.style.display=""; // DOB is offered in both modes
/* Label stays plain "Date of birth" in both modes — per request 2026-08-30, no "(optional)"
suffix. The field IS optional next to a CIN (see _ok()), we just don't advertise it:
labelling it optional invites people to skip a second identifier we'd rather have. */
/* Switching to "no CIN" clears any CIN already typed so we don't submit a half-abandoned
value. Switching to "yes" keeps the DOB — it's a welcome second identifier, not a conflict. */
if(mode==="dob"){delete answers.cin;if(c)c.value=""}
if(errC)errC.style.display="none";if(errD)errD.style.display="none";
enableCont(step.id,_ok());
setTimeout(function(){var f=(mode==="cin"?c:d);if(f)f.focus()},60);
});
});
if(c)c.addEventListener("input",function(e){
var raw=(e.target.value||"").toUpperCase().replace(/[^0-9A-Z]/g,"").substring(0,9);
if(raw.length<=8){raw=raw.replace(/[A-Z]/g,"")}else{raw=raw.substring(0,8).replace(/[A-Z]/g,"")+raw.substring(8).replace(/\d/g,"")}
e.target.value=raw;answers.cin=raw;
if(errC){var bad=raw.length===9&&!_validCin(raw);errC.textContent=L("cinFormatErr");errC.style.display=bad?"block":"none"}
enableCont(step.id,_ok());
});
if(d)d.addEventListener("input",function(e){
e.target.value=fmtDob(e.target.value);
answers.dob=_validDob(e.target.value)?_padDob(e.target.value):e.target.value;
if(errD){var bad=e.target.value.length===10&&!_validDob(e.target.value);errD.textContent=(step.dobErr?step.dobErr[lang]:"Please enter a valid date (MM/DD/YYYY).");errD.style.display=bad?"block":"none"}
enableCont(step.id,_ok());
});
},50);
return box}
if(step.type==="cin_dob"){box.innerHTML='
';
/* DOB is REQUIRED here as of 2026-08-30 (kiosk mode). CIN stays optional — kiosk users often
have their card, but not always, and DOB is what the team verifies enrollment against.
Continue stays disabled until DOB is a real date. */
var _cdOk=function(){return isValidDob(answers.dob)};
box.appendChild(contBtn(()=>{var cin=val("cin").toUpperCase();if(cin&&!/^\d{8}[A-Z]$/.test(cin)){var e=document.getElementById("cin-err");if(e){e.textContent=L("cinFormatErr");e.style.display="block"}return}if(!isValidDob(val("dob")))return;answers.cin=cin;answers.dob=padDob(val("dob"));commit(step.id)},step.id,!_cdOk()));
setTimeout(()=>{var c=document.getElementById("in-cin"),d=document.getElementById("in-dob"),errEl=document.getElementById("cin-err"),dErr=document.getElementById("cd2-dob-err");
if(c)c.addEventListener("input",function(e){var raw=(e.target.value||"").toUpperCase().replace(/[^0-9A-Z]/g,"").substring(0,9);if(raw.length<=8){raw=raw.replace(/[A-Z]/g,"")}else{raw=raw.substring(0,8).replace(/[A-Z]/g,"")+raw.substring(8).replace(/\d/g,"")}e.target.value=raw;if(errEl){if(raw&&!/^\d{8}[A-Z]$/.test(raw)&&raw.length===9){errEl.textContent=L("cinFormatErr");errEl.style.display="block"}else{errEl.style.display="none"}}});
if(d)d.addEventListener("input",function(e){e.target.value=fmtDob(e.target.value);var v=e.target.value.trim();answers.dob=isValidDob(v)?padDob(v):v;if(dErr){dErr.textContent=(step.dobErr?step.dobErr[lang]:"Please enter a valid date (MM/DD/YYYY).");dErr.style.display=(v.length===10&&!isValidDob(v))?"block":"none"}enableCont(step.id,_cdOk())})},50);return box}if(step.type==="plan_exp"){
box.innerHTML='
';
const _ecBtn=contBtn(()=>{answers.early_name=val("ec-name");answers.early_phone=fmtPhoneStore(val("ec-phone"));answers.early_email=val("ec-email");if(answers.early_name)lead.name=lead.name||answers.early_name;if(answers.early_phone)lead.phone=lead.phone||answers.early_phone;if(answers.early_email)lead.email=lead.email||answers.early_email;lead.consent=true;lead.consentAtNY=nyTimestamp();lead.consentMethod="click-through";lead.consentVersion=(window.TANGELO_CONSENT_VERSION||"");commit(step.id)},"early_contact",!(_hasN&&_hasP));
_ecBtn.querySelector("button").textContent=_cc.btnLabel+" →";
box.appendChild(_ecBtn);setTimeout(()=>{var n=document.getElementById("in-ec-name"),p=document.getElementById("in-ec-phone"),e=document.getElementById("in-ec-email");function recheck(){var nv=(n?n.value.trim():""),pd=(p?p.value:"").replace(/\D/g,"");enableCont("early_contact",nv.length>1&&pd.length>=10)}if(p)p.addEventListener("input",function(){p.value=fmtPhoneDisp(p.value);recheck()});if(n)n.addEventListener("input",recheck);if(e)e.addEventListener("input",recheck)},50);return box}if(step.type==="contact"){
var _c=(window.TANGELO_BUILD_CONSENT||function(){return{consentHTML:"",btnLabel:"Submit"}})(FLOW===NYC_STEPS,lead.region==="nyc",lang);
// Language dropdown — hidden in kiosk mode (kiosk has its own top language bar). Pre-selects the
// current UI language so most users just leave it. Overwrites lead.lang on submit so the team
// gets the explicit choice instead of just browser-detected. EN/ES/KO only (navigator capacity).
var _langLbl = ({en:"Language",es:"Idioma",ko:"언어",ru:"Язык",zh:"语言"})[lang] || "Language";
var _langHTML = window.__TGL_KIOSK_MODE ? "" : '';
box.innerHTML=''+_langHTML+'
'+_c.consentHTML+'
';
const b=contBtn(()=>submitContact(),null,true);b.querySelector("button").textContent=_c.btnLabel+" →";box.appendChild(b);setTimeout(()=>{["c-name","c-phone","c-email"].forEach(id=>{const e=document.getElementById(id);if(e)e.addEventListener("input",validateContact);if(e)e.addEventListener("change",validateContact)});const ph=document.getElementById("c-phone");if(ph)ph.addEventListener("input",function(){ph.value=fmtPhoneDisp(ph.value)});validateContact()},50);return box}return box}
function optEl(step,o,multi){const el=document.createElement("label");el.className="opt";el.dataset.v=o.v;const cur=answers[step.id];const selected=multi?(Array.isArray(cur)&&cur.includes(o.v)):(cur===o.v);if(selected)el.classList.add("sel");el.innerHTML=''+o.ttl[lang]+''+(o.desc?''+o.desc[lang]+'':"")+'';el.onclick=(e)=>{e.preventDefault();if(multi){let arr=Array.isArray(answers[step.id])?answers[step.id].slice():[];if(o.exclusive){arr=arr.includes(o.v)?[]:[o.v]}else{arr=arr.filter(x=>{const opt=step.options.find(p=>p.v===x);return!(opt&&opt.exclusive)});arr=arr.includes(o.v)?arr.filter(x=>x!==o.v):arr.concat(o.v)}answers[step.id]=arr;step.options.forEach(p=>{const n=el.parentElement.querySelector('[data-v="'+p.v+'"]');if(n)n.classList.toggle("sel",arr.includes(p.v))});enableCont(step.id,arr.length>0)}else{answers[step.id]=o.v;el.parentElement.querySelectorAll(".opt").forEach(n=>n.classList.remove("sel"));el.classList.add("sel");
if(step.id==="heard"&&isCAMediCal()){enableCont(step.id,true);return}
if(window._tglAutoCommit)clearTimeout(window._tglAutoCommit);window._tglAutoCommit=setTimeout(()=>{if(FLOW[current]&&FLOW[current].id===step.id)commit(step.id)},250)}};return el}
function contBtn(fn,gateId,startDisabled){const wrap=document.createElement("div");wrap.className="btn-row";const b=document.createElement("button");b.className="scr-btn scr-btn-primary";b.textContent=L("cont");b.onclick=fn;if(gateId){const has=answers[gateId];const ok=Array.isArray(has)?has.length>0:!!has;b.disabled=!ok;b.dataset.gate=gateId}
/* BUGFIX 2026-08-30: an explicit startDisabled is now AUTHORITATIVE (it can enable, not just
disable). The gateId lookup above assumes a step stores its answer under answers[stepId],
which is false for steps that write to their own keys — early_contact (early_name /
early_phone) and cin_dob (cin / dob / cinDobMode). For those, re-entering a completed step
left Continue permanently disabled: the gate lookup found nothing, and because the fields
were already filled the user never fired an input event to re-enable it. Callers that omit
the argument keep the old gateId behavior. */
if(startDisabled!==undefined)b.disabled=!!startDisabled;else if(startDisabled)b.disabled=true;
wrap.appendChild(b);return wrap}
function enableCont(gateId,ok){const b=document.querySelector('button[data-gate="'+gateId+'"]');if(b)b.disabled=!ok}
function val(id){const e=document.getElementById("in-"+id);return e?e.value.trim():""}
function submitZip(){const z=document.getElementById("in-zip").value.trim();const msg=document.getElementById("zip-msg");const r=zipPath(z);answers.zip=z;lead.zip=z;if(r.path==="invalid"){msg.textContent=L("zipInvalid");return}lead.path=r.path;lead.region=r.region;if(r.path==="nyc"){lead.borough=r.borough;FLOW=NYC_STEPS}else{FLOW=CAPTURE_STEPS.map(s=>s.id==="cap_plan"?makeCapPlanStep(r.region):s)}setCoBrand(r.region);current=firstVisibleFrom(1);render();scrollToFlow(current)}
function commit(id){current=firstVisibleFrom(current+1);render();
var plan=answers.cap_plan;
var isCA=!!(window.TANGELO_IS_CA_PLAN&&window.TANGELO_IS_CA_PLAN(plan));
if(String(plan||"").indexOf("Blue Shield of CA Promise")===0){
if(id==="cap_doctor")pushAfterDoctorBSC();
else if(id==="early_contact")pushEarlyContactBSC();
else if(id==="cin_dob")pushPartialBSC();
else if(id==="heard")pushPreContactBSC();
}else if(isCA){
if(id==="cap_doctor")pushAfterDoctorCA();
else if(id==="early_contact")pushEarlyContactCA();
else if(id==="cin_dob")pushPartialCA();
else if(id==="heard")pushPreContactCA();
}
if(current1&&phone.replace(/\D/g,"").length>=10;const b=document.querySelector("#step-contact .scr-btn-primary");if(b)b.disabled=!ok;return ok}
/* Delegates to the shared helper in PAGE-HEAD so the BSC Promise prefix match (the value may
carry a " - LA County" suffix) lives in exactly one place. */
function isCAMediCal(){return !!(window.TANGELO_IS_CA_PLAN&&window.TANGELO_IS_CA_PLAN(answers.cap_plan))}
function submitCAFlow(){if(!lead.name||!lead.phone||(lead.phone||"").replace(/\D/g,"").length<10)return;lead.answers=JSON.parse(JSON.stringify(answers));lead.lang=lang;lead.submittedAtNY=nyTimestamp();current=FLOW.length;render();const d=decideEligibility();lead.decision=d.code;lead.tier=d.tier||null;lead.reason=d.reason||null;pushLead(lead);try{window.dataLayer=window.dataLayer||[];window.dataLayer.push({event:"tangelo_lead_submit",refId:lead.refId||"",market:"ca"})}catch(e){}if(d.code==="ELIGIBLE")showEligible();else if(d.code==="ELIGIBLE_BSC"||d.code==="ELIGIBLE_CCHP")showHealthieBooking(d);else if(d.code==="IEHP_REFERRAL")showIEHPReferral(d);else showLead(d)}
function val0(id){const e=document.getElementById(id);return e?e.value.trim():""}
function submitContact(){if(!validateContact())return;lead.name=val0("c-name");lead.phone=fmtPhoneStore(val0("c-phone"));lead.email=val0("c-email");lead.consent=true;lead.consentAtNY=nyTimestamp();lead.consentMethod="click-through";lead.consentVersion=(window.TANGELO_CONSENT_VERSION||"");lead.answers=JSON.parse(JSON.stringify(answers));var _cLang=document.getElementById("c-lang");if(_cLang&&_cLang.value)lang=_cLang.value;lead.lang=lang;lead.submittedAtNY=nyTimestamp();current=FLOW.length;render();const d=decideEligibility();lead.decision=d.code;lead.tier=d.tier||null;lead.reason=d.reason||null;pushLead(lead);try{window.dataLayer=window.dataLayer||[];window.dataLayer.push({event:"tangelo_lead_submit",refId:lead.refId||"",market:(lead.path==="ca"?"ca":(lead.path==="nyc"||lead.path==="ny"?"ny":"other"))});}catch(e){}if(d.code==="ELIGIBLE")showEligible();else showLead(d)}
function decideEligibility(){return (window.TANGELO_DECIDE||function(){return{code:"NY_LEAD",h:{en:"",es:""},p:{en:"",es:""}}})(lead,answers)}
function showEligible(){document.getElementById("resLead").classList.remove("show");const el=document.getElementById("resEligible");el.classList.add("show");document.getElementById("recapEligible").innerHTML=buildRecap();(window.TANGELO_CAL_INIT||function(){})({lead:lead,lang:lang,L:L,calcomBase:CALCOM_BASE,endpoint:LEAD_ENDPOINT});mountKioskRestart(el);scrollToEl(el)}
function showLead(d){document.getElementById("resEligible").classList.remove("show");const el=document.getElementById("resLead");el.classList.add("show");if(d.h)document.getElementById("leadH").textContent=d.h[lang];if(d.p)document.getElementById("leadP").textContent=d.p[lang];document.getElementById("recapLead").innerHTML=buildRecap();var ctaWrap=document.getElementById("leadCta");var callBtn=document.getElementById("leadCallBtn");if(ctaWrap){ctaWrap.innerHTML="";if(d.cta){var a=document.createElement("a");a.className="scr-btn scr-btn-primary";a.href=d.cta.url;a.target="_blank";a.rel="noopener";a.textContent=d.cta.label[lang]||d.cta.label.en;a.style.cssText="background:#fff;color:var(--ink);font-weight:800;padding:14px 28px;font-size:16px;text-decoration:none;display:inline-block;margin-top:6px";ctaWrap.appendChild(a)}}if(callBtn)callBtn.style.display=d.cta?"none":"";
if(String(answers.cap_plan||"").indexOf("Blue Shield of CA Promise")===0){const lp=document.getElementById("leadP");if(lp)lp.textContent=L("bscLeadP");const h1=document.querySelector('[data-i18n="n1h"]');const p1=document.querySelector('[data-i18n="n1p"]');if(h1)h1.textContent=L("n1hBSC");if(p1)p1.textContent=L("n1pBSC");}
mountKioskRestart(el);scrollToEl(el)}
/* IEHP result screen. Renders the standard lead card, then appends the provider-referral
instructions and a print button. IEHP is never bookable by the member — the referral has to
be submitted by their doctor through the IEHP Provider Portal with clinical documentation. */
function showIEHPReferral(d){
showLead(d);
var C=window.TANGELO_IEHP||{};
var el=document.getElementById("resLead");if(!el)return;
var prior=document.getElementById("iehpBlock");if(prior)prior.parentNode.removeChild(prior);
var wrap=document.createElement("div");wrap.id="iehpBlock";
wrap.style.cssText="margin-top:20px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.18);border-radius:16px;padding:18px 20px;text-align:left";
var stepsHTML=(C.portalSteps||[]).map(function(s){return '
'+s+'
'}).join("");
var critHTML=(C.criteria||[]).map(function(s){return '
'+s+'
'}).join("");
wrap.innerHTML=
'
'+L2("iehpWhatToDoH","What to do next")+'
'
+'
'+L2("iehpWhatToDoP","Ask your doctor, PCP or care manager to submit an IEHP referral for Medically Tailored Meals to Tangelo. Print the page below (or email it to yourself) and bring it to them — it has every field they need.")+'
'+L2("iehpQuestions","Questions? Your doctor's office can reach us at")+' '+(C.phone||"")+' '+L2("iehpOr","or")+' '+(C.email||"")+'.
';
el.appendChild(wrap);
var btn=document.getElementById("iehpPrintBtn");
if(btn)btn.addEventListener("click",function(){printIEHPHandout()});
}
/* Opens a clean, print-optimized page with the referral request. Personalized with the
member's name + refId so an incoming portal referral can be tied back to this lead.
Uses a new window rather than server-side PDF generation: works on mobile (the print
sheet offers "Save to Files" / email), and needs no backend. */
function printIEHPHandout(){
var C=window.TANGELO_IEHP||{};
var nm=(lead.name||"").trim();
var ref=(lead.refId||"");
var steps=(C.portalSteps||[]).map(function(s){return "
"+s+"
"}).join("");
var crit=(C.criteria||[]).map(function(s){return "
Patient: '+esc(nm||"(name not provided)")+(ref?' · Tangelo ref: '+esc(ref):'')+'
':'')
+'
To the provider
'
+'
This patient may qualify for Medically Tailored Meals at no cost through IEHP\'s Community Supports benefit. Tangelo is a contracted Community Supports provider. To refer, please submit through the IEHP Provider Portal:
Community Supports / Medically Tailored Meals Referral Form: '+(C.formUrl||"")+'
'
+'
Questions? '+(C.phone||"")+' · '+(C.email||"")+' Servicing provider name in the portal: '+(C.servicingProvider||"Tangelo")+' · CPT '+(C.cpt||"")+'
'
+''
+'';
var w=window.open("","_blank");
if(!w){alert(L2("iehpPopupBlocked","Please allow pop-ups to print the referral request, or use the PDF link instead."));return}
w.document.open();w.document.write(html);w.document.close();
setTimeout(function(){try{w.focus();w.print()}catch(e){}},400);
}
/* Tiny helpers: L2 falls back to an English default when the i18n key isn't defined yet, so
adding copy here doesn't require touching the hosted i18n file first. esc() guards the
patient's own name against breaking the printed markup. */
function L2(key,fallback){try{var v=L(key);return (v&&v!==key)?v:fallback}catch(e){return fallback}}
function esc(s){return String(s==null?"":s).replace(/[&<>"']/g,function(c){return {"&":"&","<":"<",">":">",'"':""","'":"'"}[c]})}
function showHealthieBooking(d){document.getElementById("resEligible").classList.remove("show");document.getElementById("resLead").classList.remove("show");const el=document.getElementById("resHealthie");el.classList.add("show");document.getElementById("recapHealthie").innerHTML=buildRecap();(window.TANGELO_HEALTHIE||function(){})({plan:d.plan,lang:lang,lead:lead,endpoint:LEAD_ENDPOINT,wrap:document.getElementById("healthieWrap"),L:L});mountKioskRestart(el);scrollToEl(el)}
const KIOSK_AUTO_SECONDS=150;
function mountKioskRestart(resultEl){if(!lead.kioskRef)return;const old=resultEl.querySelector(".kiosk-restart");if(old)old.remove();const url=kioskHomeUrl();const fmt=(s)=>{const m=Math.floor(s/60);const r=s%60;return m+":"+(r<10?"0":"")+r};const panel=document.createElement("div");panel.className="kiosk-restart";panel.innerHTML='
'}
function pushLead(payload){if(!LEAD_ENDPOINT)return;try{
// Prefix match — cap_plan carries a " - " suffix for BSC Promise. An === here would
// silently send bsc:false and the lead would miss the BSC Leads tab in Apps Script.
const bsc=(payload.answers&&String(payload.answers.cap_plan||"").indexOf("Blue Shield of CA Promise")===0)||false;
fetch(LEAD_ENDPOINT,{method:"POST",headers:{"Content-Type":"text/plain;charset=utf-8"},body:JSON.stringify({type:"lead",bsc:bsc,...payload})})
}catch(e){}}
function answerSummary(step){if(step.type==="cin_dob"){return[answers.cin,answers.dob].filter(Boolean).join(" · ")}if(step.type==="early_contact"){return[answers.early_name,fmtPhoneDisp(answers.early_phone),answers.early_email].filter(Boolean).join(" · ")}const v=answers[step.id];if(v==null||v==="")return"";if(step.type==="multi"&&Array.isArray(v))return v.map(x=>{const o=step.options.find(p=>p.v===x);return o?o.ttl[lang]:x}).join(", ");if(step.type==="select")return v==="__other"?(answers[step.id+"Other"]||(lang==="es"?"Otro":"Other")):v;if(step.type==="text2")return[v.a,v.b].filter(Boolean).join(" · ");if(step.type==="zip")return v;if(step.options){const o=step.options.find(p=>p.v===v);return o?o.ttl[lang]:v}return""+v}
function updateProgress(){const vis=FLOW.filter(isVisible);const total=vis.length;const done=vis.filter((s)=>FLOW.indexOf(s)scrollToEl(document.getElementById("step-"+s.id)),60)}
function scrollToEl(el){if(el)el.scrollIntoView({behavior:"smooth",block:"center"})}
function applyI18n(){document.querySelectorAll("[data-i18n]").forEach(n=>{n.innerHTML=L(n.getAttribute("data-i18n"))})}
function renderKioskLangToggle(){if(!lead.kioskRef)return;if(document.getElementById("kioskLangBar"))return;const bar=document.createElement("div");bar.id="kioskLangBar";bar.className="kiosk-lang-bar";const langs=[{c:"ko",label:"한국어"},{c:"en",label:"English"},{c:"es",label:"Español"}];bar.innerHTML=langs.map(L=>'').join("");document.body.insertBefore(bar,document.body.firstChild);function adjustForBar(){const h=bar.offsetHeight||56;document.body.style.paddingTop=h+"px";document.querySelectorAll(".w-nav, .navbar, header, .nav, [class*='Navbar']").forEach(el=>{try{const cs=window.getComputedStyle(el);if(cs.position==="fixed"){const curTop=parseInt(cs.top,10)||0;if(curTop{b.onclick=function(){const nl=b.dataset.lang;if(nl===lang)return;try{localStorage.setItem("tgl_lang",nl)}catch(e){}lang=nl;bar.querySelectorAll("button").forEach(x=>x.classList.toggle("active",x.dataset.lang===nl));applyI18n();render()}})}
renderKioskLangToggle();
applyI18n();render();fetchGeo();
(function(){try{const u=new URL(window.location.href);const z=(u.searchParams.get("zip")||"").trim();if(/^\d{5}$/.test(z)){setTimeout(()=>{const i=document.getElementById("in-zip");if(i){i.value=z;submitZip()}},80)}}catch(e){}})();