diff --git a/assets/scss/layouts/_layouts.scss b/assets/scss/layouts/_layouts.scss
index ad18a92264..3a0b6d838e 100644
--- a/assets/scss/layouts/_layouts.scss
+++ b/assets/scss/layouts/_layouts.scss
@@ -46,6 +46,9 @@
// Product Sale Badges
@import "products/productSaleBadges";
+// Featured Promotion Callouts
+@import "products/featuredPromotions";
+
// Product view
@import "products/productSwatch";
diff --git a/assets/scss/layouts/products/_featuredPromotions.scss b/assets/scss/layouts/products/_featuredPromotions.scss
new file mode 100644
index 0000000000..dc33c9deae
--- /dev/null
+++ b/assets/scss/layouts/products/_featuredPromotions.scss
@@ -0,0 +1,47 @@
+// =============================================================================
+// FEATURED PROMOTIONS (CSS)
+// =============================================================================
+//
+// Chip-style callouts rendered inside product cards, list items, and on PDP.
+//
+// Markup is server-rendered by `templates/components/products/featured-promotion-callouts.html`
+// from the `featured_promotions` array on the Stencil product context (PROMO-1488).
+// The container is only emitted when the array is non-empty, so there is no
+// `hidden`/`is-loaded` toggling here.
+
+.featuredPromotions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: spacing("eighth");
+ list-style: none;
+ margin: spacing("eighth") 0 0;
+ padding: 0;
+}
+
+.featuredPromotions-chip {
+ background: stencilColor("color_badge_product_sale_badges");
+ border-radius: 2px;
+ color: stencilColor("color_text_product_sale_badges");
+ display: inline-block;
+ font-size: rem-calc(12px);
+ font-weight: 600;
+ line-height: rem-calc(16px);
+ padding: spacing("eighth") spacing("third");
+ text-transform: uppercase;
+ transition: background-color 800ms ease;
+}
+
+.product:hover .featuredPromotions-chip {
+ background: stencilColor("color_hover_product_sale_badges");
+}
+
+.productView .featuredPromotions {
+ margin-top: spacing("half");
+
+ .featuredPromotions-chip {
+ font-size: rem-calc(13px);
+ line-height: rem-calc(18px);
+ padding: spacing("eighth") spacing("half");
+ text-transform: none;
+ }
+}
diff --git a/lang/en.json b/lang/en.json
index d7c996e1ad..0acef78c07 100755
--- a/lang/en.json
+++ b/lang/en.json
@@ -833,7 +833,10 @@
"suffix": "each"
}
},
- "card_default_image_alt": "Image coming soon"
+ "card_default_image_alt": "Image coming soon",
+ "featured_promotions": {
+ "aria_label": "Featured promotions"
+ }
},
"invoice": {
"for_order": "{name} Invoice for Order #{id}",
diff --git a/templates/components/brand/product-listing.html b/templates/components/brand/product-listing.html
index 2e2a9c6ff9..9fc5d11429 100644
--- a/templates/components/brand/product-listing.html
+++ b/templates/components/brand/product-listing.html
@@ -4,9 +4,9 @@
{{#if theme_settings.product_list_display_mode '===' 'grid'}}
- {{> components/products/grid products=brand.products show_compare=brand.show_compare theme_settings=theme_settings event="list"}}
+ {{> components/products/grid products=brand.products show_compare=brand.show_compare theme_settings=theme_settings event="list" show_featured_promotions=true}}
{{else}}
- {{> components/products/list products=brand.products show_compare=brand.show_compare theme_settings=theme_settings event="list"}}
+ {{> components/products/list products=brand.products show_compare=brand.show_compare theme_settings=theme_settings event="list" show_featured_promotions=true}}
{{/if}}
diff --git a/templates/components/category/product-listing.html b/templates/components/category/product-listing.html
index f8980d248e..06a75bfc80 100644
--- a/templates/components/category/product-listing.html
+++ b/templates/components/category/product-listing.html
@@ -5,9 +5,9 @@
{{#if theme_settings.product_list_display_mode '===' 'grid'}}
- {{> components/products/grid products=category.products show_compare=category.show_compare theme_settings=theme_settings event="list" }}
+ {{> components/products/grid products=category.products show_compare=category.show_compare theme_settings=theme_settings event="list" show_featured_promotions=true }}
{{else}}
- {{> components/products/list products=category.products show_compare=category.show_compare theme_settings=theme_settings event="list" }}
+ {{> components/products/list products=category.products show_compare=category.show_compare theme_settings=theme_settings event="list" show_featured_promotions=true }}
{{/if}}
diff --git a/templates/components/products/card.html b/templates/components/products/card.html
index c90f62e76a..695583255e 100644
--- a/templates/components/products/card.html
+++ b/templates/components/products/card.html
@@ -132,6 +132,9 @@
{{> components/common/login-for-pricing}}
{{/or}}
+ {{#if show_featured_promotions}}
+ {{> components/products/featured-promotion-callouts callouts=featured_promotions}}
+ {{/if}}
{{{region name="product_item_below_price"}}}
{{> components/products/bulk-discount-rates}}
diff --git a/templates/components/products/featured-promotion-callouts.html b/templates/components/products/featured-promotion-callouts.html
new file mode 100644
index 0000000000..cf7601d019
--- /dev/null
+++ b/templates/components/products/featured-promotion-callouts.html
@@ -0,0 +1,23 @@
+{{!--
+ Renders "Featured Promotion" callout chips for a product.
+
+ Source: server-rendered Stencil context. The Storefront service populates
+ `product.featured_promotions` (PROMO-1488) on:
+ - the product details page object (PDP)
+ - each product card in category/brand/search listings (PLP)
+ via the GraphQL `Product.featuredPromotions` field, gated by the
+ `PROMO-1488.featured_promotions_in_graphql_enabled` LaunchDarkly flag.
+
+ When the flag is off (or no callouts apply), `featured_promotions` is
+ omitted from the Stencil context and the block below renders nothing.
+
+ Caller: pass the product's `featured_promotions` array as `callouts`,
+ e.g. `{{> components/products/featured-promotion-callouts callouts=product.featured_promotions }}`.
+--}}
+{{#if callouts.length}}
+
+{{/if}}
diff --git a/templates/components/products/grid.html b/templates/components/products/grid.html
index 51c8ffcb00..bfca8953c2 100644
--- a/templates/components/products/grid.html
+++ b/templates/components/products/grid.html
@@ -1,7 +1,7 @@
{{#each products}}
-
- {{>components/products/card settings=../settings show_compare=../show_compare show_rating=../settings.show_product_rating theme_settings=../theme_settings customer=../customer event=../event position=(add @index 1)}}
+ {{>components/products/card settings=../settings show_compare=../show_compare show_rating=../settings.show_product_rating theme_settings=../theme_settings customer=../customer event=../event position=(add @index 1) show_featured_promotions=../show_featured_promotions}}
{{/each}}
diff --git a/templates/components/products/list-item.html b/templates/components/products/list-item.html
index b2678a4ab1..2dcc5625b2 100644
--- a/templates/components/products/list-item.html
+++ b/templates/components/products/list-item.html
@@ -86,6 +86,9 @@
{{#or customer (unless settings.hide_price_from_guests)}}
{{#if price}}
{{> components/products/price price=price}}
+ {{#if show_featured_promotions}}
+ {{> components/products/featured-promotion-callouts callouts=featured_promotions}}
+ {{/if}}
{{{region name="product_item_below_price"}}}
{{/if}}
{{else}}
diff --git a/templates/components/products/list.html b/templates/components/products/list.html
index 4251cfb752..b5d5697374 100644
--- a/templates/components/products/list.html
+++ b/templates/components/products/list.html
@@ -1,7 +1,7 @@
{{#each products}}
-
- {{>components/products/list-item show_compare=../show_compare show_rating=../settings.show_product_rating theme_settings=../theme_settings customer=../customer event=../event settings=../settings position=(add @index 1)}}
+ {{>components/products/list-item show_compare=../show_compare show_rating=../settings.show_product_rating theme_settings=../theme_settings customer=../customer event=../event settings=../settings position=(add @index 1) show_featured_promotions=../show_featured_promotions}}
{{/each}}
diff --git a/templates/components/products/product-view.html b/templates/components/products/product-view.html
index 162ca95931..2939bb9bec 100644
--- a/templates/components/products/product-view.html
+++ b/templates/components/products/product-view.html
@@ -121,6 +121,7 @@
{{> components/common/login-for-pricing}}
{{/or}}
+ {{> components/products/featured-promotion-callouts callouts=product.featured_promotions}}
{{{region name="product_below_price"}}}
{{#if settings.show_product_rating}}
diff --git a/templates/components/search/product-listing.html b/templates/components/search/product-listing.html
index 97d62a9578..aafaa8e9ca 100644
--- a/templates/components/search/product-listing.html
+++ b/templates/components/search/product-listing.html
@@ -5,9 +5,9 @@
{{/if}}
{{#if theme_settings.product_list_display_mode '===' 'grid'}}
- {{> components/products/grid products=product_results.products show_compare=product_results.show_compare event="list" theme_settings=theme_settings}}
+ {{> components/products/grid products=product_results.products show_compare=product_results.show_compare event="list" theme_settings=theme_settings show_featured_promotions=true}}
{{else}}
- {{> components/products/list products=product_results.products show_compare=product_results.show_compare event="list" theme_settings=theme_settings}}
+ {{> components/products/list products=product_results.products show_compare=product_results.show_compare event="list" theme_settings=theme_settings show_featured_promotions=true}}
{{/if}}