@lilydesignsystem/themes 0.1.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/LICENSE.md +64 -0
- package/dist/abyss.css +3174 -0
- package/dist/acid.css +3174 -0
- package/dist/adobe-spectrum.css +3174 -0
- package/dist/aqua.css +3174 -0
- package/dist/autumn.css +3174 -0
- package/dist/black.css +3174 -0
- package/dist/bumblebee.css +3174 -0
- package/dist/business.css +3174 -0
- package/dist/caramellatte.css +3174 -0
- package/dist/cmyk.css +3174 -0
- package/dist/coffee.css +3174 -0
- package/dist/corporate.css +3174 -0
- package/dist/cupcake.css +3174 -0
- package/dist/cyberpunk.css +3174 -0
- package/dist/dark.css +3175 -0
- package/dist/dim.css +3174 -0
- package/dist/dracula.css +3174 -0
- package/dist/emerald.css +3174 -0
- package/dist/fantasy.css +3174 -0
- package/dist/forest.css +3174 -0
- package/dist/garden.css +3174 -0
- package/dist/halloween.css +3174 -0
- package/dist/lemonade.css +3174 -0
- package/dist/light.css +3174 -0
- package/dist/lofi.css +3174 -0
- package/dist/luxury.css +3174 -0
- package/dist/mozilla-protocol.css +3174 -0
- package/dist/night.css +3174 -0
- package/dist/nord.css +3174 -0
- package/dist/pastel.css +3174 -0
- package/dist/retro.css +3174 -0
- package/dist/silk.css +3174 -0
- package/dist/sunset.css +3174 -0
- package/dist/synthwave.css +3174 -0
- package/dist/united-kingdom-government-digital-service.css +3179 -0
- package/dist/united-kingdom-national-health-service-england-for-patients.css +3215 -0
- package/dist/united-kingdom-national-health-service-england-for-practitioners.css +3308 -0
- package/dist/united-kingdom-national-health-service-scotland-for-patients.css +3318 -0
- package/dist/united-kingdom-national-health-service-scotland-for-practitioners.css +3404 -0
- package/dist/united-kingdom-national-health-service-wales-for-patients.css +4211 -0
- package/dist/united-kingdom-national-health-service-wales-for-practitioners.css +4387 -0
- package/dist/united-states-web-design-system.css +3175 -0
- package/dist/valentine.css +3175 -0
- package/dist/winter.css +3175 -0
- package/dist/wireframe.css +3175 -0
- package/index.md +95 -0
- package/package.json +43 -0
|
@@ -0,0 +1,3174 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Lily theme: business
|
|
3
|
+
*
|
|
4
|
+
* Standalone Lily Design System theme — declares the theme tokens and inlines
|
|
5
|
+
* the component CSS for all 492 Lily components, so this single file is the
|
|
6
|
+
* only stylesheet required to render a Lily-styled page.
|
|
7
|
+
*
|
|
8
|
+
* Credit for the theme source: DaisyUI (https://daisyui.com/)
|
|
9
|
+
*
|
|
10
|
+
* Upstream tracked: DaisyUI v5-era theme palette, adapted to Lily tokens and hooks.
|
|
11
|
+
* ========================================================================= */
|
|
12
|
+
|
|
13
|
+
/* Theme tokens — the colour, radius, border, and depth variables consumed
|
|
14
|
+
* by every Lily component rule below. The theme applies by default (`:root`)
|
|
15
|
+
* and also when explicitly opted into via `<html data-theme="business">`,
|
|
16
|
+
* so multiple themes can coexist in one document and be switched at runtime
|
|
17
|
+
* by updating the `data-theme` attribute. */
|
|
18
|
+
|
|
19
|
+
:where(:root, :root[data-theme="business"]) {
|
|
20
|
+
color-scheme: dark;
|
|
21
|
+
|
|
22
|
+
/* Page-level surface (primary canvas). Sits behind body copy
|
|
23
|
+
and primary content areas. Lightest base shade in light
|
|
24
|
+
themes, deepest in dark themes. */
|
|
25
|
+
--color-base-100: oklch(24.35% 0 0);
|
|
26
|
+
/* Secondary surface — section panels, card backgrounds,
|
|
27
|
+
sidebars, table-header fills. One step away from the page
|
|
28
|
+
surface. */
|
|
29
|
+
--color-base-200: oklch(22.65% 0 0);
|
|
30
|
+
/* Tertiary surface — dividers, sunken wells, hover-row
|
|
31
|
+
backgrounds. The most muted of the three base shades. */
|
|
32
|
+
--color-base-300: oklch(20.94% 0 0);
|
|
33
|
+
/* Primary text colour. High-contrast against base-100 to meet
|
|
34
|
+
WCAG contrast ratios for body copy. */
|
|
35
|
+
--color-base-content: oklch(84.87% 0 0);
|
|
36
|
+
/* Primary brand / action colour. Used on primary buttons,
|
|
37
|
+
active navigation items, selected states, and the focus
|
|
38
|
+
ring. */
|
|
39
|
+
--color-primary: oklch(41.7% 0.099 251.473);
|
|
40
|
+
/* Foreground colour used over `--color-primary` fills (so
|
|
41
|
+
primary buttons retain a guaranteed contrast ratio). */
|
|
42
|
+
--color-primary-content: oklch(88.34% 0.019 251.473);
|
|
43
|
+
/* Secondary brand colour. Pressed/hover state for primary
|
|
44
|
+
buttons and visited links; also drives the secondary chrome
|
|
45
|
+
family. */
|
|
46
|
+
--color-secondary: oklch(64.09% 0.027 229.389);
|
|
47
|
+
/* Foreground colour used over `--color-secondary` fills. */
|
|
48
|
+
--color-secondary-content: oklch(12.82% 0.005 229.389);
|
|
49
|
+
/* Accent colour — used sparingly for emphasis, the AI label,
|
|
50
|
+
illustrations, and tertiary call-outs. */
|
|
51
|
+
--color-accent: oklch(67.27% 0.167 35.791);
|
|
52
|
+
/* Foreground colour used over `--color-accent` fills. */
|
|
53
|
+
--color-accent-content: oklch(13.45% 0.033 35.791);
|
|
54
|
+
/* Neutral chrome surface — footer bars, code blocks,
|
|
55
|
+
tooltips, government-banner strips. Typically the theme's
|
|
56
|
+
darkest neutral. */
|
|
57
|
+
--color-neutral: oklch(27.44% 0.013 253.041);
|
|
58
|
+
/* Foreground colour used over `--color-neutral` fills. */
|
|
59
|
+
--color-neutral-content: oklch(85.49% 0.002 253.041);
|
|
60
|
+
/* Informational status colour — informational banners, links,
|
|
61
|
+
'did-you-know' callouts. */
|
|
62
|
+
--color-info: oklch(62.62% 0.143 240.033);
|
|
63
|
+
/* Foreground colour used over `--color-info` fills. */
|
|
64
|
+
--color-info-content: oklch(12.52% 0.028 240.033);
|
|
65
|
+
/* Success / confirmation colour — used on success panels,
|
|
66
|
+
completed step indicators, validation pass states, and the
|
|
67
|
+
green RAG status. */
|
|
68
|
+
--color-success: oklch(70.23% 0.094 156.596);
|
|
69
|
+
/* Foreground colour used over `--color-success` fills. */
|
|
70
|
+
--color-success-content: oklch(14.04% 0.018 156.596);
|
|
71
|
+
/* Warning colour — yellow/amber band; used on phase banners,
|
|
72
|
+
in-progress states, validation warnings, and the amber RAG
|
|
73
|
+
status. */
|
|
74
|
+
--color-warning: oklch(77.48% 0.115 81.519);
|
|
75
|
+
/* Foreground colour used over `--color-warning` fills. Often
|
|
76
|
+
dark so text remains legible on a bright yellow background. */
|
|
77
|
+
--color-warning-content: oklch(15.5% 0.023 81.519);
|
|
78
|
+
/* Error / destructive colour — used on alert dialogs, error
|
|
79
|
+
messages, validation failures, urgent care cards, and the
|
|
80
|
+
red RAG status. */
|
|
81
|
+
--color-error: oklch(51.61% 0.146 29.674);
|
|
82
|
+
/* Foreground colour used over `--color-error` fills. */
|
|
83
|
+
--color-error-content: oklch(90.32% 0.029 29.674);
|
|
84
|
+
/* Smallest corner radius. Applied to chips, badges, switches,
|
|
85
|
+
and radio/checkbox containers (mapped to `--lily-radius-
|
|
86
|
+
sm`). */
|
|
87
|
+
--radius-selector: 0rem;
|
|
88
|
+
/* Medium corner radius. Applied to inputs, buttons, menu
|
|
89
|
+
items, tooltips, and most everyday form controls (mapped to
|
|
90
|
+
`--lily-radius-md`). */
|
|
91
|
+
--radius-field: 0.25rem;
|
|
92
|
+
/* Largest corner radius. Applied to cards, dialogs, drawers,
|
|
93
|
+
and hero blocks (mapped to `--lily-radius-lg`). */
|
|
94
|
+
--radius-box: 0.25rem;
|
|
95
|
+
/* Base size for selector-style controls (checkbox/radio glyph
|
|
96
|
+
size, switch thumb diameter). Currently unused by Lily's
|
|
97
|
+
baseline component rules but available for theme
|
|
98
|
+
extensions. */
|
|
99
|
+
--size-selector: 0.25rem;
|
|
100
|
+
/* Base size for field-style controls (input height
|
|
101
|
+
multiplier). Currently unused by Lily's baseline component
|
|
102
|
+
rules but available for theme extensions. */
|
|
103
|
+
--size-field: 0.25rem;
|
|
104
|
+
/* Default border width applied to inputs, buttons, dividers,
|
|
105
|
+
table cells, etc. Single source of truth for the system's
|
|
106
|
+
stroke weight. */
|
|
107
|
+
--border: 1px;
|
|
108
|
+
/* Depth flag (0 or 1). Lily's baseline rules read it
|
|
109
|
+
implicitly via the shadow tokens; a depth-0 theme
|
|
110
|
+
effectively renders flat. */
|
|
111
|
+
--depth: 0;
|
|
112
|
+
/* Noise flag (0 or 1). Reserved for theme extensions that
|
|
113
|
+
want to layer a subtle texture; the baseline rules do not
|
|
114
|
+
consume it. */
|
|
115
|
+
--noise: 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* ----------------------------------------------------------------------------
|
|
119
|
+
* Lily component styling — applied automatically once this theme stylesheet
|
|
120
|
+
* is loaded. Every Lily class hook (492 components) consumes the theme tokens
|
|
121
|
+
* declared above, so no other stylesheet is required for the theme to render.
|
|
122
|
+
*
|
|
123
|
+
* Rules live in @layer lily with :where() selectors so the specificity stays
|
|
124
|
+
* at 0 — application CSS always wins. To replace a Lily component's default
|
|
125
|
+
* look, declare a higher-specificity rule (or a later @layer) in your own
|
|
126
|
+
* stylesheet.
|
|
127
|
+
* -------------------------------------------------------------------------- */
|
|
128
|
+
|
|
129
|
+
@layer lily {
|
|
130
|
+
/* ==========================================================================
|
|
131
|
+
* Tokens & primitives
|
|
132
|
+
* --------------------------------------------------------------------------
|
|
133
|
+
* Lily exposes a small, stable set of derived tokens (the `--lily-*`
|
|
134
|
+
* family) layered on top of the upstream theme primitives (the
|
|
135
|
+
* `--color-*`, `--radius-*`, `--border`, `--depth`, `--noise` family).
|
|
136
|
+
*
|
|
137
|
+
* Component rules consume only the `--lily-*` tokens. That indirection
|
|
138
|
+
* means a consumer can swap upstream themes (or invent a new one) without
|
|
139
|
+
* touching component CSS — the component rules below remain stable
|
|
140
|
+
* because their inputs do.
|
|
141
|
+
* ====================================================================== */
|
|
142
|
+
|
|
143
|
+
:where(:root) {
|
|
144
|
+
/* --- Surfaces ------------------------------------------------------ */
|
|
145
|
+
/* Default page surface — the canvas behind body copy. */
|
|
146
|
+
--lily-surface: var(--color-base-100);
|
|
147
|
+
/* Secondary surface — section panels, sidebars, table headers,
|
|
148
|
+
muted callouts. One step away from the page background. */
|
|
149
|
+
--lily-surface-alt: var(--color-base-200);
|
|
150
|
+
/* Sunken surface — used behind progress tracks, skeletons, and
|
|
151
|
+
inset wells. Suggests depth without requiring a shadow. */
|
|
152
|
+
--lily-surface-sunken: var(--color-base-300);
|
|
153
|
+
|
|
154
|
+
/* --- Text ---------------------------------------------------------- */
|
|
155
|
+
/* Primary body-copy colour. Maps to the theme's high-contrast
|
|
156
|
+
reading colour. */
|
|
157
|
+
--lily-text: var(--color-base-content);
|
|
158
|
+
/* Muted / secondary text — mixed 70% with transparent to keep the
|
|
159
|
+
hue but lower contrast for captions, helptext, placeholders. */
|
|
160
|
+
--lily-text-muted: color-mix(
|
|
161
|
+
in oklch,
|
|
162
|
+
var(--color-base-content) 70%,
|
|
163
|
+
transparent
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
/* --- Borders ------------------------------------------------------- */
|
|
167
|
+
/* Default border — 20% blend with body content colour, low-contrast,
|
|
168
|
+
used for subtle dividers between content blocks. */
|
|
169
|
+
--lily-border: color-mix(
|
|
170
|
+
in oklch,
|
|
171
|
+
var(--color-base-content) 20%,
|
|
172
|
+
transparent
|
|
173
|
+
);
|
|
174
|
+
/* Higher-contrast border — 40% blend, used on inputs, buttons, and
|
|
175
|
+
anywhere a clear edge is required (WCAG non-text contrast). */
|
|
176
|
+
--lily-border-strong: color-mix(
|
|
177
|
+
in oklch,
|
|
178
|
+
var(--color-base-content) 40%,
|
|
179
|
+
transparent
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
/* --- Focus ring ---------------------------------------------------- */
|
|
183
|
+
/* Outline colour for `:focus-visible`. Always the primary brand
|
|
184
|
+
colour so focus is visually tied to interactive intent. */
|
|
185
|
+
--lily-focus-ring: var(--color-primary);
|
|
186
|
+
|
|
187
|
+
/* --- Radii --------------------------------------------------------- */
|
|
188
|
+
/* Three tiers of corner rounding. `sm` for chips/badges,
|
|
189
|
+
`md` for inputs/buttons/cards, `lg` for dialogs/heroes. */
|
|
190
|
+
--lily-radius-sm: var(--radius-selector);
|
|
191
|
+
--lily-radius-md: var(--radius-field);
|
|
192
|
+
--lily-radius-lg: var(--radius-box);
|
|
193
|
+
|
|
194
|
+
/* --- Spacing scale ------------------------------------------------- */
|
|
195
|
+
/* Five-step spacing scale used by every gap, padding, and margin.
|
|
196
|
+
Linear progression keeps rhythm consistent at any zoom level. */
|
|
197
|
+
--lily-space-xs: 0.25rem;
|
|
198
|
+
--lily-space-sm: 0.5rem;
|
|
199
|
+
--lily-space-md: 1rem;
|
|
200
|
+
--lily-space-lg: 1.5rem;
|
|
201
|
+
--lily-space-xl: 2rem;
|
|
202
|
+
|
|
203
|
+
/* --- Typography ---------------------------------------------------- */
|
|
204
|
+
/* Body font stack — system fonts first so consumers get a
|
|
205
|
+
native-feeling baseline without shipping a web font. */
|
|
206
|
+
--lily-font-body:
|
|
207
|
+
system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
|
|
208
|
+
Arial, sans-serif;
|
|
209
|
+
/* Monospaced font stack — used by code, kbd, identifiers, and
|
|
210
|
+
anywhere alignment matters more than reading speed. */
|
|
211
|
+
--lily-font-mono:
|
|
212
|
+
ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
|
|
213
|
+
"Liberation Mono", monospace;
|
|
214
|
+
|
|
215
|
+
/* --- Shadows ------------------------------------------------------- */
|
|
216
|
+
/* Three depth tiers. The shadow colour is derived from the body
|
|
217
|
+
content token so it adapts to light/dark themes automatically. */
|
|
218
|
+
--lily-shadow-sm: 0 1px 2px
|
|
219
|
+
color-mix(in oklch, var(--color-base-content) 8%, transparent);
|
|
220
|
+
--lily-shadow-md: 0 4px 12px
|
|
221
|
+
color-mix(in oklch, var(--color-base-content) 12%, transparent);
|
|
222
|
+
--lily-shadow-lg: 0 12px 32px
|
|
223
|
+
color-mix(in oklch, var(--color-base-content) 16%, transparent);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/* Focus ring — every interactive Lily class hook gets the same visible
|
|
227
|
+
focus indicator. Centralising the selector means a consumer can
|
|
228
|
+
restyle every focus state at once by overriding `--lily-focus-ring`
|
|
229
|
+
(or this rule) rather than chasing 100+ component selectors. */
|
|
230
|
+
:where(
|
|
231
|
+
[class$="-input"],
|
|
232
|
+
[class$="-button"],
|
|
233
|
+
[class$="-link"],
|
|
234
|
+
[class$="-list-item"],
|
|
235
|
+
[class$="-option"],
|
|
236
|
+
[class$="-picker-button"],
|
|
237
|
+
.button,
|
|
238
|
+
.input,
|
|
239
|
+
.select,
|
|
240
|
+
.option,
|
|
241
|
+
.menu-item,
|
|
242
|
+
.tab-bar-button,
|
|
243
|
+
.switch-button,
|
|
244
|
+
.toggle-button,
|
|
245
|
+
.checkbox-input,
|
|
246
|
+
.radio-input,
|
|
247
|
+
.file-upload,
|
|
248
|
+
.signature-pad,
|
|
249
|
+
.editable
|
|
250
|
+
):focus-visible {
|
|
251
|
+
outline: 2px solid var(--lily-focus-ring);
|
|
252
|
+
outline-offset: 2px;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* ==========================================================================
|
|
256
|
+
* Inputs
|
|
257
|
+
* --------------------------------------------------------------------------
|
|
258
|
+
* Every Lily class ending in `-input` (textual, date, picker, range, file,
|
|
259
|
+
* national-identifier, etc.) shares the same baseline styling. The
|
|
260
|
+
* `[class$="-input"]` attribute selector catches single-class usage
|
|
261
|
+
* (`class="email-input"`); consumers needing multi-class composition can
|
|
262
|
+
* override with higher-specificity rules in their own stylesheet.
|
|
263
|
+
*
|
|
264
|
+
* The `:not([class$="-with-mask-input"])` exclusion exists because the
|
|
265
|
+
* masked-input variant carries its own typography (monospaced + letter
|
|
266
|
+
* spacing) and we don't want the generic baseline overriding it.
|
|
267
|
+
* Hidden inputs (`type="hidden"`) are also excluded — they must not be
|
|
268
|
+
* laid out as visible inputs.
|
|
269
|
+
* ====================================================================== */
|
|
270
|
+
|
|
271
|
+
/* Baseline visual treatment for every textual input. */
|
|
272
|
+
:where(
|
|
273
|
+
[class$="-input"]:not([class$="-with-mask-input"]):not([type="hidden"]),
|
|
274
|
+
.input
|
|
275
|
+
) {
|
|
276
|
+
appearance: none; /* drop UA native chrome (Safari especially) */
|
|
277
|
+
display: inline-block;
|
|
278
|
+
width: 100%; /* fill parent by default; consumer caps via container */
|
|
279
|
+
max-width: 100%;
|
|
280
|
+
min-height: 2.5rem; /* WCAG 2.5.5 target-size guidance (~44px) */
|
|
281
|
+
padding: 0.5rem 0.75rem;
|
|
282
|
+
font: inherit;
|
|
283
|
+
font-family: var(--lily-font-body);
|
|
284
|
+
color: var(--lily-text);
|
|
285
|
+
background-color: var(--lily-surface);
|
|
286
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
287
|
+
border-radius: var(--lily-radius-md);
|
|
288
|
+
box-sizing: border-box;
|
|
289
|
+
/* Smooth focus/hover edge transitions — short enough to feel
|
|
290
|
+
responsive, long enough to read as intentional. */
|
|
291
|
+
transition:
|
|
292
|
+
border-color 120ms ease,
|
|
293
|
+
box-shadow 120ms ease;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* Hover affordance — switches the border to the primary brand colour so
|
|
297
|
+
users get a visual cue that the field is interactive. The `:not(:disabled)`
|
|
298
|
+
guard prevents the cue from appearing on locked-out controls. */
|
|
299
|
+
:where([class$="-input"], .input):hover:not(:disabled) {
|
|
300
|
+
border-color: var(--color-primary);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/* Disabled / aria-disabled — desaturate and shift to the muted surface so
|
|
304
|
+
the control reads as inactive without losing its layout footprint. */
|
|
305
|
+
:where([class$="-input"], .input):disabled,
|
|
306
|
+
:where([class$="-input"], .input)[aria-disabled="true"] {
|
|
307
|
+
color: var(--lily-text-muted);
|
|
308
|
+
background-color: var(--lily-surface-alt);
|
|
309
|
+
cursor: not-allowed;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/* Invalid input — red border. The `aria-invalid="true"` attribute is the
|
|
313
|
+
ARIA contract; pairing it with a colour change keeps WCAG 1.4.1
|
|
314
|
+
(no colour-only meaning) honest because the ARIA state is also there. */
|
|
315
|
+
:where([class$="-input"], .input)[aria-invalid="true"] {
|
|
316
|
+
border-color: var(--color-error);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* Placeholder — match the muted text token. `opacity: 1` overrides Firefox's
|
|
320
|
+
legacy default placeholder opacity, which would otherwise compound on
|
|
321
|
+
our already-muted colour. */
|
|
322
|
+
:where([class$="-input"], .input)::placeholder {
|
|
323
|
+
color: var(--lily-text-muted);
|
|
324
|
+
opacity: 1;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/* --- Input type-specific tweaks ----------------------------------------- */
|
|
328
|
+
|
|
329
|
+
/* Hidden inputs must never render. */
|
|
330
|
+
:where(.hidden-input) {
|
|
331
|
+
display: none;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/* Submit / reset / image / generic button inputs render as buttons. */
|
|
335
|
+
:where(.button-input, .submit-input, .reset-input, .image-input) {
|
|
336
|
+
width: auto;
|
|
337
|
+
min-width: 2.5rem;
|
|
338
|
+
background-color: var(--color-primary);
|
|
339
|
+
color: var(--color-primary-content);
|
|
340
|
+
border-color: transparent;
|
|
341
|
+
cursor: pointer;
|
|
342
|
+
font-weight: 600;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/* Reset input is the secondary-action variant — muted surface, not the
|
|
346
|
+
primary brand colour, because "reset" is a destructive op. */
|
|
347
|
+
:where(.reset-input) {
|
|
348
|
+
background-color: var(--lily-surface-alt);
|
|
349
|
+
color: var(--lily-text);
|
|
350
|
+
border-color: var(--lily-border-strong);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/* Color input — narrow swatch with internal padding so the colour chip
|
|
354
|
+
reads cleanly inside the input frame. */
|
|
355
|
+
:where(.color-input) {
|
|
356
|
+
min-height: 2.5rem;
|
|
357
|
+
padding: 0.25rem;
|
|
358
|
+
width: 3rem;
|
|
359
|
+
cursor: pointer;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/* Range / angle slider — strip the input chrome so the consumer can
|
|
363
|
+
restyle the track. `accent-color` provides a minimal styled fallback. */
|
|
364
|
+
:where(.range-input, .angle-slider-range-input) {
|
|
365
|
+
appearance: none;
|
|
366
|
+
background: transparent;
|
|
367
|
+
border: 0;
|
|
368
|
+
padding: 0;
|
|
369
|
+
height: 1.5rem;
|
|
370
|
+
accent-color: var(--color-primary);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* File inputs — slightly tighter padding because the UA-rendered
|
|
374
|
+
"Choose file" button consumes most of the visual space. */
|
|
375
|
+
:where(.file-input, .image-file-input) {
|
|
376
|
+
padding: 0.375rem 0.5rem;
|
|
377
|
+
cursor: pointer;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/* Checkbox / radio — small square/round controls with the brand accent. */
|
|
381
|
+
:where(.checkbox-input, .radio-input) {
|
|
382
|
+
width: 1.125rem;
|
|
383
|
+
height: 1.125rem;
|
|
384
|
+
min-height: 0; /* override the 2.5rem input baseline */
|
|
385
|
+
padding: 0;
|
|
386
|
+
accent-color: var(--color-primary);
|
|
387
|
+
cursor: pointer;
|
|
388
|
+
}
|
|
389
|
+
:where(.radio-input) {
|
|
390
|
+
border-radius: 50%;
|
|
391
|
+
}
|
|
392
|
+
:where(.checkbox-input) {
|
|
393
|
+
border-radius: var(--lily-radius-sm);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/* Textarea variants — taller minimum, line-height tuned for reading,
|
|
397
|
+
vertical-only resize so layout columns aren't disturbed. */
|
|
398
|
+
:where(.text-area-input, .text-area-input-with-character-counter) {
|
|
399
|
+
min-height: 6rem;
|
|
400
|
+
line-height: 1.5;
|
|
401
|
+
resize: vertical;
|
|
402
|
+
}
|
|
403
|
+
/* Character-counter variant stacks the textarea and the counter span. */
|
|
404
|
+
:where(.text-area-input-with-character-counter) {
|
|
405
|
+
display: flex;
|
|
406
|
+
flex-direction: column;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/* --- Composite inputs with built-in DOM structure ----------------------- */
|
|
410
|
+
|
|
411
|
+
/* PIN input — N small slots side-by-side. The wrapper is invisible;
|
|
412
|
+
the children carry the styling. */
|
|
413
|
+
:where(.pin-input-div) {
|
|
414
|
+
display: inline-flex;
|
|
415
|
+
gap: 0.5rem;
|
|
416
|
+
padding: 0;
|
|
417
|
+
background: transparent;
|
|
418
|
+
border: 0;
|
|
419
|
+
width: auto;
|
|
420
|
+
min-height: 0;
|
|
421
|
+
}
|
|
422
|
+
:where(.pin-input-div > input) {
|
|
423
|
+
width: 2.5rem;
|
|
424
|
+
height: 3rem;
|
|
425
|
+
padding: 0;
|
|
426
|
+
text-align: center;
|
|
427
|
+
font-size: 1.125rem;
|
|
428
|
+
font-weight: 600;
|
|
429
|
+
background-color: var(--lily-surface);
|
|
430
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
431
|
+
border-radius: var(--lily-radius-md);
|
|
432
|
+
color: var(--lily-text);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/* Password-toggle composite — text input + reveal button, sharing
|
|
436
|
+
a single visual frame via flush radii. */
|
|
437
|
+
:where(.password-input-or-text-input-div) {
|
|
438
|
+
display: inline-flex;
|
|
439
|
+
align-items: stretch;
|
|
440
|
+
width: 100%;
|
|
441
|
+
background: transparent;
|
|
442
|
+
border: 0;
|
|
443
|
+
padding: 0;
|
|
444
|
+
min-height: 0;
|
|
445
|
+
}
|
|
446
|
+
:where(.password-input-or-text-input-div > input) {
|
|
447
|
+
flex: 1;
|
|
448
|
+
min-height: 2.5rem;
|
|
449
|
+
padding: 0.5rem 0.75rem;
|
|
450
|
+
background-color: var(--lily-surface);
|
|
451
|
+
color: var(--lily-text);
|
|
452
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
453
|
+
border-right: 0; /* drop the seam where input meets button */
|
|
454
|
+
border-radius: var(--lily-radius-md) 0 0 var(--lily-radius-md);
|
|
455
|
+
}
|
|
456
|
+
:where(.password-input-or-text-input-div > button) {
|
|
457
|
+
padding: 0 0.75rem;
|
|
458
|
+
background-color: var(--lily-surface-alt);
|
|
459
|
+
color: var(--lily-text);
|
|
460
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
461
|
+
border-radius: 0 var(--lily-radius-md) var(--lily-radius-md) 0;
|
|
462
|
+
cursor: pointer;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/* --- Input compositions ------------------------------------------------- */
|
|
466
|
+
|
|
467
|
+
/* Input group — flush-joined controls (input + button, etc.). The negative
|
|
468
|
+
margin collapses overlapping borders into a single shared edge. */
|
|
469
|
+
:where(.input-group) {
|
|
470
|
+
display: inline-flex;
|
|
471
|
+
align-items: stretch;
|
|
472
|
+
width: 100%;
|
|
473
|
+
}
|
|
474
|
+
:where(.input-group > *) {
|
|
475
|
+
border-radius: 0;
|
|
476
|
+
margin-left: calc(-1 * var(--border));
|
|
477
|
+
}
|
|
478
|
+
:where(.input-group > *:first-child) {
|
|
479
|
+
border-top-left-radius: var(--lily-radius-md);
|
|
480
|
+
border-bottom-left-radius: var(--lily-radius-md);
|
|
481
|
+
margin-left: 0;
|
|
482
|
+
}
|
|
483
|
+
:where(.input-group > *:last-child) {
|
|
484
|
+
border-top-right-radius: var(--lily-radius-md);
|
|
485
|
+
border-bottom-right-radius: var(--lily-radius-md);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/* Masked input — monospaced font + slight letter-spacing so the mask
|
|
489
|
+
template (phone, SSN, etc.) aligns over the typed characters. */
|
|
490
|
+
:where(.input-with-mask) {
|
|
491
|
+
font-family: var(--lily-font-mono);
|
|
492
|
+
letter-spacing: 0.05em;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/* Search input — reserve space on the inline-start for the magnifier
|
|
496
|
+
glyph. The `linear-gradient(transparent, transparent)` is a no-op
|
|
497
|
+
background-image; it ensures the property exists so consumers can
|
|
498
|
+
layer an SVG icon over it by overriding `background-image`. */
|
|
499
|
+
:where(.text-input-with-search, .search-input) {
|
|
500
|
+
background-image: linear-gradient(transparent, transparent);
|
|
501
|
+
padding-inline-start: 2.25rem;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/* ==========================================================================
|
|
505
|
+
* Views
|
|
506
|
+
* --------------------------------------------------------------------------
|
|
507
|
+
* Read-only display chips for identifiers, dates, ratings, and other
|
|
508
|
+
* pre-formatted data. Every Lily class ending in `-view` is a span/div
|
|
509
|
+
* that renders a value the user shouldn't edit.
|
|
510
|
+
*
|
|
511
|
+
* The exclusions (`theme-view`, `split-view`)
|
|
512
|
+
* are larger containers that don't fit the chip pattern — they're
|
|
513
|
+
* styled separately further down.
|
|
514
|
+
* ====================================================================== */
|
|
515
|
+
|
|
516
|
+
:where(
|
|
517
|
+
[class$="-view"]:not(.theme-view):not(
|
|
518
|
+
.split-view
|
|
519
|
+
)
|
|
520
|
+
) {
|
|
521
|
+
display: inline-block;
|
|
522
|
+
padding: 0.125rem 0.5rem;
|
|
523
|
+
font-family: var(--lily-font-mono); /* fixed-width for alignment */
|
|
524
|
+
color: var(--lily-text);
|
|
525
|
+
background-color: var(--lily-surface-alt);
|
|
526
|
+
border: var(--border) solid var(--lily-border);
|
|
527
|
+
border-radius: var(--lily-radius-md);
|
|
528
|
+
line-height: 1.4;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/* Dates / ranges are human-readable, not codes — switch back to body font. */
|
|
532
|
+
:where(.date-time-view, .date-range, .review-date) {
|
|
533
|
+
font-family: var(--lily-font-body);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/* Theme-view — small label + colour swatch composition. */
|
|
537
|
+
:where(.theme-view) {
|
|
538
|
+
display: inline-flex;
|
|
539
|
+
align-items: center;
|
|
540
|
+
gap: 0.5rem;
|
|
541
|
+
padding: 0.25rem 0.5rem;
|
|
542
|
+
color: var(--lily-text);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/* ==========================================================================
|
|
546
|
+
* Buttons
|
|
547
|
+
* --------------------------------------------------------------------------
|
|
548
|
+
* Every class ending in `-button` and the bare `.button` share one
|
|
549
|
+
* baseline. Hamburger-menu is excluded because it's an icon-only square
|
|
550
|
+
* with its own minimal frame styling (further down).
|
|
551
|
+
* ====================================================================== */
|
|
552
|
+
|
|
553
|
+
/* Baseline button — primary-coloured pill. Variants override colour or
|
|
554
|
+
shape below. */
|
|
555
|
+
:where(.button, [class$="-button"]:not(.hamburger-menu-button)) {
|
|
556
|
+
appearance: none;
|
|
557
|
+
display: inline-flex;
|
|
558
|
+
align-items: center;
|
|
559
|
+
justify-content: center;
|
|
560
|
+
gap: 0.5rem; /* leave room for an icon + label */
|
|
561
|
+
min-height: 2.5rem; /* WCAG target-size guidance */
|
|
562
|
+
padding: 0.5rem 1rem;
|
|
563
|
+
font: inherit;
|
|
564
|
+
font-family: var(--lily-font-body);
|
|
565
|
+
font-weight: 600;
|
|
566
|
+
line-height: 1.2;
|
|
567
|
+
color: var(--color-primary-content);
|
|
568
|
+
background-color: var(--color-primary);
|
|
569
|
+
border: var(--border) solid transparent;
|
|
570
|
+
border-radius: var(--lily-radius-md);
|
|
571
|
+
cursor: pointer;
|
|
572
|
+
user-select: none; /* prevent text drag-select on double-click */
|
|
573
|
+
text-decoration: none;
|
|
574
|
+
transition:
|
|
575
|
+
background-color 120ms ease,
|
|
576
|
+
color 120ms ease,
|
|
577
|
+
border-color 120ms ease;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/* Hover — shift to the secondary token for a subtle change of state. */
|
|
581
|
+
:where(.button, [class$="-button"]):hover:not(:disabled):not(
|
|
582
|
+
[aria-disabled="true"]
|
|
583
|
+
) {
|
|
584
|
+
background-color: var(--color-secondary);
|
|
585
|
+
color: var(--color-secondary-content);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/* Disabled — half opacity, not-allowed cursor. */
|
|
589
|
+
:where(.button, [class$="-button"]):disabled,
|
|
590
|
+
:where(.button, [class$="-button"])[aria-disabled="true"] {
|
|
591
|
+
opacity: 0.5;
|
|
592
|
+
cursor: not-allowed;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/* Pressed (toggle/switch active state) — re-use the secondary colour. */
|
|
596
|
+
:where(.button, [class$="-button"])[aria-pressed="true"] {
|
|
597
|
+
background-color: var(--color-secondary);
|
|
598
|
+
color: var(--color-secondary-content);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/* --- Button variants ---------------------------------------------------- */
|
|
602
|
+
|
|
603
|
+
/* Icon button — square; aspect-ratio keeps it from squashing when the
|
|
604
|
+
icon font changes size. */
|
|
605
|
+
:where(.icon-button) {
|
|
606
|
+
padding: 0.5rem;
|
|
607
|
+
min-width: 2.5rem;
|
|
608
|
+
aspect-ratio: 1;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/* Floating action button — pinned to the bottom-right of the viewport.
|
|
612
|
+
Uses logical inset properties so it flips correctly under RTL. */
|
|
613
|
+
:where(.float-button) {
|
|
614
|
+
position: fixed;
|
|
615
|
+
inset-block-end: 1rem;
|
|
616
|
+
inset-inline-end: 1rem;
|
|
617
|
+
box-shadow: var(--lily-shadow-lg);
|
|
618
|
+
border-radius: 999px;
|
|
619
|
+
width: 3.5rem;
|
|
620
|
+
height: 3.5rem;
|
|
621
|
+
padding: 0;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/* Split button — extra padding-end for the dropdown caret. */
|
|
625
|
+
:where(.split-button) {
|
|
626
|
+
padding-inline-end: 0.5rem;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/* Download button — stacks the action label over a hint (filesize, etc.). */
|
|
630
|
+
:where(.download-button) {
|
|
631
|
+
flex-direction: column;
|
|
632
|
+
align-items: flex-start;
|
|
633
|
+
text-align: start;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/* Clipboard-copy — muted style because it's auxiliary, not primary. */
|
|
637
|
+
:where(.clipboard-copy-button) {
|
|
638
|
+
background-color: var(--lily-surface-alt);
|
|
639
|
+
color: var(--lily-text);
|
|
640
|
+
border-color: var(--lily-border-strong);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/* Switch button — iOS-style toggle pill. The track is the sunken
|
|
644
|
+
surface; the thumb is drawn by the consumer (or via ::before in
|
|
645
|
+
higher-specificity overrides). */
|
|
646
|
+
:where(.switch-button) {
|
|
647
|
+
position: relative;
|
|
648
|
+
width: 2.75rem;
|
|
649
|
+
min-width: 2.75rem;
|
|
650
|
+
height: 1.5rem;
|
|
651
|
+
min-height: 1.5rem;
|
|
652
|
+
padding: 0;
|
|
653
|
+
background-color: var(--lily-surface-sunken);
|
|
654
|
+
border-radius: 999px;
|
|
655
|
+
}
|
|
656
|
+
:where(
|
|
657
|
+
.switch-button[aria-pressed="true"],
|
|
658
|
+
.switch-button[aria-checked="true"]
|
|
659
|
+
) {
|
|
660
|
+
background-color: var(--color-primary);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/* Toggle button — when un-pressed, render as a muted secondary chip. */
|
|
664
|
+
:where(.toggle-button[aria-pressed="false"]) {
|
|
665
|
+
background-color: var(--lily-surface-alt);
|
|
666
|
+
color: var(--lily-text);
|
|
667
|
+
border-color: var(--lily-border-strong);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/* Link-style "button" — for back/skip/go-to controls that look like
|
|
671
|
+
text links but use the button machinery for keyboard semantics. */
|
|
672
|
+
:where(
|
|
673
|
+
.back-link,
|
|
674
|
+
.skip-link,
|
|
675
|
+
.go-to-top,
|
|
676
|
+
.go-to-next-section,
|
|
677
|
+
.go-to-previous-section
|
|
678
|
+
) {
|
|
679
|
+
background-color: transparent;
|
|
680
|
+
color: var(--color-primary);
|
|
681
|
+
border-color: transparent;
|
|
682
|
+
text-decoration: underline;
|
|
683
|
+
text-underline-offset: 0.2em;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/* Skip-link — visually hidden off-screen until focused, then snaps to the
|
|
687
|
+
top-left of the page. Required pattern for keyboard accessibility
|
|
688
|
+
(WCAG 2.4.1 bypass blocks). */
|
|
689
|
+
:where(.skip-link) {
|
|
690
|
+
position: absolute;
|
|
691
|
+
top: -3rem;
|
|
692
|
+
left: 0.5rem;
|
|
693
|
+
padding: 0.5rem 1rem;
|
|
694
|
+
background-color: var(--color-primary);
|
|
695
|
+
color: var(--color-primary-content);
|
|
696
|
+
text-decoration: none;
|
|
697
|
+
border-radius: var(--lily-radius-md);
|
|
698
|
+
z-index: 9999;
|
|
699
|
+
}
|
|
700
|
+
:where(.skip-link:focus) {
|
|
701
|
+
top: 0.5rem;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/* Button group — horizontal cluster of related actions. */
|
|
705
|
+
:where(.button-group) {
|
|
706
|
+
display: inline-flex;
|
|
707
|
+
gap: 0.25rem;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/* --- Bars of buttons (action / menu / tab / task / tool) ---------------- */
|
|
711
|
+
|
|
712
|
+
:where(.action-bar, .menu-bar, .tab-bar, .task-bar, .tool-bar) {
|
|
713
|
+
display: flex;
|
|
714
|
+
align-items: center;
|
|
715
|
+
gap: 0.25rem;
|
|
716
|
+
padding: 0.5rem;
|
|
717
|
+
background-color: var(--lily-surface-alt);
|
|
718
|
+
border: var(--border) solid var(--lily-border);
|
|
719
|
+
border-radius: var(--lily-radius-md);
|
|
720
|
+
}
|
|
721
|
+
/* Children of bars render flush with the bar — transparent background,
|
|
722
|
+
no border, so the bar's surface acts as the visual frame. */
|
|
723
|
+
:where(
|
|
724
|
+
.action-bar-button,
|
|
725
|
+
.menu-bar-button,
|
|
726
|
+
.tab-bar-button,
|
|
727
|
+
.task-bar-button,
|
|
728
|
+
.tool-bar-button
|
|
729
|
+
) {
|
|
730
|
+
background-color: transparent;
|
|
731
|
+
color: var(--lily-text);
|
|
732
|
+
border-color: transparent;
|
|
733
|
+
}
|
|
734
|
+
/* Selected tab — explicit primary colour. */
|
|
735
|
+
:where(.tab-bar-button[aria-selected="true"]) {
|
|
736
|
+
background-color: var(--color-primary);
|
|
737
|
+
color: var(--color-primary-content);
|
|
738
|
+
}
|
|
739
|
+
/* Panel revealed by the active tab. */
|
|
740
|
+
:where(.tab-panel) {
|
|
741
|
+
padding: 1rem;
|
|
742
|
+
background-color: var(--lily-surface);
|
|
743
|
+
border: var(--border) solid var(--lily-border);
|
|
744
|
+
border-radius: var(--lily-radius-md);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/* ==========================================================================
|
|
748
|
+
* Links, anchors, link-like
|
|
749
|
+
* --------------------------------------------------------------------------
|
|
750
|
+
* Generic `-link` styling — primary-coloured underlined text. The
|
|
751
|
+
* exclusions (`skip-link`, `back-link`) are styled as buttons above.
|
|
752
|
+
* ====================================================================== */
|
|
753
|
+
|
|
754
|
+
:where([class$="-link"]:not(.skip-link):not(.back-link)) {
|
|
755
|
+
color: var(--color-primary);
|
|
756
|
+
text-decoration: underline;
|
|
757
|
+
text-underline-offset: 0.15em;
|
|
758
|
+
}
|
|
759
|
+
/* Hover — thicker underline for a subtle affordance cue. */
|
|
760
|
+
:where([class$="-link"]):hover {
|
|
761
|
+
text-decoration-thickness: 2px;
|
|
762
|
+
}
|
|
763
|
+
/* Visited — secondary token. */
|
|
764
|
+
:where([class$="-link"]):visited {
|
|
765
|
+
color: var(--color-secondary);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/* ==========================================================================
|
|
769
|
+
* Lists & list items
|
|
770
|
+
* --------------------------------------------------------------------------
|
|
771
|
+
* Lily wraps `<ol>` / `<ul>` in role-specific classes (CheckList, DoList,
|
|
772
|
+
* etc.). The baseline kills the default browser bullet styling and zeroes
|
|
773
|
+
* margins so consumers can compose lists inside other components.
|
|
774
|
+
* ====================================================================== */
|
|
775
|
+
|
|
776
|
+
/* Baseline — kill bullets and the indent gutter on every list class. */
|
|
777
|
+
:where(
|
|
778
|
+
.accordion-list,
|
|
779
|
+
.breadcrumb-list,
|
|
780
|
+
.chat-list,
|
|
781
|
+
.check-list,
|
|
782
|
+
.collection-list,
|
|
783
|
+
.contents-list,
|
|
784
|
+
.description-list,
|
|
785
|
+
.document-list,
|
|
786
|
+
.do-list,
|
|
787
|
+
.dont-list,
|
|
788
|
+
.icon-list,
|
|
789
|
+
.pagination-list,
|
|
790
|
+
.section-list,
|
|
791
|
+
.step-list,
|
|
792
|
+
.summary-list,
|
|
793
|
+
.task-list,
|
|
794
|
+
.timeline-list,
|
|
795
|
+
.tour-list,
|
|
796
|
+
.tree-list,
|
|
797
|
+
.validation-list
|
|
798
|
+
) {
|
|
799
|
+
list-style: none;
|
|
800
|
+
margin: 0;
|
|
801
|
+
padding: 0;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/* Baseline — every list-item gets a thin hairline rule between rows. */
|
|
805
|
+
:where(
|
|
806
|
+
.accordion-list-item,
|
|
807
|
+
.breadcrumb-list-item,
|
|
808
|
+
.chat-list-item,
|
|
809
|
+
.check-list-item,
|
|
810
|
+
.collection-list-item,
|
|
811
|
+
.contents-list-item,
|
|
812
|
+
.description-list-item,
|
|
813
|
+
.document-list-item,
|
|
814
|
+
.do-list-item,
|
|
815
|
+
.dont-list-item,
|
|
816
|
+
.icon-list-item,
|
|
817
|
+
.pagination-list-item,
|
|
818
|
+
.section-list-item,
|
|
819
|
+
.step-list-item,
|
|
820
|
+
.summary-list-item,
|
|
821
|
+
.task-list-item,
|
|
822
|
+
.timeline-list-item,
|
|
823
|
+
.tour-list-item,
|
|
824
|
+
.tree-list-item,
|
|
825
|
+
.validation-list-item
|
|
826
|
+
) {
|
|
827
|
+
padding: 0.5rem 0;
|
|
828
|
+
border-bottom: var(--border) solid var(--lily-border);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/* --- Breadcrumb --------------------------------------------------------- */
|
|
832
|
+
/* Horizontal list separated by a "/" pseudo-element between items. */
|
|
833
|
+
:where(.breadcrumb-list) {
|
|
834
|
+
display: flex;
|
|
835
|
+
flex-wrap: wrap;
|
|
836
|
+
gap: 0.5rem;
|
|
837
|
+
align-items: center;
|
|
838
|
+
}
|
|
839
|
+
:where(.breadcrumb-list-item) {
|
|
840
|
+
border: 0; /* override the generic list-item bottom-border */
|
|
841
|
+
padding: 0;
|
|
842
|
+
display: inline-flex;
|
|
843
|
+
align-items: center;
|
|
844
|
+
}
|
|
845
|
+
/* Slash separator generated between adjacent items, not before the first. */
|
|
846
|
+
:where(.breadcrumb-list-item + .breadcrumb-list-item)::before {
|
|
847
|
+
content: "/";
|
|
848
|
+
margin-inline-end: 0.5rem;
|
|
849
|
+
color: var(--lily-text-muted);
|
|
850
|
+
}
|
|
851
|
+
/* Final crumb (the current page) — muted because it isn't a link. */
|
|
852
|
+
:where(.breadcrumb-list-item[aria-current="page"]) {
|
|
853
|
+
color: var(--lily-text-muted);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/* --- Pagination --------------------------------------------------------- */
|
|
857
|
+
:where(.pagination-list) {
|
|
858
|
+
display: flex;
|
|
859
|
+
flex-wrap: wrap;
|
|
860
|
+
gap: 0.25rem;
|
|
861
|
+
align-items: center;
|
|
862
|
+
}
|
|
863
|
+
:where(.pagination-list-item) {
|
|
864
|
+
border: 0;
|
|
865
|
+
padding: 0;
|
|
866
|
+
}
|
|
867
|
+
/* Pagination link — square-ish chip with a generous tap target. */
|
|
868
|
+
:where(.pagination-link) {
|
|
869
|
+
display: inline-flex;
|
|
870
|
+
align-items: center;
|
|
871
|
+
justify-content: center;
|
|
872
|
+
min-width: 2.5rem;
|
|
873
|
+
padding: 0.5rem 0.75rem;
|
|
874
|
+
border-radius: var(--lily-radius-md);
|
|
875
|
+
text-decoration: none;
|
|
876
|
+
}
|
|
877
|
+
/* Current page — filled with the primary brand colour. */
|
|
878
|
+
:where(.pagination-link[aria-current="page"]) {
|
|
879
|
+
background-color: var(--color-primary);
|
|
880
|
+
color: var(--color-primary-content);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/* --- Marker glyphs ------------------------------------------------------ */
|
|
884
|
+
/* Check / do — green ✓; dont — red ✗. The `::marker` pseudo-element
|
|
885
|
+
only works on list-items with the default list-style display, so the
|
|
886
|
+
generic baseline above intentionally kept that. */
|
|
887
|
+
:where(.check-list-item)::marker {
|
|
888
|
+
content: "✓ ";
|
|
889
|
+
color: var(--color-success);
|
|
890
|
+
}
|
|
891
|
+
:where(.do-list-item)::marker {
|
|
892
|
+
content: "✓ ";
|
|
893
|
+
color: var(--color-success);
|
|
894
|
+
}
|
|
895
|
+
:where(.dont-list-item)::marker {
|
|
896
|
+
content: "✗ ";
|
|
897
|
+
color: var(--color-error);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/* --- Tree --------------------------------------------------------------- */
|
|
901
|
+
/* Nested tree lists indent their children. */
|
|
902
|
+
:where(.tree-list .tree-list) {
|
|
903
|
+
padding-inline-start: 1.25rem;
|
|
904
|
+
}
|
|
905
|
+
:where(.tree-list-item) {
|
|
906
|
+
border: 0;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/* --- Step list ---------------------------------------------------------- */
|
|
910
|
+
/* CSS counter draws the step number in a circular badge. */
|
|
911
|
+
:where(.step-list) {
|
|
912
|
+
counter-reset: lily-step;
|
|
913
|
+
}
|
|
914
|
+
:where(.step-list-item) {
|
|
915
|
+
counter-increment: lily-step;
|
|
916
|
+
display: flex;
|
|
917
|
+
align-items: flex-start;
|
|
918
|
+
gap: 0.75rem;
|
|
919
|
+
}
|
|
920
|
+
:where(.step-list-item)::before {
|
|
921
|
+
content: counter(lily-step);
|
|
922
|
+
flex: 0 0 auto;
|
|
923
|
+
display: inline-flex;
|
|
924
|
+
align-items: center;
|
|
925
|
+
justify-content: center;
|
|
926
|
+
width: 1.75rem;
|
|
927
|
+
height: 1.75rem;
|
|
928
|
+
border-radius: 50%;
|
|
929
|
+
background-color: var(--lily-surface-sunken);
|
|
930
|
+
color: var(--lily-text);
|
|
931
|
+
font-weight: 600;
|
|
932
|
+
}
|
|
933
|
+
/* Step status variants — colour-coded badge fill. */
|
|
934
|
+
:where(.step-list-item[data-status="finished"])::before {
|
|
935
|
+
background-color: var(--color-success);
|
|
936
|
+
color: var(--color-success-content);
|
|
937
|
+
}
|
|
938
|
+
:where(.step-list-item[data-status="in-progress"])::before {
|
|
939
|
+
background-color: var(--color-primary);
|
|
940
|
+
color: var(--color-primary-content);
|
|
941
|
+
}
|
|
942
|
+
:where(.step-list-item[data-status="error"])::before {
|
|
943
|
+
background-color: var(--color-error);
|
|
944
|
+
color: var(--color-error-content);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/* --- Task list ---------------------------------------------------------- */
|
|
948
|
+
/* Flex row so the checkbox aligns with its label. */
|
|
949
|
+
:where(.task-list-item) {
|
|
950
|
+
display: flex;
|
|
951
|
+
align-items: center;
|
|
952
|
+
gap: 0.5rem;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/* --- Timeline ----------------------------------------------------------- */
|
|
956
|
+
/* Vertical rule down the left, with a dot per event. */
|
|
957
|
+
:where(.timeline-list-item) {
|
|
958
|
+
position: relative;
|
|
959
|
+
padding-inline-start: 1.5rem;
|
|
960
|
+
border-left: var(--border) solid var(--lily-border-strong);
|
|
961
|
+
margin-inline-start: 0.5rem;
|
|
962
|
+
}
|
|
963
|
+
:where(.timeline-list-item)::before {
|
|
964
|
+
content: "";
|
|
965
|
+
position: absolute;
|
|
966
|
+
inset-inline-start: -0.4rem;
|
|
967
|
+
inset-block-start: 0.65rem;
|
|
968
|
+
width: 0.7rem;
|
|
969
|
+
height: 0.7rem;
|
|
970
|
+
border-radius: 50%;
|
|
971
|
+
background-color: var(--color-primary);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/* --- Validation list — pass / fail / pending status colours ------------ */
|
|
975
|
+
:where(.validation-list-item[data-status="passed"]) {
|
|
976
|
+
color: var(--color-success);
|
|
977
|
+
}
|
|
978
|
+
:where(.validation-list-item[data-status="failed"]) {
|
|
979
|
+
color: var(--color-error);
|
|
980
|
+
}
|
|
981
|
+
:where(.validation-list-item[data-status="pending"]) {
|
|
982
|
+
color: var(--lily-text-muted);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/* --- Description list (semantic <dl>) ----------------------------------- */
|
|
986
|
+
/* Two-column grid: term in the left column, description in the right. */
|
|
987
|
+
:where(.description-list) {
|
|
988
|
+
display: grid;
|
|
989
|
+
grid-template-columns: minmax(min-content, max-content) 1fr;
|
|
990
|
+
column-gap: 1rem;
|
|
991
|
+
row-gap: 0.5rem;
|
|
992
|
+
}
|
|
993
|
+
/* `display: contents` lets the dt/dd children participate directly in
|
|
994
|
+
the parent grid without an intermediate row wrapper. */
|
|
995
|
+
:where(.description-list-item) {
|
|
996
|
+
display: contents;
|
|
997
|
+
border: 0;
|
|
998
|
+
}
|
|
999
|
+
:where(.description-list dt) {
|
|
1000
|
+
font-weight: 600;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/* --- Summary list (three-column key/value/action grid) ------------------ */
|
|
1004
|
+
:where(.summary-list) {
|
|
1005
|
+
display: grid;
|
|
1006
|
+
grid-template-columns: minmax(0, max-content) 1fr auto;
|
|
1007
|
+
column-gap: 1rem;
|
|
1008
|
+
row-gap: 0.5rem;
|
|
1009
|
+
}
|
|
1010
|
+
:where(.summary-list-item) {
|
|
1011
|
+
display: contents;
|
|
1012
|
+
border: 0;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
/* --- Icon / collection / document lists — flex rows with leading icon -- */
|
|
1016
|
+
:where(.icon-list-item, .collection-list-item, .document-list-item) {
|
|
1017
|
+
display: flex;
|
|
1018
|
+
align-items: flex-start;
|
|
1019
|
+
gap: 0.75rem;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
/* --- Navs --------------------------------------------------------------- */
|
|
1023
|
+
/* Nav wrappers are layout-neutral by default — the inner list handles
|
|
1024
|
+
layout, the nav just provides the landmark semantics. */
|
|
1025
|
+
:where(
|
|
1026
|
+
.accordion-nav,
|
|
1027
|
+
.breadcrumb-nav,
|
|
1028
|
+
.chat-nav,
|
|
1029
|
+
.contents-nav,
|
|
1030
|
+
.pagination-nav,
|
|
1031
|
+
.section-nav,
|
|
1032
|
+
.tree-nav,
|
|
1033
|
+
.navigation-menu
|
|
1034
|
+
) {
|
|
1035
|
+
display: block;
|
|
1036
|
+
padding: 0;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
/* ==========================================================================
|
|
1040
|
+
* Tables (plain, data, calendar, kanban, gantt)
|
|
1041
|
+
* --------------------------------------------------------------------------
|
|
1042
|
+
* Every Lily table variant shares the same baseline: full-width, collapsed
|
|
1043
|
+
* borders, body font. Variants override below for specialised behaviour
|
|
1044
|
+
* (kanban columns, gantt bars, calendar selection).
|
|
1045
|
+
* ====================================================================== */
|
|
1046
|
+
|
|
1047
|
+
:where(.table, .data-table, .calendar-table, .kanban-table, .gantt-table) {
|
|
1048
|
+
width: 100%;
|
|
1049
|
+
border-collapse: collapse; /* shared edges between cells */
|
|
1050
|
+
background-color: var(--lily-surface);
|
|
1051
|
+
color: var(--lily-text);
|
|
1052
|
+
font-family: var(--lily-font-body);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/* Thead gets the alt surface so it visually anchors above the body. */
|
|
1056
|
+
:where(
|
|
1057
|
+
.table-head,
|
|
1058
|
+
.data-table-head,
|
|
1059
|
+
.calendar-table-head,
|
|
1060
|
+
.kanban-table-head,
|
|
1061
|
+
.gantt-table-thead
|
|
1062
|
+
) {
|
|
1063
|
+
background-color: var(--lily-surface-alt);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
/* Header cells — bold, slightly tighter padding, with a 2px under-rule. */
|
|
1067
|
+
:where(
|
|
1068
|
+
.table-th,
|
|
1069
|
+
.data-table-th,
|
|
1070
|
+
.calendar-table-th,
|
|
1071
|
+
.kanban-table-th,
|
|
1072
|
+
.gantt-table-th
|
|
1073
|
+
) {
|
|
1074
|
+
padding: 0.625rem 0.75rem;
|
|
1075
|
+
text-align: start;
|
|
1076
|
+
font-weight: 600;
|
|
1077
|
+
border-bottom: 2px solid var(--lily-border-strong);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
/* Body cells — top-aligned (multi-line content reads better when the
|
|
1081
|
+
baseline is at the top, not centred). */
|
|
1082
|
+
:where(
|
|
1083
|
+
.table-td,
|
|
1084
|
+
.data-table-td,
|
|
1085
|
+
.calendar-table-td,
|
|
1086
|
+
.kanban-table-td,
|
|
1087
|
+
.gantt-table-td
|
|
1088
|
+
) {
|
|
1089
|
+
padding: 0.625rem 0.75rem;
|
|
1090
|
+
border-bottom: var(--border) solid var(--lily-border);
|
|
1091
|
+
vertical-align: top;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
/* Row hover — subtle highlight for scanning long tables. */
|
|
1095
|
+
:where(
|
|
1096
|
+
.table-row,
|
|
1097
|
+
.data-table-row,
|
|
1098
|
+
.calendar-table-row,
|
|
1099
|
+
.kanban-table-row,
|
|
1100
|
+
.gantt-table-tr
|
|
1101
|
+
):hover {
|
|
1102
|
+
background-color: var(--lily-surface-alt);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/* Data-table filter form — chips that sit above the table. */
|
|
1106
|
+
:where(.data-filter-form) {
|
|
1107
|
+
display: flex;
|
|
1108
|
+
flex-wrap: wrap;
|
|
1109
|
+
gap: 0.75rem;
|
|
1110
|
+
padding: 1rem;
|
|
1111
|
+
background-color: var(--lily-surface-alt);
|
|
1112
|
+
border-radius: var(--lily-radius-md);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
/* --- Calendar specifics ------------------------------------------------- */
|
|
1116
|
+
/* Selected date — filled with the primary brand colour. */
|
|
1117
|
+
:where(.calendar-table-td[aria-selected="true"]) {
|
|
1118
|
+
background-color: var(--color-primary);
|
|
1119
|
+
color: var(--color-primary-content);
|
|
1120
|
+
}
|
|
1121
|
+
/* Today — outlined rather than filled, so a selected non-today date
|
|
1122
|
+
still reads as the "selected" one. */
|
|
1123
|
+
:where(.calendar-table-td[aria-current="date"]) {
|
|
1124
|
+
outline: 2px solid var(--color-primary);
|
|
1125
|
+
outline-offset: -2px;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
/* --- Kanban specifics --------------------------------------------------- */
|
|
1129
|
+
/* Each column renders as a `<td>`; widen the cells so cards have room. */
|
|
1130
|
+
:where(.kanban-table) {
|
|
1131
|
+
display: table;
|
|
1132
|
+
}
|
|
1133
|
+
:where(.kanban-table-td) {
|
|
1134
|
+
vertical-align: top;
|
|
1135
|
+
background-color: var(--lily-surface);
|
|
1136
|
+
min-width: 14rem;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
/* --- Gantt specifics ---------------------------------------------------- */
|
|
1140
|
+
/* Cells marked as bars are filled with the primary colour to render the
|
|
1141
|
+
schedule bar inline within the grid. */
|
|
1142
|
+
:where(.gantt-table-td[data-state="bar"]) {
|
|
1143
|
+
background-color: var(--color-primary);
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
/* ==========================================================================
|
|
1147
|
+
* Cards, panels, surfaces
|
|
1148
|
+
* --------------------------------------------------------------------------
|
|
1149
|
+
* Family of generic content containers. Differ mostly in elevation
|
|
1150
|
+
* (shadow depth) and accent colour.
|
|
1151
|
+
* ====================================================================== */
|
|
1152
|
+
|
|
1153
|
+
:where(
|
|
1154
|
+
.card,
|
|
1155
|
+
.feature-card,
|
|
1156
|
+
.product-card,
|
|
1157
|
+
.care-card,
|
|
1158
|
+
.hover-card,
|
|
1159
|
+
.panel,
|
|
1160
|
+
.floating-panel,
|
|
1161
|
+
.success-panel
|
|
1162
|
+
) {
|
|
1163
|
+
display: block;
|
|
1164
|
+
padding: 1rem;
|
|
1165
|
+
background-color: var(--lily-surface);
|
|
1166
|
+
color: var(--lily-text);
|
|
1167
|
+
border: var(--border) solid var(--lily-border);
|
|
1168
|
+
border-radius: var(--lily-radius-lg);
|
|
1169
|
+
box-shadow: var(--lily-shadow-sm);
|
|
1170
|
+
}
|
|
1171
|
+
/* Feature card — generous padding because it leads the page. */
|
|
1172
|
+
:where(.feature-card) {
|
|
1173
|
+
padding: 1.5rem;
|
|
1174
|
+
}
|
|
1175
|
+
/* Hover card — popover-like; lift it with the medium shadow. */
|
|
1176
|
+
:where(.hover-card) {
|
|
1177
|
+
box-shadow: var(--lily-shadow-md);
|
|
1178
|
+
}
|
|
1179
|
+
/* Floating panel — pinned overlay; largest shadow. */
|
|
1180
|
+
:where(.floating-panel) {
|
|
1181
|
+
box-shadow: var(--lily-shadow-lg);
|
|
1182
|
+
}
|
|
1183
|
+
/* Success panel — green border + faint green tint. */
|
|
1184
|
+
:where(.success-panel) {
|
|
1185
|
+
border-color: var(--color-success);
|
|
1186
|
+
background-color: color-mix(
|
|
1187
|
+
in oklch,
|
|
1188
|
+
var(--color-success) 8%,
|
|
1189
|
+
var(--lily-surface)
|
|
1190
|
+
);
|
|
1191
|
+
}
|
|
1192
|
+
/* Care card urgency variants — coloured left rail (urgent/non-urgent/
|
|
1193
|
+
primary). Pattern adapted from the NHS care-card guidance. */
|
|
1194
|
+
:where(.care-card[data-urgency="urgent"]) {
|
|
1195
|
+
border-color: var(--color-error);
|
|
1196
|
+
border-left-width: 0.375rem;
|
|
1197
|
+
}
|
|
1198
|
+
:where(.care-card[data-urgency="non-urgent"]) {
|
|
1199
|
+
border-color: var(--color-info);
|
|
1200
|
+
border-left-width: 0.375rem;
|
|
1201
|
+
}
|
|
1202
|
+
:where(.care-card[data-urgency="primary"]) {
|
|
1203
|
+
border-color: var(--color-primary);
|
|
1204
|
+
border-left-width: 0.375rem;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
/* ==========================================================================
|
|
1208
|
+
* Banners, alerts, callouts, notifications
|
|
1209
|
+
* --------------------------------------------------------------------------
|
|
1210
|
+
* Family of messages with a coloured left rail. The rail colour is set
|
|
1211
|
+
* per severity so the message reads at a glance.
|
|
1212
|
+
* ====================================================================== */
|
|
1213
|
+
|
|
1214
|
+
/* Baseline — alert/banner/callout/notification all share the same frame. */
|
|
1215
|
+
:where(
|
|
1216
|
+
.alert,
|
|
1217
|
+
.banner,
|
|
1218
|
+
.announcement-banner,
|
|
1219
|
+
.phase-banner,
|
|
1220
|
+
.government-banner,
|
|
1221
|
+
.medical-banner,
|
|
1222
|
+
.super-banner,
|
|
1223
|
+
.information-callout,
|
|
1224
|
+
.warning-callout,
|
|
1225
|
+
.summary-box,
|
|
1226
|
+
.notification,
|
|
1227
|
+
.toast,
|
|
1228
|
+
.sonner
|
|
1229
|
+
) {
|
|
1230
|
+
display: flex;
|
|
1231
|
+
align-items: flex-start;
|
|
1232
|
+
gap: 0.75rem;
|
|
1233
|
+
padding: 1rem;
|
|
1234
|
+
background-color: var(--lily-surface-alt);
|
|
1235
|
+
color: var(--lily-text);
|
|
1236
|
+
border: var(--border) solid var(--lily-border);
|
|
1237
|
+
border-inline-start-width: 0.375rem; /* the coloured rail */
|
|
1238
|
+
border-radius: var(--lily-radius-md);
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
/* Severity variants — rail + faint background tint. */
|
|
1242
|
+
:where(
|
|
1243
|
+
.alert[data-severity="info"],
|
|
1244
|
+
.information-callout,
|
|
1245
|
+
.announcement-banner
|
|
1246
|
+
) {
|
|
1247
|
+
border-inline-start-color: var(--color-info);
|
|
1248
|
+
background-color: color-mix(
|
|
1249
|
+
in oklch,
|
|
1250
|
+
var(--color-info) 8%,
|
|
1251
|
+
var(--lily-surface)
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
:where(.alert[data-severity="success"]) {
|
|
1255
|
+
border-inline-start-color: var(--color-success);
|
|
1256
|
+
background-color: color-mix(
|
|
1257
|
+
in oklch,
|
|
1258
|
+
var(--color-success) 8%,
|
|
1259
|
+
var(--lily-surface)
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
1262
|
+
:where(.alert[data-severity="warning"], .warning-callout, .phase-banner) {
|
|
1263
|
+
border-inline-start-color: var(--color-warning);
|
|
1264
|
+
background-color: color-mix(
|
|
1265
|
+
in oklch,
|
|
1266
|
+
var(--color-warning) 12%,
|
|
1267
|
+
var(--lily-surface)
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
:where(
|
|
1271
|
+
.alert[data-severity="error"],
|
|
1272
|
+
.error-message,
|
|
1273
|
+
.error-summary,
|
|
1274
|
+
.super-banner
|
|
1275
|
+
) {
|
|
1276
|
+
border-inline-start-color: var(--color-error);
|
|
1277
|
+
background-color: color-mix(
|
|
1278
|
+
in oklch,
|
|
1279
|
+
var(--color-error) 8%,
|
|
1280
|
+
var(--lily-surface)
|
|
1281
|
+
);
|
|
1282
|
+
}
|
|
1283
|
+
/* Medical banner — primary brand colour. */
|
|
1284
|
+
:where(.medical-banner) {
|
|
1285
|
+
border-inline-start-color: var(--color-primary);
|
|
1286
|
+
}
|
|
1287
|
+
/* Medical banner inner boxes — danger / advice variants. */
|
|
1288
|
+
:where(.medical-banner-box-for-danger) {
|
|
1289
|
+
border-color: var(--color-error);
|
|
1290
|
+
background-color: color-mix(
|
|
1291
|
+
in oklch,
|
|
1292
|
+
var(--color-error) 8%,
|
|
1293
|
+
var(--lily-surface)
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
:where(.medical-banner-box-for-advice) {
|
|
1297
|
+
border-color: var(--color-info);
|
|
1298
|
+
background-color: color-mix(
|
|
1299
|
+
in oklch,
|
|
1300
|
+
var(--color-info) 8%,
|
|
1301
|
+
var(--lily-surface)
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
/* Government banner — solid neutral surface (US-government / GOV.UK
|
|
1305
|
+
style: a chrome bar at the top of the page identifying the site
|
|
1306
|
+
as an official property). No coloured rail. */
|
|
1307
|
+
:where(.government-banner) {
|
|
1308
|
+
background-color: var(--color-neutral);
|
|
1309
|
+
color: var(--color-neutral-content);
|
|
1310
|
+
border-color: transparent;
|
|
1311
|
+
border-inline-start-color: transparent;
|
|
1312
|
+
}
|
|
1313
|
+
/* Summary box — primary-coloured rail; used for "answer at a glance"
|
|
1314
|
+
callouts on long forms (e.g. cost summary). */
|
|
1315
|
+
:where(.summary-box) {
|
|
1316
|
+
border-color: var(--color-primary);
|
|
1317
|
+
border-inline-start-width: 0.375rem;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
/* Banner boxes — chrome strip variants used inside header areas. */
|
|
1321
|
+
:where(.banner-box, .medical-banner-box) {
|
|
1322
|
+
display: flex;
|
|
1323
|
+
align-items: center;
|
|
1324
|
+
gap: 0.75rem;
|
|
1325
|
+
padding: 0.75rem 1rem;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
/* Sticky promo — sits at the very top of the viewport on scroll. */
|
|
1329
|
+
:where(.sticky-promo-banner) {
|
|
1330
|
+
position: sticky;
|
|
1331
|
+
inset-block-start: 0;
|
|
1332
|
+
z-index: 10;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
/* Error message — inline form-validation message. */
|
|
1336
|
+
:where(.error-message) {
|
|
1337
|
+
color: var(--color-error);
|
|
1338
|
+
font-weight: 600;
|
|
1339
|
+
}
|
|
1340
|
+
/* Error summary — heavyweight 4px border (GOV.UK pattern) so users
|
|
1341
|
+
scrolling back to the top of a form see it immediately. */
|
|
1342
|
+
:where(.error-summary) {
|
|
1343
|
+
padding: 1rem;
|
|
1344
|
+
border: 0.25rem solid var(--color-error);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
/* Toast / Sonner — floating notifications; medium elevation. */
|
|
1348
|
+
:where(.toast, .sonner) {
|
|
1349
|
+
box-shadow: var(--lily-shadow-md);
|
|
1350
|
+
}
|
|
1351
|
+
/* In-page notification — small elevation. */
|
|
1352
|
+
:where(.notification) {
|
|
1353
|
+
box-shadow: var(--lily-shadow-sm);
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
/* ==========================================================================
|
|
1357
|
+
* Forms
|
|
1358
|
+
* --------------------------------------------------------------------------
|
|
1359
|
+
* Form / field / fieldset layout primitives. Stack vertically with a
|
|
1360
|
+
* consistent gap so consumer markup stays brief.
|
|
1361
|
+
* ====================================================================== */
|
|
1362
|
+
|
|
1363
|
+
:where(.form, .editable-form) {
|
|
1364
|
+
display: flex;
|
|
1365
|
+
flex-direction: column;
|
|
1366
|
+
gap: 1rem;
|
|
1367
|
+
}
|
|
1368
|
+
/* Field — wraps a single label + input + hint/error trio. */
|
|
1369
|
+
:where(.field) {
|
|
1370
|
+
display: flex;
|
|
1371
|
+
flex-direction: column;
|
|
1372
|
+
gap: 0.375rem;
|
|
1373
|
+
}
|
|
1374
|
+
/* Fieldset — semantic <fieldset>; border + padded inset, legend bold. */
|
|
1375
|
+
:where(.fieldset) {
|
|
1376
|
+
border: var(--border) solid var(--lily-border);
|
|
1377
|
+
border-radius: var(--lily-radius-md);
|
|
1378
|
+
padding: 1rem;
|
|
1379
|
+
}
|
|
1380
|
+
:where(.fieldset > legend) {
|
|
1381
|
+
padding-inline: 0.5rem;
|
|
1382
|
+
font-weight: 600;
|
|
1383
|
+
}
|
|
1384
|
+
/* Label — bold and dark; consumers can override per-form. */
|
|
1385
|
+
:where(.label) {
|
|
1386
|
+
font-weight: 600;
|
|
1387
|
+
color: var(--lily-text);
|
|
1388
|
+
}
|
|
1389
|
+
/* Hint — small muted helptext under the input. */
|
|
1390
|
+
:where(.hint) {
|
|
1391
|
+
color: var(--lily-text-muted);
|
|
1392
|
+
font-size: 0.875rem;
|
|
1393
|
+
}
|
|
1394
|
+
/* Character counter — same colour/size as hint but right-aligned. */
|
|
1395
|
+
:where(.character-counter) {
|
|
1396
|
+
color: var(--lily-text-muted);
|
|
1397
|
+
font-size: 0.875rem;
|
|
1398
|
+
text-align: end;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
/* ==========================================================================
|
|
1402
|
+
* Layout & containers
|
|
1403
|
+
* ====================================================================== */
|
|
1404
|
+
|
|
1405
|
+
/* Page-width containers. */
|
|
1406
|
+
:where(
|
|
1407
|
+
.container,
|
|
1408
|
+
.container-with-fixed-width,
|
|
1409
|
+
.container-with-fluid-width
|
|
1410
|
+
) {
|
|
1411
|
+
display: block;
|
|
1412
|
+
width: 100%;
|
|
1413
|
+
margin-inline: auto;
|
|
1414
|
+
padding-inline: 1rem;
|
|
1415
|
+
box-sizing: border-box;
|
|
1416
|
+
}
|
|
1417
|
+
/* Fixed-width — caps at a comfortable reading width (~1152px). */
|
|
1418
|
+
:where(.container-with-fixed-width) {
|
|
1419
|
+
max-width: 72rem;
|
|
1420
|
+
}
|
|
1421
|
+
/* Fluid-width — fills the viewport edge-to-edge. */
|
|
1422
|
+
:where(.container-with-fluid-width) {
|
|
1423
|
+
max-width: none;
|
|
1424
|
+
}
|
|
1425
|
+
/* Reset the inline padding when a container should butt against the edge. */
|
|
1426
|
+
:where(.padding-reset) {
|
|
1427
|
+
padding-inline: 0;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
/* Flex / grid / masonry primitives. */
|
|
1431
|
+
:where(.flex-stack) {
|
|
1432
|
+
display: flex;
|
|
1433
|
+
flex-direction: column;
|
|
1434
|
+
gap: 1rem;
|
|
1435
|
+
}
|
|
1436
|
+
:where(.grid) {
|
|
1437
|
+
display: grid;
|
|
1438
|
+
gap: 1rem;
|
|
1439
|
+
}
|
|
1440
|
+
:where(.masonry) {
|
|
1441
|
+
column-count: 3;
|
|
1442
|
+
column-gap: 1rem;
|
|
1443
|
+
}
|
|
1444
|
+
/* Horizontal-rule replacement that respects theme borders. */
|
|
1445
|
+
:where(.separator) {
|
|
1446
|
+
border: 0;
|
|
1447
|
+
border-top: var(--border) solid var(--lily-border);
|
|
1448
|
+
margin: 1rem 0;
|
|
1449
|
+
}
|
|
1450
|
+
/* Generic content tile. */
|
|
1451
|
+
:where(.tile) {
|
|
1452
|
+
display: block;
|
|
1453
|
+
padding: 1rem;
|
|
1454
|
+
background-color: var(--lily-surface);
|
|
1455
|
+
border: var(--border) solid var(--lily-border);
|
|
1456
|
+
border-radius: var(--lily-radius-md);
|
|
1457
|
+
}
|
|
1458
|
+
/* Sidebar — secondary-surface panel; sits beside main content. */
|
|
1459
|
+
:where(.sidebar) {
|
|
1460
|
+
display: block;
|
|
1461
|
+
background-color: var(--lily-surface-alt);
|
|
1462
|
+
padding: 1rem;
|
|
1463
|
+
border-radius: var(--lily-radius-md);
|
|
1464
|
+
}
|
|
1465
|
+
/* Aspect-ratio box — 16:9 default; consumers override `aspect-ratio`. */
|
|
1466
|
+
:where(.aspect-ratio-container) {
|
|
1467
|
+
position: relative;
|
|
1468
|
+
display: block;
|
|
1469
|
+
aspect-ratio: 16 / 9;
|
|
1470
|
+
overflow: hidden;
|
|
1471
|
+
border-radius: var(--lily-radius-md);
|
|
1472
|
+
}
|
|
1473
|
+
/* Framer — bordered box for embeds / illustrations. */
|
|
1474
|
+
:where(.framer) {
|
|
1475
|
+
padding: 1rem;
|
|
1476
|
+
border: var(--border) solid var(--lily-border);
|
|
1477
|
+
border-radius: var(--lily-radius-md);
|
|
1478
|
+
}
|
|
1479
|
+
/* Article-layout — declares column-width tokens that content-block reads.
|
|
1480
|
+
Pattern lifted from the Reuters Graphics components system. */
|
|
1481
|
+
:where(.article-layout) {
|
|
1482
|
+
--content-width-narrower: 20.625rem; /* 330px */
|
|
1483
|
+
--content-width-narrow: 31.875rem; /* 510px */
|
|
1484
|
+
--content-width-normal: 41.25rem; /* 660px (default reading width) */
|
|
1485
|
+
--content-width-wide: 58.125rem; /* 930px (chart escape) */
|
|
1486
|
+
--content-width-wider: 75rem; /* 1200px (full-bleed escape) */
|
|
1487
|
+
display: block;
|
|
1488
|
+
}
|
|
1489
|
+
/* Content-block — reads the column-width tokens; switch via data-width. */
|
|
1490
|
+
:where(.content-block) {
|
|
1491
|
+
max-width: var(--content-width-normal);
|
|
1492
|
+
margin-inline: auto;
|
|
1493
|
+
padding-inline: 1rem;
|
|
1494
|
+
box-sizing: border-box;
|
|
1495
|
+
}
|
|
1496
|
+
:where(.content-block[data-width="narrower"]) {
|
|
1497
|
+
max-width: var(--content-width-narrower);
|
|
1498
|
+
}
|
|
1499
|
+
:where(.content-block[data-width="narrow"]) {
|
|
1500
|
+
max-width: var(--content-width-narrow);
|
|
1501
|
+
}
|
|
1502
|
+
:where(.content-block[data-width="wide"]) {
|
|
1503
|
+
max-width: var(--content-width-wide);
|
|
1504
|
+
}
|
|
1505
|
+
:where(.content-block[data-width="wider"]) {
|
|
1506
|
+
max-width: var(--content-width-wider);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
/* --- Grail layout (5-region responsive page shell) --------------------- */
|
|
1510
|
+
/* Header spans the top; left-aside / main / right-aside fill the middle;
|
|
1511
|
+
footer spans the bottom. At ≤768px the asides drop below the main. */
|
|
1512
|
+
:where(.grail-layout) {
|
|
1513
|
+
display: grid;
|
|
1514
|
+
min-height: 100vh;
|
|
1515
|
+
grid-template-areas:
|
|
1516
|
+
"header header header"
|
|
1517
|
+
"left main right"
|
|
1518
|
+
"footer footer footer";
|
|
1519
|
+
grid-template-rows: auto 1fr auto;
|
|
1520
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 3fr) minmax(0, 1fr);
|
|
1521
|
+
background-color: var(--lily-surface);
|
|
1522
|
+
color: var(--lily-text);
|
|
1523
|
+
}
|
|
1524
|
+
:where(.grail-layout-top-header) {
|
|
1525
|
+
grid-area: header;
|
|
1526
|
+
}
|
|
1527
|
+
:where(.grail-layout-left-aside) {
|
|
1528
|
+
grid-area: left;
|
|
1529
|
+
}
|
|
1530
|
+
:where(.grail-layout-center-main) {
|
|
1531
|
+
grid-area: main;
|
|
1532
|
+
}
|
|
1533
|
+
:where(.grail-layout-right-aside) {
|
|
1534
|
+
grid-area: right;
|
|
1535
|
+
}
|
|
1536
|
+
:where(.grail-layout-bottom-footer) {
|
|
1537
|
+
grid-area: footer;
|
|
1538
|
+
}
|
|
1539
|
+
/* Header / footer chrome — secondary surface, padded. */
|
|
1540
|
+
:where(.grail-layout-top-header, .grail-layout-bottom-footer) {
|
|
1541
|
+
background-color: var(--lily-surface-alt);
|
|
1542
|
+
padding: 1rem;
|
|
1543
|
+
}
|
|
1544
|
+
/* Asides — secondary surface, padded. */
|
|
1545
|
+
:where(.grail-layout-left-aside, .grail-layout-right-aside) {
|
|
1546
|
+
padding: 1rem;
|
|
1547
|
+
background-color: var(--lily-surface-alt);
|
|
1548
|
+
}
|
|
1549
|
+
/* Main content area — primary surface, more generous padding. */
|
|
1550
|
+
:where(.grail-layout-center-main) {
|
|
1551
|
+
padding: 1.5rem;
|
|
1552
|
+
}
|
|
1553
|
+
/* Mobile breakpoint — collapse to a single column, stacking the regions. */
|
|
1554
|
+
@media (max-width: 48rem) {
|
|
1555
|
+
:where(.grail-layout) {
|
|
1556
|
+
grid-template-areas: "header" "main" "left" "right" "footer";
|
|
1557
|
+
grid-template-columns: 1fr;
|
|
1558
|
+
grid-template-rows: auto auto auto auto auto;
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
/* Standalone semantic header / footer landmarks. */
|
|
1563
|
+
:where(.header) {
|
|
1564
|
+
display: block;
|
|
1565
|
+
padding: 1rem;
|
|
1566
|
+
background-color: var(--lily-surface);
|
|
1567
|
+
border-bottom: var(--border) solid var(--lily-border);
|
|
1568
|
+
}
|
|
1569
|
+
:where(.footer) {
|
|
1570
|
+
display: block;
|
|
1571
|
+
padding: 1rem;
|
|
1572
|
+
background-color: var(--lily-surface-alt);
|
|
1573
|
+
border-top: var(--border) solid var(--lily-border);
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
/* ==========================================================================
|
|
1577
|
+
* Dialogs, popovers, overlays
|
|
1578
|
+
* --------------------------------------------------------------------------
|
|
1579
|
+
* Modal and floating UI. Backdrop is a blur + 50% black overlay; dialog
|
|
1580
|
+
* frames are rounded with the largest shadow.
|
|
1581
|
+
* ====================================================================== */
|
|
1582
|
+
|
|
1583
|
+
/* Native <dialog> + variant types. */
|
|
1584
|
+
:where(
|
|
1585
|
+
.dialog,
|
|
1586
|
+
.alert-dialog,
|
|
1587
|
+
.timeout-dialog,
|
|
1588
|
+
.popconfirm-dialog,
|
|
1589
|
+
.file-dialog
|
|
1590
|
+
) {
|
|
1591
|
+
background-color: var(--lily-surface);
|
|
1592
|
+
color: var(--lily-text);
|
|
1593
|
+
border: var(--border) solid var(--lily-border);
|
|
1594
|
+
border-radius: var(--lily-radius-lg);
|
|
1595
|
+
padding: 1.5rem;
|
|
1596
|
+
box-shadow: var(--lily-shadow-lg);
|
|
1597
|
+
max-width: min(40rem, 90vw); /* cap on big screens, fit on small */
|
|
1598
|
+
}
|
|
1599
|
+
/* Backdrop — dim the page and blur slightly so focus stays on the dialog. */
|
|
1600
|
+
:where(
|
|
1601
|
+
.dialog::backdrop,
|
|
1602
|
+
.alert-dialog::backdrop,
|
|
1603
|
+
.timeout-dialog::backdrop,
|
|
1604
|
+
.popconfirm-dialog::backdrop,
|
|
1605
|
+
.file-dialog::backdrop
|
|
1606
|
+
) {
|
|
1607
|
+
background-color: color-mix(in oklch, black 50%, transparent);
|
|
1608
|
+
backdrop-filter: blur(2px);
|
|
1609
|
+
}
|
|
1610
|
+
/* Alert dialog — red rail so the user knows it's destructive. */
|
|
1611
|
+
:where(.alert-dialog) {
|
|
1612
|
+
border-color: var(--color-error);
|
|
1613
|
+
border-inline-start-width: 0.375rem;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
/* Popover / tooltip family — small floating labels. */
|
|
1617
|
+
:where(.popover, .popup, .tooltip, .coachmark, .contextual-help) {
|
|
1618
|
+
display: block;
|
|
1619
|
+
padding: 0.5rem 0.75rem;
|
|
1620
|
+
background-color: var(--color-neutral);
|
|
1621
|
+
color: var(--color-neutral-content);
|
|
1622
|
+
border-radius: var(--lily-radius-md);
|
|
1623
|
+
box-shadow: var(--lily-shadow-md);
|
|
1624
|
+
font-size: 0.875rem;
|
|
1625
|
+
max-width: 20rem;
|
|
1626
|
+
}
|
|
1627
|
+
/* Popover / popup — surface-coloured (more substantial than a tooltip). */
|
|
1628
|
+
:where(.popover, .popup) {
|
|
1629
|
+
background-color: var(--lily-surface);
|
|
1630
|
+
color: var(--lily-text);
|
|
1631
|
+
border: var(--border) solid var(--lily-border);
|
|
1632
|
+
max-width: 24rem;
|
|
1633
|
+
}
|
|
1634
|
+
/* Coachmark — primary-coloured border so it reads as a tutorial hint. */
|
|
1635
|
+
:where(.coachmark) {
|
|
1636
|
+
border: 2px solid var(--color-primary);
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
/* Full-page overlay container — dims everything beneath a high-z child. */
|
|
1640
|
+
:where(.overlay-container) {
|
|
1641
|
+
position: fixed;
|
|
1642
|
+
inset: 0;
|
|
1643
|
+
background-color: color-mix(in oklch, black 50%, transparent);
|
|
1644
|
+
z-index: 100;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
/* Drawers — side panels (right edge by default; RTL-aware via logical
|
|
1648
|
+
properties). Sit above the overlay container (z-index 101). */
|
|
1649
|
+
:where(.drawer, .slide-out-drawer, .sheet) {
|
|
1650
|
+
position: fixed;
|
|
1651
|
+
inset-block: 0;
|
|
1652
|
+
inset-inline-end: 0;
|
|
1653
|
+
width: min(28rem, 90vw);
|
|
1654
|
+
background-color: var(--lily-surface);
|
|
1655
|
+
color: var(--lily-text);
|
|
1656
|
+
border-inline-start: var(--border) solid var(--lily-border);
|
|
1657
|
+
box-shadow: var(--lily-shadow-lg);
|
|
1658
|
+
padding: 1rem;
|
|
1659
|
+
z-index: 101;
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
/* ==========================================================================
|
|
1663
|
+
* Menus
|
|
1664
|
+
* ====================================================================== */
|
|
1665
|
+
|
|
1666
|
+
/* Menu containers — surface-coloured popover with thin border + sm shadow. */
|
|
1667
|
+
:where(.menu, .context-menu, .dropdown-menu, .tree-menu, .command) {
|
|
1668
|
+
display: block;
|
|
1669
|
+
background-color: var(--lily-surface);
|
|
1670
|
+
color: var(--lily-text);
|
|
1671
|
+
border: var(--border) solid var(--lily-border);
|
|
1672
|
+
border-radius: var(--lily-radius-md);
|
|
1673
|
+
padding: 0.25rem;
|
|
1674
|
+
box-shadow: var(--lily-shadow-sm);
|
|
1675
|
+
list-style: none;
|
|
1676
|
+
margin: 0;
|
|
1677
|
+
}
|
|
1678
|
+
/* Menu items — flex row with icon + label slot. */
|
|
1679
|
+
:where(.menu-item, .context-menu-item) {
|
|
1680
|
+
display: flex;
|
|
1681
|
+
align-items: center;
|
|
1682
|
+
gap: 0.5rem;
|
|
1683
|
+
padding: 0.5rem 0.75rem;
|
|
1684
|
+
border-radius: var(--lily-radius-md);
|
|
1685
|
+
cursor: pointer;
|
|
1686
|
+
}
|
|
1687
|
+
/* Highlight on hover / aria-selected — alt surface. */
|
|
1688
|
+
:where(
|
|
1689
|
+
.menu-item:hover,
|
|
1690
|
+
.context-menu-item:hover,
|
|
1691
|
+
.menu-item[aria-selected="true"]
|
|
1692
|
+
) {
|
|
1693
|
+
background-color: var(--lily-surface-alt);
|
|
1694
|
+
}
|
|
1695
|
+
/* Menu group — section within a menu. The aria-label becomes a header. */
|
|
1696
|
+
:where(.menu-group) {
|
|
1697
|
+
padding: 0.25rem 0;
|
|
1698
|
+
}
|
|
1699
|
+
:where(.menu-group::before) {
|
|
1700
|
+
content: attr(aria-label);
|
|
1701
|
+
display: block;
|
|
1702
|
+
padding: 0.25rem 0.75rem;
|
|
1703
|
+
color: var(--lily-text-muted);
|
|
1704
|
+
font-size: 0.75rem;
|
|
1705
|
+
text-transform: uppercase;
|
|
1706
|
+
letter-spacing: 0.05em;
|
|
1707
|
+
}
|
|
1708
|
+
/* Cascader / navigation-menu — horizontal flex row of menu columns. */
|
|
1709
|
+
:where(.cascader, .navigation-menu) {
|
|
1710
|
+
display: flex;
|
|
1711
|
+
gap: 0.25rem;
|
|
1712
|
+
}
|
|
1713
|
+
/* Hamburger — bordered icon-button. */
|
|
1714
|
+
:where(.hamburger-menu) {
|
|
1715
|
+
display: inline-flex;
|
|
1716
|
+
align-items: center;
|
|
1717
|
+
justify-content: center;
|
|
1718
|
+
padding: 0.5rem;
|
|
1719
|
+
background: transparent;
|
|
1720
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
1721
|
+
border-radius: var(--lily-radius-md);
|
|
1722
|
+
color: var(--lily-text);
|
|
1723
|
+
cursor: pointer;
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
/* ==========================================================================
|
|
1727
|
+
* Segments, toggles, groups
|
|
1728
|
+
* ====================================================================== */
|
|
1729
|
+
|
|
1730
|
+
/* Generic group containers — inline-flex, wrap, small gap. */
|
|
1731
|
+
:where(
|
|
1732
|
+
.segment-group,
|
|
1733
|
+
.toggle-group,
|
|
1734
|
+
.checkbox-group,
|
|
1735
|
+
.radio-group,
|
|
1736
|
+
.dial-group,
|
|
1737
|
+
.tag-group,
|
|
1738
|
+
.avatar-group,
|
|
1739
|
+
.mutually-exclusive
|
|
1740
|
+
) {
|
|
1741
|
+
display: inline-flex;
|
|
1742
|
+
gap: 0.25rem;
|
|
1743
|
+
flex-wrap: wrap;
|
|
1744
|
+
}
|
|
1745
|
+
/* Segment group / toggle group get an inset background (iOS-segmented
|
|
1746
|
+
control aesthetic). */
|
|
1747
|
+
:where(.segment-group, .toggle-group) {
|
|
1748
|
+
padding: 0.25rem;
|
|
1749
|
+
background-color: var(--lily-surface-alt);
|
|
1750
|
+
border-radius: var(--lily-radius-md);
|
|
1751
|
+
}
|
|
1752
|
+
/* Segment items — transparent until pressed; then primary fill. */
|
|
1753
|
+
:where(.segment-group-item) {
|
|
1754
|
+
padding: 0.375rem 0.75rem;
|
|
1755
|
+
background: transparent;
|
|
1756
|
+
border: 0;
|
|
1757
|
+
border-radius: var(--lily-radius-md);
|
|
1758
|
+
color: var(--lily-text);
|
|
1759
|
+
cursor: pointer;
|
|
1760
|
+
}
|
|
1761
|
+
:where(
|
|
1762
|
+
.segment-group-item[aria-pressed="true"],
|
|
1763
|
+
.segment-group-item[aria-selected="true"]
|
|
1764
|
+
) {
|
|
1765
|
+
background-color: var(--color-primary);
|
|
1766
|
+
color: var(--color-primary-content);
|
|
1767
|
+
}
|
|
1768
|
+
/* Avatar group — overlap each subsequent avatar by 0.5rem, with a
|
|
1769
|
+
contrast ring for separation. */
|
|
1770
|
+
:where(.avatar-group > *) {
|
|
1771
|
+
margin-inline-start: -0.5rem;
|
|
1772
|
+
border: 2px solid var(--lily-surface);
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
/* ==========================================================================
|
|
1776
|
+
* Progress, loading
|
|
1777
|
+
* ====================================================================== */
|
|
1778
|
+
|
|
1779
|
+
/* Native <progress> / <meter> / bar variant — short, pill-shaped track. */
|
|
1780
|
+
:where(.progress, .progress-bar, .meter) {
|
|
1781
|
+
display: block;
|
|
1782
|
+
width: 100%;
|
|
1783
|
+
height: 0.5rem;
|
|
1784
|
+
appearance: none;
|
|
1785
|
+
background-color: var(--lily-surface-sunken);
|
|
1786
|
+
border: 0;
|
|
1787
|
+
border-radius: 999px;
|
|
1788
|
+
overflow: hidden;
|
|
1789
|
+
}
|
|
1790
|
+
/* Vendor pseudo-elements: track + value. */
|
|
1791
|
+
:where(.progress::-webkit-progress-bar, .meter::-webkit-meter-bar) {
|
|
1792
|
+
background-color: var(--lily-surface-sunken);
|
|
1793
|
+
}
|
|
1794
|
+
:where(
|
|
1795
|
+
.progress::-webkit-progress-value,
|
|
1796
|
+
.meter::-webkit-meter-optimum-value
|
|
1797
|
+
) {
|
|
1798
|
+
background-color: var(--color-primary);
|
|
1799
|
+
}
|
|
1800
|
+
:where(.progress::-moz-progress-bar) {
|
|
1801
|
+
background-color: var(--color-primary);
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
/* Progress circle — conic-gradient renders the sweep based on the
|
|
1805
|
+
--progress custom property (0–100). */
|
|
1806
|
+
:where(.progress-circle) {
|
|
1807
|
+
display: inline-block;
|
|
1808
|
+
width: 2rem;
|
|
1809
|
+
height: 2rem;
|
|
1810
|
+
border-radius: 50%;
|
|
1811
|
+
background: conic-gradient(
|
|
1812
|
+
var(--color-primary) calc(var(--progress, 0) * 1%),
|
|
1813
|
+
var(--lily-surface-sunken) 0
|
|
1814
|
+
);
|
|
1815
|
+
}
|
|
1816
|
+
/* Spinner / loading — classic CSS rotating partial-ring. */
|
|
1817
|
+
:where(.progress-spinner, .loading) {
|
|
1818
|
+
display: inline-block;
|
|
1819
|
+
width: 1.5rem;
|
|
1820
|
+
height: 1.5rem;
|
|
1821
|
+
border: 3px solid var(--lily-surface-sunken);
|
|
1822
|
+
border-top-color: var(--color-primary);
|
|
1823
|
+
border-radius: 50%;
|
|
1824
|
+
animation: lily-spin 0.8s linear infinite;
|
|
1825
|
+
}
|
|
1826
|
+
@keyframes lily-spin {
|
|
1827
|
+
to {
|
|
1828
|
+
transform: rotate(360deg);
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
/* Skeleton — shimmering placeholder while content is loading. */
|
|
1832
|
+
:where(.skeleton) {
|
|
1833
|
+
display: block;
|
|
1834
|
+
background: linear-gradient(
|
|
1835
|
+
90deg,
|
|
1836
|
+
var(--lily-surface-alt) 0%,
|
|
1837
|
+
var(--lily-surface-sunken) 50%,
|
|
1838
|
+
var(--lily-surface-alt) 100%
|
|
1839
|
+
);
|
|
1840
|
+
background-size: 200% 100%;
|
|
1841
|
+
animation: lily-skeleton 1.4s ease-in-out infinite;
|
|
1842
|
+
border-radius: var(--lily-radius-md);
|
|
1843
|
+
min-height: 1rem;
|
|
1844
|
+
}
|
|
1845
|
+
@keyframes lily-skeleton {
|
|
1846
|
+
0% {
|
|
1847
|
+
background-position: 200% 0;
|
|
1848
|
+
}
|
|
1849
|
+
100% {
|
|
1850
|
+
background-position: -200% 0;
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
/* Respect prefers-reduced-motion — kill the perpetual animations.
|
|
1854
|
+
(WCAG 2.3.3 Animation from interactions.) */
|
|
1855
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1856
|
+
:where(.progress-spinner, .loading, .skeleton, .beach-ball) {
|
|
1857
|
+
animation: none;
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
/* ==========================================================================
|
|
1862
|
+
* Avatars, badges, tags, status
|
|
1863
|
+
* ====================================================================== */
|
|
1864
|
+
|
|
1865
|
+
/* Avatar — circular tile (2.5rem) with sunken background as the
|
|
1866
|
+
fallback colour when no image is provided. */
|
|
1867
|
+
:where(.avatar) {
|
|
1868
|
+
display: inline-flex;
|
|
1869
|
+
align-items: center;
|
|
1870
|
+
justify-content: center;
|
|
1871
|
+
width: 2.5rem;
|
|
1872
|
+
height: 2.5rem;
|
|
1873
|
+
border-radius: 50%;
|
|
1874
|
+
background-color: var(--lily-surface-sunken);
|
|
1875
|
+
color: var(--lily-text);
|
|
1876
|
+
overflow: hidden;
|
|
1877
|
+
font-weight: 600;
|
|
1878
|
+
}
|
|
1879
|
+
:where(.avatar-image) {
|
|
1880
|
+
width: 100%;
|
|
1881
|
+
height: 100%;
|
|
1882
|
+
object-fit: cover;
|
|
1883
|
+
display: block;
|
|
1884
|
+
}
|
|
1885
|
+
/* Avatar fallback text — uppercase initials. */
|
|
1886
|
+
:where(.avatar-text) {
|
|
1887
|
+
text-transform: uppercase;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
/* Badge / flair / tag family — small pill-shaped labels. */
|
|
1891
|
+
:where(.badge, .flair, .status-tag, .tag, .ai-label) {
|
|
1892
|
+
display: inline-flex;
|
|
1893
|
+
align-items: center;
|
|
1894
|
+
gap: 0.25rem;
|
|
1895
|
+
padding: 0.125rem 0.5rem;
|
|
1896
|
+
font-size: 0.75rem;
|
|
1897
|
+
font-weight: 600;
|
|
1898
|
+
line-height: 1.5;
|
|
1899
|
+
background-color: var(--color-neutral);
|
|
1900
|
+
color: var(--color-neutral-content);
|
|
1901
|
+
border-radius: 999px;
|
|
1902
|
+
}
|
|
1903
|
+
/* Tag — neutral chip with a visible border (so it's not confused with
|
|
1904
|
+
a status badge). */
|
|
1905
|
+
:where(.tag) {
|
|
1906
|
+
background-color: var(--lily-surface-alt);
|
|
1907
|
+
color: var(--lily-text);
|
|
1908
|
+
border: var(--border) solid var(--lily-border);
|
|
1909
|
+
}
|
|
1910
|
+
/* AI label — accent colour so AI-generated content is visually marked. */
|
|
1911
|
+
:where(.ai-label) {
|
|
1912
|
+
background-color: var(--color-accent);
|
|
1913
|
+
color: var(--color-accent-content);
|
|
1914
|
+
}
|
|
1915
|
+
/* Status tags — pre-baked colour for each status. */
|
|
1916
|
+
:where(.status-tag[data-status="success"]) {
|
|
1917
|
+
background-color: var(--color-success);
|
|
1918
|
+
color: var(--color-success-content);
|
|
1919
|
+
}
|
|
1920
|
+
:where(.status-tag[data-status="warning"]) {
|
|
1921
|
+
background-color: var(--color-warning);
|
|
1922
|
+
color: var(--color-warning-content);
|
|
1923
|
+
}
|
|
1924
|
+
:where(.status-tag[data-status="error"]) {
|
|
1925
|
+
background-color: var(--color-error);
|
|
1926
|
+
color: var(--color-error-content);
|
|
1927
|
+
}
|
|
1928
|
+
:where(.status-tag[data-status="info"]) {
|
|
1929
|
+
background-color: var(--color-info);
|
|
1930
|
+
color: var(--color-info-content);
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
/* Status light — a coloured dot followed by a label. */
|
|
1934
|
+
:where(.status-light) {
|
|
1935
|
+
display: inline-flex;
|
|
1936
|
+
align-items: center;
|
|
1937
|
+
gap: 0.375rem;
|
|
1938
|
+
}
|
|
1939
|
+
:where(.status-light)::before {
|
|
1940
|
+
content: "";
|
|
1941
|
+
display: inline-block;
|
|
1942
|
+
width: 0.625rem;
|
|
1943
|
+
height: 0.625rem;
|
|
1944
|
+
border-radius: 50%;
|
|
1945
|
+
background-color: var(--color-neutral);
|
|
1946
|
+
}
|
|
1947
|
+
:where(.status-light[data-status="success"])::before {
|
|
1948
|
+
background-color: var(--color-success);
|
|
1949
|
+
}
|
|
1950
|
+
:where(.status-light[data-status="warning"])::before {
|
|
1951
|
+
background-color: var(--color-warning);
|
|
1952
|
+
}
|
|
1953
|
+
:where(.status-light[data-status="error"])::before {
|
|
1954
|
+
background-color: var(--color-error);
|
|
1955
|
+
}
|
|
1956
|
+
:where(.status-light[data-status="info"])::before {
|
|
1957
|
+
background-color: var(--color-info);
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
/* ==========================================================================
|
|
1961
|
+
* Pickers, ratings, theme
|
|
1962
|
+
* ====================================================================== */
|
|
1963
|
+
|
|
1964
|
+
/* Picker baseline — inline row of selectable chips/buttons. */
|
|
1965
|
+
:where(
|
|
1966
|
+
.color-picker,
|
|
1967
|
+
.five-face-rating-picker,
|
|
1968
|
+
.five-star-rating-picker,
|
|
1969
|
+
.net-promoter-score-picker,
|
|
1970
|
+
.red-amber-green-picker,
|
|
1971
|
+
.red-orange-yellow-green-blue-picker,
|
|
1972
|
+
.emoji-character-picker,
|
|
1973
|
+
.calendar-range-picker
|
|
1974
|
+
) {
|
|
1975
|
+
display: inline-flex;
|
|
1976
|
+
align-items: center;
|
|
1977
|
+
gap: 0.25rem;
|
|
1978
|
+
padding: 0.25rem;
|
|
1979
|
+
background-color: var(--lily-surface);
|
|
1980
|
+
border: var(--border) solid var(--lily-border);
|
|
1981
|
+
border-radius: var(--lily-radius-md);
|
|
1982
|
+
}
|
|
1983
|
+
/* Picker buttons — small alt-surface chips. */
|
|
1984
|
+
:where(
|
|
1985
|
+
.color-picker-button,
|
|
1986
|
+
.five-face-rating-picker-button,
|
|
1987
|
+
.five-star-rating-picker-button,
|
|
1988
|
+
.net-promoter-score-picker-button,
|
|
1989
|
+
.red-amber-green-picker-button,
|
|
1990
|
+
.red-orange-yellow-green-blue-picker-button
|
|
1991
|
+
) {
|
|
1992
|
+
background-color: var(--lily-surface-alt);
|
|
1993
|
+
color: var(--lily-text);
|
|
1994
|
+
border: var(--border) solid var(--lily-border);
|
|
1995
|
+
min-width: 2rem;
|
|
1996
|
+
min-height: 2rem;
|
|
1997
|
+
padding: 0.25rem 0.5rem;
|
|
1998
|
+
}
|
|
1999
|
+
/* Color picker — circular swatch. */
|
|
2000
|
+
:where(.color-picker-button) {
|
|
2001
|
+
width: 1.75rem;
|
|
2002
|
+
height: 1.75rem;
|
|
2003
|
+
padding: 0;
|
|
2004
|
+
border-radius: 50%;
|
|
2005
|
+
}
|
|
2006
|
+
/* Filled stars — warning (gold) colour for both viewer and pressed state. */
|
|
2007
|
+
:where(
|
|
2008
|
+
.five-star-rating-view,
|
|
2009
|
+
.five-star-rating-picker-button[aria-pressed="true"]
|
|
2010
|
+
) {
|
|
2011
|
+
color: var(--color-warning);
|
|
2012
|
+
}
|
|
2013
|
+
/* RAG (red/amber/green) — semantic colour per status. */
|
|
2014
|
+
:where(
|
|
2015
|
+
.red-amber-green-view[data-status="red"],
|
|
2016
|
+
.red-amber-green-picker-button[data-status="red"]
|
|
2017
|
+
) {
|
|
2018
|
+
background-color: var(--color-error);
|
|
2019
|
+
color: var(--color-error-content);
|
|
2020
|
+
}
|
|
2021
|
+
:where(
|
|
2022
|
+
.red-amber-green-view[data-status="amber"],
|
|
2023
|
+
.red-amber-green-picker-button[data-status="amber"]
|
|
2024
|
+
) {
|
|
2025
|
+
background-color: var(--color-warning);
|
|
2026
|
+
color: var(--color-warning-content);
|
|
2027
|
+
}
|
|
2028
|
+
:where(
|
|
2029
|
+
.red-amber-green-view[data-status="green"],
|
|
2030
|
+
.red-amber-green-picker-button[data-status="green"]
|
|
2031
|
+
) {
|
|
2032
|
+
background-color: var(--color-success);
|
|
2033
|
+
color: var(--color-success-content);
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
/* Native <select> styling — drop the UA chrome and draw our own caret
|
|
2037
|
+
via two stacked linear-gradients. */
|
|
2038
|
+
:where(select.theme-select, .select, .select-with-extras, .tree-select) {
|
|
2039
|
+
width: 100%;
|
|
2040
|
+
min-height: 2.5rem;
|
|
2041
|
+
padding: 0.5rem 2rem 0.5rem 0.75rem; /* extra right padding for caret */
|
|
2042
|
+
font: inherit;
|
|
2043
|
+
background-color: var(--lily-surface);
|
|
2044
|
+
color: var(--lily-text);
|
|
2045
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
2046
|
+
border-radius: var(--lily-radius-md);
|
|
2047
|
+
appearance: none;
|
|
2048
|
+
background-image:
|
|
2049
|
+
linear-gradient(45deg, transparent 50%, var(--lily-text) 50%),
|
|
2050
|
+
linear-gradient(135deg, var(--lily-text) 50%, transparent 50%);
|
|
2051
|
+
background-position:
|
|
2052
|
+
calc(100% - 1.1rem) 1.1rem,
|
|
2053
|
+
calc(100% - 0.7rem) 1.1rem;
|
|
2054
|
+
background-size: 0.4rem 0.4rem;
|
|
2055
|
+
background-repeat: no-repeat;
|
|
2056
|
+
}
|
|
2057
|
+
/* Options inherit the select colours so the dropdown matches the input. */
|
|
2058
|
+
:where(.option, .theme-select-option) {
|
|
2059
|
+
background-color: var(--lily-surface);
|
|
2060
|
+
color: var(--lily-text);
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
/* The four *-picker helpers are an icon button that opens a popup,
|
|
2064
|
+
so they are styled as a popup rather than a form field. No :has()
|
|
2065
|
+
guard is needed any more: before the July 2026 rename these shared
|
|
2066
|
+
the `.theme-select` hook with the catalog theme-select component
|
|
2067
|
+
and had to be told apart. Distinct names, no collision. */
|
|
2068
|
+
:where(
|
|
2069
|
+
.theme-picker,
|
|
2070
|
+
.locale-picker,
|
|
2071
|
+
.text-size-picker,
|
|
2072
|
+
.share-picker,
|
|
2073
|
+
.date-time-picker
|
|
2074
|
+
) {
|
|
2075
|
+
position: relative;
|
|
2076
|
+
display: inline-block;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
:where(
|
|
2080
|
+
.theme-picker-button,
|
|
2081
|
+
.locale-picker-button,
|
|
2082
|
+
.text-size-picker-button,
|
|
2083
|
+
.share-picker-button,
|
|
2084
|
+
.date-time-picker-button
|
|
2085
|
+
) {
|
|
2086
|
+
display: inline-flex;
|
|
2087
|
+
align-items: center;
|
|
2088
|
+
justify-content: center;
|
|
2089
|
+
min-width: 2.5rem;
|
|
2090
|
+
min-height: 2.5rem;
|
|
2091
|
+
padding: var(--lily-space-xs);
|
|
2092
|
+
font: inherit;
|
|
2093
|
+
line-height: 1;
|
|
2094
|
+
color: var(--lily-text);
|
|
2095
|
+
background-color: var(--lily-surface);
|
|
2096
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
2097
|
+
border-radius: var(--lily-radius-md);
|
|
2098
|
+
cursor: pointer;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
/* The icon is decorative (aria-hidden); the button's aria-label
|
|
2102
|
+
carries the accessible name. Reversed 2026-09-16: five of the
|
|
2103
|
+
six picker icons (theme, locale, text-size, motion, share) are
|
|
2104
|
+
now bundled SVGs, not Unicode glyphs. Each ships its own
|
|
2105
|
+
explicit width="1.05rem" height="1.05rem" on the <svg> element,
|
|
2106
|
+
so unlike a font-dependent character glyph -- where different
|
|
2107
|
+
glyphs ink different fractions of their em box, needing a
|
|
2108
|
+
per-glyph optical correction -- every icon in this family
|
|
2109
|
+
already inks the same visual size by construction (the icon's
|
|
2110
|
+
own author controls its viewBox). This rule only supplies flex
|
|
2111
|
+
centering; override the icon's own width/height if you need a
|
|
2112
|
+
different size. */
|
|
2113
|
+
:where(
|
|
2114
|
+
.theme-picker-icon,
|
|
2115
|
+
.locale-picker-icon,
|
|
2116
|
+
.text-size-picker-icon,
|
|
2117
|
+
.motion-picker-icon,
|
|
2118
|
+
.share-picker-icon
|
|
2119
|
+
) {
|
|
2120
|
+
display: inline-flex;
|
|
2121
|
+
align-items: center;
|
|
2122
|
+
justify-content: center;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
/* date-time-picker's calendar icon is still a Unicode glyph
|
|
2126
|
+
(U+1F4C5 + U+FE0E) -- out of scope for the 2026-09-16 SVG-icon
|
|
2127
|
+
reversal, since date-time-picker was not part of that change
|
|
2128
|
+
(see AGENTS/helpers.md) -- so it keeps the font-size-based
|
|
2129
|
+
sizing the other five used to share.
|
|
2130
|
+
|
|
2131
|
+
U+1F4C5 calendar inks 1.000 of its em box (max extent) against
|
|
2132
|
+
U+25D1 half-circle's reference 0.850 (the pre-reversal
|
|
2133
|
+
baseline, still valid here since this is the same glyph
|
|
2134
|
+
measurement, unchanged): 0.850/1.000 ≈ 0.85, shipped as 0.845.
|
|
2135
|
+
A colour-emoji font paints every one of its glyphs into one
|
|
2136
|
+
identical em square, so globe, calendar, rocket and heart all
|
|
2137
|
+
measure the same ink box -- any future emoji helper icon can
|
|
2138
|
+
reuse this factor without re-measuring.
|
|
2139
|
+
|
|
2140
|
+
(Measuring also confirms the U+FE0E text-presentation selector is
|
|
2141
|
+
ignored here: the bare and VS-15 forms are metrically identical. It
|
|
2142
|
+
stays in the source as a hint to the platforms that do honour it.) */
|
|
2143
|
+
:where(.date-time-picker-icon) {
|
|
2144
|
+
display: inline-flex;
|
|
2145
|
+
align-items: center;
|
|
2146
|
+
justify-content: center;
|
|
2147
|
+
font-size: calc(1.25em * var(--lily-picker-icon-scale, 1));
|
|
2148
|
+
line-height: 1;
|
|
2149
|
+
--lily-picker-icon-scale: 0.845;
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
/* The share list holds real links and a button rather than options,
|
|
2153
|
+
so its items get the same padding without the option selectors. */
|
|
2154
|
+
:where(.share-picker-list) > :where(.share-picker-list-item) {
|
|
2155
|
+
list-style: none;
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
:where(.share-picker-target, .share-picker-copy) {
|
|
2159
|
+
display: block;
|
|
2160
|
+
width: 100%;
|
|
2161
|
+
padding: var(--lily-space-xs) var(--lily-space-sm);
|
|
2162
|
+
font: inherit;
|
|
2163
|
+
text-align: start;
|
|
2164
|
+
color: var(--lily-text);
|
|
2165
|
+
background: none;
|
|
2166
|
+
border: 0;
|
|
2167
|
+
border-radius: var(--lily-radius-sm);
|
|
2168
|
+
cursor: pointer;
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
:where(.share-picker-target:hover, .share-picker-copy:hover) {
|
|
2172
|
+
background-color: var(--lily-surface-alt);
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
/* Copy feedback. Never display:none this — that silences the live
|
|
2176
|
+
region for screen-reader users. */
|
|
2177
|
+
:where(.share-picker-status) {
|
|
2178
|
+
margin: var(--lily-space-xs) 0 0;
|
|
2179
|
+
font-size: 0.875em;
|
|
2180
|
+
color: var(--lily-text-muted);
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
/* The status paragraph is always rendered so the aria-live region
|
|
2184
|
+
exists before the first announcement (see above); empty, it still
|
|
2185
|
+
generates a line box and carries the margin-top set above, both of
|
|
2186
|
+
which push the button row out of alignment in a flex layout like
|
|
2187
|
+
picker-bar (found independently by two downstream consumers, each
|
|
2188
|
+
patching around it locally). :empty here matches a Svelte-rendered
|
|
2189
|
+
{status} of "" (a zero-length text node doesn't count as a child
|
|
2190
|
+
per the CSS spec), so this only applies while there is nothing to
|
|
2191
|
+
announce, and normal spacing returns the moment status has text. */
|
|
2192
|
+
:where(.share-picker-status:empty) {
|
|
2193
|
+
margin: 0;
|
|
2194
|
+
line-height: 0;
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
:where(
|
|
2198
|
+
.theme-picker-list,
|
|
2199
|
+
.locale-picker-list,
|
|
2200
|
+
.text-size-picker-list,
|
|
2201
|
+
.share-picker-list
|
|
2202
|
+
) {
|
|
2203
|
+
position: absolute;
|
|
2204
|
+
z-index: 10;
|
|
2205
|
+
inset-inline-start: 0;
|
|
2206
|
+
min-width: max-content;
|
|
2207
|
+
max-height: 60vh;
|
|
2208
|
+
margin-block-start: var(--lily-space-xs);
|
|
2209
|
+
padding: var(--lily-space-xs);
|
|
2210
|
+
overflow-y: auto;
|
|
2211
|
+
list-style: none;
|
|
2212
|
+
color: var(--lily-text);
|
|
2213
|
+
background-color: var(--lily-surface);
|
|
2214
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
2215
|
+
border-radius: var(--lily-radius-md);
|
|
2216
|
+
box-shadow: var(--lily-shadow-md);
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
/* Explicit, because the rules above would otherwise beat the UA
|
|
2220
|
+
stylesheet's [hidden] { display: none }. */
|
|
2221
|
+
:where(
|
|
2222
|
+
.theme-picker-list,
|
|
2223
|
+
.locale-picker-list,
|
|
2224
|
+
.text-size-picker-list,
|
|
2225
|
+
.share-picker-list
|
|
2226
|
+
)[hidden] {
|
|
2227
|
+
display: none;
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
:where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
|
|
2231
|
+
> :where(
|
|
2232
|
+
.theme-picker-option,
|
|
2233
|
+
.locale-picker-option,
|
|
2234
|
+
.text-size-picker-option
|
|
2235
|
+
) {
|
|
2236
|
+
padding: var(--lily-space-xs) var(--lily-space-sm);
|
|
2237
|
+
border-radius: var(--lily-radius-sm);
|
|
2238
|
+
cursor: pointer;
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
/* data-active is the keyboard cursor (aria-activedescendant); focus
|
|
2242
|
+
stays on the listbox, so this is the only visible cue for it. */
|
|
2243
|
+
:where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
|
|
2244
|
+
> :where([data-active]) {
|
|
2245
|
+
background-color: var(--lily-surface-alt);
|
|
2246
|
+
outline: var(--lily-focus-ring);
|
|
2247
|
+
outline-offset: -2px;
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
/* aria-selected marks the applied theme/locale, which is not the
|
|
2251
|
+
same thing as the keyboard cursor. Both can be visible at once. */
|
|
2252
|
+
:where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
|
|
2253
|
+
> :where([aria-selected="true"]) {
|
|
2254
|
+
font-weight: 600;
|
|
2255
|
+
background-color: var(--lily-surface-sunken);
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
/* Locale options inherit the select colours, same as theme options. */
|
|
2259
|
+
:where(.locale-picker-option) {
|
|
2260
|
+
background-color: var(--lily-surface);
|
|
2261
|
+
color: var(--lily-text);
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2264
|
+
/* ----------------------------------------------------------------------
|
|
2265
|
+
* date-time-picker
|
|
2266
|
+
*
|
|
2267
|
+
* The one helper that is a form control rather than a page-header
|
|
2268
|
+
* control, so it is the only one with a text field beside its trigger
|
|
2269
|
+
* and a dialog rather than a listbox. The field itself needs no rules
|
|
2270
|
+
* here: `.date-time-picker-input` already matches the generic
|
|
2271
|
+
* [class$="-input"] baseline further up.
|
|
2272
|
+
* -------------------------------------------------------------------- */
|
|
2273
|
+
|
|
2274
|
+
:where(.date-time-picker-field) {
|
|
2275
|
+
display: flex;
|
|
2276
|
+
align-items: center;
|
|
2277
|
+
gap: var(--lily-space-xs);
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
:where(.date-time-picker-dialog) {
|
|
2281
|
+
position: absolute;
|
|
2282
|
+
z-index: 10;
|
|
2283
|
+
inset-inline-start: 0;
|
|
2284
|
+
margin-block-start: var(--lily-space-xs);
|
|
2285
|
+
padding: var(--lily-space-sm);
|
|
2286
|
+
color: var(--lily-text);
|
|
2287
|
+
background-color: var(--lily-surface);
|
|
2288
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
2289
|
+
border-radius: var(--lily-radius-md);
|
|
2290
|
+
box-shadow: var(--lily-shadow-md);
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2293
|
+
/* Explicit, because the rule above would otherwise beat the UA
|
|
2294
|
+
stylesheet's [hidden] { display: none } — the same trap the
|
|
2295
|
+
listbox popups have to step around. */
|
|
2296
|
+
:where(.date-time-picker-dialog)[hidden] {
|
|
2297
|
+
display: none;
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
:where(.date-time-picker-header) {
|
|
2301
|
+
display: flex;
|
|
2302
|
+
align-items: center;
|
|
2303
|
+
justify-content: space-between;
|
|
2304
|
+
gap: var(--lily-space-xs);
|
|
2305
|
+
margin-block-end: var(--lily-space-xs);
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
/* The month/year heading is a live region, so it must keep its box
|
|
2309
|
+
even while empty — never display:none it. */
|
|
2310
|
+
:where(.date-time-picker-period) {
|
|
2311
|
+
flex: 1;
|
|
2312
|
+
font-weight: 600;
|
|
2313
|
+
text-align: center;
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
/* The four navigation buttons and the footer/shortcut buttons do not
|
|
2317
|
+
end in `-button`, so the generic button family never reaches them. */
|
|
2318
|
+
:where(
|
|
2319
|
+
.date-time-picker-previous-year,
|
|
2320
|
+
.date-time-picker-previous-month,
|
|
2321
|
+
.date-time-picker-previous-week,
|
|
2322
|
+
.date-time-picker-previous-day,
|
|
2323
|
+
.date-time-picker-next-day,
|
|
2324
|
+
.date-time-picker-next-week,
|
|
2325
|
+
.date-time-picker-next-month,
|
|
2326
|
+
.date-time-picker-next-year,
|
|
2327
|
+
.date-time-picker-shortcut,
|
|
2328
|
+
.date-time-picker-clear,
|
|
2329
|
+
.date-time-picker-cancel,
|
|
2330
|
+
.date-time-picker-confirm
|
|
2331
|
+
) {
|
|
2332
|
+
padding: var(--lily-space-xs) var(--lily-space-sm);
|
|
2333
|
+
font: inherit;
|
|
2334
|
+
color: var(--lily-text);
|
|
2335
|
+
background-color: var(--lily-surface);
|
|
2336
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
2337
|
+
border-radius: var(--lily-radius-sm);
|
|
2338
|
+
cursor: pointer;
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
:where(
|
|
2342
|
+
.date-time-picker-previous-year:hover,
|
|
2343
|
+
.date-time-picker-previous-month:hover,
|
|
2344
|
+
.date-time-picker-previous-week:hover,
|
|
2345
|
+
.date-time-picker-previous-day:hover,
|
|
2346
|
+
.date-time-picker-next-day:hover,
|
|
2347
|
+
.date-time-picker-next-week:hover,
|
|
2348
|
+
.date-time-picker-next-month:hover,
|
|
2349
|
+
.date-time-picker-next-year:hover,
|
|
2350
|
+
.date-time-picker-shortcut:hover,
|
|
2351
|
+
.date-time-picker-clear:hover,
|
|
2352
|
+
.date-time-picker-cancel:hover,
|
|
2353
|
+
.date-time-picker-confirm:hover
|
|
2354
|
+
) {
|
|
2355
|
+
background-color: var(--lily-surface-alt);
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
/* The commit action is the primary one on the dialog. */
|
|
2359
|
+
:where(.date-time-picker-confirm) {
|
|
2360
|
+
color: var(--color-primary-content);
|
|
2361
|
+
background-color: var(--color-primary);
|
|
2362
|
+
border-color: var(--color-primary);
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
:where(.date-time-picker-calendar) {
|
|
2366
|
+
border-collapse: collapse;
|
|
2367
|
+
table-layout: fixed;
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
:where(.date-time-picker-weekday, .date-time-picker-week-heading) {
|
|
2371
|
+
padding: var(--lily-space-xs);
|
|
2372
|
+
font-size: 0.8125em;
|
|
2373
|
+
font-weight: 600;
|
|
2374
|
+
color: var(--lily-text-muted);
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
/* Week numbers are reference data, not navigation: muted, and set in
|
|
2378
|
+
tabular figures so the column does not shimmer as months change. */
|
|
2379
|
+
:where(.date-time-picker-week) {
|
|
2380
|
+
padding-inline-end: var(--lily-space-xs);
|
|
2381
|
+
font-size: 0.8125em;
|
|
2382
|
+
font-weight: 400;
|
|
2383
|
+
font-variant-numeric: tabular-nums;
|
|
2384
|
+
color: var(--lily-text-muted);
|
|
2385
|
+
text-align: end;
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
:where(.date-time-picker-day) {
|
|
2389
|
+
display: flex;
|
|
2390
|
+
align-items: center;
|
|
2391
|
+
justify-content: center;
|
|
2392
|
+
/* 2rem is a compromise: WCAG 2.5.8 (AA) wants 24px, 2.5.5 (AAA)
|
|
2393
|
+
wants 44px, and seven 44px columns do not fit a 320px viewport
|
|
2394
|
+
alongside dialog chrome. Consumers targeting AAA should enlarge
|
|
2395
|
+
these and let the dialog go full-width on small screens. */
|
|
2396
|
+
min-width: 2rem;
|
|
2397
|
+
min-height: 2rem;
|
|
2398
|
+
padding: 0;
|
|
2399
|
+
font: inherit;
|
|
2400
|
+
font-variant-numeric: tabular-nums;
|
|
2401
|
+
color: var(--lily-text);
|
|
2402
|
+
background: none;
|
|
2403
|
+
border: var(--border) solid transparent;
|
|
2404
|
+
border-radius: var(--lily-radius-sm);
|
|
2405
|
+
cursor: pointer;
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
:where(.date-time-picker-day:hover:not([data-disabled])) {
|
|
2409
|
+
background-color: var(--lily-surface-alt);
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
/* Adjacent-month days stay legible rather than being hidden: they are
|
|
2413
|
+
real, selectable dates, and blanking them makes the grid harder to
|
|
2414
|
+
scan across a month boundary. */
|
|
2415
|
+
:where(.date-time-picker-day[data-outside]) {
|
|
2416
|
+
color: var(--lily-text-muted);
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
/* Today is marked with a border, the selection with a fill. Two
|
|
2420
|
+
different channels, so a day that is both still reads as both. */
|
|
2421
|
+
:where(.date-time-picker-day[data-today]) {
|
|
2422
|
+
border-color: var(--lily-border-strong);
|
|
2423
|
+
font-weight: 600;
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
:where(.date-time-picker-day[data-selected]) {
|
|
2427
|
+
color: var(--color-primary-content);
|
|
2428
|
+
background-color: var(--color-primary);
|
|
2429
|
+
border-color: var(--color-primary);
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
:where(.date-time-picker-day[data-disabled]) {
|
|
2433
|
+
color: var(--lily-text-muted);
|
|
2434
|
+
cursor: not-allowed;
|
|
2435
|
+
/* Struck through as well as dimmed: "unavailable" must not rest on
|
|
2436
|
+
contrast alone (WCAG 1.4.1). */
|
|
2437
|
+
text-decoration: line-through;
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
:where(.date-time-picker-time) {
|
|
2441
|
+
display: flex;
|
|
2442
|
+
flex-wrap: wrap;
|
|
2443
|
+
align-items: center;
|
|
2444
|
+
gap: var(--lily-space-xs);
|
|
2445
|
+
margin-block-start: var(--lily-space-sm);
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
:where(.date-time-picker-time-label) {
|
|
2449
|
+
font-size: 0.8125em;
|
|
2450
|
+
color: var(--lily-text-muted);
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
:where(.date-time-picker-time-zone) {
|
|
2454
|
+
display: flex;
|
|
2455
|
+
flex-wrap: wrap;
|
|
2456
|
+
align-items: center;
|
|
2457
|
+
gap: var(--lily-space-xs);
|
|
2458
|
+
margin-block-end: var(--lily-space-sm);
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
:where(.date-time-picker-time-zone-label) {
|
|
2462
|
+
font-size: 0.8125em;
|
|
2463
|
+
color: var(--lily-text-muted);
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
:where(
|
|
2467
|
+
.date-time-picker-hour,
|
|
2468
|
+
.date-time-picker-minute,
|
|
2469
|
+
.date-time-picker-meridiem,
|
|
2470
|
+
.date-time-picker-time-zone-select
|
|
2471
|
+
) {
|
|
2472
|
+
padding: var(--lily-space-xs);
|
|
2473
|
+
font: inherit;
|
|
2474
|
+
color: var(--lily-text);
|
|
2475
|
+
background-color: var(--lily-surface);
|
|
2476
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
2477
|
+
border-radius: var(--lily-radius-sm);
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
:where(.date-time-picker-shortcuts) {
|
|
2481
|
+
display: flex;
|
|
2482
|
+
flex-wrap: wrap;
|
|
2483
|
+
gap: var(--lily-space-xs);
|
|
2484
|
+
margin-block-start: var(--lily-space-sm);
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
:where(.date-time-picker-footer) {
|
|
2488
|
+
display: flex;
|
|
2489
|
+
justify-content: flex-end;
|
|
2490
|
+
gap: var(--lily-space-xs);
|
|
2491
|
+
margin-block-start: var(--lily-space-sm);
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
/* Combobox / listbox / autosuggest — non-native variant of <select>. */
|
|
2495
|
+
:where(.combobox, .listbox, .autosuggest) {
|
|
2496
|
+
background-color: var(--lily-surface);
|
|
2497
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
2498
|
+
border-radius: var(--lily-radius-md);
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
/* ==========================================================================
|
|
2502
|
+
* Editorial typography
|
|
2503
|
+
* --------------------------------------------------------------------------
|
|
2504
|
+
* Headlines, body text, byline, blockquote, code — the long-form reading
|
|
2505
|
+
* primitives. Headlines use clamp() so they shrink on narrow viewports
|
|
2506
|
+
* without media queries.
|
|
2507
|
+
* ====================================================================== */
|
|
2508
|
+
|
|
2509
|
+
:where(.headline, .hero-headline, .section-heading) {
|
|
2510
|
+
color: var(--lily-text);
|
|
2511
|
+
font-family: var(--lily-font-body);
|
|
2512
|
+
font-weight: 700;
|
|
2513
|
+
line-height: 1.15;
|
|
2514
|
+
margin: 0 0 0.5rem 0;
|
|
2515
|
+
}
|
|
2516
|
+
:where(.headline) {
|
|
2517
|
+
font-size: clamp(1.5rem, 3vw, 2.25rem);
|
|
2518
|
+
}
|
|
2519
|
+
:where(.hero-headline) {
|
|
2520
|
+
font-size: clamp(2rem, 5vw, 3.5rem);
|
|
2521
|
+
}
|
|
2522
|
+
:where(.section-heading) {
|
|
2523
|
+
font-size: clamp(1.25rem, 2vw, 1.75rem);
|
|
2524
|
+
}
|
|
2525
|
+
/* Body text — 1.6 line-height (sweet spot for reading). */
|
|
2526
|
+
:where(.body-text) {
|
|
2527
|
+
line-height: 1.6;
|
|
2528
|
+
color: var(--lily-text);
|
|
2529
|
+
}
|
|
2530
|
+
/* Byline — author / date line under a headline. */
|
|
2531
|
+
:where(.byline) {
|
|
2532
|
+
color: var(--lily-text-muted);
|
|
2533
|
+
font-size: 0.875rem;
|
|
2534
|
+
}
|
|
2535
|
+
/* Blockquote — primary-coloured rail + italic body. */
|
|
2536
|
+
:where(.blockquote) {
|
|
2537
|
+
margin: 1rem 0;
|
|
2538
|
+
padding: 0.5rem 1rem;
|
|
2539
|
+
border-inline-start: 0.25rem solid var(--color-primary);
|
|
2540
|
+
color: var(--lily-text);
|
|
2541
|
+
font-style: italic;
|
|
2542
|
+
}
|
|
2543
|
+
/* End-notes / related content — top-bordered section at the foot. */
|
|
2544
|
+
:where(.end-notes, .related-content) {
|
|
2545
|
+
margin-top: 2rem;
|
|
2546
|
+
padding-top: 1rem;
|
|
2547
|
+
border-top: var(--border) solid var(--lily-border);
|
|
2548
|
+
}
|
|
2549
|
+
/* Caption / footnote / citation — small muted text. */
|
|
2550
|
+
:where(.caption, .footnote, .citation) {
|
|
2551
|
+
font-size: 0.875rem;
|
|
2552
|
+
color: var(--lily-text-muted);
|
|
2553
|
+
}
|
|
2554
|
+
/* KBD — keyboard key glyph; thicker bottom border simulates the keytop. */
|
|
2555
|
+
:where(.kbd) {
|
|
2556
|
+
display: inline-block;
|
|
2557
|
+
padding: 0.125rem 0.4rem;
|
|
2558
|
+
font-family: var(--lily-font-mono);
|
|
2559
|
+
font-size: 0.85em;
|
|
2560
|
+
background-color: var(--lily-surface-alt);
|
|
2561
|
+
border: var(--border) solid var(--lily-border-strong);
|
|
2562
|
+
border-bottom-width: 2px;
|
|
2563
|
+
border-radius: var(--lily-radius-sm);
|
|
2564
|
+
}
|
|
2565
|
+
/* Inline code — slight background tint + monospaced font. */
|
|
2566
|
+
:where(.code) {
|
|
2567
|
+
font-family: var(--lily-font-mono);
|
|
2568
|
+
padding: 0.1em 0.3em;
|
|
2569
|
+
background-color: var(--lily-surface-alt);
|
|
2570
|
+
border-radius: var(--lily-radius-sm);
|
|
2571
|
+
font-size: 0.9em;
|
|
2572
|
+
}
|
|
2573
|
+
/* Code block — full-width block with horizontal scroll. */
|
|
2574
|
+
:where(.code-block) {
|
|
2575
|
+
display: block;
|
|
2576
|
+
padding: 1rem;
|
|
2577
|
+
background-color: var(--color-neutral);
|
|
2578
|
+
color: var(--color-neutral-content);
|
|
2579
|
+
font-family: var(--lily-font-mono);
|
|
2580
|
+
border-radius: var(--lily-radius-md);
|
|
2581
|
+
overflow-x: auto;
|
|
2582
|
+
white-space: pre;
|
|
2583
|
+
}
|
|
2584
|
+
/* Inset text — left-railed callout for "Important" content
|
|
2585
|
+
(GOV.UK / NHS pattern). */
|
|
2586
|
+
:where(.inset-text) {
|
|
2587
|
+
padding: 0.75rem 1rem;
|
|
2588
|
+
border-inline-start: 0.25rem solid var(--color-primary);
|
|
2589
|
+
background-color: var(--lily-surface-alt);
|
|
2590
|
+
}
|
|
2591
|
+
/* Generic character — monospaced single-glyph display. */
|
|
2592
|
+
:where(.character) {
|
|
2593
|
+
font-family: var(--lily-font-mono);
|
|
2594
|
+
}
|
|
2595
|
+
/* Clamp-text — truncate to N lines (controlled by --lily-clamp-lines). */
|
|
2596
|
+
:where(.clamp-text) {
|
|
2597
|
+
display: -webkit-box;
|
|
2598
|
+
-webkit-line-clamp: var(--lily-clamp-lines, 3);
|
|
2599
|
+
line-clamp: var(--lily-clamp-lines, 3);
|
|
2600
|
+
-webkit-box-orient: vertical;
|
|
2601
|
+
overflow: hidden;
|
|
2602
|
+
}
|
|
2603
|
+
/* Screen-reader-only — visually hidden but available to AT. The
|
|
2604
|
+
classic clip-rect pattern (works in every screen reader). */
|
|
2605
|
+
:where(.screen-reader-span) {
|
|
2606
|
+
position: absolute;
|
|
2607
|
+
width: 1px;
|
|
2608
|
+
height: 1px;
|
|
2609
|
+
padding: 0;
|
|
2610
|
+
margin: -1px;
|
|
2611
|
+
overflow: hidden;
|
|
2612
|
+
clip: rect(0, 0, 0, 0);
|
|
2613
|
+
white-space: nowrap;
|
|
2614
|
+
border: 0;
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
/* ==========================================================================
|
|
2618
|
+
* Hero, figure, photo, media
|
|
2619
|
+
* ====================================================================== */
|
|
2620
|
+
|
|
2621
|
+
/* Hero block — primary-filled banner with centred content. clamp() pad
|
|
2622
|
+
scales vertically across viewport sizes. */
|
|
2623
|
+
:where(.hero) {
|
|
2624
|
+
display: block;
|
|
2625
|
+
padding: clamp(2rem, 5vw, 4rem) 1rem;
|
|
2626
|
+
background-color: var(--color-primary);
|
|
2627
|
+
color: var(--color-primary-content);
|
|
2628
|
+
border-radius: var(--lily-radius-lg);
|
|
2629
|
+
text-align: center;
|
|
2630
|
+
}
|
|
2631
|
+
/* Figure — centred block with vertical margin. */
|
|
2632
|
+
:where(.figure) {
|
|
2633
|
+
margin: 1rem 0;
|
|
2634
|
+
text-align: center;
|
|
2635
|
+
}
|
|
2636
|
+
/* Feature photo — responsive lead image. */
|
|
2637
|
+
:where(.feature-photo) {
|
|
2638
|
+
display: block;
|
|
2639
|
+
width: 100%;
|
|
2640
|
+
height: auto;
|
|
2641
|
+
border-radius: var(--lily-radius-md);
|
|
2642
|
+
}
|
|
2643
|
+
/* Photo pack — responsive grid of thumbnails. */
|
|
2644
|
+
:where(.photo-pack) {
|
|
2645
|
+
display: grid;
|
|
2646
|
+
grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
|
|
2647
|
+
gap: 0.5rem;
|
|
2648
|
+
}
|
|
2649
|
+
/* Generic image — responsive block image. */
|
|
2650
|
+
:where(.image) {
|
|
2651
|
+
max-width: 100%;
|
|
2652
|
+
height: auto;
|
|
2653
|
+
display: block;
|
|
2654
|
+
}
|
|
2655
|
+
/* QR / barcode / signature — frame them as a labelled tile. */
|
|
2656
|
+
:where(.qr-code-image, .barcode-image, .signature-pad) {
|
|
2657
|
+
display: inline-block;
|
|
2658
|
+
background-color: var(--lily-surface);
|
|
2659
|
+
border: var(--border) solid var(--lily-border);
|
|
2660
|
+
border-radius: var(--lily-radius-md);
|
|
2661
|
+
padding: 0.5rem;
|
|
2662
|
+
}
|
|
2663
|
+
/* Signature pad — drawable surface; crosshair cursor signals input. */
|
|
2664
|
+
:where(.signature-pad) {
|
|
2665
|
+
min-height: 8rem;
|
|
2666
|
+
cursor: crosshair;
|
|
2667
|
+
}
|
|
2668
|
+
/* Video player — responsive black-letterboxed frame. */
|
|
2669
|
+
:where(.video-player) {
|
|
2670
|
+
display: block;
|
|
2671
|
+
width: 100%;
|
|
2672
|
+
max-width: 100%;
|
|
2673
|
+
border-radius: var(--lily-radius-md);
|
|
2674
|
+
/* Video chrome is black in every theme; pair the text colour with
|
|
2675
|
+
it here rather than inheriting the theme's (possibly dark)
|
|
2676
|
+
content colour onto a black surface. */
|
|
2677
|
+
background-color: black;
|
|
2678
|
+
color: white;
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
/* ==========================================================================
|
|
2682
|
+
* Mockups & pictograms
|
|
2683
|
+
* --------------------------------------------------------------------------
|
|
2684
|
+
* Device frames for screenshots / illustrations — browser, phone, tablet,
|
|
2685
|
+
* laptop, watch, shell window. All share the same rounded-outline frame
|
|
2686
|
+
* baseline; specific frames override the radius / border-width.
|
|
2687
|
+
* ====================================================================== */
|
|
2688
|
+
|
|
2689
|
+
:where(
|
|
2690
|
+
.mockup-browser,
|
|
2691
|
+
.mockup-window,
|
|
2692
|
+
.mockup-shell,
|
|
2693
|
+
.mockup-phone-portrait,
|
|
2694
|
+
.mockup-phone-landscape,
|
|
2695
|
+
.mockup-tablet-portrait,
|
|
2696
|
+
.mockup-tablet-landscape,
|
|
2697
|
+
.mockup-laptop,
|
|
2698
|
+
.mockup-watch
|
|
2699
|
+
) {
|
|
2700
|
+
display: block;
|
|
2701
|
+
background-color: var(--lily-surface);
|
|
2702
|
+
border: 2px solid var(--color-neutral);
|
|
2703
|
+
border-radius: var(--lily-radius-lg);
|
|
2704
|
+
overflow: hidden;
|
|
2705
|
+
box-shadow: var(--lily-shadow-md);
|
|
2706
|
+
}
|
|
2707
|
+
/* Mockup shell — terminal window; dark neutral fill + mono font. */
|
|
2708
|
+
:where(.mockup-shell) {
|
|
2709
|
+
background-color: var(--color-neutral);
|
|
2710
|
+
color: var(--color-neutral-content);
|
|
2711
|
+
font-family: var(--lily-font-mono);
|
|
2712
|
+
padding: 1rem;
|
|
2713
|
+
}
|
|
2714
|
+
/* Phones — heavier bezel (6px) and more rounded corners. */
|
|
2715
|
+
:where(.mockup-phone-portrait, .mockup-phone-landscape) {
|
|
2716
|
+
border-radius: 1.5rem;
|
|
2717
|
+
border-width: 6px;
|
|
2718
|
+
}
|
|
2719
|
+
/* Smartwatch — chunky bezel (4px) and pill radius. */
|
|
2720
|
+
:where(.mockup-watch) {
|
|
2721
|
+
border-radius: 1rem;
|
|
2722
|
+
border-width: 4px;
|
|
2723
|
+
}
|
|
2724
|
+
/* Pictogram — stacked icon + caption, centred. */
|
|
2725
|
+
:where(.pictogram) {
|
|
2726
|
+
display: inline-flex;
|
|
2727
|
+
flex-direction: column;
|
|
2728
|
+
align-items: center;
|
|
2729
|
+
gap: 0.5rem;
|
|
2730
|
+
padding: 1rem;
|
|
2731
|
+
text-align: center;
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
/* ==========================================================================
|
|
2735
|
+
* Charts (containers only — content supplied by consumer)
|
|
2736
|
+
* --------------------------------------------------------------------------
|
|
2737
|
+
* Headless: Lily provides the frame + a 6-colour palette as custom
|
|
2738
|
+
* properties. The consumer's chart library (D3, Chart.js, ECharts, etc.)
|
|
2739
|
+
* reads `var(--lily-chart-color-1..6)` for its series colours.
|
|
2740
|
+
* ====================================================================== */
|
|
2741
|
+
|
|
2742
|
+
:where(
|
|
2743
|
+
.area-chart,
|
|
2744
|
+
.bar-chart,
|
|
2745
|
+
.column-chart,
|
|
2746
|
+
.line-chart,
|
|
2747
|
+
.scatter-chart,
|
|
2748
|
+
.sparkline,
|
|
2749
|
+
.tile-map,
|
|
2750
|
+
.graphic-block
|
|
2751
|
+
) {
|
|
2752
|
+
display: block;
|
|
2753
|
+
background-color: var(--lily-surface);
|
|
2754
|
+
border-radius: var(--lily-radius-md);
|
|
2755
|
+
padding: 1rem;
|
|
2756
|
+
color: var(--lily-text);
|
|
2757
|
+
/* Six-colour palette — the consumer's chart library picks these up. */
|
|
2758
|
+
--lily-chart-color-1: var(--color-primary);
|
|
2759
|
+
--lily-chart-color-2: var(--color-secondary);
|
|
2760
|
+
--lily-chart-color-3: var(--color-accent);
|
|
2761
|
+
--lily-chart-color-4: var(--color-info);
|
|
2762
|
+
--lily-chart-color-5: var(--color-success);
|
|
2763
|
+
--lily-chart-color-6: var(--color-warning);
|
|
2764
|
+
}
|
|
2765
|
+
/* Sparkline — small inline chart; no padding. */
|
|
2766
|
+
:where(.sparkline) {
|
|
2767
|
+
padding: 0;
|
|
2768
|
+
height: 1.5rem;
|
|
2769
|
+
width: 6rem;
|
|
2770
|
+
display: inline-block;
|
|
2771
|
+
}
|
|
2772
|
+
/* Graphic block — bordered chart container. */
|
|
2773
|
+
:where(.graphic-block) {
|
|
2774
|
+
border: var(--border) solid var(--lily-border);
|
|
2775
|
+
}
|
|
2776
|
+
|
|
2777
|
+
/* ==========================================================================
|
|
2778
|
+
* Scrolling, splits, resize
|
|
2779
|
+
* ====================================================================== */
|
|
2780
|
+
|
|
2781
|
+
/* Scroll area — capped at 20rem, auto-overflow. */
|
|
2782
|
+
:where(.scroll-area) {
|
|
2783
|
+
overflow: auto;
|
|
2784
|
+
max-height: 20rem;
|
|
2785
|
+
}
|
|
2786
|
+
/* Horizontal scroller — flex row that overflows on x. */
|
|
2787
|
+
:where(.horizontal-scroller) {
|
|
2788
|
+
overflow-x: auto;
|
|
2789
|
+
display: flex;
|
|
2790
|
+
gap: 0.5rem;
|
|
2791
|
+
}
|
|
2792
|
+
/* Scroller (Reuters-pattern scrollytelling) — positioning anchor. */
|
|
2793
|
+
:where(.scroller, .scroller-base, .scroller-video) {
|
|
2794
|
+
position: relative;
|
|
2795
|
+
display: block;
|
|
2796
|
+
}
|
|
2797
|
+
/* Custom scrollbar track. */
|
|
2798
|
+
:where(.scroll-bar) {
|
|
2799
|
+
background-color: var(--lily-surface-sunken);
|
|
2800
|
+
border-radius: 999px;
|
|
2801
|
+
height: 0.5rem;
|
|
2802
|
+
}
|
|
2803
|
+
/* Affix — stick to the top of the viewport on scroll. */
|
|
2804
|
+
:where(.affix) {
|
|
2805
|
+
position: sticky;
|
|
2806
|
+
inset-block-start: 0;
|
|
2807
|
+
}
|
|
2808
|
+
/* Visible — IntersectionObserver target; baseline is a visible block. */
|
|
2809
|
+
:where(.visible) {
|
|
2810
|
+
display: block;
|
|
2811
|
+
}
|
|
2812
|
+
/* Resizable — native CSS resize handle (corner). */
|
|
2813
|
+
:where(.resizable) {
|
|
2814
|
+
resize: both;
|
|
2815
|
+
overflow: auto;
|
|
2816
|
+
}
|
|
2817
|
+
/* Split-view + splitter — two-pane horizontal layout. */
|
|
2818
|
+
:where(.split-view) {
|
|
2819
|
+
display: flex;
|
|
2820
|
+
align-items: stretch;
|
|
2821
|
+
gap: 0;
|
|
2822
|
+
}
|
|
2823
|
+
:where(.splitter) {
|
|
2824
|
+
flex: 0 0 0.375rem;
|
|
2825
|
+
background-color: var(--lily-border);
|
|
2826
|
+
cursor: col-resize;
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
/* ==========================================================================
|
|
2830
|
+
* Misc unique components
|
|
2831
|
+
* ====================================================================== */
|
|
2832
|
+
|
|
2833
|
+
/* Statistic — stacked label + value; value is large and primary-coloured. */
|
|
2834
|
+
:where(.statistic) {
|
|
2835
|
+
display: inline-flex;
|
|
2836
|
+
flex-direction: column;
|
|
2837
|
+
gap: 0.25rem;
|
|
2838
|
+
}
|
|
2839
|
+
:where(.statistic > [data-part="value"]) {
|
|
2840
|
+
font-size: 1.5rem;
|
|
2841
|
+
font-weight: 700;
|
|
2842
|
+
color: var(--color-primary);
|
|
2843
|
+
}
|
|
2844
|
+
/* Watermark — diagonal repeating-line pattern at 8% opacity behind content. */
|
|
2845
|
+
:where(.watermark) {
|
|
2846
|
+
position: absolute;
|
|
2847
|
+
inset: 0;
|
|
2848
|
+
pointer-events: none;
|
|
2849
|
+
opacity: 0.08;
|
|
2850
|
+
background: repeating-linear-gradient(
|
|
2851
|
+
-45deg,
|
|
2852
|
+
var(--lily-text) 0 1px,
|
|
2853
|
+
transparent 1px 8rem
|
|
2854
|
+
);
|
|
2855
|
+
}
|
|
2856
|
+
/* Beach ball (macOS "waiting" indicator) — six-colour conic wheel. */
|
|
2857
|
+
:where(.beach-ball) {
|
|
2858
|
+
display: inline-block;
|
|
2859
|
+
width: 2rem;
|
|
2860
|
+
height: 2rem;
|
|
2861
|
+
border-radius: 50%;
|
|
2862
|
+
background: conic-gradient(
|
|
2863
|
+
var(--color-error),
|
|
2864
|
+
var(--color-warning),
|
|
2865
|
+
var(--color-success),
|
|
2866
|
+
var(--color-info),
|
|
2867
|
+
var(--color-primary),
|
|
2868
|
+
var(--color-error)
|
|
2869
|
+
);
|
|
2870
|
+
animation: lily-spin 2s linear infinite;
|
|
2871
|
+
}
|
|
2872
|
+
/* Diff — side-by-side two-column comparison. */
|
|
2873
|
+
:where(.diff) {
|
|
2874
|
+
display: grid;
|
|
2875
|
+
grid-template-columns: 1fr 1fr;
|
|
2876
|
+
gap: 0.5rem;
|
|
2877
|
+
}
|
|
2878
|
+
/* Addressograph box — paper-form ID label (NHS / hospital pattern). */
|
|
2879
|
+
:where(.addressograph-box) {
|
|
2880
|
+
display: block;
|
|
2881
|
+
padding: 0.75rem 1rem;
|
|
2882
|
+
background-color: var(--lily-surface-alt);
|
|
2883
|
+
border: 2px solid var(--lily-text);
|
|
2884
|
+
font-family: var(--lily-font-mono);
|
|
2885
|
+
line-height: 1.4;
|
|
2886
|
+
}
|
|
2887
|
+
/* Government identifier — dark chrome bar containing an ID number. */
|
|
2888
|
+
:where(.government-identifier) {
|
|
2889
|
+
display: flex;
|
|
2890
|
+
align-items: center;
|
|
2891
|
+
gap: 0.75rem;
|
|
2892
|
+
padding: 0.75rem 1rem;
|
|
2893
|
+
background-color: var(--color-neutral);
|
|
2894
|
+
color: var(--color-neutral-content);
|
|
2895
|
+
}
|
|
2896
|
+
/* Share / signup / CTA panels — alt-surface promo blocks. */
|
|
2897
|
+
:where(.share-page, .newsletter-signup, .call-to-action) {
|
|
2898
|
+
padding: 1rem;
|
|
2899
|
+
background-color: var(--lily-surface-alt);
|
|
2900
|
+
border-radius: var(--lily-radius-md);
|
|
2901
|
+
}
|
|
2902
|
+
/* CTA — override with primary fill so it reads as the page action. */
|
|
2903
|
+
:where(.call-to-action) {
|
|
2904
|
+
background-color: var(--color-primary);
|
|
2905
|
+
color: var(--color-primary-content);
|
|
2906
|
+
}
|
|
2907
|
+
/* Links inside the call-to-action inherit its content colour —
|
|
2908
|
+
otherwise the UA default link blue lands on the primary fill. */
|
|
2909
|
+
:where(.call-to-action) :where(a) {
|
|
2910
|
+
color: inherit;
|
|
2911
|
+
}
|
|
2912
|
+
/* Expander / collapsible / details — boxed disclosure controls. */
|
|
2913
|
+
:where(.expander, .collapsible, .details) {
|
|
2914
|
+
display: block;
|
|
2915
|
+
border: var(--border) solid var(--lily-border);
|
|
2916
|
+
border-radius: var(--lily-radius-md);
|
|
2917
|
+
padding: 0.5rem 1rem;
|
|
2918
|
+
}
|
|
2919
|
+
:where(.details > summary, .expander > summary, .collapsible > summary) {
|
|
2920
|
+
cursor: pointer;
|
|
2921
|
+
font-weight: 600;
|
|
2922
|
+
padding: 0.25rem 0;
|
|
2923
|
+
}
|
|
2924
|
+
/* Carousel — horizontal scroller with snap-points so each slide locks
|
|
2925
|
+
into view as the user swipes. */
|
|
2926
|
+
:where(.carousel) {
|
|
2927
|
+
display: flex;
|
|
2928
|
+
overflow-x: auto;
|
|
2929
|
+
scroll-snap-type: x mandatory;
|
|
2930
|
+
gap: 0.5rem;
|
|
2931
|
+
}
|
|
2932
|
+
:where(.carousel > *) {
|
|
2933
|
+
scroll-snap-align: start;
|
|
2934
|
+
flex: 0 0 auto;
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
/* --- Semantic entities — neutral display blocks. ----------------------- */
|
|
2938
|
+
:where(
|
|
2939
|
+
.person,
|
|
2940
|
+
.organization,
|
|
2941
|
+
.place,
|
|
2942
|
+
.event,
|
|
2943
|
+
.comment,
|
|
2944
|
+
.question,
|
|
2945
|
+
.answer
|
|
2946
|
+
) {
|
|
2947
|
+
display: block;
|
|
2948
|
+
padding: 0.75rem 0;
|
|
2949
|
+
}
|
|
2950
|
+
/* Draft wrapper — dashed border + optional "Draft" pill prefix. */
|
|
2951
|
+
:where(.draft) {
|
|
2952
|
+
border: 1px dashed var(--lily-border-strong);
|
|
2953
|
+
background-color: var(--lily-surface-alt);
|
|
2954
|
+
padding: 1rem;
|
|
2955
|
+
border-radius: var(--lily-radius-md);
|
|
2956
|
+
}
|
|
2957
|
+
:where(.draft[data-status="draft"])::before {
|
|
2958
|
+
content: "Draft";
|
|
2959
|
+
display: inline-block;
|
|
2960
|
+
margin-inline-end: 0.5rem;
|
|
2961
|
+
padding: 0.125rem 0.5rem;
|
|
2962
|
+
background-color: var(--color-warning);
|
|
2963
|
+
color: var(--color-warning-content);
|
|
2964
|
+
border-radius: 999px;
|
|
2965
|
+
font-size: 0.75rem;
|
|
2966
|
+
font-weight: 600;
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
/* Dial — circular gauge driven by --dial-value (0–100). */
|
|
2970
|
+
:where(.dial) {
|
|
2971
|
+
display: inline-block;
|
|
2972
|
+
width: 4rem;
|
|
2973
|
+
height: 4rem;
|
|
2974
|
+
border-radius: 50%;
|
|
2975
|
+
background: conic-gradient(
|
|
2976
|
+
var(--color-primary) calc(var(--dial-value, 0) * 1%),
|
|
2977
|
+
var(--lily-surface-sunken) 0
|
|
2978
|
+
);
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2981
|
+
/* File upload — drop-zone aesthetic: dashed border, alt surface. */
|
|
2982
|
+
:where(.file-upload) {
|
|
2983
|
+
display: block;
|
|
2984
|
+
padding: 1.5rem;
|
|
2985
|
+
background-color: var(--lily-surface-alt);
|
|
2986
|
+
border: 2px dashed var(--lily-border-strong);
|
|
2987
|
+
border-radius: var(--lily-radius-md);
|
|
2988
|
+
text-align: center;
|
|
2989
|
+
cursor: pointer;
|
|
2990
|
+
}
|
|
2991
|
+
/* File manager — surface-coloured frame holding a file list. */
|
|
2992
|
+
:where(.file-manager) {
|
|
2993
|
+
display: block;
|
|
2994
|
+
background-color: var(--lily-surface);
|
|
2995
|
+
border: var(--border) solid var(--lily-border);
|
|
2996
|
+
border-radius: var(--lily-radius-md);
|
|
2997
|
+
padding: 0.5rem;
|
|
2998
|
+
}
|
|
2999
|
+
/* Transfer list — two columns + central button stack. */
|
|
3000
|
+
:where(.transfer-list) {
|
|
3001
|
+
display: grid;
|
|
3002
|
+
grid-template-columns: 1fr auto 1fr;
|
|
3003
|
+
gap: 0.5rem;
|
|
3004
|
+
align-items: center;
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
/* Tour — onboarding card with medium elevation. */
|
|
3008
|
+
:where(.tour) {
|
|
3009
|
+
display: block;
|
|
3010
|
+
background-color: var(--lily-surface);
|
|
3011
|
+
border: var(--border) solid var(--lily-border);
|
|
3012
|
+
border-radius: var(--lily-radius-lg);
|
|
3013
|
+
padding: 1rem;
|
|
3014
|
+
box-shadow: var(--lily-shadow-md);
|
|
3015
|
+
}
|
|
3016
|
+
|
|
3017
|
+
/* Editable text — dashed underline indicates click-to-edit. */
|
|
3018
|
+
:where(.editable) {
|
|
3019
|
+
display: inline-block;
|
|
3020
|
+
padding: 0.125rem 0.25rem;
|
|
3021
|
+
border-bottom: 1px dashed var(--lily-border-strong);
|
|
3022
|
+
cursor: text;
|
|
3023
|
+
}
|
|
3024
|
+
/* Editing state — alt surface + primary underline. */
|
|
3025
|
+
:where(.editable[aria-expanded="true"]) {
|
|
3026
|
+
background-color: var(--lily-surface-alt);
|
|
3027
|
+
border-bottom-color: var(--color-primary);
|
|
3028
|
+
}
|
|
3029
|
+
|
|
3030
|
+
/* Accordion-checkbox — a checkbox that toggles a panel via sibling
|
|
3031
|
+
combinator (no JS needed). */
|
|
3032
|
+
:where(.accordion-checkbox) {
|
|
3033
|
+
display: block;
|
|
3034
|
+
border: var(--border) solid var(--lily-border);
|
|
3035
|
+
border-radius: var(--lily-radius-md);
|
|
3036
|
+
padding: 0.5rem 0.75rem;
|
|
3037
|
+
}
|
|
3038
|
+
:where(.accordion-checkbox-input) {
|
|
3039
|
+
margin-inline-end: 0.5rem;
|
|
3040
|
+
}
|
|
3041
|
+
:where(.accordion-checkbox-panel) {
|
|
3042
|
+
display: none;
|
|
3043
|
+
padding-block-start: 0.5rem;
|
|
3044
|
+
}
|
|
3045
|
+
/* Reveal the panel when the input is checked. */
|
|
3046
|
+
:where(.accordion-checkbox-input:checked ~ .accordion-checkbox-panel) {
|
|
3047
|
+
display: block;
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
/* Icon — 1em square container; sizes with surrounding text. */
|
|
3051
|
+
:where(.icon) {
|
|
3052
|
+
display: inline-flex;
|
|
3053
|
+
align-items: center;
|
|
3054
|
+
justify-content: center;
|
|
3055
|
+
width: 1em;
|
|
3056
|
+
height: 1em;
|
|
3057
|
+
flex: 0 0 auto;
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
/* Emoji — inline glyph; not italicised. */
|
|
3061
|
+
:where(.emoji) {
|
|
3062
|
+
display: inline-block;
|
|
3063
|
+
font-style: normal;
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
/* Slider — primary-filled track based on --slider-value (0–100). */
|
|
3067
|
+
:where(.slider) {
|
|
3068
|
+
display: block;
|
|
3069
|
+
width: 100%;
|
|
3070
|
+
height: 1.5rem;
|
|
3071
|
+
background: linear-gradient(
|
|
3072
|
+
to right,
|
|
3073
|
+
var(--color-primary) calc(var(--slider-value, 50) * 1%),
|
|
3074
|
+
var(--lily-surface-sunken) 0
|
|
3075
|
+
);
|
|
3076
|
+
border-radius: 999px;
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
/* Timer — fixed-width digits so the display doesn't jiggle as it ticks. */
|
|
3080
|
+
:where(.timer) {
|
|
3081
|
+
display: inline-block;
|
|
3082
|
+
font-family: var(--lily-font-mono);
|
|
3083
|
+
font-variant-numeric: tabular-nums;
|
|
3084
|
+
font-weight: 600;
|
|
3085
|
+
}
|
|
3086
|
+
|
|
3087
|
+
/* Medical banner inner boxes — spacing-only override. */
|
|
3088
|
+
:where(.medical-banner-box-for-advice, .medical-banner-box-for-danger) {
|
|
3089
|
+
padding: 0.75rem 1rem;
|
|
3090
|
+
border-radius: var(--lily-radius-md);
|
|
3091
|
+
margin: 0.25rem 0;
|
|
3092
|
+
}
|
|
3093
|
+
|
|
3094
|
+
/* ==========================================================================
|
|
3095
|
+
* Print
|
|
3096
|
+
* --------------------------------------------------------------------------
|
|
3097
|
+
* On paper, transient/floating chrome (skip-link, FAB, toast, tooltip)
|
|
3098
|
+
* is meaningless — hide it. Card-like surfaces drop their drop-shadow
|
|
3099
|
+
* and shift to a high-contrast outline so they're readable in monochrome.
|
|
3100
|
+
* ====================================================================== */
|
|
3101
|
+
@media print {
|
|
3102
|
+
:where(
|
|
3103
|
+
.skip-link,
|
|
3104
|
+
.float-button,
|
|
3105
|
+
.toast,
|
|
3106
|
+
.sonner,
|
|
3107
|
+
.tooltip,
|
|
3108
|
+
.coachmark
|
|
3109
|
+
) {
|
|
3110
|
+
display: none !important;
|
|
3111
|
+
}
|
|
3112
|
+
:where(.card, .panel, .dialog, .alert) {
|
|
3113
|
+
box-shadow: none;
|
|
3114
|
+
border-color: var(--lily-text);
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
|
|
3119
|
+
/* ============================================================================
|
|
3120
|
+
* WCAG 2.2 target-size (minimum) floor — 2.5.8
|
|
3121
|
+
*
|
|
3122
|
+
* Every interactive Lily hook offers a >=24x24 CSS-pixel target. Links
|
|
3123
|
+
* that render as short inline text (a pagination "1", a breadcrumb crumb)
|
|
3124
|
+
* fail the 24px floor under typographic sizing alone, so the link-shaped
|
|
3125
|
+
* hooks become inline-block with a minimum box. :where() keeps specificity
|
|
3126
|
+
* at zero, so any consumer rule still wins. Shared verbatim by all themes.
|
|
3127
|
+
* ========================================================================= */
|
|
3128
|
+
|
|
3129
|
+
:where(.action-link,
|
|
3130
|
+
.back-link,
|
|
3131
|
+
.breadcrumb-list-item > a,
|
|
3132
|
+
.pagination-list-item > a,
|
|
3133
|
+
.contents-list-item > a,
|
|
3134
|
+
.section-list-item > a) {
|
|
3135
|
+
display: inline-block;
|
|
3136
|
+
min-inline-size: 24px;
|
|
3137
|
+
min-block-size: 24px;
|
|
3138
|
+
}
|
|
3139
|
+
|
|
3140
|
+
:where(.pagination-list-item > a) {
|
|
3141
|
+
text-align: center;
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
:where(input:not([type="checkbox"]):not([type="radio"]), select, textarea) {
|
|
3145
|
+
min-block-size: 24px;
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3148
|
+
/* ============================================================================
|
|
3149
|
+
* Overflow guards — narrow-viewport safety, shared verbatim by all themes.
|
|
3150
|
+
*
|
|
3151
|
+
* Content that is intrinsically wider than the viewport scrolls or wraps
|
|
3152
|
+
* within its own box instead of pushing the page wider. Deliberately NOT
|
|
3153
|
+
* `display: block` on <table> — that strips implicit table semantics for
|
|
3154
|
+
* assistive technology; capping width and letting cell content wrap keeps
|
|
3155
|
+
* both the layout and the roles. Proven in the example apps' own
|
|
3156
|
+
* stylesheets before the theme layer took over component styling.
|
|
3157
|
+
* ========================================================================= */
|
|
3158
|
+
|
|
3159
|
+
:where(pre) {
|
|
3160
|
+
max-width: 100%;
|
|
3161
|
+
overflow-x: auto;
|
|
3162
|
+
}
|
|
3163
|
+
|
|
3164
|
+
:where(table) {
|
|
3165
|
+
max-width: 100%;
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
:where(th, td) {
|
|
3169
|
+
overflow-wrap: anywhere;
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
:where(a, code) {
|
|
3173
|
+
overflow-wrap: anywhere;
|
|
3174
|
+
}
|