{"id":103,"date":"2026-07-08T22:38:39","date_gmt":"2026-07-09T02:38:39","guid":{"rendered":"http:\/\/offplan.network\/?page_id=103"},"modified":"2026-07-08T22:45:20","modified_gmt":"2026-07-09T02:45:20","slug":"enroll","status":"publish","type":"page","link":"http:\/\/offplancare.com\/es\/enroll\/","title":{"rendered":"Enroll"},"content":{"rendered":"<div class=\"container\">\n<p class=\"wp-block-paragraph\">\t\t<div class=\"careos-enroll\" x-data=\"careosFunnel\" x-cloak>\n\n\t\t\t<!-- Chip expressions are dataset-driven (stepChipClass) \u2014 NO single\n\t\t\t     quotes or comparison operators inside these attributes: wptexturize's\n\t\t\t     tag scanner ends the tag at a bare `>`, texturizes the spilled\n\t\t\t     remainder (curly-quote entities), and the browser's attribute parser\n\t\t\t     then eats the following chip (screenshot-verified live). -->\n\t\t\t<!-- AB#650 ZIP-first: eligibility leads the flow; plan\/about follow. AB#978\n\t\t\t     (UX review): the bar used to track only 4 of 9 screens and vanished\n\t\t\t     outright on identity\/consent\/checkout \u2014 every purchase-flow\n\t\t\t     screen now maps to a chip via STEP_PHASE (funnel.js), so the indicator\n\t\t\t     never disappears mid-funnel. Chips are phases, not screens: \"About you\"\n\t\t\t     covers about\/identity\/review_hold, \"Coverage\" covers\n\t\t\t     coverage_triage\/membership_ack, \"Payment\" covers consent\/checkout.\n\t\t\t     data-step-num is the chip's phase number (stepChipClass compares it to\n\t\t\t     stepPhase()). The Coverage and Payment chips are code-owned literals\n\t\t\t     (insurance-adjacent \/ billing-adjacent labels).\n\t\t\t     Step-2 redesign (mobile-first): the five labelled chips are now progress\n\t\t\t     DOTS; the visible \"Step 2 of 5 \u00b7 Membership\" line is stepProgress(), fed\n\t\t\t     the same five labels as DATA (the JSON array below, in chip order \u2014 keep\n\t\t\t     it in step with the <li>s). The <ol> is aria-hidden; the progress line is\n\t\t\t     the accessible text. -->\n\t\t\t<div class=\"ce-stepper\" x-show=\"showStepper()\">\n\t\t\t\t<ol class=\"ce-steps\" aria-hidden=\"true\">\n\t\t\t\t\t<li data-step-num=\"0\" :class=\"stepChipClass($el)\">Eligibility<\/li>\n\t\t\t\t\t<li data-step-num=\"1\" :class=\"stepChipClass($el)\">Membership<\/li>\n\t\t\t\t\t<li data-step-num=\"2\" :class=\"stepChipClass($el)\">About you<\/li>\n\t\t\t\t\t<li data-step-num=\"3\" :class=\"stepChipClass($el)\">Coverage<\/li>\n\t\t\t\t\t<li data-step-num=\"4\" :class=\"stepChipClass($el)\">Payment<\/li>\n\t\t\t\t<\/ol>\n\t\t\t\t<p class=\"ce-steps-label\" x-text=\"stepProgress([&quot;Eligibility&quot;,&quot;Membership&quot;,&quot;About you&quot;,&quot;Coverage&quot;,&quot;Payment&quot;], &quot;Step {n} of {total} \\u00b7 {label}&quot;)\"><\/p>\n\t\t\t<\/div>\n\n\t\t\t<!-- 2. Plan (AB#650: after the ZIP gate; ?plan= deep links pre-select here) -->\n\t\t\t<!-- Step-2 mobile-first redesign (Option B \"count badge\" + bottom-sheet map,\n\t\t\t     Pepper 2026-09-03; spec docs\/briefings\/2026-09-03-enrollment-step2-mobile-redesign-spec.md):\n\t\t\t     ONE single-column layout at every width \u2014 the AB#976 two-column grid,\n\t\t\t     its wide-container 34\u219264rem width jump and the per-location <ul> are gone.\n\t\t\t     Top to bottom: headline (the availability proof IS the heading \u2014\n\t\t\t     the proofHeading fallback chain: offices \u2192 physicians \u2192 place\/generic),\n\t\t\t     distance sub-line, up to three nearest-office chips + \"+N more\" +\n\t\t\t     \"See on a map\", the plan cards, the terms line, then the CTA bar.\n\t\t\t     DOM order stays heading \u2192 proof \u2192 options \u2192 sheet: the AB#976 a11y\n\t\t\t     ordering (review 10158\/10151) \u2014 a screen reader \/ no-CSS read hits the\n\t\t\t     proof before the cards and never meets the map list before either.\n\t\t\t     AB#1024's interactive Azure Maps canvas moved INSIDE the bottom sheet\n\t\t\t     (opened deliberately by the map link, so normal pan\/zoom no longer eats\n\t\t\t     the page's vertical swipes). fetchLocations() runs non-blockingly after\n\t\t\t     an in-market market_check; hasLocations() gates the chips, the map link\n\t\t\t     and the sheet \u2014 no locations, and the step renders the degraded path\n\t\t\t     (headline fallback + cards) exactly as before. Map failure at any stage\n\t\t\t     (token 404 dark-ship, SDK error) funnels through markMapFailed() and the\n\t\t\t     sheet still opens with the LIST only. No physician\/practice names or\n\t\t\t     street addresses anywhere here \u2014 postal locality, a distance and an\n\t\t\t     accepting\/not-accepting line. -->\n\t\t\t<div x-show=\"step === 'plan'\">\n\t\t\t\t<h2 class=\"ce-proof-heading\" x-text=\"proofHeading(&quot;An office near {zip} is accepting new members&quot;, &quot;{count} offices near {zip} are accepting new members&quot;, &quot;A physician near {zip} is accepting new members&quot;, &quot;{count} physicians near {zip} are accepting new members&quot;, &quot;Great news \\u2014 we&#039;re in {place}!&quot;, &quot;Great news \\u2014 we serve your area!&quot;)\">Great news \u2014 we serve your area!<\/h2>\n\t\t\t\t<p class=\"ce-proof-sub\" x-show=\"hasNearestDistance()\" x-text=\"proofSubline(&quot;The nearest is about {distance} away.&quot;, &quot;All within {radius} miles \\u2014 the nearest about {distance} away.&quot;)\"><\/p>\n\t\t\t\t<!-- proof strip: display-only chips. Null distances are skipped (never\n\t\t\t\t     \"About null miles\"); all-null collapses to a single count chip. -->\n\t\t\t\t<ul class=\"ce-chips\" x-show=\"hasLocations()\">\n\t\t\t\t\t<template x-for=\"(chip, i) in proofChips(&quot;About {distance}&quot;)\" :key=\"i\">\n\t\t\t\t\t\t<li class=\"ce-chip\">\t\t<span class=\"ce-chip-pin\" aria-hidden=\"true\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" focusable=\"false\"><path d=\"M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z\"><\/path><circle cx=\"12\" cy=\"10\" r=\"3\"><\/circle><\/svg><\/span>\n\t\t<span x-text=\"chip\"><\/span><\/li>\n\t\t\t\t\t<\/template>\n\t\t\t\t\t<li class=\"ce-chip\" x-show=\"chipsCountOnly()\" x-text=\"countOnlyChip(&quot;{count} offices&quot;)\"><\/li>\n\t\t\t\t\t<li class=\"ce-chip ce-chip-more\" x-show=\"hasMoreChips()\" x-text=\"moreChip(&quot;+{count} more&quot;)\"><\/li>\n\t\t\t\t\t<li><button type=\"button\" class=\"ce-map-link\" x-ref=\"maplink\" @click=\"openSheet()\">See on a map<\/button><\/li>\n\t\t\t\t<\/ul>\n\t\t\t\t<div class=\"ce-plans\">\n\t\t\t\t\t<template x-for=\"p in plans\" :key=\"p.plan_code\">\n\t\t\t\t\t\t<button type=\"button\" class=\"ce-plan\" :class=\"{ selected: plan_code === p.plan_code }\" @click=\"selectPlan(p)\">\n\t\t\t\t\t\t\t<span class=\"ce-plan-row\">\n\t\t\t\t\t\t\t\t<span class=\"ce-plan-name\" x-text=\"p.display_name\"><\/span>\n\t\t\t\t\t\t\t\t<span class=\"ce-plan-price\" x-text=\"p.price_teaser\"><\/span>\n\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t<!-- the unit line (Plan_Catalog::price_detail): who the rate is per \u2014\n\t\t\t\t\t\t\t     the family card spells out the per-adult and per-child rates so the\n\t\t\t\t\t\t\t     \"From\" price above it is never read as a flat family rate. -->\n\t\t\t\t\t\t\t<span class=\"ce-plan-desc\" x-text=\"p.price_detail\"><\/span>\n\t\t\t\t\t\t<\/button>\n\t\t\t\t\t<\/template>\n\t\t\t\t<\/div>\n\t\t\t\t<p class=\"ce-plan-terms\">Month-to-month, cancel anytime. You'll see your exact monthly total before you pay.<\/p>\n\t\t\t\t<!-- CTA bar (.ce-nav, funnel.css \u2014 sticky at the bottom on phones, in-flow at\n\t\t\t\t     \u226548rem, the same bar on every step). Disabled Continue says WHY it is\n\t\t\t\t     disabled instead of just fading. -->\n\t\t\t\t<div class=\"ce-nav\">\n\t\t\t\t\t<button type=\"button\" class=\"ce-back\" @click=\"step = 'eligibility'\">Back<\/button>\n\t\t\t\t\t<button type=\"button\" :disabled=\"!plan_code\" @click=\"step = 'about'\" x-text=\"continueLabel(&quot;Continue&quot;, &quot;Choose a membership first&quot;, &quot;Next: add your household&quot;)\">Continue<\/button>\n\t\t\t\t<\/div>\n\n\t\t\t\t<!-- Bottom-sheet map. x-show (not x-if) on purpose: the live Azure Maps\n\t\t\t\t     instance is attached to x-ref=\"locmap\" and must survive close\/reopen.\n\t\t\t\t     Focus moves to the close button on open and back to the map link on\n\t\t\t\t     close (openSheet()\/closeSheet()); Esc and a backdrop tap also close. -->\n\t\t\t\t<div class=\"ce-sheet-backdrop\" x-show=\"sheet_open\" @click=\"closeSheet()\"><\/div>\n\t\t\t\t<div class=\"ce-sheet\" x-show=\"sheet_open\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Map of nearby office locations\" @keydown.escape.window=\"closeSheet()\">\n\t\t\t\t\t<div class=\"ce-sheet-handle\" aria-hidden=\"true\"><\/div>\n\t\t\t\t\t<div class=\"ce-sheet-head\">\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<p class=\"ce-sheet-title\" x-text=\"sheetTitle(&quot;{count} offices near {zip}&quot;)\"><\/p>\n\t\t\t\t\t\t\t<p class=\"ce-sheet-sub\" x-text=\"sheetStatusLine(&quot;All accepting new members&quot;, &quot;{accepting} of {count} accepting new members&quot;)\"><\/p>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<button type=\"button\" class=\"ce-sheet-close\" x-ref=\"sheetclose\" @click=\"closeSheet()\" aria-label=\"Close map\">\n\t\t\t\t\t\t\t\t\t<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M6 6l12 12M18 6L6 18\"><\/path><\/svg>\n\t\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t<\/div>\n\t\t\t\t\t<div class=\"ce-sheet-map\" x-show=\"map_ok\" x-ref=\"locmap\" role=\"region\" tabindex=\"0\"\n\t\t\t\t\t     aria-label=\"Map of nearby office locations\"><\/div>\n\t\t\t\t\t<ul class=\"ce-sheet-list\">\n\t\t\t\t\t\t<template x-for=\"(loc, i) in locations\" :key=\"i\">\n\t\t\t\t\t\t\t<li class=\"ce-sheet-item\">\n\t\t\t\t\t\t\t\t\t\t<span class=\"ce-chip-pin\" aria-hidden=\"true\"><svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" focusable=\"false\"><path d=\"M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z\"><\/path><circle cx=\"12\" cy=\"10\" r=\"3\"><\/circle><\/svg><\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"ce-sheet-text\">\n\t\t\t\t\t\t\t\t\t<span class=\"ce-sheet-place\" x-text=\"locationPlace(loc)\"><\/span>\n\t\t\t\t\t\t\t\t\t<span class=\"ce-sheet-line\" x-text=\"locationsLine(loc, &quot;Accepting new members&quot;, &quot;Not accepting new members&quot;)\"><\/span>\n\t\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t<\/ul>\n\t\t\t\t\t<div class=\"ce-sheet-foot\">\n\t\t\t\t\t\t<button type=\"button\" class=\"ce-sheet-back\" @click=\"closeSheet()\">Back to memberships<\/button>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\n\t\t\t<!-- 2. About you -->\n\t\t\t<!-- This step CREATES the session: its submit runs createSession() and hosts\n\t\t\t     the Turnstile widget. It cannot sit any earlier \u2014 the payload carries\n\t\t\t     segment_tag and enrollment_intent, both collected on this form. The\n\t\t\t     server-side bot gate reads the token by container id (createSession()). -->\n\t\t\t<form x-show=\"step === 'about'\" @submit.prevent=\"createSession()\">\n\t\t\t\t<h2>Tell us about you<\/h2>\n\t\t\t\t<label>Which best describes you?\t\t\t\t\t<select x-model=\"segment_tag\" required>\n\t\t\t\t\t\t<option value=\"\">Select\u2026<\/option>\n\t\t\t\t\t\t<option value=\"self_employed\">Self-employed professional<\/option>\n\t\t\t\t\t\t<option value=\"small_biz\">Small business owner<\/option>\n\t\t\t\t\t\t<option value=\"gig_1099\">1099 or gig worker<\/option>\n\t\t\t\t\t\t<option value=\"young_healthy\">Just turned 26<\/option>\n\t\t\t\t\t\t<option value=\"employed_no_plan_offered\">Employed, no health coverage offered<\/option>\n\t\t\t\t\t\t<option value=\"employed_declined_plan\">Employed, declined my employer&#039;s coverage<\/option>\n\t\t\t\t\t\t<option value=\"employed_with_plan\">Employed, keeping my employer&#039;s coverage<\/option>\n\t\t\t\t\t\t<option value=\"retired_pre_medicare\">Retired early, not yet on Medicare<\/option>\n\t\t\t\t\t<\/select>\n\t\t\t\t<\/label>\n\t\t\t\t<label>When are you looking to start?\t\t\t\t\t<select x-model=\"enrollment_intent\" required>\n\t\t\t\t\t\t<option value=\"\">Select\u2026<\/option>\n\t\t\t\t\t\t<option value=\"asap\">As soon as possible<\/option>\n\t\t\t\t\t\t<option value=\"three_months\">In the next 3 months<\/option>\n\t\t\t\t\t\t<option value=\"six_months\">In the next 6 months<\/option>\n\t\t\t\t\t\t<option value=\"just_curious\">Just curious<\/option>\n\t\t\t\t\t<\/select>\n\t\t\t\t<\/label>\n\t\t\t\t<div class=\"ce-row\" x-show=\"showHouseholdCounts()\">\n\t\t\t\t\t<label>Adults <input type=\"number\" min=\"1\" max=\"2\" x-model.number=\"household_adults\" @change=\"syncHousehold()\"><\/label>\n\t\t\t\t\t<label>Children <input type=\"number\" min=\"0\" max=\"10\" x-model.number=\"household_children\" @change=\"syncHousehold()\"><\/label>\n\t\t\t\t<\/div>\n\t\t\t\t<!-- AB#978: the required major-medical select that used to sit here was dead\n\t\t\t\t     weight \u2014 its answer was never posted to any endpoint (absent from every\n\t\t\t\t     funnel.js payload) yet blocked Continue. The coverage_triage step asks the\n\t\t\t\t     real, recorded coverage question. -->\n\t\t\t\t<div id=\"ce-turnstile-about\" class=\"cf-turnstile\" data-sitekey=\"0x4AAAAAAD8NkY3-_P1n-VKR\" data-theme=\"light\"><\/div>\n\t\t\t\t<div class=\"ce-nav\">\n\t\t\t\t\t<button type=\"button\" class=\"ce-back\" @click=\"step = 'plan'\">Back<\/button>\n\t\t\t\t\t<button type=\"submit\" :disabled=\"loading\" x-text=\"loading ? &quot;Creating\\u2026&quot; : &quot;Continue to enrollment&quot;\">Continue to enrollment<\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t<\/form>\n\n\t\t\t<!-- 1. Eligibility (AB#650: the funnel's entry step \u2014 coverage is checked\n\t\t\t     before anything else is asked; no Back from here) -->\n\t\t\t<form x-show=\"step === 'eligibility'\" @submit.prevent=\"checkEligibility\">\n\t\t\t\t<h2>Where would you like to see a doctor?<\/h2>\n\t\t\t\t<p class=\"ce-sub\">We&#039;ll confirm there&#039;s an OffPlan physician near you.<\/p>\n\t\t\t\t<label>ZIP code\t\t\t\t\t<input name=\"zip\" x-model=\"zip\" inputmode=\"numeric\" autocomplete=\"postal-code\" maxlength=\"5\" required>\n\t\t\t\t<\/label>\n\t\t\t\t<input type=\"text\" x-model=\"website\" class=\"ce-hp\" tabindex=\"-1\" autocomplete=\"off\" aria-hidden=\"true\">\n\t\t\t\t<div class=\"ce-nav\">\n\t\t\t\t\t<span><\/span>\n\t\t\t\t\t<button type=\"submit\" :disabled=\"loading\" x-text=\"loading ? &quot;Checking\\u2026&quot; : &quot;Check eligibility&quot;\"><\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t<\/form>\n\n\t\t\t<!-- 6. Identity -->\n\t\t\t<form x-show=\"step === 'identity'\" @submit.prevent=\"submitIdentity\">\n\t\t\t\t<h2>Tell us who&#039;s enrolling<\/h2>\n\t\t\t\t<div class=\"ce-row\">\n\t\t\t\t\t<label>First name <input x-model=\"first_name\" autocomplete=\"given-name\" :class=\"primFieldClass('first_name')\" required><\/label>\n\t\t\t\t\t<label>Last name <input x-model=\"last_name\" autocomplete=\"family-name\" :class=\"primFieldClass('last_name')\" required><\/label>\n\t\t\t\t<\/div>\n\t\t\t\t<label>Email <input type=\"email\" x-model=\"email\" autocomplete=\"email\" :class=\"primFieldClass('email')\" required><\/label>\n\t\t\t\t<!-- Phone: the admin console's member-lookup control, in Alpine \u2014 a flag + calling\n\t\t\t\t     code selector and a national-format-as-you-type input. phone_input is display\n\t\t\t\t     only; syncPhone() derives `phone` (E.164 when the number is valid for the\n\t\t\t\t     selected country, else the text as typed so the API's 422 lands on this field). -->\n\t\t\t\t<label for=\"ce-phone-input\">Phone<\/label>\n\t\t\t\t<div class=\"ce-phone\">\n\t\t\t\t\t<span class=\"ce-phone-country\">\n\t\t\t\t\t\t<span aria-hidden=\"true\" x-text=\"phoneCountryLabel()\"><\/span>\n\t\t\t\t\t\t<select aria-label=\"Phone country\" :value=\"phone_country\" @change=\"changePhoneCountry($event)\">\n\t\t\t\t\t\t\t<template x-for=\"c in phoneCountries()\" :key=\"c.code\">\n\t\t\t\t\t\t\t\t<option :value=\"c.code\" :selected=\"c.code === phone_country\" x-text=\"c.name + ' (' + c.callingCode + ')'\"><\/option>\n\t\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t<\/select>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t<input id=\"ce-phone-input\" type=\"tel\" inputmode=\"tel\" x-model=\"phone_input\" @input=\"syncPhone($event)\" autocomplete=\"tel\" :class=\"primFieldClass('phone')\" required>\n\t\t\t\t<\/div>\n\t\t\t\t<!-- AB#844: the SUBSCRIBER's own DOB, captured pre-payment. Dependent DOBs\n\t\t\t\t     already ride on each dependent row below. -->\n\t\t\t\t<label>Date of birth <input type=\"text\" inputmode=\"numeric\" autocomplete=\"bday\" maxlength=\"10\" placeholder=\"MM\/DD\/YYYY\" x-model=\"dob_input\" @input=\"syncDob($event)\" :class=\"primFieldClass('date_of_birth')\" required><\/label>\n\t\t\t\t<template x-if=\"showSpouseIdentity()\">\n\t\t\t\t\t<fieldset class=\"ce-household\">\n\t\t\t\t\t\t<legend>Your spouse or partner<\/legend>\n\t\t\t\t\t\t<template x-for=\"row in spouseRows()\" :key=\"row.key\">\n\t\t\t\t\t\t\t<div class=\"ce-dep\">\n\t\t\t\t\t\t\t\t<div class=\"ce-row\">\n\t\t\t\t\t\t\t\t\t<label>Dependent first name <input x-model=\"row.dep.first_name\" autocomplete=\"off\" :class=\"depFieldClass(row.index, firstNameField())\"><\/label>\n\t\t\t\t\t\t\t\t\t<label>Dependent last name <input x-model=\"row.dep.last_name\" autocomplete=\"off\" :class=\"depFieldClass(row.index, lastNameField())\"><\/label>\n\t\t\t\t\t\t\t\t\t<label>Date of birth <input type=\"text\" inputmode=\"numeric\" autocomplete=\"off\" maxlength=\"10\" placeholder=\"MM\/DD\/YYYY\" x-model=\"row.dep.dob_input\" @input=\"syncDepDob(row.dep, $event)\" :class=\"depFieldClass(row.index, dobField())\"><\/label>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<label>Spouse email (optional) <input type=\"email\" x-model=\"row.dep.email\" autocomplete=\"off\" :class=\"depFieldClass(row.index, emailField())\"><\/label>\n\t\t\t\t\t\t\t\t<p class=\"ce-hint\">For their own account access \u2014 they can activate later.<\/p>\n\t\t\t\t\t\t\t\t<p class=\"ce-err-field\" x-show=\"depHasError(row.index)\" x-text=\"depError(row.index)\"><\/p>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t<\/fieldset>\n\t\t\t\t<\/template>\n\t\t\t\t<template x-if=\"showChildrenIdentity()\">\n\t\t\t\t\t<fieldset class=\"ce-household\">\n\t\t\t\t\t\t<legend>Children on this membership<\/legend>\n\t\t\t\t\t\t<template x-for=\"row in childRows()\" :key=\"row.key\">\n\t\t\t\t\t\t\t<div class=\"ce-dep\">\n\t\t\t\t\t\t\t\t<div class=\"ce-row\">\n\t\t\t\t\t\t\t\t\t<label>Dependent first name <input x-model=\"row.dep.first_name\" autocomplete=\"off\" :class=\"depFieldClass(row.index, firstNameField())\"><\/label>\n\t\t\t\t\t\t\t\t\t<label>Dependent last name <input x-model=\"row.dep.last_name\" autocomplete=\"off\" :class=\"depFieldClass(row.index, lastNameField())\"><\/label>\n\t\t\t\t\t\t\t\t\t<label>Date of birth <input type=\"text\" inputmode=\"numeric\" autocomplete=\"off\" maxlength=\"10\" placeholder=\"MM\/DD\/YYYY\" x-model=\"row.dep.dob_input\" @input=\"syncDepDob(row.dep, $event)\" :class=\"depFieldClass(row.index, dobField())\"><\/label>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<p class=\"ce-err-field\" x-show=\"depHasError(row.index)\" x-text=\"depError(row.index)\"><\/p>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t<\/fieldset>\n\t\t\t\t<\/template>\n\t\t\t\t<p class=\"ce-price\" aria-live=\"polite\" x-show=\"showHouseholdTotal()\">\n\t\t\t\t\tYour household total: <span x-text=\"householdTotalText()\"><\/span>\n\t\t\t\t<\/p>\n\t\t\t\t<div class=\"ce-nav\">\n\t\t\t\t\t<button type=\"button\" class=\"ce-back\" @click=\"step = 'about'\">Back<\/button>\n\t\t\t\t\t<button type=\"submit\" :disabled=\"loading\" x-text=\"loading ? &quot;Saving\\u2026&quot; : &quot;Continue&quot;\"><\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t<\/form>\n\n\t\t\t<!-- 6b. Review hold (AB#733, re-enrollment spec \u00a79.1) -->\n\t\t\t<div x-show=\"step === 'review_hold'\">\n\t\t\t\t<template x-if=\"reviewIsWindow()\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2>You can cancel anytime. Rejoining within 3 months requires a quick review.<\/h2>\n\t\t\t\t\t\t<p x-text=\"reviewWindowBody(&quot;Your membership can restart on {rejoin_on}. Want to rejoin sooner? Request a quick review and our team will take a look.&quot;)\">Your membership can restart on {rejoin_on}. Want to rejoin sooner? Request a quick review and our team will take a look.<\/p>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/template>\n\t\t\t\t<template x-if=\"!reviewIsWindow()\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2>One quick step before checkout<\/h2>\n\t\t\t\t\t\t<p>Our team needs to take a quick look at your enrollment. Request a review and we&#039;ll follow up by email \u2014 usually the same business day.<\/p>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/template>\n\t\t\t\t<p class=\"ce-note\" role=\"status\" x-show=\"review_requested\">Thanks \u2014 our team is on it. We&#039;ll email you, usually within one business day.<\/p>\n\t\t\t\t<div class=\"ce-nav\">\n\t\t\t\t\t<button type=\"button\" class=\"ce-back\" @click=\"step = 'identity'\">Back<\/button>\n\t\t\t\t\t<button type=\"button\" x-show=\"!review_requested\" :disabled=\"loading\" @click=\"requestReview()\" x-text=\"loading ? &quot;Saving\\u2026&quot; : &quot;Request a review&quot;\"><\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t<\/div>\n\n\t\t\t<!-- AB#967: the pre-payment \"Physician select\" and \"Physician selected\" screens\n\t\t\t     (steps 7-8) were removed outright \u2014 physician selection now happens\n\t\t\t     post-payment, on the return step (see the \"post-payment physician\n\t\t\t     selection\" block below), with the physician's real name\/photo\/bio\n\t\t\t     visible instead of the anonymized AB#963 cards this replaced. -->\n\n\t\t\t<!-- 9. Coverage triage (AB#472 4-way routing; spec \u00a77 firewall) -->\n\t\t\t<form x-show=\"step === 'coverage_triage'\" @submit.prevent=\"continueTriage\">\n\t\t\t\t<h2>A quick coverage check-in<\/h2>\n\t\t\t\t<p class=\"ce-sub\">OffPlan membership covers everyday primary care. This helps us route you to a licensed partner for anything major \u2014 it never signs you up for insurance.<\/p>\n\t\t\t\t<div class=\"ce-choices\">\n\t\t\t\t\t<button type=\"button\" :class=\"{ selected: coverage_triage_status === 'has_coverage' }\" @click=\"coverage_triage_status = 'has_coverage'\">I already have coverage<\/button>\n\t\t\t\t\t<button type=\"button\" :class=\"{ selected: coverage_triage_status === 'recent_qle' }\" @click=\"coverage_triage_status = 'recent_qle'\">I recently had a life event (job loss, move, marriage\u2026)<\/button>\n\t\t\t\t\t<button type=\"button\" :class=\"{ selected: coverage_triage_status === 'no_coverage' }\" @click=\"coverage_triage_status = 'no_coverage'\">I don't have coverage<\/button>\n\t\t\t\t\t<button type=\"button\" :class=\"{ selected: coverage_triage_status === 'unsure' }\" @click=\"coverage_triage_status = 'unsure'\">I'm not sure<\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<template x-if=\"coverage_triage_status === 'recent_qle'\">\n\t\t\t\t\t<label>When did that happen? <input type=\"date\" x-model=\"qle_event_date\" required><\/label>\n\t\t\t\t<\/template>\n\t\t\t\t<!-- AB#846 (spec \u00a72.1, controller ruling D3): four-option coverage routing\n\t\t\t\t     choice, superseding the has_coverage cushion checkbox above with an explicit\n\t\t\t\t     pick every prospect makes. Radio labels are tier-2 (CopyComplianceTest),\n\t\t\t\t     verbatim from spec \u00a72.1 \u2014 the stored value is the API's closed set, not the\n\t\t\t\t     visible text. membership_only alone breaks from submitTriage(): Continue\n\t\t\t\t     (continueTriage()) routes it to the membership_ack screen (Task 9) instead of\n\t\t\t\t     posting triage immediately \u2014 the acknowledgment collected there is what\n\t\t\t\t     actually completes the record. The other three post straight through. -->\n\t\t\t\t<div class=\"ce-routing-choice\" role=\"radiogroup\">\n\t\t\t\t\t<label class=\"ce-check\"><input type=\"radio\" name=\"coverage_routing_choice\" x-model=\"coverage_routing_choice\" value=\"yes_contact_me\"> Yes, connect me with a licensed agent<\/label>\n\t\t\t\t\t<label class=\"ce-check\"><input type=\"radio\" name=\"coverage_routing_choice\" x-model=\"coverage_routing_choice\" value=\"tell_me_more\"> Tell me more first<\/label>\n\t\t\t\t\t<label class=\"ce-check\"><input type=\"radio\" name=\"coverage_routing_choice\" x-model=\"coverage_routing_choice\" value=\"check_back_before_oe\"> Not right now, but check back before open enrollment<\/label>\n\t\t\t\t\t<label class=\"ce-check\"><input type=\"radio\" name=\"coverage_routing_choice\" x-model=\"coverage_routing_choice\" value=\"membership_only\"> Just the membership, thanks<\/label>\n\t\t\t\t<\/div>\n\t\t\t\t<!-- AB#844 routing answers. AB#978 (benefits review): gated on the ROUTING\n\t\t\t\t     CHOICE \u2014 the FPL derivation only matters when a TownHealth conversation is\n\t\t\t\t     actually wanted (yes_contact_me \/ tell_me_more), so the other choices\n\t\t\t\t     proceed without income questions. x-if (not x-show) removes the inputs\n\t\t\t\t     from the DOM entirely, so their static `required` can't invisibly block\n\t\t\t\t     the form when hidden. Server contract verified: API validator and the\n\t\t\t\t     record_triage PHP layer both treat all three as validated-if-present,\n\t\t\t\t     never required, so the ungated submit path stays 422-free. -->\n\t\t\t\t<template x-if=\"showIncomeQuestions()\">\n\t\t\t\t<div class=\"ce-routing\">\n\t\t\t\t\t<label>\n\t\t\t\t\t\tProjected household income for 2026\t\t\t\t\t\t<select x-model=\"household_income_band\" required>\n\t\t\t\t\t\t\t<option value=\"\">Select a range<\/option>\n\t\t\t\t\t\t\t<option value=\"under_60k\">Under $60,000<\/option>\n\t\t\t\t\t\t\t<option value=\"60k_to_100k\">$60,000 to $100,000<\/option>\n\t\t\t\t\t\t\t<option value=\"100k_to_150k\">$100,000 to $150,000<\/option>\n\t\t\t\t\t\t\t<option value=\"over_150k\">Over $150,000<\/option>\n\t\t\t\t\t\t\t<option value=\"prefer_not_to_say\">I&#039;d rather not say<\/option>\n\t\t\t\t\t\t<\/select>\n\t\t\t\t\t<\/label>\n\t\t\t\t\t<p class=\"ce-hint\">An estimate is fine \u2014 we only need the range.<\/p>\n\n\t\t\t\t\t<label>\n\t\t\t\t\t\tHow many people are in your household?\t\t\t\t\t\t<input type=\"number\" x-model.number=\"household_size\" min=\"1\" max=\"8\" required>\n\t\t\t\t\t<\/label>\n\t\t\t\t\t<p class=\"ce-hint\">Everyone you claim on your tax return, including yourself \u2014 not just the people enrolling here.<\/p>\n\n\t\t\t\t\t<label>\n\t\t\t\t\t\tHow steady is that income?\t\t\t\t\t\t<select x-model=\"income_variability\" required>\n\t\t\t\t\t\t\t<option value=\"\">Select one<\/option>\n\t\t\t\t\t\t\t<option value=\"steady\">About the same every month<\/option>\n\t\t\t\t\t\t\t<option value=\"somewhat_variable\">It varies somewhat<\/option>\n\t\t\t\t\t\t\t<option value=\"highly_variable\">It varies a lot<\/option>\n\t\t\t\t\t\t<\/select>\n\t\t\t\t\t<\/label>\n\t\t\t\t<\/div>\n\t\t\t\t<\/template>\n\t\t\t\t<template x-if=\"triageRequiresDisclosure()\">\n\t\t\t\t\t<label class=\"ce-check\">\n\t\t\t\t\t\t<input type=\"checkbox\" x-model=\"disclosure_ack\" required>\n\t\t\t\t\t\t<span x-text=\"( careosEnroll.disclosures && careosEnroll.disclosures.townhealth_handoff && careosEnroll.disclosures.townhealth_handoff.body ) || &quot;I understand OffPlan will share my routing answer with TownHealth Partners LLC, a licensed insurance agency, so they can contact me \\u2014 OffPlan is not an insurance agency and does not sell or bind coverage.&quot;\">I understand OffPlan will share my routing answer with TownHealth Partners LLC, a licensed insurance agency, so they can contact me \u2014 OffPlan is not an insurance agency and does not sell or bind coverage.<\/span>\n\t\t\t\t\t<\/label>\n\t\t\t\t<\/template>\n\t\t\t\t<div class=\"ce-nav\">\n\t\t\t\t\t<!-- AB#967: identity now leads straight into coverage_triage (the deleted\n\t\t\t\t\t     physician_selected step no longer sits between them). -->\n\t\t\t\t\t<button type=\"button\" class=\"ce-back\" @click=\"step = 'identity'\">Back<\/button>\n\t\t\t\t\t<!-- The gate lives in triageBlocked() (funnel.js) so the label can say why\n\t\t\t\t\t     Continue is off \u2014 a tier-2 literal, like the rest of this step. -->\n\t\t\t\t\t<button type=\"submit\" :disabled=\"loading || triageBlocked()\" x-text=\"loading ? 'Saving\u2026' : ( triageBlocked() ? 'Answer above to continue' : 'Continue' )\"><\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t<\/form>\n\n\t\t\t<!-- 9b. Membership-only acknowledgment (AB#846 spec \u00a72.2). Shown only after the\n\t\t\t     coverage_triage screen's Continue routes here on the membership_only choice\n\t\t\t     (continueTriage(), Task 8) \u2014 a record that the member read and understood the\n\t\t\t     coverage gap, not a scare tactic (spec \u00a72.2 tone note). The body renders via\n\t\t\t     the same served-body\/fallback\/no-JS pattern as the two AB#587 disclosures\n\t\t\t     above (TownhealthHandoff shape): JS prefers the API-served body from\n\t\t\t     careosEnroll.disclosures, falls back to the versioned constant, and the no-JS\n\t\t\t     text node inside the span is that same constant, server-rendered. The heading\n\t\t\t     is the body's own first sentence, not a separate registry key. Continue calls\n\t\t\t     submitTriage() directly \u2014 this screen, not continueTriage(), is what actually\n\t\t\t     completes the triage record for membership_only, carrying the acknowledgment\n\t\t\t     alongside the fields already chosen on the coverage_triage screen. -->\n\t\t\t<form x-show=\"step === 'membership_ack'\" @submit.prevent=\"submitTriage\">\n\t\t\t\t<div class=\"ce-disclosure-body\">\n\t\t\t\t\t<span x-text=\"( careosEnroll.disclosures && careosEnroll.disclosures.membership_only_acknowledgment && careosEnroll.disclosures.membership_only_acknowledgment.body ) || &quot;Our OffPlan membership is not health insurance, and it only covers everyday care with a direct primary care physician. OffPlan does not cover hospital stays, surgery, emergency care, or serious illness. If something major happens, you would be responsible for the full cost.\\n\\nYou can add coverage later. Open enrollment runs November 1 through January 15, and certain life events open a window sooner.&quot;\">Our OffPlan membership is not health insurance, and it only covers everyday care with a direct primary care physician. OffPlan does not cover hospital stays, surgery, emergency care, or serious illness. If something major happens, you would be responsible for the full cost.\n\nYou can add coverage later. Open enrollment runs November 1 through January 15, and certain life events open a window sooner.<\/span>\n\t\t\t\t<\/div>\n\t\t\t\t<label class=\"ce-check\">\n\t\t\t\t\t<input type=\"checkbox\" x-model=\"membership_ack_confirmed\" required>\n\t\t\t\t\tI understand and want to continue with the membership only.\n\t\t\t\t<\/label>\n\t\t\t\t<div class=\"ce-nav\">\n\t\t\t\t\t<button type=\"button\" class=\"ce-back\" @click=\"backFromMembershipAckToTriage()\">Back<\/button>\n\t\t\t\t\t<button type=\"submit\" :disabled=\"loading || !membership_ack_confirmed\" x-text=\"loading ? 'Saving\u2026' : ( membership_ack_confirmed ? 'Continue' : 'Check the box to continue' )\"><\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t<\/form>\n\n\t\t\t<!-- 10. Recurring disclosure + express, non-pre-checked consent (spec \u00a713) -->\n\t\t\t<form x-show=\"step === 'consent'\" @submit.prevent=\"submitConsent\">\n\t\t\t\t<h2>Review &amp; confirm your membership<\/h2>\n\t\t\t\t<template x-if=\"handoff\">\n\t\t\t\t\t<!-- AB#843 (spec \u00a71.4): the handoff confirmation must state the\n\t\t\t\t\t     one-business-day contact promise, that no plan has been\n\t\t\t\t\t     recommended or bound, and that OffPlan Care is not insurance.\n\t\t\t\t\t     Code-owned (tier-2, CopyComplianceTest) like every\n\t\t\t\t\t     insurance-adjacent claim \u2014 deliberately NOT registry keys.\n\t\t\t\t\t     Server-side SLA already exists: EnrollmentHandoff.ContactSlaDueAt. -->\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<p class=\"ce-sub\">A licensed TownHealth Partners agent will contact you within one business day about your coverage options \u2014 this doesn't affect your OffPlan membership below.<\/p>\n\t\t\t\t\t\t<p class=\"ce-sub\">No plan has been recommended or bound. OffPlan Care is not insurance.<\/p>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/template>\n\t\t\t\t<!-- AB#561: consent is only meaningful against a real disclosed amount \u2014 with no\n\t\t\t\t     price (e.g. a resume where rehydration failed) hide the $0.00 disclosure and\n\t\t\t\t     block submission instead of letting the API 409\/422 the mismatch. -->\n\t\t\t\t<!-- AB#590: the first month is pro-rated at checkout. consentDisclosure() renders the\n\t\t\t\t     pro-rated sentence (\"billed $Y today for Jul 16\u2013Jul 31 (pro-rated), then $X each\n\t\t\t\t     month...\") or the full-month sentence when enrolling on the 1st. -->\n\t\t\t\t<template x-if=\"hasPrice()\">\n\t\t\t\t\t<p class=\"ce-sub\" x-text=\"consentDisclosure()\"><\/p>\n\t\t\t\t<\/template>\n\t\t\t\t<template x-if=\"!hasPrice()\">\n\t\t\t\t\t<p class=\"ce-sub\">We couldn\u2019t confirm your monthly price. Please reopen the link from your email, or start a new enrollment.<\/p>\n\t\t\t\t<\/template>\n\t\t\t\t<!-- The party taking the charge. The funnel is branded OffPlan, but the charge is\n\t\t\t\t     taken by the contracting Friendly PC as merchant of record, so the hosted\n\t\t\t\t     checkout and the invoice lead with that legal name. Naming it here first is\n\t\t\t\t     what keeps that checkout from reading as the wrong one. Code-owned (tier-2):\n\t\t\t\t     who collects the payment is a compliance statement, not marketing copy. The\n\t\t\t\t     name is server-supplied with the first charge; the line renders only once it\n\t\t\t\t     has arrived. This names the merchant of record only \u2014 never the member's\n\t\t\t\t     physician or practice. -->\n\t\t\t\t<template x-if=\"billedBy()\">\n\t\t\t\t\t<p class=\"ce-sub ce-billed-by\">Billed by: <strong x-text=\"billedBy()\"><\/strong><br>You'll see this name at checkout and on your invoice.<\/p>\n\t\t\t\t<\/template>\n\t\t\t\t<label class=\"ce-check\">\n\t\t\t\t\t<input type=\"checkbox\" x-model=\"terms_accepted\" required>\n\t\t\t\t\t<span x-text=\"( careosEnroll.disclosures && careosEnroll.disclosures.recurring_consent && careosEnroll.disclosures.recurring_consent.body ) || &quot;I authorize OffPlan to charge my payment method the amount above, on this recurring monthly schedule, until I cancel.&quot;\">I authorize OffPlan to charge my payment method the amount above, on this recurring monthly schedule, until I cancel.<\/span>\n\t\t\t\t<\/label>\n\t\t\t\t<!-- AB#1070 (R1\/R2\/R3): the ToS\/Privacy clickwrap. Registry-driven \u2014\n\t\t\t\t     the API decides which documents (if any) this market requires, so an\n\t\t\t\t     EMPTY list renders nothing at all and the step behaves exactly as it did\n\t\t\t\t     in v0.24.0. There is deliberately no code-owned fallback body: consent\n\t\t\t\t     can only be recorded against a document the server actually served, with\n\t\t\t\t     the version and content hash it served. -->\n\t\t\t\t<!-- A failed fetch BLOCKS the step (the submit gate below reads\n\t\t\t\t     documents_error) rather than letting the buyer past documents they were\n\t\t\t\t     never shown. Explanation and recovery sit together, right where the\n\t\t\t\t     documents would have been \u2014 not in the form-level alert two controls\n\t\t\t\t     below, which is also where an unrelated submit error lands. -->\n\t\t\t\t<div class=\"ce-doc-retry\" x-show=\"documents_error\">\n\t\t\t\t\t<p class=\"ce-err\" role=\"alert\">Something went wrong.<\/p>\n\t\t\t\t\t<button type=\"button\" @click=\"fetchDocuments()\">Try again<\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<template x-for=\"doc in documents\" :key=\"doc.key\">\n\t\t\t\t\t<div class=\"ce-doc\">\n\t\t\t\t\t\t<!-- The registry's 2-3 line plain-language summary, versioned WITH the\n\t\t\t\t\t\t     document. Omitted (not faked) when the API sends none. -->\n\t\t\t\t\t\t<template x-if=\"doc.summary\">\n\t\t\t\t\t\t\t<p class=\"ce-sub\" x-text=\"doc.summary\"><\/p>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t<a href=\"#\" class=\"ce-doc-link\" @click.prevent=\"openDocument(doc.key)\" x-text=\"docLinkLabel(doc, &quot;Read the full {name}&quot;)\"><\/a>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/template>\n\t\t\t\t<!-- ONE control for both documents: the counterparty is the same, so a\n\t\t\t\t     second checkbox would only add friction, not consent. Never pre-checked,\n\t\t\t\t     never persisted, cleared on every (re)fetch. The <a> links inside the\n\t\t\t\t     label open the sheet WITHOUT toggling the box: a label's activation\n\t\t\t\t     behavior explicitly does nothing for clicks targeted at interactive\n\t\t\t\t     content descendants (HTML spec), and @click.prevent stops the\n\t\t\t\t     navigation. The line adapts to whichever documents came back. -->\n\t\t\t\t<label class=\"ce-check\" x-show=\"hasPlatformDocuments()\">\n\t\t\t\t\t<input type=\"checkbox\" x-model=\"documents_accepted\">\n\t\t\t\t\t<span>\n\t\t\t\t\t\t<template x-if=\"hasDocument('terms_of_service')\"><span>I agree to the <a href=\"#\" class=\"ce-doc-inline\" @click.prevent=\"openDocument('terms_of_service')\">Terms of Service<\/a><\/span><\/template>\n\t\t\t\t\t\t<template x-if=\"hasBothDocuments()\"><span> and acknowledge the <a href=\"#\" class=\"ce-doc-inline\" @click.prevent=\"openDocument('privacy_policy')\">Privacy Policy<\/a><\/span><\/template>\n\t\t\t\t\t\t<template x-if=\"hasPrivacyOnly()\"><span>I acknowledge the <a href=\"#\" class=\"ce-doc-inline\" @click.prevent=\"openDocument('privacy_policy')\">Privacy Policy<\/a><\/span><\/template>\n\t\t\t\t\t<\/span>\n\t\t\t\t<\/label>\n\t\t\t\t<label class=\"ce-check\" x-show=\"hasDocument('membership_agreement')\">\n\t\t\t\t\t<input type=\"checkbox\" x-model=\"membership_agreement_accepted\">\n\t\t\t\t\t<span x-text=\"agreementLabel(&quot;I agree to the Membership Agreement with {entity}&quot;)\"><\/span>\n\t\t\t\t<\/label>\n\t\t\t\t<div class=\"ce-nav\">\n\t\t\t\t\t<button type=\"button\" class=\"ce-back\" @click=\"step = 'coverage_triage'\">Back<\/button>\n\t\t\t\t\t<!-- The label names whichever gate is holding the button: the recurring\n\t\t\t\t\t     checkbox, either in-flight fetch (both start together on entry, so\n\t\t\t\t\t     one \"Loading your price\u2026\" covers the window \u2014 and a market with NO\n\t\t\t\t\t     documents must never flash the documents gate while its empty list\n\t\t\t\t\t     is still arriving), the AB#1070 documents control once it is\n\t\t\t\t\t     actionable (unchecked, or failed to load), or a price that never\n\t\t\t\t\t     rehydrated (the PRICE_UNKNOWN_COPY block above explains that one in\n\t\t\t\t\t     full). -->\n\t\t\t\t\t<button type=\"submit\" :disabled=\"loading || !terms_accepted || documents_loading || documents_error || !documentsSatisfied() || !hasPrice() || first_charge_loading || !first_charge_cents\" x-text=\"loading ? 'Saving\u2026' : ( !terms_accepted ? 'Check the box to continue' : ( documents_loading || first_charge_loading ? 'Loading your price\u2026' : ( documents_error || !documentsSatisfied() ? &quot;Confirm the documents to continue&quot; : ( hasPrice() &amp;&amp; first_charge_cents ? 'Agree &amp; continue to payment' : 'Price unavailable' ) ) ) )\"><\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t<\/form>\n\n\t\t\t<!-- AB#1070 (R3): the full text of one document, in place. Same dialog\n\t\t\t     as the plan step's map sheet \u2014 x-show (not x-if) so the focus wiring\n\t\t\t     survives close\/reopen, Esc and a backdrop tap close it, focus\n\t\t\t     moves to the close button on open and back to the link that opened it. There\n\t\t\t     is deliberately no external link and no new tab anywhere in this step: the\n\t\t\t     member reads the exact text whose version + content_hash the consent record\n\t\t\t     will carry, and never leaves the funnel mid-enrollment to do it. -->\n\t\t\t<div class=\"ce-sheet-backdrop\" x-show=\"doc_open\" @click=\"closeDocument()\"><\/div>\n\t\t\t<div class=\"ce-sheet ce-doc-sheet\" x-show=\"doc_open\" role=\"dialog\" aria-modal=\"true\" :aria-label=\"docName(doc_open)\" @keydown.escape.window=\"closeDocument()\">\n\t\t\t\t<div class=\"ce-sheet-handle\" aria-hidden=\"true\"><\/div>\n\t\t\t\t<div class=\"ce-sheet-head\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<p class=\"ce-sheet-title\" x-text=\"docName(doc_open)\"><\/p>\n\t\t\t\t\t\t<!-- The version the member is actually reading \u2014 the same string\n\t\t\t\t\t\t     submitConsent() posts back in document_acceptances. -->\n\t\t\t\t\t\t<p class=\"ce-doc-version\">Version <span x-text=\"docVersion()\"><\/span><\/p>\n\t\t\t\t\t<\/div>\n\t\t\t\t\t<button type=\"button\" class=\"ce-sheet-close\" x-ref=\"docclose\" @click=\"closeDocument()\" aria-label=\"Close\">\n\t\t\t\t\t\t\t\t<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.4\" stroke-linecap=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M6 6l12 12M18 6L6 18\"><\/path><\/svg>\n\t\t\t\t\t\t\t<\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<!-- Plain text from the API, rendered as TEXT through x-text (never as\n\t\t\t\t     markup \u2014 see the whole-template guard in FunnelShortcodeTest), with its\n\t\t\t\t     own line breaks preserved by .ce-doc-body's white-space: pre-wrap.\n\t\t\t\t     tabindex makes the scroll box reachable from the keyboard. -->\n\t\t\t\t<div class=\"ce-doc-body\" tabindex=\"0\"><template x-for=\"(segment, index) in docSegments()\" :key=\"index\"><span :class=\"{ 'ce-statutory-disclosure': segment.disclosure }\" x-text=\"segment.text\"><\/span><\/template><\/div>\n\t\t\t\t<div class=\"ce-sheet-foot\">\n\t\t\t\t\t<button type=\"button\" class=\"ce-sheet-back\" @click=\"closeDocument()\">Back to enrollment<\/button>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\n\t\t\t<!-- 11. Checkout redirect (Finix hosted checkout) -->\n\t\t\t<div x-show=\"step === 'checkout'\">\n\t\t\t\t<h2>Secure payment<\/h2>\n\t\t\t\t<p class=\"ce-sub\">You'll finish payment on our payment partner's secure page, then come right back.<\/p>\n\t\t\t\t<div class=\"ce-nav\">\n\t\t\t\t\t<span><\/span>\n\t\t\t\t\t<button type=\"button\" :disabled=\"loading\" @click=\"redirectToCheckout()\" x-text=\"loading ? 'Preparing\u2026' : 'Continue to secure payment'\"><\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t<\/div>\n\n\t\t\t<!-- 12. Return (P-D5 API-truth poll + C-D2 idempotent claim_url reveal) -->\n\t\t\t<div x-show=\"step === 'return'\">\n\t\t\t\t<!-- AB#967: post-payment physician selection. pollSession() has confirmed\n\t\t\t\t     payment succeeded but the API has no physician on the session yet (no\n\t\t\t\t     `physician` block) \u2014 prompt the buyer to pick one now, with real\n\t\t\t\t     identity (session_id-gated search_physicians), before the celebratory\n\t\t\t\t     claim\/success content below. Placed BEFORE that content so it renders\n\t\t\t\t     first when both are momentarily eligible; needsPhysicianSelection()\n\t\t\t\t     keeps them mutually exclusive. claim_url is still captured on every\n\t\t\t\t     poll regardless (pollSession, unchanged) \u2014 the no-capacity edge below\n\t\t\t\t     shows it directly so a paid member is never stranded without their\n\t\t\t\t     portal link. -->\n\t\t\t\t<template x-if=\"needsPhysicianSelection()\">\n\t\t\t\t\t<div class=\"ce-post-payment-select\">\n\t\t\t\t\t\t<template x-if=\"showPrimaryPostPaymentPicker()\">\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<h2>Choose your physician<\/h2>\n\t\t\t\t\t\t\t\t<p class=\"ce-sub\">They&#039;ll be your main point of contact for everyday care.<\/p>\n\t\t\t\t\t\t\t\t<div class=\"ce-plans\">\n\t\t\t\t\t\t\t\t\t<template x-for=\"p in physicians\" :key=\"p.id\">\n\t\t\t\t\t\t\t\t\t\t<!-- Real identity: payment has succeeded, so name\/headshot\/bio\n\t\t\t\t\t\t\t\t\t\t     ride the wire now (search_physicians with session_id) \u2014\n\t\t\t\t\t\t\t\t\t\t     unlike the deleted anonymized pre-payment cards this\n\t\t\t\t\t\t\t\t\t\t     replaces. -->\n\t\t\t\t\t\t\t\t\t\t<!-- AB#1160: the card is selectable only when the panel is open AND\n\t\t\t\t\t\t\t\t\t\t     the whole household (subscriber + children) falls inside this\n\t\t\t\t\t\t\t\t\t\t     physician's accepted age range. canSelectPrimary() carries both\n\t\t\t\t\t\t\t\t\t\t     halves so the attribute stays operator-free; the server's\n\t\t\t\t\t\t\t\t\t\t     physician_age_ineligible 422 is the defense in depth behind it,\n\t\t\t\t\t\t\t\t\t\t     same posture as physician_closed. -->\n\t\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"ce-plan\" :disabled=\"!canSelectPrimary(p)\" @click=\"selectPostPaymentPhysician(p)\">\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"ce-plan-head\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<template x-if=\"headshotSrc(p)\">\n\t\t\t<img class=\"ce-avatar ce-avatar-sm\" :src=\"headshotSrc(p)\" @error=\"markHeadshotFailed(p)\" alt=\"\" loading=\"lazy\" width=\"40\" height=\"40\">\n\t\t<\/template>\n\t\t<template x-if=\"!headshotSrc(p)\">\n\t\t\t<span class=\"ce-avatar ce-avatar-sm ce-avatar-initial\" x-text=\"avatarInitial(p)\" aria-hidden=\"true\"><\/span>\n\t\t<\/template>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"ce-plan-name\" x-text=\"p.name\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"ce-plan-creds\" x-show=\"credentialsLine(p)\" x-text=\"credentialsLine(p)\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"ce-plan-langs\" x-show=\"languagesLine(p)\" x-text=\"languagesLine(p)\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t<span x-text=\"locationLine(p)\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t<!-- The published window, then (only when it actually excludes\n\t\t\t\t\t\t\t\t\t\t\t     somebody) why that means this card is off. Both lines are\n\t\t\t\t\t\t\t\t\t\t\t     empty\/hidden for a physician who accepts every age. -->\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"ce-plan-ages\" x-show=\"acceptedAgesLine(p)\" x-text=\"acceptedAgesLine(p)\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"ce-plan-ineligible\" x-show=\"primaryAgeIneligible(p)\" x-text=\"ageIneligibleLine(p)\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t<span x-text=\"p.capacity_open ? 'Accepting patients' : 'At capacity'\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t<span x-show=\"p.meet_and_greet\">Meet-and-greet available<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"ce-select-cta\">Select<\/span>\n\t\t\t\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t\t\t\t\t\t<!-- Review fix (AB#967): a transient search failure must not\n\t\t\t\t\t\t\t\t     trap a paid user with an empty roster and no way back\n\t\t\t\t\t\t\t\t     short of a reload \u2014 retryPhysicianSearch() clears the\n\t\t\t\t\t\t\t\t     one-shot guard and re-runs the search. -->\n\t\t\t\t\t\t\t\t<template x-if=\"physicianSearchFailed()\">\n\t\t\t\t\t\t\t\t\t<button type=\"button\" @click=\"retryPhysicianSearch()\">Try again<\/button>\n\t\t\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t<!-- Optional second phase (household_adults === 2 only): posts\n\t\t\t\t\t\t     spouse_physician_id via the SAME select_physician endpoint,\n\t\t\t\t\t\t     re-supplying the already-confirmed primary physician_id\n\t\t\t\t\t\t     (Select_Physician_Request requires it every call) \u2014 not the\n\t\t\t\t\t\t     submitHousehold\/dependents PUT the deleted pre-payment spouse\n\t\t\t\t\t\t     picker used. -->\n\t\t\t\t\t\t<template x-if=\"spouse_pick_open\">\n\t\t\t\t\t\t\t<div class=\"ce-spouse-pick\">\n\t\t\t\t\t\t\t\t<h3>Pick a physician for your spouse too?<\/h3>\n\t\t\t\t\t\t\t\t<div class=\"ce-plans\">\n\t\t\t\t\t\t\t\t\t<template x-for=\"p in physicians\" :key=\"p.id\">\n\t\t\t\t\t\t\t\t\t\t<!-- AB#1160: the spouse's own age gate \u2014 spouse_age_eligible is a\n\t\t\t\t\t\t\t\t\t\t     per-card verdict for the spouse alone (null when the session\n\t\t\t\t\t\t\t\t\t\t     has no spouse, which canSelectSpouse() treats as selectable).\n\t\t\t\t\t\t\t\t\t\t     The API's spouse_physician_age_ineligible 422 backs it up. -->\n\t\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"ce-plan\" :disabled=\"!canSelectSpouse(p)\" @click=\"selectPostPaymentSpousePhysician(p)\">\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"ce-plan-name\" x-text=\"p.name\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"ce-plan-ages\" x-show=\"acceptedAgesLine(p)\" x-text=\"acceptedAgesLine(p)\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"ce-plan-ineligible\" x-show=\"spouseAgeIneligible(p)\" x-text=\"spouseAgeIneligibleLine(p)\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t<span x-text=\"physicianAvailability(p)\"><\/span>\n\t\t\t\t\t\t\t\t\t\t<\/button>\n\t\t\t\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<button type=\"button\" class=\"ce-back\" :disabled=\"loading\" @click=\"skipPostPaymentSpouseSelection()\">Skip for now<\/button>\n\t\t\t\t\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t<!-- Roster-empty\/all-closed OR post-payment-window-expired edge: a paid\n\t\t\t\t\t\t     member must still see their claim\/success content \u2014 selection\n\t\t\t\t\t\t     finishes later via ops follow-up (kept simple and honest: we'll\n\t\t\t\t\t\t     be in touch to match them, and the portal link is shown right\n\t\t\t\t\t\t     here). The none_open line is scoped to the capacity case only \u2014\n\t\t\t\t\t\t     it would misstate an expired-window edge, where physicians may\n\t\t\t\t\t\t     well be open. NO waitlist bridge here (review finding, controller\n\t\t\t\t\t\t     ruling supersedes the original brief): POST\n\t\t\t\t\t\t     waitlist\/from-session\/{id} throws StateConflictException for\n\t\t\t\t\t\t     Completed\/Claimed sessions \u2014 every paid user would 409 on that\n\t\t\t\t\t\t     dead CTA. bridgeToWaitlist() is left defined in funnel.js (a\n\t\t\t\t\t\t     generic session->waitlist off-ramp a future PRE-payment surface\n\t\t\t\t\t\t     may still want) \u2014 it is simply never called from this\n\t\t\t\t\t\t     post-payment block. Review fix: a 410 session_expired from\n\t\t\t\t\t\t     select\/search (the post-payment selection window closed,\n\t\t\t\t\t\t     ExpiresAtUtc +30d from create) lands here too via\n\t\t\t\t\t\t     post_payment_window_expired \u2014 NEVER the unpaid-abandonment\n\t\t\t\t\t\t     expireSession() \"start fresh\" screen, which would wipe the\n\t\t\t\t\t\t     claim_url a paid member already has. -->\n\t\t\t\t\t\t<template x-if=\"showPostPaymentFollowUp()\">\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<!-- AB#1160: the age-gate twin of the none_open line below \u2014 every\n\t\t\t\t\t\t\t\t     nearby physician's accepted range excludes somebody in the\n\t\t\t\t\t\t\t\t     household. Scoped to its own result exactly like the capacity\n\t\t\t\t\t\t\t\t     line: \"no open physicians\" would misstate a roster that is\n\t\t\t\t\t\t\t\t     open but age-mismatched. -->\n\t\t\t\t\t\t\t\t<template x-if=\"hasNoAgeEligiblePostPayment()\">\n\t\t\t\t\t\t\t\t\t<p>None of the physicians near you currently accept every age in your household. We&#039;ll be in touch to match your family with a physician.<\/p>\n\t\t\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t\t\t<template x-if=\"hasNoCapacityPostPayment()\">\n\t\t\t\t\t\t\t\t\t<p>No open physicians near that ZIP right now.<\/p>\n\t\t\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t\t\t<p>We&#039;ll be in touch to match you with a physician \u2014 you can still access your account below.<\/p>\n\t\t\t\t\t\t\t\t<p><a :href=\"claim_url\" class=\"ce-plan\">Set up my member portal<\/a><\/p>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/template>\n\t\t\t\t<template x-if=\"!needsPhysicianSelection()\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<template x-if=\"claim_url\">\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<h2>You&#039;re in! \ud83c\udf89<\/h2>\n\t\t\t\t\t\t\t\t<p>Your membership starts now. Set up your member portal to meet your care team \u2014 you&#039;ll create your account when you arrive. No password needed; we&#039;ll email you a one-time code. The code comes from Microsoft on our behalf; check spam if it&#039;s slow.<\/p>\n\t\t\t\t\t\t\t\t<!-- AB#963: the physician reveal. Only renders when pollSession() has\n\t\t\t\t\t\t\t\t     captured a `physician` block from the API \u2014 the server gates that\n\t\t\t\t\t\t\t\t     field on payment success, so the UI never fabricates an identity\n\t\t\t\t\t\t\t\t     that wasn't actually confirmed. -->\n\t\t\t\t\t\t\t\t<template x-if=\"hasRevealedPhysician()\">\n\t\t\t\t\t\t\t\t\t<div class=\"ce-reveal\">\n\t\t\t\t\t\t\t\t\t\t<h3>Meet your physician<\/h3>\n\t\t\t\t\t\t\t\t\t\t\t\t<template x-if=\"headshotSrc(revealed_physician)\">\n\t\t\t<img class=\"ce-avatar ce-avatar-lg\" :src=\"headshotSrc(revealed_physician)\" @error=\"markHeadshotFailed(revealed_physician)\" alt=\"\" loading=\"lazy\" width=\"56\" height=\"56\">\n\t\t<\/template>\n\t\t<template x-if=\"!headshotSrc(revealed_physician)\">\n\t\t\t<span class=\"ce-avatar ce-avatar-lg ce-avatar-initial\" x-text=\"avatarInitial(revealed_physician)\" aria-hidden=\"true\"><\/span>\n\t\t<\/template>\n\t\t\t\t\t\t\t\t\t\t\t\t<p class=\"ce-reveal-name\" x-text=\"revealedPhysicianName()\"><\/p>\n\t\t\t\t\t\t\t\t\t\t<p class=\"ce-reveal-practice\" x-show=\"hasRevealedPractice()\" x-text=\"revealedPhysicianPractice()\"><\/p>\n\t\t\t\t\t\t\t\t\t\t<p>They&#039;ll be reaching out soon to say hello.<\/p>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t\t\t<p><a :href=\"claim_url\" class=\"ce-plan\">Set up my member portal<\/a><\/p>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t<template x-if=\"!claim_url && claim_lost\">\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<h2>Payment received<\/h2>\n\t\t\t\t\t\t\t\t<p>We couldn&#039;t display your portal link here. Check your email for it, or contact support and we&#039;ll get you set up.<\/p>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t<template x-if=\"!claim_url && !claim_lost && !poll_exhausted && !payment_declined\">\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<div class=\"ce-wait\">\n\t\t\t\t\t\t\t\t\t<div class=\"ce-spinner\" aria-hidden=\"true\"><\/div>\n\t\t\t\t\t\t\t\t\t<h2>Confirming your payment\u2026<\/h2>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<p class=\"ce-wait-note\" role=\"status\" aria-live=\"polite\">This usually takes just a few seconds.<\/p>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t<template x-if=\"!claim_url && !claim_lost && poll_exhausted\">\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<h2>Still confirming your payment\u2026<\/h2>\n\t\t\t\t\t\t\t\t<p>This is taking a little longer than usual. Your payment is safe \u2014 check again in a moment.<\/p>\n\t\t\t\t\t\t\t\t<button type=\"button\" :disabled=\"loading\" @click=\"checkAgain()\" x-text=\"loading ? 'Checking\u2026' : 'Check again'\"><\/button>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t<template x-if=\"payment_declined\">\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<h2>Payment couldn't be completed<\/h2>\n\t\t\t\t\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"payment_declined\"><\/p>\n\t\t\t\t\t\t\t\t<button type=\"button\" @click=\"retryCheckout()\">Try a different card<\/button>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/template>\n\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t<\/div>\n\n\t\t\t<!-- Session expired (410) -->\n\t\t\t<div x-show=\"step === 'expired'\">\n\t\t\t\t<h2>Your session expired<\/h2>\n\t\t\t\t<p>No worries \u2014 let&#039;s start fresh.<\/p>\n\t\t\t\t<!-- startOver() clears the stale cookie + all local state (the old\n\t\t\t\t     inline reset left the cookie behind, resurrecting the session\n\t\t\t\t     on the next reload). -->\n\t\t\t\t<button type=\"button\" @click=\"startOver()\">Start over<\/button>\n\t\t\t<\/div>\n\n\t\t\t<!-- 5b. Out-of-market waitlist (AB#650: also the enrollment-closed capture) -->\n\t\t\t<form x-show=\"step === 'email'\" @submit.prevent=\"submitWaitlist\">\n\t\t\t\t<!-- AB#655: personalized when the market check derived a city\n\t\t\t\t     (\"We're not in Marietta yet!\") \u2014 confirms we parsed their\n\t\t\t\t     location; the server-rendered generic heading is the no-JS\/\n\t\t\t\t     no-city fallback. -->\n\t\t\t\t<h2 x-text=\"waitlistHeading(&quot;We&#039;re not in {city} yet!&quot;, &quot;We&#039;re not in your area yet&quot;)\">We&#039;re not in your area yet<\/h2>\n\t\t\t\t<p class=\"ce-sub\">Join the waitlist \u2014 we&#039;ll let you know the moment we reach you.<\/p>\n\t\t\t\t<label>Email\t\t\t\t\t<input type=\"email\" x-model=\"email\" required>\n\t\t\t\t<\/label>\n\t\t\t\t<!-- AB#650: ZIP is normally carried from the eligibility step; the\n\t\t\t\t     closed-screen path never ran it, so ask here when it's missing.\n\t\t\t\t     :required mirrors visibility \u2014 a hidden required input would\n\t\t\t\t     block submit invisibly. -->\n\t\t\t\t<label x-show=\"!zip\">ZIP code\t\t\t\t\t<input x-model=\"zip\" inputmode=\"numeric\" maxlength=\"5\" :required=\"!zip\">\n\t\t\t\t<\/label>\n\t\t\t\t<!-- AB#655: shown only when the market check could NOT derive a state\n\t\t\t\t     (unmappable ZIP \/ closed-screen path with no check run) \u2014 the API\n\t\t\t\t     now derives state from the ZIP itself and this input is the last\n\t\t\t\t     resort, not the default. :required mirrors visibility. -->\n\t\t\t\t<label x-show=\"!(market && market.state)\">State\t\t\t\t\t<input type=\"text\" x-model=\"waitlist_state\" maxlength=\"2\" pattern=\"[A-Za-z]{2}\" autocomplete=\"address-level1\" x-on:input=\"waitlist_state = waitlist_state.toUpperCase()\" :required=\"!(market && market.state)\">\n\t\t\t\t<\/label>\n\t\t\t\t<!-- AB#650\/AB#651: optional demand questions \u2014 ZIP-first means the funnel\n\t\t\t\t     never asked these before the waitlist; they power re-engagement\n\t\t\t\t     segmentation and the children-by-ZIP demand map. Unanswered stays\n\t\t\t\t     unanswered (omitted from the POST, stored as null). -->\n\t\t\t\t<label>Which best describes you? (optional)\t\t\t\t\t<select x-model=\"wl_segment\">\n\t\t\t\t\t\t<option value=\"\">Select\u2026<\/option>\n\t\t\t\t\t\t<option value=\"self_employed\">Self-employed professional<\/option>\n\t\t\t\t\t\t<option value=\"small_biz\">Small business owner<\/option>\n\t\t\t\t\t\t<option value=\"gig_1099\">1099 or gig worker<\/option>\n\t\t\t\t\t\t<option value=\"young_healthy\">Just turned 26<\/option>\n\t\t\t\t\t\t<option value=\"employed_no_plan_offered\">Employed, no health coverage offered<\/option>\n\t\t\t\t\t\t<option value=\"employed_declined_plan\">Employed, declined my employer&#039;s coverage<\/option>\n\t\t\t\t\t\t<option value=\"employed_with_plan\">Employed, keeping my employer&#039;s coverage<\/option>\n\t\t\t\t\t\t<option value=\"retired_pre_medicare\">Retired early, not yet on Medicare<\/option>\n\t\t\t\t\t<\/select>\n\t\t\t\t<\/label>\n\t\t\t\t<label>Which membership interests you? (optional)\t\t\t\t\t<select x-model=\"wl_plan_interest\">\n\t\t\t\t\t\t<option value=\"\">Select\u2026<\/option>\n\t\t\t\t\t\t<template x-for=\"p in plans\" :key=\"p.plan_code\">\n\t\t\t\t\t\t\t<option :value=\"p.plan_code\" x-text=\"p.display_name\" :selected=\"wl_plan_interest === p.plan_code\"><\/option>\n\t\t\t\t\t\t<\/template>\n\t\t\t\t\t\t<!-- AB#657 (Omar): demand-only option \u2014 child-only isn't in the plan\n\t\t\t\t\t\t     catalog yet, but interest must be measurable now. PlanInterest is\n\t\t\t\t\t\t     a free string on the capture API, so no backend change. -->\n\t\t\t\t\t\t<option value=\"child_only\">Dependent Child only<\/option>\n\t\t\t\t\t<\/select>\n\t\t\t\t<\/label>\n\t\t\t\t<div class=\"ce-row\">\n\t\t\t\t\t<label>Adults in your household (optional) <input type=\"number\" min=\"0\" max=\"20\" x-model=\"wl_household_adults\"><\/label>\n\t\t\t\t\t<label>Children in your household (optional) <input type=\"number\" min=\"0\" max=\"20\" x-model=\"wl_household_children\"><\/label>\n\t\t\t\t<\/div>\n\t\t\t\t<label class=\"ce-check\">\n\t\t\t\t\t<input type=\"checkbox\" x-model=\"marketing_consent\" required>\n\t\t\t\t\tEmail me when OffPlan is available in my area.\n\t\t\t\t<\/label>\n\t\t\t\t<input type=\"text\" x-model=\"website\" class=\"ce-hp\" tabindex=\"-1\" autocomplete=\"off\" aria-hidden=\"true\">\n\t\t\t\t<div id=\"ce-turnstile-waitlist\" class=\"cf-turnstile\" data-sitekey=\"0x4AAAAAAD8NkY3-_P1n-VKR\" data-theme=\"light\"><\/div>\n\t\t\t\t<div class=\"ce-nav\">\n\t\t\t\t\t<button type=\"button\" class=\"ce-back\" @click=\"waitlistBack()\">Back<\/button>\n\t\t\t\t\t<button type=\"submit\" :disabled=\"loading\" x-text=\"loading ? &quot;Joining\\u2026&quot; : &quot;Join the waitlist&quot;\"><\/button>\n\t\t\t\t<\/div>\n\t\t\t\t<p class=\"ce-err\" role=\"alert\" x-text=\"error\"><\/p>\n\t\t\t<\/form>\n\n\t\t\t<!-- Enrollment closed (AB#650 kill switch). New signups pause; the waitlist\n\t\t\t     stays open so marketing capture continues; in-flight sessions (return\/\n\t\t\t     claim\/resume) are deliberately NOT gated. -->\n\t\t\t<div x-show=\"step === 'closed'\">\n\t\t\t\t<h2>Enrollment is temporarily paused<\/h2>\n\t\t\t\t<p class=\"ce-sub\">We&#039;re not accepting new signups right now. Leave your details and we&#039;ll let you know the moment we reopen.<\/p>\n\t\t\t\t<div class=\"ce-nav\">\n\t\t\t\t\t<span><\/span>\n\t\t\t\t\t<button type=\"button\" @click=\"step = 'email'\">Join the waitlist<\/button>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\n\t\t\t<!-- 6. Done -->\n\t\t\t<div x-show=\"step === 'done'\">\n\t\t\t\t<h2>You&#039;re on the list \ud83c\udf89<\/h2>\n\t\t\t\t<p>We&#039;ll email you when we reach your area. Thanks for telling us a bit about yourself.<\/p>\n\t\t\t<\/div>\n\n\t\t\t<!-- Restart escape hatch: shown whenever a session exists (including the\n\t\t\t     done\/review_hold states \u2014 enrolling another person is a legit\n\t\t\t     follow-up). Abandons server-side, clears the cookie, resets all local\n\t\t\t     state. Attribute expressions kept quote\/operator-free\n\t\t\t     (texturize-proofing \u2014 see the step-indicator note above). -->\n\t\t\t<p class=\"ce-restart-row\" x-show=\"session_id\">\n\t\t\t\t<button type=\"button\" class=\"ce-restart\" @click=\"startOver()\">Start over<\/button>\n\t\t\t<\/p>\n\n\t\t<\/div>\n\t\t<\/p>\n<\/div>\n\n<div class=\"container\">\n<p class=\"wp-block-paragraph\"><\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-careos-funnel.php","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-103","page","type-page","status-publish","hentry"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Enroll - OffPlan<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/offplancare.com\/es\/enroll\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Enroll - OffPlan\" \/>\n<meta property=\"og:url\" content=\"https:\/\/offplancare.com\/es\/enroll\/\" \/>\n<meta property=\"og:site_name\" content=\"OffPlan\" \/>\n<meta property=\"article:modified_time\" content=\"2026-07-09T02:45:20+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/offplancare.com\/wp-content\/uploads\/2026\/05\/offplan-sharer.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/offplancare.com\\\/enroll\\\/\",\"url\":\"https:\\\/\\\/offplancare.com\\\/enroll\\\/\",\"name\":\"Enroll - OffPlan\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/offplancare.com\\\/#website\"},\"datePublished\":\"2026-07-09T02:38:39+00:00\",\"dateModified\":\"2026-07-09T02:45:20+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/offplancare.com\\\/enroll\\\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/offplancare.com\\\/enroll\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/offplancare.com\\\/enroll\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"http:\\\/\\\/offplancare.com\\\/es\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Enroll\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/offplancare.com\\\/#website\",\"url\":\"https:\\\/\\\/offplancare.com\\\/\",\"name\":\"OffPlan\",\"description\":\"Healthcare without Insurance\",\"publisher\":{\"@id\":\"https:\\\/\\\/offplancare.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/offplancare.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/offplancare.com\\\/#organization\",\"name\":\"OffPlan\",\"url\":\"https:\\\/\\\/offplancare.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/offplancare.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"http:\\\/\\\/offplancare.com\\\/wp-content\\\/uploads\\\/2026\\\/02\\\/offplan-logo.jpg\",\"contentUrl\":\"http:\\\/\\\/offplancare.com\\\/wp-content\\\/uploads\\\/2026\\\/02\\\/offplan-logo.jpg\",\"width\":1000,\"height\":800,\"caption\":\"OffPlan\"},\"image\":{\"@id\":\"https:\\\/\\\/offplancare.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Enroll - OffPlan","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/offplancare.com\/es\/enroll\/","og_locale":"es_MX","og_type":"article","og_title":"Enroll - OffPlan","og_url":"https:\/\/offplancare.com\/es\/enroll\/","og_site_name":"OffPlan","article_modified_time":"2026-07-09T02:45:20+00:00","og_image":[{"width":1200,"height":630,"url":"http:\/\/offplancare.com\/wp-content\/uploads\/2026\/05\/offplan-sharer.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/offplancare.com\/enroll\/","url":"https:\/\/offplancare.com\/enroll\/","name":"Enroll - OffPlan","isPartOf":{"@id":"https:\/\/offplancare.com\/#website"},"datePublished":"2026-07-09T02:38:39+00:00","dateModified":"2026-07-09T02:45:20+00:00","breadcrumb":{"@id":"https:\/\/offplancare.com\/enroll\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/offplancare.com\/enroll\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/offplancare.com\/enroll\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"http:\/\/offplancare.com\/es\/"},{"@type":"ListItem","position":2,"name":"Enroll"}]},{"@type":"WebSite","@id":"https:\/\/offplancare.com\/#website","url":"https:\/\/offplancare.com\/","name":"OffPlan","description":"Healthcare without Insurance","publisher":{"@id":"https:\/\/offplancare.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/offplancare.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/offplancare.com\/#organization","name":"OffPlan","url":"https:\/\/offplancare.com\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/offplancare.com\/#\/schema\/logo\/image\/","url":"http:\/\/offplancare.com\/wp-content\/uploads\/2026\/02\/offplan-logo.jpg","contentUrl":"http:\/\/offplancare.com\/wp-content\/uploads\/2026\/02\/offplan-logo.jpg","width":1000,"height":800,"caption":"OffPlan"},"image":{"@id":"https:\/\/offplancare.com\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"http:\/\/offplancare.com\/es\/wp-json\/wp\/v2\/pages\/103","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/offplancare.com\/es\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/offplancare.com\/es\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/offplancare.com\/es\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/offplancare.com\/es\/wp-json\/wp\/v2\/comments?post=103"}],"version-history":[{"count":0,"href":"http:\/\/offplancare.com\/es\/wp-json\/wp\/v2\/pages\/103\/revisions"}],"wp:attachment":[{"href":"http:\/\/offplancare.com\/es\/wp-json\/wp\/v2\/media?parent=103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}