@certrev/cert-block 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/render-cert-block.d.ts +6 -4
- package/dist/components/render-cert-block.d.ts.map +1 -1
- package/dist/components/render-cert-block.js +60 -36
- package/dist/components/render-cert-block.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/render-cert-block.test.ts.snap +6 -6
- package/src/__tests__/render-cert-block.test.ts +26 -3
- package/src/components/render-cert-block.ts +65 -44
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
* hooks on the ROOT element so the block is self-contained on a storefront that does
|
|
20
20
|
* NOT define the guide's `:root` — the accent (`--ba`), its auto-contrast ink
|
|
21
21
|
* (`--ba-fg`), the corner radius (`--br`), the body font (`--bf`) and surface
|
|
22
|
-
* (`--surface`) come from the resolved theme; the navy trust tints + the fixed
|
|
23
|
-
* label
|
|
24
|
-
* aesthetic").
|
|
25
|
-
*
|
|
22
|
+
* (`--surface`) come from the resolved theme; the navy trust tints + the fixed mono
|
|
23
|
+
* label font (`--font-mono`) are LOCKED literals (guide "the lock is legal, not
|
|
24
|
+
* aesthetic"). Names, the memo quote, disclosures, links, and the "CertREV" wordmark
|
|
25
|
+
* ride the body font; the serif/grotesk slots remain reachable only as a brand's
|
|
26
|
+
* themeable body-font choice. A brand themes accent / font / corners / surface, but
|
|
27
|
+
* the navy header bar + trust ink stay fixed (accent theming of the bar is Phase B).
|
|
26
28
|
*
|
|
27
29
|
* COMPLIANCE (LOCKED, non-negotiable): the three material disclosures always render
|
|
28
30
|
* on a CLAIM face (banner + sidebar) — the compensation cue, the byte-exact FTC
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-cert-block.d.ts","sourceRoot":"","sources":["../../src/components/render-cert-block.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"render-cert-block.d.ts","sourceRoot":"","sources":["../../src/components/render-cert-block.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH,OAAO,EAMN,KAAK,kBAAkB,EAEvB,MAAM,iBAAiB,CAAA;AAExB,wCAAwC;AACxC,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAA;AAE7D;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC9B,oDAAoD;IACpD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,qFAAqF;IACrF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,6EAA6E;IAC7E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,iFAAiF;IACjF,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAA;IACrC,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,oFAAoF;IACpF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,yEAAyE;IACzE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,wEAAwE;IACxE,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,yFAAyF;IACzF,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAChC;AAED,2CAA2C;AAC3C,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;IAC5B,+FAA+F;IAC/F,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAC5C,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;CAC9B;AAsTD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAWnE"}
|
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
* hooks on the ROOT element so the block is self-contained on a storefront that does
|
|
20
20
|
* NOT define the guide's `:root` — the accent (`--ba`), its auto-contrast ink
|
|
21
21
|
* (`--ba-fg`), the corner radius (`--br`), the body font (`--bf`) and surface
|
|
22
|
-
* (`--surface`) come from the resolved theme; the navy trust tints + the fixed
|
|
23
|
-
* label
|
|
24
|
-
* aesthetic").
|
|
25
|
-
*
|
|
22
|
+
* (`--surface`) come from the resolved theme; the navy trust tints + the fixed mono
|
|
23
|
+
* label font (`--font-mono`) are LOCKED literals (guide "the lock is legal, not
|
|
24
|
+
* aesthetic"). Names, the memo quote, disclosures, links, and the "CertREV" wordmark
|
|
25
|
+
* ride the body font; the serif/grotesk slots remain reachable only as a brand's
|
|
26
|
+
* themeable body-font choice. A brand themes accent / font / corners / surface, but
|
|
27
|
+
* the navy header bar + trust ink stay fixed (accent theming of the bar is Phase B).
|
|
26
28
|
*
|
|
27
29
|
* COMPLIANCE (LOCKED, non-negotiable): the three material disclosures always render
|
|
28
30
|
* on a CLAIM face (banner + sidebar) — the compensation cue, the byte-exact FTC
|
|
@@ -50,15 +52,13 @@ const LOGO_PATHS = [
|
|
|
50
52
|
'M310.21 335.2L294.54 319.54C287.23 312.22 287.23 300.36 294.54 293.04L315.88 271.71C323.2 264.39 335.06 264.39 342.38 271.71L358.04 287.37C365.36 294.69 365.36 306.55 358.04 313.87L336.71 335.2C329.39 342.52 317.53 342.52 310.21 335.2Z',
|
|
51
53
|
];
|
|
52
54
|
/**
|
|
53
|
-
* The 4-chevron CertREV mark at `size`px, filled `
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* ink on a light themed accent (so it never goes white-on-light). The memo credit
|
|
57
|
-
* passes the fixed navy `#0a1b3f` (it sits on the white surface).
|
|
55
|
+
* The 4-chevron CertREV mark at `size`px, always filled `currentColor` so it tracks
|
|
56
|
+
* its container's ink — white on the hardcoded-navy header, and the muted navy-55 of
|
|
57
|
+
* the memo footer's "Verified by CertREV" lockup (it sits on the white surface).
|
|
58
58
|
*/
|
|
59
|
-
function logo(size
|
|
59
|
+
function logo(size) {
|
|
60
60
|
return (`<svg viewBox="0 0 375 375" width="${size}" height="${size}" style="flex-shrink:0" aria-label="CertREV">` +
|
|
61
|
-
LOGO_PATHS.map((d) => `<path fill="
|
|
61
|
+
LOGO_PATHS.map((d) => `<path fill="currentColor" d="${d}"></path>`).join('') +
|
|
62
62
|
`</svg>`);
|
|
63
63
|
}
|
|
64
64
|
/** The bio-accordion caret (progressive-enhancement affordance). */
|
|
@@ -67,19 +67,30 @@ const CARET = `<span class="certrev-cert__caret" style="display:inline-flex;vert
|
|
|
67
67
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
68
68
|
// Small pure helpers
|
|
69
69
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
70
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Strip a leading honorific ("Dr. Jane Smith" → "Jane Smith") so the initials + first-name token don't
|
|
72
|
+
* capture it — matches the Liquid twin, which removes a matched honorific so "Dr. Marcus Ellison" yields
|
|
73
|
+
* the "ME" avatar + "Marcus's profile", never "DM" / "Dr.'s profile".
|
|
74
|
+
*/
|
|
75
|
+
function stripHonorific(name) {
|
|
76
|
+
return (name
|
|
77
|
+
.trim()
|
|
78
|
+
.replace(/^(dr|prof|professor|mr|mrs|ms|mx|rev|sir|dame)\.?\s+/i, '')
|
|
79
|
+
.trim() || name.trim());
|
|
80
|
+
}
|
|
81
|
+
/** "Jane Doe" → "JD"; "Dr. Marcus Ellison" → "ME" (first letter of the first two words, honorific stripped). */
|
|
71
82
|
function initials(name) {
|
|
72
|
-
const parts = name
|
|
83
|
+
const parts = stripHonorific(name).split(/\s+/).filter(Boolean);
|
|
73
84
|
const chars = parts
|
|
74
85
|
.slice(0, 2)
|
|
75
86
|
.map((p) => p[0] ?? '')
|
|
76
87
|
.join('');
|
|
77
88
|
return (chars || '?').toUpperCase();
|
|
78
89
|
}
|
|
79
|
-
/** The first name token (for "View Jane's profile"). */
|
|
90
|
+
/** The first name token (for "View Jane's profile") — honorific stripped. */
|
|
80
91
|
function firstNameOf(name) {
|
|
81
|
-
const
|
|
82
|
-
return
|
|
92
|
+
const clean = stripHonorific(name);
|
|
93
|
+
return clean.split(/\s+/)[0] || clean;
|
|
83
94
|
}
|
|
84
95
|
/**
|
|
85
96
|
* A LOCKED display string: use the caller's value ONLY when it is a non-blank
|
|
@@ -153,8 +164,6 @@ function rootStyle(theme) {
|
|
|
153
164
|
`--navy-75:rgba(10,27,63,.75)`,
|
|
154
165
|
`--stone:#ece9e1`,
|
|
155
166
|
`--font-mono:${RENDER_BLOCK_FONT_STACKS.mono}`,
|
|
156
|
-
`--font-serif:${RENDER_BLOCK_FONT_STACKS.serif}`,
|
|
157
|
-
`--font-wordmark:${RENDER_BLOCK_FONT_STACKS.grotesk}`,
|
|
158
167
|
`font-family:var(--bf)`,
|
|
159
168
|
`color:var(--navy)`,
|
|
160
169
|
].join(';');
|
|
@@ -172,31 +181,38 @@ function bannerHeaderCard(facts) {
|
|
|
172
181
|
const subtitle = facts.authorTitle
|
|
173
182
|
? `<div style="font-size:13px;color:var(--navy-55);">${escapeHtml(facts.authorTitle)}</div>`
|
|
174
183
|
: '';
|
|
184
|
+
// A subtle right-aligned arrow opens the certificate: the whole navy bar is the mouse
|
|
185
|
+
// target (data-certrev-modal-open); this focusable <a> is the keyboard / SR / no-JS control.
|
|
186
|
+
const certHref = safeHttpUrl(facts.certificateUrl) ?? '#';
|
|
187
|
+
const headerArrow = `<a href="${escapeAttribute(certHref)}" data-certrev-modal-open rel="noopener" aria-label="View certificate" ` +
|
|
188
|
+
`style="display:inline-flex;align-items:center;flex-shrink:0;color:inherit;opacity:.72;text-decoration:none;">` +
|
|
189
|
+
`<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path></svg></a>`;
|
|
175
190
|
return (`<div style="border:1px solid var(--navy-10);border-radius:calc(var(--br,14px) * 0.7);overflow:hidden;font-family:var(--bf);">` +
|
|
176
|
-
// navy header
|
|
177
|
-
`<div style="display:flex;align-items:center;justify-content:space-between;gap:16px;padding:15px 22px;background
|
|
178
|
-
`<span style="display:inline-flex;align-items:center;gap:11px;font-family:var(--font-mono);font-size:12px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;">${logo(20
|
|
191
|
+
// navy header — the trust bar stays fixed navy (accent theming is Phase B); mark + eyebrow + cert arrow
|
|
192
|
+
`<div data-certrev-modal-open style="display:flex;align-items:center;justify-content:space-between;gap:16px;padding:15px 22px;background:#0a1b3f;color:#fff;cursor:pointer;">` +
|
|
193
|
+
`<span style="display:inline-flex;align-items:center;gap:11px;font-family:var(--font-mono);font-size:12px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;">${logo(20)} Expert reviewed</span>` +
|
|
194
|
+
headerArrow +
|
|
179
195
|
`</div>` +
|
|
180
196
|
`<div style="padding:22px 24px 18px;">` +
|
|
181
197
|
`<div style="display:grid;grid-template-columns:1fr 1fr;gap:22px;">` +
|
|
182
|
-
// written by
|
|
198
|
+
// written by — muted label (navy-35)
|
|
183
199
|
`<div>` +
|
|
184
200
|
`<div style="font-family:var(--font-mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-35);margin-bottom:11px;">Written by</div>` +
|
|
185
201
|
`<div style="display:flex;align-items:center;gap:12px;">${avatar(initials(facts.authorName), 42, 12)}` +
|
|
186
202
|
`<div><div style="font-size:15px;font-weight:700;">${escapeHtml(facts.authorName)}</div>${subtitle}</div></div>` +
|
|
187
203
|
`</div>` +
|
|
188
|
-
// reviewed by
|
|
204
|
+
// reviewed by — emphasized label (navy, 700): the certification's authority voice
|
|
189
205
|
`<div>` +
|
|
190
|
-
`<div style="font-family:var(--font-mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--navy
|
|
206
|
+
`<div style="font-family:var(--font-mono);font-size:10px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--navy);margin-bottom:11px;">Reviewed by</div>` +
|
|
191
207
|
`<div class="certrev-cert__rev" role="button" tabindex="0" aria-expanded="false" data-certrev-bio-toggle aria-label="Read more about ${escapeAttribute(facts.reviewerName)}" style="display:flex;align-items:flex-start;gap:12px;cursor:pointer;border-radius:8px;transition:opacity .15s;">` +
|
|
192
208
|
`${avatar(initials(facts.reviewerName), 42, 12)}${verificationBlock(facts, true)}` +
|
|
193
209
|
`</div>` +
|
|
194
210
|
`</div>` +
|
|
195
211
|
`</div>` +
|
|
196
|
-
// hairline + mono footer
|
|
212
|
+
// hairline + mono footer — "Certified <date>" + "Compensated expert", UNIFORM navy-55
|
|
197
213
|
`<div style="height:1px;background:var(--navy-10);margin:16px 0 14px;"></div>` +
|
|
198
|
-
`<div style="display:flex;align-items:center;justify-content:space-between;gap:
|
|
199
|
-
`<span>Certified <span style="
|
|
214
|
+
`<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-55);">` +
|
|
215
|
+
`<span>Certified <span style="margin-left:8px;">${certified}</span></span>` +
|
|
200
216
|
`<span>${escapeHtml(compensationCue)}</span>` +
|
|
201
217
|
`</div>` +
|
|
202
218
|
`</div>` +
|
|
@@ -208,20 +224,28 @@ function bannerMemoCard(facts) {
|
|
|
208
224
|
? `<span style="color:var(--navy-55);">, ${escapeHtml(facts.credential)}</span>`
|
|
209
225
|
: '';
|
|
210
226
|
const first = firstNameOf(facts.reviewerName);
|
|
227
|
+
// The memo footer's profile/certificate actions read as the JetBrains-mono uppercase stamp
|
|
228
|
+
// that matches the badge footer lockup (Owen 2026-07-17) — navy, so they still read as actions.
|
|
229
|
+
const stampLink = 'font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy);text-decoration:none;cursor:pointer;';
|
|
211
230
|
return (`<div style="border:1px solid var(--navy-10);border-radius:calc(var(--br,14px) * 0.7);padding:24px;font-family:var(--bf);">` +
|
|
212
231
|
`<div style="font-family:var(--font-mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--navy-55);margin-bottom:14px;">Expert memo</div>` +
|
|
213
232
|
`<div style="display:flex;gap:15px;">${avatar(initials(facts.reviewerName), 46, 13)}` +
|
|
214
233
|
`<div style="flex:1;min-width:0;">` +
|
|
215
|
-
`<div style="font-size:16px;
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
certificateLink(facts.certificateUrl, 'View certificate', 'font-size:14px;font-weight:700;color:var(--navy);text-decoration:none;cursor:pointer;') +
|
|
220
|
-
`</div>` +
|
|
234
|
+
`<div style="font-size:16px;line-height:1.2;"><span style="font-weight:700;">${escapeHtml(facts.reviewerName)}</span>${credTail}</div>` +
|
|
235
|
+
// Readable, UPRIGHT DM Sans quote (Owen 2026-07-17: the display-serif italic hurt legibility);
|
|
236
|
+
// pre-line preserves the reviewer's paragraph breaks. No left accent bar (matches the guide).
|
|
237
|
+
`<p style="margin:11px 0 14px;font-size:15.5px;line-height:1.6;color:var(--navy-75);white-space:pre-line;">${escapeHtml(facts.memo)}</p>` +
|
|
221
238
|
`</div>` +
|
|
222
239
|
`</div>` +
|
|
240
|
+
// footer hairline + one trust row: "Verified by CertREV" left, the two actions right
|
|
223
241
|
`<div style="height:1px;background:var(--navy-10);margin:18px 0 14px;"></div>` +
|
|
224
|
-
`<div style="display:
|
|
242
|
+
`<div style="display:flex;align-items:center;justify-content:space-between;gap:16px 22px;flex-wrap:wrap;">` +
|
|
243
|
+
`<div style="display:inline-flex;align-items:center;gap:9px;font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-55);">${logo(15)}<span>Verified by <span style="font-weight:700;color:var(--navy);">CertREV</span></span></div>` +
|
|
244
|
+
`<div style="display:flex;flex-wrap:wrap;gap:22px;">` +
|
|
245
|
+
profileLink(facts.profileUrl, `View ${escapeHtml(first)}'s profile`, stampLink) +
|
|
246
|
+
certificateLink(facts.certificateUrl, 'View certificate', stampLink) +
|
|
247
|
+
`</div>` +
|
|
248
|
+
`</div>` +
|
|
225
249
|
`<div style="font-size:13px;color:var(--navy-55);margin-top:8px;line-height:1.5;">${escapeHtml(scopeLine)}</div>` +
|
|
226
250
|
`</div>`);
|
|
227
251
|
}
|
|
@@ -235,11 +259,11 @@ function sidebarCard(facts) {
|
|
|
235
259
|
? `<p style="font-size:14px;line-height:1.55;color:var(--navy-75);margin:16px 0 0;">${escapeHtml(facts.bio)}</p>`
|
|
236
260
|
: '';
|
|
237
261
|
return (`<div style="background:var(--surface);border:1px solid var(--navy-10);border-radius:var(--br,14px);overflow:hidden;box-shadow:0 4px 18px var(--navy-06);font-family:var(--bf);">` +
|
|
238
|
-
`<div style="display:flex;align-items:center;justify-content:center;gap:10px;padding:12px;background
|
|
262
|
+
`<div style="display:flex;align-items:center;justify-content:center;gap:10px;padding:12px;background:#0a1b3f;color:#fff;font-family:var(--font-mono);font-size:12px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;">${logo(18)} Expert reviewed</div>` +
|
|
239
263
|
`<div style="padding:20px;">` +
|
|
240
264
|
`<div style="display:flex;align-items:flex-start;gap:13px;">${avatar(initials(facts.reviewerName), 46, 13)}${verificationBlock(facts, false)}</div>` +
|
|
241
265
|
bioPara +
|
|
242
|
-
`<blockquote style="margin:16px 0 0;padding-left:16px;border-left:3px solid var(--ba,#0a1b3f);font-
|
|
266
|
+
`<blockquote style="margin:16px 0 0;padding-left:16px;border-left:3px solid var(--ba,#0a1b3f);font-size:15px;line-height:1.5;color:var(--navy-75);white-space:pre-line;">${escapeHtml(facts.memo)}</blockquote>` +
|
|
243
267
|
`<div style="font-size:12.5px;line-height:1.5;color:var(--navy-55);margin-top:16px;"><span style="font-family:var(--font-mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;">${escapeHtml(compensationCue)}</span> · ${escapeHtml(scopeLine)}</div>` +
|
|
244
268
|
`</div>` +
|
|
245
269
|
`<div style="display:grid;grid-template-columns:1fr 1fr;border-top:1px solid var(--navy-10);">` +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-cert-block.js","sourceRoot":"","sources":["../../src/components/render-cert-block.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"render-cert-block.js","sourceRoot":"","sources":["../../src/components/render-cert-block.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACN,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,+BAA+B,EAC/B,wBAAwB,EAExB,iBAAiB,GACjB,MAAM,iBAAiB,CAAA;AAgDxB,gFAAgF;AAChF,mFAAmF;AACnF,sFAAsF;AACtF,gFAAgF;AAEhF,MAAM,UAAU,GAAG;IAClB,gOAAgO;IAChO,6NAA6N;IAC7N,yOAAyO;IACzO,6OAA6O;CAC7O,CAAA;AAED;;;;GAIG;AACH,SAAS,IAAI,CAAC,IAAY;IACzB,OAAO,CACN,qCAAqC,IAAI,aAAa,IAAI,+CAA+C;QACzG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gCAAgC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5E,QAAQ,CACR,CAAA;AACF,CAAC;AAED,oEAAoE;AACpE,MAAM,KAAK,GACV,+JAA+J;IAC/J,oNAAoN,CAAA;AAErN,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF;;;;GAIG;AACH,SAAS,cAAc,CAAC,IAAY;IACnC,OAAO,CACN,IAAI;SACF,IAAI,EAAE;SACN,OAAO,CAAC,uDAAuD,EAAE,EAAE,CAAC;SACpE,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,CACvB,CAAA;AACF,CAAC;AAED,gHAAgH;AAChH,SAAS,QAAQ,CAAC,IAAY;IAC7B,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC/D,MAAM,KAAK,GAAG,KAAK;SACjB,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACtB,IAAI,CAAC,EAAE,CAAC,CAAA;IACV,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;AACpC,CAAC;AAED,6EAA6E;AAC7E,SAAS,WAAW,CAAC,IAAY;IAChC,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;IAClC,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAA;AACtC,CAAC;AAED;;;;;GAKG;AACH,SAAS,MAAM,CAAC,QAA4B,EAAE,QAAgB;IAC7D,OAAO,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAA;AAC9C,CAAC;AAED,mDAAmD;AACnD,SAAS,MAAM,CAAC,IAAY,EAAE,IAAY,EAAE,QAAgB;IAC3D,OAAO,CACN,qBAAqB,IAAI,aAAa,IAAI,oEAAoE;QAC9G,iHAAiH,QAAQ,qBAAqB;QAC9I,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAC3B,CAAA;AACF,CAAC;AAED,+EAA+E;AAC/E,SAAS,kBAAkB,CAAC,IAAY,EAAE,UAAkB;IAC3D,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;IAC1B,OAAO,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;AAC1D,CAAC;AAED,0FAA0F;AAC1F,SAAS,WAAW,CAAC,GAAW,EAAE,KAAa,EAAE,KAAa;IAC7D,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,CAAA;IACpC,OAAO,YAAY,eAAe,CAAC,IAAI,CAAC,4DAA4D,KAAK,KAAK,KAAK,MAAM,CAAA;AAC1H,CAAC;AAED,4EAA4E;AAC5E,SAAS,eAAe,CAAC,GAAW,EAAE,KAAa,EAAE,KAAa;IACjE,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,CAAA;IACpC,OAAO,YAAY,eAAe,CAAC,IAAI,CAAC,mDAAmD,KAAK,KAAK,KAAK,MAAM,CAAA;AACjH,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,KAAqB,EAAE,aAAsB;IACvE,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,+BAA+B,CAAC,CAAA;IACpF,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAA;IACjG,MAAM,KAAK,GAAG,aAAa,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IACrD,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAA;IAChD,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAA;IAClD,MAAM,GAAG,GACR,aAAa,IAAI,KAAK,CAAC,GAAG;QACzB,CAAC,CAAC,oIAAoI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ;QACnK,CAAC,CAAC,EAAE,CAAA;IACN,OAAO,CACN,OAAO;QACP,yBAAyB,QAAQ,sBAAsB,kBAAkB,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,GAAG,KAAK,QAAQ;QAC/H,yBAAyB,QAAQ,2DAA2D,UAAU,CAAC,cAAc,CAAC,QAAQ;QAC9H,yBAAyB,QAAQ,+CAA+C,QAAQ,QAAQ;QAChG,GAAG;QACH,QAAQ,CACR,CAAA;AACF,CAAC;AAED,gFAAgF;AAChF,8EAA8E;AAC9E,gFAAgF;AAEhF,SAAS,SAAS,CAAC,KAAyB;IAC3C,iFAAiF;IACjF,8EAA8E;IAC9E,kDAAkD;IAClD,OAAO;QACN,QAAQ,KAAK,CAAC,WAAW,EAAE;QAC3B,WAAW,KAAK,CAAC,QAAQ,EAAE;QAC3B,QAAQ,KAAK,CAAC,YAAY,EAAE;QAC5B,QAAQ,wBAAwB,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;QAClD,aAAa,KAAK,CAAC,OAAO,EAAE;QAC5B,gBAAgB;QAChB,8BAA8B;QAC9B,8BAA8B;QAC9B,8BAA8B;QAC9B,8BAA8B;QAC9B,8BAA8B;QAC9B,iBAAiB;QACjB,eAAe,wBAAwB,CAAC,IAAI,EAAE;QAC9C,uBAAuB;QACvB,mBAAmB;KACnB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACZ,CAAC;AAED,SAAS,IAAI,CAAC,IAAmB,EAAE,KAAyB,EAAE,KAAa;IAC1E,OAAO,CACN,0CAA0C,IAAI,wBAAwB,IAAI,IAAI;QAC9E,iCAAiC,oBAAoB,YAAY,SAAS,CAAC,KAAK,CAAC,KAAK,KAAK,QAAQ,CACnG,CAAA;AACF,CAAC;AAED,gFAAgF;AAChF,6EAA6E;AAC7E,gFAAgF;AAEhF,SAAS,gBAAgB,CAAC,KAAqB;IAC9C,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,sBAAsB,CAAC,CAAA;IAC7E,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IAChF,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW;QACjC,CAAC,CAAC,qDAAqD,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ;QAC5F,CAAC,CAAC,EAAE,CAAA;IACL,sFAAsF;IACtF,6FAA6F;IAC7F,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,GAAG,CAAA;IACzD,MAAM,WAAW,GAChB,YAAY,eAAe,CAAC,QAAQ,CAAC,yEAAyE;QAC9G,+GAA+G;QAC/G,4OAA4O,CAAA;IAC7O,OAAO,CACN,+HAA+H;QAC/H,wGAAwG;QACxG,8KAA8K;QAC9K,4KAA4K,IAAI,CAAC,EAAE,CAAC,yBAAyB;QAC7M,WAAW;QACX,QAAQ;QACR,uCAAuC;QACvC,oEAAoE;QACpE,qCAAqC;QACrC,OAAO;QACP,kKAAkK;QAClK,0DAA0D,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE;QACtG,qDAAqD,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,QAAQ,cAAc;QAChH,QAAQ;QACR,kFAAkF;QAClF,OAAO;QACP,gLAAgL;QAChL,uIAAuI,eAAe,CAAC,KAAK,CAAC,YAAY,CAAC,mHAAmH;QAC7R,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE;QAClF,QAAQ;QACR,QAAQ;QACR,QAAQ;QACR,sFAAsF;QACtF,8EAA8E;QAC9E,uOAAuO;QACvO,kDAAkD,SAAS,gBAAgB;QAC3E,SAAS,UAAU,CAAC,eAAe,CAAC,SAAS;QAC7C,QAAQ;QACR,QAAQ;QACR,QAAQ,CACR,CAAA;AACF,CAAC;AAED,SAAS,cAAc,CAAC,KAAqB;IAC5C,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;IAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU;QAChC,CAAC,CAAC,yCAAyC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS;QAChF,CAAC,CAAC,EAAE,CAAA;IACL,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;IAC7C,2FAA2F;IAC3F,gGAAgG;IAChG,MAAM,SAAS,GACd,oKAAoK,CAAA;IACrK,OAAO,CACN,4HAA4H;QAC5H,mKAAmK;QACnK,uCAAuC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE;QACrF,mCAAmC;QACnC,+EAA+E,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,QAAQ,QAAQ;QACvI,+FAA+F;QAC/F,8FAA8F;QAC9F,6GAA6G,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM;QACzI,QAAQ;QACR,QAAQ;QACR,qFAAqF;QACrF,8EAA8E;QAC9E,2GAA2G;QAC3G,iMAAiM,IAAI,CAAC,EAAE,CAAC,gGAAgG;QACzS,qDAAqD;QACrD,WAAW,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,UAAU,CAAC,KAAK,CAAC,YAAY,EAAE,SAAS,CAAC;QAC/E,eAAe,CAAC,KAAK,CAAC,cAAc,EAAE,kBAAkB,EAAE,SAAS,CAAC;QACpE,QAAQ;QACR,QAAQ;QACR,oFAAoF,UAAU,CAAC,SAAS,CAAC,QAAQ;QACjH,QAAQ,CACR,CAAA;AACF,CAAC;AAED,gFAAgF;AAChF,mEAAmE;AACnE,gFAAgF;AAEhF,SAAS,WAAW,CAAC,KAAqB;IACzC,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,sBAAsB,CAAC,CAAA;IAC7E,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;IAC1D,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG;QACxB,CAAC,CAAC,oFAAoF,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM;QACjH,CAAC,CAAC,EAAE,CAAA;IACL,OAAO,CACN,kLAAkL;QAClL,sOAAsO,IAAI,CAAC,EAAE,CAAC,wBAAwB;QACtQ,6BAA6B;QAC7B,8DAA8D,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ;QACpJ,OAAO;QACP,2KAA2K,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe;QAChN,+LAA+L,UAAU,CAAC,eAAe,CAAC,aAAa,UAAU,CAAC,SAAS,CAAC,QAAQ;QACpQ,QAAQ;QACR,+FAA+F;QAC/F,WAAW,CACV,KAAK,CAAC,UAAU,EAChB,cAAc,EACd,4JAA4J,CAC5J;QACD,eAAe,CACd,KAAK,CAAC,cAAc,EACpB,kBAAkB,EAClB,sHAAsH,CACtH;QACD,QAAQ;QACR,QAAQ,CACR,CAAA;AACF,CAAC;AAED,gFAAgF;AAChF,+EAA+E;AAC/E,gFAAgF;AAEhF,SAAS,YAAY,CAAC,KAAqB;IAC1C,OAAO,CACN,4NAA4N;QAC5N,8JAA8J;QAC9J,WAAW,CACV,KAAK,CAAC,UAAU,EAChB,SAAS,EACT,kHAAkH,CAClH;QACD,oCAAoC;QACpC,eAAe,CACd,KAAK,CAAC,cAAc,EACpB,aAAa,EACb,kHAAkH,CAClH;QACD,QAAQ,CACR,CAAA;AACF,CAAC;AAED,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAA2B;IAC1D,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC5C,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;IAC7B,QAAQ,IAAI,EAAE,CAAC;QACd,KAAK,QAAQ;YACZ,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,CAAA;QAC1E,KAAK,SAAS;YACb,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAA;QAC7C,KAAK,UAAU;YACd,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAA;IAC/C,CAAC;AACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@certrev/cert-block",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Headless / crypto_verify render edge for the CertREV CertDeliveryEnvelope. SSR-safe React components (<CertBadge>/<ExpertBio>/<CertRevBacklink>), a deterministic schema.org JSON-LD projector, a fail-closed verify layer over the shared VerdictKernel, and a framework-agnostic <certrev-badge> Web Component. Sign once (portal), render everywhere (Hydrogen / Next / Builder / universal embed).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
|
-
exports[`renderCertBlock — locked-design snapshots > banner (navy default) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--banner" data-certrev-mode="banner" data-certrev-strings-version="2026-07" style="--ba:#0a1b3f;--ba-fg:#ffffff;--br:14px;--bf:'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;--surface:#ffffff;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace
|
|
3
|
+
exports[`renderCertBlock — locked-design snapshots > banner (navy default) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--banner" data-certrev-mode="banner" data-certrev-strings-version="2026-07" style="--ba:#0a1b3f;--ba-fg:#ffffff;--br:14px;--bf:'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;--surface:#ffffff;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;font-family:var(--bf);color:var(--navy)"><div style="border:1px solid var(--navy-10);border-radius:calc(var(--br,14px) * 0.7);overflow:hidden;font-family:var(--bf);"><div data-certrev-modal-open style="display:flex;align-items:center;justify-content:space-between;gap:16px;padding:15px 22px;background:#0a1b3f;color:#fff;cursor:pointer;"><span style="display:inline-flex;align-items:center;gap:11px;font-family:var(--font-mono);font-size:12px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;"><svg viewBox="0 0 375 375" width="20" height="20" style="flex-shrink:0" aria-label="CertREV"><path fill="currentColor" d="M67.59 221.77L138.77 292.95C145.8 299.98 145.8 311.44 138.77 318.47L123.02 334.22C116 341.25 104.54 341.25 97.5 334.22L26.32 263.04C19.29 256.01 19.29 244.55 26.32 237.52L42.07 221.77C49.1 214.74 60.56 214.74 67.59 221.77Z"></path><path fill="currentColor" d="M96.79 335.08L81.12 319.42C73.8 312.1 73.8 300.23 81.12 292.92L315.88 58.16C323.2 50.85 335.06 50.85 342.38 58.16L358.04 73.83C365.36 81.14 365.36 93.01 358.04 100.33L123.29 335.08C115.97 342.4 104.1 342.4 96.79 335.08Z"></path><path fill="currentColor" d="M203.5 335.14L187.83 319.48C180.52 312.16 180.52 300.29 187.83 292.98L315.88 164.93C323.2 157.62 335.06 157.62 342.38 164.93L358.04 180.6C365.36 187.92 365.36 199.78 358.04 207.1L230 335.14C222.68 342.46 210.82 342.46 203.5 335.14Z"></path><path fill="currentColor" d="M310.21 335.2L294.54 319.54C287.23 312.22 287.23 300.36 294.54 293.04L315.88 271.71C323.2 264.39 335.06 264.39 342.38 271.71L358.04 287.37C365.36 294.69 365.36 306.55 358.04 313.87L336.71 335.2C329.39 342.52 317.53 342.52 310.21 335.2Z"></path></svg> Expert reviewed</span><a href="https://certrev.com/verify/sample" data-certrev-modal-open rel="noopener" aria-label="View certificate" style="display:inline-flex;align-items:center;flex-shrink:0;color:inherit;opacity:.72;text-decoration:none;"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path></svg></a></div><div style="padding:22px 24px 18px;"><div style="display:grid;grid-template-columns:1fr 1fr;gap:22px;"><div><div style="font-family:var(--font-mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-35);margin-bottom:11px;">Written by</div><div style="display:flex;align-items:center;gap:12px;"><div style="width:42px;height:42px;border-radius:50%;background:var(--stone);color:var(--navy-55);display:flex;align-items:center;justify-content:center;font-family:var(--font-mono);font-weight:700;font-size:12px;flex-shrink:0;">TE</div><div><div style="font-size:15px;font-weight:700;">The Editorial Team</div><div style="font-size:13px;color:var(--navy-55);">Editorial</div></div></div></div><div><div style="font-family:var(--font-mono);font-size:10px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--navy);margin-bottom:11px;">Reviewed by</div><div class="certrev-cert__rev" role="button" tabindex="0" aria-expanded="false" data-certrev-bio-toggle aria-label="Read more about Jane Doe" style="display:flex;align-items:flex-start;gap:12px;cursor:pointer;border-radius:8px;transition:opacity .15s;"><div style="width:42px;height:42px;border-radius:50%;background:var(--stone);color:var(--navy-55);display:flex;align-items:center;justify-content:center;font-family:var(--font-mono);font-weight:700;font-size:12px;flex-shrink:0;">JD</div><div><div style="font-size:15px;font-weight:700;">Jane Doe, MD<span class="certrev-cert__caret" style="display:inline-flex;vertical-align:middle;margin-left:4px;color:var(--navy-35);transition:transform .18s ease-out;"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg></span></div><div style="font-size:13px;color:var(--navy-55);line-height:1.45;margin-top:3px;">Credential verified by CertREV</div><div style="font-size:13px;color:var(--navy-55);line-height:1.35;">on Apr 14, 2026</div><div class="certrev-cert__bio" hidden style="display:none;margin-top:8px;font-size:12.5px;line-height:1.5;color:var(--navy-75);">Board-certified dermatologist in San Francisco specializing in photoprotection, skin-cancer prevention, and evidence-based skincare, with fifteen years of clinical practice.</div></div></div></div></div><div style="height:1px;background:var(--navy-10);margin:16px 0 14px;"></div><div style="display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-55);"><span>Certified <span style="margin-left:8px;">Apr 14, 2026</span></span><span>Compensated expert</span></div></div></div><div style="border:1px solid var(--navy-10);border-radius:calc(var(--br,14px) * 0.7);padding:24px;font-family:var(--bf);"><div style="font-family:var(--font-mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--navy-55);margin-bottom:14px;">Expert memo</div><div style="display:flex;gap:15px;"><div style="width:46px;height:46px;border-radius:50%;background:var(--stone);color:var(--navy-55);display:flex;align-items:center;justify-content:center;font-family:var(--font-mono);font-weight:700;font-size:13px;flex-shrink:0;">JD</div><div style="flex:1;min-width:0;"><div style="font-size:16px;line-height:1.2;"><span style="font-weight:700;">Jane Doe</span><span style="color:var(--navy-55);">, MD</span></div><p style="margin:11px 0 14px;font-size:15.5px;line-height:1.6;color:var(--navy-75);white-space:pre-line;">Patients ask me almost every week whether the SPF in their foundation is enough on its own. Treat makeup with SPF as a helpful last layer, not the base of your routine.</p></div></div><div style="height:1px;background:var(--navy-10);margin:18px 0 14px;"></div><div style="display:flex;align-items:center;justify-content:space-between;gap:16px 22px;flex-wrap:wrap;"><div style="display:inline-flex;align-items:center;gap:9px;font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-55);"><svg viewBox="0 0 375 375" width="15" height="15" style="flex-shrink:0" aria-label="CertREV"><path fill="currentColor" d="M67.59 221.77L138.77 292.95C145.8 299.98 145.8 311.44 138.77 318.47L123.02 334.22C116 341.25 104.54 341.25 97.5 334.22L26.32 263.04C19.29 256.01 19.29 244.55 26.32 237.52L42.07 221.77C49.1 214.74 60.56 214.74 67.59 221.77Z"></path><path fill="currentColor" d="M96.79 335.08L81.12 319.42C73.8 312.1 73.8 300.23 81.12 292.92L315.88 58.16C323.2 50.85 335.06 50.85 342.38 58.16L358.04 73.83C365.36 81.14 365.36 93.01 358.04 100.33L123.29 335.08C115.97 342.4 104.1 342.4 96.79 335.08Z"></path><path fill="currentColor" d="M203.5 335.14L187.83 319.48C180.52 312.16 180.52 300.29 187.83 292.98L315.88 164.93C323.2 157.62 335.06 157.62 342.38 164.93L358.04 180.6C365.36 187.92 365.36 199.78 358.04 207.1L230 335.14C222.68 342.46 210.82 342.46 203.5 335.14Z"></path><path fill="currentColor" d="M310.21 335.2L294.54 319.54C287.23 312.22 287.23 300.36 294.54 293.04L315.88 271.71C323.2 264.39 335.06 264.39 342.38 271.71L358.04 287.37C365.36 294.69 365.36 306.55 358.04 313.87L336.71 335.2C329.39 342.52 317.53 342.52 310.21 335.2Z"></path></svg><span>Verified by <span style="font-weight:700;color:var(--navy);">CertREV</span></span></div><div style="display:flex;flex-wrap:wrap;gap:22px;"><a href="https://certrev.com/expert/sample" data-certrev-modal-open="expert" rel="noopener" style="font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy);text-decoration:none;cursor:pointer;">View Jane's profile</a><a href="https://certrev.com/verify/sample" data-certrev-modal-open rel="noopener" style="font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy);text-decoration:none;cursor:pointer;">View certificate</a></div></div><div style="font-size:13px;color:var(--navy-55);margin-top:8px;line-height:1.5;">Independent editorial review of this article’s text and sources. Not a product endorsement, nor medical advice.</div></div></div>"`;
|
|
4
4
|
|
|
5
|
-
exports[`renderCertBlock — locked-design snapshots > banner (themed, non-navy accent) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--banner" data-certrev-mode="banner" data-certrev-strings-version="2026-07" style="--ba:#E8603C;--ba-fg:#141414;--br:22px;--bf:'Plus Jakarta Sans', system-ui, Helvetica, Arial, sans-serif;--surface:#faf8f4;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace
|
|
5
|
+
exports[`renderCertBlock — locked-design snapshots > banner (themed, non-navy accent) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--banner" data-certrev-mode="banner" data-certrev-strings-version="2026-07" style="--ba:#E8603C;--ba-fg:#141414;--br:22px;--bf:'Plus Jakarta Sans', system-ui, Helvetica, Arial, sans-serif;--surface:#faf8f4;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;font-family:var(--bf);color:var(--navy)"><div style="border:1px solid var(--navy-10);border-radius:calc(var(--br,14px) * 0.7);overflow:hidden;font-family:var(--bf);"><div data-certrev-modal-open style="display:flex;align-items:center;justify-content:space-between;gap:16px;padding:15px 22px;background:#0a1b3f;color:#fff;cursor:pointer;"><span style="display:inline-flex;align-items:center;gap:11px;font-family:var(--font-mono);font-size:12px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;"><svg viewBox="0 0 375 375" width="20" height="20" style="flex-shrink:0" aria-label="CertREV"><path fill="currentColor" d="M67.59 221.77L138.77 292.95C145.8 299.98 145.8 311.44 138.77 318.47L123.02 334.22C116 341.25 104.54 341.25 97.5 334.22L26.32 263.04C19.29 256.01 19.29 244.55 26.32 237.52L42.07 221.77C49.1 214.74 60.56 214.74 67.59 221.77Z"></path><path fill="currentColor" d="M96.79 335.08L81.12 319.42C73.8 312.1 73.8 300.23 81.12 292.92L315.88 58.16C323.2 50.85 335.06 50.85 342.38 58.16L358.04 73.83C365.36 81.14 365.36 93.01 358.04 100.33L123.29 335.08C115.97 342.4 104.1 342.4 96.79 335.08Z"></path><path fill="currentColor" d="M203.5 335.14L187.83 319.48C180.52 312.16 180.52 300.29 187.83 292.98L315.88 164.93C323.2 157.62 335.06 157.62 342.38 164.93L358.04 180.6C365.36 187.92 365.36 199.78 358.04 207.1L230 335.14C222.68 342.46 210.82 342.46 203.5 335.14Z"></path><path fill="currentColor" d="M310.21 335.2L294.54 319.54C287.23 312.22 287.23 300.36 294.54 293.04L315.88 271.71C323.2 264.39 335.06 264.39 342.38 271.71L358.04 287.37C365.36 294.69 365.36 306.55 358.04 313.87L336.71 335.2C329.39 342.52 317.53 342.52 310.21 335.2Z"></path></svg> Expert reviewed</span><a href="https://certrev.com/verify/sample" data-certrev-modal-open rel="noopener" aria-label="View certificate" style="display:inline-flex;align-items:center;flex-shrink:0;color:inherit;opacity:.72;text-decoration:none;"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path></svg></a></div><div style="padding:22px 24px 18px;"><div style="display:grid;grid-template-columns:1fr 1fr;gap:22px;"><div><div style="font-family:var(--font-mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-35);margin-bottom:11px;">Written by</div><div style="display:flex;align-items:center;gap:12px;"><div style="width:42px;height:42px;border-radius:50%;background:var(--stone);color:var(--navy-55);display:flex;align-items:center;justify-content:center;font-family:var(--font-mono);font-weight:700;font-size:12px;flex-shrink:0;">TE</div><div><div style="font-size:15px;font-weight:700;">The Editorial Team</div><div style="font-size:13px;color:var(--navy-55);">Editorial</div></div></div></div><div><div style="font-family:var(--font-mono);font-size:10px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--navy);margin-bottom:11px;">Reviewed by</div><div class="certrev-cert__rev" role="button" tabindex="0" aria-expanded="false" data-certrev-bio-toggle aria-label="Read more about Jane Doe" style="display:flex;align-items:flex-start;gap:12px;cursor:pointer;border-radius:8px;transition:opacity .15s;"><div style="width:42px;height:42px;border-radius:50%;background:var(--stone);color:var(--navy-55);display:flex;align-items:center;justify-content:center;font-family:var(--font-mono);font-weight:700;font-size:12px;flex-shrink:0;">JD</div><div><div style="font-size:15px;font-weight:700;">Jane Doe, MD<span class="certrev-cert__caret" style="display:inline-flex;vertical-align:middle;margin-left:4px;color:var(--navy-35);transition:transform .18s ease-out;"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg></span></div><div style="font-size:13px;color:var(--navy-55);line-height:1.45;margin-top:3px;">Credential verified by CertREV</div><div style="font-size:13px;color:var(--navy-55);line-height:1.35;">on Apr 14, 2026</div><div class="certrev-cert__bio" hidden style="display:none;margin-top:8px;font-size:12.5px;line-height:1.5;color:var(--navy-75);">Board-certified dermatologist in San Francisco specializing in photoprotection, skin-cancer prevention, and evidence-based skincare, with fifteen years of clinical practice.</div></div></div></div></div><div style="height:1px;background:var(--navy-10);margin:16px 0 14px;"></div><div style="display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-55);"><span>Certified <span style="margin-left:8px;">Apr 14, 2026</span></span><span>Compensated expert</span></div></div></div><div style="border:1px solid var(--navy-10);border-radius:calc(var(--br,14px) * 0.7);padding:24px;font-family:var(--bf);"><div style="font-family:var(--font-mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--navy-55);margin-bottom:14px;">Expert memo</div><div style="display:flex;gap:15px;"><div style="width:46px;height:46px;border-radius:50%;background:var(--stone);color:var(--navy-55);display:flex;align-items:center;justify-content:center;font-family:var(--font-mono);font-weight:700;font-size:13px;flex-shrink:0;">JD</div><div style="flex:1;min-width:0;"><div style="font-size:16px;line-height:1.2;"><span style="font-weight:700;">Jane Doe</span><span style="color:var(--navy-55);">, MD</span></div><p style="margin:11px 0 14px;font-size:15.5px;line-height:1.6;color:var(--navy-75);white-space:pre-line;">Patients ask me almost every week whether the SPF in their foundation is enough on its own. Treat makeup with SPF as a helpful last layer, not the base of your routine.</p></div></div><div style="height:1px;background:var(--navy-10);margin:18px 0 14px;"></div><div style="display:flex;align-items:center;justify-content:space-between;gap:16px 22px;flex-wrap:wrap;"><div style="display:inline-flex;align-items:center;gap:9px;font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-55);"><svg viewBox="0 0 375 375" width="15" height="15" style="flex-shrink:0" aria-label="CertREV"><path fill="currentColor" d="M67.59 221.77L138.77 292.95C145.8 299.98 145.8 311.44 138.77 318.47L123.02 334.22C116 341.25 104.54 341.25 97.5 334.22L26.32 263.04C19.29 256.01 19.29 244.55 26.32 237.52L42.07 221.77C49.1 214.74 60.56 214.74 67.59 221.77Z"></path><path fill="currentColor" d="M96.79 335.08L81.12 319.42C73.8 312.1 73.8 300.23 81.12 292.92L315.88 58.16C323.2 50.85 335.06 50.85 342.38 58.16L358.04 73.83C365.36 81.14 365.36 93.01 358.04 100.33L123.29 335.08C115.97 342.4 104.1 342.4 96.79 335.08Z"></path><path fill="currentColor" d="M203.5 335.14L187.83 319.48C180.52 312.16 180.52 300.29 187.83 292.98L315.88 164.93C323.2 157.62 335.06 157.62 342.38 164.93L358.04 180.6C365.36 187.92 365.36 199.78 358.04 207.1L230 335.14C222.68 342.46 210.82 342.46 203.5 335.14Z"></path><path fill="currentColor" d="M310.21 335.2L294.54 319.54C287.23 312.22 287.23 300.36 294.54 293.04L315.88 271.71C323.2 264.39 335.06 264.39 342.38 271.71L358.04 287.37C365.36 294.69 365.36 306.55 358.04 313.87L336.71 335.2C329.39 342.52 317.53 342.52 310.21 335.2Z"></path></svg><span>Verified by <span style="font-weight:700;color:var(--navy);">CertREV</span></span></div><div style="display:flex;flex-wrap:wrap;gap:22px;"><a href="https://certrev.com/expert/sample" data-certrev-modal-open="expert" rel="noopener" style="font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy);text-decoration:none;cursor:pointer;">View Jane's profile</a><a href="https://certrev.com/verify/sample" data-certrev-modal-open rel="noopener" style="font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy);text-decoration:none;cursor:pointer;">View certificate</a></div></div><div style="font-size:13px;color:var(--navy-55);margin-top:8px;line-height:1.5;">Independent editorial review of this article’s text and sources. Not a product endorsement, nor medical advice.</div></div></div>"`;
|
|
6
6
|
|
|
7
|
-
exports[`renderCertBlock — locked-design snapshots > floating (navy default) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--floating" data-certrev-mode="floating" data-certrev-strings-version="2026-07" style="--ba:#0a1b3f;--ba-fg:#ffffff;--br:14px;--bf:'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;--surface:#ffffff;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace
|
|
7
|
+
exports[`renderCertBlock — locked-design snapshots > floating (navy default) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--floating" data-certrev-mode="floating" data-certrev-strings-version="2026-07" style="--ba:#0a1b3f;--ba-fg:#ffffff;--br:14px;--bf:'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;--surface:#ffffff;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;font-family:var(--bf);color:var(--navy)"><div class="certrev-cert__pill" style="display:inline-flex;align-items:center;gap:14px;padding:12px 22px;border-radius:999px;background:var(--ba,#0a1b3f);color:var(--ba-fg,#fff);box-shadow:0 10px 26px var(--navy-10);"><span style="font-family:var(--font-mono);font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;opacity:.75;">Expert reviewed:</span><a href="https://certrev.com/expert/sample" data-certrev-modal-open="expert" rel="noopener" style="font-size:14px;font-weight:700;text-decoration:underline;text-underline-offset:3px;color:inherit;cursor:pointer;">Profile</a><span style="opacity:.5;">·</span><a href="https://certrev.com/verify/sample" data-certrev-modal-open rel="noopener" style="font-size:14px;font-weight:700;text-decoration:underline;text-underline-offset:3px;color:inherit;cursor:pointer;">Certificate</a></div></div>"`;
|
|
8
8
|
|
|
9
|
-
exports[`renderCertBlock — locked-design snapshots > floating (themed, non-navy accent) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--floating" data-certrev-mode="floating" data-certrev-strings-version="2026-07" style="--ba:#E8603C;--ba-fg:#141414;--br:22px;--bf:'Plus Jakarta Sans', system-ui, Helvetica, Arial, sans-serif;--surface:#faf8f4;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace
|
|
9
|
+
exports[`renderCertBlock — locked-design snapshots > floating (themed, non-navy accent) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--floating" data-certrev-mode="floating" data-certrev-strings-version="2026-07" style="--ba:#E8603C;--ba-fg:#141414;--br:22px;--bf:'Plus Jakarta Sans', system-ui, Helvetica, Arial, sans-serif;--surface:#faf8f4;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;font-family:var(--bf);color:var(--navy)"><div class="certrev-cert__pill" style="display:inline-flex;align-items:center;gap:14px;padding:12px 22px;border-radius:999px;background:var(--ba,#0a1b3f);color:var(--ba-fg,#fff);box-shadow:0 10px 26px var(--navy-10);"><span style="font-family:var(--font-mono);font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;opacity:.75;">Expert reviewed:</span><a href="https://certrev.com/expert/sample" data-certrev-modal-open="expert" rel="noopener" style="font-size:14px;font-weight:700;text-decoration:underline;text-underline-offset:3px;color:inherit;cursor:pointer;">Profile</a><span style="opacity:.5;">·</span><a href="https://certrev.com/verify/sample" data-certrev-modal-open rel="noopener" style="font-size:14px;font-weight:700;text-decoration:underline;text-underline-offset:3px;color:inherit;cursor:pointer;">Certificate</a></div></div>"`;
|
|
10
10
|
|
|
11
|
-
exports[`renderCertBlock — locked-design snapshots > sidebar (navy default) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--sidebar" data-certrev-mode="sidebar" data-certrev-strings-version="2026-07" style="--ba:#0a1b3f;--ba-fg:#ffffff;--br:14px;--bf:'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;--surface:#ffffff;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace
|
|
11
|
+
exports[`renderCertBlock — locked-design snapshots > sidebar (navy default) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--sidebar" data-certrev-mode="sidebar" data-certrev-strings-version="2026-07" style="--ba:#0a1b3f;--ba-fg:#ffffff;--br:14px;--bf:'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;--surface:#ffffff;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;font-family:var(--bf);color:var(--navy)"><div style="background:var(--surface);border:1px solid var(--navy-10);border-radius:var(--br,14px);overflow:hidden;box-shadow:0 4px 18px var(--navy-06);font-family:var(--bf);"><div style="display:flex;align-items:center;justify-content:center;gap:10px;padding:12px;background:#0a1b3f;color:#fff;font-family:var(--font-mono);font-size:12px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;"><svg viewBox="0 0 375 375" width="18" height="18" style="flex-shrink:0" aria-label="CertREV"><path fill="currentColor" d="M67.59 221.77L138.77 292.95C145.8 299.98 145.8 311.44 138.77 318.47L123.02 334.22C116 341.25 104.54 341.25 97.5 334.22L26.32 263.04C19.29 256.01 19.29 244.55 26.32 237.52L42.07 221.77C49.1 214.74 60.56 214.74 67.59 221.77Z"></path><path fill="currentColor" d="M96.79 335.08L81.12 319.42C73.8 312.1 73.8 300.23 81.12 292.92L315.88 58.16C323.2 50.85 335.06 50.85 342.38 58.16L358.04 73.83C365.36 81.14 365.36 93.01 358.04 100.33L123.29 335.08C115.97 342.4 104.1 342.4 96.79 335.08Z"></path><path fill="currentColor" d="M203.5 335.14L187.83 319.48C180.52 312.16 180.52 300.29 187.83 292.98L315.88 164.93C323.2 157.62 335.06 157.62 342.38 164.93L358.04 180.6C365.36 187.92 365.36 199.78 358.04 207.1L230 335.14C222.68 342.46 210.82 342.46 203.5 335.14Z"></path><path fill="currentColor" d="M310.21 335.2L294.54 319.54C287.23 312.22 287.23 300.36 294.54 293.04L315.88 271.71C323.2 264.39 335.06 264.39 342.38 271.71L358.04 287.37C365.36 294.69 365.36 306.55 358.04 313.87L336.71 335.2C329.39 342.52 317.53 342.52 310.21 335.2Z"></path></svg> Expert reviewed</div><div style="padding:20px;"><div style="display:flex;align-items:flex-start;gap:13px;"><div style="width:46px;height:46px;border-radius:50%;background:var(--stone);color:var(--navy-55);display:flex;align-items:center;justify-content:center;font-family:var(--font-mono);font-weight:700;font-size:13px;flex-shrink:0;">JD</div><div><div style="font-size:16px;font-weight:700;">Jane Doe, MD</div><div style="font-size:12.5px;color:var(--navy-55);line-height:1.45;margin-top:3px;">Credential verified by CertREV</div><div style="font-size:12.5px;color:var(--navy-55);line-height:1.35;">on Apr 14, 2026</div></div></div><p style="font-size:14px;line-height:1.55;color:var(--navy-75);margin:16px 0 0;">Board-certified dermatologist in San Francisco specializing in photoprotection, skin-cancer prevention, and evidence-based skincare, with fifteen years of clinical practice.</p><blockquote style="margin:16px 0 0;padding-left:16px;border-left:3px solid var(--ba,#0a1b3f);font-size:15px;line-height:1.5;color:var(--navy-75);white-space:pre-line;">Patients ask me almost every week whether the SPF in their foundation is enough on its own. Treat makeup with SPF as a helpful last layer, not the base of your routine.</blockquote><div style="font-size:12.5px;line-height:1.5;color:var(--navy-55);margin-top:16px;"><span style="font-family:var(--font-mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;">Compensated expert</span> · Independent editorial review of this article’s text and sources. Not a product endorsement, nor medical advice.</div></div><div style="display:grid;grid-template-columns:1fr 1fr;border-top:1px solid var(--navy-10);"><a href="https://certrev.com/expert/sample" data-certrev-modal-open="expert" rel="noopener" style="text-align:center;padding:14px;font-size:14px;font-weight:700;color:var(--navy);text-decoration:none;border-right:1px solid var(--navy-10);cursor:pointer;">View Profile</a><a href="https://certrev.com/verify/sample" data-certrev-modal-open rel="noopener" style="text-align:center;padding:14px;font-size:14px;font-weight:700;color:var(--navy);text-decoration:none;cursor:pointer;">View Certificate</a></div></div></div>"`;
|
|
12
12
|
|
|
13
|
-
exports[`renderCertBlock — locked-design snapshots > sidebar (themed, non-navy accent) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--sidebar" data-certrev-mode="sidebar" data-certrev-strings-version="2026-07" style="--ba:#E8603C;--ba-fg:#141414;--br:22px;--bf:'Plus Jakarta Sans', system-ui, Helvetica, Arial, sans-serif;--surface:#faf8f4;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace
|
|
13
|
+
exports[`renderCertBlock — locked-design snapshots > sidebar (themed, non-navy accent) matches the locked snapshot 1`] = `"<div class="certrev-cert certrev-cert--sidebar" data-certrev-mode="sidebar" data-certrev-strings-version="2026-07" style="--ba:#E8603C;--ba-fg:#141414;--br:22px;--bf:'Plus Jakarta Sans', system-ui, Helvetica, Arial, sans-serif;--surface:#faf8f4;--navy:#0a1b3f;--navy-06:rgba(10,27,63,.06);--navy-10:rgba(10,27,63,.10);--navy-35:rgba(10,27,63,.35);--navy-55:rgba(10,27,63,.55);--navy-75:rgba(10,27,63,.75);--stone:#ece9e1;--font-mono:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;font-family:var(--bf);color:var(--navy)"><div style="background:var(--surface);border:1px solid var(--navy-10);border-radius:var(--br,14px);overflow:hidden;box-shadow:0 4px 18px var(--navy-06);font-family:var(--bf);"><div style="display:flex;align-items:center;justify-content:center;gap:10px;padding:12px;background:#0a1b3f;color:#fff;font-family:var(--font-mono);font-size:12px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;"><svg viewBox="0 0 375 375" width="18" height="18" style="flex-shrink:0" aria-label="CertREV"><path fill="currentColor" d="M67.59 221.77L138.77 292.95C145.8 299.98 145.8 311.44 138.77 318.47L123.02 334.22C116 341.25 104.54 341.25 97.5 334.22L26.32 263.04C19.29 256.01 19.29 244.55 26.32 237.52L42.07 221.77C49.1 214.74 60.56 214.74 67.59 221.77Z"></path><path fill="currentColor" d="M96.79 335.08L81.12 319.42C73.8 312.1 73.8 300.23 81.12 292.92L315.88 58.16C323.2 50.85 335.06 50.85 342.38 58.16L358.04 73.83C365.36 81.14 365.36 93.01 358.04 100.33L123.29 335.08C115.97 342.4 104.1 342.4 96.79 335.08Z"></path><path fill="currentColor" d="M203.5 335.14L187.83 319.48C180.52 312.16 180.52 300.29 187.83 292.98L315.88 164.93C323.2 157.62 335.06 157.62 342.38 164.93L358.04 180.6C365.36 187.92 365.36 199.78 358.04 207.1L230 335.14C222.68 342.46 210.82 342.46 203.5 335.14Z"></path><path fill="currentColor" d="M310.21 335.2L294.54 319.54C287.23 312.22 287.23 300.36 294.54 293.04L315.88 271.71C323.2 264.39 335.06 264.39 342.38 271.71L358.04 287.37C365.36 294.69 365.36 306.55 358.04 313.87L336.71 335.2C329.39 342.52 317.53 342.52 310.21 335.2Z"></path></svg> Expert reviewed</div><div style="padding:20px;"><div style="display:flex;align-items:flex-start;gap:13px;"><div style="width:46px;height:46px;border-radius:50%;background:var(--stone);color:var(--navy-55);display:flex;align-items:center;justify-content:center;font-family:var(--font-mono);font-weight:700;font-size:13px;flex-shrink:0;">JD</div><div><div style="font-size:16px;font-weight:700;">Jane Doe, MD</div><div style="font-size:12.5px;color:var(--navy-55);line-height:1.45;margin-top:3px;">Credential verified by CertREV</div><div style="font-size:12.5px;color:var(--navy-55);line-height:1.35;">on Apr 14, 2026</div></div></div><p style="font-size:14px;line-height:1.55;color:var(--navy-75);margin:16px 0 0;">Board-certified dermatologist in San Francisco specializing in photoprotection, skin-cancer prevention, and evidence-based skincare, with fifteen years of clinical practice.</p><blockquote style="margin:16px 0 0;padding-left:16px;border-left:3px solid var(--ba,#0a1b3f);font-size:15px;line-height:1.5;color:var(--navy-75);white-space:pre-line;">Patients ask me almost every week whether the SPF in their foundation is enough on its own. Treat makeup with SPF as a helpful last layer, not the base of your routine.</blockquote><div style="font-size:12.5px;line-height:1.5;color:var(--navy-55);margin-top:16px;"><span style="font-family:var(--font-mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;">Compensated expert</span> · Independent editorial review of this article’s text and sources. Not a product endorsement, nor medical advice.</div></div><div style="display:grid;grid-template-columns:1fr 1fr;border-top:1px solid var(--navy-10);"><a href="https://certrev.com/expert/sample" data-certrev-modal-open="expert" rel="noopener" style="text-align:center;padding:14px;font-size:14px;font-weight:700;color:var(--navy);text-decoration:none;border-right:1px solid var(--navy-10);cursor:pointer;">View Profile</a><a href="https://certrev.com/verify/sample" data-certrev-modal-open rel="noopener" style="text-align:center;padding:14px;font-size:14px;font-weight:700;color:var(--navy);text-decoration:none;cursor:pointer;">View Certificate</a></div></div></div>"`;
|
|
@@ -207,11 +207,13 @@ describe('theming', () => {
|
|
|
207
207
|
it('the fixed CertREV logo chrome renders on the banner + sidebar headers and the memo credit', () => {
|
|
208
208
|
const banner = renderCertBlock({ mode: 'banner', facts: FACTS })
|
|
209
209
|
const sidebar = renderCertBlock({ mode: 'sidebar', facts: FACTS })
|
|
210
|
-
//
|
|
210
|
+
// every mark tracks its container ink via currentColor (navy header + memo verified lockup)
|
|
211
211
|
expect(banner).toContain('aria-label="CertREV"')
|
|
212
212
|
expect(banner).toContain('<path fill="currentColor"')
|
|
213
|
-
|
|
214
|
-
|
|
213
|
+
// the memo footer carries the "Verified by CertREV" trust mark; the wordmark rides the body
|
|
214
|
+
// font now (the grotesk --font-wordmark slot is gone from the locked chrome)
|
|
215
|
+
expect(banner).toContain('Verified by')
|
|
216
|
+
expect(banner).not.toContain('font-family:var(--font-wordmark)')
|
|
215
217
|
expect(sidebar).toContain('aria-label="CertREV"')
|
|
216
218
|
expect(sidebar).toContain('<path fill="currentColor"')
|
|
217
219
|
})
|
|
@@ -257,3 +259,24 @@ describe('escaping (this is storefront HTML)', () => {
|
|
|
257
259
|
})
|
|
258
260
|
}
|
|
259
261
|
})
|
|
262
|
+
|
|
263
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
264
|
+
// Reviewer name — honorific stripping (parity with the Liquid twin)
|
|
265
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
266
|
+
|
|
267
|
+
describe('reviewer name — honorific stripping (Liquid parity)', () => {
|
|
268
|
+
it('strips a leading honorific for the avatar initials + the first-name link', () => {
|
|
269
|
+
const html = renderCertBlock({ mode: 'banner', facts: { ...FACTS, reviewerName: 'Dr. Marcus Ellison' } })
|
|
270
|
+
// "Dr. Marcus Ellison" → "ME" avatar, never "DM"
|
|
271
|
+
expect(html).toContain('flex-shrink:0;">ME<')
|
|
272
|
+
expect(html).not.toContain('flex-shrink:0;">DM<')
|
|
273
|
+
// "View Marcus's profile", never "View Dr.'s profile" (apostrophe-agnostic)
|
|
274
|
+
expect(html).toMatch(/View Marcus.s profile/)
|
|
275
|
+
expect(html).not.toMatch(/View Dr\..s profile/)
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
it('leaves an un-prefixed name untouched', () => {
|
|
279
|
+
const html = renderCertBlock({ mode: 'banner', facts: { ...FACTS, reviewerName: 'Jane Doe' } })
|
|
280
|
+
expect(html).toContain('flex-shrink:0;">JD<')
|
|
281
|
+
})
|
|
282
|
+
})
|
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
* hooks on the ROOT element so the block is self-contained on a storefront that does
|
|
20
20
|
* NOT define the guide's `:root` — the accent (`--ba`), its auto-contrast ink
|
|
21
21
|
* (`--ba-fg`), the corner radius (`--br`), the body font (`--bf`) and surface
|
|
22
|
-
* (`--surface`) come from the resolved theme; the navy trust tints + the fixed
|
|
23
|
-
* label
|
|
24
|
-
* aesthetic").
|
|
25
|
-
*
|
|
22
|
+
* (`--surface`) come from the resolved theme; the navy trust tints + the fixed mono
|
|
23
|
+
* label font (`--font-mono`) are LOCKED literals (guide "the lock is legal, not
|
|
24
|
+
* aesthetic"). Names, the memo quote, disclosures, links, and the "CertREV" wordmark
|
|
25
|
+
* ride the body font; the serif/grotesk slots remain reachable only as a brand's
|
|
26
|
+
* themeable body-font choice. A brand themes accent / font / corners / surface, but
|
|
27
|
+
* the navy header bar + trust ink stay fixed (accent theming of the bar is Phase B).
|
|
26
28
|
*
|
|
27
29
|
* COMPLIANCE (LOCKED, non-negotiable): the three material disclosures always render
|
|
28
30
|
* on a CLAIM face (banner + sidebar) — the compensation cue, the byte-exact FTC
|
|
@@ -108,16 +110,14 @@ const LOGO_PATHS = [
|
|
|
108
110
|
]
|
|
109
111
|
|
|
110
112
|
/**
|
|
111
|
-
* The 4-chevron CertREV mark at `size`px, filled `
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* ink on a light themed accent (so it never goes white-on-light). The memo credit
|
|
115
|
-
* passes the fixed navy `#0a1b3f` (it sits on the white surface).
|
|
113
|
+
* The 4-chevron CertREV mark at `size`px, always filled `currentColor` so it tracks
|
|
114
|
+
* its container's ink — white on the hardcoded-navy header, and the muted navy-55 of
|
|
115
|
+
* the memo footer's "Verified by CertREV" lockup (it sits on the white surface).
|
|
116
116
|
*/
|
|
117
|
-
function logo(size: number
|
|
117
|
+
function logo(size: number): string {
|
|
118
118
|
return (
|
|
119
119
|
`<svg viewBox="0 0 375 375" width="${size}" height="${size}" style="flex-shrink:0" aria-label="CertREV">` +
|
|
120
|
-
LOGO_PATHS.map((d) => `<path fill="
|
|
120
|
+
LOGO_PATHS.map((d) => `<path fill="currentColor" d="${d}"></path>`).join('') +
|
|
121
121
|
`</svg>`
|
|
122
122
|
)
|
|
123
123
|
}
|
|
@@ -131,9 +131,23 @@ const CARET =
|
|
|
131
131
|
// Small pure helpers
|
|
132
132
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
133
133
|
|
|
134
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* Strip a leading honorific ("Dr. Jane Smith" → "Jane Smith") so the initials + first-name token don't
|
|
136
|
+
* capture it — matches the Liquid twin, which removes a matched honorific so "Dr. Marcus Ellison" yields
|
|
137
|
+
* the "ME" avatar + "Marcus's profile", never "DM" / "Dr.'s profile".
|
|
138
|
+
*/
|
|
139
|
+
function stripHonorific(name: string): string {
|
|
140
|
+
return (
|
|
141
|
+
name
|
|
142
|
+
.trim()
|
|
143
|
+
.replace(/^(dr|prof|professor|mr|mrs|ms|mx|rev|sir|dame)\.?\s+/i, '')
|
|
144
|
+
.trim() || name.trim()
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** "Jane Doe" → "JD"; "Dr. Marcus Ellison" → "ME" (first letter of the first two words, honorific stripped). */
|
|
135
149
|
function initials(name: string): string {
|
|
136
|
-
const parts = name
|
|
150
|
+
const parts = stripHonorific(name).split(/\s+/).filter(Boolean)
|
|
137
151
|
const chars = parts
|
|
138
152
|
.slice(0, 2)
|
|
139
153
|
.map((p) => p[0] ?? '')
|
|
@@ -141,10 +155,10 @@ function initials(name: string): string {
|
|
|
141
155
|
return (chars || '?').toUpperCase()
|
|
142
156
|
}
|
|
143
157
|
|
|
144
|
-
/** The first name token (for "View Jane's profile"). */
|
|
158
|
+
/** The first name token (for "View Jane's profile") — honorific stripped. */
|
|
145
159
|
function firstNameOf(name: string): string {
|
|
146
|
-
const
|
|
147
|
-
return
|
|
160
|
+
const clean = stripHonorific(name)
|
|
161
|
+
return clean.split(/\s+/)[0] || clean
|
|
148
162
|
}
|
|
149
163
|
|
|
150
164
|
/**
|
|
@@ -231,8 +245,6 @@ function rootStyle(theme: ResolvedBlockTheme): string {
|
|
|
231
245
|
`--navy-75:rgba(10,27,63,.75)`,
|
|
232
246
|
`--stone:#ece9e1`,
|
|
233
247
|
`--font-mono:${RENDER_BLOCK_FONT_STACKS.mono}`,
|
|
234
|
-
`--font-serif:${RENDER_BLOCK_FONT_STACKS.serif}`,
|
|
235
|
-
`--font-wordmark:${RENDER_BLOCK_FONT_STACKS.grotesk}`,
|
|
236
248
|
`font-family:var(--bf)`,
|
|
237
249
|
`color:var(--navy)`,
|
|
238
250
|
].join(';')
|
|
@@ -255,32 +267,40 @@ function bannerHeaderCard(facts: CertBlockFacts): string {
|
|
|
255
267
|
const subtitle = facts.authorTitle
|
|
256
268
|
? `<div style="font-size:13px;color:var(--navy-55);">${escapeHtml(facts.authorTitle)}</div>`
|
|
257
269
|
: ''
|
|
270
|
+
// A subtle right-aligned arrow opens the certificate: the whole navy bar is the mouse
|
|
271
|
+
// target (data-certrev-modal-open); this focusable <a> is the keyboard / SR / no-JS control.
|
|
272
|
+
const certHref = safeHttpUrl(facts.certificateUrl) ?? '#'
|
|
273
|
+
const headerArrow =
|
|
274
|
+
`<a href="${escapeAttribute(certHref)}" data-certrev-modal-open rel="noopener" aria-label="View certificate" ` +
|
|
275
|
+
`style="display:inline-flex;align-items:center;flex-shrink:0;color:inherit;opacity:.72;text-decoration:none;">` +
|
|
276
|
+
`<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path></svg></a>`
|
|
258
277
|
return (
|
|
259
278
|
`<div style="border:1px solid var(--navy-10);border-radius:calc(var(--br,14px) * 0.7);overflow:hidden;font-family:var(--bf);">` +
|
|
260
|
-
// navy header
|
|
261
|
-
`<div style="display:flex;align-items:center;justify-content:space-between;gap:16px;padding:15px 22px;background
|
|
262
|
-
`<span style="display:inline-flex;align-items:center;gap:11px;font-family:var(--font-mono);font-size:12px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;">${logo(20
|
|
279
|
+
// navy header — the trust bar stays fixed navy (accent theming is Phase B); mark + eyebrow + cert arrow
|
|
280
|
+
`<div data-certrev-modal-open style="display:flex;align-items:center;justify-content:space-between;gap:16px;padding:15px 22px;background:#0a1b3f;color:#fff;cursor:pointer;">` +
|
|
281
|
+
`<span style="display:inline-flex;align-items:center;gap:11px;font-family:var(--font-mono);font-size:12px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;">${logo(20)} Expert reviewed</span>` +
|
|
282
|
+
headerArrow +
|
|
263
283
|
`</div>` +
|
|
264
284
|
`<div style="padding:22px 24px 18px;">` +
|
|
265
285
|
`<div style="display:grid;grid-template-columns:1fr 1fr;gap:22px;">` +
|
|
266
|
-
// written by
|
|
286
|
+
// written by — muted label (navy-35)
|
|
267
287
|
`<div>` +
|
|
268
288
|
`<div style="font-family:var(--font-mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-35);margin-bottom:11px;">Written by</div>` +
|
|
269
289
|
`<div style="display:flex;align-items:center;gap:12px;">${avatar(initials(facts.authorName), 42, 12)}` +
|
|
270
290
|
`<div><div style="font-size:15px;font-weight:700;">${escapeHtml(facts.authorName)}</div>${subtitle}</div></div>` +
|
|
271
291
|
`</div>` +
|
|
272
|
-
// reviewed by
|
|
292
|
+
// reviewed by — emphasized label (navy, 700): the certification's authority voice
|
|
273
293
|
`<div>` +
|
|
274
|
-
`<div style="font-family:var(--font-mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--navy
|
|
294
|
+
`<div style="font-family:var(--font-mono);font-size:10px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--navy);margin-bottom:11px;">Reviewed by</div>` +
|
|
275
295
|
`<div class="certrev-cert__rev" role="button" tabindex="0" aria-expanded="false" data-certrev-bio-toggle aria-label="Read more about ${escapeAttribute(facts.reviewerName)}" style="display:flex;align-items:flex-start;gap:12px;cursor:pointer;border-radius:8px;transition:opacity .15s;">` +
|
|
276
296
|
`${avatar(initials(facts.reviewerName), 42, 12)}${verificationBlock(facts, true)}` +
|
|
277
297
|
`</div>` +
|
|
278
298
|
`</div>` +
|
|
279
299
|
`</div>` +
|
|
280
|
-
// hairline + mono footer
|
|
300
|
+
// hairline + mono footer — "Certified <date>" + "Compensated expert", UNIFORM navy-55
|
|
281
301
|
`<div style="height:1px;background:var(--navy-10);margin:16px 0 14px;"></div>` +
|
|
282
|
-
`<div style="display:flex;align-items:center;justify-content:space-between;gap:
|
|
283
|
-
`<span>Certified <span style="
|
|
302
|
+
`<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-55);">` +
|
|
303
|
+
`<span>Certified <span style="margin-left:8px;">${certified}</span></span>` +
|
|
284
304
|
`<span>${escapeHtml(compensationCue)}</span>` +
|
|
285
305
|
`</div>` +
|
|
286
306
|
`</div>` +
|
|
@@ -294,29 +314,30 @@ function bannerMemoCard(facts: CertBlockFacts): string {
|
|
|
294
314
|
? `<span style="color:var(--navy-55);">, ${escapeHtml(facts.credential)}</span>`
|
|
295
315
|
: ''
|
|
296
316
|
const first = firstNameOf(facts.reviewerName)
|
|
317
|
+
// The memo footer's profile/certificate actions read as the JetBrains-mono uppercase stamp
|
|
318
|
+
// that matches the badge footer lockup (Owen 2026-07-17) — navy, so they still read as actions.
|
|
319
|
+
const stampLink =
|
|
320
|
+
'font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy);text-decoration:none;cursor:pointer;'
|
|
297
321
|
return (
|
|
298
322
|
`<div style="border:1px solid var(--navy-10);border-radius:calc(var(--br,14px) * 0.7);padding:24px;font-family:var(--bf);">` +
|
|
299
323
|
`<div style="font-family:var(--font-mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--navy-55);margin-bottom:14px;">Expert memo</div>` +
|
|
300
324
|
`<div style="display:flex;gap:15px;">${avatar(initials(facts.reviewerName), 46, 13)}` +
|
|
301
325
|
`<div style="flex:1;min-width:0;">` +
|
|
302
|
-
`<div style="font-size:16px;
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
facts.profileUrl,
|
|
307
|
-
`View ${escapeHtml(first)}'s profile`,
|
|
308
|
-
'font-size:14px;font-weight:700;color:var(--navy);text-decoration:none;cursor:pointer;',
|
|
309
|
-
) +
|
|
310
|
-
certificateLink(
|
|
311
|
-
facts.certificateUrl,
|
|
312
|
-
'View certificate',
|
|
313
|
-
'font-size:14px;font-weight:700;color:var(--navy);text-decoration:none;cursor:pointer;',
|
|
314
|
-
) +
|
|
315
|
-
`</div>` +
|
|
326
|
+
`<div style="font-size:16px;line-height:1.2;"><span style="font-weight:700;">${escapeHtml(facts.reviewerName)}</span>${credTail}</div>` +
|
|
327
|
+
// Readable, UPRIGHT DM Sans quote (Owen 2026-07-17: the display-serif italic hurt legibility);
|
|
328
|
+
// pre-line preserves the reviewer's paragraph breaks. No left accent bar (matches the guide).
|
|
329
|
+
`<p style="margin:11px 0 14px;font-size:15.5px;line-height:1.6;color:var(--navy-75);white-space:pre-line;">${escapeHtml(facts.memo)}</p>` +
|
|
316
330
|
`</div>` +
|
|
317
331
|
`</div>` +
|
|
332
|
+
// footer hairline + one trust row: "Verified by CertREV" left, the two actions right
|
|
318
333
|
`<div style="height:1px;background:var(--navy-10);margin:18px 0 14px;"></div>` +
|
|
319
|
-
`<div style="display:
|
|
334
|
+
`<div style="display:flex;align-items:center;justify-content:space-between;gap:16px 22px;flex-wrap:wrap;">` +
|
|
335
|
+
`<div style="display:inline-flex;align-items:center;gap:9px;font-family:var(--font-mono);font-size:10.5px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--navy-55);">${logo(15)}<span>Verified by <span style="font-weight:700;color:var(--navy);">CertREV</span></span></div>` +
|
|
336
|
+
`<div style="display:flex;flex-wrap:wrap;gap:22px;">` +
|
|
337
|
+
profileLink(facts.profileUrl, `View ${escapeHtml(first)}'s profile`, stampLink) +
|
|
338
|
+
certificateLink(facts.certificateUrl, 'View certificate', stampLink) +
|
|
339
|
+
`</div>` +
|
|
340
|
+
`</div>` +
|
|
320
341
|
`<div style="font-size:13px;color:var(--navy-55);margin-top:8px;line-height:1.5;">${escapeHtml(scopeLine)}</div>` +
|
|
321
342
|
`</div>`
|
|
322
343
|
)
|
|
@@ -334,11 +355,11 @@ function sidebarCard(facts: CertBlockFacts): string {
|
|
|
334
355
|
: ''
|
|
335
356
|
return (
|
|
336
357
|
`<div style="background:var(--surface);border:1px solid var(--navy-10);border-radius:var(--br,14px);overflow:hidden;box-shadow:0 4px 18px var(--navy-06);font-family:var(--bf);">` +
|
|
337
|
-
`<div style="display:flex;align-items:center;justify-content:center;gap:10px;padding:12px;background
|
|
358
|
+
`<div style="display:flex;align-items:center;justify-content:center;gap:10px;padding:12px;background:#0a1b3f;color:#fff;font-family:var(--font-mono);font-size:12px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;">${logo(18)} Expert reviewed</div>` +
|
|
338
359
|
`<div style="padding:20px;">` +
|
|
339
360
|
`<div style="display:flex;align-items:flex-start;gap:13px;">${avatar(initials(facts.reviewerName), 46, 13)}${verificationBlock(facts, false)}</div>` +
|
|
340
361
|
bioPara +
|
|
341
|
-
`<blockquote style="margin:16px 0 0;padding-left:16px;border-left:3px solid var(--ba,#0a1b3f);font-
|
|
362
|
+
`<blockquote style="margin:16px 0 0;padding-left:16px;border-left:3px solid var(--ba,#0a1b3f);font-size:15px;line-height:1.5;color:var(--navy-75);white-space:pre-line;">${escapeHtml(facts.memo)}</blockquote>` +
|
|
342
363
|
`<div style="font-size:12.5px;line-height:1.5;color:var(--navy-55);margin-top:16px;"><span style="font-family:var(--font-mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;">${escapeHtml(compensationCue)}</span> · ${escapeHtml(scopeLine)}</div>` +
|
|
343
364
|
`</div>` +
|
|
344
365
|
`<div style="display:grid;grid-template-columns:1fr 1fr;border-top:1px solid var(--navy-10);">` +
|