barua-ui 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -0
- package/css/barua.css +28 -0
- package/css/base.css +242 -0
- package/css/components/actions.css +371 -0
- package/css/components/auth.css +237 -0
- package/css/components/charts.css +370 -0
- package/css/components/content.css +802 -0
- package/css/components/control-center.css +370 -0
- package/css/components/feedback.css +364 -0
- package/css/components/forms.css +511 -0
- package/css/components/marketing.css +280 -0
- package/css/components/media.css +321 -0
- package/css/components/mobile.css +177 -0
- package/css/components/nav.css +682 -0
- package/css/components/overlays.css +574 -0
- package/css/components/productivity.css +525 -0
- package/css/components/specialized.css +367 -0
- package/css/liquid.css +213 -0
- package/css/tokens.css +365 -0
- package/css/utilities.css +507 -0
- package/dist/index.cjs +2750 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1106 -0
- package/dist/index.d.ts +1106 -0
- package/dist/index.js +2462 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
Barua UI — Utilities & Layout primitives
|
|
3
|
+
Container, Stack/HStack/VStack, Grid, Flex, Spacer, Divider, Scroll Area,
|
|
4
|
+
materials, text styles, safe area.
|
|
5
|
+
========================================================================== */
|
|
6
|
+
|
|
7
|
+
@layer utilities {
|
|
8
|
+
/* ---- Container --------------------------------------------------------- */
|
|
9
|
+
.b-container {
|
|
10
|
+
width: 100%;
|
|
11
|
+
max-width: var(--b-container-lg);
|
|
12
|
+
margin-inline: auto;
|
|
13
|
+
padding-inline: var(--b-space-4);
|
|
14
|
+
}
|
|
15
|
+
.b-container--sm { max-width: var(--b-container-sm); }
|
|
16
|
+
|
|
17
|
+
/* The wall — the surface a wallpaper hangs on.
|
|
18
|
+
Glass is a material, and a material only reads as one when there is
|
|
19
|
+
something behind it: over a flat page, five levels of glass all look like
|
|
20
|
+
the same grey. Give the wall a picture and the whole system comes alive,
|
|
21
|
+
which is why changing it belongs to the person using the interface.
|
|
22
|
+
Harmless until a picture is set: --b-wall-image defaults to none. */
|
|
23
|
+
.b-wall {
|
|
24
|
+
background:
|
|
25
|
+
var(--b-wall-image, none) center / cover no-repeat fixed
|
|
26
|
+
var(--b-wall-ground, var(--b-bg));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Wallpaper-driven scheme: a surface pinned to a known-bright or
|
|
30
|
+
known-dark backdrop resolves every light-dark() token that way, so text,
|
|
31
|
+
glass and fills answer to the picture rather than to the app theme.
|
|
32
|
+
Set [data-wall-scheme] on <html>; mark the surface .b-wallpaper-scope. */
|
|
33
|
+
[data-wall-scheme="light"] :is(.b-wallpaper-scope, .b-wall),
|
|
34
|
+
[data-wall-scheme="dark"] :is(.b-wallpaper-scope, .b-wall) {
|
|
35
|
+
/* Re-anchor the ink inside the scope: text colour is resolved further up
|
|
36
|
+
and inherited down, so without this the scheme would flip the glass but
|
|
37
|
+
not the words sitting on it. */
|
|
38
|
+
color: var(--b-text);
|
|
39
|
+
}
|
|
40
|
+
[data-wall-scheme="light"] :is(.b-wallpaper-scope, .b-wall) { color-scheme: light; }
|
|
41
|
+
[data-wall-scheme="dark"] :is(.b-wallpaper-scope, .b-wall) { color-scheme: dark; }
|
|
42
|
+
|
|
43
|
+
/* Stage — a full-viewport, non-scrolling surface (ambient walls, kiosks,
|
|
44
|
+
TV/CarPlay-style screens). Desktop locks to the viewport and clips;
|
|
45
|
+
below md it behaves as a normal scrolling page. */
|
|
46
|
+
@media (min-width: 768px) {
|
|
47
|
+
.b-stage {
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
height: 100dvh;
|
|
51
|
+
overflow: clip;
|
|
52
|
+
}
|
|
53
|
+
.b-stage > .b-container,
|
|
54
|
+
.b-stage > main { display: flex; flex-direction: column; flex: 1; min-height: 0; }
|
|
55
|
+
.b-stage .b-scroll-area { flex: 1; min-height: 0; }
|
|
56
|
+
.b-stage > .b-container > .b-dashboard,
|
|
57
|
+
.b-stage > .b-container > main.b-dashboard,
|
|
58
|
+
.b-stage > main > .b-dashboard { flex: 1; min-height: 0; grid-auto-rows: minmax(0, 1fr); }
|
|
59
|
+
.b-stage > .b-container > .b-dashboard > .b-card,
|
|
60
|
+
.b-stage > .b-container > main.b-dashboard > .b-card,
|
|
61
|
+
.b-stage > main > .b-dashboard > .b-card { min-height: 0; overflow: hidden; }
|
|
62
|
+
}
|
|
63
|
+
.b-container--md { max-width: var(--b-container-md); }
|
|
64
|
+
.b-container--xl { max-width: var(--b-container-xl); }
|
|
65
|
+
.b-container--fluid { max-width: none; }
|
|
66
|
+
|
|
67
|
+
/* ---- Stack (VStack default, HStack modifier) --------------------------- */
|
|
68
|
+
.b-stack, .b-vstack {
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
gap: var(--b-gap, var(--b-space-4));
|
|
72
|
+
}
|
|
73
|
+
.b-hstack {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: row;
|
|
76
|
+
align-items: center;
|
|
77
|
+
gap: var(--b-gap, var(--b-space-3));
|
|
78
|
+
}
|
|
79
|
+
.b-stack--start { align-items: flex-start; }
|
|
80
|
+
.b-stack--center { align-items: center; }
|
|
81
|
+
.b-stack--end { align-items: flex-end; }
|
|
82
|
+
.b-stack--stretch { align-items: stretch; }
|
|
83
|
+
.b-stack--between { justify-content: space-between; }
|
|
84
|
+
.b-stack--wrap { flex-wrap: wrap; }
|
|
85
|
+
.b-gap-0 { --b-gap: 0; }
|
|
86
|
+
.b-gap-1 { --b-gap: var(--b-space-1); }
|
|
87
|
+
.b-gap-2 { --b-gap: var(--b-space-2); }
|
|
88
|
+
.b-gap-3 { --b-gap: var(--b-space-3); }
|
|
89
|
+
.b-gap-4 { --b-gap: var(--b-space-4); }
|
|
90
|
+
.b-gap-6 { --b-gap: var(--b-space-6); }
|
|
91
|
+
.b-gap-8 { --b-gap: var(--b-space-8); }
|
|
92
|
+
|
|
93
|
+
/* ---- Spacer ------------------------------------------------------------ */
|
|
94
|
+
.b-spacer { flex: 1 1 0%; min-width: 0; min-height: 0; }
|
|
95
|
+
|
|
96
|
+
/* ---- Grid -------------------------------------------------------------- */
|
|
97
|
+
.b-grid {
|
|
98
|
+
display: grid;
|
|
99
|
+
gap: var(--b-gap, var(--b-space-4));
|
|
100
|
+
grid-template-columns: repeat(var(--b-cols, 12), minmax(0, 1fr));
|
|
101
|
+
}
|
|
102
|
+
.b-grid--2 { --b-cols: 2; }
|
|
103
|
+
.b-grid--3 { --b-cols: 3; }
|
|
104
|
+
.b-grid--4 { --b-cols: 4; }
|
|
105
|
+
.b-grid--6 { --b-cols: 6; }
|
|
106
|
+
.b-grid--auto {
|
|
107
|
+
grid-template-columns: repeat(auto-fill, minmax(var(--b-col-min, 16rem), 1fr));
|
|
108
|
+
}
|
|
109
|
+
.b-col-span-2 { grid-column: span 2; }
|
|
110
|
+
.b-col-span-3 { grid-column: span 3; }
|
|
111
|
+
.b-col-span-4 { grid-column: span 4; }
|
|
112
|
+
.b-col-span-6 { grid-column: span 6; }
|
|
113
|
+
.b-col-span-full { grid-column: 1 / -1; }
|
|
114
|
+
|
|
115
|
+
/* Card Grid & Masonry */
|
|
116
|
+
.b-card-grid {
|
|
117
|
+
display: grid;
|
|
118
|
+
gap: var(--b-space-4);
|
|
119
|
+
grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
|
|
120
|
+
}
|
|
121
|
+
.b-masonry {
|
|
122
|
+
columns: var(--b-masonry-cols, 3) 16rem;
|
|
123
|
+
column-gap: var(--b-space-4);
|
|
124
|
+
}
|
|
125
|
+
.b-masonry > * { break-inside: avoid; margin-block-end: var(--b-space-4); }
|
|
126
|
+
|
|
127
|
+
/* ---- Flex shorthand ---------------------------------------------------- */
|
|
128
|
+
.b-flex { display: flex; gap: var(--b-gap, var(--b-space-3)); }
|
|
129
|
+
.b-flex--center { align-items: center; justify-content: center; }
|
|
130
|
+
.b-flex--between { align-items: center; justify-content: space-between; }
|
|
131
|
+
.b-flex--wrap { flex-wrap: wrap; }
|
|
132
|
+
.b-grow { flex-grow: 1; min-width: 0; }
|
|
133
|
+
.b-shrink-0 { flex-shrink: 0; }
|
|
134
|
+
|
|
135
|
+
/* ---- Divider ----------------------------------------------------------- */
|
|
136
|
+
.b-divider {
|
|
137
|
+
border: none;
|
|
138
|
+
border-top: 1px solid var(--b-separator);
|
|
139
|
+
margin: 0;
|
|
140
|
+
align-self: stretch;
|
|
141
|
+
}
|
|
142
|
+
.b-divider--vertical {
|
|
143
|
+
border-top: none;
|
|
144
|
+
border-inline-start: 1px solid var(--b-separator);
|
|
145
|
+
width: 0;
|
|
146
|
+
min-height: 1em;
|
|
147
|
+
}
|
|
148
|
+
.b-divider--inset { margin-inline-start: var(--b-space-12); }
|
|
149
|
+
.b-divider--label {
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
gap: var(--b-space-3);
|
|
153
|
+
border: none;
|
|
154
|
+
color: var(--b-text-tertiary);
|
|
155
|
+
font-size: var(--b-text-footnote);
|
|
156
|
+
}
|
|
157
|
+
.b-divider--label::before,
|
|
158
|
+
.b-divider--label::after {
|
|
159
|
+
content: "";
|
|
160
|
+
flex: 1;
|
|
161
|
+
border-top: 1px solid var(--b-separator);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* ---- Scroll Area ------------------------------------------------------- */
|
|
165
|
+
.b-scroll-area {
|
|
166
|
+
overflow: auto;
|
|
167
|
+
overscroll-behavior: contain;
|
|
168
|
+
scrollbar-gutter: stable;
|
|
169
|
+
}
|
|
170
|
+
/* A scroll pane's content keeps its own height: as a flex parent it would
|
|
171
|
+
otherwise compress its children to fit and nothing would ever scroll. */
|
|
172
|
+
.b-scroll-area > * { flex-shrink: 0; }
|
|
173
|
+
.b-scroll-area--x { overflow: auto hidden; }
|
|
174
|
+
.b-scroll-area--y { overflow: hidden auto; }
|
|
175
|
+
.b-scroll-area--fade {
|
|
176
|
+
mask-image: linear-gradient(to bottom, transparent, black var(--b-space-4),
|
|
177
|
+
black calc(100% - var(--b-space-4)), transparent);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* ---- Split view / resizable panels ------------------------------------- */
|
|
181
|
+
.b-split {
|
|
182
|
+
display: flex;
|
|
183
|
+
align-items: stretch;
|
|
184
|
+
min-height: 0;
|
|
185
|
+
}
|
|
186
|
+
.b-split > .b-panel { min-width: 0; overflow: auto; }
|
|
187
|
+
.b-panel {
|
|
188
|
+
background: var(--b-surface);
|
|
189
|
+
border: 1px solid var(--b-separator);
|
|
190
|
+
border-radius: var(--b-radius-lg);
|
|
191
|
+
}
|
|
192
|
+
.b-panel--plain { background: none; border: none; border-radius: 0; }
|
|
193
|
+
.b-resizable { resize: horizontal; overflow: auto; min-width: 12rem; max-width: 70%; }
|
|
194
|
+
.b-resizable--vertical { resize: vertical; min-height: 6rem; max-height: 80vh; }
|
|
195
|
+
.b-resize-handle {
|
|
196
|
+
flex: 0 0 auto;
|
|
197
|
+
width: 9px;
|
|
198
|
+
margin-inline: -4px;
|
|
199
|
+
cursor: col-resize;
|
|
200
|
+
position: relative;
|
|
201
|
+
z-index: var(--b-z-raised);
|
|
202
|
+
}
|
|
203
|
+
.b-resize-handle::after {
|
|
204
|
+
content: "";
|
|
205
|
+
position: absolute;
|
|
206
|
+
inset: 0 4px;
|
|
207
|
+
background: var(--b-separator);
|
|
208
|
+
transition: background var(--b-duration-fast) var(--b-ease-standard);
|
|
209
|
+
}
|
|
210
|
+
.b-resize-handle:hover::after,
|
|
211
|
+
.b-resize-handle.is-active::after { background: var(--b-color-accent); inset: 0 3px; border-radius: 2px; }
|
|
212
|
+
|
|
213
|
+
/* ---- Section ----------------------------------------------------------- */
|
|
214
|
+
.b-section { padding-block: var(--b-space-10); }
|
|
215
|
+
.b-section--tight { padding-block: var(--b-space-6); }
|
|
216
|
+
|
|
217
|
+
/* ---- Materials (Liquid Glass) -------------------------------------------
|
|
218
|
+
Multi-layer glass material utilities. Each level composes:
|
|
219
|
+
background tint + backdrop-filter + specular edge + depth shadow.
|
|
220
|
+
---------------------------------------------------------------------- */
|
|
221
|
+
.b-material-ultrathin, .b-material-thin, .b-material-regular,
|
|
222
|
+
.b-material-thick, .b-material-chrome, .b-material-accent {
|
|
223
|
+
position: relative;
|
|
224
|
+
-webkit-backdrop-filter: var(--b-glass);
|
|
225
|
+
backdrop-filter: var(--b-glass);
|
|
226
|
+
border: 1px solid light-dark(rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.04));
|
|
227
|
+
box-shadow: var(--b-glass-ambient);
|
|
228
|
+
overflow: hidden;
|
|
229
|
+
}
|
|
230
|
+
.b-material-ultrathin::before, .b-material-thin::before,
|
|
231
|
+
.b-material-regular::before, .b-material-thick::before,
|
|
232
|
+
.b-material-chrome::before, .b-material-accent::before {
|
|
233
|
+
content: "";
|
|
234
|
+
position: absolute;
|
|
235
|
+
inset: 0;
|
|
236
|
+
border-radius: inherit;
|
|
237
|
+
box-shadow: var(--b-glass-edge);
|
|
238
|
+
pointer-events: none;
|
|
239
|
+
}
|
|
240
|
+
.b-material-ultrathin { background: var(--b-material-ultrathin-bg);
|
|
241
|
+
-webkit-backdrop-filter: var(--b-glass-light); backdrop-filter: var(--b-glass-light); }
|
|
242
|
+
.b-material-thin { background: var(--b-material-thin-bg); }
|
|
243
|
+
.b-material-regular { background: var(--b-material-regular-bg); }
|
|
244
|
+
.b-material-thick { background: var(--b-material-thick-bg);
|
|
245
|
+
-webkit-backdrop-filter: var(--b-glass-heavy); backdrop-filter: var(--b-glass-heavy); }
|
|
246
|
+
.b-material-chrome { background: var(--b-material-chrome-bg); }
|
|
247
|
+
.b-material-accent { background: var(--b-material-accent-bg); }
|
|
248
|
+
|
|
249
|
+
/* Clear variant — permanently transparent, for media-rich backgrounds.
|
|
250
|
+
Needs dimming layer for legibility. Only use when:
|
|
251
|
+
1. Element is on top of media-rich content
|
|
252
|
+
2. Content layer won't be negatively impacted by dimming
|
|
253
|
+
3. Content above is bold and bright */
|
|
254
|
+
.b-material-clear {
|
|
255
|
+
position: relative;
|
|
256
|
+
background: light-dark(rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.06));
|
|
257
|
+
-webkit-backdrop-filter: blur(var(--b-blur-md)) saturate(1.5);
|
|
258
|
+
backdrop-filter: blur(var(--b-blur-md)) saturate(1.5);
|
|
259
|
+
border: 1px solid light-dark(rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.04));
|
|
260
|
+
box-shadow: var(--b-glass-shadow);
|
|
261
|
+
overflow: hidden;
|
|
262
|
+
}
|
|
263
|
+
.b-material-clear::before {
|
|
264
|
+
content: "";
|
|
265
|
+
position: absolute;
|
|
266
|
+
inset: 0;
|
|
267
|
+
border-radius: inherit;
|
|
268
|
+
box-shadow: var(--b-glass-edge);
|
|
269
|
+
pointer-events: none;
|
|
270
|
+
}
|
|
271
|
+
/* Dimming layer for clear variant — ensures legibility over media */
|
|
272
|
+
.b-material-clear--dimmed::after {
|
|
273
|
+
content: "";
|
|
274
|
+
position: absolute;
|
|
275
|
+
inset: 0;
|
|
276
|
+
border-radius: inherit;
|
|
277
|
+
background: light-dark(rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.22));
|
|
278
|
+
pointer-events: none;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* Prominent variant — tinted accent glass for primary navigation/actions */
|
|
282
|
+
.b-material-prominent {
|
|
283
|
+
position: relative;
|
|
284
|
+
background: var(--b-glass-tint-strong);
|
|
285
|
+
-webkit-backdrop-filter: var(--b-glass);
|
|
286
|
+
backdrop-filter: var(--b-glass);
|
|
287
|
+
border: 1px solid light-dark(rgba(10, 122, 255, 0.12), rgba(10, 132, 255, 0.16));
|
|
288
|
+
box-shadow: var(--b-glass-shadow);
|
|
289
|
+
overflow: hidden;
|
|
290
|
+
}
|
|
291
|
+
.b-material-prominent::before {
|
|
292
|
+
content: "";
|
|
293
|
+
position: absolute;
|
|
294
|
+
inset: 0;
|
|
295
|
+
border-radius: inherit;
|
|
296
|
+
box-shadow: var(--b-glass-edge);
|
|
297
|
+
pointer-events: none;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* ---- Glass Container ---------------------------------------------------
|
|
301
|
+
Groups multiple glass elements so they blend shapes and morph together.
|
|
302
|
+
Similar to Apple's GlassEffectContainer. Children with glass effects
|
|
303
|
+
will merge their shapes when within the container's spacing.
|
|
304
|
+
---------------------------------------------------------------------- */
|
|
305
|
+
.b-glass-container {
|
|
306
|
+
display: flex;
|
|
307
|
+
flex-wrap: wrap;
|
|
308
|
+
gap: var(--b-glass-spacing, var(--b-space-2));
|
|
309
|
+
isolation: isolate;
|
|
310
|
+
}
|
|
311
|
+
.b-glass-container--col { flex-direction: column; }
|
|
312
|
+
|
|
313
|
+
/* ---- Glass Morph Transitions -------------------------------------------
|
|
314
|
+
Use these on elements inside a .b-glass-container to enable
|
|
315
|
+
fluid morphing between glass shapes during transitions.
|
|
316
|
+
---------------------------------------------------------------------- */
|
|
317
|
+
.b-glass-morph {
|
|
318
|
+
transition: scale var(--b-duration-normal) var(--b-ease-spring),
|
|
319
|
+
opacity var(--b-duration-normal) var(--b-ease-out),
|
|
320
|
+
translate var(--b-duration-normal) var(--b-ease-spring);
|
|
321
|
+
}
|
|
322
|
+
.b-glass-morph-enter {
|
|
323
|
+
animation: b-glass-materialize var(--b-duration-slow) var(--b-ease-spring) both;
|
|
324
|
+
}
|
|
325
|
+
.b-glass-morph-exit {
|
|
326
|
+
animation: b-glass-materialize var(--b-duration-slow) var(--b-ease-spring) reverse both;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* ---- Glass Interactive -------------------------------------------------
|
|
330
|
+
Adds Apple's "energize" effect — scale, bounce, and shimmer on press.
|
|
331
|
+
Apply to any glass element that should respond to touch/pointer.
|
|
332
|
+
---------------------------------------------------------------------- */
|
|
333
|
+
.b-glass-interactive {
|
|
334
|
+
cursor: pointer;
|
|
335
|
+
transition: scale var(--b-duration-instant) var(--b-ease-standard),
|
|
336
|
+
background var(--b-duration-fast) var(--b-ease-standard),
|
|
337
|
+
box-shadow var(--b-duration-fast) var(--b-ease-standard);
|
|
338
|
+
}
|
|
339
|
+
.b-glass-interactive:hover {
|
|
340
|
+
scale: 1.02;
|
|
341
|
+
}
|
|
342
|
+
.b-glass-interactive:active {
|
|
343
|
+
scale: 0.97;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* ---- Scroll Edge Effect ------------------------------------------------
|
|
347
|
+
Dissolves content that scrolls beneath a glass element, maintaining
|
|
348
|
+
legibility. Apply to the scrollable container, with the glass element
|
|
349
|
+
as a sticky sibling.
|
|
350
|
+
---------------------------------------------------------------------- */
|
|
351
|
+
.b-scroll-edge {
|
|
352
|
+
--b-scroll-edge-h: 3rem;
|
|
353
|
+
position: relative;
|
|
354
|
+
}
|
|
355
|
+
.b-scroll-edge::before,
|
|
356
|
+
.b-scroll-edge::after {
|
|
357
|
+
content: "";
|
|
358
|
+
position: sticky;
|
|
359
|
+
display: block;
|
|
360
|
+
inset-inline: 0;
|
|
361
|
+
height: var(--b-scroll-edge-h);
|
|
362
|
+
pointer-events: none;
|
|
363
|
+
z-index: 1;
|
|
364
|
+
}
|
|
365
|
+
.b-scroll-edge::before {
|
|
366
|
+
top: 0;
|
|
367
|
+
background: linear-gradient(to bottom,
|
|
368
|
+
var(--b-material-chrome-bg) 0%,
|
|
369
|
+
transparent 100%);
|
|
370
|
+
-webkit-mask-image: linear-gradient(to bottom, black 0%, transparent 100%);
|
|
371
|
+
mask-image: linear-gradient(to bottom, black 0%, transparent 100%);
|
|
372
|
+
}
|
|
373
|
+
.b-scroll-edge::after {
|
|
374
|
+
bottom: 0;
|
|
375
|
+
background: linear-gradient(to top,
|
|
376
|
+
var(--b-material-chrome-bg) 0%,
|
|
377
|
+
transparent 100%);
|
|
378
|
+
-webkit-mask-image: linear-gradient(to top, black 0%, transparent 100%);
|
|
379
|
+
mask-image: linear-gradient(to top, black 0%, transparent 100%);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/* ---- Text styles (Apple type roles) ------------------------------------ */
|
|
383
|
+
.b-large-title { font-size: var(--b-text-large-title); font-weight: var(--b-weight-bold); line-height: var(--b-leading-tight); letter-spacing: var(--b-tracking-tight); }
|
|
384
|
+
.b-title1 { font-size: var(--b-text-title1); font-weight: var(--b-weight-bold); line-height: var(--b-leading-tight); letter-spacing: var(--b-tracking-tight); }
|
|
385
|
+
.b-title2 { font-size: var(--b-text-title2); font-weight: var(--b-weight-semibold); line-height: var(--b-leading-tight); }
|
|
386
|
+
.b-title3 { font-size: var(--b-text-title3); font-weight: var(--b-weight-semibold); line-height: var(--b-leading-snug); }
|
|
387
|
+
/* Each role states its own leading and tracking: inheriting them from body
|
|
388
|
+
gave a 12px caption the metrics tuned for 17px reading text. */
|
|
389
|
+
.b-headline { font-size: var(--b-text-headline); font-weight: var(--b-weight-semibold); line-height: var(--b-leading-snug); letter-spacing: var(--b-tracking-text); }
|
|
390
|
+
.b-body { font-size: var(--b-text-body); line-height: var(--b-leading-body); letter-spacing: var(--b-tracking-text); }
|
|
391
|
+
.b-callout { font-size: var(--b-text-callout); line-height: var(--b-leading-body); letter-spacing: var(--b-tracking-text); }
|
|
392
|
+
.b-subheadline { font-size: var(--b-text-subheadline); line-height: var(--b-leading-body); letter-spacing: 0; }
|
|
393
|
+
.b-footnote { font-size: var(--b-text-footnote); line-height: var(--b-leading-snug); letter-spacing: var(--b-tracking-small); }
|
|
394
|
+
.b-caption { font-size: var(--b-text-caption); line-height: var(--b-leading-snug); letter-spacing: var(--b-tracking-small); }
|
|
395
|
+
.b-caption2 { font-size: var(--b-text-caption2); line-height: var(--b-leading-snug); letter-spacing: var(--b-tracking-small); }
|
|
396
|
+
.b-overline { font-size: var(--b-text-caption); font-weight: var(--b-weight-semibold);
|
|
397
|
+
text-transform: uppercase; letter-spacing: var(--b-tracking-wide); color: var(--b-text-secondary); }
|
|
398
|
+
|
|
399
|
+
.b-text-secondary { color: var(--b-text-secondary); }
|
|
400
|
+
.b-text-tertiary { color: var(--b-text-tertiary); }
|
|
401
|
+
.b-text-accent { color: var(--b-color-accent-text); }
|
|
402
|
+
.b-text-success { color: var(--b-color-success); }
|
|
403
|
+
.b-text-warning { color: var(--b-color-warning); }
|
|
404
|
+
.b-text-danger { color: var(--b-color-danger); }
|
|
405
|
+
.b-text-start { text-align: start; }
|
|
406
|
+
.b-text-center { text-align: center; }
|
|
407
|
+
.b-text-end { text-align: end; }
|
|
408
|
+
/* Case as its own concern: .b-overline bundles case with colour and tracking,
|
|
409
|
+
which is right for a label and wrong for everything else. */
|
|
410
|
+
.b-text-uppercase { text-transform: uppercase; }
|
|
411
|
+
.b-text-lowercase { text-transform: lowercase; }
|
|
412
|
+
.b-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
413
|
+
.b-line-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
414
|
+
.b-line-clamp-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
|
|
415
|
+
.b-tabular-nums { font-variant-numeric: tabular-nums; }
|
|
416
|
+
|
|
417
|
+
/* Icons — inline 20×20 SVGs from the icon library (docs/icons.html) */
|
|
418
|
+
.b-icon { width: 1.25rem; height: 1.25rem; flex: none; }
|
|
419
|
+
.b-icon--sm { width: 1rem; height: 1rem; }
|
|
420
|
+
.b-icon--lg { width: 1.75rem; height: 1.75rem; }
|
|
421
|
+
|
|
422
|
+
/* ---- Elevation / radius / misc helpers --------------------------------- */
|
|
423
|
+
.b-elevation-0 { box-shadow: var(--b-elevation-0); }
|
|
424
|
+
.b-elevation-1 { box-shadow: var(--b-elevation-1); }
|
|
425
|
+
.b-elevation-2 { box-shadow: var(--b-elevation-2); }
|
|
426
|
+
.b-elevation-3 { box-shadow: var(--b-elevation-3); }
|
|
427
|
+
.b-elevation-4 { box-shadow: var(--b-elevation-4); }
|
|
428
|
+
.b-elevation-5 { box-shadow: var(--b-elevation-5); }
|
|
429
|
+
.b-radius-md { border-radius: var(--b-radius-md); }
|
|
430
|
+
.b-radius-lg { border-radius: var(--b-radius-lg); }
|
|
431
|
+
.b-radius-xl { border-radius: var(--b-radius-xl); }
|
|
432
|
+
.b-radius-full { border-radius: var(--b-radius-full); }
|
|
433
|
+
.b-hidden { display: none !important; }
|
|
434
|
+
.b-relative { position: relative; }
|
|
435
|
+
|
|
436
|
+
/* ---- Container queries (SwiftUI ViewThatFits) ---------------------------
|
|
437
|
+
Mark a wrapper .b-cq; children opt into visibility by the CONTAINER's
|
|
438
|
+
width, not the viewport's. sm ≥24rem, md ≥40rem, lg ≥56rem.
|
|
439
|
+
--------------------------------------------------------------------------- */
|
|
440
|
+
.b-cq { container-type: inline-size; }
|
|
441
|
+
.b-cq-show-sm, .b-cq-show-md, .b-cq-show-lg { display: none; }
|
|
442
|
+
@container (min-width: 24rem) {
|
|
443
|
+
.b-cq-show-sm { display: revert; }
|
|
444
|
+
.b-cq-hide-sm { display: none; }
|
|
445
|
+
}
|
|
446
|
+
@container (min-width: 40rem) {
|
|
447
|
+
.b-cq-show-md { display: revert; }
|
|
448
|
+
.b-cq-hide-md { display: none; }
|
|
449
|
+
}
|
|
450
|
+
@container (min-width: 56rem) {
|
|
451
|
+
.b-cq-show-lg { display: revert; }
|
|
452
|
+
.b-cq-hide-lg { display: none; }
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/* ---- Redacted (SwiftUI .redacted(reason: .placeholder)) ------------------ */
|
|
456
|
+
.b-redacted, .b-redacted * { color: transparent !important; }
|
|
457
|
+
.b-redacted {
|
|
458
|
+
position: relative;
|
|
459
|
+
pointer-events: none;
|
|
460
|
+
user-select: none;
|
|
461
|
+
}
|
|
462
|
+
.b-redacted img, .b-redacted svg, .b-redacted video { visibility: hidden; }
|
|
463
|
+
.b-redacted::after {
|
|
464
|
+
content: "";
|
|
465
|
+
position: absolute;
|
|
466
|
+
inset: 0;
|
|
467
|
+
border-radius: var(--b-radius-sm);
|
|
468
|
+
background: var(--b-fill-tertiary);
|
|
469
|
+
animation: b-pulse 1.6s var(--b-ease-standard) infinite;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/* ---- Symbol effects (SF Symbols bounce / pulse) -------------------------- */
|
|
473
|
+
.b-icon--bounce svg, .b-icon--bounce { animation: b-icon-bounce 0.5s var(--b-ease-bounce); }
|
|
474
|
+
.b-icon--pulse svg, .b-icon--pulse { animation: b-pulse 1.6s var(--b-ease-standard) infinite; }
|
|
475
|
+
@keyframes b-icon-bounce {
|
|
476
|
+
30% { translate: 0 -3px; scale: 1.15; }
|
|
477
|
+
60% { translate: 0 1px; scale: 0.96; }
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/* ---- Safe area (mobile) ------------------------------------------------ */
|
|
481
|
+
.b-safe-area {
|
|
482
|
+
padding-top: env(safe-area-inset-top);
|
|
483
|
+
padding-bottom: env(safe-area-inset-bottom);
|
|
484
|
+
padding-left: env(safe-area-inset-left);
|
|
485
|
+
padding-right: env(safe-area-inset-right);
|
|
486
|
+
}
|
|
487
|
+
.b-safe-bottom { padding-bottom: max(var(--b-space-3), env(safe-area-inset-bottom)); }
|
|
488
|
+
|
|
489
|
+
/* ---- Touch target ------------------------------------------------------ */
|
|
490
|
+
.b-touch-target { position: relative; }
|
|
491
|
+
.b-touch-target::after {
|
|
492
|
+
content: "";
|
|
493
|
+
position: absolute;
|
|
494
|
+
inset: 50% auto auto 50%;
|
|
495
|
+
translate: -50% -50%;
|
|
496
|
+
width: max(100%, var(--b-touch-target));
|
|
497
|
+
height: max(100%, var(--b-touch-target));
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/* ---- Responsive visibility --------------------------------------------- */
|
|
501
|
+
@media (max-width: 767px) {
|
|
502
|
+
.b-hide-mobile { display: none !important; }
|
|
503
|
+
}
|
|
504
|
+
@media (min-width: 768px) {
|
|
505
|
+
.b-hide-desktop { display: none !important; }
|
|
506
|
+
}
|
|
507
|
+
}
|