@redsift/products 12.5.7 → 12.5.8-muiv7

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.
@@ -404,6 +404,50 @@ var EXTRACTOR_STRINGS = {
404
404
  "card.bimi.vmc.issuer_md": "**Issuer: {issuer}**",
405
405
  "card.bimi.vmc.trademarkAuthority_md": "**Trademark Authority: {trademarkAuthority}**",
406
406
  "card.bimi.vmc.valid-for-domain_md": "**Valid for domains:** `{domains}`",
407
+ // BIMI VMC/CMC published-certificate metadata (WEB-1137 / DS-93)
408
+ // Validity
409
+ "card.bimi.vmc.cert-section-validity": "Validity",
410
+ "card.bimi.vmc.cert-valid-from_md": "**Start:** {date}",
411
+ "card.bimi.vmc.cert-expiry_md": "**Expiry:** {date}",
412
+ // Certificate-validity widget (WEB-1139 / DS-93) — cell labels + status pill.
413
+ // Replaces the WEB-1138 duration prose; the widget formats the dates itself.
414
+ "card.bimi.vmc.cert-issued-label": "Issued",
415
+ "card.bimi.vmc.cert-expires-label": "Expires",
416
+ "card.bimi.vmc.cert-status-label": "Status",
417
+ "card.bimi.vmc.cert-status-valid": "Valid",
418
+ "card.bimi.vmc.cert-status-days-left_one": "{count} day left",
419
+ "card.bimi.vmc.cert-status-days-left_other": "{count} days left",
420
+ "card.bimi.vmc.cert-status-expires-today": "Expires today",
421
+ "card.bimi.vmc.cert-status-expired_one": "Expired {count} day ago",
422
+ "card.bimi.vmc.cert-status-expired_other": "Expired {count} days ago",
423
+ "card.bimi.vmc.cert-status-not-yet-active": "Not yet active",
424
+ // Certificate
425
+ "card.bimi.vmc.cert-section-certificate": "Certificate",
426
+ "card.bimi.vmc.cert-issuer-common-name_md": "**Issuer:** {issuerCommonName}",
427
+ "card.bimi.vmc.cert-issuer-organization_md": "**Issuer organization:** {issuerOrganization}",
428
+ "card.bimi.vmc.cert-issuer-country_md": "**Issuer country:** {issuerCountry}",
429
+ "card.bimi.vmc.cert-type_md": "**Certificate type:** {assertionMarkType}",
430
+ "card.bimi.vmc.cert-certified-domains_md": "**Certified domains:** `{certifiedDomains}`",
431
+ // Subject identity
432
+ "card.bimi.vmc.cert-section-subject-identity": "Subject identity",
433
+ "card.bimi.vmc.cert-serial-number_md": "**Serial number:** {serialNumber}",
434
+ "card.bimi.vmc.cert-organization_md": "**Organization:** {organization}",
435
+ "card.bimi.vmc.cert-common-name_md": "**Common name:** {commonName}",
436
+ "card.bimi.vmc.cert-business-category_md": "**Business category:** {businessCategory}",
437
+ "card.bimi.vmc.cert-organization-identifier_md": "**Organization identifier:** {organizationIdentifier}",
438
+ "card.bimi.vmc.cert-legal-entity-identifier_md": "**Legal entity identifier:** {legalEntityIdentifier}",
439
+ "card.bimi.vmc.cert-jurisdiction_md": "**Jurisdiction:** {jurisdiction}",
440
+ "card.bimi.vmc.cert-address_md": "**Address:** {address}",
441
+ // Mark evidence
442
+ "card.bimi.vmc.cert-section-mark-evidence": "Mark evidence",
443
+ "card.bimi.vmc.cert-trademark-registration_md": "**Trademark registration:** {trademarkRegistration}",
444
+ "card.bimi.vmc.cert-trademark-office_md": "**Trademark office:** {trademarkOfficeName}",
445
+ "card.bimi.vmc.cert-mark-type_md": "**Mark type:** {markType}",
446
+ "card.bimi.vmc.cert-trademark-country_md": "**Trademark country or region:** {trademarkCountryOrRegion}",
447
+ // Verification issues
448
+ "card.bimi.vmc.cert-section-verification-issues": "Verification issues",
449
+ "card.bimi.vmc.cert-no-issues-reported_md": "None reported",
450
+ "card.bimi.vmc.cert-ambiguous-leaf_md": "Ambiguous leaf certificate selection",
407
451
  // BIMI section titles
408
452
  "section-titles.bimi-domain": "DMARC Domains",
409
453
  "section-titles.bimi-policy": "Your BIMI Policy",
@@ -843,6 +887,50 @@ var EXTRACTOR_STRINGS = {
843
887
  "card.bimi.vmc.issuer_md": "**Issuer : {issuer}**",
844
888
  "card.bimi.vmc.trademarkAuthority_md": "**Autorit\xE9 de la marque : {trademarkAuthority}**",
845
889
  "card.bimi.vmc.valid-for-domain_md": "**Valide pour les domaines :** `{domains}`",
890
+ // BIMI VMC/CMC published-certificate metadata (WEB-1137 / DS-93)
891
+ // Validity
892
+ "card.bimi.vmc.cert-section-validity": "Validit\xE9",
893
+ "card.bimi.vmc.cert-valid-from_md": "**D\xE9but :** {date}",
894
+ "card.bimi.vmc.cert-expiry_md": "**Expiration :** {date}",
895
+ // Certificate-validity widget (WEB-1139 / DS-93) — cell labels + status pill.
896
+ // Replaces the WEB-1138 duration prose; the widget formats the dates itself.
897
+ "card.bimi.vmc.cert-issued-label": "\xC9mis",
898
+ "card.bimi.vmc.cert-expires-label": "Expire",
899
+ "card.bimi.vmc.cert-status-label": "Statut",
900
+ "card.bimi.vmc.cert-status-valid": "Valide",
901
+ "card.bimi.vmc.cert-status-days-left_one": "Expire dans {count} jour",
902
+ "card.bimi.vmc.cert-status-days-left_other": "Expire dans {count} jours",
903
+ "card.bimi.vmc.cert-status-expires-today": "Expire aujourd'hui",
904
+ "card.bimi.vmc.cert-status-expired_one": "Expir\xE9 il y a {count} jour",
905
+ "card.bimi.vmc.cert-status-expired_other": "Expir\xE9 il y a {count} jours",
906
+ "card.bimi.vmc.cert-status-not-yet-active": "Pas encore actif",
907
+ // Certificate
908
+ "card.bimi.vmc.cert-section-certificate": "Certificat",
909
+ "card.bimi.vmc.cert-issuer-common-name_md": "**\xC9metteur :** {issuerCommonName}",
910
+ "card.bimi.vmc.cert-issuer-organization_md": "**Organisation de l'\xE9metteur :** {issuerOrganization}",
911
+ "card.bimi.vmc.cert-issuer-country_md": "**Pays de l'\xE9metteur :** {issuerCountry}",
912
+ "card.bimi.vmc.cert-type_md": "**Type de certificat :** {assertionMarkType}",
913
+ "card.bimi.vmc.cert-certified-domains_md": "**Domaines certifi\xE9s :** `{certifiedDomains}`",
914
+ // Subject identity
915
+ "card.bimi.vmc.cert-section-subject-identity": "Identit\xE9 du sujet",
916
+ "card.bimi.vmc.cert-serial-number_md": "**Num\xE9ro de s\xE9rie :** {serialNumber}",
917
+ "card.bimi.vmc.cert-organization_md": "**Organisation :** {organization}",
918
+ "card.bimi.vmc.cert-common-name_md": "**Nom commun :** {commonName}",
919
+ "card.bimi.vmc.cert-business-category_md": "**Cat\xE9gorie d'activit\xE9 :** {businessCategory}",
920
+ "card.bimi.vmc.cert-organization-identifier_md": "**Identifiant de l'organisation :** {organizationIdentifier}",
921
+ "card.bimi.vmc.cert-legal-entity-identifier_md": "**Identifiant d'entit\xE9 juridique :** {legalEntityIdentifier}",
922
+ "card.bimi.vmc.cert-jurisdiction_md": "**Juridiction :** {jurisdiction}",
923
+ "card.bimi.vmc.cert-address_md": "**Adresse :** {address}",
924
+ // Mark evidence
925
+ "card.bimi.vmc.cert-section-mark-evidence": "Preuve de la marque",
926
+ "card.bimi.vmc.cert-trademark-registration_md": "**Enregistrement de la marque :** {trademarkRegistration}",
927
+ "card.bimi.vmc.cert-trademark-office_md": "**Office des marques :** {trademarkOfficeName}",
928
+ "card.bimi.vmc.cert-mark-type_md": "**Type de marque :** {markType}",
929
+ "card.bimi.vmc.cert-trademark-country_md": "**Pays ou r\xE9gion de la marque :** {trademarkCountryOrRegion}",
930
+ // Verification issues
931
+ "card.bimi.vmc.cert-section-verification-issues": "Probl\xE8mes de v\xE9rification",
932
+ "card.bimi.vmc.cert-no-issues-reported_md": "Aucun signal\xE9",
933
+ "card.bimi.vmc.cert-ambiguous-leaf_md": "S\xE9lection ambigu\xEB du certificat feuille",
846
934
  // BIMI section titles
847
935
  "section-titles.bimi-domain": "Domaines DMARC",
848
936
  "section-titles.bimi-policy": "Votre politique BIMI",
@@ -1296,7 +1384,7 @@ var enUS = {
1296
1384
  "investigate.card.dmarc.permerror-rua-fallback_md": "A valid reporting URI ([](RUA#:glossary)) is present, so receivers will fall back to acting as if the policy is **p=none**.",
1297
1385
  "investigate.card.dmarc.summary-domain-temperror": "The domain's DMARC record could not be retrieved due to a DNS error.",
1298
1386
  "investigate.card.subdo.not-detected": "No SubdoMailers Detected",
1299
- "investigate.card.subdo.button-name": "Check SPF",
1387
+ "investigate.card.subdo.button-name": "View in SPF Checker",
1300
1388
  "investigate.card.subdo.detected": "SubdoMailers Detected",
1301
1389
  "investigate.card.subdo.blog": "You can have a full view of your SPF setup on our SPF Checker, or learn more about the SubdoMailing attack on our knowledge base.",
1302
1390
  "investigate.card.subdo.spf-subdo-poisoned-include_md": "Compromised include: **{raw}**",
@@ -2011,7 +2099,7 @@ var frFR = {
2011
2099
  "investigate.card.dmarc.txt-published-policy-on-domain_md_one": "[](TXT_RECORD#:glossary) publié sur `{policyDomain}`",
2012
2100
  "investigate.card.dmarc.txt-published-policy-on-domain_md_other": "{count} [](TXT_RECORDS#:glossary) publié sur `{policyDomain}`",
2013
2101
  "investigate.card.subdo.not-detected": "Aucun SubdoMailer n'a été détecté",
2014
- "investigate.card.subdo.button-name": "Vérifier SPF",
2102
+ "investigate.card.subdo.button-name": "Voir dans le vérificateur SPF",
2015
2103
  "investigate.card.subdo.detected": "SubdoMailers détectés",
2016
2104
  "investigate.card.subdo.blog": "Vous pouvez obtenir un aperçu complet de votre configuration SPF sur notre vérificateur SPF, ou en savoir plus sur l'attaque SubdoMailing sur notre base de connaissances.",
2017
2105
  "investigate.card.subdo.spf-subdo-poisoned-include_md": "Inclusion compromise : **{raw}**",
@@ -2041,12 +2129,12 @@ var frFR = {
2041
2129
  "investigate.card.spf.txt-published-policy-on-domain_md_one": "[](TXT_RECORD#:glossary) publié sur `{policyDomain}`",
2042
2130
  "investigate.card.spf.txt-published-policy-on-domain_md_other": "{count} [](TXT_RECORDS#:glossary) publié sur `{policyDomain}`",
2043
2131
  "investigate.card.fcrdns.sender-ip-match-ehlo-all_md": "Le [](SENDER_IP#:glossary) correspond au [](EHLO#:glossary) dans les deux sens.",
2044
- "investigate.card.dkim.selector-statuses.pass_one": "Sélecteur { count } passé",
2045
- "investigate.card.dkim.selector-statuses.pass_other": "{ count } sélecteurs passés",
2046
- "investigate.card.dkim.selector-statuses.fail_one": "Le sélecteur { count } a échoué",
2047
- "investigate.card.dkim.selector-statuses.fail_other": "Les sélecteurs { count } ont échoué",
2048
- "investigate.card.dkim.selector-statuses.warning_one": "Sélecteur { count } avec avertissements",
2049
- "investigate.card.dkim.selector-statuses.warning_other": "Sélecteurs { count } avec avertissements",
2132
+ "investigate.card.dkim.selector-statuses.pass_one": "{count} sélecteur réussi",
2133
+ "investigate.card.dkim.selector-statuses.pass_other": "{count} sélecteurs réussis",
2134
+ "investigate.card.dkim.selector-statuses.fail_one": "{count} sélecteur échoué",
2135
+ "investigate.card.dkim.selector-statuses.fail_other": "{count} sélecteurs échoués",
2136
+ "investigate.card.dkim.selector-statuses.warning_one": "{count} sélecteur avec des avertissements",
2137
+ "investigate.card.dkim.selector-statuses.warning_other": "{count} sélecteurs avec des avertissements",
2050
2138
  "investigate.card.dkim.error-raw_md": [
2051
2139
  "Il s'agit de l'erreur brute :",
2052
2140
  "```{error}```"
@@ -2936,8 +3024,8 @@ function useCollapseController(_ref) {
2936
3024
  */
2937
3025
 
2938
3026
  // Default fallback values - use DS CSS variables with hardcoded ultimate fallbacks
2939
- const DS_FONT_BODY$8 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
2940
- const DS_TEXT_COLOR$4 = 'var(--redsift-color-neutral-x-dark-grey, #3B3A58)';
3027
+ const DS_FONT_BODY$9 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
3028
+ const DS_TEXT_COLOR$5 = 'var(--redsift-color-neutral-x-dark-grey, #3B3A58)';
2941
3029
 
2942
3030
  /**
2943
3031
  * Intro text container for signal cards.
@@ -2949,8 +3037,8 @@ const StyledIntroText = styled.div`
2949
3037
  margin-bottom: 0.75rem;
2950
3038
  font-size: 14px;
2951
3039
  line-height: 1.5;
2952
- font-family: var(--sc-font-body, ${DS_FONT_BODY$8});
2953
- color: var(--sc-text-color, ${DS_TEXT_COLOR$4});
3040
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$9});
3041
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$5});
2954
3042
 
2955
3043
  strong {
2956
3044
  font-weight: 600;
@@ -2992,18 +3080,18 @@ const StyledCardFooter = styled.div`
2992
3080
  // ============================================================================
2993
3081
 
2994
3082
  // Default fallback values - use DS CSS variables with hardcoded ultimate fallbacks
2995
- const DS_FONT_BODY$7 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
2996
- const DS_TEXT_COLOR$3 = 'var(--redsift-color-neutral-x-dark-grey, #3B3A58)';
3083
+ const DS_FONT_BODY$8 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
3084
+ const DS_TEXT_COLOR$4 = 'var(--redsift-color-neutral-x-dark-grey, #3B3A58)';
2997
3085
  const DS_LINK_COLOR$1 = 'var(--redsift-color-notifications-info-primary, #4285f4)';
2998
3086
  const DescriptionContainer = styled.div`
2999
3087
  display: flex;
3000
3088
  flex-direction: column;
3001
3089
  `;
3002
3090
  const DescriptionText = styled.div`
3003
- font-family: var(--sc-font-body, ${DS_FONT_BODY$7});
3091
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$8});
3004
3092
  font-size: 14px;
3005
3093
  line-height: 1.5;
3006
- color: var(--sc-text-color, ${DS_TEXT_COLOR$3});
3094
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$4});
3007
3095
 
3008
3096
  p {
3009
3097
  margin: 0 0 1rem;
@@ -3296,7 +3384,7 @@ ExpandableDescription.displayName = 'ExpandableDescription';
3296
3384
  // these will be overridden with Investigate-specific fonts.
3297
3385
 
3298
3386
  // Default fallback values - use DS CSS variables with hardcoded ultimate fallbacks
3299
- const DS_FONT_BODY$6 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
3387
+ const DS_FONT_BODY$7 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
3300
3388
  const StyledContainer$1 = styled.div`
3301
3389
  display: ${_ref => {
3302
3390
  let {
@@ -3319,14 +3407,14 @@ const StyledContainer$1 = styled.div`
3319
3407
  } = _ref3;
3320
3408
  return $borderBottom && $marginBottom === 0 ? '0.5rem' : `${$marginBottom}px`;
3321
3409
  }};
3322
- font-family: var(--sc-font-body, ${DS_FONT_BODY$6});
3410
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$7});
3323
3411
 
3324
3412
  &:first-child {
3325
3413
  margin-top: 0;
3326
3414
  }
3327
3415
 
3328
3416
  > h2 {
3329
- font-family: var(--sc-font-body, ${DS_FONT_BODY$6});
3417
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$7});
3330
3418
  font-size: 1.35rem;
3331
3419
  font-weight: 600;
3332
3420
  margin: 0 0 0.25rem;
@@ -3364,9 +3452,9 @@ var SignalCardSection$1 = SignalCardSection;
3364
3452
  // ============================================================================
3365
3453
 
3366
3454
  // Default fallback values - use DS CSS variables with hardcoded ultimate fallbacks
3367
- const DS_FONT_BODY$5 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
3455
+ const DS_FONT_BODY$6 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
3368
3456
  const DS_FONT_CODE$2 = "var(--redsift-typography-font-family-source-code-pro, 'Source Code Pro', monospace)";
3369
- const DS_TEXT_COLOR$2 = 'var(--redsift-color-neutral-x-dark-grey, #3B3A58)';
3457
+ const DS_TEXT_COLOR$3 = 'var(--redsift-color-neutral-x-dark-grey, #3B3A58)';
3370
3458
  const DS_BG_LIGHT$2 = 'var(--redsift-color-neutral-x-light-grey, #EAEAED)';
3371
3459
  const InfoItemContainer = styled.div`
3372
3460
  padding: ${_ref => {
@@ -3386,10 +3474,10 @@ const InfoItemRow = styled.div`
3386
3474
  }};
3387
3475
  gap: 0.75rem;
3388
3476
  flex-wrap: wrap;
3389
- font-family: var(--sc-font-body, ${DS_FONT_BODY$5});
3477
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$6});
3390
3478
  font-size: 14px;
3391
3479
  line-height: 1.5;
3392
- color: var(--sc-text-color, ${DS_TEXT_COLOR$2});
3480
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$3});
3393
3481
  `;
3394
3482
  const InfoItemIcon = styled.span`
3395
3483
  display: inline-flex;
@@ -3452,10 +3540,10 @@ const InfoItemLabel = styled.span`
3452
3540
  `;
3453
3541
  const InfoItemSubtexts = styled.div`
3454
3542
  margin: 0;
3455
- font-family: var(--sc-font-body, ${DS_FONT_BODY$5});
3543
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$6});
3456
3544
  font-size: 14px;
3457
3545
  line-height: 1.5;
3458
- color: var(--sc-text-color, ${DS_TEXT_COLOR$2});
3546
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$3});
3459
3547
 
3460
3548
  ${_ref6 => {
3461
3549
  let {
@@ -3480,7 +3568,7 @@ const InfoItemSubtexts = styled.div`
3480
3568
  code {
3481
3569
  background-color: var(--sc-code-bg, ${DS_BG_LIGHT$2});
3482
3570
  font-family: var(--sc-font-code, ${DS_FONT_CODE$2});
3483
- color: var(--sc-text-color, ${DS_TEXT_COLOR$2});
3571
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$3});
3484
3572
  padding: 0.2em 0.5em;
3485
3573
  border-radius: 3px;
3486
3574
  white-space: pre-wrap;
@@ -3505,7 +3593,7 @@ const InfoItemList = styled.ul`
3505
3593
  code {
3506
3594
  background-color: var(--sc-code-bg, ${DS_BG_LIGHT$2});
3507
3595
  font-family: var(--sc-font-code, ${DS_FONT_CODE$2});
3508
- color: var(--sc-text-color, ${DS_TEXT_COLOR$2});
3596
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$3});
3509
3597
  padding: 0.2em 0.5em;
3510
3598
  border-radius: 3px;
3511
3599
  white-space: pre-wrap;
@@ -3522,7 +3610,7 @@ const InfoItemList = styled.ul`
3522
3610
  const InfoItemCodeBlock = styled.pre`
3523
3611
  background-color: var(--sc-code-bg, ${DS_BG_LIGHT$2});
3524
3612
  font-family: var(--sc-font-code, ${DS_FONT_CODE$2});
3525
- color: var(--sc-text-color, ${DS_TEXT_COLOR$2});
3613
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$3});
3526
3614
  font-size: 14px;
3527
3615
  padding: 0.5em;
3528
3616
  border-radius: 4px;
@@ -3565,10 +3653,10 @@ InfoItemsWrapper.displayName = 'InfoItemsWrapper';
3565
3653
  // these will be overridden with Investigate-specific fonts.
3566
3654
 
3567
3655
  // Default fallback values - use DS CSS variables with hardcoded ultimate fallbacks
3568
- const DS_FONT_BODY$4 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
3656
+ const DS_FONT_BODY$5 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
3569
3657
  const StyledContainer = styled.div`
3570
3658
  border-radius: 4px;
3571
- font-family: var(--sc-font-body, ${DS_FONT_BODY$4});
3659
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$5});
3572
3660
  > div {
3573
3661
  display: grid;
3574
3662
  padding: 0;
@@ -3609,7 +3697,7 @@ var SignalCardInfoBox$1 = SignalCardInfoBox;
3609
3697
  // these will be overridden with Investigate-specific fonts.
3610
3698
 
3611
3699
  // Default fallback values - use DS CSS variables with hardcoded ultimate fallbacks
3612
- const DS_FONT_BODY$3 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
3700
+ const DS_FONT_BODY$4 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
3613
3701
  const DEFAULT_PALETTE = {
3614
3702
  base: '#e5e5e5',
3615
3703
  hover: '#d6d6d6'
@@ -3678,7 +3766,7 @@ const StyledGlossaryTag = styled.a`
3678
3766
  user-select: none;
3679
3767
  font-size: 14px;
3680
3768
  font-weight: 400;
3681
- font-family: var(--sc-font-body, ${DS_FONT_BODY$3});
3769
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$4});
3682
3770
  white-space: nowrap;
3683
3771
  line-height: 1.3;
3684
3772
  color: ${COLOR.grey.darkest} !important;
@@ -4583,26 +4671,26 @@ const EXTRACTION_CAPTION_KEYS = {
4583
4671
  // ============================================================================
4584
4672
 
4585
4673
  // Default fallback values - use DS CSS variables with hardcoded ultimate fallbacks
4586
- const DS_FONT_BODY$2 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
4674
+ const DS_FONT_BODY$3 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
4587
4675
  const DS_FONT_CODE$1 = "var(--redsift-typography-font-family-source-code-pro, 'Source Code Pro', monospace)";
4588
- const DS_TEXT_COLOR$1 = 'var(--redsift-color-neutral-x-dark-grey, #3B3A58)';
4676
+ const DS_TEXT_COLOR$2 = 'var(--redsift-color-neutral-x-dark-grey, #3B3A58)';
4589
4677
  const DS_BG_LIGHT$1 = 'var(--redsift-color-neutral-x-light-grey, #EAEAED)';
4590
4678
  styled.div`
4591
4679
  padding: 0;
4592
4680
  margin-bottom: 0.25rem;
4593
- font-family: var(--sc-font-body, ${DS_FONT_BODY$2});
4681
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$3});
4594
4682
  line-height: normal;
4595
4683
  `;
4596
4684
  styled.span`
4597
4685
  margin: 0;
4598
4686
  margin-right: 0.5rem;
4599
- font-family: var(--sc-font-body, ${DS_FONT_BODY$2});
4687
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$3});
4600
4688
  font-size: 16px;
4601
4689
  font-weight: 600;
4602
- color: var(--sc-text-color, ${DS_TEXT_COLOR$1});
4690
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$2});
4603
4691
  `;
4604
4692
  styled.span`
4605
- font-family: var(--sc-font-body, ${DS_FONT_BODY$2});
4693
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$3});
4606
4694
  font-size: 12px;
4607
4695
  font-weight: 400;
4608
4696
  color: ${COLOR.grey.medium};
@@ -4657,10 +4745,10 @@ const InfoItemsGrid = styled.div`
4657
4745
  word-break: break-word;
4658
4746
  border-radius: ${props => props.$insideCollapsible ? '0' : '4px'};
4659
4747
  margin: ${props => props.$insideCollapsible ? '0' : 'initial'};
4660
- font-family: var(--sc-font-body, ${DS_FONT_BODY$2});
4748
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$3});
4661
4749
  font-size: 14px;
4662
4750
  line-height: 1.5;
4663
- color: var(--sc-text-color, ${DS_TEXT_COLOR$1});
4751
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$2});
4664
4752
  `;
4665
4753
  const GridLabel = styled.div`
4666
4754
  display: flex;
@@ -4680,10 +4768,10 @@ const GridLabel = styled.div`
4680
4768
  const GridValue = styled.div`
4681
4769
  display: flex;
4682
4770
  align-items: center;
4683
- font-family: var(--sc-font-body, ${DS_FONT_BODY$2});
4771
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$3});
4684
4772
  font-size: 14px;
4685
4773
  font-weight: 600;
4686
- color: var(--sc-text-color, ${DS_TEXT_COLOR$1});
4774
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$2});
4687
4775
  word-break: break-all;
4688
4776
 
4689
4777
  p {
@@ -4708,7 +4796,7 @@ const GridValue = styled.div`
4708
4796
  const CodeBlock = styled.div`
4709
4797
  font-family: var(--sc-font-code, ${DS_FONT_CODE$1});
4710
4798
  font-size: 14px;
4711
- color: var(--sc-text-color, ${DS_TEXT_COLOR$1});
4799
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$2});
4712
4800
  border-radius: 4px;
4713
4801
  width: 100%;
4714
4802
  word-break: break-all;
@@ -4735,9 +4823,9 @@ InfoItemsHighlight.displayName = 'InfoItemsHighlight';
4735
4823
  // these will be overridden with Investigate-specific fonts.
4736
4824
 
4737
4825
  // Default fallback values - use DS CSS variables with hardcoded ultimate fallbacks
4738
- const DS_FONT_BODY$1 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
4826
+ const DS_FONT_BODY$2 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
4739
4827
  const DS_FONT_CODE = "var(--redsift-typography-font-family-source-code-pro, 'Source Code Pro', monospace)";
4740
- const DS_TEXT_COLOR = 'var(--redsift-color-neutral-x-dark-grey, #3B3A58)';
4828
+ const DS_TEXT_COLOR$1 = 'var(--redsift-color-neutral-x-dark-grey, #3B3A58)';
4741
4829
  const DS_LINK_COLOR = 'var(--redsift-color-notifications-info-primary, #4285f4)';
4742
4830
  const DS_BG_LIGHT = 'var(--redsift-color-neutral-x-light-grey, #EAEAED)';
4743
4831
  const StyledChecklistContainer = styled.div`
@@ -4807,7 +4895,7 @@ const StyledItemText = styled.div`
4807
4895
  } = _ref8;
4808
4896
  return $compact ? '0.5rem' : '0.75rem';
4809
4897
  }};
4810
- font-family: var(--sc-font-body, ${DS_FONT_BODY$1});
4898
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$2});
4811
4899
  font-size: 0.875rem;
4812
4900
  line-height: ${_ref9 => {
4813
4901
  let {
@@ -4815,7 +4903,7 @@ const StyledItemText = styled.div`
4815
4903
  } = _ref9;
4816
4904
  return $compact ? '1.4' : '2';
4817
4905
  }};
4818
- color: var(--sc-text-color, ${DS_TEXT_COLOR});
4906
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$1});
4819
4907
  min-width: 0; /* Allow flex container to shrink */
4820
4908
 
4821
4909
  @media (max-width: 480px) {
@@ -4872,7 +4960,7 @@ const StyledContent = styled.span`
4872
4960
 
4873
4961
  code {
4874
4962
  background-color: var(--sc-code-bg, ${DS_BG_LIGHT});
4875
- color: var(--sc-text-color, ${DS_TEXT_COLOR});
4963
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$1});
4876
4964
  border-radius: 4px;
4877
4965
  padding: 0 0.25rem;
4878
4966
  word-break: break-word;
@@ -4880,10 +4968,10 @@ const StyledContent = styled.span`
4880
4968
  `;
4881
4969
  const StyledSubtexts = styled.div`
4882
4970
  margin: 0.5em 0 0.5em 0;
4883
- font-family: var(--sc-font-body, ${DS_FONT_BODY$1});
4971
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$2});
4884
4972
  font-size: 0.875rem;
4885
4973
  line-height: 2;
4886
- color: var(--sc-text-color, ${DS_TEXT_COLOR});
4974
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$1});
4887
4975
 
4888
4976
  display: flex;
4889
4977
  flex-direction: column;
@@ -4908,7 +4996,7 @@ const StyledSubtexts = styled.div`
4908
4996
  code {
4909
4997
  background-color: var(--sc-code-bg, ${DS_BG_LIGHT});
4910
4998
  font-family: var(--sc-font-code, ${DS_FONT_CODE});
4911
- color: var(--sc-text-color, ${DS_TEXT_COLOR});
4999
+ color: var(--sc-text-color, ${DS_TEXT_COLOR$1});
4912
5000
  padding: 0.2em 0.5em;
4913
5001
  border-radius: 3px;
4914
5002
  white-space: pre-wrap;
@@ -5384,7 +5472,7 @@ const Slider = styled.span`
5384
5472
  }};
5385
5473
  }
5386
5474
  `;
5387
- const StyledLabel = styled.label`
5475
+ const StyledLabel$1 = styled.label`
5388
5476
  display: inline-flex;
5389
5477
  align-items: center;
5390
5478
  ${_ref21 => {
@@ -5465,7 +5553,7 @@ const CheckBox = _ref22 => {
5465
5553
  $selected: selected,
5466
5554
  $accentColor: accentColor,
5467
5555
  $disabled: disabled
5468
- }) : null)), id && /*#__PURE__*/React__default.createElement(StyledLabel, {
5556
+ }) : null)), id && /*#__PURE__*/React__default.createElement(StyledLabel$1, {
5469
5557
  htmlFor: id,
5470
5558
  $alignLabel: alignLabel,
5471
5559
  $hasChildren: Boolean(children)
@@ -6380,7 +6468,7 @@ const _excluded$4 = ["isOpen", "parentRef", "ContentComponent", "placement", "st
6380
6468
  // these will be overridden with Investigate-specific fonts.
6381
6469
 
6382
6470
  // Default fallback values - use DS CSS variables with hardcoded ultimate fallbacks
6383
- const DS_FONT_BODY = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
6471
+ const DS_FONT_BODY$1 = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
6384
6472
 
6385
6473
  /**
6386
6474
  * TooltipInPortal Component
@@ -6423,7 +6511,7 @@ const TooltipStyled = styled(Tooltip$1)`
6423
6511
  & .tooltip__content {
6424
6512
  padding: 8px;
6425
6513
  font-size: 13px;
6426
- font-family: var(--sc-font-body, ${DS_FONT_BODY});
6514
+ font-family: var(--sc-font-body, ${DS_FONT_BODY$1});
6427
6515
  min-width: 260px;
6428
6516
  max-width: 320px;
6429
6517
  }
@@ -7193,7 +7281,16 @@ const BIMI_KEY_TO_TESTID = {
7193
7281
  'card.bimi.vmc-not-vmc-title_md': 'vmc-validity-invalid',
7194
7282
  'card.bimi.pemErrors.cert-not-found_md': 'vmc-cert-not-found',
7195
7283
  'card.bimi.vmc.expired-date_md': 'vmc-expiration-expired',
7196
- 'card.bimi.vmc.expiry-date_md': 'vmc-expiration-valid'
7284
+ 'card.bimi.vmc.expiry-date_md': 'vmc-expiration-valid',
7285
+ // Legacy VMC rows superseded by the DS-93 published-certificate sections.
7286
+ // Stamped with stable testids so SignalCardBimi can suppress them by testid
7287
+ // rather than by fragile label-text matching (see SignalCardBimi vmcSection).
7288
+ 'card.bimi.vmc.issuer_md': 'vmc-issuer',
7289
+ 'card.bimi.vmc.valid-for-domain_md': 'vmc-valid-for-domains',
7290
+ 'card.bimi.vmc.trademarkAuthority_md': 'vmc-trademark-authority',
7291
+ // Legacy "Assertion Mark:" row — duplicated by Mark evidence › "Mark type:"
7292
+ // (both render the trademark mark class, e.g. "Registered Mark").
7293
+ 'card.bimi.vmc.assertionMark_md': 'vmc-assertion-mark'
7197
7294
  };
7198
7295
 
7199
7296
  // =============================================================================
@@ -7957,6 +8054,438 @@ const uncompressLogo = svgUrl => {
7957
8054
 
7958
8055
  var SVGLogo$1 = SVGLogo;
7959
8056
 
8057
+ const DAY_MS = 24 * 60 * 60 * 1000;
8058
+
8059
+ /**
8060
+ * Amber-warning window: certificates within this many days of expiry surface an
8061
+ * amber status pill rather than green, giving operators a heads-up before it
8062
+ * lapses. Anything past expiry is red.
8063
+ */
8064
+ const EXPIRY_WARNING_DAYS = 30;
8065
+ const DS_FONT_BODY = "var(--redsift-typography-body-font-family, 'Poppins', sans-serif)";
8066
+ const DS_TEXT_COLOR = 'var(--redsift-color-neutral-x-dark-grey, #3B3A58)';
8067
+ const DS_TEXT_MUTED = 'var(--redsift-color-neutral-dark-grey, #6E6D83)';
8068
+ const DS_BORDER = 'var(--redsift-color-neutral-light-grey, #D9D8DE)';
8069
+ const DS_GREEN = 'var(--redsift-color-notifications-success-primary, #2e7d32)';
8070
+ const DS_AMBER = 'var(--redsift-color-notifications-warning-primary, #f5a623)';
8071
+ const DS_RED = 'var(--redsift-color-notifications-error-primary, #d32f2f)';
8072
+
8073
+ /**
8074
+ * Parse an ISO date/datetime string to a Date. Accepts both bare `YYYY-MM-DD`
8075
+ * and full ISO datetimes (`2025-07-29T00:00:00Z`) — the IPForensics
8076
+ * publishedCertificate emits the latter. Returns null when the input is missing
8077
+ * or unparseable so callers can degrade gracefully.
8078
+ */
8079
+ const parseCertDate = value => {
8080
+ if (!value) return null;
8081
+ // A bare YYYY-MM-DD is interpreted as UTC midnight; a full ISO datetime is
8082
+ // parsed as-is (it carries its own offset). Anchoring the date-only form to
8083
+ // UTC keeps the whole-day arithmetic stable regardless of the viewer's zone.
8084
+ const normalized = /^\d{4}-\d{2}-\d{2}$/.test(value) ? `${value}T00:00:00Z` : value;
8085
+ const parsed = new Date(normalized);
8086
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
8087
+ };
8088
+
8089
+ /** Whole-day difference between two dates (b - a), truncated toward zero. */
8090
+ const diffInDays = (a, b) => Math.trunc((b.getTime() - a.getTime()) / DAY_MS);
8091
+
8092
+ /**
8093
+ * Format a parsed certificate date as a locale-aware, human-readable day
8094
+ * (e.g. "29 Jul 2025") in UTC. UTC keeps the displayed day matching the
8095
+ * certificate's own boundary, independent of the viewer's timezone.
8096
+ */
8097
+ const formatDay = date => new Intl.DateTimeFormat(undefined, {
8098
+ day: '2-digit',
8099
+ month: 'short',
8100
+ year: 'numeric',
8101
+ timeZone: 'UTC'
8102
+ }).format(date);
8103
+ const StyledWidget = styled.div`
8104
+ display: flex;
8105
+ flex-wrap: wrap;
8106
+ align-items: stretch;
8107
+ gap: 1px;
8108
+ border: 1px solid var(--sc-border-color, ${DS_BORDER});
8109
+ border-radius: 8px;
8110
+ overflow: hidden;
8111
+ /* The 1px flex gaps reveal this divider colour between cells; cells sit on a
8112
+ lighter surface (below) so the columns read as distinct, not one slab. */
8113
+ background: var(--sc-border-color, ${DS_BORDER});
8114
+ font-family: var(--sc-font-body, ${DS_FONT_BODY});
8115
+ `;
8116
+ const StyledCell = styled.div`
8117
+ flex: 1 1 33%;
8118
+ min-width: 120px;
8119
+ display: flex;
8120
+ flex-direction: column;
8121
+ gap: 0.25rem;
8122
+ padding: 0.75rem 1rem;
8123
+ /* Section surface — x-light-grey (#f4f4f6) matches the other card sections.
8124
+ It is lighter than the divider (light-grey) so the 1px gaps still read as
8125
+ hairlines between cells. */
8126
+ background: var(--redsift-color-neutral-x-light-grey, #f4f4f6);
8127
+ `;
8128
+ const StyledLabel = styled.span`
8129
+ font-size: 0.6875rem;
8130
+ font-weight: 600;
8131
+ letter-spacing: 0.05em;
8132
+ text-transform: uppercase;
8133
+ color: var(--sc-text-muted, ${DS_TEXT_MUTED});
8134
+ `;
8135
+ const StyledValue = styled.span`
8136
+ font-size: 0.9375rem;
8137
+ font-weight: 600;
8138
+ color: var(--sc-text-color, ${DS_TEXT_COLOR});
8139
+ `;
8140
+ const statusColor = status => {
8141
+ switch (status) {
8142
+ case 'valid':
8143
+ return DS_GREEN;
8144
+ case 'expiring':
8145
+ return DS_AMBER;
8146
+ case 'expired':
8147
+ case 'not-yet-active':
8148
+ return DS_RED;
8149
+ }
8150
+ };
8151
+ const StyledPill = styled.span`
8152
+ display: inline-flex;
8153
+ align-items: center;
8154
+ gap: 0.4rem;
8155
+ align-self: flex-start;
8156
+ padding: 0.125rem 0;
8157
+ font-size: 0.9375rem;
8158
+ font-weight: 600;
8159
+ color: ${_ref => {
8160
+ let {
8161
+ $status
8162
+ } = _ref;
8163
+ return statusColor($status);
8164
+ }};
8165
+
8166
+ &::before {
8167
+ content: '';
8168
+ width: 0.5rem;
8169
+ height: 0.5rem;
8170
+ border-radius: 50%;
8171
+ background: currentColor;
8172
+ flex-shrink: 0;
8173
+ }
8174
+ `;
8175
+ /**
8176
+ * A glanceable three-part certificate-validity widget: the issue date, the
8177
+ * expiry date, and a color-coded status pill counting down (or up, once
8178
+ * expired) the days to expiry. Replaces the previous prose validity rows so the
8179
+ * issue date and remaining validity are legible at a glance (DS-93 feedback).
8180
+ *
8181
+ * All copy routes through `t` and stays translatable; the humanized durations
8182
+ * are a render-layer concern (the API returns only the raw dates). Renders
8183
+ * nothing when neither date is parseable.
8184
+ */
8185
+ const CertificateValidityWidget = _ref2 => {
8186
+ let {
8187
+ validFrom,
8188
+ expiry,
8189
+ t,
8190
+ now,
8191
+ 'data-testid': testId
8192
+ } = _ref2;
8193
+ const from = parseCertDate(validFrom);
8194
+ const to = parseCertDate(expiry);
8195
+ if (!from && !to) return null;
8196
+
8197
+ // Days remaining until expiry (negative once past). The expiry boundary day
8198
+ // itself is treated as "expires today" — not remaining validity.
8199
+ const daysToExpiry = to ? diffInDays(now, to) : null;
8200
+ // Not-yet-active takes precedence: a future start date means the cert isn't in
8201
+ // force yet, whatever the expiry says.
8202
+ const notYetActive = from ? diffInDays(now, from) > 0 : false;
8203
+ let status;
8204
+ let statusLabel;
8205
+ if (notYetActive) {
8206
+ status = 'not-yet-active';
8207
+ statusLabel = t('card.bimi.vmc.cert-status-not-yet-active');
8208
+ } else if (daysToExpiry === null) {
8209
+ // No expiry date but an active start — treat as valid with no countdown.
8210
+ status = 'valid';
8211
+ statusLabel = t('card.bimi.vmc.cert-status-valid');
8212
+ } else if (daysToExpiry < 0) {
8213
+ status = 'expired';
8214
+ statusLabel = t('card.bimi.vmc.cert-status-expired', {
8215
+ count: Math.abs(daysToExpiry)
8216
+ });
8217
+ } else if (daysToExpiry === 0) {
8218
+ status = 'expiring';
8219
+ statusLabel = t('card.bimi.vmc.cert-status-expires-today');
8220
+ } else {
8221
+ status = daysToExpiry <= EXPIRY_WARNING_DAYS ? 'expiring' : 'valid';
8222
+ statusLabel = t('card.bimi.vmc.cert-status-days-left', {
8223
+ count: daysToExpiry
8224
+ });
8225
+ }
8226
+ return /*#__PURE__*/React__default.createElement(StyledWidget, {
8227
+ "data-testid": testId
8228
+ }, from && /*#__PURE__*/React__default.createElement(StyledCell, {
8229
+ "data-testid": "bimi-cert-validity-issued"
8230
+ }, /*#__PURE__*/React__default.createElement(StyledLabel, null, t('card.bimi.vmc.cert-issued-label')), /*#__PURE__*/React__default.createElement(StyledValue, null, formatDay(from))), to && /*#__PURE__*/React__default.createElement(StyledCell, {
8231
+ "data-testid": "bimi-cert-validity-expires"
8232
+ }, /*#__PURE__*/React__default.createElement(StyledLabel, null, t('card.bimi.vmc.cert-expires-label')), /*#__PURE__*/React__default.createElement(StyledValue, null, formatDay(to))), /*#__PURE__*/React__default.createElement(StyledCell, {
8233
+ "data-testid": "bimi-cert-validity-status"
8234
+ }, /*#__PURE__*/React__default.createElement(StyledLabel, null, t('card.bimi.vmc.cert-status-label')), /*#__PURE__*/React__default.createElement(StyledPill, {
8235
+ $status: status,
8236
+ "data-testid": `bimi-cert-validity-pill-${status}`
8237
+ }, statusLabel)));
8238
+ };
8239
+ CertificateValidityWidget.displayName = 'CertificateValidityWidget';
8240
+
8241
+ /**
8242
+ * A rendered published-certificate section: a titled group of Checklist items.
8243
+ */
8244
+
8245
+ /**
8246
+ * Reference URL for the BIMI certificate-type explainer, used by the VMC/CMC
8247
+ * type badge. Follows the existing external-link convention in the card.
8248
+ */
8249
+ const CERT_TYPE_REFERENCE_URL = 'https://bimigroup.org/verified-mark-certificates-vmc-and-bimi/';
8250
+
8251
+ /** Join defined, non-empty parts with a separator; undefined when nothing remains. */
8252
+ const joinParts = function (parts) {
8253
+ let sep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ', ';
8254
+ const filtered = parts.map(p => p === null || p === void 0 ? void 0 : p.trim()).filter(p => !!p);
8255
+ return filtered.length ? filtered.join(sep) : undefined;
8256
+ };
8257
+
8258
+ /**
8259
+ * Build a single info ChecklistItem when its value is present. Returns null so
8260
+ * callers can filter absent fields out and only render populated rows.
8261
+ */
8262
+ const infoRow = (t, key, params, testId, value) => {
8263
+ if (!value) return null;
8264
+ // 'no-icon' renders the label/value with no leading icon — these dense
8265
+ // metadata rows read as a plain key/value list, so an info dot per row is
8266
+ // just noise.
8267
+ return {
8268
+ type: 'no-icon',
8269
+ text: t(key, params),
8270
+ 'data-testid': testId
8271
+ };
8272
+ };
8273
+
8274
+ /** External-link anchor rendered inline inside a Checklist item. */
8275
+ const ExternalLink = _ref => {
8276
+ let {
8277
+ href,
8278
+ children,
8279
+ 'data-testid': testId
8280
+ } = _ref;
8281
+ return /*#__PURE__*/React__default.createElement("a", {
8282
+ href: href,
8283
+ target: "_blank",
8284
+ rel: "noopener noreferrer",
8285
+ "data-testid": testId
8286
+ }, children);
8287
+ };
8288
+
8289
+ /**
8290
+ * Build the five published-certificate sections (Validity, Certificate, Subject
8291
+ * identity, Mark evidence, Verification issues) from IPForensics
8292
+ * VmcPublishedCertificate + VmcPemEvidence data.
8293
+ *
8294
+ * `assertionMarkType` ('VMC' | 'CMC') is the certificate type and lives on the
8295
+ * parent `vmc` object, NOT inside the published certificate — the certificate's
8296
+ * own `markType` field is the trademark mark *class* ("Registered Mark" etc.),
8297
+ * which is rendered separately under Mark evidence. The "Certificate type:" row
8298
+ * must use `assertionMarkType`.
8299
+ *
8300
+ * All labels come from @redsift/signal-logic BIMI_KEYS via `t` so they remain
8301
+ * translatable. `now` is injected for deterministic humanized durations in
8302
+ * tests and stories.
8303
+ */
8304
+ const buildPublishedCertificateSections = (cert, pem, t, now, assertionMarkType) => {
8305
+ var _cert$certifiedDomain, _cert$certifiedDomain2, _pem$errors;
8306
+ const sections = [];
8307
+
8308
+ // --- Validity ---
8309
+ // Rendered as a single glanceable widget (issued · expires · days-to-expiry
8310
+ // status pill) rather than prose rows, so the issue date and remaining
8311
+ // validity read at a glance (DS-93 feedback). The widget returns null when
8312
+ // neither date is parseable; only add the section when it has something to
8313
+ // show. It is carried as an 'image'-type Checklist item so it escapes the
8314
+ // key/value row layout and spans the section width (same slot SVGLogo uses).
8315
+ const hasValidityDates = !!parseCertDate(cert.validFrom) || !!parseCertDate(cert.expiry);
8316
+ if (hasValidityDates) {
8317
+ sections.push({
8318
+ id: 'bimi-cert-validity',
8319
+ title: t('card.bimi.vmc.cert-section-validity'),
8320
+ items: [{
8321
+ type: 'image',
8322
+ 'data-testid': 'bimi-cert-validity-widget-item',
8323
+ text: /*#__PURE__*/React__default.createElement(CertificateValidityWidget, {
8324
+ validFrom: cert.validFrom,
8325
+ expiry: cert.expiry,
8326
+ t: t,
8327
+ now: now,
8328
+ "data-testid": "bimi-cert-validity-widget"
8329
+ })
8330
+ }],
8331
+ testId: 'bimi-cert-validity-section'
8332
+ });
8333
+ }
8334
+
8335
+ // --- Certificate ---
8336
+ const certItems = [];
8337
+ const issuerCommon = infoRow(t, 'card.bimi.vmc.cert-issuer-common-name_md', {
8338
+ issuerCommonName: cert.issuerCommonName
8339
+ }, 'bimi-cert-issuer-common-name', cert.issuerCommonName);
8340
+ if (issuerCommon) certItems.push(issuerCommon);
8341
+ const issuerOrg = infoRow(t, 'card.bimi.vmc.cert-issuer-organization_md', {
8342
+ issuerOrganization: cert.issuerOrganization
8343
+ }, 'bimi-cert-issuer-organization', cert.issuerOrganization);
8344
+ if (issuerOrg) certItems.push(issuerOrg);
8345
+ const issuerCountry = infoRow(t, 'card.bimi.vmc.cert-issuer-country_md', {
8346
+ issuerCountry: cert.issuerCountry
8347
+ }, 'bimi-cert-issuer-country', cert.issuerCountry);
8348
+ if (issuerCountry) certItems.push(issuerCountry);
8349
+
8350
+ // Certificate type row: a bold "Certificate type:" label (which itself
8351
+ // contains spaces, e.g. "Certificate type:" / FR "Type de certificat :")
8352
+ // with the VMC/CMC value as an external-link badge. We interpolate a NUL
8353
+ // sentinel for the value so the label markdown (**…**) parses correctly, then
8354
+ // split the template at that exact sentinel and splice the linked badge in
8355
+ // where the value goes — only the value links, not the label. Splitting on
8356
+ // the sentinel (never a bare space) is what keeps multi-word labels intact.
8357
+ //
8358
+ // Value is `assertionMarkType` ('VMC'/'CMC') from the parent vmc object — NOT
8359
+ // the certificate's own `markType`, which is the trademark mark class and is
8360
+ // rendered under Mark evidence instead.
8361
+ if (assertionMarkType) {
8362
+ const VALUE_TOKEN = '';
8363
+ const template = t('card.bimi.vmc.cert-type_md', {
8364
+ assertionMarkType: VALUE_TOKEN
8365
+ });
8366
+ const tokenIndex = template.indexOf(VALUE_TOKEN);
8367
+ // If the placeholder is somehow absent, keep the whole label before the
8368
+ // badge rather than dropping any text.
8369
+ const before = tokenIndex === -1 ? template : template.slice(0, tokenIndex);
8370
+ const after = tokenIndex === -1 ? '' : template.slice(tokenIndex + VALUE_TOKEN.length);
8371
+ certItems.push({
8372
+ type: 'no-icon',
8373
+ 'data-testid': 'bimi-cert-type',
8374
+ text: /*#__PURE__*/React__default.createElement("span", null, parseGlossaryMarkdown(before), /*#__PURE__*/React__default.createElement(ExternalLink, {
8375
+ href: CERT_TYPE_REFERENCE_URL,
8376
+ "data-testid": "bimi-cert-type-link"
8377
+ }, assertionMarkType), after && parseGlossaryMarkdown(after))
8378
+ });
8379
+ }
8380
+
8381
+ // Certified domains as chips with external links, comma-separated.
8382
+ const certifiedDomains = (_cert$certifiedDomain = (_cert$certifiedDomain2 = cert.certifiedDomains) === null || _cert$certifiedDomain2 === void 0 ? void 0 : _cert$certifiedDomain2.filter(d => !!d)) !== null && _cert$certifiedDomain !== void 0 ? _cert$certifiedDomain : [];
8383
+ if (certifiedDomains.length) {
8384
+ certItems.push({
8385
+ type: 'no-icon',
8386
+ 'data-testid': 'bimi-cert-certified-domains',
8387
+ text: /*#__PURE__*/React__default.createElement("span", {
8388
+ "data-testid": "bimi-cert-certified-domains-chips"
8389
+ }, certifiedDomains.map((domain, idx) => /*#__PURE__*/React__default.createElement(React__default.Fragment, {
8390
+ key: domain
8391
+ }, idx > 0 && ', ', domain.includes('*') ? domain : /*#__PURE__*/React__default.createElement(ExternalLink, {
8392
+ href: `https://${domain}`
8393
+ }, domain))))
8394
+ });
8395
+ }
8396
+ if (certItems.length) {
8397
+ sections.push({
8398
+ id: 'bimi-cert-certificate',
8399
+ title: t('card.bimi.vmc.cert-section-certificate'),
8400
+ items: certItems,
8401
+ testId: 'bimi-cert-certificate-section'
8402
+ });
8403
+ }
8404
+
8405
+ // --- Subject identity ---
8406
+ const jurisdiction = joinParts([cert.jurisdictionLocality, cert.jurisdictionStateOrProvince, cert.jurisdictionCountry]);
8407
+ const address = joinParts([cert.streetAddress, cert.locality, cert.stateOrProvince, cert.country]);
8408
+ const organizationIdentifier = cert.organizationIdentifier ? cert.organizationIdentifierScheme ? `${cert.organizationIdentifier} (${cert.organizationIdentifierScheme})` : cert.organizationIdentifier : undefined;
8409
+ const subjectItems = [infoRow(t, 'card.bimi.vmc.cert-serial-number_md', {
8410
+ serialNumber: cert.serialNumber
8411
+ }, 'bimi-cert-serial-number', cert.serialNumber), infoRow(t, 'card.bimi.vmc.cert-organization_md', {
8412
+ organization: cert.organization
8413
+ }, 'bimi-cert-organization', cert.organization), infoRow(t, 'card.bimi.vmc.cert-common-name_md', {
8414
+ commonName: cert.commonName
8415
+ }, 'bimi-cert-common-name', cert.commonName), infoRow(t, 'card.bimi.vmc.cert-business-category_md', {
8416
+ businessCategory: cert.businessCategory
8417
+ }, 'bimi-cert-business-category', cert.businessCategory), infoRow(t, 'card.bimi.vmc.cert-organization-identifier_md', {
8418
+ organizationIdentifier
8419
+ }, 'bimi-cert-organization-identifier', organizationIdentifier), infoRow(t, 'card.bimi.vmc.cert-legal-entity-identifier_md', {
8420
+ legalEntityIdentifier: cert.legalEntityIdentifier
8421
+ }, 'bimi-cert-legal-entity-identifier', cert.legalEntityIdentifier), infoRow(t, 'card.bimi.vmc.cert-jurisdiction_md', {
8422
+ jurisdiction
8423
+ }, 'bimi-cert-jurisdiction', jurisdiction), infoRow(t, 'card.bimi.vmc.cert-address_md', {
8424
+ address
8425
+ }, 'bimi-cert-address', address)].filter(i => i !== null);
8426
+ if (subjectItems.length) {
8427
+ sections.push({
8428
+ id: 'bimi-cert-subject-identity',
8429
+ title: t('card.bimi.vmc.cert-section-subject-identity'),
8430
+ items: subjectItems,
8431
+ testId: 'bimi-cert-subject-identity-section'
8432
+ });
8433
+ }
8434
+
8435
+ // --- Mark evidence ---
8436
+ const markItems = [infoRow(t, 'card.bimi.vmc.cert-trademark-registration_md', {
8437
+ trademarkRegistration: cert.trademarkRegistration
8438
+ }, 'bimi-cert-trademark-registration', cert.trademarkRegistration), infoRow(t, 'card.bimi.vmc.cert-trademark-office_md', {
8439
+ trademarkOfficeName: cert.trademarkOfficeName
8440
+ }, 'bimi-cert-trademark-office', cert.trademarkOfficeName), infoRow(t, 'card.bimi.vmc.cert-mark-type_md', {
8441
+ markType: cert.markType
8442
+ }, 'bimi-cert-mark-type', cert.markType), infoRow(t, 'card.bimi.vmc.cert-trademark-country_md', {
8443
+ trademarkCountryOrRegion: cert.trademarkCountryOrRegion
8444
+ }, 'bimi-cert-trademark-country', cert.trademarkCountryOrRegion)].filter(i => i !== null);
8445
+ if (markItems.length) {
8446
+ sections.push({
8447
+ id: 'bimi-cert-mark-evidence',
8448
+ title: t('card.bimi.vmc.cert-section-mark-evidence'),
8449
+ items: markItems,
8450
+ testId: 'bimi-cert-mark-evidence-section'
8451
+ });
8452
+ }
8453
+
8454
+ // --- Verification issues ---
8455
+ // Sourced from PEM evidence errors plus an ambiguous leaf-selection signal.
8456
+ const errorMessages = ((_pem$errors = pem === null || pem === void 0 ? void 0 : pem.errors) !== null && _pem$errors !== void 0 ? _pem$errors : []).map(e => typeof e === 'string' ? e : e === null || e === void 0 ? void 0 : e.message).filter(m => !!m);
8457
+ const isAmbiguous = (pem === null || pem === void 0 ? void 0 : pem.leafSelectionMethod) === 'AMBIGUOUS';
8458
+ const issueItems = [];
8459
+ if (isAmbiguous) {
8460
+ issueItems.push({
8461
+ type: 'warning',
8462
+ text: t('card.bimi.vmc.cert-ambiguous-leaf_md'),
8463
+ 'data-testid': 'bimi-cert-issue-ambiguous'
8464
+ });
8465
+ }
8466
+ errorMessages.forEach((message, idx) => {
8467
+ issueItems.push({
8468
+ type: 'warning',
8469
+ text: message,
8470
+ 'data-testid': `bimi-cert-issue-${idx}`
8471
+ });
8472
+ });
8473
+ if (!issueItems.length) {
8474
+ issueItems.push({
8475
+ type: 'good',
8476
+ text: t('card.bimi.vmc.cert-no-issues-reported_md'),
8477
+ 'data-testid': 'bimi-cert-no-issues'
8478
+ });
8479
+ }
8480
+ sections.push({
8481
+ id: 'bimi-cert-verification-issues',
8482
+ title: t('card.bimi.vmc.cert-section-verification-issues'),
8483
+ items: issueItems,
8484
+ testId: 'bimi-cert-verification-issues-section'
8485
+ });
8486
+ return sections;
8487
+ };
8488
+
7960
8489
  const _excluded$2 = ["jmap", "onHeightChange", "useInvestigateColors", "isCollapsible", "areAllCollapsed", "onCollapseAll", "className"];
7961
8490
  const COMPONENT_NAME$2 = 'SignalCardBimi';
7962
8491
  const CLASSNAME$2 = 'redsift-signal-card-bimi';
@@ -7966,6 +8495,7 @@ const CLASSNAME$2 = 'redsift-signal-card-bimi';
7966
8495
  * BIMI record validation, VMC certificate details, and SVG logo validation.
7967
8496
  */
7968
8497
  const SignalCardBimi = /*#__PURE__*/forwardRef((props, ref) => {
8498
+ var _bimi$vmc;
7969
8499
  const {
7970
8500
  t
7971
8501
  } = useSignalCardTranslation('investigate');
@@ -8024,31 +8554,76 @@ const SignalCardBimi = /*#__PURE__*/forwardRef((props, ref) => {
8024
8554
  items
8025
8555
  });
8026
8556
  }, [adapterResult === null || adapterResult === void 0 ? void 0 : adapterResult.svgSection, bimi, isDeclinationToPublish]);
8557
+ const hasPublishedCertificate = !!(bimi !== null && bimi !== void 0 && (_bimi$vmc = bimi.vmc) !== null && _bimi$vmc !== void 0 && _bimi$vmc.publishedCertificate);
8027
8558
 
8028
8559
  // Inject SVGLogo into VMC section (React-specific)
8029
8560
  const vmcSection = useMemo(() => {
8030
- var _bimi$vmc;
8561
+ var _bimi$vmc2;
8031
8562
  if (isDeclinationToPublish || !(adapterResult !== null && adapterResult !== void 0 && adapterResult.vmcSection)) return null;
8032
- const logoSrc = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc = bimi.vmc) === null || _bimi$vmc === void 0 ? void 0 : _bimi$vmc.logoSrc;
8033
- if (!logoSrc) return adapterResult.vmcSection;
8034
- const items = [...adapterResult.vmcSection.items];
8035
- // Insert logo before the first 'no-icon' item (matching original helpers behavior)
8036
- const noIconIdx = items.findIndex(item => item.type === 'no-icon');
8037
- const svgItem = {
8038
- text: /*#__PURE__*/React__default.createElement(SVGLogo$1, {
8039
- svgUrl: logoSrc
8040
- }),
8041
- type: 'image'
8042
- };
8043
- if (noIconIdx >= 0) {
8044
- items.splice(noIconIdx, 0, svgItem);
8045
- } else {
8046
- items.push(svgItem);
8563
+ let items = [...adapterResult.vmcSection.items];
8564
+
8565
+ // When the full published certificate is present, the new metadata sections
8566
+ // (below) supersede several legacy VMC rows with richer equivalents, so drop
8567
+ // the duplicated legacy rows to avoid showing each field twice (DS-93):
8568
+ // issuer → Certificate Issuer
8569
+ // expiry → Validity › Expiry (matched by testid)
8570
+ // valid-for-domains → Certificate › Certified domains
8571
+ // trademark authority → Mark evidence › Trademark office
8572
+ // assertion mark → Mark evidence › Mark type (both are the mark class)
8573
+ // The legacy VMC validity-status row has no equivalent in the new sections
8574
+ // and is kept.
8575
+ if (hasPublishedCertificate) {
8576
+ // Suppress by stable data-testid (stamped in the extractor adapter's
8577
+ // BIMI_KEY_TO_TESTID map) rather than by label text. Matching on wording
8578
+ // is fragile — a copy change in signal-logic would silently stop matching
8579
+ // and reintroduce the duplicated rows. The adapter owns these testids:
8580
+ // issuer → vmc-issuer (Certificate › Issuer)
8581
+ // valid-for-domains → vmc-valid-for-domains (Certificate › Certified domains)
8582
+ // trademark authority → vmc-trademark-authority (Mark evidence › Trademark office)
8583
+ // expiry → vmc-expiration-* (Validity › Expiry)
8584
+ const suppressedTestIds = new Set(['vmc-issuer', 'vmc-valid-for-domains', 'vmc-trademark-authority', 'vmc-assertion-mark', 'vmc-expiration-valid', 'vmc-expiration-expired']);
8585
+ items = items.filter(item => {
8586
+ const testId = item['data-testid'];
8587
+ return !(testId && suppressedTestIds.has(testId));
8588
+ });
8589
+ }
8590
+ const logoSrc = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc2 = bimi.vmc) === null || _bimi$vmc2 === void 0 ? void 0 : _bimi$vmc2.logoSrc;
8591
+ if (logoSrc) {
8592
+ // Insert logo before the first 'no-icon' item (matching original helpers behavior)
8593
+ const noIconIdx = items.findIndex(item => item.type === 'no-icon');
8594
+ const svgItem = {
8595
+ text: /*#__PURE__*/React__default.createElement(SVGLogo$1, {
8596
+ svgUrl: logoSrc
8597
+ }),
8598
+ type: 'image'
8599
+ };
8600
+ if (noIconIdx >= 0) {
8601
+ items.splice(noIconIdx, 0, svgItem);
8602
+ } else {
8603
+ items.push(svgItem);
8604
+ }
8047
8605
  }
8048
8606
  return _objectSpread2(_objectSpread2({}, adapterResult.vmcSection), {}, {
8049
8607
  items
8050
8608
  });
8051
- }, [adapterResult === null || adapterResult === void 0 ? void 0 : adapterResult.vmcSection, bimi, isDeclinationToPublish]);
8609
+ }, [adapterResult === null || adapterResult === void 0 ? void 0 : adapterResult.vmcSection, bimi, isDeclinationToPublish, hasPublishedCertificate]);
8610
+
8611
+ // Build the published-certificate metadata sections (VMC/CMC leaf identity,
8612
+ // mark evidence, verification issues). Only present when IPForensics resolved
8613
+ // a unique leaf; otherwise this is empty and the card degrades to the legacy
8614
+ // VMC section above (DS-93). `now` drives the humanized validity durations.
8615
+ const publishedCertSections = useMemo(() => {
8616
+ var _bimi$vmc3, _bimi$vmc4, _bimi$vmc5;
8617
+ if (isDeclinationToPublish) return [];
8618
+ const cert = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc3 = bimi.vmc) === null || _bimi$vmc3 === void 0 ? void 0 : _bimi$vmc3.publishedCertificate;
8619
+ if (!cert) return [];
8620
+ const pem = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc4 = bimi.vmc) === null || _bimi$vmc4 === void 0 ? void 0 : _bimi$vmc4.pem;
8621
+ // assertionMarkType ('VMC'/'CMC') is a sibling of publishedCertificate on
8622
+ // vmc, not a field of the certificate itself — pass it through for the
8623
+ // "Certificate type:" row (cert.markType is the trademark mark class).
8624
+ const assertionMarkType = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc5 = bimi.vmc) === null || _bimi$vmc5 === void 0 ? void 0 : _bimi$vmc5.assertionMarkType;
8625
+ return buildPublishedCertificateSections(cert, pem, t, new Date(), assertionMarkType);
8626
+ }, [bimi, t, isDeclinationToPublish]);
8052
8627
  const getTranslatedCaption = useCallback(caption => {
8053
8628
  if (!caption) return undefined;
8054
8629
  return t(EXTRACTION_CAPTION_KEYS[caption]);
@@ -8106,6 +8681,20 @@ const SignalCardBimi = /*#__PURE__*/forwardRef((props, ref) => {
8106
8681
  testId: 'bimi-vmc-section'
8107
8682
  });
8108
8683
  }
8684
+
8685
+ // Full published-certificate metadata sections (DS-93). Rendered only when
8686
+ // vmc.publishedCertificate is present; otherwise the card keeps its legacy
8687
+ // VMC rendering above.
8688
+ publishedCertSections.forEach(section => {
8689
+ sections.push({
8690
+ id: section.id,
8691
+ title: section.title,
8692
+ content: /*#__PURE__*/React__default.createElement(Checklist$1, {
8693
+ items: section.items
8694
+ }),
8695
+ testId: section.testId
8696
+ });
8697
+ });
8109
8698
  if (svgSection) {
8110
8699
  sections.push({
8111
8700
  id: 'safeSVG',