What is going on up there
Two columns, 1fr and 0.9fr, 100 px apart. On the
left, a stack: eyebrow, heading, paragraph, then a row carrying the call to action
and the social proof. On the right, a single photograph — its bottom left corner is
bevelled in the file itself, not with a clip-path — and a white card
pinned 8 px from its bottom right corner, three corners rounded and the fourth
square.
The only thing that moves is the button. On hover and on keyboard focus,
its label rises out of a one-line window while a copy arrives from below, and its
arrow leaves to the right while a copy enters from the left. Both last 350 ms
on cubic-bezier(.25,.46,.45,.94): those values were read from the
original's animation engine, not estimated.
Tuning it
Everything goes through CSS variables, at the top of
testimonial-hero.css. One of them rescales the whole thing:
--prh-font-size, which is the body size of the running text. The others
are overridden one at a time: --prh-fond, --prh-encre,
--prh-bouton-fond, --prh-carte-largeur,
--prh-duree, --prh-courbe, and
--prh-photo-ratio, which you change at the same time as the
photograph.
The narrow breakpoints are written with @container and not with
@media: the hero folds when its column is narrow, whatever the
window is doing. You can see it below.
The component has no JavaScript. The same page with
script-src 'none' shows it: nothing changes.