@@ -45,6 +45,120 @@ <h1 class="mt-4 text-3xl font-semibold tracking-tight sm:text-4xl">
4545 showBusinessPlanModal : false ,
4646 showEvaluationModal : false ,
4747 activeStep : 0 ,
48+ band : 'band2' ,
49+ salesCycle : {
50+ stages : {
51+ PQL : {
52+ label : "PQL" ,
53+ description : "Partner Qualified Lead registered in portal. Recast approval is required to assign Partner of Record." ,
54+ entryCriteria : [ "Partner identifies lead" , "Lead submitted in Partner Portal" ] ,
55+ exitCriteria : [ "Recast approves or declines within SLA" , "Partner of Record set in CRM" ] ,
56+ deliverables : [ "Registration form (company, domain, contacts, use case)" , "Approval notification" ] ,
57+ } ,
58+ Identification : {
59+ label : "Identification (10% Pipeline)" ,
60+ description : "Initial contact made; meeting confirmed; problem identified." ,
61+ entryCriteria : [ "Approved lead" , "Intro outreach completed" ] ,
62+ exitCriteria : [ "Discovery meeting held" , "Clear problem statement" ] ,
63+ deliverables : [ "Discovery notes" , "Next-step email / agenda" ] ,
64+ } ,
65+ Qualification : {
66+ label : "Qualification (25% Pipeline)" ,
67+ description : "Pain and decision process validated; budget signal present; technical feasibility confirmed." ,
68+ entryCriteria : [ "Engaged prospect" , "Business + technical discovery" ] ,
69+ exitCriteria : [ "Budget/timeline/authority captured" , "Technical viability confirmed" ] ,
70+ deliverables : [ "MEDDICC summary" , "Qualified Opportunity in CRM" ] ,
71+ } ,
72+ Development : {
73+ label : "Development (50% Best Case)" ,
74+ description : "Solutioning and validation; business case and compelling event linked to value." ,
75+ entryCriteria : [ "Technical work started" , "Solution fit agreed" ] ,
76+ exitCriteria : [ "Technical Win achieved" , "Budget allocated" ] ,
77+ deliverables : [ "Technical validation checklist" , "Mutual Action Plan (MAP)" , "High-level architecture / scope" ] ,
78+ } ,
79+ Proposal : {
80+ label : "Proposal (75% Best Case)" ,
81+ description : "Commercial alignment; quote/SOW delivered; legal/security reviews in progress." ,
82+ entryCriteria : [ "Budget identified" , "Solution design accepted" ] ,
83+ exitCriteria : [ "Budget approval in progress" , "Security/Legal submitted" ] ,
84+ deliverables : [ "Final quote or SOW" , "Security questionnaire / DPA (if required)" ] ,
85+ } ,
86+ Closing : {
87+ label : "Closing (90% Commit)" ,
88+ description : "Signature or PO routing; go-live plan established." ,
89+ entryCriteria : [ "Commercial terms finalized" , "Redlines near completion" ] ,
90+ exitCriteria : [ "Signature/PO received" , "Launch date confirmed" ] ,
91+ deliverables : [ "Executed order form/PO" , "Launch plan" ] ,
92+ } ,
93+ ClosedWon : {
94+ label : "Closed Won (100% Closed)" ,
95+ description : "Provisioning and fulfillment completed; CS intro scheduled." ,
96+ entryCriteria : [ "Executed paperwork" ] ,
97+ exitCriteria : [ "Software/license delivered" , "CS kickoff scheduled" ] ,
98+ deliverables : [ "Fulfillment confirmation" , "Handoff note to CS" ] ,
99+ } ,
100+ Onboarding : {
101+ label : "Onboarding" ,
102+ description : "Kickoff → Implementation → UAT → Launch → Enablement; drive time-to-value and adoption." ,
103+ entryCriteria : [ "Closed-won handoff" ] ,
104+ exitCriteria : [ "Go-live achieved" , "Enablement milestones completed" ] ,
105+ deliverables : [ "Kickoff deck" , "Implementation checklist" , "UAT sign-off" , "Training/Certification path" ] ,
106+ } ,
107+ } ,
108+ bandMeta : {
109+ band1 : {
110+ name : "Band 1 – Full-Cycle Ownership" ,
111+ summary : "Partner leads end-to-end (lead → close). Recast provides SMEs as needed." ,
112+ margin : "30%" ,
113+ color : "bg-green-100 text-green-800" ,
114+ } ,
115+ band2 : {
116+ name : "Band 2 – Joint Engagement" ,
117+ summary : "Co-sell motion. Partner drives top/mid-funnel; Recast supports validation and close." ,
118+ margin : "15%" ,
119+ color : "bg-amber-100 text-amber-800" ,
120+ } ,
121+ band3 : {
122+ name : "Band 3 – Transactional / Referral" ,
123+ summary : "Partner sources or influences; Recast runs the sale." ,
124+ margin : "5% (discretionary)" ,
125+ color : "bg-slate-200 text-slate-800" ,
126+ } ,
127+ } ,
128+ bands : {
129+ band1 : {
130+ PQL : { primaryOwner : "Partner AE" , support : [ "Recast Channel Manager" ] , accountable : "Recast Channel Manager" } ,
131+ Identification : { primaryOwner : "Partner AE" , support : [ "Recast AE" ] , accountable : "Partner Sales Lead" } ,
132+ Qualification : { primaryOwner : "Partner AE" , support : [ "Partner SE" ] , accountable : "Partner Sales Lead" } ,
133+ Development : { primaryOwner : "Partner SE" , support : [ "Recast SE (as-needed)" , "Partner AE" ] , accountable : "Partner SE Lead" } ,
134+ Proposal : { primaryOwner : "Partner AE" , support : [ "Partner SE" , "Recast AE (pricing review)" , "Recast Legal/Security (as-needed)" ] , accountable : "Partner Sales Lead" } ,
135+ Closing : { primaryOwner : "Partner AE" , support : [ "Recast AE" , "Channel Ops" ] , accountable : "Partner Sales Lead" } ,
136+ ClosedWon : { primaryOwner : "Partner AE" , support : [ "Recast AE" , "Recast CS" ] , accountable : "Recast Sales Leader" } ,
137+ Onboarding : { primaryOwner : "Partner Services" , support : [ "Recast CS" , "Partner PM" ] , accountable : "Recast CS Leader" } ,
138+ } ,
139+ band2 : {
140+ PQL : { primaryOwner : "Partner AE" , support : [ "Recast Channel Manager" ] , accountable : "Recast Channel Manager" } ,
141+ Identification : { primaryOwner : "Partner AE" , support : [ "Recast AE" ] , accountable : "Recast AE" } ,
142+ Qualification : { primaryOwner : "Partner AE" , support : [ "Recast SE" ] , accountable : "Recast AE" } ,
143+ Development : { primaryOwner : "Recast SE" , support : [ "Partner SE" , "Partner AE" ] , accountable : "Recast SE Lead" } ,
144+ Proposal : { primaryOwner : "Recast AE" , support : [ "Partner AE" , "Recast Legal/Security" ] , accountable : "Recast Sales Leader" } ,
145+ Closing : { primaryOwner : "Recast AE" , support : [ "Partner AE" , "Channel Ops" ] , accountable : "Recast Sales Leader" } ,
146+ ClosedWon : { primaryOwner : "Recast AE" , support : [ "Recast CS" , "Partner AE" ] , accountable : "Recast Sales Leader" } ,
147+ Onboarding : { primaryOwner : "Recast CS" , support : [ "Partner Services" ] , accountable : "Recast CS Leader" } ,
148+ } ,
149+ band3 : {
150+ PQL : { primaryOwner : "Partner (Referral / LAR)" , support : [ "Recast Channel Manager" ] , accountable : "Recast Channel Manager" } ,
151+ Identification : { primaryOwner : "Recast AE" , support : [ "Partner (Intro only)" ] , accountable : "Recast AE" } ,
152+ Qualification : { primaryOwner : "Recast AE" , support : [ "Recast SE" ] , accountable : "Recast AE" } ,
153+ Development : { primaryOwner : "Recast SE" , support : [ "Recast AE" ] , accountable : "Recast SE Lead" } ,
154+ Proposal : { primaryOwner : "Recast AE" , support : [ "Legal/Security" , "Finance" ] , accountable : "Recast Sales Leader" } ,
155+ Closing : { primaryOwner : "Recast AE" , support : [ "Channel Ops" ] , accountable : "Recast Sales Leader" } ,
156+ ClosedWon : { primaryOwner : "Recast AE" , support : [ "CS" ] , accountable : "Recast Sales Leader" } ,
157+ Onboarding : { primaryOwner : "Recast CS" , support : [ "Partner (as applicable)" ] , accountable : "Recast CS Leader" } ,
158+ } ,
159+ } ,
160+ rows : [ "PQL" , "Identification" , "Qualification" , "Development" , "Proposal" , "Closing" , "ClosedWon" , "Onboarding" ] ,
161+ } ,
48162 model : {
49163 tiers : {
50164 Registered : {
@@ -215,8 +329,14 @@ <h1 class="mt-4 text-3xl font-semibold tracking-tight sm:text-4xl">
215329 { id : 'requirements' , label : 'Requirements & Benefits' , icon : 'check-circle' } ,
216330 { id : 'margins' , label : 'Margins' , icon : 'dollar-sign' } ,
217331 { id : 'roe' , label : 'Rules of Engagement' , icon : 'gavel' } ,
332+ { id : 'salesmotion' , label : 'Sales Motion' , icon : 'table' } ,
218333 { id : 'onboarding' , label : 'Onboarding' , icon : 'rocket' }
219334 ] ;
335+ function setDefaultBand ( type ) {
336+ if ( type === 'Registered' ) return 'band3' ;
337+ if ( type === 'Preferred' ) return 'band2' ;
338+ return 'band1' ;
339+ }
220340 function getPartnerData ( type ) {
221341 if ( [ "Registered" , "Preferred" , "Premier" ] . includes ( type ) ) {
222342 return {
@@ -266,6 +386,9 @@ <h1 class="mt-4 text-3xl font-semibold tracking-tight sm:text-4xl">
266386 case 'roe' :
267387 html += renderROEContent ( ) ;
268388 break ;
389+ case 'salesmotion' :
390+ html += renderSalesMotionContent ( ) ;
391+ break ;
269392 case 'onboarding' :
270393 if ( STATE . partnerType !== 'Registered' ) {
271394 html += renderOnboardingContent ( ) ;
@@ -506,6 +629,57 @@ <h3 class="text-lg font-semibold p-5 border-b border-[#E2E8F0] flex items-center
506629 html += '</tbody></table>' ;
507630 return html ;
508631 }
632+ function renderSalesMotionContent ( ) {
633+ let html = '<h2 class="text-2xl font-bold mb-6 flex items-center gap-3"><i data-lucide="table" class="h-6 w-6 stroke-[#0070F3]"></i>Sales Motion</h2>' ;
634+ html += '<div class="flex flex-col gap-4 md:flex-row md:items-end md:justify-between mb-4">' ;
635+ html += '<div><p class="text-sm text-[#4A5568] mt-1">View the sales cycle matrix showing stages, ownership, support, exit criteria, and deliverables based on the selected band.</p></div>' ;
636+ html += '<select id="bandSelect" class="w-[280px] rounded-lg border border-[#E2E8F0] bg-white px-4 py-2.5 text-sm focus:border-[#0070F3] focus:ring-2 focus:ring-[#0070F3] focus:ring-opacity-50">' ;
637+ [ 'band1' , 'band2' , 'band3' ] . forEach ( b => {
638+ const m = STATE . salesCycle . bandMeta [ b ] ;
639+ html += `<option value="${ b } " ${ STATE . band === b ? 'selected' : '' } >${ m . name } </option>` ;
640+ } ) ;
641+ html += '</select></div>' ;
642+ const meta = STATE . salesCycle . bandMeta [ STATE . band ] ;
643+ html += '<div class="flex flex-wrap items-center gap-3 mb-6">' ;
644+ html += `<span class="px-3 py-1 text-xs rounded-2xl ${ meta . color } ">${ meta . name } </span>` ;
645+ html += `<span class="text-xs text-[#4A5568]">${ meta . summary } </span>` ;
646+ html += '</div>' ;
647+ html += '<div class="overflow-x-auto rounded-2xl border border-[#E2E8F0]">' ;
648+ html += '<table class="min-w-[920px] w-full text-sm">' ;
649+ html += '<thead class="bg-[#F7F9FB]">' ;
650+ html += '<tr class="text-left"><th class="p-3">Stage</th><th class="p-3">Owner</th><th class="p-3">Support</th><th class="p-3">Exit Criteria</th><th class="p-3">Deliverables</th></tr>' ;
651+ html += '</thead><tbody>' ;
652+ STATE . salesCycle . rows . forEach ( key => {
653+ const stage = STATE . salesCycle . stages [ key ] ;
654+ const own = STATE . salesCycle . bands [ STATE . band ] [ key ] ;
655+ html += '<tr class="border-t border-[#E2E8F0] align-top">' ;
656+ html += '<td class="p-3 w-[18%]"><div class="font-medium">' + stage . label + '</div><div class="text-xs text-[#4A5568] mt-1">' + stage . description + '</div></td>' ;
657+ html += '<td class="p-3 w-[18%]"><div class="flex items-start gap-2"><i data-lucide="user-round" class="h-4 w-4 mt-0.5 stroke-[#0070F3]"></i><div><div class="font-medium">' + own . primaryOwner + '</div><div class="text-[11px] text-[#4A5568]">Accountable: ' + own . accountable + '</div></div></div></td>' ;
658+ html += '<td class="p-3 w-[18%]"><div class="flex flex-wrap gap-2">' ;
659+ own . support . forEach ( s => {
660+ html += '<span class="rounded-xl bg-[#E2E8F0] px-2 py-1 text-xs text-[#4A5568]">' + s + '</span>' ;
661+ } ) ;
662+ html += '</div></td>' ;
663+ html += '<td class="p-3 w-[23%]"><ul class="list-disc pl-4 space-y-1">' ;
664+ stage . exitCriteria . forEach ( e => { html += '<li>' + e + '</li>' ; } ) ;
665+ html += '</ul></td>' ;
666+ html += '<td class="p-3 w-[23%]"><ul class="list-disc pl-4 space-y-1">' ;
667+ stage . deliverables . forEach ( d => { html += '<li>' + d + '</li>' ; } ) ;
668+ html += '</ul></td>' ;
669+ html += '</tr>' ;
670+ } ) ;
671+ html += '</tbody></table></div>' ;
672+ html += '<div class="mt-6 text-xs text-[#4A5568] flex flex-wrap gap-4">' ;
673+ html += '<span class="flex items-center gap-1"><i data-lucide="handshake" class="h-3 w-3 stroke-[#0070F3]"></i> Band 1 rewards full-cycle ownership</span>' ;
674+ html += '<span class="flex items-center gap-1"><i data-lucide="users-round" class="h-3 w-3 stroke-[#0070F3]"></i> Band 2 is co-sell</span>' ;
675+ html += '<span class="flex items-center gap-1"><i data-lucide="shield-check" class="h-3 w-3 stroke-[#0070F3]"></i> Band 3 is referral/transactional</span>' ;
676+ html += '</div>' ;
677+ html += '<div class="mt-4 rounded-2xl border border-[#E2E8F0] p-4 bg-[#F7F9FB] flex gap-3 items-start">' ;
678+ html += '<i data-lucide="info" class="h-5 w-5 mt-0.5 stroke-[#0070F3]"></i>' ;
679+ html += '<div><div class="font-medium">Lead Registration & Partner of Record</div><p class="text-[#4A5568] text-sm mt-1">A lead is not considered Partner of Record until approved by Recast through the Partner Portal. Margin eligibility is set at deal approval based on documented ownership and CRM evidence.</p></div>' ;
680+ html += '</div>' ;
681+ return html ;
682+ }
509683 function renderOnboardingContent ( ) {
510684 const steps = STATE . model . onboarding . steps ;
511685 let buttonsHtml = '<div class="flex flex-wrap gap-3 mb-6">' ;
@@ -726,6 +900,7 @@ <h2 class="text-2xl font-bold mb-6 flex items-center gap-3"><i data-lucide="scal
726900 function addEventListeners ( ) {
727901 document . getElementById ( 'partnerType' ) . addEventListener ( 'change' , ( e ) => {
728902 STATE . partnerType = e . target . value ;
903+ STATE . band = setDefaultBand ( STATE . partnerType ) ;
729904 if ( STATE . partnerType === 'Registered' ) {
730905 STATE . newPartner = false ;
731906 if ( [ 'margins' , 'onboarding' ] . includes ( STATE . activeTab ) ) {
@@ -763,6 +938,13 @@ <h2 class="text-2xl font-bold mb-6 flex items-center gap-3"><i data-lucide="scal
763938 render ( ) ;
764939 } ) ;
765940 }
941+ const bandSelect = document . getElementById ( 'bandSelect' ) ;
942+ if ( bandSelect ) {
943+ bandSelect . addEventListener ( 'change' , ( e ) => {
944+ STATE . band = e . target . value ;
945+ render ( ) ;
946+ } ) ;
947+ }
766948 document . querySelectorAll ( '[data-step]' ) . forEach ( ( btn ) => {
767949 btn . addEventListener ( 'click' , ( ) => {
768950 STATE . activeStep = parseInt ( btn . dataset . step ) ;
0 commit comments