Skip to content

Pin the first screen at 390x844 on the nine pages a buyer lands on - #364

Merged
Apolloccrypt merged 1 commit into
mainfrom
test/first-screen-geometry
Sep 2, 2026
Merged

Pin the first screen at 390x844 on the nine pages a buyer lands on#364
Apolloccrypt merged 1 commit into
mainfrom
test/first-screen-geometry

Conversation

@Apolloccrypt

@Apolloccrypt Apolloccrypt commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Every copper pin in this repo reads markup. The text is in the HTML, so the
assertion is green, and none of them looks at where that text ends up on a
screen. A single CSS line moves it: margin-top: 400px on .about-byline
leaves /about with the same words, the same DOM and the same passing suite, and
pushes the name of the person behind the product below a 390x844 phone screen.

tests/pricing-fold.test.mjs already measures this for /pricing. This is the
same instrument pointed at the other nine pages.

The font had to be forced, and that is the finding

design-system.css resolves --sans and --mono to system stacks with no
@font-face anywhere. The same page is therefore a different height on every
machine. The first push of this branch was green here and red in CI:
ui-sans-serif resolves to Cantarell on Fedora and to DejaVu Sans on
ubuntu-latest, and /parasign moved 63px between them, /help 41px.

A gate whose numbers depend on the runner is not a gate, so the suite forces
DejaVu Sans / DejaVu Sans Mono on every page. That is what CI renders
anyway and it is the widest of the faces in play, so a developer now reads the
same numbers the gate does. DejaVu arrives with playwright install --with-deps; the resolved family is printed in every failure message, so a run
on a machine without it says so rather than looking like a layout regression.

What is pinned

Bottom edge from getBoundingClientRect(), in CSS pixels from the top of the
document, Chromium at 390x844, signed out, served from frontend/ the way
deploy/nginx-paramant-live.conf routes it. These are the numbers the suite
prints today.

Page Claim Selector top bottom
/ H1 [data-home="out"] h1 88 215
who it is for [data-home="out"] p.lede 231 442
first action, to /sign [data-home="out"] .home-actions a 466 512
Community and business plans split [data-home="out"] p.hero-note 528 579
heading of the section that explains the split #split-h 671 725
/parasign who it is for p.ps-who 472 544
first action, to /sign .ps-actions a.btn-primary 576 622
free limit p.ps-fine 696 760
SES scope statement text range in .scope-note p 825 863 (below)
/parasend who it is for p.ps-who 396 492
first action, to /parashare .ps-actions a.btn-primary 524 570
free limit p.ps-sub 644 727
/about the name .about-byline .n 463 489
the title .about-byline .t 493 525
first action, to /pricing .hero-cta a.btn-primary 549 596
second action, to /security .hero-cta a.btn-secondary 608 654
/security bounded promise .page-hero .lede 179 476
who is behind it .hero-by 600 662
first action, to /pricing .hero-cta a.btn-primary 682 728
second action, to /verify .hero-cta a.btn-secondary 742 788
/trust lede .page-hero .lede 179 422
first action, to /security .hero-cta a.btn-primary 442 488
second action, to /pricing .hero-cta a.btn-secondary 502 548
/docs the line for the buyer p.docs-buyer 170 237
first button, to #quickstart .docs-hero-actions a.docs-hero-btn 376 414
second button, to /pricing same, index 1 426 464
/help first answer .buyer-qa-item p.buyer-qa-a 357 419
second answer same, index 1 494 639
third answer same, index 2 715 860 (below)
/download status sentence header.dl-lead h1 115 284
the sentence under it header.dl-lead p.dl-sub 300 374
first button, to / .dl-actions a.btn-primary 402 449
second button, to /pricing .dl-actions a.btn-outline 402 449

All nine pages also assert scrollWidth == clientWidth == 390. Equal, not
merely no wider: a page that lays out narrower than the screen is the same bug
seen from the other side. This is the defect /pricing shipped, where a
white-space: nowrap button set the min-content width of the whole grid track
and clipped every tier card.

Two claims do not fit, and both are real

Marked (below) above. On a narrow face they sit on the first screen and the
reviewers read them there; on a wide one they hang over the edge.

Page Claim Cantarell DejaVu What the reader loses
/parasign SES scope statement 800 863, 19px over that a ParaSign signature is not a qualified one under eIDAS
/help third answer 819 860, 16px over that the documents live in Germany

I did not loosen the rule to 863 and I did not touch the pages, which is not a
test's job. Those two claims are pinned in place instead of to the fold:
each holds its measured bottom with 2px for a Chromium rounding change, so it
cannot drift further while it waits to be fixed, and the suite goes red with an
explicit message if someone fixes the page without dropping the pin.

Both are small copy or spacing jobs. Worth a follow-up, not worth blocking a
measuring instrument that did exactly what it was built to do on its first run.

Three decisions worth naming

The bottom edge, never the top. A line whose top sits at y=830 is on screen
and unreadable. Every assertion compares bottom against 844 and the failure
message names the measured value and the overshoot:

/about: the name of the person behind it ends at y=865, 21px past the 844px
first screen (top y=839, font DejaVu Sans). A phone reader has to scroll for it.

One claim is measured on a text range, not its block. The SES scope note on
/parasign sits in a paragraph running to y=911, and that is by design: it goes
on to say what a ParaSign signature is not, under eIDAS and QES. Asserting the
block bottom would be red on a page nobody broke. What has to be readable before
a buyer signs is the sentence, so the test builds a Range over that phrase and
measures its own line boxes.

Text is checked as well as geometry. Every claim carries the words it
expects, so a selector that silently starts matching a different same-classed
element fails on the text rather than on a number that happens to still fit.

No copy changed, no attribute added

The task allowed a data-fold hook where no stable one existed. None was
needed: every claim rides an id or class the pages already carry
([data-home="out"], #split-h, .ps-who, .about-byline .n, .hero-by,
.docs-buyer, .buyer-qa-a, .dl-lead). The diff is one new file. The only
page that lacked a hook was /download, and #358 landed a hero with real classes
while this was being written.

Sabotage, one CSS shove per page

A <style> block appended before </body>, suite rerun, page reverted. All nine
red, each on the claim the shove actually moved.

Page Injected Red on
/ .home-actions{margin-top:400px} split line, y=955, 111px past
/parasign .ps-actions{margin-top:400px} first action, y=990, 146px past
/parasend .ps-actions{margin-top:400px} first action, y=938, 94px past
/about .about-byline{margin-top:400px} the name, y=865, 21px past
/security .hero-by{margin-top:400px} who is behind it, y=1046, 202px past
/trust .hero-cta{margin-top:400px} first action, y=868, 24px past
/docs .docs-hero-actions{margin-top:400px} second button, y=850, 6px past
/help .buyer-qa{margin-top:400px} second answer, y=991, 147px past
/download .dl-actions{margin-top:430px} first button, y=851, 7px past

/download is worth reading twice. margin-top replaces the element's own
margin rather than adding to it, and .dl-actions already carries
margin-top:28px. A 400px shove is a 372px move, the buttons land at 821, and
the suite stays green because they are still readable. That is the measurement
working, not a gap in it. 430px moves them to 851 and it goes red.

CI

The suite imports playwright, so .github/workflows/sign-e2e.yml:40 picks it
up with the other browser suites by import, with no workflow change. That
selector was written for exactly this.

Tests

  • tests/first-screen.test.mjs: 9 pages, all pass
  • browser suites, grep -l "from 'playwright'" tests/*.mjs minus sign-full and product-heartbeat: 21/21
  • tests/sign-full.test.mjs: 33/33
  • non-browser suites, grep -L "from 'playwright'" tests/*.mjs: 153 tests, 151 pass, 2 skipped, 0 fail
  • tests/static-sanity.sh: PASS, all 11 checks clear, including 10 (commit style) and 11 (test-scope guard, 111 suites)

@Apolloccrypt
Apolloccrypt force-pushed the test/first-screen-geometry branch from 7335b20 to 94a202a Compare September 2, 2026 19:37
Every copper pin in this repo reads markup. A CSS line moves the words
without touching them: margin-top:400px on .about-byline leaves /about
with the same HTML, the same DOM and a green suite, and drops the name
of the person behind the product below a 390x844 phone screen.

tests/pricing-fold.test.mjs already measures this for /pricing. This is
the same instrument pointed at the other nine pages. Bottom edge from
getBoundingClientRect, asserted against 844, and a failure names the
measured value and the overshoot:

  /          H1 215, audience 442, first action 512, the Community and
             business plans split 579, split heading 725
  /parasign  audience 544, first action 622, free limit 760
  /parasend  audience 492, first action 570, free limit 727
  /about     name 489, title 525, actions 596 and 654
  /security  bounded promise 476, who is behind it 662, actions 728/788
  /trust     lede 422, actions 488 and 548
  /docs      buyer line 237, buttons 414 and 464
  /help      first two answers 419 and 639
  /download  status sentence 284, sub 374, both buttons 449

Every page also asserts scrollWidth = clientWidth = 390, so a card that
overflows its grid is caught the way /pricing was.

The font is forced to DejaVu Sans. design-system.css resolves --sans and
--mono to system stacks with no @font-face, so page height depends on the
machine: the first run of this file was green on Fedora, where
ui-sans-serif resolves to Cantarell, and red on ubuntu-latest, where it
resolves to DejaVu. A gate whose numbers depend on the runner is not a
gate.

Under that wider face two claims do not fit, and both are real rather
than an artefact of the measurement:

  /parasign  the SES scope statement ends at 863, 19px over. On a wide
             face a buyer scrolls to learn the signature is not a
             qualified one.
  /help      the third answer ends at 860, 16px over. That is the answer
             saying the documents live in Germany.

They are pinned in place instead of to the fold, so they cannot drift
further, and the suite goes red if either is fixed without dropping its
pin. The SES claim is measured on a text range: its paragraph runs to
911 by design, and what has to be readable is the sentence.

No copy changed and no attribute was added: every selector is an id or
class the pages already carry. The suite imports playwright, so
sign-e2e picks it up with the other browser suites.

Sabotage, one CSS shove per page, all nine red on the right claim:
.home-actions, .ps-actions on both product pages, .about-byline,
.hero-by, .hero-cta, .docs-hero-actions and .buyer-qa at 400px, and
.dl-actions at 430px. margin-top replaces the element's own margin
rather than adding to it, so 400px on .dl-actions is a 372px move and
lands 23px short of the edge, which is the measurement working.
@Apolloccrypt
Apolloccrypt force-pushed the test/first-screen-geometry branch from 94a202a to 3906ee8 Compare September 2, 2026 19:42
@Apolloccrypt
Apolloccrypt merged commit 727175f into main Sep 2, 2026
10 checks passed
@Apolloccrypt
Apolloccrypt deleted the test/first-screen-geometry branch September 5, 2026 18:57
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