@sarimarcus/content-sites-ui 0.15.1 → 0.17.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.
@@ -0,0 +1,629 @@
1
+ /* Styles for the /search page, shared by every site: hero, form, filter chips, result cards
2
+ (renderResult.ts), suggestion chips (SearchSuggestions.astro), empty/zero/error states. Colours come from the
3
+ semantic theme roles and fonts from --font-display / --font-body; a site tunes what differs through these
4
+ optional hooks (defaults in brackets):
5
+ --search-page-base [--background] layer under the page's primary glow
6
+ --search-surface [--background] input, chips, result cards
7
+ --search-eyebrow-font [--font-body] hero eyebrow
8
+ --search-input-shadow [black 4% / 6%] resting input shadow (full box-shadow value)
9
+ --search-chip-hover-bg [primary 4% on surface] chip hover background
10
+ --search-chip-active-foreground [--primary-foreground] active chip text
11
+ --search-card-hover-shadow [black 4% / 8%] result card hover shadow (full box-shadow value)
12
+ --search-badge-bg [primary 7%] result card type badge background
13
+ --search-badge-border [primary 14%] result card type badge border
14
+ --search-mark-bg [primary 18%] query highlight in excerpts */
15
+
16
+
17
+ /* ─────────────────────────────────────────────────────────────
18
+ * Page shell
19
+ * ───────────────────────────────────────────────────────────── */
20
+
21
+ .search-page {
22
+ min-height: calc(100vh - 4rem);
23
+ background:
24
+ radial-gradient(
25
+ ellipse 60rem 28rem at 50% -8rem,
26
+ color-mix(in srgb, var(--primary) 7%, transparent) 0%,
27
+ transparent 60%
28
+ ),
29
+ var(--search-page-base, var(--background));
30
+ }
31
+
32
+ /* ─────────────────────────────────────────────────────────────
33
+ * Hero
34
+ * ───────────────────────────────────────────────────────────── */
35
+
36
+ .search-hero {
37
+ padding: 3.5rem 0 2.25rem;
38
+ }
39
+
40
+ .search-hero__eyebrow {
41
+ font-family: var(--search-eyebrow-font, var(--font-body));
42
+ font-size: 0.75rem;
43
+ font-weight: 500;
44
+ letter-spacing: 0.14em;
45
+ text-transform: uppercase;
46
+ color: var(--primary);
47
+ margin: 0 0 0.75rem;
48
+ }
49
+
50
+ .search-hero__heading {
51
+ font-family: var(--font-display);
52
+ font-size: clamp(1.875rem, 4vw, 2.75rem);
53
+ font-weight: 400;
54
+ line-height: 1.1;
55
+ letter-spacing: -0.015em;
56
+ color: var(--foreground);
57
+ margin: 0 0 0.875rem;
58
+ max-width: 32ch;
59
+ }
60
+
61
+ .search-hero__subhead {
62
+ font-family: var(--font-body);
63
+ font-size: 1rem;
64
+ line-height: 1.55;
65
+ color: var(--muted-foreground);
66
+ margin: 0 0 2rem;
67
+ max-width: 52ch;
68
+ }
69
+
70
+ @media (min-width: 768px) {
71
+ .search-hero {
72
+ padding: 4.5rem 0 2.75rem;
73
+ }
74
+
75
+ .search-hero__subhead {
76
+ font-size: 1.0625rem;
77
+ }
78
+ }
79
+
80
+ /* ─────────────────────────────────────────────────────────────
81
+ * Form
82
+ * ───────────────────────────────────────────────────────────── */
83
+
84
+ .search-form {
85
+ position: relative;
86
+ display: flex;
87
+ align-items: center;
88
+ max-width: 44rem;
89
+ margin: 0 0 1.25rem;
90
+ }
91
+
92
+ .search-form__icon {
93
+ position: absolute;
94
+ left: 1.125rem;
95
+ top: 50%;
96
+ transform: translateY(-50%);
97
+ display: flex;
98
+ pointer-events: none;
99
+ color: var(--muted-foreground);
100
+ z-index: 1;
101
+ }
102
+
103
+ .search-form__input {
104
+ width: 100%;
105
+ font-family: var(--font-body);
106
+ font-size: 1.125rem;
107
+ line-height: 1.4;
108
+ color: var(--foreground);
109
+ background: var(--search-surface, var(--background));
110
+ border: 1.5px solid var(--border);
111
+ border-radius: 999px;
112
+ padding: 1rem 3.5rem 1rem 3rem;
113
+ box-shadow: var(--search-input-shadow, 0 1px 2px rgb(0 0 0 / 0.04), 0 4px 12px -4px rgb(0 0 0 / 0.06));
114
+ transition:
115
+ border-color 180ms cubic-bezier(0.4, 0, 0.2, 1),
116
+ box-shadow 180ms cubic-bezier(0.4, 0, 0.2, 1),
117
+ background-color 180ms cubic-bezier(0.4, 0, 0.2, 1);
118
+ appearance: none;
119
+ -webkit-appearance: none;
120
+ }
121
+
122
+ .search-form__input::-webkit-search-decoration,
123
+ .search-form__input::-webkit-search-cancel-button,
124
+ .search-form__input::-webkit-search-results-button,
125
+ .search-form__input::-webkit-search-results-decoration {
126
+ display: none;
127
+ }
128
+
129
+ .search-form__input::placeholder {
130
+ color: var(--muted-foreground);
131
+ opacity: 0.85;
132
+ }
133
+
134
+ .search-form__input:hover {
135
+ border-color: color-mix(in srgb, var(--primary) 30%, var(--border));
136
+ }
137
+
138
+ .search-form__input:focus {
139
+ outline: none;
140
+ background: var(--search-surface, var(--background));
141
+ border-color: var(--primary);
142
+ box-shadow:
143
+ 0 0 0 4px color-mix(in srgb, var(--primary) 14%, transparent),
144
+ 0 4px 16px -2px color-mix(in srgb, var(--primary) 12%, transparent);
145
+ }
146
+
147
+ .search-form__clear {
148
+ position: absolute;
149
+ right: 0.5rem;
150
+ top: 50%;
151
+ transform: translateY(-50%);
152
+ display: flex;
153
+ align-items: center;
154
+ justify-content: center;
155
+ width: 2.75rem;
156
+ height: 2.75rem;
157
+ background: transparent;
158
+ border: none;
159
+ border-radius: 999px;
160
+ color: var(--muted-foreground);
161
+ cursor: pointer;
162
+ transition:
163
+ color 150ms ease,
164
+ background-color 150ms ease;
165
+ }
166
+
167
+ .search-form__clear:hover {
168
+ background: color-mix(in srgb, var(--primary) 10%, transparent);
169
+ color: var(--primary);
170
+ }
171
+
172
+ .search-form__clear:focus-visible {
173
+ outline: 2px solid var(--primary);
174
+ outline-offset: 2px;
175
+ }
176
+
177
+ .search-form__clear[hidden] {
178
+ display: none;
179
+ }
180
+
181
+ @media (min-width: 768px) {
182
+ .search-form__input {
183
+ font-size: 1.1875rem;
184
+ padding: 1.125rem 3.75rem 1.125rem 3.25rem;
185
+ }
186
+
187
+ .search-form__icon {
188
+ left: 1.25rem;
189
+ }
190
+ }
191
+
192
+ /* ─────────────────────────────────────────────────────────────
193
+ * Filter chips
194
+ * ───────────────────────────────────────────────────────────── */
195
+
196
+ .search-filters {
197
+ display: flex;
198
+ flex-wrap: wrap;
199
+ gap: 0.5rem;
200
+ margin-top: 0.5rem;
201
+ }
202
+
203
+ /* An author `display: flex` outranks the UA `[hidden] {display:none}`, so the row stayed visible in the empty state. */
204
+ .search-filters[hidden] {
205
+ display: none;
206
+ }
207
+
208
+ .search-chip {
209
+ display: inline-flex;
210
+ align-items: center;
211
+ gap: 0.4375rem;
212
+ font-family: var(--font-body);
213
+ font-size: 0.875rem;
214
+ font-weight: 500;
215
+ line-height: 1;
216
+ color: var(--foreground);
217
+ background: var(--search-surface, var(--background));
218
+ border: 1px solid var(--border);
219
+ border-radius: 999px;
220
+ padding: 0.5625rem 0.9375rem;
221
+ min-height: 2.75rem;
222
+ cursor: pointer;
223
+ white-space: nowrap;
224
+ transition:
225
+ color 150ms ease,
226
+ background-color 150ms ease,
227
+ border-color 150ms ease,
228
+ box-shadow 150ms ease,
229
+ transform 80ms ease;
230
+ }
231
+
232
+ .search-chip__icon {
233
+ width: 0.9375rem;
234
+ height: 0.9375rem;
235
+ flex-shrink: 0;
236
+ }
237
+
238
+ .search-chip:hover {
239
+ border-color: color-mix(in srgb, var(--primary) 35%, var(--border));
240
+ background: var(--search-chip-hover-bg, color-mix(in srgb, var(--primary) 4%, var(--search-surface, var(--background))));
241
+ }
242
+
243
+ .search-chip:focus-visible {
244
+ outline: 2px solid var(--primary);
245
+ outline-offset: 2px;
246
+ }
247
+
248
+ .search-chip:active {
249
+ transform: translateY(0.5px);
250
+ }
251
+
252
+ .search-chip--active {
253
+ color: var(--search-chip-active-foreground, var(--primary-foreground));
254
+ background: var(--primary);
255
+ border-color: var(--primary);
256
+ box-shadow: 0 1px 2px color-mix(in srgb, var(--primary) 30%, transparent);
257
+ }
258
+
259
+ .search-chip--active:hover {
260
+ background: var(--primary-strong);
261
+ border-color: var(--primary-strong);
262
+ }
263
+
264
+ .search-chip--suggest {
265
+ font-weight: 500;
266
+ }
267
+
268
+ /* Mobile: horizontal scroll for filter row */
269
+ @media (max-width: 640px) {
270
+ .search-filters {
271
+ flex-wrap: nowrap;
272
+ overflow-x: auto;
273
+ overflow-y: hidden;
274
+ margin-left: -1rem;
275
+ margin-right: -1rem;
276
+ padding: 0.25rem 1rem;
277
+ scrollbar-width: none;
278
+ -ms-overflow-style: none;
279
+ }
280
+
281
+ .search-filters::-webkit-scrollbar {
282
+ display: none;
283
+ }
284
+ }
285
+
286
+ /* ─────────────────────────────────────────────────────────────
287
+ * Results region
288
+ * ───────────────────────────────────────────────────────────── */
289
+
290
+ .search-results-region {
291
+ padding: 1rem 0 5rem;
292
+ }
293
+
294
+ .search-state {
295
+ display: block;
296
+ }
297
+
298
+ .search-state[hidden] {
299
+ display: none;
300
+ }
301
+
302
+ .search-state__heading {
303
+ font-family: var(--font-display);
304
+ font-size: 1.375rem;
305
+ font-weight: 500;
306
+ line-height: 1.3;
307
+ color: var(--foreground);
308
+ margin: 1.25rem 0 0.5rem;
309
+ }
310
+
311
+ .search-state__heading strong {
312
+ font-weight: 500;
313
+ color: var(--primary);
314
+ }
315
+
316
+ .search-state__subhead {
317
+ font-family: var(--font-body);
318
+ font-size: 1rem;
319
+ line-height: 1.55;
320
+ color: var(--muted-foreground);
321
+ margin: 0 0 1.5rem;
322
+ max-width: 52ch;
323
+ }
324
+
325
+ .search-state__loading {
326
+ display: inline-flex;
327
+ align-items: center;
328
+ gap: 0.625rem;
329
+ font-family: var(--font-body);
330
+ font-size: 0.9375rem;
331
+ color: var(--muted-foreground);
332
+ padding: 1.5rem 0;
333
+ margin: 0;
334
+ }
335
+
336
+ .search-state__spinner {
337
+ display: inline-block;
338
+ width: 1rem;
339
+ height: 1rem;
340
+ border: 2px solid color-mix(in srgb, var(--primary) 25%, transparent);
341
+ border-top-color: var(--primary);
342
+ border-radius: 50%;
343
+ animation: search-spin 720ms linear infinite;
344
+ }
345
+
346
+ @keyframes search-spin {
347
+ to { transform: rotate(360deg); }
348
+ }
349
+
350
+ /* ─────────────────────────────────────────────────────────────
351
+ * Suggestion + fallback chips
352
+ * ───────────────────────────────────────────────────────────── */
353
+
354
+ .search-suggestions__label,
355
+ .search-fallback__label {
356
+ font-family: var(--font-body);
357
+ font-size: 0.8125rem;
358
+ font-weight: 500;
359
+ letter-spacing: 0.04em;
360
+ text-transform: uppercase;
361
+ color: var(--muted-foreground);
362
+ margin: 1.5rem 0 0.625rem;
363
+ }
364
+
365
+ .search-suggestions {
366
+ display: flex;
367
+ flex-wrap: wrap;
368
+ gap: 0.5rem;
369
+ list-style: none;
370
+ padding: 0;
371
+ margin: 0 0 0.5rem;
372
+ }
373
+
374
+ .search-fallback__links {
375
+ display: flex;
376
+ flex-wrap: wrap;
377
+ gap: 0.875rem;
378
+ list-style: none;
379
+ padding: 0;
380
+ margin: 0.25rem 0 0;
381
+ }
382
+
383
+ .search-fallback__link {
384
+ font-family: var(--font-body);
385
+ font-size: 0.9375rem;
386
+ font-weight: 500;
387
+ color: var(--primary);
388
+ text-decoration: none;
389
+ border-bottom: 1px solid color-mix(in srgb, var(--primary) 30%, transparent);
390
+ padding-bottom: 1px;
391
+ transition: color 150ms ease, border-color 150ms ease;
392
+ }
393
+
394
+ .search-fallback__link:hover {
395
+ color: var(--primary-strong);
396
+ border-bottom-color: var(--primary);
397
+ }
398
+
399
+ .search-fallback__link:focus-visible {
400
+ outline: 2px solid var(--primary);
401
+ outline-offset: 3px;
402
+ border-radius: 2px;
403
+ }
404
+
405
+ /* ─────────────────────────────────────────────────────────────
406
+ * Results heading + grid
407
+ * ───────────────────────────────────────────────────────────── */
408
+
409
+ .search-results__heading {
410
+ font-family: var(--font-body);
411
+ font-size: 0.9375rem;
412
+ color: var(--muted-foreground);
413
+ margin: 1.25rem 0 1.25rem;
414
+ padding-bottom: 0.875rem;
415
+ border-bottom: 1px solid var(--border);
416
+ }
417
+
418
+ .search-results__heading strong {
419
+ color: var(--foreground);
420
+ font-weight: 600;
421
+ }
422
+
423
+ .search-results__list {
424
+ display: grid;
425
+ grid-template-columns: 1fr;
426
+ gap: 1rem;
427
+ list-style: none;
428
+ padding: 0;
429
+ margin: 0;
430
+ align-items: start;
431
+ }
432
+
433
+ @media (min-width: 640px) {
434
+ .search-results__list {
435
+ grid-template-columns: repeat(2, minmax(0, 1fr));
436
+ gap: 1.125rem;
437
+ }
438
+
439
+ /* Lead result: full-width slot, more excerpt */
440
+ .search-results__list > li:first-child {
441
+ grid-column: 1 / -1;
442
+ }
443
+
444
+ .search-results__list > li:first-child .search-card__title {
445
+ font-size: 1.25rem;
446
+ }
447
+
448
+ .search-results__list > li:first-child .search-card__excerpt {
449
+ -webkit-line-clamp: 4;
450
+ line-clamp: 4;
451
+ }
452
+ }
453
+
454
+ @media (min-width: 1024px) {
455
+ .search-results__list {
456
+ grid-template-columns: repeat(3, minmax(0, 1fr));
457
+ gap: 1.25rem;
458
+ }
459
+
460
+ /* Lead result spans 2 of 3 cols — magazine-style pairing with second card */
461
+ .search-results__list > li:first-child {
462
+ grid-column: span 2;
463
+ }
464
+ }
465
+
466
+ .search-results__actions {
467
+ display: flex;
468
+ justify-content: center;
469
+ margin-top: 2.5rem;
470
+ }
471
+
472
+ .search-load-more {
473
+ font-family: var(--font-body);
474
+ font-size: 0.9375rem;
475
+ font-weight: 500;
476
+ color: var(--primary);
477
+ background: transparent;
478
+ border: 1.5px solid color-mix(in srgb, var(--primary) 35%, transparent);
479
+ border-radius: 0.5rem;
480
+ padding: 0.75rem 1.75rem;
481
+ min-height: 2.75rem;
482
+ cursor: pointer;
483
+ transition:
484
+ color 150ms ease,
485
+ background-color 150ms ease,
486
+ border-color 150ms ease;
487
+ }
488
+
489
+ .search-load-more:hover {
490
+ background: color-mix(in srgb, var(--primary) 8%, transparent);
491
+ border-color: var(--primary);
492
+ }
493
+
494
+ .search-load-more:focus-visible {
495
+ outline: 2px solid var(--primary);
496
+ outline-offset: 3px;
497
+ }
498
+
499
+ .search-load-more[hidden] {
500
+ display: none;
501
+ }
502
+
503
+ /* ─────────────────────────────────────────────────────────────
504
+ * Result card
505
+ * ───────────────────────────────────────────────────────────── */
506
+
507
+ .search-card {
508
+ background: var(--search-surface, var(--background));
509
+ border: 1px solid var(--border);
510
+ border-radius: 0.75rem;
511
+ overflow: hidden;
512
+ transition:
513
+ border-color 150ms ease,
514
+ box-shadow 200ms cubic-bezier(0.4, 0, 0.2, 1),
515
+ transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
516
+ }
517
+
518
+ .search-card:hover {
519
+ border-color: color-mix(in srgb, var(--primary) 35%, var(--border));
520
+ box-shadow: var(--search-card-hover-shadow, 0 4px 6px -2px rgb(0 0 0 / 0.04), 0 12px 24px -8px rgb(0 0 0 / 0.08));
521
+ transform: translateY(-1px);
522
+ }
523
+
524
+ .search-card:focus-within {
525
+ border-color: var(--primary);
526
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 16%, transparent);
527
+ }
528
+
529
+ .search-card__link {
530
+ display: block;
531
+ color: inherit;
532
+ text-decoration: none;
533
+ height: 100%;
534
+ padding: 1.125rem 1.25rem 1.1875rem 1.375rem;
535
+ }
536
+
537
+ .search-card__link:focus-visible {
538
+ outline: none;
539
+ }
540
+
541
+ .search-card__body {
542
+ display: flex;
543
+ flex-direction: column;
544
+ }
545
+
546
+ .search-card__badge {
547
+ display: inline-flex;
548
+ align-items: center;
549
+ gap: 0.375rem;
550
+ font-family: var(--font-body);
551
+ font-size: 0.75rem;
552
+ font-weight: 500;
553
+ letter-spacing: 0.03em;
554
+ text-transform: uppercase;
555
+ color: var(--muted-foreground);
556
+ background: var(--search-badge-bg, color-mix(in srgb, var(--primary) 7%, transparent));
557
+ border: 1px solid var(--search-badge-border, color-mix(in srgb, var(--primary) 14%, transparent));
558
+ border-radius: 999px;
559
+ padding: 0.1875rem 0.625rem 0.1875rem 0.5rem;
560
+ margin-bottom: 0.625rem;
561
+ }
562
+
563
+ .search-card__badge-icon {
564
+ width: 0.875rem;
565
+ height: 0.875rem;
566
+ flex-shrink: 0;
567
+ color: var(--primary);
568
+ }
569
+
570
+ .search-card__title {
571
+ font-family: var(--font-display);
572
+ font-size: 1.125rem;
573
+ font-weight: 600;
574
+ line-height: 1.3;
575
+ letter-spacing: -0.005em;
576
+ color: var(--foreground);
577
+ margin: 0 0 0.4375rem;
578
+ transition: color 150ms ease;
579
+ }
580
+
581
+ .search-card__link:hover .search-card__title {
582
+ color: var(--primary);
583
+ }
584
+
585
+ .search-card__excerpt {
586
+ font-family: var(--font-body);
587
+ font-size: 0.875rem;
588
+ line-height: 1.55;
589
+ color: var(--muted-foreground);
590
+ margin: 0;
591
+ display: -webkit-box;
592
+ -webkit-line-clamp: 3;
593
+ -webkit-box-orient: vertical;
594
+ line-clamp: 3;
595
+ overflow: hidden;
596
+ }
597
+
598
+ .search-card__excerpt mark {
599
+ background: var(--search-mark-bg, color-mix(in srgb, var(--primary) 18%, transparent));
600
+ color: var(--foreground);
601
+ padding: 0 0.1875rem;
602
+ border-radius: 0.125rem;
603
+ font-weight: 500;
604
+ }
605
+
606
+ /* ─────────────────────────────────────────────────────────────
607
+ * Reduced motion
608
+ * ───────────────────────────────────────────────────────────── */
609
+
610
+ @media (prefers-reduced-motion: reduce) {
611
+ .search-form__input,
612
+ .search-form__clear,
613
+ .search-chip,
614
+ .search-card,
615
+ .search-card__title,
616
+ .search-load-more,
617
+ .search-fallback__link {
618
+ transition: none !important;
619
+ }
620
+
621
+ .search-card:hover {
622
+ transform: none;
623
+ }
624
+
625
+ .search-state__spinner {
626
+ animation: none;
627
+ border-top-color: var(--primary);
628
+ }
629
+ }
@@ -1,7 +1,8 @@
1
1
  /* Semantic theme roles. A site imports this right after its own `@theme inline` block and sets a value for every
2
2
  role below in its `:root` (`--X` for each `--color-X: var(--X)`), plus `--radius`. A `-tint` value carries its own
3
3
  alpha (a colour-mix), so a site keeps its tint strength; `-emphasis` is the accent-coloured text that reads on a
4
- tint, a card or a muted surface. Runtime vars, so a site's
4
+ tint, a card or a muted surface; `inverse` is the contrasting chrome surface (the footer) with its strong and
5
+ body text. Runtime vars, so a site's
5
6
  `.dark` block and its non-Tailwind sheets (consent, search, map) read the same values. No brand names here:
6
7
  scripts/platform/validate-theme-contract.mjs checks both rules. */
7
8
  @theme inline {
@@ -45,6 +46,9 @@
45
46
  --color-ring: var(--ring);
46
47
  --color-overlay: var(--overlay);
47
48
  --color-overlay-foreground: var(--overlay-foreground);
49
+ --color-inverse: var(--inverse);
50
+ --color-inverse-foreground: var(--inverse-foreground);
51
+ --color-inverse-muted: var(--inverse-muted);
48
52
  --color-badge-on-image: var(--badge-on-image);
49
53
  --color-badge-on-image-foreground: var(--badge-on-image-foreground);
50
54
  --color-chip-on-image: var(--chip-on-image);