--color-action — see findings.
The LinkedIn icon renders because linkedinurl='#!' passes the
length > 1 guard (also see findings).
Content · 8 of 13
The attributed testimonial. It has no background of its own — only a 32px
backdrop-filter — so it is the one component that cannot be
judged on a plain surface.
| Prop | Type | Notes |
|---|---|---|
| item * | TestimonialCard | The six fields the component reads, declared in the component itself: photo.url, photo.name, name, position, review, linkedinurl, verification. A generated CMS entity satisfies it unchanged; the component carries no CMS schema. |
| resolveImage | (url: string) => string | Supplied by the caller for relative media URLs; omit it when they are already absolute. |
| className | string | Interpolated with no fallback — see findings. |
Shown over testimonials-background.svg, the plate named for
the section this card ships in. The blur is what separates the card from
the art behind it — there is nothing else doing that job.
One card on a canvas shows the blur; it does not show what the blur is for. Laid two-up over a single continuous plate, the art runs behind each card and out the other side, the alleys between them stay unblurred, and the falloff in the plate's opacity ladder puts every card on a slightly different ground — which is the case the component has to survive and the one a flat swatch cannot pose.
A sentinel filename controls rendering.
The avatar is gated on item.photo.name !== 'no-image.svg'. The
contract between CMS and component is a magic string: rename the placeholder
asset in the CMS and every testimonial sprouts a broken avatar. There is also
no guard on photo itself, so a testimonial with no photo
relation throws on photo.name rather than falling back.
linkedinurl.length > 1 is a truthiness test in disguise.
It guards against the empty string and a single character, not against an
invalid URL. Any one-character-plus value renders a live external link.
The same expression throws if linkedinurl is null rather than
empty.
The verification row fails contrast.
text-action on the site's #0A0A0B ground is 2.94:1, below the
4.5:1 floor for text this size (it was 3.03:1 against the pre-redesign
#050505 — the rebuild nudged it further down). It is also the trust signal on a
testimonial, so it is load-bearing copy. --color-hovered
(≈8.4:1) is the in-palette fix. Same shape as DESIGN.md §10.5.
className has no fallback.
The template interpolates ${className} directly, unlike
ArticlePreview's ${className ?? ''}. Omitting the prop puts the
literal string undefined into the class list. Harmless as a
class name, but it ships in the markup.
Judge it on art, never on flat color.
With no background of its own, previewing this card on #0A0A0B
makes the blur invisible and the design look unfinished. That is a preview
error, not a component defect.