I believe I figured it out. In the code I pasted I did have the the "promotedResults" section separate from the "hasPrimaryorSecondaryResults" section, however they were contained within the same DIV. I moved the the promoted results to it's own DIV and viola, promoted results started displaying even if there are no primary or seconday results.
Does not work:
<div class="template_root">
{{#if @root.promotedResults}}
{{#each @root.promotedResults as |promotedResult|}}
<div class="bnf-container">
<div class="bnf-heroFrame">
<div class="bnf-heroColumn">
<div class="bnf-bookmarkContent">
<a class="bnf-href" href="{{Url}}">{{Title}}</a><br />
</div>
<div>
<a class="bnf-url" href="{{Url}}">{{Url}}</a>
</div>
</div>
</div>
</div>
{{/each}}
{{/if}}
{{#if @root.hasPrimaryOrSecondaryResults}}
<div class="template_defaultCard">
<div class="document-card-container">
{{#each data.items as |item|}}
<div class="document-card-item">
{{#> resultTypes item=item}}
{{!-- The block below will be used as default item template if no result types matched --}}
{{#eq item.contentclass 'STS_ListItem_851'}}
<span>No related news found</span>
{{else}}
<p>
<a class='bnf-href' href="{{getUrl item}}">{{slot item @root.slots.Title}}</a><br />
{{Path}}<br />
</p>
<!--pnp-document-card data-item="{{JSONstringify item}}" data-fields-configuration="{{JSONstringify @root.documentCardFields}}" data-enable-preview="{{@root.enablePreview}}" data-show-file-icon="{{@root.showFileIcon}}" data-is-compact="{{@root.isCompact}}"></pnp-document-card-->
{{/eq}}
{{/resultTypes}}
</div>
{{/each}}
</div>
</div>
Does work
<div class="template_root">
{{#if @root.promotedResults}}
{{#each @root.promotedResults as |promotedResult|}}
<div class="bnf-container">
<div class="bnf-heroFrame">
<div class="bnf-heroColumn">
<div class="bnf-bookmarkContent">
<a class="bnf-href" href="{{Url}}">{{Title}}</a><br />
</div>
<div>
<a class="bnf-url" href="{{Url}}">{{Url}}</a>
</div>
</div>
</div>
</div>
{{/each}}
{{/if}}
</div>
<div class="template_root">
{{#if @root.hasPrimaryOrSecondaryResults}}
<div class="template_defaultCard">
<div class="document-card-container">
{{#each data.items as |item|}}
<div class="document-card-item">
{{#> resultTypes item=item}}
{{!-- The block below will be used as default item template if no result types matched --}}
{{#eq item.contentclass 'STS_ListItem_851'}}
<span>No related news found</span>
{{else}}
<p>
<a class='bnf-href' href="{{getUrl item}}">{{slot item @root.slots.Title}}</a><br />
{{Path}}<br />
</p>
<!--pnp-document-card data-item="{{JSONstringify item}}" data-fields-configuration="{{JSONstringify @root.documentCardFields}}" data-enable-preview="{{@root.enablePreview}}" data-show-file-icon="{{@root.showFileIcon}}" data-is-compact="{{@root.isCompact}}"></pnp-document-card-->
{{/eq}}
{{/resultTypes}}
</div>
{{/each}}
</div>
</div>
{{#if @root.paging.showPaging}}
<pnp-pagination data-total-items="{{@root.paging.totalItemsCount}}"
data-hide-first-last-pages="{{@root.paging.hideFirstLastPages}}"
data-hide-disabled="{{@root.paging.hideDisabled}}"
data-hide-navigation="{{@root.paging.hideNavigation}}"
data-range="{{@root.paging.pagingRange}}"
data-items-count-per-page="{{@root.paging.itemsCountPerPage}}"
data-current-page-number="{{@root.paging.currentPageNumber}}">
</pnp-pagination>
{{/if}}
{{else}}
{{#unless showBlank}}
{{/unless}}
{{/if}}
</div>