baseline-foundry 0.1.3

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 (145) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +588 -0
  3. package/config/experiments/ibm-plex-engine-smoke.json +115 -0
  4. package/config/experiments/ubuntu-engine-smoke.json +115 -0
  5. package/config/foundation-theme.json +117 -0
  6. package/config/tiers/app.json +120 -0
  7. package/config/tiers/documentation.json +120 -0
  8. package/config/tiers/editorial.json +120 -0
  9. package/config/tiers/os.json +120 -0
  10. package/dist/accordion.d.ts +5 -0
  11. package/dist/accordion.js +32 -0
  12. package/dist/application-layout.d.ts +4 -0
  13. package/dist/application-layout.js +181 -0
  14. package/dist/baseline-grid-overlay.d.ts +5 -0
  15. package/dist/baseline-grid-overlay.js +50 -0
  16. package/dist/baseline-grid-theme.d.ts +3 -0
  17. package/dist/baseline-grid-theme.js +3 -0
  18. package/dist/baseline-grid.d.ts +7 -0
  19. package/dist/baseline-grid.js +35 -0
  20. package/dist/build.d.ts +21 -0
  21. package/dist/build.js +440 -0
  22. package/dist/code-snippet.d.ts +6 -0
  23. package/dist/code-snippet.js +95 -0
  24. package/dist/contextual-menu.d.ts +4 -0
  25. package/dist/contextual-menu.js +156 -0
  26. package/dist/css-app-tier.d.ts +1 -0
  27. package/dist/css-app-tier.js +77 -0
  28. package/dist/css-components/article-pagination.d.ts +13 -0
  29. package/dist/css-components/article-pagination.js +151 -0
  30. package/dist/css-components/button-actions.d.ts +7 -0
  31. package/dist/css-components/button-actions.js +165 -0
  32. package/dist/css-components/cards-options.d.ts +6 -0
  33. package/dist/css-components/cards-options.js +180 -0
  34. package/dist/css-components/chip-badge-status.d.ts +10 -0
  35. package/dist/css-components/chip-badge-status.js +162 -0
  36. package/dist/css-components/content-card.d.ts +25 -0
  37. package/dist/css-components/content-card.js +517 -0
  38. package/dist/css-components/control-row.d.ts +2 -0
  39. package/dist/css-components/control-row.js +18 -0
  40. package/dist/css-components/cta-figure-aspect.d.ts +1 -0
  41. package/dist/css-components/cta-figure-aspect.js +123 -0
  42. package/dist/css-components/document-navigation.d.ts +13 -0
  43. package/dist/css-components/document-navigation.js +400 -0
  44. package/dist/css-components/editorial-content.d.ts +6 -0
  45. package/dist/css-components/editorial-content.js +52 -0
  46. package/dist/css-components/icon.d.ts +1 -0
  47. package/dist/css-components/icon.js +75 -0
  48. package/dist/css-components/interactive-feedback.d.ts +2 -0
  49. package/dist/css-components/interactive-feedback.js +230 -0
  50. package/dist/css-components/interactive-tables.d.ts +7 -0
  51. package/dist/css-components/interactive-tables.js +164 -0
  52. package/dist/css-components/linked-logo-site-layout.d.ts +21 -0
  53. package/dist/css-components/linked-logo-site-layout.js +214 -0
  54. package/dist/css-components/list-tree.d.ts +5 -0
  55. package/dist/css-components/list-tree.js +98 -0
  56. package/dist/css-components/list.d.ts +3 -0
  57. package/dist/css-components/list.js +119 -0
  58. package/dist/css-components/logo-media.d.ts +16 -0
  59. package/dist/css-components/logo-media.js +219 -0
  60. package/dist/css-components/navigation-layout.d.ts +5 -0
  61. package/dist/css-components/navigation-layout.js +151 -0
  62. package/dist/css-components/panel.d.ts +6 -0
  63. package/dist/css-components/panel.js +148 -0
  64. package/dist/css-components/search-box-and-filter.d.ts +9 -0
  65. package/dist/css-components/search-box-and-filter.js +267 -0
  66. package/dist/css-components/sites-editorial-ports.d.ts +19 -0
  67. package/dist/css-components/sites-editorial-ports.js +264 -0
  68. package/dist/css-components/sites-foundation.d.ts +17 -0
  69. package/dist/css-components/sites-foundation.js +173 -0
  70. package/dist/css-components/sites-rich-lists.d.ts +18 -0
  71. package/dist/css-components/sites-rich-lists.js +364 -0
  72. package/dist/css-components/static-content-ports.d.ts +14 -0
  73. package/dist/css-components/static-content-ports.js +206 -0
  74. package/dist/css-components/tab-section.d.ts +19 -0
  75. package/dist/css-components/tab-section.js +103 -0
  76. package/dist/css-components/table.d.ts +7 -0
  77. package/dist/css-components/table.js +79 -0
  78. package/dist/css-components/tabs-choice-breadcrumbs.d.ts +9 -0
  79. package/dist/css-components/tabs-choice-breadcrumbs.js +307 -0
  80. package/dist/css-components/tiered-list-equal-height-row.d.ts +1 -0
  81. package/dist/css-components/tiered-list-equal-height-row.js +286 -0
  82. package/dist/css-components.d.ts +2 -0
  83. package/dist/css-components.js +2701 -0
  84. package/dist/css-grid.d.ts +1 -0
  85. package/dist/css-grid.js +179 -0
  86. package/dist/css.d.ts +6 -0
  87. package/dist/css.js +431 -0
  88. package/dist/experiments/ibm-plex-engine-smoke/styles.css +8969 -0
  89. package/dist/experiments/ibm-plex-engine-smoke/surfaces.json +604 -0
  90. package/dist/experiments/ibm-plex-engine-smoke/tokens.json +217 -0
  91. package/dist/in-page-navigation.d.ts +7 -0
  92. package/dist/in-page-navigation.js +136 -0
  93. package/dist/index.d.ts +37 -0
  94. package/dist/index.js +18 -0
  95. package/dist/interactive-feedback.d.ts +14 -0
  96. package/dist/interactive-feedback.js +96 -0
  97. package/dist/interactive-tables.d.ts +28 -0
  98. package/dist/interactive-tables.js +184 -0
  99. package/dist/list-tree.d.ts +4 -0
  100. package/dist/list-tree.js +44 -0
  101. package/dist/panel-drawer.d.ts +4 -0
  102. package/dist/panel-drawer.js +171 -0
  103. package/dist/presets/app-tier/styles.css +9459 -0
  104. package/dist/presets/app-tier/surfaces.json +1225 -0
  105. package/dist/presets/app-tier/tokens.json +221 -0
  106. package/dist/presets/prose/styles.css +9442 -0
  107. package/dist/presets/prose/surfaces.json +1225 -0
  108. package/dist/presets/prose/tokens.json +221 -0
  109. package/dist/presets.d.ts +6 -0
  110. package/dist/presets.js +27 -0
  111. package/dist/range-controls.d.ts +9 -0
  112. package/dist/range-controls.js +73 -0
  113. package/dist/resizable-aside.d.ts +4 -0
  114. package/dist/resizable-aside.js +328 -0
  115. package/dist/side-navigation.d.ts +4 -0
  116. package/dist/side-navigation.js +219 -0
  117. package/dist/styles.css +9442 -0
  118. package/dist/surfaces.json +1225 -0
  119. package/dist/tabs.d.ts +4 -0
  120. package/dist/tabs.js +88 -0
  121. package/dist/tier-registry.d.ts +10 -0
  122. package/dist/tier-registry.js +25 -0
  123. package/dist/tiers/app/styles.css +9459 -0
  124. package/dist/tiers/app/surfaces.json +1225 -0
  125. package/dist/tiers/app/tokens.json +221 -0
  126. package/dist/tiers/documentation/styles.css +9442 -0
  127. package/dist/tiers/documentation/surfaces.json +1225 -0
  128. package/dist/tiers/documentation/tokens.json +221 -0
  129. package/dist/tiers/editorial/styles.css +9442 -0
  130. package/dist/tiers/editorial/surfaces.json +1225 -0
  131. package/dist/tiers/editorial/tokens.json +221 -0
  132. package/dist/tiers/os/styles.css +9442 -0
  133. package/dist/tiers/os/surfaces.json +1225 -0
  134. package/dist/tiers/os/tokens.json +221 -0
  135. package/dist/tokens.json +221 -0
  136. package/dist/tooltip.d.ts +4 -0
  137. package/dist/tooltip.js +70 -0
  138. package/dist/top-navigation.d.ts +4 -0
  139. package/dist/top-navigation.js +354 -0
  140. package/dist/types.d.ts +155 -0
  141. package/dist/types.js +1 -0
  142. package/dist/vanilla-theme-colors.d.ts +5 -0
  143. package/dist/vanilla-theme-colors.js +208 -0
  144. package/docs/publishing.md +66 -0
  145. package/package.json +108 -0
@@ -0,0 +1,517 @@
1
+ /**
2
+ * Rich content-card parity with current Vanilla. This intentionally remains a
3
+ * separate family from the general-purpose `bf-card` primitive.
4
+ *
5
+ * Vanilla -> BF rhythm mapping (Vanilla's spacing unit is 0.5rem):
6
+ * - 16px content padding/gap -> `--bf-space-2`.
7
+ * - 8px footer/image spacing -> `--bf-space-1`.
8
+ * - 32px wrapper separation -> `--bf-space-4`.
9
+ * - 380px vertical minimum -> 48 BF baselines (384px in editorial), avoiding
10
+ * Vanilla's half-baseline ending while retaining its occupied silhouette.
11
+ * - 192px horizontal/text minimum -> 24 BF baselines.
12
+ * - 352px eight-column minimum -> 44 BF baselines.
13
+ * - 284px horizontal media width -> 36 BF baselines (288px in editorial).
14
+ *
15
+ * The root card establishes a named query container. Only descendants change
16
+ * inside container queries; this avoids the invalid query-the-container-itself
17
+ * pattern. Global media queries are retained only where Vanilla's behaviour is
18
+ * genuinely viewport/input based (grid span, hover reveal and line clamping).
19
+ *
20
+ * The expanded click target is a pseudo-element of the one real main link,
21
+ * rather than a duplicate aria-hidden overlay anchor. Nested controls are
22
+ * raised above it, so every distinct action stays pointer- and keyboard-
23
+ * reachable.
24
+ */
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
+ }
516
+ `;
517
+ }
@@ -0,0 +1,2 @@
1
+ /** A wrapping form composition whose children retain their owned spacing. */
2
+ export declare function controlRowCss(): string;
@@ -0,0 +1,18 @@
1
+ /** A wrapping form composition whose children retain their owned spacing. */
2
+ export function controlRowCss() {
3
+ return `:where(.bf-theme) :where(.bf-control-row) {
4
+ align-items: end;
5
+ display: flex;
6
+ flex-wrap: wrap;
7
+ gap: var(--bf-field-gap);
8
+ margin: 0;
9
+ min-inline-size: 0;
10
+ }
11
+
12
+ :where(.bf-theme) :where(.bf-control-row) > :where(.bf-field, .bf-control) {
13
+ align-self: end;
14
+ flex: 1 1 min(100%, 16rem);
15
+ min-inline-size: 0;
16
+ }
17
+ `;
18
+ }
@@ -0,0 +1 @@
1
+ export declare function ctaFigureAspectCss(): string;
@@ -0,0 +1,123 @@
1
+ export function ctaFigureAspectCss() {
2
+ return `/* ------------------------------------------------------------------ */
3
+ /* CTA block (Vanilla parity). */
4
+ /* Inline-row of call-to-action items (typically a heading and one or */
5
+ /* more buttons or links). Container-owned spacing: borderless by */
6
+ /* default, .is-bordered adds a top divider rule and small padding. */
7
+ /* (Vanilla ships the same modifier as has-border; renamed for the BF */
8
+ /* is-* convention.) */
9
+ /* ------------------------------------------------------------------ */
10
+ /* ------------------------------------------------------------------ */
11
+
12
+ :where(.bf-theme) :where(.bf-cta-block) {
13
+ align-items: baseline;
14
+ column-gap: var(--bf-space-2);
15
+ display: flex;
16
+ flex-wrap: wrap;
17
+ margin-block-end: 0;
18
+ row-gap: var(--bf-space-1);
19
+ }
20
+
21
+ :where(.bf-theme) :where(.bf-cta-block.is-bordered) {
22
+ border-block-start: var(--bf-border-width) solid var(--bf-color-border-low-contrast);
23
+ padding-block-start: calc(var(--bf-space-1) - var(--bf-border-width));
24
+ }
25
+
26
+ /* ------------------------------------------------------------------ */
27
+ /* Figure (Vanilla parity). */
28
+ /* Native <figure> wrapper for an image, video, or other media plus */
29
+ /* an italic caption. The owning stack sets external spacing; the */
30
+ /* caption owns its own top space so the */
31
+ /* image sits flush against the next baseline above its caption. */
32
+ /* ------------------------------------------------------------------ */
33
+
34
+ :where(.bf-theme) :where(.bf-figure) {
35
+ display: block;
36
+ inline-size: 100%;
37
+ margin: 0;
38
+ }
39
+
40
+ :where(.bf-theme) :where(.bf-figure) > :where(img, picture, video, canvas, svg) {
41
+ block-size: auto;
42
+ display: block;
43
+ inline-size: 100%;
44
+ max-inline-size: 100%;
45
+ }
46
+
47
+ /* Keep light artwork legible when the surrounding theme is dark. */
48
+ :where(.bf-theme) :where(.bf-figure.is-light-inset) > :where(img, picture, video, canvas, svg, .bf-aspect) {
49
+ background: #fff;
50
+ box-sizing: border-box;
51
+ padding: var(--bf-space-2);
52
+ }
53
+
54
+ :where(.bf-theme) :where(.bf-figure-caption) {
55
+ color: var(--bf-color-text-default);
56
+ display: block;
57
+ font-style: italic;
58
+ inline-size: 100%;
59
+ margin-block: var(--bf-space-1) 0;
60
+ }
61
+
62
+ /* ------------------------------------------------------------------ */
63
+ /* Aspect — generic aspect-ratio slot. */
64
+ /* Reserves a fixed-ratio box so embedded media (img/picture/video/ */
65
+ /* canvas/iframe) load without layout shift. Composes inside bf-figure */
66
+ /* when a constrained captioned image is needed. */
67
+ /* ------------------------------------------------------------------ */
68
+
69
+ :where(.bf-theme) :where(.bf-aspect) {
70
+ aspect-ratio: 16 / 9;
71
+ display: block;
72
+ inline-size: 100%;
73
+ overflow: hidden;
74
+ position: relative;
75
+ }
76
+
77
+ :where(.bf-theme) :where(.bf-aspect.is-16-9) {
78
+ aspect-ratio: 16 / 9;
79
+ }
80
+
81
+ :where(.bf-theme) :where(.bf-aspect.is-3-2) {
82
+ aspect-ratio: 3 / 2;
83
+ }
84
+
85
+ :where(.bf-theme) :where(.bf-aspect.is-4-3) {
86
+ aspect-ratio: 4 / 3;
87
+ }
88
+
89
+ :where(.bf-theme) :where(.bf-aspect.is-2-3) {
90
+ aspect-ratio: 2 / 3;
91
+ }
92
+
93
+ :where(.bf-theme) :where(.bf-aspect.is-cinematic) {
94
+ aspect-ratio: 12 / 5;
95
+ }
96
+
97
+ :where(.bf-theme) :where(.bf-aspect.is-square) {
98
+ aspect-ratio: 1 / 1;
99
+ }
100
+
101
+ :where(.bf-theme) :where(.bf-aspect) > :where(img, picture, video, canvas, iframe) {
102
+ block-size: 100%;
103
+ display: block;
104
+ inline-size: 100%;
105
+ object-fit: cover;
106
+ }
107
+
108
+ :where(.bf-theme) :where(.bf-aspect) > :where(picture) > :where(img) {
109
+ block-size: 100%;
110
+ display: block;
111
+ inline-size: 100%;
112
+ object-fit: cover;
113
+ }
114
+
115
+ :where(.bf-theme) :where(.bf-aspect.is-contain) > :where(img, video, canvas, iframe) {
116
+ object-fit: contain;
117
+ }
118
+
119
+ :where(.bf-theme) :where(.bf-aspect.is-contain) > :where(picture) > :where(img) {
120
+ object-fit: contain;
121
+ }
122
+ `;
123
+ }
@@ -0,0 +1,13 @@
1
+ type DocumentNavigationCssOptions = {
2
+ bodyCaseTypeStyles: string;
3
+ bodyTypeStyles: string;
4
+ headingTypeStyles: string;
5
+ };
6
+ /**
7
+ * Document-navigation ports keep the useful rendered hierarchy from current
8
+ * Vanilla while using BF roles, logical properties and intrinsic breakpoints.
9
+ * Behaviour remains deliberately external: controllers synchronise their
10
+ * aria-expanded state with the matching is-expanded modifier.
11
+ */
12
+ export declare function documentNavigationCss(options: DocumentNavigationCssOptions): string;
13
+ export {};