Separate customer type into its own question section

The retail/wholesale radios were visually mixed in with the voice/broadband
checkboxes, making it easy to misread "Wholesale" as a service type.
Moved to a distinct Q1b section "Who are your customers?" that only
appears after checking voice or broadband. Single selection covers
both services (retail / wholesale / both).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
justin 2026-04-29 09:33:42 -05:00
parent 95d4779660
commit 790e980ef8

View file

@ -87,22 +87,17 @@ select:focus,input:focus{outline:none;border-color:#1e3a5f;box-shadow:0 0 0 2px
<div id="q1">
<p class="q-label">What type of service will you offer?</p>
<p class="q-hint">Select all that apply.</p>
<label class="svc-row"><input type="checkbox" data-svc="voice"> <span class="svc-name">Voice / phone service</span> <span class="svc-inc">VoIP, CLEC, or traditional</span></label>
<div id="q1-voice-mode" class="hidden" style="margin-left:1.5rem;margin-bottom:.5rem;padding:.4rem .65rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px">
<p style="font-size:.8rem;font-weight:600;color:#6b7280;margin-bottom:.25rem">Who will you sell voice service to?</p>
<label style="display:flex;align-items:center;gap:.4rem;font-size:.84rem;margin-bottom:.15rem;cursor:pointer"><input type="radio" name="voice_mode" value="retail" checked> Retail — end users (businesses or consumers)</label>
<label style="display:flex;align-items:center;gap:.4rem;font-size:.84rem;margin-bottom:.15rem;cursor:pointer"><input type="radio" name="voice_mode" value="wholesale"> Wholesale — sell to other carriers or resellers</label>
<label style="display:flex;align-items:center;gap:.4rem;font-size:.84rem;cursor:pointer"><input type="radio" name="voice_mode" value="both"> Both retail and wholesale</label>
</div>
<label class="svc-row"><input type="checkbox" data-svc="broadband"> <span class="svc-name">Broadband internet service</span> <span class="svc-inc">ISP, fiber, fixed wireless</span></label>
<div id="q1-broadband-mode" class="hidden" style="margin-left:1.5rem;margin-bottom:.5rem;padding:.4rem .65rem;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px">
<p style="font-size:.8rem;font-weight:600;color:#6b7280;margin-bottom:.25rem">Who will you sell broadband service to?</p>
<label style="display:flex;align-items:center;gap:.4rem;font-size:.84rem;margin-bottom:.15rem;cursor:pointer"><input type="radio" name="broadband_mode" value="retail" checked> Retail — end users (businesses or consumers)</label>
<label style="display:flex;align-items:center;gap:.4rem;font-size:.84rem;margin-bottom:.15rem;cursor:pointer"><input type="radio" name="broadband_mode" value="wholesale"> Wholesale — sell to other carriers or ISPs</label>
<label style="display:flex;align-items:center;gap:.4rem;font-size:.84rem;cursor:pointer"><input type="radio" name="broadband_mode" value="both"> Both retail and wholesale</label>
</div>
</div>
<!-- Q1b: Customer type — separate section, only shown after checking voice/broadband -->
<div id="q1b" class="hidden" style="margin-top:1rem">
<p class="q-label">Who are your customers?</p>
<p class="q-hint">This affects which FCC filings are required. If your voice and broadband customers are different, select the option that covers both.</p>
<button type="button" class="q-card" data-custtype="retail">Retail — I sell directly to businesses or consumers</button>
<button type="button" class="q-card" data-custtype="wholesale">Wholesale — I sell to other carriers, resellers, or CLECs</button>
<button type="button" class="q-card" data-custtype="both">Both — I have retail end users and wholesale/carrier customers</button>
</div>
<!-- Q2: Voice delivery (shown if voice selected) -->
@ -340,7 +335,7 @@ select:focus,input:focus{outline:none;border-color:#1e3a5f;box-shadow:0 0 0 2px
// ── Wizard state ──
var wizard = {
serviceTypes: [], voiceMode: 'retail', broadbandMode: 'retail',
serviceTypes: [], customerType: 'retail',
voiceDelivery: '', infraNeeds: [],
broadbandType: '', operatingStates: '',
// Derived
@ -372,19 +367,19 @@ select:focus,input:focus{outline:none;border-color:#1e3a5f;box-shadow:0 0 0 2px
wizard.serviceTypes = Array.from(document.querySelectorAll('[data-svc]:checked')).map(function(c) { return c.dataset.svc; });
var hasVoice = wizard.serviceTypes.indexOf('voice') >= 0;
var hasBroadband = wizard.serviceTypes.indexOf('broadband') >= 0;
document.getElementById('q1-voice-mode').classList.toggle('hidden', !hasVoice);
document.getElementById('q1-broadband-mode').classList.toggle('hidden', !hasBroadband);
document.getElementById('q1b').classList.toggle('hidden', !hasVoice && !hasBroadband);
document.getElementById('q2').classList.toggle('hidden', !hasVoice);
document.getElementById('q4').classList.toggle('hidden', !hasBroadband);
if (hasVoice || hasBroadband) document.getElementById('q5').classList.remove('hidden');
});
});
// Voice/broadband mode radios
document.querySelectorAll('input[name=voice_mode]').forEach(function(r) {
r.addEventListener('change', function() { wizard.voiceMode = this.value; });
});
document.querySelectorAll('input[name=broadband_mode]').forEach(function(r) {
r.addEventListener('change', function() { wizard.broadbandMode = this.value; });
// ── Q1b: Customer type ──
document.querySelectorAll('[data-custtype]').forEach(function(btn) {
btn.addEventListener('click', function() {
document.querySelectorAll('[data-custtype]').forEach(function(b) { b.classList.remove('selected'); });
btn.classList.add('selected');
wizard.customerType = btn.dataset.custtype;
});
});
// ── Q2: Voice delivery ──
@ -433,15 +428,15 @@ select:focus,input:focus{outline:none;border-color:#1e3a5f;box-shadow:0 0 0 2px
var hasVoice = wizard.serviceTypes.indexOf('voice') >= 0;
var hasBroadband = wizard.serviceTypes.indexOf('broadband') >= 0;
var bbRetail = hasBroadband && (wizard.broadbandMode === 'retail' || wizard.broadbandMode === 'both');
var hasRetail = wizard.customerType === 'retail' || wizard.customerType === 'both';
// Voice carriers always need RMD + CPNI regardless of retail/wholesale
wizard.needsRmd = hasVoice;
wizard.needsCpni = hasVoice;
// CALEA: all voice carriers + facilities-based broadband
wizard.needsCalea = hasVoice || (hasBroadband && wizard.broadbandType === 'facilities');
// BDC only for broadband with retail end users (not wholesale-only broadband)
wizard.needsBdc = bbRetail;
// BDC only for broadband providers with retail end users
wizard.needsBdc = hasBroadband && hasRetail;
wizard.needsOcn = wizard.infraNeeds.indexOf('lcr') >= 0 || wizard.infraNeeds.indexOf('own_dids') >= 0 ||
wizard.infraNeeds.indexOf('interconnect') >= 0 || wizard.infraNeeds.indexOf('stir_sign') >= 0;
wizard.needsStirShaken = wizard.infraNeeds.indexOf('stir_sign') >= 0 || wizard.needsOcn;
@ -703,8 +698,7 @@ select:focus,input:focus{outline:none;border-color:#1e3a5f;box-shadow:0 0 0 2px
address_zip: wizard.addrZip,
service_wizard: {
service_types: wizard.serviceTypes,
voice_mode: wizard.voiceMode,
broadband_mode: wizard.broadbandMode,
customer_type: wizard.customerType,
voice_delivery: wizard.voiceDelivery,
infra_needs: wizard.infraNeeds,
broadband_type: wizard.broadbandType,