@@ -164,38 +164,50 @@ const overlayMaskGradientStyles = (angle: string) => css`
164164 );
165165` ;
166166
167+ const contentOverlayStyle = css `
168+ position : absolute;
169+ bottom : 0 ;
170+ left : 0 ;
171+ width : 100% ;
172+ ` ;
173+
167174const overlayStyles = css `
168175 position : relative;
169176 display : flex;
170177 flex-direction : column;
171178 text-align : start;
172179 gap : ${ space [ 1 ] } px;
173180 padding : ${ space [ 9 ] } px ${ space [ 2 ] } px ${ space [ 2 ] } px;
181+
182+ /*
183+ * Ensure the waveform is behind the other elements, e.g. headline, pill.
184+ * Links define their own z-index.
185+ */
186+ > : not (.waveform ): not (a ) {
187+ z-index : 1 ;
188+ }
189+ ` ;
190+
191+ const blurStyles = css `
192+ position : absolute;
193+ inset : 0 ;
174194 backdrop-filter : blur (12px ) brightness (0.5 );
175195 @supports not (backdrop-filter : blur (12px )) {
176196 background-color : ${ transparentColour ( sourcePalette . neutral [ 10 ] , 0.7 ) } ;
177197 }
178198 ${ overlayMaskGradientStyles ( '180deg' ) } ;
199+ ` ;
179200
180- /*
181- * Ensure the waveform is behind the other elements, e.g. headline, pill.
182- * Links define their own z-index.
183- */
184-
185- > : not (.waveform ): not (a) {
186- z-index : 1 ;
201+ const immersiveOverlayBlurStyles = css `
202+ ${ from . tablet } {
203+ padding: ${ space [ 2 ] } px ${ space [ 12 ] } px ${ space [ 2 ] } px ${ space [ 2 ] } px;
204+ ${ overlayMaskGradientStyles ( '270deg' ) }
187205 }
188206` ;
189207
190208const immersiveOverlayStyles = css `
191209 ${ from . tablet } {
192210 height: 100%;
193- /**
194- * Why 48px right padding?
195- * 48px is to point at which the gradient can go behind the content whilst maintaining accessibility.
196- */
197- padding : ${ space [ 2 ] } px ${ space [ 12 ] } px ${ space [ 2 ] } px ${ space [ 2 ] } px;
198- ${ overlayMaskGradientStyles ( '270deg' ) }
199211 }
200212` ;
201213
@@ -644,165 +656,186 @@ export const FeatureCard = ({
644656 noPointerEvents ,
645657 ] }
646658 >
647- { mainMedia ?. type === 'Audio' &&
648- ! ! mainMedia . podcastImage ?. src &&
649- ( isImmersive ? (
650- < Hide from = "tablet" >
651- { renderPodcastImage (
659+ < div css = { contentOverlayStyle } >
660+ { mainMedia ?. type === 'Audio' &&
661+ ! ! mainMedia . podcastImage ?. src &&
662+ ( isImmersive ? (
663+ < Hide from = "tablet" >
664+ { renderPodcastImage (
665+ mainMedia . podcastImage
666+ . src ,
667+ mainMedia . podcastImage
668+ . altText ?? '' ,
669+ false , // Immersive cards are styled as feature cards below the tablet viewport
670+ ) }
671+ </ Hide >
672+ ) : (
673+ renderPodcastImage (
652674 mainMedia . podcastImage . src ,
653675 mainMedia . podcastImage
654676 . altText ?? '' ,
655- false , // Immersive cards are styled as feature cards below the tablet viewport
656- ) }
657- </ Hide >
658- ) : (
659- renderPodcastImage (
660- mainMedia . podcastImage . src ,
661- mainMedia . podcastImage
662- . altText ?? '' ,
663- false ,
664- )
665- ) ) }
666- < div
667- css = { [
668- overlayStyles ,
669- isImmersive &&
670- immersiveOverlayStyles ,
671- isSelfHostedVideoWithControls &&
672- underlineOnHoverStyles ,
673- ] }
674- >
675- { /** Only the overlay is a link for self-hosted videos with controls. */ }
676- { isSelfHostedVideoWithControls && (
677- < CardLink
678- linkTo = { linkTo }
679- headlineText = { headlineText }
680- dataLinkName = { dataLinkName }
681- isExternalLink = { isExternalLink }
682- />
683- ) }
677+ false ,
678+ )
679+ ) ) }
680+ < div
681+ css = { [
682+ blurStyles ,
683+ isImmersive &&
684+ immersiveOverlayBlurStyles ,
685+ ] }
686+ />
684687
685- { isImmersive &&
686- mainMedia ?. type === 'Audio' &&
687- ! ! mainMedia . podcastImage ?. src && (
688- < div
689- css = {
690- podcastImageContainerStyles
688+ < div
689+ css = { [
690+ overlayStyles ,
691+ isImmersive &&
692+ immersiveOverlayStyles ,
693+ isSelfHostedVideoWithControls &&
694+ underlineOnHoverStyles ,
695+ ] }
696+ >
697+ { /** Only the overlay is a link for self-hosted videos with controls. */ }
698+ { isSelfHostedVideoWithControls && (
699+ < CardLink
700+ linkTo = { linkTo }
701+ headlineText = { headlineText }
702+ dataLinkName = { dataLinkName }
703+ isExternalLink = {
704+ isExternalLink
691705 }
692- >
693- < Hide until = "tablet" >
694- { renderPodcastImage (
695- mainMedia
696- . podcastImage
697- . src ,
698- mainMedia
699- . podcastImage
700- . altText ?? '' ,
701- true ,
702- ) }
703- </ Hide >
704- </ div >
706+ />
705707 ) }
706708
707- { /**
708- * Without the wrapping div the headline and byline would have space
709- * inserted between them due to being direct children of the flex container
710- */ }
711- < div >
712- < CardHeadline
713- headlineText = { headlineText }
714- format = { format }
715- fontSizes = { headlineSizes }
716- showQuotes = { showQuotes }
717- kickerText = {
718- format . design ===
719- ArticleDesign . LiveBlog &&
720- ! kickerText
721- ? 'Live'
722- : kickerText
723- }
724- showPulsingDot = {
725- format . design ===
726- ArticleDesign . LiveBlog ||
727- showPulsingDot
728- }
729- byline = { byline }
730- showByline = { showByline }
731- isExternalLink = { isExternalLink }
732- headlineColour = { palette (
733- '--feature-card-headline' ,
734- ) }
735- kickerColour = { palette (
736- '--feature-card-kicker-text' ,
737- ) }
738- quoteColour = { palette (
739- '--feature-card-quote-icon' ,
709+ { isImmersive &&
710+ mainMedia ?. type === 'Audio' &&
711+ ! ! mainMedia . podcastImage
712+ ?. src && (
713+ < div
714+ css = {
715+ podcastImageContainerStyles
716+ }
717+ >
718+ < Hide until = "tablet" >
719+ { renderPodcastImage (
720+ mainMedia
721+ . podcastImage
722+ . src ,
723+ mainMedia
724+ . podcastImage
725+ . altText ??
726+ '' ,
727+ true ,
728+ ) }
729+ </ Hide >
730+ </ div >
740731 ) }
741- />
742- </ div >
743-
744- { ! isUndefined ( starRating ) && (
745- < StarRating
746- rating = { starRating }
747- size = { starRatingSize }
748- useAlternativeTheme = { true }
749- />
750- ) }
751732
752- { ! ! trailText && (
753- < div css = { trailTextWrapper } >
754- < TrailText
755- trailText = { trailText }
756- trailTextColour = { palette (
757- '--feature-card-trail-text' ,
733+ { /**
734+ * Without the wrapping div the headline and byline would have space
735+ * inserted between them due to being direct children of the flex container
736+ */ }
737+ < div >
738+ < CardHeadline
739+ headlineText = { headlineText }
740+ format = { format }
741+ fontSizes = { headlineSizes }
742+ showQuotes = { showQuotes }
743+ kickerText = {
744+ format . design ===
745+ ArticleDesign . LiveBlog &&
746+ ! kickerText
747+ ? 'Live'
748+ : kickerText
749+ }
750+ showPulsingDot = {
751+ format . design ===
752+ ArticleDesign . LiveBlog ||
753+ showPulsingDot
754+ }
755+ byline = { byline }
756+ showByline = { showByline }
757+ isExternalLink = {
758+ isExternalLink
759+ }
760+ headlineColour = { palette (
761+ '--feature-card-headline' ,
762+ ) }
763+ kickerColour = { palette (
764+ '--feature-card-kicker-text' ,
765+ ) }
766+ quoteColour = { palette (
767+ '--feature-card-quote-icon' ,
758768 ) }
759- trailTextSize = "regular"
760- padBottom = { false }
761- hideUntil = "tablet"
762769 />
763770 </ div >
764- ) }
765771
766- < CardFooter
767- format = { format }
768- age = {
769- showCardAge ? (
770- < FeatureCardCardAge
771- webPublicationDate = {
772- webPublicationDate
773- }
774- showClock = { ! ! showClock }
775- serverTime = { serverTime }
776- isStorylines = {
777- isStorylines
778- }
779- />
780- ) : undefined
781- }
782- commentCount = {
783- showCommentCount ? (
784- < FeatureCardCommentCount
785- linkTo = { linkTo }
786- discussionId = {
787- discussionId
788- }
789- discussionApiUrl = {
790- discussionApiUrl
791- }
792- />
793- ) : undefined
794- }
795- showLivePlayable = { false }
796- isNewsletter = { isNewsletter }
797- mainMedia = { mainMedia }
798- />
772+ { ! isUndefined ( starRating ) && (
773+ < StarRating
774+ rating = { starRating }
775+ size = { starRatingSize }
776+ useAlternativeTheme = { true }
777+ />
778+ ) }
799779
800- { ! isImmersive &&
801- mainMedia ?. type === 'Audio' &&
802- renderWaveform (
803- mainMedia . duration ,
804- 233 ,
780+ { ! ! trailText && (
781+ < div css = { trailTextWrapper } >
782+ < TrailText
783+ trailText = { trailText }
784+ trailTextColour = { palette (
785+ '--feature-card-trail-text' ,
786+ ) }
787+ trailTextSize = "regular"
788+ padBottom = { false }
789+ hideUntil = "tablet"
790+ />
791+ </ div >
805792 ) }
793+
794+ < CardFooter
795+ format = { format }
796+ age = {
797+ showCardAge ? (
798+ < FeatureCardCardAge
799+ webPublicationDate = {
800+ webPublicationDate
801+ }
802+ showClock = {
803+ ! ! showClock
804+ }
805+ serverTime = {
806+ serverTime
807+ }
808+ isStorylines = {
809+ isStorylines
810+ }
811+ />
812+ ) : undefined
813+ }
814+ commentCount = {
815+ showCommentCount ? (
816+ < FeatureCardCommentCount
817+ linkTo = { linkTo }
818+ discussionId = {
819+ discussionId
820+ }
821+ discussionApiUrl = {
822+ discussionApiUrl
823+ }
824+ />
825+ ) : undefined
826+ }
827+ showLivePlayable = { false }
828+ isNewsletter = { isNewsletter }
829+ mainMedia = { mainMedia }
830+ />
831+
832+ { ! isImmersive &&
833+ mainMedia ?. type === 'Audio' &&
834+ renderWaveform (
835+ mainMedia . duration ,
836+ 233 ,
837+ ) }
838+ </ div >
806839 </ div >
807840 </ div >
808841
0 commit comments