renderAppStoreBlockHtml function
Renders the fa1.dev homepage App Store block (the whole <section>
element, WITHOUT the markers) for links.
AC2: App Store badge + link, paid-release vs free-forever-beta
messaging, and an Android slot that renders "coming soon" while
links.play is unset. AC6: zero superlative claims — the store copy
compliance list (issue #643) applies to the site like to the store.
Implementation
String renderAppStoreBlockHtml(LinksConfig links) {
final android = links.play == null
? '''
<a class="btn btn-store btn-soon" aria-disabled="true">
<span class="sooner">Android</span> coming soon
</a>'''
: '''
<a class="btn btn-store" href="${_escapeAttr(links.play!)}" target="_blank" rel="noopener" data-store-referral="play">
<span class="sooner">Android</span> Get it on Google Play
</a>''';
return '''
<section id="app-store" class="app-store reveal">
<p class="kicker">Mobile</p>
<h2>Fa in your pocket.</h2>
<p class="section-lede">
The same agent and the same sandbox, from the App Store. The App
Store release is paid — that is what funds development. The public
TestFlight beta is free forever and tracks the same code; pick
whichever fits you. See the app in the store frames on the
<a href="./app-store/">App Store page</a>.
</p>
<div class="store-row">
<a class="btn btn-primary btn-store" href="${_escapeAttr(links.appstore)}" target="_blank" rel="noopener" data-store-referral="appstore">
${_appleLogoSvg('beta-mark', 15)}
Download on the App Store
</a>
<a class="btn btn-beta btn-store" href="${_escapeAttr(links.testflight)}" target="_blank" rel="noopener" data-store-referral="testflight">
${_appleLogoSvg('beta-mark', 15)}
Join the free beta on TestFlight
</a>
$android
<a class="btn btn-store" href="${_escapeAttr(links.site)}" data-store-referral="site">fa1.dev</a>
</div>
<ul class="pills" aria-label="Release channels">
<li>App Store — paid release</li>
<li>TestFlight — free beta, forever</li>
<li>Android — ${links.play == null ? 'coming soon' : 'on Google Play'}</li>
</ul>
</section>''';
}