feat(donate): balance and surface the donate CTAs - #117
Merged
Conversation
The two ways to donate had wildly unequal visual weight: PayPal got a full-size heading and a filled primary button, while Ghost Keys (card via Stripe) was a muted grey paragraph with an inline text link and no button at all. Ian wants them presented as two genuine, equally-weighted choices. Give the card option the same treatment as PayPal: a matching heading, a real button reusing the existing .funding-donate-button style (the same pattern already used for Ghost Key CTAs on /ghostkey/), and a one-line note underneath explaining what it does, mirrored on both sides so neither reads as the "real" option and neither as the afterthought. No urgency, scarcity, or pre-selection — just parity. Testing: built with hugo, screenshotted desktop/mobile x light/dark with Playwright, and diffed bounding boxes before/after. Headings are now the same font-size/color in both themes; both buttons render at identical height/font-size with the same background color; both notes render at the same font-size. Confirmed no other content file references .funding-ghost-keys before editing its rules. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TdTrb76FvWpw1LXF7eoHJB
Both CTAs were below the fold on every viewport (71-81% down desktop, 74-81% down mobile), buried under "Why Freenet matters", "About the project", and "Major supporters". A visitor on /donate/ already decided to give (they clicked "Donate" in the nav) — making them scroll past three sections of persuasion before they can act is pure friction, the same mistake fixed on /ghostkey/ in PR #93. Add a two-column CTA row right under the hero lead paragraph, using the same balanced heading/button/note treatment as the existing bottom section (which stays in place, unchanged wording, as a second chance for anyone who reads first). "Why Freenet matters", "About the project", and "Major supporters" are untouched below. Also pin .funding-donate-button's line-height explicitly: the hero button (bare div, no <p> wrapper) and the bottom button (wrapped in a <p> that inherits .funding-section p's line-height: 1.75) were rendering 4px apart in height purely from ambient context. Pinning it makes every instance of the button pixel-identical regardless of where it's placed. Testing: hugo build clean. Playwright screenshots + bounding-box measurements at desktop (1280x900) and mobile (390x844), light and dark, before and after. Both hero buttons now render at 16-20% down the page (above the fold on both viewports); all four button instances across the page are 48px tall / 24px line-height / same background in both themes. Also screenshotted /ghostkey/ to confirm the line-height change doesn't visibly regress its existing button. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TdTrb76FvWpw1LXF7eoHJB
Review of #117 found the note under both donate buttons was rendering two different colors depending on placement: rgb(100,116,139) on /ghostkey/ (light) vs rgb(55,65,81) in the donate page's bottom sections, and the equivalent pair in dark mode. Root cause: .gk-cta-note (0,1,0) loses to .funding-section p (0,1,1) whenever a note is nested inside a .funding-section container, which the hero CTA row and bottom donate sections both are. The class only ever "worked" on /ghostkey/ because nothing there outranked it. Fix: .gk-cta-note.gk-cta-note (0,2,0) beats .funding-section p outright, regardless of source order, so this can't silently break again if the file gets reordered. Comment explains why, so nobody simplifies it back to a single class. Verified by measuring computed color, not inferring from the cascade: all four .gk-cta-note instances on /donate/ (hero x2, bottom x2) and all four on /ghostkey/ now report the identical rgb() value in both light and dark. Confirmed the /ghostkey/ button heights (48px) and page height (8291px) are unchanged by this fix — this commit only touches the note's own selector. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TdTrb76FvWpw1LXF7eoHJB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two issues with the donate page's CTAs:
## Donateheading and a filled primary button. Ghost Keys (card via Stripe) was a muted grey paragraph with an inline text link and no button at all./donate/already decided to give (they clicked "Donate" in the nav); making a decided donor scroll past three sections of persuasion before they can act is friction, the same mistake fixed on/ghostkey/in PR feat(ghostkey): fix donation funnel conversion and suppress Stripe Link #93.Approach
Symmetry: gave the card option the same treatment as PayPal, reusing existing patterns:
## Donate via PayPal/## Donate via card), same size/color in both themes..funding-donate-button— the same class already used for Ghost Key CTAs on/ghostkey/. Links to/ghostkey/create/, the existing entry point..gk-cta-note), not just one, so the fine print doesn't itself mark one option as "the lesser choice.".funding-ghost-keys's color/size overrides, kept only the divider.Above the fold: added a two-column CTA row right after the hero lead paragraph — same heading/button/note treatment as the bottom section, which stays in place unchanged (a second chance for anyone who reads the mission/major-supporters content first, per the pattern already established on
/ghostkey/). No escalating language on the repeat; wording is identical top and bottom. "Why Freenet matters", "About the project", and "Major supporters" are untouched.Pixel parity fix: discovered while measuring that the hero button (bare
<div>, no<p>wrapper) and the bottom button (wrapped in a<p>that inherits.funding-section p'sline-height: 1.75) rendered 4px apart in height purely from ambient context. Pinnedline-height: 1.5explicitly on.funding-donate-buttonso every instance is pixel-identical regardless of where it's placed. This is a deliberate, shared normalization: it also changes/ghostkey/'s three existing buttons from 49.59px to 48px tall (page 6px shorter overall), imperceptible at normal zoom, and intentional —.funding-donate-buttonis now consistent across both pages, so a future change to its line-height is a real cross-page change, not a local one.No dark patterns: no urgency, scarcity, pre-selection, or guilt-framed copy on either option.
Testing
Built with
hugo --quiet(clean). Verified with Playwright at desktop (1280x900) and mobile (390x844), light and dark, before and after — read every screenshot, not just the numbers.Position (desktop / mobile, "% down the page"):
Both hero CTAs land inside the first viewport on both desktop and mobile.
Balance (desktop, both themes, all 4 button instances — hero x2 + bottom repeat x2):
rgb(0,102,204)background — identicalrgb(26,26,46)light /rgb(232,232,232)dark) on both PayPal and card sectionsButton width differs only by label length (195px "Donate via PayPal" vs 177px "Donate via card").
Update: review findings addressed
Independent review (thanks!) caught a real bug and one inaccurate claim above, both fixed in a follow-up commit:
.gk-cta-note(specificity 0,1,0) was silently losing to.funding-section p(specificity 0,1,1) whenever a note landed inside a.funding-sectioncontainer — which the hero row and bottom sections both are, but/ghostkey/'s notes never were. Measured:rgb(100,116,139)on /ghostkey/ vsrgb(55,65,81)in the donate page's bottom sections (light), and the equivalent pair in dark. Fixed with.gk-cta-note.gk-cta-note(specificity 0,2,0), which wins outright regardless of file order — commented so it isn't "simplified" back to a single class. Re-measured after the fix: all 8 note instances across both pages (donate hero x2, donate bottom x2, ghostkey x4) now report the identical computed color per theme./ghostkey/'s buttons (49.59px → 48px), not "doesn't visibly change" as originally stated. It's kept as a deliberate, imperceptible, cross-page normalization — see the corrected paragraph above.Not changed, per reviewer + my agreement: the note-length asymmetry (PayPal one line, card three) is content-driven — a Ghost Key genuinely needs more explanation — and the buttons, which carry the actual decision, are identical.
Closes the visual-parity and above-the-fold requests from Ian.
[AI-assisted - Claude]