@comicrelief/component-library 8.49.0 → 8.50.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 (101) hide show
  1. package/dist/components/Atoms/Button/Button.style.js +1 -1
  2. package/dist/components/Atoms/Button/Button.test.js +1 -1
  3. package/dist/components/Atoms/Link/Link.style.js +1 -1
  4. package/dist/components/Atoms/Link/Link.test.js +1 -1
  5. package/dist/components/Molecules/ArticleTeaser/ArticleTeaser.js +0 -1
  6. package/dist/components/Molecules/ArticleTeaser/ArticleTeaser.test.js +0 -2
  7. package/dist/components/Molecules/CTA/CTAMultiCard/CTAMultiCard.js +59 -0
  8. package/{src/components/Molecules → dist/components/Molecules/CTA}/CTAMultiCard/CTAMultiCard.md +4 -4
  9. package/dist/components/Molecules/CTA/CTAMultiCard/CTAMultiCard.style.js +55 -0
  10. package/dist/components/Molecules/CTA/CTAMultiCard/CTAMultiCard.test.js +91 -0
  11. package/dist/components/Molecules/CTA/CTAMultiCard/__snapshots__/CTAMultiCard.test.js.snap +2931 -0
  12. package/dist/components/Molecules/CTA/CTAMultiCard/example_data.json +107 -0
  13. package/dist/components/Molecules/CTA/CTASingleCard/CTASingleCard.js +44 -0
  14. package/dist/components/Molecules/CTA/CTASingleCard/CTASingleCard.md +124 -0
  15. package/dist/components/Molecules/CTA/CTASingleCard/CTASingleCard.style.js +23 -0
  16. package/dist/components/Molecules/CTA/CTASingleCard/CTASingleCard.test.js +96 -0
  17. package/dist/components/Molecules/CTA/CTASingleCard/__snapshots__/CTASingleCard.test.js.snap +903 -0
  18. package/dist/components/Molecules/CTA/shared/CTACard.js +67 -0
  19. package/dist/components/Molecules/CTA/shared/CTACard.style.js +269 -0
  20. package/dist/components/Molecules/{CTAMultiCard → CTA/shared}/_ArrowIcon.js +1 -1
  21. package/dist/components/Molecules/CardDs/__snapshots__/CardDs.test.js.snap +2 -2
  22. package/dist/components/Molecules/Countdown/Countdown.js +4 -8
  23. package/dist/components/Molecules/Descriptor/Descriptor.js +1 -2
  24. package/dist/components/Molecules/Descriptor/Descriptor.test.js +0 -2
  25. package/dist/components/Molecules/InfoBanner/InfoBanner.js +6 -12
  26. package/dist/components/Molecules/InfoBanner/__snapshots__/InfoBanner.test.js.snap +0 -1
  27. package/dist/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/CTAMultiCard.style.js +11 -11
  28. package/dist/components/Molecules/OLD_CTAMultiCard/_ArrowIcon.js +29 -0
  29. package/dist/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/__snapshots__/CTAMultiCard.test.js.snap +8 -0
  30. package/dist/components/Molecules/Promo/__snapshots__/Promo.test.js.snap +2 -2
  31. package/dist/components/Molecules/SearchResult/SearchResult.js +2 -4
  32. package/dist/components/Molecules/SearchResult/__snapshots__/SearchResult.test.js.snap +0 -8
  33. package/dist/components/Molecules/SingleMessage/__snapshots__/SingleMessage.test.js.snap +2 -2
  34. package/dist/components/Molecules/SingleMessageDS/SingleMessageDs.style.js +1 -1
  35. package/dist/components/Molecules/SingleMessageDS/__snapshots__/SingleMessageDs.test.js.snap +1 -2
  36. package/dist/components/Organisms/CookieBanner/CookieBanner.test.js +1 -1
  37. package/dist/components/Organisms/Donate/Donate.js +1 -2
  38. package/dist/components/Organisms/Donate/__snapshots__/Donate.test.js.snap +0 -4
  39. package/dist/components/Organisms/EmailSignUp/_EmailSignUp.js +1 -2
  40. package/dist/components/Organisms/EmailSignUp/__snapshots__/EmailSignUp.test.js.snap +1 -2
  41. package/dist/components/Organisms/FooterNew/__snapshots__/FooterNew.test.js.snap +1 -1
  42. package/dist/components/Organisms/ImpactSlider/ImpactSlider.js +0 -1
  43. package/dist/components/Organisms/ImpactSlider/_ImpactMoneybuys.js +0 -1
  44. package/dist/components/Organisms/WYMDCarousel/WYMDCarousel.js +0 -2
  45. package/dist/components/Organisms/WYMDCarousel/__snapshots__/WYMDCarousel.test.js.snap +0 -1
  46. package/dist/index.js +8 -1
  47. package/package.json +1 -1
  48. package/src/components/Atoms/Button/Button.style.js +1 -1
  49. package/src/components/Atoms/Button/Button.test.js +1 -1
  50. package/src/components/Atoms/Link/Link.style.js +1 -1
  51. package/src/components/Atoms/Link/Link.test.js +1 -1
  52. package/src/components/Molecules/ArticleTeaser/ArticleTeaser.js +0 -1
  53. package/src/components/Molecules/ArticleTeaser/ArticleTeaser.test.js +0 -2
  54. package/src/components/Molecules/CTA/CTAMultiCard/CTAMultiCard.js +99 -0
  55. package/{dist/components/Molecules → src/components/Molecules/CTA}/CTAMultiCard/CTAMultiCard.md +4 -4
  56. package/src/components/Molecules/CTA/CTAMultiCard/CTAMultiCard.style.js +68 -0
  57. package/src/components/Molecules/CTA/CTAMultiCard/CTAMultiCard.test.js +107 -0
  58. package/src/components/Molecules/CTA/CTAMultiCard/__snapshots__/CTAMultiCard.test.js.snap +2931 -0
  59. package/src/components/Molecules/CTA/CTAMultiCard/example_data.json +107 -0
  60. package/src/components/Molecules/CTA/CTASingleCard/CTASingleCard.js +72 -0
  61. package/src/components/Molecules/CTA/CTASingleCard/CTASingleCard.md +124 -0
  62. package/src/components/Molecules/CTA/CTASingleCard/CTASingleCard.style.js +19 -0
  63. package/src/components/Molecules/CTA/CTASingleCard/CTASingleCard.test.js +96 -0
  64. package/src/components/Molecules/CTA/CTASingleCard/__snapshots__/CTASingleCard.test.js.snap +903 -0
  65. package/src/components/Molecules/CTA/shared/CTACard.js +115 -0
  66. package/src/components/Molecules/CTA/shared/CTACard.style.js +356 -0
  67. package/src/components/Molecules/CardDs/__snapshots__/CardDs.test.js.snap +2 -2
  68. package/src/components/Molecules/Countdown/Countdown.js +4 -4
  69. package/src/components/Molecules/Descriptor/Descriptor.js +0 -2
  70. package/src/components/Molecules/Descriptor/Descriptor.test.js +0 -2
  71. package/src/components/Molecules/InfoBanner/InfoBanner.js +6 -6
  72. package/src/components/Molecules/InfoBanner/__snapshots__/InfoBanner.test.js.snap +0 -1
  73. package/src/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/CTAMultiCard.style.js +2 -0
  74. package/src/components/Molecules/OLD_CTAMultiCard/_ArrowIcon.js +22 -0
  75. package/src/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/__snapshots__/CTAMultiCard.test.js.snap +8 -0
  76. package/src/components/Molecules/Promo/__snapshots__/Promo.test.js.snap +2 -2
  77. package/src/components/Molecules/SearchResult/SearchResult.js +2 -2
  78. package/src/components/Molecules/SearchResult/__snapshots__/SearchResult.test.js.snap +0 -8
  79. package/src/components/Molecules/SingleMessage/__snapshots__/SingleMessage.test.js.snap +2 -2
  80. package/src/components/Molecules/SingleMessageDS/SingleMessageDs.style.js +0 -1
  81. package/src/components/Molecules/SingleMessageDS/__snapshots__/SingleMessageDs.test.js.snap +1 -2
  82. package/src/components/Organisms/CookieBanner/CookieBanner.test.js +1 -1
  83. package/src/components/Organisms/Donate/Donate.js +1 -1
  84. package/src/components/Organisms/Donate/__snapshots__/Donate.test.js.snap +0 -4
  85. package/src/components/Organisms/EmailSignUp/_EmailSignUp.js +1 -1
  86. package/src/components/Organisms/EmailSignUp/__snapshots__/EmailSignUp.test.js.snap +1 -2
  87. package/src/components/Organisms/FooterNew/__snapshots__/FooterNew.test.js.snap +1 -1
  88. package/src/components/Organisms/ImpactSlider/ImpactSlider.js +1 -1
  89. package/src/components/Organisms/ImpactSlider/_ImpactMoneybuys.js +1 -1
  90. package/src/components/Organisms/WYMDCarousel/WYMDCarousel.js +2 -2
  91. package/src/components/Organisms/WYMDCarousel/__snapshots__/WYMDCarousel.test.js.snap +0 -1
  92. package/src/index.js +2 -1
  93. /package/dist/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/CTAMultiCard.js +0 -0
  94. /package/dist/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/CTAMultiCard.test.js +0 -0
  95. /package/dist/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/SingleCard.js +0 -0
  96. /package/dist/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/example_data.json +0 -0
  97. /package/src/components/Molecules/{CTAMultiCard → CTA/shared}/_ArrowIcon.js +0 -0
  98. /package/src/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/CTAMultiCard.js +0 -0
  99. /package/src/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/CTAMultiCard.test.js +0 -0
  100. /package/src/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/SingleCard.js +0 -0
  101. /package/src/components/Molecules/{CTAMultiCard → OLD_CTAMultiCard}/example_data.json +0 -0
@@ -0,0 +1,115 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import Picture from '../../../Atoms/Picture/Picture';
4
+ import ArrowIcon from './_ArrowIcon';
5
+ import altCtaUnderline from '../../../../theme/shared/assets/alt_cta_underline.svg';
6
+ import {
7
+ CardLink,
8
+ ImageWrapper,
9
+ CopyAndLinkSection,
10
+ Copy,
11
+ CTA,
12
+ CTAText,
13
+ CTATextUnderline,
14
+ ArrowIconWrapper,
15
+ CardWrapper
16
+ } from './CTACard.style';
17
+
18
+ const CTACard = ({
19
+ card,
20
+ columns,
21
+ isCarousel,
22
+ isFullWidth,
23
+ isSingleCard
24
+ }) => {
25
+ // isSingleCard implies isFullWidth - single cards are always full width
26
+ const effectiveIsFullWidth = isSingleCard || isFullWidth;
27
+
28
+ const {
29
+ id,
30
+ body,
31
+ link,
32
+ linkLabel,
33
+ fallback,
34
+ imageLow,
35
+ images,
36
+ bgColour,
37
+ description,
38
+ target,
39
+ external
40
+ } = card;
41
+
42
+ return (
43
+ <CardWrapper
44
+ key={id}
45
+ isCarousel={isCarousel}
46
+ isFullWidth={effectiveIsFullWidth}
47
+ columns={columns}
48
+ >
49
+ <CardLink
50
+ href={link}
51
+ target={target}
52
+ rel={external}
53
+ isCarousel={isCarousel}
54
+ isSingleCard={isSingleCard}
55
+ backgroundColor={bgColour}
56
+ >
57
+ {imageLow && (
58
+ <ImageWrapper isSingleCard={isSingleCard}>
59
+ <Picture
60
+ alt={description}
61
+ imageLow={imageLow}
62
+ images={images}
63
+ image={fallback}
64
+ objectFit="cover"
65
+ width="100%"
66
+ height="100%"
67
+ />
68
+ </ImageWrapper>
69
+ )}
70
+ <CopyAndLinkSection backgroundColor={bgColour} isSingleCard={isSingleCard}>
71
+ <Copy>
72
+ {body}
73
+ </Copy>
74
+ {linkLabel && (
75
+ <CTA>
76
+ <CTAText>
77
+ {linkLabel}
78
+ <CTATextUnderline
79
+ src={altCtaUnderline}
80
+ alt=""
81
+ aria-hidden="true"
82
+ />
83
+ </CTAText>
84
+ <ArrowIconWrapper>
85
+ <ArrowIcon />
86
+ </ArrowIconWrapper>
87
+ </CTA>
88
+ )}
89
+ </CopyAndLinkSection>
90
+ </CardLink>
91
+ </CardWrapper>
92
+ );
93
+ };
94
+
95
+ CTACard.propTypes = {
96
+ card: PropTypes.shape({
97
+ id: PropTypes.string.isRequired,
98
+ body: PropTypes.node,
99
+ link: PropTypes.string.isRequired,
100
+ linkLabel: PropTypes.string,
101
+ fallback: PropTypes.string,
102
+ imageLow: PropTypes.string,
103
+ images: PropTypes.string,
104
+ bgColour: PropTypes.string.isRequired,
105
+ description: PropTypes.string,
106
+ target: PropTypes.string.isRequired,
107
+ external: PropTypes.string
108
+ }).isRequired,
109
+ columns: PropTypes.oneOf([2, 3]),
110
+ isCarousel: PropTypes.bool,
111
+ isFullWidth: PropTypes.bool,
112
+ isSingleCard: PropTypes.bool
113
+ };
114
+
115
+ export default CTACard;
@@ -0,0 +1,356 @@
1
+ import styled, { css } from 'styled-components';
2
+ import { bounceUpAnimation, springScaleAnimation } from '../../../../theme/shared/animations';
3
+ import { breakpointValues } from '../../../../theme/shared/allBreakpoints';
4
+ import fontHelper from '../../../../theme/crTheme/fontHelper';
5
+
6
+ // const CardsContainer = styled.div`
7
+ // display: flex;
8
+ // flex-direction: column;
9
+ // width: 100%;
10
+ // background: ${({ theme, backgroundColor }) => theme.color(backgroundColor)};
11
+ // gap: 1rem;
12
+
13
+ // // Mobile carousel mode - horizontal scroll container (only on mobile, below M breakpoint)
14
+ // ${({ isCarousel }) => isCarousel && css`
15
+ // @media (max-width: ${breakpointValues.M - 1}px) {
16
+ // flex-direction: row;
17
+ // flex-wrap: nowrap;
18
+ // overflow-x: visible;
19
+ // overflow-y: scroll;
20
+ // -webkit-overflow-scrolling: touch;
21
+ // scroll-snap-type: x mandatory;
22
+ // padding: 0.75rem 0.5rem;
23
+ // margin-left: 0.5rem;
24
+
25
+ // scrollbar-width: none;
26
+ // -ms-overflow-style: none;
27
+ // &::-webkit-scrollbar {
28
+ // display: none;
29
+ // }
30
+ // }
31
+ // `}
32
+
33
+ // // Mobile stack mode - vertical layout (only on mobile, below M breakpoint)
34
+ // ${({ isCarousel }) => !isCarousel && css`
35
+ // @media (max-width: ${breakpointValues.M - 1}px) {
36
+ // flex-direction: column;
37
+ // background: transparent;
38
+ // }
39
+ // `}
40
+
41
+ // // Desktop flexbox layout - 2 columns with centered wrap
42
+ // @media ${({ theme }) => theme.allBreakpoints('M')} {
43
+ // flex-direction: row;
44
+ // flex-wrap: wrap;
45
+ // justify-content: center;
46
+ // align-items: stretch;
47
+ // width: fit-content;
48
+ // max-width: 100%;
49
+ // margin: 0 auto;
50
+ // }
51
+
52
+ // // Desktop grid layout for XL breakpoint - 3 columns
53
+ // @media ${({ theme }) => theme.allBreakpoints('XL')} {
54
+ // display: grid;
55
+ // justify-content: center;
56
+ // grid-template-columns: ${({ columns }) => `repeat(${columns}, 1fr)`};
57
+ // width: ${({ columns }) => (columns === 2 ? 'fit-content' : '100%')};
58
+ // margin: ${({ columns }) => (columns === 2 ? '0 auto' : '0')};
59
+ // max-width: 100%;
60
+ // }
61
+ // `;
62
+
63
+ const ImageWrapper = styled.div`
64
+ width: 100%;
65
+ overflow: hidden;
66
+ flex-shrink: 0;
67
+ background: transparent;
68
+ border-radius: 1rem 1rem 0 0;
69
+
70
+ // Side-by-side layout: fixed proportion for image (1/3 width) with min/max constraints
71
+ ${({ isSingleCard }) => isSingleCard && css`
72
+ @media ${({ theme }) => theme.breakpoints2026('M')} {
73
+ width: calc(100% / 3);
74
+ min-width: 292px;
75
+ max-width: 309px;
76
+ flex-shrink: 0;
77
+ flex-grow: 0;
78
+ height: 100%;
79
+ border-radius: 1rem 0 0 1rem;
80
+ }
81
+
82
+ @media ${({ theme }) => theme.breakpoints2026('L')} {
83
+ min-width: 355px;
84
+ max-width: 362px;
85
+ }
86
+
87
+ @media ${({ theme }) => theme.breakpoints2026('XL')} {
88
+ min-width: 363px;
89
+ max-width: 363px;
90
+ }
91
+ `}
92
+
93
+ img {
94
+ width: 100%;
95
+ height: auto;
96
+ object-fit: cover;
97
+ display: block;
98
+
99
+ // Side-by-side layout: image should fill height on desktop
100
+ ${({ isSingleCard }) => isSingleCard && css`
101
+ @media ${({ theme }) => theme.breakpoints2026('M')} {
102
+ height: 100%;
103
+ object-fit: cover;
104
+ }
105
+ `}
106
+
107
+ // Desktop-only image zoom animation on card hover
108
+ @media ${({ theme }) => theme.allBreakpoints('M')} {
109
+ ${springScaleAnimation(true)}
110
+ }
111
+ }
112
+ `;
113
+
114
+ const CTAText = styled.span`
115
+ ${({ theme }) => fontHelper(theme, 'span')}
116
+ color: ${({ theme }) => theme.color('grey')};
117
+ font-weight: bold;
118
+ text-decoration: none;
119
+ position: relative;
120
+ display: inline-block;
121
+ `;
122
+
123
+ const CTATextUnderline = styled.img`
124
+ height: 4px;
125
+ width: 100%;
126
+ position: absolute;
127
+ left: 0;
128
+ bottom: -5px;
129
+ transition: opacity 0.15s 0.1s;
130
+ opacity: 0;
131
+ pointer-events: none;
132
+ `;
133
+
134
+ const ArrowIconWrapper = styled.div`
135
+ width: 32px;
136
+ height: 32px;
137
+ border-radius: 50%;
138
+ background: ${({ theme }) => theme.color('grey')};
139
+ display: flex;
140
+ align-items: center;
141
+ justify-content: center;
142
+ flex-shrink: 0;
143
+ `;
144
+
145
+ // Card wrapper link - makes entire card clickable
146
+ const CardLink = styled.a`
147
+ display: flex;
148
+ position: relative;
149
+ flex-direction: column;
150
+ width: 100%;
151
+ flex: 1 1 auto;
152
+ background: transparent;
153
+ border-radius: 1rem;
154
+ box-shadow: 0 0 1rem rgba(0, 0, 0, 0.15);
155
+ text-decoration: none;
156
+ overflow: hidden;
157
+ cursor: pointer;
158
+ box-sizing: border-box;
159
+
160
+ // Side-by-side layout for single card desktop view
161
+ ${({ isSingleCard }) => isSingleCard && css`
162
+ @media ${({ theme }) => theme.breakpoints2026('M')} {
163
+ flex-direction: row;
164
+ align-items: stretch;
165
+ // the 4 rem below is to account for the padding of the CopyAndLinkSection
166
+ min-height: calc(219px - 4rem);
167
+ }
168
+
169
+ @media ${({ theme }) => theme.breakpoints2026('L')} {
170
+ min-height: calc(272px - 4rem);
171
+ }
172
+ `}
173
+
174
+ img {
175
+ // Zoom the image in slightly by default so the 'bounce' animation doesn't cause issues
176
+ transform: scale(1.02);
177
+ transition: transform ${0.4}s cubic-bezier(0.68, ${-1.15}, 0.265, ${2.35});
178
+ }
179
+
180
+ // Desktop-only hover effects
181
+ @media ${({ theme }) => theme.allBreakpoints('M')} {
182
+ ${bounceUpAnimation(true, 0.02, 1)};
183
+
184
+ &:hover {
185
+ box-shadow: 0 0 1.5rem rgba(0, 0, 0, 0.25);
186
+
187
+ ${ImageWrapper} img {
188
+ transform: scale(1.1);
189
+ }
190
+
191
+ ${CTAText} {
192
+ color: ${({ theme }) => theme.color('red')};
193
+ text-decoration: none;
194
+ }
195
+
196
+ ${CTATextUnderline} {
197
+ opacity: 1;
198
+ }
199
+
200
+ ${ArrowIconWrapper} {
201
+ background: ${({ theme }) => theme.color('red')};
202
+ }
203
+ }
204
+ }
205
+ `;
206
+
207
+ const CardWrapper = styled.div`
208
+ width: 100%;
209
+ flex-shrink: 0;
210
+ display: flex;
211
+ flex-direction: column;
212
+ align-self: stretch;
213
+
214
+ // Full width mode - always full width, no constraints
215
+ ${({ isFullWidth }) => isFullWidth && css`
216
+ width: 100%;
217
+ max-width: 100%;
218
+
219
+ @media ${({ theme }) => theme.allBreakpoints('M')} {
220
+ flex-basis: 100%;
221
+ max-width: 100%;
222
+ height: auto;
223
+ }
224
+
225
+ @media ${({ theme }) => theme.allBreakpoints('XL')} {
226
+ flex-basis: 100%;
227
+ max-width: 100%;
228
+ height: auto;
229
+ }
230
+ `}
231
+
232
+ // Carousel mode - fixed card width in horizontal scroll (L and below)
233
+ ${({ isCarousel, isFullWidth }) => isCarousel && !isFullWidth && css`
234
+ @media (max-width: ${breakpointValues.L - 1}px) {
235
+ scroll-snap-align: start;
236
+ flex: 0 0 309px;
237
+ width: 309px;
238
+ flex-shrink: 0;
239
+ }
240
+ `}
241
+
242
+ // Below L: max-width rules vary by layout
243
+ ${({ isCarousel, isFullWidth }) => !isCarousel && !isFullWidth && css`
244
+ /* Below M: stacked cards, keep them centred */
245
+ @media (max-width: ${breakpointValues.M - 1}px) {
246
+ max-width: ${({ columns }) => (columns === 3 ? '309px' : '345px')};
247
+ margin-left: auto;
248
+ margin-right: auto;
249
+ }
250
+
251
+ @media (min-width: ${breakpointValues.M}px) and (max-width: ${breakpointValues.L - 1}px) {
252
+ align-self: stretch;
253
+ ${({ columns }) => (columns === 3
254
+ ? css`
255
+ flex: 0 0 100%;
256
+ max-width: 309px;
257
+ margin-left: auto;
258
+ margin-right: auto;
259
+ `
260
+ : css`
261
+ flex: 0 0 345px;
262
+ max-width: 345px;
263
+ margin-left: 0;
264
+ margin-right: 0;
265
+ `)}
266
+ }
267
+ `}
268
+
269
+ // L breakpoint: min/max rules vary by layout
270
+ ${({ isFullWidth }) => !isFullWidth && css`
271
+ @media (min-width: ${breakpointValues.L}px) and (max-width: ${breakpointValues.XL - 1}px) {
272
+ ${({ columns }) => (
273
+ columns === 3
274
+ ? css`
275
+ flex-basis: calc(33.333% - 1rem);
276
+ min-width: 286px;
277
+ max-width: 371px;
278
+ `
279
+ : css`
280
+ flex-basis: calc(50% - 1rem);
281
+ min-width: 443px;
282
+ max-width: 564px;
283
+ `
284
+ )}
285
+ align-self: stretch;
286
+ }
287
+
288
+ // XL breakpoint and above: fixed widths vary by layout
289
+ @media ${({ theme }) => theme.allBreakpoints('XL')} {
290
+ flex-basis: unset;
291
+ width: ${({ columns }) => (columns === 3 ? '371px' : '564px')};
292
+ align-self: stretch;
293
+ }
294
+ `}
295
+ `;
296
+
297
+ const CopyAndLinkSection = styled.div`
298
+ width: 100%;
299
+ background: ${({ theme, backgroundColor }) => theme.color(backgroundColor)};
300
+ display: flex;
301
+ flex-direction: column;
302
+ padding: 2rem;
303
+ flex: 1;
304
+ min-height: 0;
305
+ border-radius: 0 0 1rem 1rem;
306
+
307
+ // Side-by-side layout: text section takes remaining width (2/3) with min/max constraints
308
+ ${({ isSingleCard }) => isSingleCard && css`
309
+ @media ${({ theme }) => theme.breakpoints2026('M')} {
310
+ width: calc(200% / 3);
311
+ min-width: 384px;
312
+ max-width: 650px;
313
+ flex: 1;
314
+ border-radius: 0 1rem 1rem 0;
315
+ }
316
+
317
+ @media ${({ theme }) => theme.breakpoints2026('L')} {
318
+ min-width: 541px;
319
+ max-width: 790px;
320
+ }
321
+
322
+ @media ${({ theme }) => theme.breakpoints2026('XL')} {
323
+ width: 789px;
324
+ }
325
+ `}
326
+ `;
327
+
328
+ const Copy = styled.div`
329
+ flex: 1;
330
+ display: flex;
331
+ flex-direction: column;
332
+ min-height: 0;
333
+ `;
334
+
335
+ const CTA = styled.div`
336
+ width: 100%;
337
+ display: flex;
338
+ flex-direction: row;
339
+ align-items: center;
340
+ justify-content: space-between;
341
+ margin-top: auto;
342
+ padding-top: 1rem;
343
+ `;
344
+
345
+ export {
346
+ CardLink,
347
+ // CardsContainer,
348
+ ImageWrapper,
349
+ CopyAndLinkSection,
350
+ Copy,
351
+ CTA,
352
+ CTAText,
353
+ CTATextUnderline,
354
+ ArrowIconWrapper,
355
+ CardWrapper
356
+ };
@@ -37,7 +37,7 @@ exports[`renders Column view correctly 1`] = `
37
37
  text-decoration: none;
38
38
  -webkit-transition: all 0.2s;
39
39
  transition: all 0.2s;
40
- min-height: 2.5em;
40
+ height: 2.5rem;
41
41
  width: 100%;
42
42
  -webkit-box-pack: center;
43
43
  -webkit-justify-content: center;
@@ -319,7 +319,7 @@ exports[`renders correctly 1`] = `
319
319
  text-decoration: none;
320
320
  -webkit-transition: all 0.2s;
321
321
  transition: all 0.2s;
322
- min-height: 2.5em;
322
+ height: 2.5rem;
323
323
  width: 100%;
324
324
  -webkit-box-pack: center;
325
325
  -webkit-justify-content: center;
@@ -58,7 +58,7 @@ const Countdown = ({
58
58
  <Text color={color} family="Anton" size="xl">
59
59
  {countdownTime.days}
60
60
  </Text>
61
- <Text color={color} size="xs" uppercase>
61
+ <Text color={color} size="xs">
62
62
  days
63
63
  </Text>
64
64
  </Digits>
@@ -69,7 +69,7 @@ const Countdown = ({
69
69
  <Text color={color} family="Anton" size="xl">
70
70
  {countdownTime.hours}
71
71
  </Text>
72
- <Text color={color} size="xs" uppercase>
72
+ <Text color={color} size="xs">
73
73
  hours
74
74
  </Text>
75
75
  </Digits>
@@ -80,7 +80,7 @@ const Countdown = ({
80
80
  <Text color={color} family="Anton" size="xl">
81
81
  {countdownTime.minutes}
82
82
  </Text>
83
- <Text color={color} size="xs" uppercase>
83
+ <Text color={color} size="xs">
84
84
  minutes
85
85
  </Text>
86
86
  </Digits>
@@ -88,7 +88,7 @@ const Countdown = ({
88
88
  <Text color={color} family="Anton" size="xl">
89
89
  {countdownTime.seconds}
90
90
  </Text>
91
- <Text color={color} size="xs" uppercase>
91
+ <Text color={color} size="xs">
92
92
  seconds
93
93
  </Text>
94
94
  </Digits>
@@ -124,7 +124,6 @@ const TagWrapper = styled.div`
124
124
 
125
125
  const Tag = styled(Text)`
126
126
  position: relative;
127
- text-transform: uppercase;
128
127
  `;
129
128
 
130
129
  const Description = styled.div`
@@ -172,7 +171,6 @@ const Descriptor = ({
172
171
  tag="h3"
173
172
  height="2rem"
174
173
  weight="normal"
175
- uppercase
176
174
  family="Anton"
177
175
  >
178
176
  {title}
@@ -67,7 +67,6 @@ it('renders article teaser correctly', () => {
67
67
  font-family: 'Anton',Impact,sans-serif;
68
68
  font-weight: normal;
69
69
  line-height: 2rem;
70
- text-transform: uppercase;
71
70
  }
72
71
 
73
72
  .c7 span {
@@ -189,7 +188,6 @@ it('renders article teaser correctly', () => {
189
188
 
190
189
  .c11 {
191
190
  position: relative;
192
- text-transform: uppercase;
193
191
  }
194
192
 
195
193
  .c12 {
@@ -42,7 +42,7 @@ const InfoBanner = ({
42
42
  }) => (
43
43
  <Container>
44
44
  <Info>
45
- <Text tag="h3" size="md" uppercase>
45
+ <Text tag="h3" size="md">
46
46
  Project Name
47
47
  </Text>
48
48
  <Text tag="p" size="s">
@@ -50,7 +50,7 @@ const InfoBanner = ({
50
50
  </Text>
51
51
  </Info>
52
52
  <Info>
53
- <Text tag="h3" size="md" uppercase>
53
+ <Text tag="h3" size="md">
54
54
  End Date
55
55
  </Text>
56
56
  <Text tag="p" size="s">
@@ -58,7 +58,7 @@ const InfoBanner = ({
58
58
  </Text>
59
59
  </Info>
60
60
  <Info>
61
- <Text tag="h3" size="md" uppercase>
61
+ <Text tag="h3" size="md">
62
62
  Funding theme
63
63
  </Text>
64
64
  <Text tag="p" size="s">
@@ -68,7 +68,7 @@ const InfoBanner = ({
68
68
  </Text>
69
69
  </Info>
70
70
  <Info>
71
- <Text tag="h3" size="md" uppercase>
71
+ <Text tag="h3" size="md">
72
72
  Amount Awarded
73
73
  </Text>
74
74
  <Text tag="p" size="s">
@@ -82,7 +82,7 @@ const InfoBanner = ({
82
82
  </Text>
83
83
  </Info>
84
84
  <Info>
85
- <Text tag="h3" size="md" uppercase>
85
+ <Text tag="h3" size="md">
86
86
  Start Date
87
87
  </Text>
88
88
  <Text tag="p" size="s">
@@ -90,7 +90,7 @@ const InfoBanner = ({
90
90
  </Text>
91
91
  </Info>
92
92
  <Info>
93
- <Text tag="h3" size="md" uppercase>
93
+ <Text tag="h3" size="md">
94
94
  Beneficiary Country
95
95
  </Text>
96
96
  <Text tag="p" size="s">
@@ -16,7 +16,6 @@ exports[`renders correctly 1`] = `
16
16
  .c2 {
17
17
  font-size: undefined;
18
18
  line-height: normal;
19
- text-transform: uppercase;
20
19
  }
21
20
 
22
21
  .c2 span {
@@ -204,6 +204,7 @@ const CardWrapper = styled.div`
204
204
  @media ${({ theme, isCarousel }) => theme.allBreakpoints(isCarousel ? 'L' : 'M')} {
205
205
  flex-basis: calc(50% - 1rem);
206
206
  max-width: 564px;
207
+ height: 100%;
207
208
  align-self: stretch;
208
209
  }
209
210
 
@@ -211,6 +212,7 @@ const CardWrapper = styled.div`
211
212
  @media ${({ theme }) => theme.allBreakpoints('XL')} {
212
213
  flex-basis: unset;
213
214
  max-width: 564px;
215
+ height: 100%;
214
216
  align-self: stretch;
215
217
  }
216
218
  `;
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ const StyledArrowIcon = styled.svg`
5
+ display: inline-block;
6
+ color: ${({ theme }) => theme.color('white')};
7
+ fill: currentColor;
8
+ `;
9
+
10
+ const ArrowIcon = () => (
11
+ <StyledArrowIcon
12
+ width="15"
13
+ height="13"
14
+ viewBox="0 0 15 13"
15
+ fill="none"
16
+ xmlns="http://www.w3.org/2000/svg"
17
+ >
18
+ <path d="M9.58496 0.349976C9.1395 -0.116662 8.40641 -0.116634 7.96094 0.349976C7.52803 0.803486 7.5281 1.53021 7.96094 1.98376L11.1582 5.33337H1.13672C0.48748 5.33337 0 5.87822 0 6.50037C2.15408e-05 7.1225 0.487494 7.66736 1.13672 7.66736H11.1582L7.96094 11.017C7.52806 11.4705 7.52899 12.1972 7.96191 12.6508C8.18163 12.8803 8.47556 13.0004 8.77344 13.0004C9.07114 13.0002 9.36533 12.8808 9.58496 12.6508L14.6758 7.31677L14.6748 7.3158L14.6875 7.3031L14.6865 7.30212C14.6954 7.29215 14.7044 7.28482 14.71 7.27771C14.7117 7.27545 14.7133 7.27285 14.7148 7.27087C14.7485 7.23203 14.7824 7.18925 14.8135 7.14099L14.8154 7.13806C14.8354 7.10658 14.8493 7.07842 14.8564 7.06384L14.8652 7.04626L14.8662 7.04431L14.8672 7.04333C14.8672 7.04333 14.868 7.04057 14.8691 7.03845C14.8709 7.03512 14.8758 7.02671 14.8799 7.01892L14.8802 7.01839C14.8888 7.002 14.9034 6.97423 14.917 6.93982V6.93787C14.9303 6.90375 14.9391 6.87285 14.9443 6.85388C14.9469 6.84458 14.9498 6.83567 14.9512 6.83044C14.9527 6.82454 14.9535 6.8228 14.9541 6.82068C14.9541 6.82068 14.9542 6.81753 14.9551 6.81482L14.958 6.80603L14.9586 6.80422C14.9631 6.78961 14.9718 6.76119 14.9785 6.72693V6.72498C15.0066 6.57705 15.0066 6.4246 14.9785 6.27673V6.27478L14.958 6.19568L14.9551 6.18591L14.9531 6.18005L14.9512 6.17224C14.9497 6.1664 14.9481 6.15677 14.9453 6.14685C14.9398 6.12695 14.9307 6.09654 14.917 6.06189C14.9032 6.02688 14.8885 5.99813 14.8799 5.98181C14.8758 5.97402 14.8709 5.96562 14.8691 5.96228L14.8564 5.93689C14.849 5.92177 14.8351 5.89372 14.8154 5.86267L14.8145 5.86072L14.7529 5.7738C14.7316 5.74659 14.7094 5.72129 14.6875 5.69763C14.6837 5.69341 14.6802 5.68854 14.6758 5.68396L9.58496 0.349976Z" fill="currentColor" />
19
+ </StyledArrowIcon>
20
+ );
21
+
22
+ export default ArrowIcon;