[object Object]

← back to AbramsEgo

feat(ads): house-ad slot + ads.txt stub

e66492651895cb16d961b3244c5b0472910132c4 · 2026-07-01 18:21:27 -0700 · Steve

Engine 4 scaffolding — landing footer renders a house ad (Fleet Health
Report / waitlist self-promo) until AD_NETWORK_PUB_ID is set, then swaps
to the generic network container. /api/ads/config + /ads.txt allowlisted
under PUBLIC_LANDING. Ads engine pill flips live only on the env switch.
Joining a network stays Steve-gated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Files touched

Diff

commit e66492651895cb16d961b3244c5b0472910132c4
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jul 1 18:21:27 2026 -0700

    feat(ads): house-ad slot + ads.txt stub
    
    Engine 4 scaffolding — landing footer renders a house ad (Fleet Health
    Report / waitlist self-promo) until AD_NETWORK_PUB_ID is set, then swaps
    to the generic network container. /api/ads/config + /ads.txt allowlisted
    under PUBLIC_LANDING. Ads engine pill flips live only on the env switch.
    Joining a network stays Steve-gated.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---
 build-queue/{tasks => done}/38-ads-slot.md |  0
 public/landing.html                        | 37 ++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/build-queue/tasks/38-ads-slot.md b/build-queue/done/38-ads-slot.md
similarity index 100%
rename from build-queue/tasks/38-ads-slot.md
rename to build-queue/done/38-ads-slot.md
diff --git a/public/landing.html b/public/landing.html
index d8f4c70..5965932 100644
--- a/public/landing.html
+++ b/public/landing.html
@@ -247,6 +247,28 @@
     <div class="kicker" style="margin-bottom:10px">Tools we run on</div>
     <div id="tools-links" style="display:flex;gap:18px;justify-content:center;flex-wrap:wrap;font-size:13px"></div>
   </section>
+
+  <!-- AD SLOT (engine 4) — house ad by default. When /api/ads/config reports a
+       pub id (Steve joined a network + set AD_NETWORK_PUB_ID, the gated
+       switch), the house card hides and the generic network container below
+       renders instead. -->
+  <section id="ad-slot" style="padding:30px 20px;border-bottom:0">
+    <div class="card" id="house-ad" style="max-width:620px;margin:0 auto;display:flex;gap:16px;align-items:center;flex-wrap:wrap">
+      <div class="ico" style="font-size:26px">📄</div>
+      <div style="flex:1;min-width:220px">
+        <div style="font-size:10px;letter-spacing:1px;text-transform:uppercase;color:var(--dim)">House ad</div>
+        <h3 style="margin:4px 0 4px">Your fleet, as a report clients can read</h3>
+        <p>The Fleet Health Report turns your live snapshot into a polished, sendable artifact.
+           <a href="/api/report/sample">See a sample</a> — or <a href="#waitlist">join the waitlist</a> for hosted plans.</p>
+      </div>
+      <a class="btn ghost" href="/api/report/sample" style="flex-shrink:0">View sample →</a>
+    </div>
+    <!-- Generic network container. The pub id lands on data-pub-id; the
+         network's loader <script> (e.g. AdSense adsbygoogle.js?client=<pub id>)
+         is added here only at go-live — joining a network is Steve's gated
+         switch, nothing in this repo signs up. -->
+    <div id="network-ad" hidden style="max-width:728px;margin:0 auto;text-align:center"></div>
+  </section>
 </main>
 
 <footer>
@@ -324,6 +346,21 @@ const usd = (n)=> n==null? '—' : '$'+Number(n).toFixed(n<1?4:2);
   }catch(e){ /* strip stays hidden */ }
 })();
 
+// Ad slot ← GET /api/ads/config. House ad by default; with a pub id the house
+// card hides and the generic network unit renders (the network's loader script
+// is added at go-live, alongside the real ads.txt entry — both Steve-gated).
+(async function wireAdSlot(){
+  try{
+    const cfg = await (await fetch('/api/ads/config')).json();
+    if(!cfg || !cfg.enabled || !cfg.pubId) return; // house ad stays
+    $('house-ad').hidden = true;
+    const slot = $('network-ad');
+    slot.innerHTML = '<ins class="ad-network-unit" data-pub-id="'+cfg.pubId.replace(/[^\w-]/g,'')+'"'+
+      ' style="display:block;min-height:90px;border:1px dashed var(--line);border-radius:12px"></ins>';
+    slot.hidden = false;
+  }catch(e){ /* house ad stays */ }
+})();
+
 // Waitlist capture → POST /api/waitlist
 $('wl-form').addEventListener('submit', async (e)=>{
   e.preventDefault();

← 3dec20a auto-save: 2026-07-01T18:07:58 (5 files) — build-queue/tasks  ·  back to AbramsEgo  ·  auto-save: 2026-07-01T18:38:06 (8 files) — data/local-fleet. 1c59231 →