baseline-foundry 0.1.3 → 0.1.4

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 (43) hide show
  1. package/README.md +568 -552
  2. package/config/experiments/ibm-plex-engine-smoke.json +115 -115
  3. package/config/experiments/ubuntu-engine-smoke.json +115 -115
  4. package/config/foundation-theme.json +110 -110
  5. package/config/tiers/app.json +116 -116
  6. package/config/tiers/documentation.json +116 -116
  7. package/config/tiers/editorial.json +116 -116
  8. package/config/tiers/os.json +116 -116
  9. package/dist/baseline-grid-overlay.js +43 -43
  10. package/dist/css-app-tier.js +73 -73
  11. package/dist/css-components/article-pagination.js +140 -140
  12. package/dist/css-components/button-actions.js +161 -161
  13. package/dist/css-components/cards-options.js +176 -176
  14. package/dist/css-components/chip-badge-status.js +158 -158
  15. package/dist/css-components/content-card.js +490 -490
  16. package/dist/css-components/control-row.js +14 -14
  17. package/dist/css-components/cta-figure-aspect.js +120 -120
  18. package/dist/css-components/document-navigation.js +390 -390
  19. package/dist/css-components/editorial-content.js +42 -42
  20. package/dist/css-components/icon.js +72 -72
  21. package/dist/css-components/interactive-feedback.js +217 -217
  22. package/dist/css-components/interactive-tables.js +155 -155
  23. package/dist/css-components/legacy-navigation.d.ts +9 -0
  24. package/dist/css-components/legacy-navigation.js +763 -0
  25. package/dist/css-components/linked-logo-site-layout.js +177 -177
  26. package/dist/css-components/list-tree.js +94 -94
  27. package/dist/css-components/logo-media.js +201 -201
  28. package/dist/css-components/navigation-layout.js +144 -144
  29. package/dist/css-components/panel.js +144 -144
  30. package/dist/css-components/search-box-and-filter.js +263 -263
  31. package/dist/css-components/sites-editorial-ports.js +243 -243
  32. package/dist/css-components/sites-foundation.js +146 -146
  33. package/dist/css-components/sites-rich-lists.js +344 -344
  34. package/dist/css-components/static-content-ports.js +182 -182
  35. package/dist/css-components/tab-section.js +82 -82
  36. package/dist/css-components/table.js +75 -75
  37. package/dist/css-components/tabs-choice-breadcrumbs.js +303 -303
  38. package/dist/css-components/tiered-list-equal-height-row.js +271 -271
  39. package/dist/css-components.js +1791 -2542
  40. package/dist/css-grid.js +172 -172
  41. package/dist/css.js +240 -240
  42. package/docs/publishing.md +30 -13
  43. package/package.json +119 -108
@@ -23,495 +23,495 @@
23
23
  * reachable.
24
24
  */
25
25
  export function contentCardCss() {
26
- return `/* ------------------------------------------------------------------ */
27
- /* Content card — rich Vanilla parity, distinct from the bf-card primitive. */
28
- /* ------------------------------------------------------------------ */
29
-
30
- :where(.bf-theme) :where(.bf-content-card-wrapper) {
31
- block-size: auto;
32
- display: flex;
33
- flex-direction: column;
34
- grid-column: 1 / -1;
35
- inline-size: 100%;
36
- min-inline-size: 0;
37
- padding-block-end: var(--bf-space-4);
38
- }
39
-
40
- /* Snap the grid-row wrapper after intrinsic image/copy measurement. Because
41
- the card flexes inside it, peers retain Vanilla's equal-height row while
42
- the card edge and the following row both land on BF baselines. */
43
- @supports (block-size: calc-size(auto, round(up, size, 1px))) {
44
- :where(.bf-theme) :where(.bf-content-card-wrapper) {
45
- block-size: calc-size(auto, round(up, size, var(--bf-baseline)));
46
- }
47
- }
48
-
49
- /* Vanilla's column names describe its eight-column grid. BF doubles the span
50
- when its own large-screen grid becomes sixteen columns. */
51
- @media (width >= 38.75rem) {
52
- :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-2) {
53
- grid-column: auto / span 2;
54
- }
55
- }
56
-
57
- @media (width >= 64.75rem) {
58
- :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-4) {
59
- grid-column: auto / span 4;
60
- }
61
-
62
- :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-6) {
63
- grid-column: auto / span 6;
64
- }
65
- }
66
-
67
- @media (width >= 105.0625rem) {
68
- :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-2) {
69
- grid-column: auto / span 4;
70
- }
71
-
72
- :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-4) {
73
- grid-column: auto / span 8;
74
- }
75
-
76
- :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-6) {
77
- grid-column: auto / span 12;
78
- }
79
- }
80
-
81
- :where(.bf-theme) :where(.bf-content-card) {
82
- background: var(--bf-color-background-default);
83
- border: var(--bf-border-width) solid var(--bf-color-border-low-contrast);
84
- box-sizing: border-box;
85
- color: var(--bf-color-text-default);
86
- container-name: bf-content-card;
87
- container-type: inline-size;
88
- flex: 1;
89
- inline-size: 100%;
90
- max-inline-size: 100%;
91
- min-inline-size: 0;
92
- overflow: hidden;
93
- position: relative;
94
- transition: border-color 400ms ease-in-out;
95
- }
96
-
97
- :where(.bf-theme) :where(.bf-content-card:hover, .bf-content-card:focus-within) {
98
- border-color: var(--bf-color-border-high-contrast);
99
- }
100
-
101
- :where(.bf-theme) :where(.bf-content-card-frame) {
102
- align-items: stretch;
103
- display: flex;
104
- flex-direction: column;
105
- inline-size: 100%;
106
- min-block-size: calc(var(--bf-space-12) - (var(--bf-border-width) * 2));
107
- min-inline-size: 0;
108
- padding-block-start: var(--bf-space-2);
109
- }
110
-
111
- :where(.bf-theme) :where(.bf-content-card.is-image) :where(.bf-content-card-frame) {
112
- min-block-size: calc((var(--bf-space-12) * 4) - (var(--bf-border-width) * 2));
113
- padding-block-start: 0;
114
- }
115
-
116
- :where(.bf-theme) :where(.bf-content-card:not(.is-image)) :where(.bf-content-card-frame) {
117
- min-block-size: calc((var(--bf-space-12) * 2) - (var(--bf-border-width) * 2));
118
- }
119
-
120
- :where(.bf-theme) :where(.bf-content-card-media) {
121
- align-items: flex-start;
122
- display: flex;
123
- flex: 0 0 auto;
124
- flex-direction: column;
125
- inline-size: 100%;
126
- max-inline-size: 100%;
127
- min-inline-size: 0;
128
- padding-block-end: var(--bf-space-2);
129
- }
130
-
131
- :where(.bf-theme) :where(.bf-content-card-image) {
132
- aspect-ratio: 16 / 9;
133
- block-size: auto;
134
- /* Preserve 16:9 within half a baseline while keeping the occupied media
135
- block on BF's grid at arbitrary card widths. */
136
- block-size: round(up, calc(100cqi * 9 / 16), var(--bf-baseline));
137
- display: block;
138
- flex: 0 0 auto;
139
- inline-size: 100%;
140
- margin: 0;
141
- max-inline-size: 100%;
142
- object-fit: cover;
143
- }
144
-
145
- :where(.bf-theme) :where(.bf-content-card-content) {
146
- display: flex;
147
- flex: 1;
148
- flex-direction: column;
149
- inline-size: 100%;
150
- justify-content: space-between;
151
- min-block-size: 0;
152
- min-inline-size: 0;
153
- }
154
-
155
- :where(.bf-theme) :where(.bf-content-card-body) {
156
- align-items: flex-start;
157
- align-self: stretch;
158
- display: grid;
159
- grid-template-columns: minmax(0, 1fr);
160
- grid-template-rows: minmax(0, 1fr);
161
- min-inline-size: 0;
162
- overflow: hidden;
163
- padding-inline: var(--bf-space-2);
164
- }
165
-
166
- :where(.bf-theme) :where(.bf-content-card-primary, .bf-content-card-description-panel) {
167
- display: flex;
168
- flex-direction: column;
169
- grid-area: 1 / 1;
170
- inline-size: 100%;
171
- min-inline-size: 0;
172
- }
173
-
174
- :where(.bf-theme) :where(.bf-content-card-primary) {
175
- opacity: 1;
176
- transition: opacity 400ms ease-in-out;
177
- }
178
-
179
- :where(.bf-theme) :where(.bf-content-card-description-panel) {
180
- opacity: 0;
181
- transform: translateY(calc(var(--bf-space-12) + var(--bf-space-6)));
182
- transition: opacity 400ms ease-in-out, transform 400ms ease-in-out;
183
- }
184
-
185
- /* A content-card title is a real heading slot. It uses BF's h4 role in the
186
- 2/4/6-column variants and the h1 role in the eight-column feature. */
187
- :where(.bf-theme) :where(.bf-content-card-title) {
188
- color: var(--bf-color-text-default);
189
- font-family: var(--bf-h4-font-family);
190
- font-size: var(--bf-h4-font-size);
191
- font-style: var(--bf-h4-font-style);
192
- font-variant-caps: var(--bf-h4-font-variant-caps);
193
- font-weight: var(--bf-h4-font-weight);
194
- inline-size: 100%;
195
- letter-spacing: var(--bf-h4-letter-spacing);
196
- line-height: var(--bf-h4-line-height);
197
- margin-block: 0 var(--bf-h4-margin-bottom);
198
- max-inline-size: none;
199
- min-inline-size: 0;
200
- overflow-wrap: anywhere;
201
- padding-block-end: 0;
202
- padding-block-start: var(--bf-h4-nudge-start);
203
- text-transform: var(--bf-h4-text-transform);
204
- }
205
-
206
- :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-title) {
207
- font-family: var(--bf-h1-font-family);
208
- font-size: var(--bf-h1-font-size);
209
- font-style: var(--bf-h1-font-style);
210
- font-variant-caps: var(--bf-h1-font-variant-caps);
211
- font-weight: var(--bf-h1-font-weight);
212
- letter-spacing: var(--bf-h1-letter-spacing);
213
- line-height: var(--bf-h1-line-height);
214
- margin-block-end: var(--bf-h1-margin-bottom);
215
- padding-block-end: 0;
216
- padding-block-start: var(--bf-h1-nudge-start);
217
- text-transform: var(--bf-h1-text-transform);
218
- }
219
-
220
- :where(.bf-theme) :where(.bf-content-card-main-link) {
221
- -webkit-box-orient: vertical;
222
- -webkit-line-clamp: 3;
223
- color: inherit;
224
- cursor: pointer;
225
- display: -webkit-box;
226
- inline-size: 100%;
227
- line-clamp: 3;
228
- min-inline-size: 0;
229
- overflow: hidden;
230
- text-decoration: none;
231
- }
232
-
233
- :where(.bf-theme) :where(.bf-content-card-main-link)::after {
234
- content: "";
235
- inset: 0;
236
- position: absolute;
237
- z-index: 1;
238
- }
239
-
240
- :where(.bf-theme) :where(.bf-content-card-main-link:is(:hover, :focus, :active, :visited)) {
241
- color: inherit;
242
- text-decoration: none;
243
- }
244
-
245
- :where(.bf-theme) :where(.bf-content-card-main-link:focus) {
246
- outline: none;
247
- }
248
-
249
- :where(.bf-theme) :where(.bf-content-card:has(.bf-content-card-main-link:focus-visible)) {
250
- outline: 3px solid var(--bf-color-focus);
251
- outline-offset: 2px;
252
- }
253
-
254
- /* All nested actions sit above the expanded main-link hit area. This includes
255
- consumer-supplied controls as well as the documented author-link slot. */
256
- :where(.bf-theme) :where(.bf-content-card) :where(a, button, input, select, textarea, summary):not(.bf-content-card-main-link),
257
- :where(.bf-theme) :where(.bf-content-card-interactive) {
258
- pointer-events: auto;
259
- position: relative;
260
- z-index: 2;
261
- }
262
-
263
- :where(.bf-theme) :where(.bf-content-card-author-date) {
264
- align-items: flex-start;
265
- color: var(--bf-color-text-muted);
266
- display: flex;
267
- flex-wrap: wrap;
268
- gap: 0 var(--bf-space-half);
269
- min-inline-size: 0;
270
- padding-block-end: var(--bf-space-1);
271
- }
272
-
273
- :where(.bf-theme) :where(.bf-content-card-author-date > *) {
274
- margin-block-end: 0;
275
- }
276
-
277
- :where(.bf-theme) :where(.bf-content-card-description) {
278
- -webkit-box-orient: vertical;
279
- -webkit-line-clamp: 4;
280
- display: -webkit-box;
281
- line-clamp: 4;
282
- max-inline-size: none;
283
- min-inline-size: 0;
284
- overflow: hidden;
285
- overflow-wrap: anywhere;
286
- }
287
-
288
- :where(.bf-theme) :where(.bf-content-card.is-cols-6) :where(.bf-content-card-main-link, .bf-content-card-description) {
289
- -webkit-line-clamp: 2;
290
- line-clamp: 2;
291
- }
292
-
293
- :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-body) {
294
- display: flex;
295
- flex-direction: column;
296
- min-block-size: 0;
297
- }
298
-
299
- :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-description-panel) {
300
- flex: 1;
301
- opacity: 1;
302
- transform: translateY(0);
303
- }
304
-
305
- :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-description) {
306
- -webkit-line-clamp: 2;
307
- line-clamp: 2;
308
- margin-block-end: var(--bf-space-2);
309
- }
310
-
311
- :where(.bf-theme) :where(.bf-content-card-footer) {
312
- border-block-start: var(--bf-border-width) solid var(--bf-color-border-low-contrast);
313
- inline-size: 100%;
314
- min-inline-size: 0;
315
- }
316
-
317
- :where(.bf-theme) :where(.bf-content-card-footer-inner) {
318
- align-items: center;
319
- display: flex;
320
- gap: var(--bf-space-1);
321
- inline-size: 100%;
322
- mask-image: linear-gradient(to right, #000 85%, transparent 100%);
323
- min-block-size: var(--bf-space-4);
324
- min-inline-size: 0;
325
- overflow-x: auto;
326
- padding-block-end: var(--bf-space-1);
327
- padding-inline: var(--bf-space-2);
328
- position: relative;
329
- scrollbar-width: none;
330
- z-index: 2;
331
- }
332
-
333
- :where([dir='rtl'].bf-theme, [dir='rtl'] .bf-theme) :where(.bf-content-card-footer-inner),
334
- :where(.bf-theme) :where([dir='rtl'] .bf-content-card-footer-inner) {
335
- mask-image: linear-gradient(to left, #000 85%, transparent 100%);
336
- }
337
-
338
- :where(.bf-theme) :where(.bf-content-card-footer-inner::-webkit-scrollbar) {
339
- display: none;
340
- }
341
-
342
- :where(.bf-theme) :where(.bf-content-card-footer-inner > *) {
343
- flex: 0 0 auto;
344
- white-space: nowrap;
345
- }
346
-
347
- :where(.bf-theme) :where(.bf-content-card-resource) {
348
- align-items: center;
349
- display: inline-flex;
350
- gap: var(--bf-space-half);
351
- }
352
-
353
- :where(.bf-theme) :where(.bf-content-card-resource > *) {
354
- margin: 0;
355
- }
356
-
357
- :where(.bf-theme) :where(.bf-content-card-footer .bf-chip) {
358
- margin: 0;
359
- margin-inline-end: var(--bf-space-3);
360
- }
361
-
362
- /* Internal geometry responds to the card's allocated width. The card root is
363
- only the container; the frame/media/body descendants own queried styles. */
364
- /* Vanilla switches the viewport at 620px/1036px. A four-column card is much
365
- narrower than that viewport after grid margins and gutters, so its internal
366
- horizontal layout uses Vanilla's 460px minimum viable allocation. The
367
- eight-column 50/50 split starts at the roughly 960px allocation left by the
368
- 1036px viewport. This preserves the rendered switch in embedded BF grids. */
369
- @container bf-content-card (width < 28.75rem) {
370
- :where(.bf-theme) :where(.bf-content-card-frame:not(:has(.bf-content-card-footer))) {
371
- min-block-size: 0;
372
- padding-block-end: calc(var(--bf-space-2) - (var(--bf-border-width) * 2));
373
- }
374
- }
375
-
376
- @container bf-content-card (width >= 28.75rem) {
377
- :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-frame) {
378
- column-gap: var(--bf-space-2);
379
- flex-direction: row;
380
- min-block-size: calc((var(--bf-space-12) * 2) - (var(--bf-border-width) * 2));
381
- padding: var(--bf-space-2) var(--bf-space-2) 0;
382
- }
383
-
384
- :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6):not(.is-image)) :where(.bf-content-card-frame) {
385
- min-block-size: calc((var(--bf-space-12) * 2) - (var(--bf-border-width) * 2));
386
- }
387
-
388
- :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-media) {
389
- align-self: stretch;
390
- inline-size: calc(var(--bf-space-12) * 3);
391
- padding-block-end: 0;
392
- }
393
-
394
- :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-image) {
395
- aspect-ratio: 16 / 9;
396
- block-size: auto;
397
- block-size: calc(var(--bf-space-12) + var(--bf-space-8));
398
- }
399
-
400
- :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-body) {
401
- padding-inline: 0;
402
- }
403
-
404
- :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-footer-inner) {
405
- padding-inline: 0;
406
- }
407
-
408
- /* An explicit image-top modifier wins after the horizontal rules. */
409
- :where(.bf-theme) :where(.bf-content-card.is-image-top:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-frame) {
410
- flex-direction: column;
411
- min-block-size: calc((var(--bf-space-12) * 4) - (var(--bf-border-width) * 2));
412
- padding: 0;
413
- }
414
-
415
- :where(.bf-theme) :where(.bf-content-card.is-image-top:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-media) {
416
- inline-size: 100%;
417
- padding-block-end: var(--bf-space-2);
418
- }
419
-
420
- :where(.bf-theme) :where(.bf-content-card.is-image-top:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-image) {
421
- aspect-ratio: 16 / 9;
422
- block-size: auto;
423
- block-size: round(up, calc(100cqi * 9 / 16), var(--bf-baseline));
424
- }
425
-
426
- :where(.bf-theme) :where(.bf-content-card.is-image-top:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-body, .bf-content-card-footer-inner) {
427
- padding-inline: var(--bf-space-2);
428
- }
429
- }
430
-
431
- @container bf-content-card (width >= 60rem) {
432
- :where(.bf-theme) :where(.bf-content-card.is-cols-8.is-image) :where(.bf-content-card-frame) {
433
- display: grid;
434
- grid-template-columns: repeat(2, minmax(0, 1fr));
435
- min-block-size: calc((var(--bf-space-12) * 3 + var(--bf-space-8)) - (var(--bf-border-width) * 2));
436
- padding: 0;
437
- }
438
-
439
- :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-content) {
440
- grid-column: 1;
441
- grid-row: 1;
442
- }
443
-
444
- :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-body) {
445
- padding-block-start: var(--bf-space-2);
446
- }
447
-
448
- :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-media) {
449
- block-size: 100%;
450
- grid-column: 2;
451
- grid-row: 1;
452
- padding: var(--bf-space-1) var(--bf-space-1) 0;
453
- }
454
-
455
- :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-image) {
456
- aspect-ratio: auto;
457
- block-size: 100%;
458
- }
459
-
460
- :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-description) {
461
- -webkit-line-clamp: 3;
462
- line-clamp: 3;
463
- margin-block-end: 0;
464
- }
465
-
466
- :where(.bf-theme) :where(.bf-content-card.is-image-top.is-cols-8.is-image) :where(.bf-content-card-frame) {
467
- display: flex;
468
- flex-direction: column;
469
- }
470
-
471
- :where(.bf-theme) :where(.bf-content-card.is-image-top.is-cols-8) :where(.bf-content-card-media) {
472
- block-size: auto;
473
- padding: 0 0 var(--bf-space-2);
474
- }
475
-
476
- :where(.bf-theme) :where(.bf-content-card.is-image-top.is-cols-8) :where(.bf-content-card-image) {
477
- aspect-ratio: 16 / 9;
478
- block-size: auto;
479
- block-size: round(up, calc(100cqi * 9 / 16), var(--bf-baseline));
480
- }
481
- }
482
-
483
- @media (38.75rem <= width < 64.75rem) {
484
- :where(.bf-theme) :where(.bf-content-card.is-cols-2) :where(.bf-content-card-author-date),
485
- :where(.bf-theme) :where(.bf-content-card.is-cols-6) :where(.bf-content-card-author-date) {
486
- display: none;
487
- }
488
-
489
- :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-main-link) {
490
- -webkit-line-clamp: 2;
491
- line-clamp: 2;
492
- }
493
- }
494
-
495
- /* Vanilla swaps primary copy for the optional description on desktop. Only
496
- hover or focus of the main action triggers the swap; focusing a nested
497
- author/footer action never makes that focused control disappear. */
498
- @media (width >= 64.75rem) {
499
- :where(.bf-theme) :where(.bf-content-card.is-description-reveal:not(.is-cols-8):hover) :where(.bf-content-card-primary),
500
- :where(.bf-theme) :where(.bf-content-card.is-description-reveal:not(.is-cols-8):has(.bf-content-card-main-link:focus-visible)) :where(.bf-content-card-primary) {
501
- opacity: 0;
502
- }
503
-
504
- :where(.bf-theme) :where(.bf-content-card.is-description-reveal:not(.is-cols-8):hover) :where(.bf-content-card-description-panel),
505
- :where(.bf-theme) :where(.bf-content-card.is-description-reveal:not(.is-cols-8):has(.bf-content-card-main-link:focus-visible)) :where(.bf-content-card-description-panel) {
506
- opacity: 1;
507
- transform: translateY(0);
508
- }
509
- }
510
-
511
- @media (prefers-reduced-motion: reduce) {
512
- :where(.bf-theme) :where(.bf-content-card, .bf-content-card-primary, .bf-content-card-description-panel) {
513
- transition-duration: 0.01ms;
514
- }
515
- }
26
+ return `/* ------------------------------------------------------------------ */
27
+ /* Content card — rich Vanilla parity, distinct from the bf-card primitive. */
28
+ /* ------------------------------------------------------------------ */
29
+
30
+ :where(.bf-theme) :where(.bf-content-card-wrapper) {
31
+ block-size: auto;
32
+ display: flex;
33
+ flex-direction: column;
34
+ grid-column: 1 / -1;
35
+ inline-size: 100%;
36
+ min-inline-size: 0;
37
+ padding-block-end: var(--bf-space-4);
38
+ }
39
+
40
+ /* Snap the grid-row wrapper after intrinsic image/copy measurement. Because
41
+ the card flexes inside it, peers retain Vanilla's equal-height row while
42
+ the card edge and the following row both land on BF baselines. */
43
+ @supports (block-size: calc-size(auto, round(up, size, 1px))) {
44
+ :where(.bf-theme) :where(.bf-content-card-wrapper) {
45
+ block-size: calc-size(auto, round(up, size, var(--bf-baseline)));
46
+ }
47
+ }
48
+
49
+ /* Vanilla's column names describe its eight-column grid. BF doubles the span
50
+ when its own large-screen grid becomes sixteen columns. */
51
+ @media (width >= 38.75rem) {
52
+ :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-2) {
53
+ grid-column: auto / span 2;
54
+ }
55
+ }
56
+
57
+ @media (width >= 64.75rem) {
58
+ :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-4) {
59
+ grid-column: auto / span 4;
60
+ }
61
+
62
+ :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-6) {
63
+ grid-column: auto / span 6;
64
+ }
65
+ }
66
+
67
+ @media (width >= 105.0625rem) {
68
+ :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-2) {
69
+ grid-column: auto / span 4;
70
+ }
71
+
72
+ :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-4) {
73
+ grid-column: auto / span 8;
74
+ }
75
+
76
+ :where(.bf-theme) :where(.bf-content-card-wrapper.is-cols-6) {
77
+ grid-column: auto / span 12;
78
+ }
79
+ }
80
+
81
+ :where(.bf-theme) :where(.bf-content-card) {
82
+ background: var(--bf-color-background-default);
83
+ border: var(--bf-border-width) solid var(--bf-color-border-low-contrast);
84
+ box-sizing: border-box;
85
+ color: var(--bf-color-text-default);
86
+ container-name: bf-content-card;
87
+ container-type: inline-size;
88
+ flex: 1;
89
+ inline-size: 100%;
90
+ max-inline-size: 100%;
91
+ min-inline-size: 0;
92
+ overflow: hidden;
93
+ position: relative;
94
+ transition: border-color 400ms ease-in-out;
95
+ }
96
+
97
+ :where(.bf-theme) :where(.bf-content-card:hover, .bf-content-card:focus-within) {
98
+ border-color: var(--bf-color-border-high-contrast);
99
+ }
100
+
101
+ :where(.bf-theme) :where(.bf-content-card-frame) {
102
+ align-items: stretch;
103
+ display: flex;
104
+ flex-direction: column;
105
+ inline-size: 100%;
106
+ min-block-size: calc(var(--bf-space-12) - (var(--bf-border-width) * 2));
107
+ min-inline-size: 0;
108
+ padding-block-start: var(--bf-space-2);
109
+ }
110
+
111
+ :where(.bf-theme) :where(.bf-content-card.is-image) :where(.bf-content-card-frame) {
112
+ min-block-size: calc((var(--bf-space-12) * 4) - (var(--bf-border-width) * 2));
113
+ padding-block-start: 0;
114
+ }
115
+
116
+ :where(.bf-theme) :where(.bf-content-card:not(.is-image)) :where(.bf-content-card-frame) {
117
+ min-block-size: calc((var(--bf-space-12) * 2) - (var(--bf-border-width) * 2));
118
+ }
119
+
120
+ :where(.bf-theme) :where(.bf-content-card-media) {
121
+ align-items: flex-start;
122
+ display: flex;
123
+ flex: 0 0 auto;
124
+ flex-direction: column;
125
+ inline-size: 100%;
126
+ max-inline-size: 100%;
127
+ min-inline-size: 0;
128
+ padding-block-end: var(--bf-space-2);
129
+ }
130
+
131
+ :where(.bf-theme) :where(.bf-content-card-image) {
132
+ aspect-ratio: 16 / 9;
133
+ block-size: auto;
134
+ /* Preserve 16:9 within half a baseline while keeping the occupied media
135
+ block on BF's grid at arbitrary card widths. */
136
+ block-size: round(up, calc(100cqi * 9 / 16), var(--bf-baseline));
137
+ display: block;
138
+ flex: 0 0 auto;
139
+ inline-size: 100%;
140
+ margin: 0;
141
+ max-inline-size: 100%;
142
+ object-fit: cover;
143
+ }
144
+
145
+ :where(.bf-theme) :where(.bf-content-card-content) {
146
+ display: flex;
147
+ flex: 1;
148
+ flex-direction: column;
149
+ inline-size: 100%;
150
+ justify-content: space-between;
151
+ min-block-size: 0;
152
+ min-inline-size: 0;
153
+ }
154
+
155
+ :where(.bf-theme) :where(.bf-content-card-body) {
156
+ align-items: flex-start;
157
+ align-self: stretch;
158
+ display: grid;
159
+ grid-template-columns: minmax(0, 1fr);
160
+ grid-template-rows: minmax(0, 1fr);
161
+ min-inline-size: 0;
162
+ overflow: hidden;
163
+ padding-inline: var(--bf-space-2);
164
+ }
165
+
166
+ :where(.bf-theme) :where(.bf-content-card-primary, .bf-content-card-description-panel) {
167
+ display: flex;
168
+ flex-direction: column;
169
+ grid-area: 1 / 1;
170
+ inline-size: 100%;
171
+ min-inline-size: 0;
172
+ }
173
+
174
+ :where(.bf-theme) :where(.bf-content-card-primary) {
175
+ opacity: 1;
176
+ transition: opacity 400ms ease-in-out;
177
+ }
178
+
179
+ :where(.bf-theme) :where(.bf-content-card-description-panel) {
180
+ opacity: 0;
181
+ transform: translateY(calc(var(--bf-space-12) + var(--bf-space-6)));
182
+ transition: opacity 400ms ease-in-out, transform 400ms ease-in-out;
183
+ }
184
+
185
+ /* A content-card title is a real heading slot. It uses BF's h4 role in the
186
+ 2/4/6-column variants and the h1 role in the eight-column feature. */
187
+ :where(.bf-theme) :where(.bf-content-card-title) {
188
+ color: var(--bf-color-text-default);
189
+ font-family: var(--bf-h4-font-family);
190
+ font-size: var(--bf-h4-font-size);
191
+ font-style: var(--bf-h4-font-style);
192
+ font-variant-caps: var(--bf-h4-font-variant-caps);
193
+ font-weight: var(--bf-h4-font-weight);
194
+ inline-size: 100%;
195
+ letter-spacing: var(--bf-h4-letter-spacing);
196
+ line-height: var(--bf-h4-line-height);
197
+ margin-block: 0 var(--bf-h4-margin-bottom);
198
+ max-inline-size: none;
199
+ min-inline-size: 0;
200
+ overflow-wrap: anywhere;
201
+ padding-block-end: 0;
202
+ padding-block-start: var(--bf-h4-nudge-start);
203
+ text-transform: var(--bf-h4-text-transform);
204
+ }
205
+
206
+ :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-title) {
207
+ font-family: var(--bf-h1-font-family);
208
+ font-size: var(--bf-h1-font-size);
209
+ font-style: var(--bf-h1-font-style);
210
+ font-variant-caps: var(--bf-h1-font-variant-caps);
211
+ font-weight: var(--bf-h1-font-weight);
212
+ letter-spacing: var(--bf-h1-letter-spacing);
213
+ line-height: var(--bf-h1-line-height);
214
+ margin-block-end: var(--bf-h1-margin-bottom);
215
+ padding-block-end: 0;
216
+ padding-block-start: var(--bf-h1-nudge-start);
217
+ text-transform: var(--bf-h1-text-transform);
218
+ }
219
+
220
+ :where(.bf-theme) :where(.bf-content-card-main-link) {
221
+ -webkit-box-orient: vertical;
222
+ -webkit-line-clamp: 3;
223
+ color: inherit;
224
+ cursor: pointer;
225
+ display: -webkit-box;
226
+ inline-size: 100%;
227
+ line-clamp: 3;
228
+ min-inline-size: 0;
229
+ overflow: hidden;
230
+ text-decoration: none;
231
+ }
232
+
233
+ :where(.bf-theme) :where(.bf-content-card-main-link)::after {
234
+ content: "";
235
+ inset: 0;
236
+ position: absolute;
237
+ z-index: 1;
238
+ }
239
+
240
+ :where(.bf-theme) :where(.bf-content-card-main-link:is(:hover, :focus, :active, :visited)) {
241
+ color: inherit;
242
+ text-decoration: none;
243
+ }
244
+
245
+ :where(.bf-theme) :where(.bf-content-card-main-link:focus) {
246
+ outline: none;
247
+ }
248
+
249
+ :where(.bf-theme) :where(.bf-content-card:has(.bf-content-card-main-link:focus-visible)) {
250
+ outline: 3px solid var(--bf-color-focus);
251
+ outline-offset: 2px;
252
+ }
253
+
254
+ /* All nested actions sit above the expanded main-link hit area. This includes
255
+ consumer-supplied controls as well as the documented author-link slot. */
256
+ :where(.bf-theme) :where(.bf-content-card) :where(a, button, input, select, textarea, summary):not(.bf-content-card-main-link),
257
+ :where(.bf-theme) :where(.bf-content-card-interactive) {
258
+ pointer-events: auto;
259
+ position: relative;
260
+ z-index: 2;
261
+ }
262
+
263
+ :where(.bf-theme) :where(.bf-content-card-author-date) {
264
+ align-items: flex-start;
265
+ color: var(--bf-color-text-muted);
266
+ display: flex;
267
+ flex-wrap: wrap;
268
+ gap: 0 var(--bf-space-half);
269
+ min-inline-size: 0;
270
+ padding-block-end: var(--bf-space-1);
271
+ }
272
+
273
+ :where(.bf-theme) :where(.bf-content-card-author-date > *) {
274
+ margin-block-end: 0;
275
+ }
276
+
277
+ :where(.bf-theme) :where(.bf-content-card-description) {
278
+ -webkit-box-orient: vertical;
279
+ -webkit-line-clamp: 4;
280
+ display: -webkit-box;
281
+ line-clamp: 4;
282
+ max-inline-size: none;
283
+ min-inline-size: 0;
284
+ overflow: hidden;
285
+ overflow-wrap: anywhere;
286
+ }
287
+
288
+ :where(.bf-theme) :where(.bf-content-card.is-cols-6) :where(.bf-content-card-main-link, .bf-content-card-description) {
289
+ -webkit-line-clamp: 2;
290
+ line-clamp: 2;
291
+ }
292
+
293
+ :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-body) {
294
+ display: flex;
295
+ flex-direction: column;
296
+ min-block-size: 0;
297
+ }
298
+
299
+ :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-description-panel) {
300
+ flex: 1;
301
+ opacity: 1;
302
+ transform: translateY(0);
303
+ }
304
+
305
+ :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-description) {
306
+ -webkit-line-clamp: 2;
307
+ line-clamp: 2;
308
+ margin-block-end: var(--bf-space-2);
309
+ }
310
+
311
+ :where(.bf-theme) :where(.bf-content-card-footer) {
312
+ border-block-start: var(--bf-border-width) solid var(--bf-color-border-low-contrast);
313
+ inline-size: 100%;
314
+ min-inline-size: 0;
315
+ }
316
+
317
+ :where(.bf-theme) :where(.bf-content-card-footer-inner) {
318
+ align-items: center;
319
+ display: flex;
320
+ gap: var(--bf-space-1);
321
+ inline-size: 100%;
322
+ mask-image: linear-gradient(to right, #000 85%, transparent 100%);
323
+ min-block-size: var(--bf-space-4);
324
+ min-inline-size: 0;
325
+ overflow-x: auto;
326
+ padding-block-end: var(--bf-space-1);
327
+ padding-inline: var(--bf-space-2);
328
+ position: relative;
329
+ scrollbar-width: none;
330
+ z-index: 2;
331
+ }
332
+
333
+ :where([dir='rtl'].bf-theme, [dir='rtl'] .bf-theme) :where(.bf-content-card-footer-inner),
334
+ :where(.bf-theme) :where([dir='rtl'] .bf-content-card-footer-inner) {
335
+ mask-image: linear-gradient(to left, #000 85%, transparent 100%);
336
+ }
337
+
338
+ :where(.bf-theme) :where(.bf-content-card-footer-inner::-webkit-scrollbar) {
339
+ display: none;
340
+ }
341
+
342
+ :where(.bf-theme) :where(.bf-content-card-footer-inner > *) {
343
+ flex: 0 0 auto;
344
+ white-space: nowrap;
345
+ }
346
+
347
+ :where(.bf-theme) :where(.bf-content-card-resource) {
348
+ align-items: center;
349
+ display: inline-flex;
350
+ gap: var(--bf-space-half);
351
+ }
352
+
353
+ :where(.bf-theme) :where(.bf-content-card-resource > *) {
354
+ margin: 0;
355
+ }
356
+
357
+ :where(.bf-theme) :where(.bf-content-card-footer .bf-chip) {
358
+ margin: 0;
359
+ margin-inline-end: var(--bf-space-3);
360
+ }
361
+
362
+ /* Internal geometry responds to the card's allocated width. The card root is
363
+ only the container; the frame/media/body descendants own queried styles. */
364
+ /* Vanilla switches the viewport at 620px/1036px. A four-column card is much
365
+ narrower than that viewport after grid margins and gutters, so its internal
366
+ horizontal layout uses Vanilla's 460px minimum viable allocation. The
367
+ eight-column 50/50 split starts at the roughly 960px allocation left by the
368
+ 1036px viewport. This preserves the rendered switch in embedded BF grids. */
369
+ @container bf-content-card (width < 28.75rem) {
370
+ :where(.bf-theme) :where(.bf-content-card-frame:not(:has(.bf-content-card-footer))) {
371
+ min-block-size: 0;
372
+ padding-block-end: calc(var(--bf-space-2) - (var(--bf-border-width) * 2));
373
+ }
374
+ }
375
+
376
+ @container bf-content-card (width >= 28.75rem) {
377
+ :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-frame) {
378
+ column-gap: var(--bf-space-2);
379
+ flex-direction: row;
380
+ min-block-size: calc((var(--bf-space-12) * 2) - (var(--bf-border-width) * 2));
381
+ padding: var(--bf-space-2) var(--bf-space-2) 0;
382
+ }
383
+
384
+ :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6):not(.is-image)) :where(.bf-content-card-frame) {
385
+ min-block-size: calc((var(--bf-space-12) * 2) - (var(--bf-border-width) * 2));
386
+ }
387
+
388
+ :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-media) {
389
+ align-self: stretch;
390
+ inline-size: calc(var(--bf-space-12) * 3);
391
+ padding-block-end: 0;
392
+ }
393
+
394
+ :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-image) {
395
+ aspect-ratio: 16 / 9;
396
+ block-size: auto;
397
+ block-size: calc(var(--bf-space-12) + var(--bf-space-8));
398
+ }
399
+
400
+ :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-body) {
401
+ padding-inline: 0;
402
+ }
403
+
404
+ :where(.bf-theme) :where(.bf-content-card:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-footer-inner) {
405
+ padding-inline: 0;
406
+ }
407
+
408
+ /* An explicit image-top modifier wins after the horizontal rules. */
409
+ :where(.bf-theme) :where(.bf-content-card.is-image-top:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-frame) {
410
+ flex-direction: column;
411
+ min-block-size: calc((var(--bf-space-12) * 4) - (var(--bf-border-width) * 2));
412
+ padding: 0;
413
+ }
414
+
415
+ :where(.bf-theme) :where(.bf-content-card.is-image-top:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-media) {
416
+ inline-size: 100%;
417
+ padding-block-end: var(--bf-space-2);
418
+ }
419
+
420
+ :where(.bf-theme) :where(.bf-content-card.is-image-top:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-image) {
421
+ aspect-ratio: 16 / 9;
422
+ block-size: auto;
423
+ block-size: round(up, calc(100cqi * 9 / 16), var(--bf-baseline));
424
+ }
425
+
426
+ :where(.bf-theme) :where(.bf-content-card.is-image-top:is(.is-cols-4, .is-cols-6)) :where(.bf-content-card-body, .bf-content-card-footer-inner) {
427
+ padding-inline: var(--bf-space-2);
428
+ }
429
+ }
430
+
431
+ @container bf-content-card (width >= 60rem) {
432
+ :where(.bf-theme) :where(.bf-content-card.is-cols-8.is-image) :where(.bf-content-card-frame) {
433
+ display: grid;
434
+ grid-template-columns: repeat(2, minmax(0, 1fr));
435
+ min-block-size: calc((var(--bf-space-12) * 3 + var(--bf-space-8)) - (var(--bf-border-width) * 2));
436
+ padding: 0;
437
+ }
438
+
439
+ :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-content) {
440
+ grid-column: 1;
441
+ grid-row: 1;
442
+ }
443
+
444
+ :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-body) {
445
+ padding-block-start: var(--bf-space-2);
446
+ }
447
+
448
+ :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-media) {
449
+ block-size: 100%;
450
+ grid-column: 2;
451
+ grid-row: 1;
452
+ padding: var(--bf-space-1) var(--bf-space-1) 0;
453
+ }
454
+
455
+ :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-image) {
456
+ aspect-ratio: auto;
457
+ block-size: 100%;
458
+ }
459
+
460
+ :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-description) {
461
+ -webkit-line-clamp: 3;
462
+ line-clamp: 3;
463
+ margin-block-end: 0;
464
+ }
465
+
466
+ :where(.bf-theme) :where(.bf-content-card.is-image-top.is-cols-8.is-image) :where(.bf-content-card-frame) {
467
+ display: flex;
468
+ flex-direction: column;
469
+ }
470
+
471
+ :where(.bf-theme) :where(.bf-content-card.is-image-top.is-cols-8) :where(.bf-content-card-media) {
472
+ block-size: auto;
473
+ padding: 0 0 var(--bf-space-2);
474
+ }
475
+
476
+ :where(.bf-theme) :where(.bf-content-card.is-image-top.is-cols-8) :where(.bf-content-card-image) {
477
+ aspect-ratio: 16 / 9;
478
+ block-size: auto;
479
+ block-size: round(up, calc(100cqi * 9 / 16), var(--bf-baseline));
480
+ }
481
+ }
482
+
483
+ @media (38.75rem <= width < 64.75rem) {
484
+ :where(.bf-theme) :where(.bf-content-card.is-cols-2) :where(.bf-content-card-author-date),
485
+ :where(.bf-theme) :where(.bf-content-card.is-cols-6) :where(.bf-content-card-author-date) {
486
+ display: none;
487
+ }
488
+
489
+ :where(.bf-theme) :where(.bf-content-card.is-cols-8) :where(.bf-content-card-main-link) {
490
+ -webkit-line-clamp: 2;
491
+ line-clamp: 2;
492
+ }
493
+ }
494
+
495
+ /* Vanilla swaps primary copy for the optional description on desktop. Only
496
+ hover or focus of the main action triggers the swap; focusing a nested
497
+ author/footer action never makes that focused control disappear. */
498
+ @media (width >= 64.75rem) {
499
+ :where(.bf-theme) :where(.bf-content-card.is-description-reveal:not(.is-cols-8):hover) :where(.bf-content-card-primary),
500
+ :where(.bf-theme) :where(.bf-content-card.is-description-reveal:not(.is-cols-8):has(.bf-content-card-main-link:focus-visible)) :where(.bf-content-card-primary) {
501
+ opacity: 0;
502
+ }
503
+
504
+ :where(.bf-theme) :where(.bf-content-card.is-description-reveal:not(.is-cols-8):hover) :where(.bf-content-card-description-panel),
505
+ :where(.bf-theme) :where(.bf-content-card.is-description-reveal:not(.is-cols-8):has(.bf-content-card-main-link:focus-visible)) :where(.bf-content-card-description-panel) {
506
+ opacity: 1;
507
+ transform: translateY(0);
508
+ }
509
+ }
510
+
511
+ @media (prefers-reduced-motion: reduce) {
512
+ :where(.bf-theme) :where(.bf-content-card, .bf-content-card-primary, .bf-content-card-description-panel) {
513
+ transition-duration: 0.01ms;
514
+ }
515
+ }
516
516
  `;
517
517
  }