Skip to content

feat(donate): balance and surface the donate CTAs - #117

Merged
sanity merged 3 commits into
mainfrom
donate-cta-symmetry
Aug 17, 2026
Merged

feat(donate): balance and surface the donate CTAs#117
sanity merged 3 commits into
mainfrom
donate-cta-symmetry

Conversation

@sanity

@sanity sanity commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Problem

Two issues with the donate page's CTAs:

  1. Unequal visual weight. PayPal got a full-size ## Donate heading 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.
  2. Both below the fold, on every viewport. They sat under "Why Freenet matters", "About the project", and "Major supporters" — 71-81% down the page on desktop, 74-81% down on mobile. A visitor on /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:

  • Matching headings (## Donate via PayPal / ## Donate via card), same size/color in both themes.
  • A real button for the card option using .funding-donate-button — the same class already used for Ghost Key CTAs on /ghostkey/. Links to /ghostkey/create/, the existing entry point.
  • A one-line note under both buttons (.gk-cta-note), not just one, so the fine print doesn't itself mark one option as "the lesser choice."
  • Stripped .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's line-height: 1.75) rendered 4px apart in height purely from ambient context. Pinned line-height: 1.5 explicitly on .funding-donate-button so 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-button is 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"):

before after
PayPal button 71% / 74% (below fold) 16% / 16% (above fold)
Card button 79% / 81% (below fold) 16% / 20% (above fold)

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):

  • All four: 48px tall, 24px line-height, 16px font, rgb(0,102,204) background — identical
  • Headings: 22.4px font-size, same color per theme (rgb(26,26,46) light / rgb(232,232,232) dark) on both PayPal and card sections
  • Notes: 14.4px font-size, same color, present under both options in both places

Button 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:

  • Bug: the "same color" claim for notes was wrong. .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-section container — which the hero row and bottom sections both are, but /ghostkey/'s notes never were. Measured: rgb(100,116,139) on /ghostkey/ vs rgb(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.
  • Inaccurate claim, corrected above: the line-height pin does change /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]

sanity and others added 2 commits August 17, 2026 08:59
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
@sanity
sanity merged commit 38877ed into main Aug 17, 2026
2 checks passed
@sanity
sanity deleted the donate-cta-symmetry branch August 17, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant