@certrev/cert-block 0.2.0 → 0.5.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.
Files changed (129) hide show
  1. package/README.md +48 -1
  2. package/dist/builder/cert-chrome-data.d.ts +129 -0
  3. package/dist/builder/cert-chrome-data.d.ts.map +1 -0
  4. package/dist/builder/cert-chrome-data.js +59 -0
  5. package/dist/builder/cert-chrome-data.js.map +1 -0
  6. package/dist/builder/cert-review-card.d.ts +68 -0
  7. package/dist/builder/cert-review-card.d.ts.map +1 -0
  8. package/dist/builder/cert-review-card.js +129 -0
  9. package/dist/builder/cert-review-card.js.map +1 -0
  10. package/dist/builder/index.d.ts +2 -0
  11. package/dist/builder/index.d.ts.map +1 -1
  12. package/dist/builder/index.js +3 -0
  13. package/dist/builder/index.js.map +1 -1
  14. package/dist/components/preview-block.d.ts +43 -0
  15. package/dist/components/preview-block.d.ts.map +1 -0
  16. package/dist/components/preview-block.js +53 -0
  17. package/dist/components/preview-block.js.map +1 -0
  18. package/dist/components/render-cert-block.d.ts +50 -5
  19. package/dist/components/render-cert-block.d.ts.map +1 -1
  20. package/dist/components/render-cert-block.js +341 -93
  21. package/dist/components/render-cert-block.js.map +1 -1
  22. package/dist/components/render-def.d.ts +27 -0
  23. package/dist/components/render-def.d.ts.map +1 -1
  24. package/dist/components/render-def.js +38 -0
  25. package/dist/components/render-def.js.map +1 -1
  26. package/dist/index.d.ts +3 -2
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +3 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/modal/avatar-resize.d.ts +60 -0
  31. package/dist/modal/avatar-resize.d.ts.map +1 -0
  32. package/dist/modal/avatar-resize.js +91 -0
  33. package/dist/modal/avatar-resize.js.map +1 -0
  34. package/dist/modal/cert-modal-view.d.ts +74 -0
  35. package/dist/modal/cert-modal-view.d.ts.map +1 -0
  36. package/dist/modal/cert-modal-view.js +160 -0
  37. package/dist/modal/cert-modal-view.js.map +1 -0
  38. package/dist/modal/certrev-cert-modal.d.ts +72 -0
  39. package/dist/modal/certrev-cert-modal.d.ts.map +1 -0
  40. package/dist/modal/certrev-cert-modal.js +270 -0
  41. package/dist/modal/certrev-cert-modal.js.map +1 -0
  42. package/dist/modal/certrev-cert-modal.styles.d.ts +35 -0
  43. package/dist/modal/certrev-cert-modal.styles.d.ts.map +1 -0
  44. package/dist/modal/certrev-cert-modal.styles.js +488 -0
  45. package/dist/modal/certrev-cert-modal.styles.js.map +1 -0
  46. package/dist/modal/certrev-cert.entry.d.ts +19 -0
  47. package/dist/modal/certrev-cert.entry.d.ts.map +1 -0
  48. package/dist/modal/certrev-cert.entry.js +39 -0
  49. package/dist/modal/certrev-cert.entry.js.map +1 -0
  50. package/dist/modal/certrev-cert.js +557 -0
  51. package/dist/modal/display-strings.d.ts +22 -0
  52. package/dist/modal/display-strings.d.ts.map +1 -0
  53. package/dist/modal/display-strings.js +35 -0
  54. package/dist/modal/display-strings.js.map +1 -0
  55. package/dist/modal/escape.d.ts +13 -0
  56. package/dist/modal/escape.d.ts.map +1 -0
  57. package/dist/modal/escape.js +20 -0
  58. package/dist/modal/escape.js.map +1 -0
  59. package/dist/modal/font-face.d.ts +4 -0
  60. package/dist/modal/font-face.d.ts.map +1 -0
  61. package/dist/modal/font-face.js +137 -0
  62. package/dist/modal/font-face.js.map +1 -0
  63. package/dist/modal/ftc-disclosure.d.ts +12 -0
  64. package/dist/modal/ftc-disclosure.d.ts.map +1 -0
  65. package/dist/modal/ftc-disclosure.js +12 -0
  66. package/dist/modal/ftc-disclosure.js.map +1 -0
  67. package/dist/modal/ftc-guard.d.ts +50 -0
  68. package/dist/modal/ftc-guard.d.ts.map +1 -0
  69. package/dist/modal/ftc-guard.js +117 -0
  70. package/dist/modal/ftc-guard.js.map +1 -0
  71. package/dist/modal/index.d.ts +20 -0
  72. package/dist/modal/index.d.ts.map +1 -0
  73. package/dist/modal/index.js +25 -0
  74. package/dist/modal/index.js.map +1 -0
  75. package/dist/modal/interactions.d.ts +53 -0
  76. package/dist/modal/interactions.d.ts.map +1 -0
  77. package/dist/modal/interactions.js +147 -0
  78. package/dist/modal/interactions.js.map +1 -0
  79. package/dist/modal/logo-paths.d.ts +15 -0
  80. package/dist/modal/logo-paths.d.ts.map +1 -0
  81. package/dist/modal/logo-paths.js +24 -0
  82. package/dist/modal/logo-paths.js.map +1 -0
  83. package/dist/modal/placement.d.ts +95 -0
  84. package/dist/modal/placement.d.ts.map +1 -0
  85. package/dist/modal/placement.js +302 -0
  86. package/dist/modal/placement.js.map +1 -0
  87. package/dist/modal/revalidate.d.ts +48 -0
  88. package/dist/modal/revalidate.d.ts.map +1 -0
  89. package/dist/modal/revalidate.js +65 -0
  90. package/dist/modal/revalidate.js.map +1 -0
  91. package/dist/modal/verify-client.d.ts +24 -0
  92. package/dist/modal/verify-client.d.ts.map +1 -0
  93. package/dist/modal/verify-client.js +38 -0
  94. package/dist/modal/verify-client.js.map +1 -0
  95. package/package.json +10 -4
  96. package/src/__tests__/__snapshots__/render-cert-block.test.ts.snap +10 -6
  97. package/src/__tests__/preview-block.test.ts +84 -0
  98. package/src/__tests__/render-cert-block.test.ts +404 -6
  99. package/src/builder/__tests__/builder.test.tsx +71 -0
  100. package/src/builder/cert-chrome-data.ts +159 -0
  101. package/src/builder/cert-review-card.tsx +177 -0
  102. package/src/builder/index.tsx +18 -0
  103. package/src/components/preview-block.ts +74 -0
  104. package/src/components/render-cert-block.ts +427 -121
  105. package/src/components/render-def.ts +55 -0
  106. package/src/index.ts +9 -0
  107. package/src/modal/avatar-resize.ts +99 -0
  108. package/src/modal/cert-modal-view.test.ts +175 -0
  109. package/src/modal/cert-modal-view.ts +210 -0
  110. package/src/modal/certrev-cert-modal.styles.ts +494 -0
  111. package/src/modal/certrev-cert-modal.test.ts +125 -0
  112. package/src/modal/certrev-cert-modal.ts +273 -0
  113. package/src/modal/certrev-cert.entry.ts +44 -0
  114. package/src/modal/display-strings.ts +38 -0
  115. package/src/modal/escape.ts +20 -0
  116. package/src/modal/font-face.ts +138 -0
  117. package/src/modal/ftc-disclosure.ts +13 -0
  118. package/src/modal/ftc-guard.test.ts +153 -0
  119. package/src/modal/ftc-guard.ts +119 -0
  120. package/src/modal/index.ts +34 -0
  121. package/src/modal/interactions.test.ts +250 -0
  122. package/src/modal/interactions.ts +166 -0
  123. package/src/modal/logo-paths.ts +23 -0
  124. package/src/modal/placement.test.ts +398 -0
  125. package/src/modal/placement.ts +331 -0
  126. package/src/modal/revalidate.test.ts +111 -0
  127. package/src/modal/revalidate.ts +81 -0
  128. package/src/modal/verify-client.test.ts +164 -0
  129. package/src/modal/verify-client.ts +42 -0
@@ -0,0 +1,557 @@
1
+ /* biome-ignore-all format: generated cert-badge bundle, see @certrev/cert-block src/modal/ */ /* biome-ignore-all lint: generated cert-badge bundle, see @certrev/cert-block src/modal/ */
2
+ "use strict";(()=>{var H="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",Le=(()=>{let e=new Int8Array(128).fill(-1);for(let t=0;t<H.length;t++)e[H.charCodeAt(t)]=t;return e[45]=62,e[95]=63,e})();function y(e){let t=[];for(let a=0;a<e.length;a++){let c=e.charCodeAt(a),f=c<128?Le[c]:-1;f>=0&&t.push(f)}let r=Math.floor(t.length*6/8),n=new Uint8Array(r),o=0,i=0,s=0;for(let a=0;a<t.length;a++)o=o<<6|t[a],i+=6,i>=8&&(i-=8,n[s++]=o>>i&255);return n}function x(e){return y(e)}function d(e,t=new Set){if(typeof e=="number"&&isNaN(e))throw new Error("NaN is not allowed");if(typeof e=="number"&&!isFinite(e))throw new Error("Infinity is not allowed");if(e===null||typeof e!="object")return JSON.stringify(e);if(typeof e.toJSON=="function"){if(t.has(e))throw new Error("Circular reference detected");t.add(e);let n=d(e.toJSON(),t);return t.delete(e),n}if(t.has(e))throw new Error("Circular reference detected");t.add(e);let r;if(Array.isArray(e))r=`[${e.map(o=>d(o===void 0||typeof o=="symbol"?null:o,t)).join(",")}]`;else{let n=[];for(let o of Object.keys(e).sort())e[o]===void 0||typeof e[o]=="symbol"||n.push(`${d(o)}:${d(e[o],t)}`);r=`{${n.join(",")}}`}return t.delete(e),r}var Ie=typeof d=="function"?d:d.default;function V(e){let t=Ie(e);if(typeof t!="string")throw new Error("canonicalize: value is not JSON-serializable");return t}function F(e){return new TextEncoder().encode(V(e))}function C(e,t="$"){if(typeof e=="number"){if(!Number.isInteger(e)||!Number.isSafeInteger(e))throw new Error(`canonicalPayloadBytes: number at ${t} (${e}) is not a safe integer \u2014 signed-payload numbers must be safe integers so PHP/Go/Java verifiers reproduce identical canonical bytes`);return}if(Array.isArray(e)){e.forEach((r,n)=>C(r,`${t}[${n}]`));return}if(e&&typeof e=="object")for(let[r,n]of Object.entries(e))C(n,`${t}.${r}`)}function T(e){return C(e),F(e)}function R(e){return C(e),F(e)}var b="ed25519";var u={name:"Ed25519"};function Me(e){return e.replace(/-----BEGIN [^-]+-----/g,"").replace(/-----END [^-]+-----/g,"").replace(/\s+/g,"")}async function K(e){switch(e.format){case"pem":return crypto.subtle.importKey("spki",y(Me(e.pem)),u,!1,["verify"]);case"spki-base64":return crypto.subtle.importKey("spki",y(e.base64),u,!1,["verify"]);case"spki-der":return crypto.subtle.importKey("spki",e.bytes,u,!1,["verify"]);case"raw":{if(e.bytes.length!==32)throw new Error(`ed25519 raw public key must be 32 bytes, got ${e.bytes.length}`);return crypto.subtle.importKey("raw",e.bytes,u,!1,["verify"])}}}function $e(e){if("format"in e)return!1;let t=e;return typeof t.type=="string"&&typeof t.algorithm=="object"&&Array.isArray(t.usages)}async function q(e){return $e(e)?e:K(e)}async function G(e,t,r){let n=T(e),o=x(t);try{return await crypto.subtle.verify(u,r,o,n)}catch{return!1}}async function Oe(e,t){let{payload:r,signature:n}=e??{};if(!r||!n||r.contractVersion!==1)return{ok:!1,reason:"unsupported_contract_version"};if(n.alg!==b)return{ok:!1,reason:"unsupported_alg"};let o=await t(n.kid);if(!o)return{ok:!1,reason:"unknown_key"};let i;try{i=await q(o)}catch{return{ok:!1,reason:"unknown_key"}}return await G(r,n.sig,i)?{ok:!0,key:i}:{ok:!1,reason:"invalid_signature"}}function j(e,t){let r=t.now??new Date;if(e.subject.platform!==t.platform)return{decision:"suppress",reason:"platform_mismatch"};if(e.subject.externalId!==t.externalId)return{decision:"suppress",reason:"subject_mismatch"};if(e.lifecycle.revokedAt!==null)return{decision:"suppress",reason:"revoked"};if(r.getTime()>=Date.parse(e.lifecycle.expiresAt))return{decision:"suppress",reason:"expired"};let n=e.subject.contentDigest,o=t.liveContentHash;return n!==null&&o!=null&&n!==o?{decision:"suppress",reason:"content_drift"}:{decision:"render",payload:e}}async function J(e,t,r){let n;try{n=await Oe(e,t)}catch{return{decision:"suppress",reason:"unknown_key"}}return n.ok?j(e.payload,r):{decision:"suppress",reason:n.reason}}function g(e){return e?.kind==="tombstone"}async function Ne(e,t){let{signature:r}=e??{};if(!e?.subject||!r||e.contractVersion!==1)return{ok:!1,reason:"unsupported_contract_version"};if(r.alg!==b)return{ok:!1,reason:"unsupported_alg"};let n=await t(r.kid);if(!n)return{ok:!1,reason:"unknown_key"};let o;try{o=await q(n)}catch{return{ok:!1,reason:"unknown_key"}}let{signature:i,...s}=e,a=x(r.sig),c=!1;try{c=await crypto.subtle.verify(u,o,a,R(s))}catch{c=!1}return c?{ok:!0,key:o}:{ok:!1,reason:"invalid_signature"}}async function W(e,t,r){let n;try{n=await Ne(e,t)}catch{return{decision:"suppress",reason:"unknown_key"}}return n.ok?e.subject.platform!==r.platform?{decision:"suppress",reason:"platform_mismatch"}:e.subject.externalId!==r.externalId?{decision:"suppress",reason:"subject_mismatch"}:{decision:"suppress",reason:"revoked"}:{decision:"suppress",reason:n.reason}}async function L(e,t,r){return g(e)?W(e,t,r):J(e,t,r)}var Z=`
3
+ @font-face {
4
+ font-family: "DM Sans";
5
+ font-style: normal;
6
+ font-weight: 400 700;
7
+ font-display: swap;
8
+ src: url("https://assets.certrev.com/fonts/cert-dm-sans-latin-ext.woff2") format("woff2");
9
+ unicode-range:
10
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
11
+ }
12
+
13
+ @font-face {
14
+ font-family: "DM Sans";
15
+ font-style: normal;
16
+ font-weight: 400 700;
17
+ font-display: swap;
18
+ src: url("https://assets.certrev.com/fonts/cert-dm-sans-latin.woff2") format("woff2");
19
+ unicode-range:
20
+ U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
21
+ }
22
+
23
+ @font-face {
24
+ font-family: "Playfair Display";
25
+ font-style: italic;
26
+ font-weight: 400 600;
27
+ font-display: swap;
28
+ src: url("https://assets.certrev.com/fonts/cert-playfair-italic-latin-ext.woff2") format("woff2");
29
+ unicode-range:
30
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
31
+ }
32
+
33
+ @font-face {
34
+ font-family: "Playfair Display";
35
+ font-style: italic;
36
+ font-weight: 400 600;
37
+ font-display: swap;
38
+ src: url("https://assets.certrev.com/fonts/cert-playfair-italic-latin.woff2") format("woff2");
39
+ unicode-range:
40
+ U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
41
+ }
42
+
43
+ @font-face {
44
+ font-family: "Playfair Display";
45
+ font-style: normal;
46
+ font-weight: 600 700;
47
+ font-display: swap;
48
+ src: url("https://assets.certrev.com/fonts/cert-playfair-latin-ext.woff2") format("woff2");
49
+ unicode-range:
50
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
51
+ }
52
+
53
+ @font-face {
54
+ font-family: "Playfair Display";
55
+ font-style: normal;
56
+ font-weight: 600 700;
57
+ font-display: swap;
58
+ src: url("https://assets.certrev.com/fonts/cert-playfair-latin.woff2") format("woff2");
59
+ unicode-range:
60
+ U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
61
+ }
62
+
63
+ @font-face {
64
+ font-family: "JetBrains Mono";
65
+ font-style: normal;
66
+ font-weight: 400 700;
67
+ font-display: swap;
68
+ src: url("https://assets.certrev.com/fonts/cert-jetbrains-mono-latin-ext.woff2") format("woff2");
69
+ unicode-range:
70
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
71
+ }
72
+
73
+ @font-face {
74
+ font-family: "JetBrains Mono";
75
+ font-style: normal;
76
+ font-weight: 400 700;
77
+ font-display: swap;
78
+ src: url("https://assets.certrev.com/fonts/cert-jetbrains-mono-latin.woff2") format("woff2");
79
+ unicode-range:
80
+ U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
81
+ }
82
+
83
+ @font-face {
84
+ font-family: "Plus Jakarta Sans";
85
+ font-style: normal;
86
+ font-weight: 700 800;
87
+ font-display: swap;
88
+ src: url("https://assets.certrev.com/fonts/cert-jakarta-latin-ext.woff2") format("woff2");
89
+ unicode-range:
90
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
91
+ }
92
+
93
+ @font-face {
94
+ font-family: "Plus Jakarta Sans";
95
+ font-style: normal;
96
+ font-weight: 700 800;
97
+ font-display: swap;
98
+ src: url("https://assets.certrev.com/fonts/cert-jakarta-latin.woff2") format("woff2");
99
+ unicode-range:
100
+ U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
101
+ }
102
+
103
+ @font-face {
104
+ font-family: "Allura";
105
+ font-style: normal;
106
+ font-weight: 400;
107
+ font-display: swap;
108
+ src: url("https://assets.certrev.com/fonts/cert-allura-latin-ext.woff2") format("woff2");
109
+ unicode-range:
110
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
111
+ }
112
+
113
+ @font-face {
114
+ font-family: "Allura";
115
+ font-style: normal;
116
+ font-weight: 400;
117
+ font-display: swap;
118
+ src: url("https://assets.certrev.com/fonts/cert-allura-latin.woff2") format("woff2");
119
+ unicode-range:
120
+ U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
121
+ }
122
+ `,Y="https://assets.certrev.com";function l(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}var Pe=["assets.certrev.com","staging-assets.certrev.com"];function ze(e){return`width=${e},height=${e},fit=cover,format=auto,onerror=redirect`}function He(e,t){let r=(e??"").trim();if(!/^https:\/\//i.test(r))return r;let n;try{n=new URL(r)}catch{return r}if(!Pe.includes(n.hostname)||n.pathname.startsWith("/cdn-cgi/image/"))return r;let o=n.pathname.replace(/^\//,"");return`${n.origin}/cdn-cgi/image/${ze(t)}/${o}`}function X(e,t){return He(e,t)}var U="Independent editorial review of this article\u2019s text and sources. Not a product endorsement, nor medical advice.";var Q=U;function I(e){if(!e)return null;let t=e instanceof Date?e:new Date(e);return Number.isNaN(t.getTime())?null:t.toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric",timeZone:"UTC"})}var B=["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","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","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","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"];function ee(e,t){let r=B.map(n=>`<path fill="${t}" d="${n}"/>`).join("");return`<svg width="${e}" height="${e}" viewBox="0 0 375 375" aria-hidden="true" style="display:block;flex-shrink:0">${r}</svg>`}function te(e=8){return`<svg width="${e}" height="${e}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>`}function re(e="crm"){let t=`crm-stamp-arc-${e}`,r=B.map(n=>`<path fill="#0a1b3f" d="${n}"/>`).join("");return`<span class="crm-stamp"><svg viewBox="0 0 128 128" width="74" height="74" role="img" aria-label="CertREV verified stamp" style="display:block"><defs><path id="${t}" d="M64 18 A46 46 0 1 1 64 110 A46 46 0 1 1 64 18"/></defs><circle cx="64" cy="64" r="58" fill="none" stroke="#0a1b3f" stroke-width="1.3"/><circle cx="64" cy="64" r="51.5" fill="none" stroke="#0a1b3f" stroke-width="0.7" stroke-opacity="0.4"/><text font-family="'JetBrains Mono',ui-monospace,monospace" font-size="7.8" font-weight="600" letter-spacing="1.3" fill="#0a1b3f"><textPath href="#${t}" startOffset="1%">CERTREV VERIFIED \xB7 CERTIFIED \xB7 </textPath></text><svg x="49" y="50" width="30" height="28" viewBox="0 0 375 375" preserveAspectRatio="xMidYMid meet">${r}</svg></svg></span>`}var M=`
123
+ :host {
124
+ --cr-navy: #0a1b3f;
125
+ --cr-lime: #d4e157;
126
+ --cr-white: #ffffff;
127
+ --cr-navy-06: rgba(10, 27, 63, 0.06);
128
+ --cr-navy-10: rgba(10, 27, 63, 0.1);
129
+ --cr-navy-25: rgba(10, 27, 63, 0.25);
130
+ --cr-navy-40: rgba(10, 27, 63, 0.4);
131
+ --cr-navy-45: rgba(10, 27, 63, 0.45);
132
+ --cr-navy-50: rgba(10, 27, 63, 0.5);
133
+ --cr-navy-55: rgba(10, 27, 63, 0.55);
134
+ --cr-navy-60: rgba(10, 27, 63, 0.6);
135
+ --cr-navy-85: rgba(10, 27, 63, 0.85);
136
+ --cr-white-60: rgba(255, 255, 255, 0.6);
137
+ --cr-white-85: rgba(255, 255, 255, 0.85);
138
+ --cr-cta-hover: #0c2149;
139
+ --cr-ghost-hover: rgba(10, 27, 63, 0.12);
140
+ --cr-shadow: 0 30px 60px -18px rgba(10, 27, 63, 0.5);
141
+ --cr-backdrop: rgba(10, 27, 63, 0.45);
142
+ --cr-sans: 'DM Sans', system-ui, -apple-system, sans-serif;
143
+ --cr-serif: 'Playfair Display', Georgia, serif;
144
+ --cr-mono: 'JetBrains Mono', ui-monospace, Menlo, monospace;
145
+ --cr-wordmark: 'Plus Jakarta Sans', system-ui, sans-serif;
146
+ --cr-script: 'Allura', cursive;
147
+ }
148
+
149
+ .crm-dialog {
150
+ border: none;
151
+ border-radius: 14px;
152
+ padding: 0;
153
+ width: 92%;
154
+ max-height: 92vh;
155
+ overflow: auto;
156
+ box-shadow: var(--cr-shadow);
157
+ background: var(--cr-white);
158
+ color: var(--cr-navy);
159
+ font-family: var(--cr-sans);
160
+ /* fixed, NOT relative (POR-10473): a :modal dialog (showModal) renders in the TOP LAYER; a
161
+ * relative dialog anchors to its scrolled document position, so once the page is scrolled the
162
+ * panel renders off-screen while the ::backdrop still covers the viewport (measured top -1972 at
163
+ * scrollY 2537). fixed is viewport-anchored (the UA inset:0 + margin:auto centers it) and still
164
+ * provides the containing block for the absolutely-positioned .crm-close (x stays in-corner). */
165
+ position: fixed;
166
+ /* defensive resets against a hostile brand theme reaching the top-layer dialog */
167
+ box-sizing: border-box;
168
+ text-align: left;
169
+ line-height: 1.4;
170
+ }
171
+ .crm-dialog *,
172
+ .crm-dialog *::before,
173
+ .crm-dialog *::after {
174
+ box-sizing: border-box;
175
+ }
176
+ .crm-dialog::backdrop {
177
+ background: var(--cr-backdrop);
178
+ }
179
+ .crm-dialog--cert {
180
+ max-width: 484px;
181
+ }
182
+ .crm-dialog--expert {
183
+ max-width: 436px;
184
+ }
185
+
186
+ /* Close (\xD7) */
187
+ .crm-close {
188
+ position: absolute;
189
+ top: 12px;
190
+ right: 15px;
191
+ z-index: 2;
192
+ background: none;
193
+ border: none;
194
+ cursor: pointer;
195
+ padding: 2px;
196
+ color: var(--cr-white-60);
197
+ font-size: 1.35rem;
198
+ line-height: 1;
199
+ font-family: var(--cr-sans);
200
+ transition: color 0.15s;
201
+ }
202
+ .crm-close:hover {
203
+ color: var(--cr-white);
204
+ }
205
+
206
+ /* Header bar */
207
+ .crm-head {
208
+ display: flex;
209
+ align-items: center;
210
+ gap: 9px;
211
+ padding: 13px 22px;
212
+ background: var(--cr-navy);
213
+ color: var(--cr-white);
214
+ }
215
+ .crm-head__eyebrow {
216
+ font-family: var(--cr-mono);
217
+ font-size: 8.5px;
218
+ font-weight: 600;
219
+ letter-spacing: 0.16em;
220
+ text-transform: uppercase;
221
+ color: var(--cr-white-85);
222
+ }
223
+ .crm-head__wordmark {
224
+ margin-left: auto;
225
+ margin-right: 22px;
226
+ font-family: var(--cr-wordmark);
227
+ font-weight: 800;
228
+ font-size: 13px;
229
+ letter-spacing: 0.03em;
230
+ color: var(--cr-white);
231
+ }
232
+
233
+ /* Body */
234
+ .crm-body--cert {
235
+ padding: 24px 28px 26px;
236
+ }
237
+ .crm-body--expert {
238
+ padding: 22px 26px 24px;
239
+ }
240
+
241
+ /* Avatar (shared, lime ring) */
242
+ .crm-avatar {
243
+ position: relative;
244
+ flex-shrink: 0;
245
+ display: flex;
246
+ align-items: center;
247
+ justify-content: center;
248
+ border-radius: 50%;
249
+ background: var(--cr-navy);
250
+ color: var(--cr-white);
251
+ font-weight: 700;
252
+ object-fit: cover;
253
+ box-shadow: 0 0 0 2px var(--cr-white), 0 0 0 3.5px var(--cr-lime);
254
+ }
255
+ .crm-avatar--56 {
256
+ width: 56px;
257
+ height: 56px;
258
+ font-size: 17px;
259
+ }
260
+ .crm-avatar--64 {
261
+ width: 64px;
262
+ height: 64px;
263
+ font-size: 1.35rem;
264
+ letter-spacing: 0.02em;
265
+ }
266
+
267
+ /* Certificate \u2014 reviewing-expert row */
268
+ .crm-expert-row {
269
+ display: flex;
270
+ align-items: center;
271
+ gap: 14px;
272
+ }
273
+ .crm-expert-row__info {
274
+ flex: 1;
275
+ min-width: 0;
276
+ }
277
+ .crm-expert-row__eyebrow {
278
+ font-family: var(--cr-mono);
279
+ font-size: 8.5px;
280
+ font-weight: 600;
281
+ letter-spacing: 0.14em;
282
+ text-transform: uppercase;
283
+ color: var(--cr-navy-45);
284
+ }
285
+ .crm-expert-row__name {
286
+ font-size: 15px;
287
+ font-weight: 700;
288
+ color: var(--cr-navy);
289
+ margin-top: 2px;
290
+ }
291
+ .crm-expert-row__creds {
292
+ font-size: 12px;
293
+ color: var(--cr-navy-60);
294
+ margin-top: 1px;
295
+ }
296
+
297
+ /* Certificate \u2014 "Certifies the article" */
298
+ .crm-certifies {
299
+ margin: 18px 0 0;
300
+ padding-top: 16px;
301
+ border-top: 1px solid var(--cr-navy-10);
302
+ }
303
+ .crm-certifies__eyebrow {
304
+ font-family: var(--cr-mono);
305
+ font-size: 9px;
306
+ font-weight: 600;
307
+ letter-spacing: 0.16em;
308
+ text-transform: uppercase;
309
+ color: var(--cr-navy-40);
310
+ }
311
+ .crm-certifies__title {
312
+ font-family: var(--cr-serif);
313
+ font-weight: 700;
314
+ font-size: 18px;
315
+ line-height: 1.25;
316
+ color: var(--cr-navy);
317
+ margin-top: 5px;
318
+ text-wrap: balance;
319
+ }
320
+
321
+ /* Certificate \u2014 meta row */
322
+ .crm-meta {
323
+ display: flex;
324
+ gap: 10px;
325
+ margin-top: 16px;
326
+ }
327
+ .crm-meta__col {
328
+ flex: 1;
329
+ }
330
+ .crm-meta__label {
331
+ font-family: var(--cr-mono);
332
+ font-size: 8px;
333
+ letter-spacing: 0.12em;
334
+ text-transform: uppercase;
335
+ color: var(--cr-navy-40);
336
+ }
337
+ .crm-meta__value {
338
+ font-size: 12.5px;
339
+ font-weight: 600;
340
+ color: var(--cr-navy);
341
+ margin-top: 3px;
342
+ }
343
+ .crm-meta__value--mono {
344
+ font-family: var(--cr-mono);
345
+ font-size: 12px;
346
+ }
347
+ .crm-meta__status {
348
+ margin-top: 3px;
349
+ }
350
+
351
+ /* Certified chip (meta status) */
352
+ .crm-chip {
353
+ display: inline-flex;
354
+ align-items: center;
355
+ gap: 3px;
356
+ padding: 2px 7px;
357
+ border-radius: 4px;
358
+ background: var(--cr-lime);
359
+ color: var(--cr-navy);
360
+ font-family: var(--cr-mono);
361
+ font-size: 8.5px;
362
+ font-weight: 700;
363
+ letter-spacing: 0.06em;
364
+ text-transform: uppercase;
365
+ }
366
+
367
+ /* Certificate \u2014 signature + stamp footer */
368
+ .crm-sig {
369
+ display: flex;
370
+ align-items: flex-end;
371
+ justify-content: space-between;
372
+ margin-top: 20px;
373
+ padding-top: 16px;
374
+ border-top: 1px solid var(--cr-navy-10);
375
+ gap: 12px;
376
+ }
377
+ .crm-sig__name {
378
+ font-family: var(--cr-script);
379
+ font-size: 30px;
380
+ line-height: 0.9;
381
+ color: var(--cr-navy);
382
+ }
383
+ .crm-sig__rule {
384
+ width: 146px;
385
+ max-width: 100%;
386
+ height: 1px;
387
+ background: var(--cr-navy-25);
388
+ margin: 4px 0 6px;
389
+ }
390
+ .crm-sig__url {
391
+ font-family: var(--cr-mono);
392
+ font-size: 8px;
393
+ font-weight: 500;
394
+ letter-spacing: 0.12em;
395
+ text-transform: uppercase;
396
+ color: var(--cr-navy-50);
397
+ }
398
+ .crm-stamp {
399
+ transform: rotate(-8deg);
400
+ flex-shrink: 0;
401
+ }
402
+ .crm-stamp svg {
403
+ display: block;
404
+ }
405
+
406
+ /* Actions (shared) */
407
+ .crm-actions {
408
+ display: flex;
409
+ gap: 10px;
410
+ margin-top: 20px;
411
+ }
412
+ .crm-cta {
413
+ flex: 1;
414
+ display: inline-block;
415
+ text-align: center;
416
+ padding: 11px 16px;
417
+ background: var(--cr-navy);
418
+ color: var(--cr-white);
419
+ text-decoration: none;
420
+ border-radius: 8px;
421
+ font-size: 13px;
422
+ font-weight: 600;
423
+ font-family: var(--cr-sans);
424
+ border: none;
425
+ cursor: pointer;
426
+ transition: background 0.15s;
427
+ }
428
+ .crm-cta:hover {
429
+ background: var(--cr-cta-hover);
430
+ }
431
+ .crm-ghost {
432
+ padding: 11px 18px;
433
+ background: var(--cr-navy-06);
434
+ color: var(--cr-navy);
435
+ border: none;
436
+ border-radius: 8px;
437
+ font-size: 13px;
438
+ font-weight: 600;
439
+ font-family: var(--cr-sans);
440
+ cursor: pointer;
441
+ transition: background 0.15s;
442
+ }
443
+ .crm-ghost:hover {
444
+ background: var(--cr-ghost-hover);
445
+ }
446
+
447
+ /* Reviewer \u2014 identity row */
448
+ .crm-id {
449
+ display: flex;
450
+ align-items: center;
451
+ gap: 14px;
452
+ }
453
+ .crm-id__info {
454
+ min-width: 0;
455
+ }
456
+ .crm-id__name {
457
+ font-size: 16px;
458
+ font-weight: 700;
459
+ line-height: 1.25;
460
+ color: var(--cr-navy);
461
+ }
462
+ .crm-id__subtitle {
463
+ font-size: 12.5px;
464
+ line-height: 1.4;
465
+ color: var(--cr-navy-60);
466
+ margin-top: 2px;
467
+ }
468
+
469
+ /* Reviewer \u2014 credential chips */
470
+ .crm-chips {
471
+ display: flex;
472
+ flex-wrap: wrap;
473
+ gap: 7px;
474
+ margin-top: 16px;
475
+ }
476
+ .crm-chips__chip {
477
+ display: inline-flex;
478
+ align-items: center;
479
+ padding: 4px 10px;
480
+ border-radius: 999px;
481
+ background: var(--cr-navy-06);
482
+ color: var(--cr-navy);
483
+ font-size: 11px;
484
+ font-weight: 600;
485
+ }
486
+
487
+ /* Reviewer \u2014 bio */
488
+ .crm-bio {
489
+ margin: 16px 0 0;
490
+ font-size: 0.9rem;
491
+ line-height: 1.55;
492
+ color: var(--cr-navy-85);
493
+ }
494
+
495
+ /* Reviewer \u2014 trust line (the disclosure footer below now owns the spacing to the actions) */
496
+ .crm-trust {
497
+ display: flex;
498
+ align-items: center;
499
+ gap: 9px;
500
+ flex-wrap: wrap;
501
+ margin: 16px 0 0;
502
+ padding-top: 16px;
503
+ border-top: 1px solid var(--cr-navy-10);
504
+ }
505
+ .crm-trust__chip {
506
+ display: inline-flex;
507
+ align-items: center;
508
+ gap: 4px;
509
+ padding: 3px 8px;
510
+ border-radius: 4px;
511
+ background: var(--cr-lime);
512
+ color: var(--cr-navy);
513
+ font-family: var(--cr-mono);
514
+ font-size: 8.5px;
515
+ font-weight: 700;
516
+ letter-spacing: 0.08em;
517
+ text-transform: uppercase;
518
+ }
519
+ .crm-trust__text {
520
+ font-family: var(--cr-mono);
521
+ font-size: 9px;
522
+ letter-spacing: 0.05em;
523
+ color: var(--cr-navy-50);
524
+ }
525
+
526
+ /* FTC disclosure footer (POR-10496) \u2014 material-connection cue (compensated only) + scope line
527
+ * (always). Rendered on both the certificate + reviewer dialogs, immediately above the actions. */
528
+ .crm-disclosure {
529
+ margin-top: 14px;
530
+ padding-top: 14px;
531
+ border-top: 1px solid var(--cr-navy-10);
532
+ font-family: var(--cr-sans);
533
+ font-size: 11.5px;
534
+ line-height: 1.5;
535
+ color: var(--cr-navy-50);
536
+ }
537
+ .crm-disclosure__cue {
538
+ font-family: var(--cr-mono);
539
+ font-size: 10px;
540
+ font-weight: 700;
541
+ letter-spacing: 0.06em;
542
+ text-transform: uppercase;
543
+ color: var(--cr-navy);
544
+ }
545
+
546
+ /* Narrow storefronts / phones */
547
+ @media (max-width: 440px) {
548
+ .crm-body--cert {
549
+ padding: 20px 18px 22px;
550
+ }
551
+ .crm-body--expert {
552
+ padding: 18px 18px 20px;
553
+ }
554
+ }
555
+ `;var Ve=/^(dr|prof|professor|mr|mrs|ms|mx|rev|sir|dame)\.?\s+/i;function ne(e){let t=e.replace(Ve,"").trim(),r=t.indexOf(",");return(r===-1?t:t.slice(0,r)).trim()}function Ke(e){let t=ne(e).split(/\s+/).filter(Boolean);return t.length===0?"":t.length===1?t[0].slice(0,2).toUpperCase():(t[0][0]+t[t.length-1][0]).toUpperCase()}function qe(e){return ne(e)}function Ge(e){return e.replace(/^https?:\/\//i,"").replace(/\/$/,"")}function oe(e){return e&&/^https?:\/\//i.test(e.trim())?e.trim():"#"}function je(e){return(e.cardLabel||e.fullName||e.abbreviation||"").trim()}function ie(e){let t=[];for(let r of e?.credentials??[]){let n=je(r);n&&!t.includes(n)&&t.push(n)}return t}function Je(e,t){return t?.showBio===!1?"":(e?.background||e?.bio||"").trim()}function ae(e,t,r,n){let o=(e?.photoUrl||"").trim();if(n&&/^https?:\/\//i.test(o)){let i=r.includes("--64")?64:56,s=X(o,i===64?128:112);return`<img class="crm-avatar ${r}" src="${l(s)}" alt="" width="${i}" height="${i}" decoding="async">`}return`<span class="crm-avatar ${r}">${l(Ke(t))}</span>`}var se='<button type="button" class="crm-close" data-certrev-modal-close aria-label="Close">&times;</button>';function ce(e){return`<div class="crm-head">${ee(16,"#ffffff")}<span class="crm-head__eyebrow">${l(e)}</span><span class="crm-head__wordmark">CertREV</span></div>`}function le(e){return`<span class="${e}">${te(8)}Certified</span>`}function fe(e){let t=(e?.compensationCue||"").trim();return`<div class="crm-disclosure">${t?`<span class="crm-disclosure__cue">${l(t)}</span> `:""}${l(Q)}</div>`}function de(e){let t=e.expert??null,r=(t?.displayName||"").trim();if(!r)return null;let n=e.display?.showExpertPhoto!==!1,o=ie(t).join(" \xB7 "),i=I(e.certifiedAt)??"",s=(e.displayCertId||"").trim(),a=(e.articleTitle||"").trim(),c=(e.verifyUrl||"").trim(),f=qe(r),v=a?`<div class="crm-certifies"><div class="crm-certifies__eyebrow">Certifies the article</div><div class="crm-certifies__title">${l(a)}</div></div>`:"",h=s?`<div class="crm-meta__col"><div class="crm-meta__label">Certificate ID</div><div class="crm-meta__value crm-meta__value--mono">${l(s)}</div></div>`:"",ke=c?`<div class="crm-sig__url">${l(Ge(c))}</div>`:"";return`${se}${ce("Certificate of Expert Review")}<div class="crm-body--cert"><div class="crm-expert-row">${ae(t,r,"crm-avatar--56",n)}<div class="crm-expert-row__info"><div class="crm-expert-row__eyebrow">Reviewing Expert</div><div class="crm-expert-row__name">${l(r)}</div>${o?`<div class="crm-expert-row__creds">${l(o)}</div>`:""}</div></div>${v}<div class="crm-meta"><div class="crm-meta__col"><div class="crm-meta__label">Issued</div><div class="crm-meta__value">${l(i)}</div></div>${h}<div class="crm-meta__col"><div class="crm-meta__label">Status</div><div class="crm-meta__status">${le("crm-chip")}</div></div></div><div class="crm-sig"><div><div class="crm-sig__name">${l(f)}</div><div class="crm-sig__rule"></div>${ke}</div>${re("cert")}</div>${fe(t)}<div class="crm-actions"><a class="crm-cta" href="${l(oe(c))}" target="_blank" rel="noopener noreferrer">View full certificate</a><button type="button" class="crm-ghost" data-certrev-modal-close>Close</button></div></div>`}function pe(e){let t=e.expert??null,r=(t?.displayName||"").trim();if(!r)return null;let n=e.display?.showExpertPhoto!==!1,o=ie(t),i=Je(t,e.display),s=I(e.certifiedAt),a=o.length?`<div class="crm-chips">${o.map(v=>`<span class="crm-chips__chip">${l(v)}</span>`).join("")}</div>`:"",c=i?`<p class="crm-bio">${l(i)}</p>`:"",f=s?`Independently reviewed \xB7 Certified ${l(s)}`:"Independently reviewed";return`${se}${ce("Verified reviewer")}<div class="crm-body--expert"><div class="crm-id">${ae(t,r,"crm-avatar--64",n)}<div class="crm-id__info"><div class="crm-id__name">${l(r)}</div></div></div>${a}${c}<div class="crm-trust">${le("crm-trust__chip")}<span class="crm-trust__text">${f}</span></div>${fe(t)}<div class="crm-actions"><a class="crm-cta" href="${l(oe(t?.profileUrl))}" target="_blank" rel="noopener noreferrer">View full profile on CertREV</a><button type="button" class="crm-ghost" data-certrev-modal-close>Close</button></div></div>`}var w="certrev-cert-modal",E=null;function We(){return typeof CSSStyleSheet<"u"&&"replaceSync"in CSSStyleSheet.prototype&&"adoptedStyleSheets"in Document.prototype}function Ze(){return We()?(E||(E=new CSSStyleSheet,E.replaceSync(M)),E):null}var ue=!1;function Ye(e){if(ue||(ue=!0,e.querySelector("style[data-certrev-modal-fonts]")))return;if(!e.querySelector("link[data-certrev-modal-preconnect]")){let r=e.createElement("link");r.rel="preconnect",r.href=Y,r.crossOrigin="",r.setAttribute("data-certrev-modal-preconnect",""),e.head.appendChild(r)}let t=e.createElement("style");t.textContent=Z,t.setAttribute("data-certrev-modal-fonts",""),e.head.appendChild(t)}var $=class extends HTMLElement{constructor(){super();this.rendered=!1;this.content=null;this.fetchInFlight=null;this.root=this.attachShadow({mode:"open"});let r=Ze();if(r)this.root.adoptedStyleSheets=[r];else{let n=document.createElement("style");n.textContent=M,this.root.appendChild(n)}this.root.addEventListener("click",n=>this.onShadowClick(n))}open(r){return this.getAttribute("data-fonts")!=="host"&&Ye(document),this.ensureRendered()?(this.show(r),!0):this.hasFetchSource()?(this.fetchThenShow(r),!0):!1}ensureRendered(){if(this.rendered)return this.content!=null;let r=this.readSyncContent();return r?(this.content=r,this.renderDialogs(r),this.rendered=!0,!0):!1}readSyncContent(){let r=this.getAttribute("data-envelope");if(r)return me(r);let n=this.querySelector("script[data-certrev-envelope]");return n?.textContent?me(n.textContent):null}hasFetchSource(){return!!(this.getAttribute("data-delivery-api")&&this.getAttribute("data-platform")&&this.getAttribute("data-external-id"))}async fetchThenShow(r){if(!this.fetchInFlight){let n=(this.getAttribute("data-delivery-api")||"").replace(/\/$/,""),o=this.getAttribute("data-platform")||"",i=this.getAttribute("data-external-id")||"";this.fetchInFlight=(async()=>{try{let s=await fetch(`${n}/api/cert/v1/delivery/${encodeURIComponent(o)}/${encodeURIComponent(i)}`,{cache:"no-store",credentials:"omit"});if(!s.ok)return;let a=await s.json();if(Xe(a)){this.markSuppressed();return}let c=g(a)?void 0:a.payload?.content;c&&(this.content=c,this.renderDialogs(c),this.rendered=!0)}catch{}})()}await this.fetchInFlight,this.rendered&&this.show(r)}renderDialogs(r){let n=de(r),o=pe(r),i=document.createElement("div");i.innerHTML=`${n?`<dialog id="cert" class="crm-dialog crm-dialog--cert" aria-label="CertREV certificate">${n}</dialog>`:""}${o?`<dialog id="expert" class="crm-dialog crm-dialog--expert" aria-label="Verified reviewer profile">${o}</dialog>`:""}`;for(let s of Array.from(i.childNodes))this.root.appendChild(s)}show(r){let n=this.root.getElementById(r);n&&typeof n.showModal=="function"&&!n.open&&n.showModal()}markSuppressed(){this.setAttribute("data-certrev-suppressed","");for(let r of Array.from(document.querySelectorAll("[data-certrev-modal-open]")))r.setAttribute("hidden",""),r.setAttribute("aria-hidden","true")}onShadowClick(r){let n=r.target;if(!n)return;if(n instanceof HTMLDialogElement&&n.classList.contains("crm-dialog")){n.close();return}let o=n.closest("[data-certrev-modal-close]");o&&(r.preventDefault(),o.closest("dialog")?.close())}};function me(e){try{let t=JSON.parse(e);return t&&typeof t=="object"?t:null}catch{return null}}function Xe(e){if(!e)return!1;if(g(e))return!0;let t=e.payload?.lifecycle;return t?!!(t.revokedAt!=null||t.expiresAt&&Date.now()>=new Date(t.expiresAt).getTime()):!1}function Qe(){typeof customElements>"u"||customElements.get(w)||customElements.define(w,$)}Qe();var et="[data-ftc-line]",tt=".certrev-memo",rt=".certrev-memo-wrap",nt="data-certrev-ftc-neutralized",ye=new WeakSet;function ot(e){let t=e.ownerDocument.defaultView;if(!t)return!0;let r=t.getComputedStyle(e);if(r.display==="none"||r.visibility==="hidden"||Number.parseFloat(r.opacity||"1")===0)return!1;let n=e.getBoundingClientRect();return n.width>0&&n.height>0}function it(e){let t=e.querySelector(et);return!t||(t.textContent||"").trim()!==U?!1:ot(t)}function at(e){let r=e.ownerDocument.createElement("div");r.setAttribute(nt,""),r.style.cssText="font-family:system-ui,-apple-system,sans-serif;font-size:12px;color:#555;padding:12px;line-height:1.4",r.innerHTML='This CertREV verification cannot be displayed because its required disclosure was not shown. <a href="https://certrev.com" style="color:#555" target="_blank" rel="noopener noreferrer">Learn more</a>.',e.replaceWith(r)}function st(e){let t=!0;for(let r of Array.from(e.querySelectorAll(tt)))it(r)||(t=!1,at(r));return t}function ge(e){if(ye.has(e))return;ye.add(e);let t=()=>{st(e)},r=()=>{t();let n=e.defaultView?.MutationObserver;if(!n)return;let o=Array.from(e.querySelectorAll(rt)),i=o.length?o:e.body?[e.body]:[];for(let s of i)new n(t).observe(s,{childList:!0,subtree:!0,characterData:!0,attributes:!0})};e.readyState==="loading"?e.addEventListener("DOMContentLoaded",r,{once:!0}):r()}var ve="data-certrev-acc",A="data-certrev-modal-open",O="data-certrev-initials";var ct=["avatar","certrev-memo__avatar"],he=new WeakSet;function xe(e){let t=e.classList.toggle("open");e.setAttribute("aria-expanded",t?"true":"false")}function Ce(e){return e==="expert"?"expert":"cert"}function be(e,t){let r=e.querySelector(w);return r&&typeof r.open=="function"?r.open(t):!1}function Ue(e){return e&&e.closest?e:null}function Ee(e){let t=e.getAttribute(O);if(t==null)return;let r=ct.find(o=>e.classList.contains(o));if(!r)return;let n=e.ownerDocument.createElement("span");n.className=`${r} ${r}--initials`,n.setAttribute("aria-hidden","true"),n.textContent=t,e.replaceWith(n)}function lt(e){for(let t of Array.from(e.querySelectorAll(`img[${O}]`)))t.complete&&t.naturalWidth===0&&Ee(t)}function ft(e){he.has(e)||(he.add(e),e.addEventListener("click",t=>{let r=Ue(t.target);if(!r)return;let n=r.closest(`[${A}]`);if(n){be(e,Ce(n.getAttribute(A)))&&t.preventDefault();return}let o=r.closest(`[${ve}]`);o&&!r.closest("a, button")&&xe(o)}),e.addEventListener("error",t=>{let r=t.target;r&&r.tagName==="IMG"&&r.hasAttribute(O)&&Ee(r)},!0),lt(e),e.addEventListener("keydown",t=>{if(t.key!=="Enter"&&t.key!==" "&&t.key!=="Spacebar")return;let r=Ue(t.target);if(!r||r.closest("a, button"))return;let n=r.closest(`[${A}]`);if(n&&be(e,Ce(n.getAttribute(A)))){t.preventDefault();return}let o=r.closest(`[${ve}]`);o&&(t.preventDefault(),xe(o))}))}function we(e){let t=()=>ft(e);e.readyState==="loading"?e.addEventListener("DOMContentLoaded",t,{once:!0}):t()}var dt=[{selector:"main article",tier:"article"},{selector:"article",tier:"article"},{selector:"main",tier:"main"},{selector:".article-template__content",tier:"theme-class"},{selector:'[id^="ArticleContent"]',tier:"theme-class"},{selector:".rte",tier:"theme-class"}],m=[{selector:".article-template__content",tier:"theme-class"},{selector:'[id^="ArticleContent"]',tier:"theme-class"},{selector:".rte",tier:"theme-class"},{selector:"main article",tier:"article"},{selector:"article",tier:"article"},{selector:"main",tier:"main"}],N=m.map(e=>e.selector).join(", "),pt='header, [role="banner"], [class*="announcement"], footer, [role="contentinfo"], nav, [role="navigation"], cart-drawer, .cart-drawer, .drawer, .mini-cart, .modal, [role="dialog"]',p="data-certrev-placement",_e="data-certrev-anchor",ut='script[type="application/ld+json"][data-certrev-graph]',mt=".certrev-card-wrap",Se=".certrev-memo-wrap",yt=".certrev-pill-wrap",De=384,gt=24,_="#references";function S(e){for(let t=e;t;t=t.parentElement){if(t.hasAttribute("hidden")||t.getAttribute("aria-hidden")==="true")return!1;let r=getComputedStyle(t);if(r.display==="none"||r.visibility==="hidden")return!1}return!0}function P(e){return e.closest(pt)!==null}function Ae(e,t){for(let{selector:r,tier:n}of t)if(e.matches(r))return n;return"article"}function D(e,t,r){for(let{selector:n,tier:o}of r)for(let i of Array.from(e.querySelectorAll(n)))if(i!==t&&!i.contains(t)&&!t.contains(i)&&S(i)&&!P(i))return{el:i,tier:o};return null}function z(e,t){let r=t.getAttribute(p);if(r)return{anchored:r!=="body-fallback",tier:r};let n=t.getAttribute(_e);if(n==="rail"){let a=e.querySelector(_)?.closest(N)??D(e,t,m)?.el??null,c=e.defaultView;if(a&&c&&S(a)&&!P(a)){let f=a.getBoundingClientRect();if(c.innerWidth-f.right>=De)return t.style.setProperty("--certrev-rail-left",`${Math.round(f.right+gt)}px`),t.setAttribute(p,"rail"),{anchored:!0,tier:"rail"};a.insertAdjacentElement("afterbegin",t);let h=Ae(a,m);return t.setAttribute(p,h),{anchored:!0,tier:h}}return t.setAttribute(p,"body-fallback"),{anchored:!1,tier:"body-fallback"}}let o=n==="bottom"?"bottom":"top",i="body-fallback";if(o==="top"){let a=e.querySelector(_)?.closest(N)??null;if(a&&a!==t&&!a.contains(t)&&!t.contains(a)&&S(a)&&!P(a))a.insertAdjacentElement("afterbegin",t),i=Ae(a,m);else{let c=D(e,t,m);c&&(c.el.insertAdjacentElement("afterbegin",t),i=c.tier)}}else{let s=e.querySelector(_);if(s&&s!==t&&!t.contains(s)&&!s.contains(t)&&S(s))s.insertAdjacentElement("beforebegin",t),i="references";else{let a=D(e,t,dt);a&&(a.el.insertAdjacentElement("afterend",t),i=a.tier)}}return t.setAttribute(p,i),{anchored:i!=="body-fallback",tier:i}}function vt(e){let t=e.querySelector(ut),r=!1;t&&t.parentNode!==e.head&&(e.head.appendChild(t),r=!0);let n=e.querySelector(mt),o=e.querySelector(Se);return e.querySelector(yt)?.setAttribute(p,"pill-fixed"),{graph:r,card:n?z(e,n):null,memo:o?z(e,o):null}}function ht(e){let t=e.defaultView;if(!t)return;let r=e.querySelector(`${Se}[${_e}="rail"]`);if(!r||r.getAttribute(p)!=="rail")return;let n,o=()=>{n&&clearTimeout(n),n=setTimeout(()=>{if(r.getAttribute(p)!=="rail"){t.removeEventListener("resize",o);return}let s=e.querySelector(_)?.closest(N)??D(e,r,m)?.el??null;(s?t.innerWidth-s.getBoundingClientRect().right:0)<De&&(r.style.removeProperty("--certrev-rail-left"),r.removeAttribute(p),z(e,r),t.removeEventListener("resize",o))},150)};t.addEventListener("resize",o)}function Fe(e){let t=()=>{vt(e),ht(e)};e.readyState==="loading"?e.addEventListener("DOMContentLoaded",t,{once:!0}):t()}async function xt(e,t){let r=e.querySelector(".certrev-badge");if(!r)return;let n=e.getAttribute("data-delivery-api"),o=e.getAttribute("data-external-id"),i=e.getAttribute("data-platform")??"shopify";if(!n||!o)return;let s;try{s=await t.verify({baseUrl:n,platform:i,externalId:o})}catch{return}s.decision!=="render"&&(r.setAttribute("hidden",""),r.setAttribute("data-certrev-suppressed",s.reason))}function Te(e,t){let r=()=>{for(let n of Array.from(e.querySelectorAll("certrev-badge[revalidate]")))xt(n,t)};e.readyState==="loading"?e.addEventListener("DOMContentLoaded",r,{once:!0}):r()}function Re(e,t=fetch){return async r=>{let o=`${r.baseUrl.replace(/\/+$/,"")}/api/cert/v1/delivery/${encodeURIComponent(r.platform)}/${encodeURIComponent(r.externalId)}`,i=await t(o,{headers:{accept:"application/json"}});if(!i.ok)throw new Error(`cert delivery ${i.status}`);let s=await i.json();return L(s,e,{platform:r.platform,externalId:r.externalId,liveContentHash:null,now:new Date})}}var Ct="cert-issuer-1",bt=`-----BEGIN PUBLIC KEY-----
556
+ MCowBQYDK2VwAyEAMWN956IOPjpAq900dL428VzA28TO/pVXnq3brwqUmwM=
557
+ -----END PUBLIC KEY-----`,Ut=e=>e===Ct?{format:"pem",pem:bt}:null;typeof document<"u"&&(Fe(document),we(document),ge(document),Te(document,{verify:Re(Ut)}));})();
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Cert-render display strings + date formatter for the MODAL — a BYTE-FAITHFUL relocation of
3
+ * portal `src/lib/cert-delivery/display-strings.ts` (POR-10721 W2). Kept a SEPARATE module from
4
+ * ftc-disclosure.ts (matching portal) so the bundle's `var` layout is byte-identical to the live asset.
5
+ *
6
+ * ⚠ Deliberately SEPARATE from `../components/render-def.ts`/`format.ts`. `formatCertDisplayDate`
7
+ * uses `toLocaleDateString` (NOT the components' fixed MONTHS array): the live modal formats dates
8
+ * via `toLocaleDateString` at runtime in the browser, so a fixed-array formatter would VISIBLY
9
+ * diverge on any browser whose ICU renders a month abbreviation differently (the "Sep"/"Sept"
10
+ * CLDR-42 case). Byte-parity with the deployed asset requires preserving the exact source.
11
+ */
12
+ /** The compensation cue (guide "line A"), byte-verbatim from portal `COMPENSATED_EXPERT_CUE`. */
13
+ export declare const COMPENSATED_EXPERT_CUE = "Compensated expert";
14
+ /** The FTC scope disclaimer, re-exported from the FTC SoT (portal `CERT_SCOPE_LINE = FTC_DISCLOSURE_LINE`). */
15
+ export declare const CERT_SCOPE_LINE: "Independent editorial review of this article’s text and sources. Not a product endorsement, nor medical advice.";
16
+ /**
17
+ * Format a timestamp the way every cert byline renders dates ("Jun 14, 2026", en-US short month,
18
+ * UTC-pinned). Byte-faithful to portal `formatCertDisplayDate`. Null for an unparseable input —
19
+ * callers treat that as "no date, no byline".
20
+ */
21
+ export declare function formatCertDisplayDate(iso: string | Date | null | undefined): string | null;
22
+ //# sourceMappingURL=display-strings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-strings.d.ts","sourceRoot":"","sources":["../../src/modal/display-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,iGAAiG;AACjG,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;AAE3D,+GAA+G;AAC/G,eAAO,MAAM,eAAe,mHAAsB,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACpC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,GACnC,MAAM,GAAG,IAAI,CAUf"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Cert-render display strings + date formatter for the MODAL — a BYTE-FAITHFUL relocation of
3
+ * portal `src/lib/cert-delivery/display-strings.ts` (POR-10721 W2). Kept a SEPARATE module from
4
+ * ftc-disclosure.ts (matching portal) so the bundle's `var` layout is byte-identical to the live asset.
5
+ *
6
+ * ⚠ Deliberately SEPARATE from `../components/render-def.ts`/`format.ts`. `formatCertDisplayDate`
7
+ * uses `toLocaleDateString` (NOT the components' fixed MONTHS array): the live modal formats dates
8
+ * via `toLocaleDateString` at runtime in the browser, so a fixed-array formatter would VISIBLY
9
+ * diverge on any browser whose ICU renders a month abbreviation differently (the "Sep"/"Sept"
10
+ * CLDR-42 case). Byte-parity with the deployed asset requires preserving the exact source.
11
+ */
12
+ import { FTC_DISCLOSURE_LINE } from "./ftc-disclosure.js";
13
+ /** The compensation cue (guide "line A"), byte-verbatim from portal `COMPENSATED_EXPERT_CUE`. */
14
+ export const COMPENSATED_EXPERT_CUE = "Compensated expert";
15
+ /** The FTC scope disclaimer, re-exported from the FTC SoT (portal `CERT_SCOPE_LINE = FTC_DISCLOSURE_LINE`). */
16
+ export const CERT_SCOPE_LINE = FTC_DISCLOSURE_LINE;
17
+ /**
18
+ * Format a timestamp the way every cert byline renders dates ("Jun 14, 2026", en-US short month,
19
+ * UTC-pinned). Byte-faithful to portal `formatCertDisplayDate`. Null for an unparseable input —
20
+ * callers treat that as "no date, no byline".
21
+ */
22
+ export function formatCertDisplayDate(iso) {
23
+ if (!iso)
24
+ return null;
25
+ const date = iso instanceof Date ? iso : new Date(iso);
26
+ if (Number.isNaN(date.getTime()))
27
+ return null;
28
+ return date.toLocaleDateString("en-US", {
29
+ month: "short",
30
+ day: "numeric",
31
+ year: "numeric",
32
+ timeZone: "UTC",
33
+ });
34
+ }
35
+ //# sourceMappingURL=display-strings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-strings.js","sourceRoot":"","sources":["../../src/modal/display-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,iGAAiG;AACjG,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAE3D,+GAA+G;AAC/G,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAEnD;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACpC,GAAqC;IAErC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,IAAI,GAAG,GAAG,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IACvD,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE;QACvC,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,KAAK;KACf,CAAC,CAAC;AACJ,CAAC"}