@codeforamerica/marcomms-design-system 1.19.0 → 1.19.1

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 (91) hide show
  1. package/package.json +2 -1
  2. package/src/components/accordion.js +141 -0
  3. package/src/components/accordion.stories.js +56 -0
  4. package/src/components/avatar.js +62 -0
  5. package/src/components/avatar.stories.js +27 -0
  6. package/src/components/bar.js +102 -0
  7. package/src/components/bar.stories.js +22 -0
  8. package/src/components/blob.js +128 -0
  9. package/src/components/blob.stories.js +73 -0
  10. package/src/components/box.js +55 -0
  11. package/src/components/box.stories.js +24 -0
  12. package/src/components/breadcrumbs.js +80 -0
  13. package/src/components/breadcrumbs.stories.js +27 -0
  14. package/src/components/button.js +163 -0
  15. package/src/components/button.scss +157 -0
  16. package/src/components/button.stories.js +49 -0
  17. package/src/components/callout.js +62 -0
  18. package/src/components/callout.stories.js +20 -0
  19. package/src/components/card.js +456 -0
  20. package/src/components/card.stories.js +227 -0
  21. package/src/components/carousel.js +662 -0
  22. package/src/components/carousel.stories.js +165 -0
  23. package/src/components/details.scss +71 -0
  24. package/src/components/details.stories.js +27 -0
  25. package/src/components/form-elements.scss +304 -0
  26. package/src/components/form-elements.stories.js +134 -0
  27. package/src/components/icon.js +44 -0
  28. package/src/components/icon.scss +32 -0
  29. package/src/components/icon.stories.js +38 -0
  30. package/src/components/label.js +63 -0
  31. package/src/components/label.stories.js +29 -0
  32. package/src/components/link-list.scss +80 -0
  33. package/src/components/link-list.stories.js +52 -0
  34. package/src/components/loader.scss +24 -0
  35. package/src/components/loader.stories.js +12 -0
  36. package/src/components/logo-card.js +93 -0
  37. package/src/components/logo-card.stories.js +48 -0
  38. package/src/components/nav.js +98 -0
  39. package/src/components/nav.stories.js +40 -0
  40. package/src/components/page-nav.js +171 -0
  41. package/src/components/page-nav.stories.js +112 -0
  42. package/src/components/pager.js +98 -0
  43. package/src/components/pager.stories.js +30 -0
  44. package/src/components/pagination.js +116 -0
  45. package/src/components/pagination.stories.js +30 -0
  46. package/src/components/person-card.js +240 -0
  47. package/src/components/person-card.stories.js +58 -0
  48. package/src/components/pill.js +33 -0
  49. package/src/components/pill.stories.js +25 -0
  50. package/src/components/placeholder.js +25 -0
  51. package/src/components/placeholder.stories.js +10 -0
  52. package/src/components/promo.js +82 -0
  53. package/src/components/promo.stories.js +37 -0
  54. package/src/components/pullquote.js +42 -0
  55. package/src/components/pullquote.stories.js +16 -0
  56. package/src/components/quote.js +111 -0
  57. package/src/components/quote.stories.js +23 -0
  58. package/src/components/reveal.js +83 -0
  59. package/src/components/reveal.stories.js +40 -0
  60. package/src/components/slide.js +122 -0
  61. package/src/components/slide.stories.js +49 -0
  62. package/src/components/social-icon.js +236 -0
  63. package/src/components/social-icon.stories.js +36 -0
  64. package/src/components/stat.js +92 -0
  65. package/src/components/stat.stories.js +28 -0
  66. package/src/components/tab-list.js +114 -0
  67. package/src/components/tab-list.stories.js +18 -0
  68. package/src/components/tab.js +95 -0
  69. package/src/components/tab.stories.js +29 -0
  70. package/src/components/tile.js +149 -0
  71. package/src/components/tile.stories.js +41 -0
  72. package/src/components/transcript.js +44 -0
  73. package/src/components/transcript.stories.js +103 -0
  74. package/src/core/base.scss +86 -0
  75. package/src/core/colors.mdx +100 -0
  76. package/src/core/grid.mdx +244 -0
  77. package/src/core/grid.scss +394 -0
  78. package/src/core/helpers.scss +111 -0
  79. package/src/core/layout.scss +103 -0
  80. package/src/core/layout.stories.js +145 -0
  81. package/src/core/reset.scss +53 -0
  82. package/src/core/shadows.mdx +108 -0
  83. package/src/core/tokens.scss +261 -0
  84. package/src/core/typography.mdx +79 -0
  85. package/src/core/typography.scss +411 -0
  86. package/src/core.js +10 -0
  87. package/src/index.js +43 -0
  88. package/src/shared/common.js +65 -0
  89. package/src/shared/layout.js +14 -0
  90. package/src/shared/typography.js +397 -0
  91. package/src/styles.scss +15 -0
@@ -0,0 +1,240 @@
1
+ import { LitElement, html, css, nothing } from "lit";
2
+ import { commonStyles } from "../shared/common";
3
+ import { typographyStyles } from "../shared/typography";
4
+ import "./avatar";
5
+ import "./social-icon";
6
+
7
+ class PersonCard extends LitElement {
8
+ static properties = {
9
+ name: { type: "string" },
10
+ title: { type: "string" },
11
+ company: { type: "string" },
12
+ pronouns: { type: "string" },
13
+ imageUrl: { type: "string" },
14
+ imageAltText: { type: "string" },
15
+ linkUrl: { type: "string" },
16
+ linkedInUrl: { type: "string" },
17
+ twitterHandle: { type: "string" },
18
+ };
19
+ static styles = [
20
+ commonStyles,
21
+ typographyStyles,
22
+ css`
23
+ :host {
24
+ display: block;
25
+ }
26
+
27
+ .card {
28
+ border-radius: var(--rounded-corners);
29
+ position: relative;
30
+ display: flex;
31
+ flex-direction: row;
32
+ margin-inline: auto;
33
+ max-width: 100%;
34
+ text-align: start;
35
+ width: var(--column-span-4);
36
+ transform: translate(0, 0); // hack to ensure pseudo element is stacked above parent background
37
+ }
38
+
39
+ .card.has-link::before {
40
+ border-radius: var(--rounded-corners);
41
+ bottom: calc(-1 * var(--thick));
42
+ content: "";
43
+ height: calc(100% + 2 * var(--thick)));
44
+ left: calc(-1 * var(--thick));
45
+ position: absolute;
46
+ right: calc(-1 * var(--thick));
47
+ top: calc(-1 * var(--thick));
48
+ width: calc(100% + 2 * var(--thick)));
49
+ z-index: -1;
50
+ transition:
51
+ background-color 0.5s ease-in-out,
52
+ box-shadow 0.5s ease-in-out;
53
+ }
54
+
55
+ .card.has-link:hover::before,
56
+ .card.has-link:focus-visible::before {
57
+ background-color: var(--white);
58
+ box-shadow: var(--shadow-medium);
59
+ }
60
+
61
+ .card.has-link .name a {
62
+ box-shadow: 0;
63
+ color: var(--purple-80);
64
+ transition: box-shadow 0.5s ease-in-out;
65
+ }
66
+
67
+ .card.has-link:hover .name a {
68
+ box-shadow: inset 0 calc(-1 * var(--thick)) 0 0 var(--purple-20);
69
+ }
70
+
71
+ a {
72
+ position: relative;
73
+ text-decoration: none;
74
+ z-index: 1;
75
+ }
76
+
77
+ a.link-overlay {
78
+ position: static;
79
+ }
80
+
81
+ a.link-overlay::before {
82
+ content: "";
83
+ position: absolute;
84
+ z-index: 0;
85
+ top: 0;
86
+ right: 0;
87
+ bottom: 0;
88
+ left: 0;
89
+ }
90
+
91
+ .avatar {
92
+ flex-grow: 0;
93
+ }
94
+
95
+ .name {
96
+ display: inline-block;
97
+ }
98
+
99
+ .pronouns {
100
+ color: var(--purple-60);
101
+ }
102
+
103
+ .details {
104
+ color: var(--black);
105
+ flex-grow: 1;
106
+ padding-block-start: var(--spacing-component-2);
107
+ padding-inline-start: var(--spacing-component-2);
108
+ }
109
+
110
+ .social {
111
+ font-size: 0.9rem;
112
+ margin-block-start: var(--spacing-component-1);
113
+ }
114
+
115
+ .social a {
116
+ align-items: center;
117
+ border-radius: 10000px;
118
+ color: var(--purple-80);
119
+ display: inline-flex;
120
+ height: var(--spacing-component-4);
121
+ justify-content: center;
122
+ margin: calc(-1 * var(--spacing-component-2));
123
+ width: var(--spacing-component-4);
124
+ }
125
+
126
+ .social a:hover {
127
+ background-color: var(--purple-20);
128
+ }
129
+
130
+ .social > a + a {
131
+ margin-inline-start: var(--spacing-component-2);
132
+ }
133
+ `,
134
+ ];
135
+ render() {
136
+ return html`
137
+ <div class="card ${this.linkUrl ? "has-link" : ""}">
138
+ <!-- Link overlay pseudo-element so we can do nested links within the card -->
139
+ ${this.linkUrl
140
+ ? html`
141
+ <a
142
+ href="${this.linkUrl}"
143
+ target="${this.linkTarget || "_self"}"
144
+ rel="${this.linkTarget == "_blank" ? "noopener" : nothing}"
145
+ class="link-overlay"
146
+ tabindex="-1"
147
+ >
148
+ </a>
149
+ `
150
+ : ""}
151
+ <div class="avatar">
152
+ ${this.linkUrl
153
+ ? html`
154
+ <a
155
+ href="${this.linkUrl}"
156
+ target="${this.linkTarget || "_self"}"
157
+ rel="${this.linkTarget == "_blank" ? "noopener" : nothing}"
158
+ >
159
+ <cfa-avatar
160
+ imageUrl="${this.imageUrl}"
161
+ altText="Avatar photo of ${this.name}"
162
+ size="3"
163
+ >
164
+ </cfa-avatar>
165
+ </a>
166
+ `
167
+ : html`
168
+ <cfa-avatar
169
+ imageUrl="${this.imageUrl}"
170
+ altText="Avatar photo of ${this.name}"
171
+ size="3"
172
+ >
173
+ </cfa-avatar>
174
+ `}
175
+ </div>
176
+ <div class="details">
177
+ <div>
178
+ <div class="name h4">
179
+ ${this.linkUrl
180
+ ? html`
181
+ <a
182
+ href="${this.linkUrl}"
183
+ target="${this.linkTarget || "_self"}"
184
+ rel="${this.linkTarget == "_blank"
185
+ ? "noopener"
186
+ : nothing}"
187
+ >
188
+ ${this.name.trim()}
189
+ </a>
190
+ `
191
+ : html` ${this.name.trim()} `}
192
+ </div>
193
+ ${this.pronouns
194
+ ? html` <span class="pronouns small">(${this.pronouns})</span> `
195
+ : ""}
196
+ </div>
197
+ <div class="title small">
198
+ ${[this.title?.trim(), this.company?.trim()]
199
+ .filter(Boolean)
200
+ .join(", ")}
201
+ </div>
202
+ ${this.linkedInUrl || this.twitterHandle
203
+ ? html`
204
+ <div class="social">
205
+ ${this.linkedInUrl
206
+ ? html`
207
+ <a
208
+ href="${this.linkedInUrl}"
209
+ target="_blank"
210
+ rel="noopener"
211
+ title="View ${this.name}'s profile on LinkedIn"
212
+ >
213
+ <cfa-social-icon icon="linkedin" />
214
+ </a>
215
+ `
216
+ : nothing}
217
+ ${this.twitterHandle
218
+ ? html`
219
+ <a
220
+ href="https://twitter.com/${this.twitterHandle}"
221
+ target="_blank"
222
+ rel="noopener"
223
+ title="View ${this.name}'s profile on X (Twitter)"
224
+ >
225
+ <cfa-social-icon icon="twitter" />
226
+ </a>
227
+ `
228
+ : nothing}
229
+ </div>
230
+ `
231
+ : nothing}
232
+ </div>
233
+ </div>
234
+ `;
235
+ }
236
+ }
237
+
238
+ if (!customElements.get("cfa-person-card")) {
239
+ customElements.define("cfa-person-card", PersonCard);
240
+ }
@@ -0,0 +1,58 @@
1
+ import { html } from "lit-html";
2
+ import "./person-card";
3
+
4
+ export default {
5
+ title: "Molecules/PersonCard",
6
+ argTypes: {
7
+ name: { type: "string" },
8
+ title: { type: "string" },
9
+ company: { type: "string" },
10
+ pronouns: { type: "string" },
11
+ imageUrl: { type: "string" },
12
+ imageAltText: { type: "string" },
13
+ linkUrl: { type: "string" },
14
+ linkTarget: { type: "string" },
15
+ linkedInUrl: { type: "string" },
16
+ twitterHandle: { type: "string" },
17
+ },
18
+ };
19
+
20
+ const Template = ({
21
+ name,
22
+ title,
23
+ company,
24
+ pronouns,
25
+ imageUrl,
26
+ imageAltText,
27
+ linkUrl,
28
+ linkedInUrl,
29
+ twitterHandle,
30
+ }) => html`
31
+ <cfa-person-card
32
+ name="${name}"
33
+ title="${title}"
34
+ company="${company}"
35
+ pronouns="${pronouns}"
36
+ imageUrl="${imageUrl}"
37
+ imageAltText="${imageAltText}"
38
+ linkUrl="${linkUrl}"
39
+ linkedInUrl="${linkedInUrl}"
40
+ twitterHandle="${twitterHandle}"
41
+ >
42
+ </cfa-person-card>
43
+ `;
44
+
45
+ export const Default = Template.bind({});
46
+ Default.args = {
47
+ name: "Amanda Renteria",
48
+ title: "Chief Executive Officer",
49
+ company: "Code for America",
50
+ pronouns: "she/her",
51
+ imageUrl:
52
+ "https://files.codeforamerica.org/2021/02/13130320/Renteria.Turq_.Standing-scaled-e1678737908242-198x300.jpg",
53
+ imageAltText: "Headshot photo of Amanda Renteria, Code for America CEO",
54
+ linkUrl: "https://www.codeforamerica.org/about/people/amanda-renteria",
55
+ linkTarget: "_blank",
56
+ linkedInUrl: "https://www.linkedin.com/in/amanda-renteria",
57
+ twitterHandle: "amandarenteria",
58
+ };
@@ -0,0 +1,33 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { commonStyles } from "../shared/common";
3
+
4
+ class Pill extends LitElement {
5
+ static styles = [
6
+ commonStyles,
7
+ css`
8
+ :host {
9
+ --bg-color: var(--gray-20);
10
+ --text-color: var(--gray-80);
11
+
12
+ background-color: var(--bg-color);
13
+ border-radius: var(--spacing-component-3);
14
+ color: var(--text-color);
15
+ display: inline-block;
16
+ font-size: var(--font-size-small);
17
+ font-weight: bold;
18
+ line-height: 1;
19
+ margin-right: var(--spacing-component-1);
20
+ padding: var(--spacing-component-1) var(--spacing-component-2);
21
+ vertical-align: middle;
22
+ }
23
+ `,
24
+ ];
25
+
26
+ render() {
27
+ return html` <slot /> `;
28
+ }
29
+ }
30
+
31
+ if (!customElements.get("cfa-pill")) {
32
+ customElements.define("cfa-pill", Pill);
33
+ }
@@ -0,0 +1,25 @@
1
+ import { html } from "lit-html";
2
+ import "./pill";
3
+
4
+ export default {
5
+ title: "Atoms/Pill",
6
+ argTypes: {
7
+ text: { type: "string" },
8
+ },
9
+ globals: {
10
+ backgrounds: {
11
+ value: "white"
12
+ }
13
+ },
14
+ };
15
+
16
+ const Template = ({ text }) => html`
17
+ <cfa-pill> ${text} </cfa-pill>
18
+ <cfa-pill> ${text} </cfa-pill>
19
+ <cfa-pill> ${text} </cfa-pill>
20
+ `;
21
+
22
+ export const Default = Template.bind({});
23
+ Default.args = {
24
+ text: "Qualitative Research",
25
+ };
@@ -0,0 +1,25 @@
1
+ import { LitElement, html, css } from "lit";
2
+
3
+ class Placeholder extends LitElement {
4
+ static styles = [
5
+ css`
6
+ :host {
7
+ --bg-color: var(--gray-20);
8
+ --height: var(--line-height-base);
9
+
10
+ display: block;
11
+ width: 100%;
12
+ height: var(--height);
13
+ background-color: var(--bg-color);
14
+ }
15
+ `,
16
+ ];
17
+
18
+ render() {
19
+ return html``;
20
+ }
21
+ }
22
+
23
+ if (!customElements.get("cfa-placeholder")) {
24
+ customElements.define("cfa-placeholder", Placeholder);
25
+ }
@@ -0,0 +1,10 @@
1
+ import "./placeholder";
2
+
3
+ export default {
4
+ title: "Atoms/Placeholder",
5
+ component: "cfa-placeholder"
6
+ };
7
+
8
+ export const Default = () => {
9
+ return document.createElement("cfa-placeholder");
10
+ };
@@ -0,0 +1,82 @@
1
+ import { LitElement, html, css, nothing } from "lit";
2
+ import { commonStyles } from "../shared/common";
3
+ import { typographyStyles } from "../shared/typography";
4
+ import "./icon";
5
+
6
+ class Promo extends LitElement {
7
+ static properties = {
8
+ heading: {},
9
+ text: {},
10
+ actionLabel: {},
11
+ linkUrl: {},
12
+ linkTarget: {},
13
+ };
14
+ static styles = [
15
+ commonStyles,
16
+ typographyStyles,
17
+ css`
18
+ :host {
19
+ --bg-color: var(--blue-20);
20
+ --padding: var(--spacing-component-4);
21
+ --text-color: var(--black);
22
+ --action-label-color: var(--purple-60);
23
+ --action-label-hover-color: var(--red-60);
24
+
25
+ display: block;
26
+ }
27
+
28
+ .promo,
29
+ a.promo {
30
+ background-color: var(--bg-color);
31
+ box-shadow: var(--shadow-small);
32
+ color: var(--text-color, #000);
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: var(--spacing-layout-half);
36
+ padding: var(--padding);
37
+ text-align: center;
38
+ text-decoration: none;
39
+ transition: box-shadow 0.2s ease-in-out;
40
+ }
41
+
42
+ a.promo:hover {
43
+ box-shadow: var(--shadow-medium);
44
+ }
45
+
46
+ .action-label {
47
+ color: var(--action-label-color);
48
+ }
49
+
50
+ a.promo:hover .action-label {
51
+ color: var(--action-label-hover-color);
52
+ }
53
+ `,
54
+ ];
55
+
56
+ render() {
57
+ return html`
58
+ <a
59
+ href="${this.linkUrl || "javascript:void(0)"}"
60
+ target="${this.linkTarget || nothing}"
61
+ class="promo
62
+ "
63
+ >
64
+ ${this.heading
65
+ ? html` <div class="h4 sans-serif">${this.heading}</div> `
66
+ : nothing}
67
+ ${this.text ? html` <div class="small">${this.text}</div> ` : nothing}
68
+ ${this.actionLabel
69
+ ? html`
70
+ <div class="action-label small strong">
71
+ ${this.actionLabel} <cfa-icon>arrow_forward</cfa-icon>
72
+ </div>
73
+ `
74
+ : nothing}
75
+ </a>
76
+ `;
77
+ }
78
+ }
79
+
80
+ if (!customElements.get("cfa-promo")) {
81
+ customElements.define("cfa-promo", Promo);
82
+ }
@@ -0,0 +1,37 @@
1
+ import { html } from "lit-html";
2
+ import "./promo";
3
+
4
+ export default {
5
+ title: "Molecules/Promo",
6
+ argTypes: {
7
+ heading: { type: "string" },
8
+ text: { type: "string" },
9
+ linkUrl: { type: "string" },
10
+ linkTarget: { type: "string" },
11
+ actionLabel: { type: "string" },
12
+ },
13
+ };
14
+
15
+ const Template = ({ heading, text, linkUrl, linkTarget, actionLabel }) => html`
16
+ <div class="row center-xs">
17
+ <div class="col-xs-12 col-md-6">
18
+ <cfa-promo
19
+ heading="${heading}"
20
+ text="${text}"
21
+ linkUrl="${linkUrl}"
22
+ linkTarget="${linkTarget}"
23
+ actionLabel="${actionLabel}"
24
+ >
25
+ </cfa-promo>
26
+ </div>
27
+ </div>
28
+ `;
29
+
30
+ export const Default = Template.bind({});
31
+ Default.args = {
32
+ heading: "Summit 2023",
33
+ text: "Join us in D.C. next month",
34
+ linkUrl: "https://summit.codeforamerica.org",
35
+ linkTarget: "_blank",
36
+ actionLabel: "Register now",
37
+ };
@@ -0,0 +1,42 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { commonStyles } from "../shared/common";
3
+
4
+ class PullQuote extends LitElement {
5
+ static properties = {};
6
+ static styles = [
7
+ commonStyles,
8
+ css`
9
+ :host {
10
+ --color: var(--purple-60);
11
+
12
+ display: block;
13
+ }
14
+ blockquote {
15
+ border-inline-start: var(--thick) solid var(--color);
16
+ color: var(--color);
17
+ font-size: var(--font-size-h3);
18
+ font-weight: 600;
19
+ line-height: var(--line-height-h3);
20
+ margin: 0;
21
+ padding: var(--spacing-layout-half) var(--spacing-layout-1);
22
+ }
23
+ p {
24
+ margin: 0;
25
+ }
26
+ p + p {
27
+ margin-block-start: var(--spacing-layout-half);
28
+ }
29
+ `,
30
+ ];
31
+ render() {
32
+ return html`
33
+ <blockquote>
34
+ <slot />
35
+ </blockquote>
36
+ `;
37
+ }
38
+ }
39
+
40
+ if (!customElements.get("cfa-pullquote")) {
41
+ customElements.define("cfa-pullquote", PullQuote);
42
+ }
@@ -0,0 +1,16 @@
1
+ import { html } from "lit-html";
2
+ import "./pullquote";
3
+
4
+ export default {
5
+ title: "Atoms/PullQuote",
6
+ argTypes: {},
7
+ };
8
+
9
+ const Template = ({ text }) => html`
10
+ <cfa-pullquote .innerHTML="${text}"></cfa-pullquote>
11
+ `;
12
+
13
+ export const Default = Template.bind({});
14
+ Default.args = {
15
+ text: "What truly ignites my interest in civic tech is the opportunity to <strong>leverage technology</strong> to close the gap between government and the people it serves.",
16
+ };
@@ -0,0 +1,111 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { commonStyles } from "../shared/common";
3
+
4
+ class Quote extends LitElement {
5
+ static properties = {
6
+ text: {},
7
+ attribution: {},
8
+ };
9
+ static styles = [
10
+ commonStyles,
11
+ css`
12
+ :host {
13
+ --attribution-color: var(--purple-60);
14
+ container-type: inline-size;
15
+ display: block;
16
+ width: 100%;
17
+ }
18
+
19
+ figure {
20
+ margin: 0 auto;
21
+ position: relative;
22
+ width: 100%;
23
+ }
24
+
25
+ @container (min-width: 25rem) {
26
+ figure {
27
+ display: grid;
28
+ grid-template-columns: 3rem 1fr;
29
+ column-gap: var(--spacing-layout-1);
30
+ grid-template-areas:
31
+ "icon content";
32
+ }
33
+
34
+ svg {
35
+ grid-area: icon;
36
+ margin-block-end: 0;
37
+ }
38
+
39
+ .content {
40
+ grid-area: content;
41
+ }
42
+ }
43
+
44
+ blockquote {
45
+ font-family: var(--font-family-serif);
46
+ font-size: var(--font-size-h3);
47
+ line-height: var(--line-height-h3);
48
+ padding: 0;
49
+ margin: 0;
50
+ position: relative;
51
+ }
52
+
53
+ ::slotted(*) {
54
+ display: inline;
55
+ }
56
+
57
+ figcaption {
58
+ color: var(--attribution-color);
59
+ font-size: var(--font-size-small);
60
+ line-height: var(--line-height-small);
61
+ font-weight: 600;
62
+ margin-block-start: var(--spacing-layout-half);
63
+ margin-inline: 0;
64
+ position: relative;
65
+ padding-inline-start: calc(var(--spacing-component-4) + var(--spacing-component-2));
66
+ }
67
+
68
+ figcaption::before {
69
+ background-color: currentColor;
70
+ content: "";
71
+ display: block;
72
+ position: absolute;
73
+ left: 0;
74
+ top: calc(var(--line-height-small) / 2 - var(--hairline) / 2);
75
+ height: var(--hairline);
76
+ width: var(--spacing-component-4);
77
+ }
78
+
79
+ svg {
80
+ display: block;
81
+ fill: var(--purple-60);
82
+ height: calc(1.5 * var(--spacing-layout-1));
83
+ margin-block-end: var(--spacing-layout-half);
84
+ opacity: 0.5;
85
+ width: auto;
86
+ }
87
+ `,
88
+ ];
89
+ render() {
90
+ return html`
91
+ <figure>
92
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 339.42 264.4" aria-hidden="true" shape-rendering="geometricPrecision">
93
+ <path d="M91.69,126.5c-9.19,0-15.39,1-18.59,3,4.01-16,12.59-32.41,25.8-49.21h0c12.8-15.99,26.61-27.79,41.4-35.39h1.2l.61-1.21c3.19-1.2,4.79-4.2,4.79-9,0-3.2-1.39-6-4.21-8.4L104.9,2.29c-1.61-1.2-3.79-1.79-6.6-1.79l-4.2,1.2c-28.8,20.8-51.4,45.6-67.8,74.4C9.09,106.1.5,137.7.5,170.9c0,28.39,8.21,51.2,24.61,68.39,14.79,16.4,33.4,24.61,55.79,24.61,19.61,0,36.6-7.01,51-21,14-14.4,21-31.4,21-51s-6-34.8-18-46.8c-11.6-12.39-26-18.6-43.21-18.6Z"/>
94
+ <path d="M276.52,126.5c-8.39,0-14.39,1-18,3,4.01-16,12.79-32.4,26.4-49.21,13.21-16,27-27.79,41.4-35.39l.6-1.21c4-1.2,6-4.2,6-9,0-2.8-1.39-5.61-4.21-8.4l-37.8-24c-2-1.2-4.21-1.79-6.6-1.79l-4.2,1.2h-.6c-29.21,20.8-52,45.61-68.39,74.4-17.21,30-25.8,61.6-25.8,94.8,0,28.39,8.21,51.2,24.6,68.39,15.6,16.4,34.61,24.61,57,24.61,19.61,0,36.6-7.01,51-21,14-14.4,21-31.4,21-51s-6-34.8-18-46.8c-11.6-12.39-26.4-18.6-44.4-18.6Z"/>
95
+ </svg>
96
+ <div class="content">
97
+ <blockquote>
98
+ <slot name="text" /><slot />
99
+ </blockquote>
100
+ <figcaption>
101
+ <slot name="attribution" />
102
+ </figcaption>
103
+ </div>
104
+ </figure>
105
+ `;
106
+ }
107
+ }
108
+
109
+ if (!customElements.get("cfa-quote")) {
110
+ customElements.define("cfa-quote", Quote);
111
+ }