@port60/template-kit 0.16.0 → 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.
- package/package.json +9 -3
- package/src/vendor/contract/v1/content-model.json +372 -76
- package/src/vendor/contract/v1/context.json +60 -3
- package/src/vendor/contract/v1/islands.json +50 -0
- package/src/vendor/contract/v1/manifest.schema.json +132 -25
- package/src/vendor/contract/v1/sections.json +18 -6
- package/src/vendor/validator/platform-base.css +294 -0
- package/src/vendor/validator/preview.mjs +11 -0
- package/src/vendor/validator/validate.mjs +15 -1
- package/starter/manifest.json +7 -2
- package/starter/sections/homeHero.liquid +9 -8
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"description": "The full donation flow for the tenant's quick-give cause: suggested amounts, custom amount, donor details, Gift Aid opt-in, payment. All payment/compliance behaviour is platform-owned.",
|
|
9
9
|
"params": [],
|
|
10
10
|
"stylingApi": [
|
|
11
|
+
".action-card",
|
|
11
12
|
".donate-card",
|
|
12
13
|
".donate-head",
|
|
13
14
|
".donate-sub",
|
|
@@ -243,6 +244,55 @@
|
|
|
243
244
|
".impact-map-card-cta",
|
|
244
245
|
".impact-map-empty"
|
|
245
246
|
]
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"name": "volunteer_signup",
|
|
250
|
+
"label": "Volunteer sign-up",
|
|
251
|
+
"status": "preview",
|
|
252
|
+
"description": "The volunteer sign-up flow: what to help with (general, then the events and campaigns that need people), when (only when the opportunity runs in shifts), a few details, then confirmation by a charity-branded email that also signs the volunteer in. Shares the donation widget's card vocabulary so a themed donate card themes this too; the vol-* classes cover what is specific to asking for help.",
|
|
253
|
+
"params": [],
|
|
254
|
+
"stylingApi": [
|
|
255
|
+
".donate-card",
|
|
256
|
+
".action-card",
|
|
257
|
+
".vol-body",
|
|
258
|
+
".volunteer-card",
|
|
259
|
+
".vol-card",
|
|
260
|
+
".vol-chosen",
|
|
261
|
+
".vol-search",
|
|
262
|
+
".vol-list",
|
|
263
|
+
".vol-group",
|
|
264
|
+
".vol-group-label",
|
|
265
|
+
".vol-option",
|
|
266
|
+
".vol-option-main",
|
|
267
|
+
".vol-option-summary",
|
|
268
|
+
".vol-option-meta",
|
|
269
|
+
".vol-needed",
|
|
270
|
+
".vol-shift-count",
|
|
271
|
+
".vol-form",
|
|
272
|
+
".vol-availability",
|
|
273
|
+
".vol-chips",
|
|
274
|
+
".vol-chip",
|
|
275
|
+
".vol-confirm",
|
|
276
|
+
".vol-optional",
|
|
277
|
+
".vol-why",
|
|
278
|
+
".vol-extra",
|
|
279
|
+
".vol-summary",
|
|
280
|
+
".vol-signed-in",
|
|
281
|
+
".vol-summary-needed",
|
|
282
|
+
".vol-field-error"
|
|
283
|
+
]
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"name": "primary_action",
|
|
287
|
+
"label": "Primary action",
|
|
288
|
+
"status": "available",
|
|
289
|
+
"description": "The composite for the site focus: mounts the donation widget or the volunteer sign-up according to what the charity chose to lead with (site.focus), so a template places one static island and the choice moves without a variable name. Both widgets wear .action-card; .donate-card and .volunteer-card carry kind-specific treatment. A template that wants a different layout per kind branches on section.primary.kind and places donation_widget or volunteer_signup directly.",
|
|
290
|
+
"params": [],
|
|
291
|
+
"stylingApi": [
|
|
292
|
+
".action-card",
|
|
293
|
+
".donate-card",
|
|
294
|
+
".volunteer-card"
|
|
295
|
+
]
|
|
246
296
|
}
|
|
247
297
|
]
|
|
248
298
|
}
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
"title": "Port60 template manifest (contract v1)",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"additionalProperties": false,
|
|
7
|
-
"required": [
|
|
7
|
+
"required": [
|
|
8
|
+
"name",
|
|
9
|
+
"version",
|
|
10
|
+
"format",
|
|
11
|
+
"supports"
|
|
12
|
+
],
|
|
8
13
|
"properties": {
|
|
9
14
|
"name": {
|
|
10
15
|
"type": "string",
|
|
@@ -18,11 +23,20 @@
|
|
|
18
23
|
},
|
|
19
24
|
"format": {
|
|
20
25
|
"type": "string",
|
|
21
|
-
"enum": [
|
|
26
|
+
"enum": [
|
|
27
|
+
"port60-liquid@1"
|
|
28
|
+
],
|
|
22
29
|
"description": "The dialect/contract major this template is written against."
|
|
23
30
|
},
|
|
24
|
-
"label": {
|
|
25
|
-
|
|
31
|
+
"label": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"maxLength": 60,
|
|
34
|
+
"description": "Human-readable name shown in pickers."
|
|
35
|
+
},
|
|
36
|
+
"description": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"maxLength": 300
|
|
39
|
+
},
|
|
26
40
|
"requiresCapabilities": {
|
|
27
41
|
"type": "array",
|
|
28
42
|
"items": {
|
|
@@ -52,7 +66,15 @@
|
|
|
52
66
|
"type": "array",
|
|
53
67
|
"items": {
|
|
54
68
|
"type": "string",
|
|
55
|
-
"enum": [
|
|
69
|
+
"enum": [
|
|
70
|
+
"general",
|
|
71
|
+
"mosque",
|
|
72
|
+
"church",
|
|
73
|
+
"appeal-charity",
|
|
74
|
+
"pta",
|
|
75
|
+
"community",
|
|
76
|
+
"training"
|
|
77
|
+
]
|
|
56
78
|
},
|
|
57
79
|
"uniqueItems": true,
|
|
58
80
|
"default": [],
|
|
@@ -66,25 +88,38 @@
|
|
|
66
88
|
"supports": {
|
|
67
89
|
"type": "object",
|
|
68
90
|
"additionalProperties": false,
|
|
69
|
-
"required": [
|
|
91
|
+
"required": [
|
|
92
|
+
"pages",
|
|
93
|
+
"sections"
|
|
94
|
+
],
|
|
70
95
|
"properties": {
|
|
71
96
|
"pages": {
|
|
72
97
|
"type": "array",
|
|
73
|
-
"items": {
|
|
98
|
+
"items": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"enum": [
|
|
101
|
+
"home",
|
|
102
|
+
"about"
|
|
103
|
+
]
|
|
104
|
+
},
|
|
74
105
|
"minItems": 1,
|
|
75
106
|
"uniqueItems": true,
|
|
76
107
|
"description": "Section based page bodies this template renders from sections/{type}.liquid. Contract v1 supports home and about. This is independent of layout chrome and route-specific pageTemplates."
|
|
77
108
|
},
|
|
78
109
|
"sections": {
|
|
79
110
|
"type": "array",
|
|
80
|
-
"items": {
|
|
111
|
+
"items": {
|
|
112
|
+
"type": "string"
|
|
113
|
+
},
|
|
81
114
|
"minItems": 1,
|
|
82
115
|
"uniqueItems": true,
|
|
83
116
|
"description": "Section types this template ships renderers for (sections/{type}.liquid). Unsupported types are omitted at render, never an error."
|
|
84
117
|
},
|
|
85
118
|
"islands": {
|
|
86
119
|
"type": "array",
|
|
87
|
-
"items": {
|
|
120
|
+
"items": {
|
|
121
|
+
"type": "string"
|
|
122
|
+
},
|
|
88
123
|
"uniqueItems": true,
|
|
89
124
|
"default": [],
|
|
90
125
|
"description": "Islands this template places. Every {% island %} name must be listed here AND exist in the platform island registry."
|
|
@@ -96,7 +131,15 @@
|
|
|
96
131
|
},
|
|
97
132
|
"pageTemplates": {
|
|
98
133
|
"type": "array",
|
|
99
|
-
"items": {
|
|
134
|
+
"items": {
|
|
135
|
+
"type": "string",
|
|
136
|
+
"enum": [
|
|
137
|
+
"events",
|
|
138
|
+
"course",
|
|
139
|
+
"articles",
|
|
140
|
+
"article"
|
|
141
|
+
]
|
|
142
|
+
},
|
|
100
143
|
"uniqueItems": true,
|
|
101
144
|
"default": [],
|
|
102
145
|
"description": "Route-specific data views rendered from pages/{page}.liquid with documented context. Events and articles own listings; course and article own detail presentation. Event transactions, course enrolment, article engagement, comments, identity and consent stay platform-owned islands. Requires supports.layout; without an entry the platform body renders inside the template chrome."
|
|
@@ -115,10 +158,34 @@
|
|
|
115
158
|
"type": "array",
|
|
116
159
|
"items": {
|
|
117
160
|
"type": "string",
|
|
118
|
-
"enum": [
|
|
161
|
+
"enum": [
|
|
162
|
+
"reveal",
|
|
163
|
+
"counter",
|
|
164
|
+
"progress",
|
|
165
|
+
"countdown",
|
|
166
|
+
"accordion",
|
|
167
|
+
"carousel",
|
|
168
|
+
"stickyHeader",
|
|
169
|
+
"stickyCta",
|
|
170
|
+
"lightbox",
|
|
171
|
+
"tabs",
|
|
172
|
+
"nav"
|
|
173
|
+
]
|
|
119
174
|
},
|
|
120
175
|
"uniqueItems": true,
|
|
121
176
|
"description": "Engine-attached behaviours this template's markup opts into via data-p60-* attributes (see the behaviour catalogue). Templates never ship JavaScript; declaring here is what makes the engine wire the markup, and the validator proves declaration and usage agree in both directions."
|
|
177
|
+
},
|
|
178
|
+
"focus": {
|
|
179
|
+
"type": "array",
|
|
180
|
+
"uniqueItems": true,
|
|
181
|
+
"items": {
|
|
182
|
+
"type": "string",
|
|
183
|
+
"enum": [
|
|
184
|
+
"donate",
|
|
185
|
+
"volunteer"
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
"description": "The site-focus kinds this template can LEAD with (docs/volunteering.md). Declaring 'volunteer' means the home hero places the composite primary_action island (or branches on section.primary.kind), so the volunteer sign-up can take the widget slot; the picker marks templates that cannot lead with volunteering. Templates that predate the setting keep rendering the donation widget, since donate is the default."
|
|
122
189
|
}
|
|
123
190
|
}
|
|
124
191
|
},
|
|
@@ -130,7 +197,10 @@
|
|
|
130
197
|
"hero": {
|
|
131
198
|
"type": "object",
|
|
132
199
|
"additionalProperties": false,
|
|
133
|
-
"required": [
|
|
200
|
+
"required": [
|
|
201
|
+
"idealAspect",
|
|
202
|
+
"minWidth"
|
|
203
|
+
],
|
|
134
204
|
"properties": {
|
|
135
205
|
"idealAspect": {
|
|
136
206
|
"type": "string",
|
|
@@ -166,7 +236,10 @@
|
|
|
166
236
|
"items": {
|
|
167
237
|
"type": "object",
|
|
168
238
|
"additionalProperties": false,
|
|
169
|
-
"required": [
|
|
239
|
+
"required": [
|
|
240
|
+
"name",
|
|
241
|
+
"values"
|
|
242
|
+
],
|
|
170
243
|
"properties": {
|
|
171
244
|
"name": {
|
|
172
245
|
"type": "string",
|
|
@@ -176,14 +249,18 @@
|
|
|
176
249
|
"values": {
|
|
177
250
|
"type": "object",
|
|
178
251
|
"minProperties": 1,
|
|
179
|
-
"propertyNames": {
|
|
180
|
-
|
|
181
|
-
|
|
252
|
+
"propertyNames": {
|
|
253
|
+
"pattern": "^[a-zA-Z][a-zA-Z0-9]{0,39}$"
|
|
254
|
+
},
|
|
255
|
+
"additionalProperties": {
|
|
256
|
+
"type": "string"
|
|
257
|
+
},
|
|
258
|
+
"description": "Knob key \u2192 value. Every key must be a declared settings knob; select values must be listed options; font values must be catalogue families."
|
|
182
259
|
}
|
|
183
260
|
}
|
|
184
261
|
},
|
|
185
262
|
"default": [],
|
|
186
|
-
"description": "One-click LOOKS: author-named bundles of knob values (scheme + fonts + width
|
|
263
|
+
"description": "One-click LOOKS: author-named bundles of knob values (scheme + fonts + width\u2026) applied together. Everything remains individually adjustable afterwards."
|
|
187
264
|
},
|
|
188
265
|
"settings": {
|
|
189
266
|
"type": "object",
|
|
@@ -194,21 +271,51 @@
|
|
|
194
271
|
"items": {
|
|
195
272
|
"type": "object",
|
|
196
273
|
"additionalProperties": false,
|
|
197
|
-
"required": [
|
|
274
|
+
"required": [
|
|
275
|
+
"key",
|
|
276
|
+
"kind",
|
|
277
|
+
"label"
|
|
278
|
+
],
|
|
198
279
|
"properties": {
|
|
199
|
-
"key": {
|
|
200
|
-
|
|
201
|
-
|
|
280
|
+
"key": {
|
|
281
|
+
"type": "string",
|
|
282
|
+
"pattern": "^[a-zA-Z][a-zA-Z0-9]{0,39}$"
|
|
283
|
+
},
|
|
284
|
+
"kind": {
|
|
285
|
+
"type": "string",
|
|
286
|
+
"enum": [
|
|
287
|
+
"color",
|
|
288
|
+
"select",
|
|
289
|
+
"toggle",
|
|
290
|
+
"font"
|
|
291
|
+
]
|
|
292
|
+
},
|
|
293
|
+
"label": {
|
|
294
|
+
"type": "string",
|
|
295
|
+
"maxLength": 60
|
|
296
|
+
},
|
|
202
297
|
"default": {},
|
|
203
|
-
"options": {
|
|
298
|
+
"options": {
|
|
299
|
+
"type": "array",
|
|
300
|
+
"items": {
|
|
301
|
+
"type": "string"
|
|
302
|
+
}
|
|
303
|
+
},
|
|
204
304
|
"group": {
|
|
205
305
|
"type": "string",
|
|
206
|
-
"enum": [
|
|
207
|
-
|
|
306
|
+
"enum": [
|
|
307
|
+
"typography",
|
|
308
|
+
"looks"
|
|
309
|
+
],
|
|
310
|
+
"description": "Where the admin surfaces this knob: 'typography' \u2192 the Typography section beside the font slots; 'looks' \u2192 the Looks section with the one-click bundles (colour schemes and accent dials belong there, and ungrouped color knobs plus a knob keyed 'scheme' default there anyway); other ungrouped knobs render under Template options."
|
|
208
311
|
},
|
|
209
312
|
"weights": {
|
|
210
313
|
"type": "array",
|
|
211
|
-
"items": {
|
|
314
|
+
"items": {
|
|
315
|
+
"type": "integer",
|
|
316
|
+
"minimum": 100,
|
|
317
|
+
"maximum": 1000
|
|
318
|
+
},
|
|
212
319
|
"uniqueItems": true,
|
|
213
320
|
"description": "FONT knobs only: the weights this template's typographic system uses for the slot. The host requests these for the tenant's chosen family (clamped to the family's real weights). The tenant picks the FAMILY; weights, sizes and tracking stay template-owned."
|
|
214
321
|
}
|
|
@@ -237,7 +237,7 @@
|
|
|
237
237
|
"name": "images",
|
|
238
238
|
"kind": "items",
|
|
239
239
|
"required": false,
|
|
240
|
-
"description": "Hero photographs (0
|
|
240
|
+
"description": "Hero photographs (0\u20136, uploaded through the platform pipeline). One = a main image; several = rotation material, a template with supports.heroImagery renders at least the first and MAY place the hero_carousel island (or a CSS scroll strip) for the rest. Like every field: absent means the template's designed no-photo state, never a placeholder.",
|
|
241
241
|
"itemFields": [
|
|
242
242
|
{
|
|
243
243
|
"name": "imageUrl",
|
|
@@ -360,16 +360,16 @@
|
|
|
360
360
|
"items": [
|
|
361
361
|
{
|
|
362
362
|
"imageUrl": "p60fixture:impact/parcel",
|
|
363
|
-
"title": "
|
|
363
|
+
"title": "\u00a310 \u00b7 A family food parcel",
|
|
364
364
|
"description": "Three days of meals, toiletries and a bag of fresh produce from the garden."
|
|
365
365
|
},
|
|
366
366
|
{
|
|
367
|
-
"icon": "
|
|
368
|
-
"title": "
|
|
367
|
+
"icon": "\ud83d\udd25",
|
|
368
|
+
"title": "\u00a325 \u00b7 A warm week",
|
|
369
369
|
"description": "Heating top-ups for a household choosing between eating and heating."
|
|
370
370
|
},
|
|
371
371
|
{
|
|
372
|
-
"title": "
|
|
372
|
+
"title": "\u00a350 \u00b7 A month of youth club",
|
|
373
373
|
"description": "Coaching, kit and hot food for a young person, four evenings a week."
|
|
374
374
|
}
|
|
375
375
|
]
|
|
@@ -513,7 +513,7 @@
|
|
|
513
513
|
"pages": [
|
|
514
514
|
"home"
|
|
515
515
|
],
|
|
516
|
-
"description": "Big headline numbers, the at-a-glance impact band. Values are author-entered text (write them exactly as they should read).",
|
|
516
|
+
"description": "Big headline numbers, the at-a-glance impact band. Values are author-entered text (write them exactly as they should read), or, per item, a live figure the platform counts (`source`).",
|
|
517
517
|
"fields": [
|
|
518
518
|
{
|
|
519
519
|
"name": "eyebrow",
|
|
@@ -544,6 +544,18 @@
|
|
|
544
544
|
"kind": "text",
|
|
545
545
|
"required": true,
|
|
546
546
|
"description": "What it counts (e.g. meals served)."
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
"name": "source",
|
|
550
|
+
"kind": "select",
|
|
551
|
+
"required": false,
|
|
552
|
+
"options": [
|
|
553
|
+
"volunteers.active",
|
|
554
|
+
"volunteers.hoursThisYear",
|
|
555
|
+
"volunteers.opportunitiesOpen",
|
|
556
|
+
"volunteers.needed"
|
|
557
|
+
],
|
|
558
|
+
"description": "A figure the platform counts rather than the author types (volunteers who helped in the last twelve months, hours logged this year, opportunities open now, volunteers still needed). When set, `value` is replaced at render with the live count, formatted for the site's locale; templates render `value` exactly as before."
|
|
547
559
|
}
|
|
548
560
|
]
|
|
549
561
|
}
|
|
@@ -2579,6 +2579,300 @@ textarea.p60-form-control {
|
|
|
2579
2579
|
border-color: var(--primary-strong);
|
|
2580
2580
|
}
|
|
2581
2581
|
|
|
2582
|
+
/* ---- Volunteer sign-up widget (components/VolunteerWidget.tsx) ----
|
|
2583
|
+
Reuses the donate card vocabulary (.donate-card/.donate-head/.field/.donate-submit/.donate-success)
|
|
2584
|
+
so a themed donate card themes this too; vol-* covers what is specific to asking for help. */
|
|
2585
|
+
.vol-search input,
|
|
2586
|
+
.vol-form input:not([type='checkbox']):not([type='radio']),
|
|
2587
|
+
.vol-form select,
|
|
2588
|
+
.vol-form textarea {
|
|
2589
|
+
width: 100%;
|
|
2590
|
+
border: 1.5px solid var(--line);
|
|
2591
|
+
border-radius: 12px;
|
|
2592
|
+
padding: 0.7rem 0.85rem;
|
|
2593
|
+
font: inherit;
|
|
2594
|
+
line-height: 1.45;
|
|
2595
|
+
color: var(--ink);
|
|
2596
|
+
background: var(--surface);
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2599
|
+
.vol-search input:focus,
|
|
2600
|
+
.vol-form input:not([type='checkbox']):not([type='radio']):focus,
|
|
2601
|
+
.vol-form select:focus,
|
|
2602
|
+
.vol-form textarea:focus {
|
|
2603
|
+
outline: none;
|
|
2604
|
+
border-color: var(--primary);
|
|
2605
|
+
box-shadow: 0 0 0 3px var(--primary-soft);
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
/* The steps live in a body of ONE height (owner rule: the hero widget must not grow and jump
|
|
2609
|
+
between steps). Lists scroll inside it; a step shorter than the body leaves quiet space. */
|
|
2610
|
+
.vol-body {
|
|
2611
|
+
display: flex;
|
|
2612
|
+
flex-direction: column;
|
|
2613
|
+
gap: 1rem;
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2616
|
+
.vol-body--list {
|
|
2617
|
+
height: 32rem;
|
|
2618
|
+
overflow: hidden;
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2621
|
+
.vol-body--form {
|
|
2622
|
+
min-height: 32rem;
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
.vol-list {
|
|
2626
|
+
display: grid;
|
|
2627
|
+
gap: 0.6rem;
|
|
2628
|
+
align-content: start;
|
|
2629
|
+
flex: 1 1 auto;
|
|
2630
|
+
min-height: 0;
|
|
2631
|
+
overflow-y: auto;
|
|
2632
|
+
padding-right: 0.2rem;
|
|
2633
|
+
scrollbar-gutter: stable;
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2636
|
+
.vol-body > .vol-form,
|
|
2637
|
+
.vol-body > .vol-chosen,
|
|
2638
|
+
.vol-body > .vol-search {
|
|
2639
|
+
flex: none;
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
.vol-group {
|
|
2643
|
+
display: grid;
|
|
2644
|
+
gap: 0.5rem;
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
.vol-group-label {
|
|
2648
|
+
margin: 0.2rem 0 0;
|
|
2649
|
+
font-size: 0.78rem;
|
|
2650
|
+
font-weight: 700;
|
|
2651
|
+
letter-spacing: 0.06em;
|
|
2652
|
+
text-transform: uppercase;
|
|
2653
|
+
color: var(--muted);
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
.vol-option {
|
|
2657
|
+
display: flex;
|
|
2658
|
+
align-items: center;
|
|
2659
|
+
justify-content: space-between;
|
|
2660
|
+
gap: 0.8rem;
|
|
2661
|
+
width: 100%;
|
|
2662
|
+
text-align: start;
|
|
2663
|
+
border: 1.5px solid var(--line);
|
|
2664
|
+
background: var(--surface);
|
|
2665
|
+
color: var(--ink);
|
|
2666
|
+
border-radius: 12px;
|
|
2667
|
+
padding: 0.85rem 1rem;
|
|
2668
|
+
font: inherit;
|
|
2669
|
+
cursor: pointer;
|
|
2670
|
+
transition: border-color 0.16s ease, background 0.16s ease;
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2673
|
+
.vol-option:hover,
|
|
2674
|
+
.vol-option:focus-visible {
|
|
2675
|
+
border-color: var(--primary);
|
|
2676
|
+
background: var(--primary-soft);
|
|
2677
|
+
outline: none;
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
.vol-option-main {
|
|
2681
|
+
display: grid;
|
|
2682
|
+
gap: 0.15rem;
|
|
2683
|
+
min-width: 0;
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
.vol-option-summary {
|
|
2687
|
+
font-size: 0.88rem;
|
|
2688
|
+
color: var(--muted);
|
|
2689
|
+
line-height: 1.35;
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
.vol-option-meta {
|
|
2693
|
+
display: grid;
|
|
2694
|
+
gap: 0.2rem;
|
|
2695
|
+
justify-items: end;
|
|
2696
|
+
flex-shrink: 0;
|
|
2697
|
+
text-align: end;
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
.vol-needed {
|
|
2701
|
+
font-size: 0.8rem;
|
|
2702
|
+
font-weight: 700;
|
|
2703
|
+
color: var(--primary-strong);
|
|
2704
|
+
white-space: nowrap;
|
|
2705
|
+
}
|
|
2706
|
+
|
|
2707
|
+
.vol-needed.is-full {
|
|
2708
|
+
color: var(--muted);
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
.vol-shift-count {
|
|
2712
|
+
font-size: 0.78rem;
|
|
2713
|
+
color: var(--muted);
|
|
2714
|
+
white-space: nowrap;
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
.vol-chosen {
|
|
2718
|
+
display: flex;
|
|
2719
|
+
align-items: center;
|
|
2720
|
+
justify-content: space-between;
|
|
2721
|
+
gap: 0.8rem;
|
|
2722
|
+
padding: 0.7rem 0.9rem;
|
|
2723
|
+
border-radius: 12px;
|
|
2724
|
+
background: var(--primary-soft);
|
|
2725
|
+
font-size: 0.92rem;
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
.vol-chosen-shift {
|
|
2729
|
+
display: block;
|
|
2730
|
+
color: var(--muted);
|
|
2731
|
+
font-size: 0.85rem;
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
.vol-form {
|
|
2735
|
+
display: grid;
|
|
2736
|
+
gap: 0.9rem;
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2739
|
+
.vol-optional {
|
|
2740
|
+
font-style: normal;
|
|
2741
|
+
font-weight: 500;
|
|
2742
|
+
color: var(--muted);
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
.vol-availability {
|
|
2746
|
+
border: 0;
|
|
2747
|
+
padding: 0;
|
|
2748
|
+
margin: 0;
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
.vol-availability legend {
|
|
2752
|
+
font-weight: 600;
|
|
2753
|
+
font-size: 0.9rem;
|
|
2754
|
+
line-height: 1.4;
|
|
2755
|
+
padding: 0;
|
|
2756
|
+
margin-bottom: 0.4rem;
|
|
2757
|
+
}
|
|
2758
|
+
|
|
2759
|
+
/* The When row is a select or a chip row; both sit on the same box height so the panel never
|
|
2760
|
+
changes height when the choice above changes. */
|
|
2761
|
+
.vol-form select,
|
|
2762
|
+
.vol-chip {
|
|
2763
|
+
box-sizing: border-box;
|
|
2764
|
+
min-height: 3.1rem;
|
|
2765
|
+
}
|
|
2766
|
+
|
|
2767
|
+
.vol-form .field > span {
|
|
2768
|
+
line-height: 1.4;
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
.vol-chips {
|
|
2772
|
+
display: flex;
|
|
2773
|
+
flex-wrap: wrap;
|
|
2774
|
+
gap: 0.4rem;
|
|
2775
|
+
}
|
|
2776
|
+
|
|
2777
|
+
.vol-summary-needed {
|
|
2778
|
+
color: var(--primary-strong);
|
|
2779
|
+
font-weight: 700;
|
|
2780
|
+
text-transform: capitalize;
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
.vol-chip {
|
|
2784
|
+
flex: 1 1 0;
|
|
2785
|
+
border: 1.5px solid var(--line);
|
|
2786
|
+
background: var(--surface);
|
|
2787
|
+
color: var(--ink);
|
|
2788
|
+
border-radius: 999px;
|
|
2789
|
+
/* The same vertical rhythm as a select in this form, so the When row never changes height. */
|
|
2790
|
+
padding: 0.7rem 0.4rem;
|
|
2791
|
+
font: inherit;
|
|
2792
|
+
font-size: 0.86rem;
|
|
2793
|
+
line-height: 1.45;
|
|
2794
|
+
font-weight: 600;
|
|
2795
|
+
cursor: pointer;
|
|
2796
|
+
white-space: nowrap;
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2799
|
+
.vol-chip.selected {
|
|
2800
|
+
border-color: var(--primary);
|
|
2801
|
+
background: var(--primary);
|
|
2802
|
+
color: #fff;
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
|
|
2806
|
+
.vol-why {
|
|
2807
|
+
text-align: center;
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
.vol-form select {
|
|
2811
|
+
appearance: none;
|
|
2812
|
+
-webkit-appearance: none;
|
|
2813
|
+
padding-right: 2.4rem;
|
|
2814
|
+
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23555' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
|
|
2815
|
+
background-repeat: no-repeat;
|
|
2816
|
+
background-position: right 0.9rem center;
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
.vol-form select:disabled {
|
|
2820
|
+
opacity: 0.6;
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2823
|
+
.vol-summary {
|
|
2824
|
+
margin: -0.3rem 0 0;
|
|
2825
|
+
font-size: 0.86rem;
|
|
2826
|
+
line-height: 1.4;
|
|
2827
|
+
min-height: calc(0.86rem * 1.4 * 2);
|
|
2828
|
+
color: var(--muted);
|
|
2829
|
+
display: -webkit-box;
|
|
2830
|
+
-webkit-line-clamp: 2;
|
|
2831
|
+
-webkit-box-orient: vertical;
|
|
2832
|
+
overflow: hidden;
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
.vol-field-error {
|
|
2836
|
+
display: block;
|
|
2837
|
+
font-style: normal;
|
|
2838
|
+
font-size: 0.8rem;
|
|
2839
|
+
line-height: 1.3;
|
|
2840
|
+
color: var(--danger, #b3261e);
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
.vol-form .field.has-error input,
|
|
2844
|
+
.vol-form .field.has-error select {
|
|
2845
|
+
border-color: var(--danger, #b3261e);
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
.vol-signed-in {
|
|
2849
|
+
margin: 0;
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
.vol-extra {
|
|
2853
|
+
display: grid;
|
|
2854
|
+
gap: 0.9rem;
|
|
2855
|
+
padding: 0.9rem;
|
|
2856
|
+
border: 1px dashed var(--line);
|
|
2857
|
+
border-radius: 12px;
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
.vol-extra .p60-form-heading {
|
|
2861
|
+
margin: 0;
|
|
2862
|
+
font-size: 1rem;
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
@media (max-width: 560px) {
|
|
2866
|
+
.vol-option {
|
|
2867
|
+
flex-direction: column;
|
|
2868
|
+
align-items: stretch;
|
|
2869
|
+
}
|
|
2870
|
+
.vol-option-meta {
|
|
2871
|
+
justify-items: start;
|
|
2872
|
+
text-align: start;
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2582
2876
|
/* ---- Members area (shell + sections; see components/members/) ----
|
|
2583
2877
|
Desktop: left rail + content. Small screens: the rail becomes a horizontal, scrollable pill
|
|
2584
2878
|
strip above the content — same registry, no separate mobile markup. */
|