@port60/template-kit 0.20.3 → 0.20.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/lib/agentsMd.mjs +10 -0
- package/src/vendor/contract/v1/context.json +1 -1
- package/src/vendor/contract/v1/fonts.json +4 -2
- package/src/vendor/contract/v1/manifest.schema.json +27 -0
- package/src/vendor/contract/v1.lock.json +252 -0
- package/src/vendor/engine/budgets.mjs +1 -1
- package/src/vendor/engine/content-footprint.mjs +9 -9
- package/src/vendor/engine/dialect.mjs +4 -4
- package/src/vendor/validator/behaviors-runtime.js +1 -1
- package/src/vendor/validator/fixture-art.mjs +5 -5
- package/src/vendor/validator/fonts.mjs +13 -3
- package/src/vendor/validator/navigation-highlights.mjs +149 -0
- package/src/vendor/validator/platform-base.css +119 -86
- package/src/vendor/validator/preview.mjs +18 -18
- package/src/vendor/validator/site-context.mjs +18 -6
- package/src/vendor/validator/validate.mjs +83 -44
- package/starter/manifest.json +39 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
/* GENERATED by scripts/build-preview-base.mjs from src/styles/global.css
|
|
1
|
+
/* GENERATED by scripts/build-preview-base.mjs from src/styles/global.css, do not edit. */
|
|
2
2
|
/* ---- PLATFORM BASE (the base/skin split, 2026-07-14) ----
|
|
3
3
|
This stylesheet is the platform's base layer: reset, CSS-variable DECLARATIONS (the theming
|
|
4
|
-
contract
|
|
4
|
+
contract, values here are the platform defaults a template overrides via :root:root), chrome
|
|
5
5
|
mechanics (header/nav/burger/footer/auth), and ALL functional-island styling (donation widget,
|
|
6
6
|
donate page, events/tickets, services, articles, members area, consent, address lookup). A
|
|
7
|
-
template's LOOK does not live here
|
|
7
|
+
template's LOOK does not live here, Classic's is src/templates/default/theme.ts, and every
|
|
8
8
|
template ships a themeCss injected at body-end. Fonts load from the layout <head> (preconnect +
|
|
9
|
-
stylesheet link) instead of a CSS @import
|
|
9
|
+
stylesheet link) instead of a CSS @import, an @import chains render-blocking requests. */
|
|
10
10
|
|
|
11
11
|
:root {
|
|
12
12
|
--bg: #fbf6ef;
|
|
@@ -23,16 +23,16 @@
|
|
|
23
23
|
/* Impact map. --marker = the map pin colour (a deliberate brand accent by default; the live-map
|
|
24
24
|
markers are a zoom-scaling MapLibre circle layer that takes this colour). --map-mode = the
|
|
25
25
|
basemap colour mode read by the map island: `auto` derives the map's paper/ink from the theme
|
|
26
|
-
neutrals below, `light`/`dark`/`muted` force a base. Template-owned
|
|
26
|
+
neutrals below, `light`/`dark`/`muted` force a base. Template-owned, set in theme.css or exposed
|
|
27
27
|
as Appearance knobs; the tenant never edits map colour directly. */
|
|
28
28
|
--marker: var(--accent);
|
|
29
29
|
--map-mode: auto;
|
|
30
|
-
/* flat (default) or globe
|
|
30
|
+
/* flat (default) or globe, MapLibre's own globe projection, a rotatable sphere. */
|
|
31
31
|
--map-projection: flat;
|
|
32
32
|
--line: rgba(31, 42, 51, 0.1);
|
|
33
33
|
--line-strong: rgba(18, 135, 122, 0.28);
|
|
34
34
|
--danger: #c0392b;
|
|
35
|
-
/* Donate/primary CTA hover
|
|
35
|
+
/* Donate/primary CTA hover, a clear GREEN "go" cue, shared by every template (a template may
|
|
36
36
|
override the token, but by default hovering a donate button turns green, not just lighter). */
|
|
37
37
|
--cta-hover: #16a34a;
|
|
38
38
|
--cta-hover-strong: #128a3f;
|
|
@@ -51,10 +51,37 @@ html {
|
|
|
51
51
|
scroll-behavior: smooth;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
/* Arabic-script text (Arabic, Persian, Urdu…) rendered by
|
|
55
|
-
unicode-range scopes
|
|
56
|
-
downloaded only when an Arabic glyph appears.
|
|
57
|
-
|
|
54
|
+
/* Arabic-script text (Arabic, Persian, Urdu…) rendered by the platform's own webfonts, sized to
|
|
55
|
+
match Latin. unicode-range scopes them to Arabic codepoints only, Latin keeps the template's
|
|
56
|
+
faces, and a file is downloaded only when an Arabic glyph appears.
|
|
57
|
+
The platform Arabic face is KFGQPC HAFS Uthmanic Script (King Fahd Glorious Quran Printing
|
|
58
|
+
Complex, self-hosted under public/fonts/, licence beside it, never modified). It ships one weight,
|
|
59
|
+
so IBM Plex Sans Arabic stays declared behind it for bold and for any glyph HAFS lacks.
|
|
60
|
+
Template font slots name both faces first too (engine/fonts.ts ARABIC_FACES), so a template's own
|
|
61
|
+
body font never drops them; a tenant who picks an Arabic family for a slot keeps their choice.
|
|
62
|
+
To swap the platform face: replace the file and src here, and the name in fonts.ts. */
|
|
63
|
+
@font-face {
|
|
64
|
+
font-family: 'KFGQPC HAFS Uthmanic Script';
|
|
65
|
+
font-style: normal;
|
|
66
|
+
font-weight: 400;
|
|
67
|
+
font-display: swap;
|
|
68
|
+
size-adjust: 130%;
|
|
69
|
+
src: url('/fonts/kfgqpc-hafs-uthmanic-script/UthmanicHafs_V22.woff2') format('woff2');
|
|
70
|
+
unicode-range: U+0600-06FF, U+0750-077F, U+0870-08FF, U+FB50-FDFF, U+FE70-FEFF, U+200C-200D;
|
|
71
|
+
}
|
|
72
|
+
/* A platform-hosted CATALOGUE family: not on the default Arabic stack, loaded only when a tenant
|
|
73
|
+
picks it for a font slot. A Quranic Nastaliq face (the Indo-Pak mushaf style): Arabic and Quran
|
|
74
|
+
text render, but Urdu prose letters come out as dotted circles in Chrome, so it is not an Urdu
|
|
75
|
+
body font. size-adjust 130%: 120% sat level with the Latin x-height, the owner reads Arabic more easily a step larger. */
|
|
76
|
+
@font-face {
|
|
77
|
+
font-family: 'KFGQPC Nastaleeq';
|
|
78
|
+
font-style: normal;
|
|
79
|
+
font-weight: 400;
|
|
80
|
+
font-display: swap;
|
|
81
|
+
size-adjust: 130%;
|
|
82
|
+
src: url('/fonts/kfgqpc-nastaleeq/KFGQPCNastaleeq-Regular.woff2') format('woff2');
|
|
83
|
+
unicode-range: U+0600-06FF, U+0750-077F, U+0870-08FF, U+FB50-FDFF, U+FE70-FEFF, U+200C-200D;
|
|
84
|
+
}
|
|
58
85
|
@font-face {
|
|
59
86
|
font-family: 'IBM Plex Sans Arabic';
|
|
60
87
|
font-style: normal;
|
|
@@ -77,7 +104,7 @@ html {
|
|
|
77
104
|
body {
|
|
78
105
|
margin: 0;
|
|
79
106
|
min-width: 320px;
|
|
80
|
-
font-family: 'IBM Plex Sans Arabic', 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
107
|
+
font-family: 'KFGQPC HAFS Uthmanic Script', 'IBM Plex Sans Arabic', 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
81
108
|
color: var(--ink);
|
|
82
109
|
background: var(--bg); /* decoration (Classic's radial washes) is the template theme's job */
|
|
83
110
|
}
|
|
@@ -92,8 +119,8 @@ img {
|
|
|
92
119
|
display: block;
|
|
93
120
|
}
|
|
94
121
|
|
|
95
|
-
/* Typography (heading scale/family, paragraph rhythm) is TEMPLATE territory
|
|
96
|
-
templates/default/theme.ts for Classic's. The base deliberately styles no bare h1
|
|
122
|
+
/* Typography (heading scale/family, paragraph rhythm) is TEMPLATE territory, see
|
|
123
|
+
templates/default/theme.ts for Classic's. The base deliberately styles no bare h1-h4/p. */
|
|
97
124
|
|
|
98
125
|
input, button, textarea, select {
|
|
99
126
|
font: inherit;
|
|
@@ -123,7 +150,7 @@ input:focus {
|
|
|
123
150
|
|
|
124
151
|
/* THE CONTENT SEAM. `.container` (contained) and `.full` (edge-to-edge) are the layout intents every
|
|
125
152
|
platform page renders through, and the contract a template fills to place content its way: a template
|
|
126
|
-
STYLES these
|
|
153
|
+
STYLES these, and overrides `--container` for width, to match its own sections. A template must
|
|
127
154
|
NEVER build a parallel content container (a class sized off `--container`); platform pages stay on
|
|
128
155
|
`.container`, so a second container makes them drift from the template's sections. The publish-time
|
|
129
156
|
validator enforces this. A template that leaves the seam alone inherits these platform defaults. */
|
|
@@ -132,7 +159,7 @@ input:focus {
|
|
|
132
159
|
margin: 0 auto;
|
|
133
160
|
}
|
|
134
161
|
|
|
135
|
-
/* Full-bleed intent
|
|
162
|
+
/* Full-bleed intent, edge-to-edge regardless of the container it sits in (a hero image, a colour
|
|
136
163
|
band). Templates restyle it freely; the default breaks out to the viewport width. */
|
|
137
164
|
.full {
|
|
138
165
|
width: 100vw;
|
|
@@ -212,7 +239,7 @@ input:focus {
|
|
|
212
239
|
display: flex;
|
|
213
240
|
align-items: center;
|
|
214
241
|
gap: 0.35rem;
|
|
215
|
-
flex-wrap: nowrap; /* never let items drop to a second line
|
|
242
|
+
flex-wrap: nowrap; /* never let items drop to a second line, compact (below) then burger */
|
|
216
243
|
}
|
|
217
244
|
|
|
218
245
|
.site-nav a {
|
|
@@ -233,7 +260,7 @@ input:focus {
|
|
|
233
260
|
box-shadow: 0 10px 22px rgba(239, 96, 68, 0.26);
|
|
234
261
|
}
|
|
235
262
|
|
|
236
|
-
/* Donate, the Port60 ID sign-in, and the account pill share one exact size
|
|
263
|
+
/* Donate, the Port60 ID sign-in, and the account pill share one exact size, they sit side by
|
|
237
264
|
side, so any height/padding drift between them reads as misalignment. The sign-in/account pair
|
|
238
265
|
is UNSCOPED: they are the member_menu ISLAND's chrome, which must look right inside ANY
|
|
239
266
|
template's nav (artifact layouts don't use .site-nav). */
|
|
@@ -256,7 +283,7 @@ input:focus {
|
|
|
256
283
|
box-shadow: 0 10px 22px rgba(22, 163, 74, 0.3);
|
|
257
284
|
}
|
|
258
285
|
|
|
259
|
-
/* Services dropdown
|
|
286
|
+
/* Services dropdown, populated client-side from the published services. */
|
|
260
287
|
.site-nav .nav-dropdown {
|
|
261
288
|
position: relative;
|
|
262
289
|
display: inline-flex;
|
|
@@ -297,9 +324,9 @@ input:focus {
|
|
|
297
324
|
background: var(--bg-tint);
|
|
298
325
|
}
|
|
299
326
|
|
|
300
|
-
/* The port60 ID sign-in button
|
|
327
|
+
/* The port60 ID sign-in button, the PLATFORM identity brand, deliberately constant across every
|
|
301
328
|
tenant site and template (the "Sign in with Google" pattern): port60 navy + cyan, independent
|
|
302
|
-
of the site palette. The hosted widget it opens offers both sign-in and register. Unscoped
|
|
329
|
+
of the site palette. The hosted widget it opens offers both sign-in and register. Unscoped ,
|
|
303
330
|
island chrome, identical in any template's nav. */
|
|
304
331
|
.nav-p60-signin.nav-p60-signin {
|
|
305
332
|
display: inline-flex;
|
|
@@ -355,9 +382,9 @@ input:focus {
|
|
|
355
382
|
height: 1.25rem;
|
|
356
383
|
}
|
|
357
384
|
|
|
358
|
-
/* Members account pill (signed in)
|
|
385
|
+
/* Members account pill (signed in), a clear "this is your account" affordance, weighted between
|
|
359
386
|
plain nav links and the Donate CTA. The menu anchors right (it's the last nav item).
|
|
360
|
-
`.open` mirrors hover/focus for touch. Unscoped
|
|
387
|
+
`.open` mirrors hover/focus for touch. Unscoped, island chrome, identical in any template's
|
|
361
388
|
nav: the wrapper carries its own positioning anchor and menu-link styling so the dropdown works
|
|
362
389
|
without .site-nav around it. */
|
|
363
390
|
.nav-account {
|
|
@@ -405,7 +432,7 @@ input:focus {
|
|
|
405
432
|
display: flex;
|
|
406
433
|
}
|
|
407
434
|
/* Artifact-template mobile panels (the layout behaviour API: #site-nav gains .open): the account
|
|
408
|
-
menu flows INLINE like any expanded nav group
|
|
435
|
+
menu flows INLINE like any expanded nav group, never a floating card half off the screen.
|
|
409
436
|
Keyed on the .open state the burger sets, so desktop hover/dropdowns are untouched. */
|
|
410
437
|
#site-nav.open .nav-account {
|
|
411
438
|
display: block;
|
|
@@ -463,7 +490,7 @@ input:focus {
|
|
|
463
490
|
background: var(--bg-tint);
|
|
464
491
|
}
|
|
465
492
|
|
|
466
|
-
/* Optional tenant footer mark (branding.footerLogoUrl)
|
|
493
|
+
/* Optional tenant footer mark (branding.footerLogoUrl), height-constrained like the header logo. */
|
|
467
494
|
.footer-logo { display: block; height: 46px; width: auto; max-width: 220px; object-fit: contain; margin-bottom: 0.9rem; }
|
|
468
495
|
|
|
469
496
|
.site-footer {
|
|
@@ -501,7 +528,7 @@ input:focus {
|
|
|
501
528
|
color: rgba(93, 107, 120, 0.8);
|
|
502
529
|
}
|
|
503
530
|
|
|
504
|
-
/* Footer socials
|
|
531
|
+
/* Footer socials, tenant's social links, rendered by the template (ours: here). Variable-driven so
|
|
505
532
|
each theme tints them. */
|
|
506
533
|
.footer-socials {
|
|
507
534
|
display: flex;
|
|
@@ -529,10 +556,10 @@ input:focus {
|
|
|
529
556
|
height: 1.15rem;
|
|
530
557
|
}
|
|
531
558
|
|
|
532
|
-
/* ---------- shared bits (.eyebrow/.card/.section-heading are template-owned
|
|
559
|
+
/* ---------- shared bits (.eyebrow/.card/.section-heading are template-owned, Classic's live in
|
|
533
560
|
templates/default/theme.ts; .button stays here because the islands depend on it) ---------- */
|
|
534
561
|
|
|
535
|
-
/* A kicker may BE a link (the archive's section kicker doubles as the way back)
|
|
562
|
+
/* A kicker may BE a link (the archive's section kicker doubles as the way back), it keeps the
|
|
536
563
|
kicker type treatment whatever the template; hover reveals the affordance. */
|
|
537
564
|
a.eyebrow {
|
|
538
565
|
text-decoration: none;
|
|
@@ -587,10 +614,10 @@ a.eyebrow:hover {
|
|
|
587
614
|
border-color: var(--line);
|
|
588
615
|
}
|
|
589
616
|
|
|
590
|
-
/* ---------- Forms (schema-driven form renderer
|
|
617
|
+
/* ---------- Forms (schema-driven form renderer, components/FormRenderer + DateField) ----------
|
|
591
618
|
Themed entirely from the site tokens so a form looks native on any template. The one thing the base
|
|
592
619
|
input{} rule gets wrong for us is the checkbox (it forces width:100%, stretching the box across the
|
|
593
|
-
row)
|
|
620
|
+
row), pinned below, which is what fixes the check-box alignment. */
|
|
594
621
|
|
|
595
622
|
.p60-form {
|
|
596
623
|
max-width: 640px;
|
|
@@ -676,7 +703,7 @@ textarea.p60-form-control {
|
|
|
676
703
|
font-size: 0.9rem;
|
|
677
704
|
}
|
|
678
705
|
|
|
679
|
-
/* Checkbox rows
|
|
706
|
+
/* Checkbox rows, pin the box small and top-align it with the first line of the label text. */
|
|
680
707
|
.p60-form-check {
|
|
681
708
|
display: flex;
|
|
682
709
|
align-items: flex-start;
|
|
@@ -704,7 +731,7 @@ textarea.p60-form-control {
|
|
|
704
731
|
font-style: italic;
|
|
705
732
|
}
|
|
706
733
|
|
|
707
|
-
/* MULTISELECT checkbox list / CHOICE radio list
|
|
734
|
+
/* MULTISELECT checkbox list / CHOICE radio list, vertical lists reusing the aligned check-row. */
|
|
708
735
|
.p60-form-checklist,
|
|
709
736
|
.p60-form-radios {
|
|
710
737
|
display: flex;
|
|
@@ -718,7 +745,7 @@ textarea.p60-form-control {
|
|
|
718
745
|
margin-bottom: 0;
|
|
719
746
|
}
|
|
720
747
|
|
|
721
|
-
/* Searchable multi-select dropdown (MultiSelectDropdown)
|
|
748
|
+
/* Searchable multi-select dropdown (MultiSelectDropdown), the "pick many from a long list" widget. */
|
|
722
749
|
.p60-ms {
|
|
723
750
|
position: relative;
|
|
724
751
|
}
|
|
@@ -840,7 +867,7 @@ textarea.p60-form-control {
|
|
|
840
867
|
font-size: 0.9rem;
|
|
841
868
|
}
|
|
842
869
|
|
|
843
|
-
/* ---- Custom desktop date picker (DateField)
|
|
870
|
+
/* ---- Custom desktop date picker (DateField), native <input type=date> is used on touch ---- */
|
|
844
871
|
.p60-date {
|
|
845
872
|
position: relative;
|
|
846
873
|
}
|
|
@@ -971,7 +998,7 @@ textarea.p60-form-control {
|
|
|
971
998
|
background: transparent;
|
|
972
999
|
}
|
|
973
1000
|
|
|
974
|
-
/* (hero / impact / band
|
|
1001
|
+
/* (hero / impact / band, the home page's Classic presentation, live in templates/default/theme.ts) */
|
|
975
1002
|
|
|
976
1003
|
/* ---------- donation widget ---------- */
|
|
977
1004
|
|
|
@@ -985,7 +1012,7 @@ textarea.p60-form-control {
|
|
|
985
1012
|
gap: 1rem;
|
|
986
1013
|
}
|
|
987
1014
|
|
|
988
|
-
/* MOBILE BREAKOUT (owner, 2026-08-17): on phones the nesting stack squashes the card badly
|
|
1015
|
+
/* MOBILE BREAKOUT (owner, 2026-08-17): on phones the nesting stack squashes the card badly ,
|
|
989
1016
|
measured on Sanctuary: 390px viewport → 346 container → 294 aside → 249px card → ~195px of
|
|
990
1017
|
actual controls. A donate form is a working control surface; it gets the full screen width
|
|
991
1018
|
(edge to edge, side borders/radius dropped, its own padding kept). The negative-margin trick
|
|
@@ -1202,7 +1229,7 @@ textarea.p60-form-control {
|
|
|
1202
1229
|
color: var(--primary-strong);
|
|
1203
1230
|
}
|
|
1204
1231
|
|
|
1205
|
-
/* Named suggested amounts
|
|
1232
|
+
/* Named suggested amounts, a vertical list with the amount + its label (e.g. "Feeds a family"). */
|
|
1206
1233
|
.amount-list {
|
|
1207
1234
|
display: grid;
|
|
1208
1235
|
gap: 0.6rem;
|
|
@@ -1275,6 +1302,12 @@ textarea.p60-form-control {
|
|
|
1275
1302
|
padding-left: 1.8rem;
|
|
1276
1303
|
}
|
|
1277
1304
|
|
|
1305
|
+
.cover-costs-row {
|
|
1306
|
+
display: flex;
|
|
1307
|
+
gap: 0.5rem;
|
|
1308
|
+
align-items: flex-start;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1278
1311
|
.donor-fields {
|
|
1279
1312
|
display: grid;
|
|
1280
1313
|
grid-template-columns: 1fr 1fr;
|
|
@@ -1427,7 +1460,7 @@ textarea.p60-form-control {
|
|
|
1427
1460
|
margin-top: 0.4rem;
|
|
1428
1461
|
}
|
|
1429
1462
|
|
|
1430
|
-
/* (about-page .prose/.value-grid
|
|
1463
|
+
/* (about-page .prose/.value-grid, Classic's section presentation, live in templates/default/theme.ts) */
|
|
1431
1464
|
|
|
1432
1465
|
/* ---------- responsive ---------- */
|
|
1433
1466
|
|
|
@@ -1615,11 +1648,11 @@ textarea.p60-form-control {
|
|
|
1615
1648
|
/* --- Articles (public) --- */
|
|
1616
1649
|
/* The blog is long-form READING (unlike the full-width marketing Services pages): the article body
|
|
1617
1650
|
sits in a ~70ch measure with article chrome (byline, reading time), and the theme owns all
|
|
1618
|
-
typography
|
|
1651
|
+
typography, content only carries semantic structure (mark, pull quotes, captions, tables,
|
|
1619
1652
|
embeds), styled here. */
|
|
1620
1653
|
.article-article {
|
|
1621
1654
|
/* The page FRAME matches every other page's container (hero image, engagement bar span it);
|
|
1622
|
-
the running text keeps its own readable measure via .article-body/.article-article-head
|
|
1655
|
+
the running text keeps its own readable measure via .article-body/.article-article-head ,
|
|
1623
1656
|
so navigating article ↔ other pages no longer visibly narrows the page. */
|
|
1624
1657
|
max-width: var(--container);
|
|
1625
1658
|
margin: 0 auto;
|
|
@@ -1673,7 +1706,7 @@ textarea.p60-form-control {
|
|
|
1673
1706
|
}
|
|
1674
1707
|
|
|
1675
1708
|
.article-body {
|
|
1676
|
-
/* Fills the container
|
|
1709
|
+
/* Fills the container, same call as .service-body ("widened by preference"): the page reads as
|
|
1677
1710
|
one full-width surface; line-height carries the readability. */
|
|
1678
1711
|
margin: 0;
|
|
1679
1712
|
color: var(--ink);
|
|
@@ -1728,7 +1761,7 @@ textarea.p60-form-control {
|
|
|
1728
1761
|
.article-body img.size-full {
|
|
1729
1762
|
max-width: 100%;
|
|
1730
1763
|
}
|
|
1731
|
-
/* The semantic highlight
|
|
1764
|
+
/* The semantic highlight, theme-tinted, never an author-picked colour. */
|
|
1732
1765
|
.article-body mark {
|
|
1733
1766
|
background: color-mix(in srgb, var(--gold) 38%, transparent);
|
|
1734
1767
|
color: inherit;
|
|
@@ -1741,7 +1774,7 @@ textarea.p60-form-control {
|
|
|
1741
1774
|
padding: 0.25rem 1rem;
|
|
1742
1775
|
color: var(--muted);
|
|
1743
1776
|
}
|
|
1744
|
-
/* The pull quote
|
|
1777
|
+
/* The pull quote, a stand-out breath in the reading flow. */
|
|
1745
1778
|
.article-body blockquote.pull {
|
|
1746
1779
|
border-inline-start: none;
|
|
1747
1780
|
border-top: 2px solid var(--line-strong);
|
|
@@ -1834,7 +1867,7 @@ textarea.p60-form-control {
|
|
|
1834
1867
|
margin: 1.5rem 0 0;
|
|
1835
1868
|
}
|
|
1836
1869
|
|
|
1837
|
-
/* Engagement bar under the article. Wraps
|
|
1870
|
+
/* Engagement bar under the article. Wraps, never scrolls sideways. */
|
|
1838
1871
|
.article-engage {
|
|
1839
1872
|
margin: 1.5rem 0;
|
|
1840
1873
|
display: flex;
|
|
@@ -1870,7 +1903,7 @@ textarea.p60-form-control {
|
|
|
1870
1903
|
font-size: 0.95rem;
|
|
1871
1904
|
}
|
|
1872
1905
|
|
|
1873
|
-
/* The share row
|
|
1906
|
+
/* The share row, plain share-intent buttons (no network SDKs). Wraps with the bar. */
|
|
1874
1907
|
.article-share-group {
|
|
1875
1908
|
display: flex;
|
|
1876
1909
|
align-items: center;
|
|
@@ -1900,7 +1933,7 @@ textarea.p60-form-control {
|
|
|
1900
1933
|
border-color: var(--accent);
|
|
1901
1934
|
color: var(--accent-strong);
|
|
1902
1935
|
}
|
|
1903
|
-
/* Brand tints on hover
|
|
1936
|
+
/* Brand tints on hover, recognisable without shouting at rest (and dark-theme safe: the
|
|
1904
1937
|
at-rest button is theme ink on theme surface). */
|
|
1905
1938
|
.article-share-btn--facebook:hover { color: #1877f2; border-color: #1877f2; }
|
|
1906
1939
|
.article-share-btn--x:hover { color: var(--ink); border-color: var(--ink); }
|
|
@@ -2014,7 +2047,7 @@ textarea.p60-form-control {
|
|
|
2014
2047
|
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
|
2015
2048
|
gap: 1.5rem;
|
|
2016
2049
|
}
|
|
2017
|
-
/* MOBILE: the stacked grid becomes an edge-to-edge SWIPE ROW with a peek (owner, 2026-08-17)
|
|
2050
|
+
/* MOBILE: the stacked grid becomes an edge-to-edge SWIPE ROW with a peek (owner, 2026-08-17) ,
|
|
2018
2051
|
the scroller bleeds to the screen edges, each card keeps its padding, the first card aligns to
|
|
2019
2052
|
the text gutter, and the cut-off next card IS the "swipe me" affordance (the reference maps'
|
|
2020
2053
|
card idiom). Snap keeps cards settling cleanly; the scrollbar is hidden, the peek replaces it. */
|
|
@@ -2095,7 +2128,7 @@ textarea.p60-form-control {
|
|
|
2095
2128
|
.article-card-counts {
|
|
2096
2129
|
margin-inline-start: 0.6rem;
|
|
2097
2130
|
}
|
|
2098
|
-
/* The featured (newest) card: a magazine lead
|
|
2131
|
+
/* The featured (newest) card: a magazine lead, image beside copy on wide screens. */
|
|
2099
2132
|
.article-card--featured {
|
|
2100
2133
|
display: grid;
|
|
2101
2134
|
grid-template-columns: 1.2fr 1fr;
|
|
@@ -2132,7 +2165,7 @@ textarea.p60-form-control {
|
|
|
2132
2165
|
color: var(--muted);
|
|
2133
2166
|
}
|
|
2134
2167
|
.article-more {
|
|
2135
|
-
/* Spans the page frame like the hero + back-link (the reading column stays 70ch)
|
|
2168
|
+
/* Spans the page frame like the hero + back-link (the reading column stays 70ch), one frame
|
|
2136
2169
|
edge + one reading edge, nothing floating at a third width. Grid auto-fills the row. */
|
|
2137
2170
|
max-width: var(--container);
|
|
2138
2171
|
margin: 2.5rem auto 0;
|
|
@@ -2178,7 +2211,7 @@ textarea.p60-form-control {
|
|
|
2178
2211
|
.event-card-image-placeholder {
|
|
2179
2212
|
display: grid;
|
|
2180
2213
|
place-items: center;
|
|
2181
|
-
/* Same fallback-tint convention as course cards
|
|
2214
|
+
/* Same fallback-tint convention as course cards, see .course-card-tint. */
|
|
2182
2215
|
background: var(--media-tint, hsl(210 34% 33%));
|
|
2183
2216
|
}
|
|
2184
2217
|
.event-card-image-placeholder span {
|
|
@@ -2212,7 +2245,7 @@ textarea.p60-form-control {
|
|
|
2212
2245
|
align-self: start;
|
|
2213
2246
|
}
|
|
2214
2247
|
|
|
2215
|
-
/* .event-detail carries NO max-width
|
|
2248
|
+
/* .event-detail carries NO max-width, page bodies fill var(--container) (the standing
|
|
2216
2249
|
full-width rule; the 760px reading measure was removed 2026-07-24, as on courses). */
|
|
2217
2250
|
.event-detail-image {
|
|
2218
2251
|
width: 100%;
|
|
@@ -2427,7 +2460,7 @@ textarea.p60-form-control {
|
|
|
2427
2460
|
align-items: center;
|
|
2428
2461
|
gap: 0.5rem;
|
|
2429
2462
|
}
|
|
2430
|
-
/* MOBILE: the rotator is MEDIA
|
|
2463
|
+
/* MOBILE: the rotator is MEDIA, it bleeds edge to edge like the hero and the map, with the
|
|
2431
2464
|
arrows overlaid on the image instead of eating width beside it. */
|
|
2432
2465
|
@media (max-width: 640px) {
|
|
2433
2466
|
.events-carousel {
|
|
@@ -2875,7 +2908,7 @@ textarea.p60-form-control {
|
|
|
2875
2908
|
|
|
2876
2909
|
/* ---- Members area (shell + sections; see components/members/) ----
|
|
2877
2910
|
Desktop: left rail + content. Small screens: the rail becomes a horizontal, scrollable pill
|
|
2878
|
-
strip above the content
|
|
2911
|
+
strip above the content, same registry, no separate mobile markup. */
|
|
2879
2912
|
.members-head {
|
|
2880
2913
|
margin-bottom: 1.6rem;
|
|
2881
2914
|
}
|
|
@@ -2911,7 +2944,7 @@ textarea.p60-form-control {
|
|
|
2911
2944
|
color: var(--ink);
|
|
2912
2945
|
text-align: left;
|
|
2913
2946
|
cursor: pointer;
|
|
2914
|
-
/* Labels WRAP inside the pill (never overflow it)
|
|
2947
|
+
/* Labels WRAP inside the pill (never overflow it), long names and translations both fit. */
|
|
2915
2948
|
line-height: 1.25;
|
|
2916
2949
|
}
|
|
2917
2950
|
.members-rail-item .members-rail-icon { flex: 0 0 auto; }
|
|
@@ -3050,7 +3083,7 @@ textarea.p60-form-control {
|
|
|
3050
3083
|
}
|
|
3051
3084
|
}
|
|
3052
3085
|
|
|
3053
|
-
/* Just above the burger point the full-size nav is tight
|
|
3086
|
+
/* Just above the burger point the full-size nav is tight, compact spacing spreads it cleanly
|
|
3054
3087
|
instead of letting anything drop. */
|
|
3055
3088
|
@media (min-width: 961px) and (max-width: 1120px) {
|
|
3056
3089
|
.site-nav {
|
|
@@ -3172,7 +3205,7 @@ textarea.p60-form-control {
|
|
|
3172
3205
|
|
|
3173
3206
|
/* ---- Members rail on mobile: a LEFT SLIDE-IN DRAWER behind a round user-icon button ----
|
|
3174
3207
|
The rail itself becomes the drawer (same items, same markup): fixed full-height panel translated
|
|
3175
|
-
off-canvas, sliding in over a scrim. The trigger is a slim bar
|
|
3208
|
+
off-canvas, sliding in over a scrim. The trigger is a slim bar, round user-icon button + the
|
|
3176
3209
|
current section name. Desktop hides all of this and shows the rail inline. */
|
|
3177
3210
|
.members-mobile-bar {
|
|
3178
3211
|
display: none;
|
|
@@ -3280,7 +3313,7 @@ textarea.p60-form-control {
|
|
|
3280
3313
|
}
|
|
3281
3314
|
|
|
3282
3315
|
/* ---- Articles front page: the newest article in full + a right sidebar (recent, topics,
|
|
3283
|
-
view-all). Newspaper-style
|
|
3316
|
+
view-all). Newspaper-style, the sidebar stacks below the article on small screens. ---- */
|
|
3284
3317
|
.article-front {
|
|
3285
3318
|
display: grid;
|
|
3286
3319
|
grid-template-columns: minmax(0, 1fr) 300px;
|
|
@@ -3383,7 +3416,7 @@ textarea.p60-form-control {
|
|
|
3383
3416
|
}
|
|
3384
3417
|
}
|
|
3385
3418
|
|
|
3386
|
-
/* ---- Consent banner + preference centre (platform-level, always on
|
|
3419
|
+
/* ---- Consent banner + preference centre (platform-level, always on, compliance is
|
|
3387
3420
|
platform-owned). Fixed bottom layer; the preference centre grows out of the same layer. ---- */
|
|
3388
3421
|
.consent-layer {
|
|
3389
3422
|
position: fixed;
|
|
@@ -3539,7 +3572,7 @@ textarea.p60-form-control {
|
|
|
3539
3572
|
color: inherit;
|
|
3540
3573
|
}
|
|
3541
3574
|
|
|
3542
|
-
/* ---- Marketing opt-in checkbox (the explicit reg-22 consent
|
|
3575
|
+
/* ---- Marketing opt-in checkbox (the explicit reg-22 consent, deliberately quiet, never
|
|
3543
3576
|
pre-ticked) + the members contact toggle. ---- */
|
|
3544
3577
|
.marketing-optin {
|
|
3545
3578
|
display: flex;
|
|
@@ -3608,11 +3641,11 @@ textarea.p60-form-control {
|
|
|
3608
3641
|
}
|
|
3609
3642
|
|
|
3610
3643
|
/* ---- Cross-document view transitions (MPA soft-feel) ----
|
|
3611
|
-
Every nav click is a full document navigation (Astro MPA
|
|
3644
|
+
Every nav click is a full document navigation (Astro MPA, no client router). This asks the
|
|
3612
3645
|
browser to HOLD the old frame and cross-fade to the new page once it's ready (Chrome 126+,
|
|
3613
3646
|
Safari 18+; others keep the instant swap): no blank frame between pages, and unchanged chrome
|
|
3614
|
-
(masthead/nav) cross-fades between identical pixels
|
|
3615
|
-
with persistent island state would be Astro's ClientRouter
|
|
3647
|
+
(masthead/nav) cross-fades between identical pixels, i.e. visually persists. True soft-nav
|
|
3648
|
+
with persistent island state would be Astro's ClientRouter, a later, bigger step. */
|
|
3616
3649
|
@view-transition {
|
|
3617
3650
|
navigation: auto;
|
|
3618
3651
|
}
|
|
@@ -3624,7 +3657,7 @@ textarea.p60-form-control {
|
|
|
3624
3657
|
}
|
|
3625
3658
|
}
|
|
3626
3659
|
|
|
3627
|
-
/* The article page's back-link needs air before the chips/title (detail page only
|
|
3660
|
+
/* The article page's back-link needs air before the chips/title (detail page only, the front
|
|
3628
3661
|
page's grid must keep its own alignment). */
|
|
3629
3662
|
.services-back + .article-article {
|
|
3630
3663
|
margin-top: 1.75rem;
|
|
@@ -3741,7 +3774,7 @@ textarea.p60-form-control {
|
|
|
3741
3774
|
mixed grids keep one card anatomy. The tint arrives as a CSS VARIABLE, not an inline background,
|
|
3742
3775
|
so a template whose palette collides with the green→indigo band can override this rule and
|
|
3743
3776
|
restyle the fallback its own way (the templates-conform contract). */
|
|
3744
|
-
/* Admin-entered prose can contain unbroken tokens (URLs, pasted refs)
|
|
3777
|
+
/* Admin-entered prose can contain unbroken tokens (URLs, pasted refs), never let one push a
|
|
3745
3778
|
container wide. Applies to every surface that renders tenant summaries/bodies. */
|
|
3746
3779
|
.event-detail-desc,
|
|
3747
3780
|
.event-about,
|
|
@@ -4023,7 +4056,7 @@ textarea.p60-form-control {
|
|
|
4023
4056
|
color: var(--muted);
|
|
4024
4057
|
white-space: pre-line;
|
|
4025
4058
|
}
|
|
4026
|
-
/* The members-area PILL BUTTON (user, 2026-07-22)
|
|
4059
|
+
/* The members-area PILL BUTTON (user, 2026-07-22), the one action idiom across member surfaces
|
|
4027
4060
|
(directions, household invite/remove, …): bordered pill, hover fill, danger modifier. */
|
|
4028
4061
|
.member-pill-btn {
|
|
4029
4062
|
display: inline-flex;
|
|
@@ -4046,7 +4079,7 @@ textarea.p60-form-control {
|
|
|
4046
4079
|
.member-pill-btn:disabled { opacity: 0.5; cursor: default; }
|
|
4047
4080
|
.member-pill-btn-danger { color: #c4462e; }
|
|
4048
4081
|
|
|
4049
|
-
/* Get directions = a proper pill button (user, 2026-07-22)
|
|
4082
|
+
/* Get directions = a proper pill button (user, 2026-07-22), the resource-chip idiom, so it
|
|
4050
4083
|
reads as an action rather than text among the venue lines. */
|
|
4051
4084
|
.member-course-directions {
|
|
4052
4085
|
display: inline-flex;
|
|
@@ -4067,7 +4100,7 @@ textarea.p60-form-control {
|
|
|
4067
4100
|
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
4068
4101
|
text-decoration: none;
|
|
4069
4102
|
}
|
|
4070
|
-
/* The feedback-loop accordion (2026-07-21): latest note + attendance history
|
|
4103
|
+
/* The feedback-loop accordion (2026-07-21): latest note + attendance history, renders only when
|
|
4071
4104
|
a course runner actually recorded something. */
|
|
4072
4105
|
.member-course-feedback {
|
|
4073
4106
|
margin-top: 0.6rem;
|
|
@@ -4147,7 +4180,7 @@ textarea.p60-form-control {
|
|
|
4147
4180
|
text-transform: uppercase;
|
|
4148
4181
|
opacity: 0.7;
|
|
4149
4182
|
}
|
|
4150
|
-
/* Download CHIPS (user, 2026-07-22): the whole pill is the button
|
|
4183
|
+
/* Download CHIPS (user, 2026-07-22): the whole pill is the button, unmistakably tappable. */
|
|
4151
4184
|
.member-resource-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.45rem; }
|
|
4152
4185
|
.member-resource-chip {
|
|
4153
4186
|
display: inline-flex;
|
|
@@ -4167,7 +4200,7 @@ textarea.p60-form-control {
|
|
|
4167
4200
|
}
|
|
4168
4201
|
.member-resource-chip-size { font-weight: 400; opacity: 0.65; font-size: 0.85rem; }
|
|
4169
4202
|
|
|
4170
|
-
/* "Billing & payment methods" (user, 2026-07-22): the billing half
|
|
4203
|
+
/* "Billing & payment methods" (user, 2026-07-22): the billing half, one line per ongoing
|
|
4171
4204
|
commitment (a family subscription = ONE line: total + who it covers). */
|
|
4172
4205
|
.members-subsection-title {
|
|
4173
4206
|
font-size: 1.05rem;
|
|
@@ -4193,7 +4226,7 @@ textarea.p60-form-control {
|
|
|
4193
4226
|
.member-billing-detail { font-size: 0.9rem; margin-top: 0.15rem; }
|
|
4194
4227
|
.member-billing-pastdue { color: var(--accent, #d33); font-weight: 600; }
|
|
4195
4228
|
|
|
4196
|
-
/* The course TITLE BAR (user, 2026-07-22): a distinct full-width band at the top of the card
|
|
4229
|
+
/* The course TITLE BAR (user, 2026-07-22): a distinct full-width band at the top of the card ,
|
|
4197
4230
|
bleeds to the card edges via negative margins, slightly larger type. */
|
|
4198
4231
|
.member-course-title-bar {
|
|
4199
4232
|
margin: -1rem -1.1rem 0.35rem;
|
|
@@ -4206,7 +4239,7 @@ textarea.p60-form-control {
|
|
|
4206
4239
|
}
|
|
4207
4240
|
|
|
4208
4241
|
/* Grouped course card (2026-07-22): the course owns venue/breaks/materials once; each PERSON is
|
|
4209
|
-
an ACCORDION row
|
|
4242
|
+
an ACCORDION row, a full-width, obviously-tappable bar (chevron + hover), default collapsed,
|
|
4210
4243
|
one open at a time. */
|
|
4211
4244
|
.member-course-people {
|
|
4212
4245
|
margin-top: 0.85rem;
|
|
@@ -4310,7 +4343,7 @@ textarea.p60-form-control {
|
|
|
4310
4343
|
flex-wrap: wrap;
|
|
4311
4344
|
}
|
|
4312
4345
|
|
|
4313
|
-
/* Courses picker refinement (2026-07-19): tap-to-select cards
|
|
4346
|
+
/* Courses picker refinement (2026-07-19): tap-to-select cards, the native checkbox/radio is
|
|
4314
4347
|
visually hidden (kept in the DOM for keyboard + screen-reader semantics); selection reads as
|
|
4315
4348
|
the highlighted card. The footer is an itemised order summary instead of a one-line count. */
|
|
4316
4349
|
.course-variant-card,
|
|
@@ -4430,7 +4463,7 @@ textarea.p60-form-control {
|
|
|
4430
4463
|
font-weight: 600;
|
|
4431
4464
|
}
|
|
4432
4465
|
|
|
4433
|
-
/* ---- Prayer timetable page (worship WP5)
|
|
4466
|
+
/* ---- Prayer timetable page (worship WP5), theme-neutral: borders/highlights derive from
|
|
4434
4467
|
currentColor so every template's palette carries through. ---- */
|
|
4435
4468
|
.pt-head {
|
|
4436
4469
|
display: flex;
|
|
@@ -4505,7 +4538,7 @@ textarea.p60-form-control {
|
|
|
4505
4538
|
opacity: 0.7;
|
|
4506
4539
|
}
|
|
4507
4540
|
|
|
4508
|
-
/* Small screens: the month table becomes stacked day cards
|
|
4541
|
+
/* Small screens: the month table becomes stacked day cards, no horizontal scrolling. */
|
|
4509
4542
|
.pt-cards {
|
|
4510
4543
|
display: none;
|
|
4511
4544
|
list-style: none;
|
|
@@ -4583,7 +4616,7 @@ textarea.p60-form-control {
|
|
|
4583
4616
|
font-size: 0.92rem;
|
|
4584
4617
|
}
|
|
4585
4618
|
|
|
4586
|
-
/* ── People / team cards
|
|
4619
|
+
/* ── People / team cards, desktop grid, single column on phones ───────────────────────────── */
|
|
4587
4620
|
.people-grid {
|
|
4588
4621
|
display: grid;
|
|
4589
4622
|
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
|
|
@@ -4614,29 +4647,29 @@ textarea.p60-form-control {
|
|
|
4614
4647
|
.people-grid { grid-template-columns: 1fr; }
|
|
4615
4648
|
}
|
|
4616
4649
|
|
|
4617
|
-
/* ── Impact map island (WP4)
|
|
4650
|
+
/* ── Impact map island (WP4), the OVERLAY borrows the theme: pins wear --marker (a brand accent by
|
|
4618
4651
|
default), the card is a themed --surface. The BASEMAP colour is derived by the map island from the
|
|
4619
|
-
theme + --map-mode (see lib/mapTheme.ts). Brand on the overlay, neutrals on the map
|
|
4652
|
+
theme + --map-mode (see lib/mapTheme.ts). Brand on the overlay, neutrals on the map, the recipe
|
|
4620
4653
|
that stays legible on any theme. Templates restyle any of this via the tokens or these classes. */
|
|
4621
4654
|
.impact-map { margin: 24px 0; }
|
|
4622
4655
|
.impact-map-head h2 { margin: 0 0 6px; }
|
|
4623
4656
|
.impact-map-intro { margin: 0 0 14px; opacity: 0.85; }
|
|
4624
4657
|
.impact-map-stats { margin: 0 0 14px; color: var(--muted); font-weight: 600; letter-spacing: 0.01em; }
|
|
4625
4658
|
/* The stable stage, shaped like THE WORLD BAND ITSELF: the island's planet view is all 360° of
|
|
4626
|
-
longitude by 84°N
|
|
4627
|
-
Web Mercator is a 1.497:1 box
|
|
4659
|
+
longitude by 84°N-58°S (whole Greenland in, only the polar void and Antarctica trimmed), which in
|
|
4660
|
+
Web Mercator is a 1.497:1 box, so a frame with that exact ratio holds the full planet edge to
|
|
4628
4661
|
edge, full width AND full height, at any screen size. A ratio wider than the band (a max-height
|
|
4629
4662
|
clamp once made it so on large screens) turns the fit height-constrained and the world renders
|
|
4630
|
-
NARROWER than the frame
|
|
4663
|
+
NARROWER than the frame, dead bars at the sides; a narrower ratio (min-height on phones) just
|
|
4631
4664
|
adds benign vertical margin. Relative + clipped so MapLibre always has a real box and can never
|
|
4632
4665
|
escape it. Keep this ratio in step with the island's planet bounds. */
|
|
4633
4666
|
.impact-map-stage { position: relative; width: 100%; aspect-ratio: 1.497; min-height: 300px;
|
|
4634
4667
|
border-radius: 14px; overflow: hidden; }
|
|
4635
4668
|
/* width:100% is LOAD-BEARING: with height pinned by min-height and width left auto, CSS derives
|
|
4636
|
-
width FROM the aspect-ratio (300 x 1.497 = 449px)
|
|
4669
|
+
width FROM the aspect-ratio (300 x 1.497 = 449px), on phones the stage overflowed the page
|
|
4637
4670
|
sideways, shoving every other section into a lopsided "left with a right gutter" layout. Width
|
|
4638
4671
|
pinned, the ratio yields height and min-height only ever makes the stage TALLER. */
|
|
4639
|
-
/* MOBILE BREAKOUT: a map is a canvas
|
|
4672
|
+
/* MOBILE BREAKOUT: a map is a canvas, every pixel is information, nothing needs a margin, so on
|
|
4640
4673
|
phones it bleeds edge to edge (media bleeds, prose gutters: the hero already sets the rhythm).
|
|
4641
4674
|
Cooperative gestures keep page-scrolling safe over the full-width canvas. */
|
|
4642
4675
|
@media (max-width: 640px) {
|
|
@@ -4662,7 +4695,7 @@ textarea.p60-form-control {
|
|
|
4662
4695
|
card on every screen size, as it always has. */
|
|
4663
4696
|
.impact-map-card--small-screens { display: none; }
|
|
4664
4697
|
@media (max-width: 640px) {
|
|
4665
|
-
/* Full width, flush under the full-bleed map
|
|
4698
|
+
/* Full width, flush under the full-bleed map, the two read as one attached sheet (the same
|
|
4666
4699
|
breakout as the donate card; the hairline top border is the seam between map and card). */
|
|
4667
4700
|
.impact-map-card--small-screens {
|
|
4668
4701
|
display: block;
|
|
@@ -4685,10 +4718,10 @@ textarea.p60-form-control {
|
|
|
4685
4718
|
Sized with width/height (NOT inset) because MapLibre forces position:relative on this element,
|
|
4686
4719
|
which would defeat absolute insets and collapse the box to zero height. */
|
|
4687
4720
|
.impact-map-gl { width: 100%; height: 100%; }
|
|
4688
|
-
/* Live-map markers are a MapLibre circle layer (WebGL)
|
|
4689
|
-
from --marker (circle-color)
|
|
4721
|
+
/* Live-map markers are a MapLibre circle layer (WebGL), they scale with zoom and take their colour
|
|
4722
|
+
from --marker (circle-color), so there is no DOM marker element to style here. The pin canvas
|
|
4690
4723
|
fallback above keeps its own .impact-map-pin dots for the no-tiles case. */
|
|
4691
|
-
/* The INLINE marker card (a MapLibre popup anchored at the clicked marker
|
|
4724
|
+
/* The INLINE marker card (a MapLibre popup anchored at the clicked marker, where "See more"
|
|
4692
4725
|
lives): the shell takes the theme's surface; the tip is recoloured per anchor side to match. */
|
|
4693
4726
|
.impact-map-popup .maplibregl-popup-content { background: var(--surface); color: var(--ink);
|
|
4694
4727
|
border: 1px solid var(--line); border-radius: var(--radius-sm); box-shadow: var(--shadow);
|