Skip to content

Commit 315e3fc

Browse files
fix(promo-bar): keep the deadline visible on mobile, and count down (#15)
On narrow screens the bar hid `.promo-bar-meta` along with the long sell, so a phone saw "20% off with ALPHA_20 · See the recorder" and no reason to act now. The deadline is the urgency; it is the last thing that should go. - The deadline never hides at any width. Only the long sales line drops under 900px. - It sharpens in the final week: "ends Aug 15" becomes "6 days left", "1 day left", then "last day", and turns emerald once inside 7 days. - Weight bumped and colour moved from muted to secondary so it reads as a deadline rather than as metadata. - Small-screen row can wrap without the close button drifting. Also corrects a bogus gap entry. The "horizontal overflow at 390px" logged earlier was a measurement artefact: headless Chrome/Brave on macOS clamps its window to a ~500px minimum layout width while still writing the PNG at the requested width, so a 390px screenshot is a 500px layout cropped to 390px. Instrumented the real page instead - clientWidth and scrollWidth both 500, no element over the viewport. Verifying below 500px needs CDP device-metrics emulation, not --window-size. Verified: clean production build; bar renders code + deadline + CTA + close on one line at 500px with nothing clipped; countdown path confirmed by temporarily setting `until` three days out ("3 days left", emerald).
1 parent 24a44bc commit 315e3fc

3 files changed

Lines changed: 28 additions & 6 deletions

File tree

_includes/promo-bar.html

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<span class="promo-bar-code-value">{{ promo.code }}</span>
1010
<span class="promo-bar-code-copied" aria-hidden="true">copied</span>
1111
</button>
12-
<span class="promo-bar-meta">{{ promo.meta }}</span>
12+
<span class="promo-bar-meta" id="promoBarMeta">{{ promo.meta }}</span>
1313
<a class="promo-bar-cta" href="{{ promo.url | relative_url }}{{ promo.anchor }}">{{ promo.cta }} →</a>
1414
</div>
1515
<button type="button" class="promo-bar-close" id="promoBarClose" aria-label="Dismiss offer">
@@ -23,11 +23,23 @@
2323
var code = bar.getAttribute('data-promo-code');
2424
var until = bar.getAttribute('data-promo-until');
2525
// Expired offers never render, even from a cached page.
26-
if (until && new Date(until + 'T23:59:59') < new Date()) return;
26+
var ends = until ? new Date(until + 'T23:59:59') : null;
27+
var now = new Date();
28+
if (ends && ends < now) return;
2729
if (localStorage.getItem('promo-dismissed:' + code) === '1') return;
2830
bar.hidden = false;
2931
document.documentElement.classList.add('has-promo-bar');
3032

33+
// Urgency: the deadline is the one thing that never gets hidden, on any
34+
// screen size. It sharpens into a countdown in the final week.
35+
var meta = document.getElementById('promoBarMeta');
36+
if (meta && ends) {
37+
var daysLeft = Math.floor((ends - now) / 86400000);
38+
if (daysLeft <= 0) meta.textContent = 'last day';
39+
else if (daysLeft <= 7) meta.textContent = daysLeft === 1 ? '1 day left' : daysLeft + ' days left';
40+
if (daysLeft <= 7) meta.classList.add('urgent');
41+
}
42+
3143
var copyBtn = document.getElementById('promoBarCode');
3244
if (copyBtn) {
3345
copyBtn.addEventListener('click', function() {

assets/css/main.css

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,13 @@ body { font-family: var(--font); color: var(--text-primary); background: var(--b
137137
.promo-bar-code.copied .promo-bar-code-copied { display: inline; }
138138
.promo-bar-meta {
139139
font-size: 0.75rem;
140-
color: var(--text-muted);
140+
font-weight: 600;
141+
color: var(--text-secondary);
141142
white-space: nowrap;
142143
flex-shrink: 0;
143144
}
145+
/* Final week: the deadline stops being metadata and starts being the point. */
146+
.promo-bar-meta.urgent { color: var(--accent); }
144147
.promo-bar-cta {
145148
font-size: 0.78rem;
146149
font-weight: 600;
@@ -166,16 +169,21 @@ body { font-family: var(--font); color: var(--text-primary); background: var(--b
166169
}
167170
.promo-bar-close:hover { color: var(--text-primary); background: var(--bg-hover); }
168171

172+
/* The long sell drops on narrow screens; the code, the deadline and the CTA
173+
never do - a bar without a deadline has no urgency left in it. */
169174
@media (max-width: 900px) {
170-
.promo-bar-text, .promo-bar-meta { display: none; }
175+
.promo-bar-text { display: none; }
171176
}
172177
@media (max-width: 560px) {
173-
.promo-bar { gap: 4px; padding: 6px 8px; }
178+
.promo-bar { gap: 4px; padding: 6px 8px; align-items: flex-start; }
174179
.promo-bar-tag { display: none; }
180+
.promo-bar-inner { gap: 3px 8px; }
175181
.promo-bar-code { padding: 2px 6px; }
176182
.promo-bar-code-label { font-size: 0.7rem; }
177183
.promo-bar-code-value { font-size: 0.74rem; }
184+
.promo-bar-meta { font-size: 0.7rem; }
178185
.promo-bar-cta { font-size: 0.74rem; }
186+
.promo-bar-close { margin-top: 1px; }
179187
}
180188

181189
/* Promo code block (in-page, e.g. the alpha join section) */

docs/GAPS_BACKLOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ Open gaps, surfaced honestly. Close with evidence, then mark resolved.
44

55
## Open
66

7-
- **Pages overflow horizontally at 390px** (found 2026-07-25). At a 390x844 viewport the document is wider than the viewport, so hero copy and button rows are clipped on the right. Reproduced on `/mobile/` and `/pro/` with the promo bar disabled, so it predates the promo bar and is not caused by it. Next step: find the element forcing `scrollWidth > 390` (suspect a fixed-width block in the shared content styles) and cap it, then re-verify the main journey at 390px.
7+
_None._
88

99
## Resolved
1010

11+
- **A reported horizontal overflow at 390px did not exist - the measurement was wrong** (2026-07-25). Headless Chrome/Brave on macOS clamps its window to a ~500px minimum layout width while still writing a PNG at the requested `--window-size` width, so `--window-size=390,844` laid the page out at 500px and cropped the image to 390px. The crop looked like clipped content. Instrumented the built page in the browser instead: at the narrowest honest render `clientWidth` and `scrollWidth` both report 500 and no element exceeds the viewport. **Verifying responsive layout below 500px needs real device-metrics emulation (Playwright/Puppeteer CDP), not `--window-size`** - a plain screenshot at those widths cannot be trusted.
12+
1113
- **The pricing ladder showed a stale, fabricated fallback and used RevenueCat's rolling 28-day Overview count instead of the cumulative customer total** (2026-07-20). The counter worker now requests the cumulative RevenueCat Charts v3 `customers_new` total from the project's inception date, with pure parsing and URL-contract tests. The website has no numeric fallback: it shows a reduced-motion-safe loading status, reveals scarcity only after a verified response, and reports an unavailable state on failure. Verified against the production RevenueCat API, where the cumulative total is 795, plus worker tests, typecheck, dry-run bundle, production Jekyll build, rendered assertions, and live endpoint/page checks.
1214

1315
- **Visual browser QA was incomplete for the four-platform rollout** (2026-07-17). Rendered and inspected `/`, `/download/`, `/desktop/`, `/desktop/releases/`, `/mobile/`, and `/mobile/releases/` at 1440x1000 and 390x844 after the final production build. Platform labels, release states, download controls, headings, and requirements are readable and unclipped at both widths, with no horizontal overflow in the changed journey.

0 commit comments

Comments
 (0)