srcdev-nuxt-components 9.3.7 → 9.3.8

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.
Files changed (108) hide show
  1. package/.claude/hooks/check-component-update.sh +30 -1
  2. package/.claude/skills/components/breadcrumb.md +49 -0
  3. package/.claude/skills/components/content-docs.md +1 -1
  4. package/.claude/skills/components/service-detail.md +156 -0
  5. package/.claude/skills/components/services-card-grid.md +9 -9
  6. package/.claude/skills/components/services-card.md +82 -30
  7. package/.claude/skills/index.md +3 -1
  8. package/.claude/skills/qa-panel.md +2 -2
  9. package/.vscode/srcdev-component-breadcrumb.code-snippets +14 -0
  10. package/.vscode/srcdev-component-service-detail.code-snippets +49 -0
  11. package/.vscode/srcdev-component-services-card.code-snippets +108 -0
  12. package/app/components/01.atoms/navigation/breadcrumb/Breadcrumb.vue +94 -0
  13. package/app/components/01.atoms/navigation/breadcrumb/CONSUMER-STYLING.md +32 -0
  14. package/app/components/01.atoms/navigation/breadcrumb/stories/Breadcrumb.stories.ts +87 -0
  15. package/app/components/01.atoms/navigation/breadcrumb/tests/Breadcrumb.spec.ts +87 -0
  16. package/app/components/01.atoms/navigation/breadcrumb/tests/__snapshots__/Breadcrumb.spec.ts.snap +13 -0
  17. package/app/components/03.organisms/services/service-detail/CONSUMER-STYLING.md +181 -0
  18. package/app/components/03.organisms/services/service-detail/ServiceDetail.vue +480 -0
  19. package/app/components/03.organisms/services/service-detail/stories/ServiceDetail.stories.ts +282 -0
  20. package/app/components/03.organisms/services/service-detail/tests/ServiceDetail.spec.ts +270 -0
  21. package/app/components/03.organisms/services/service-detail/tests/__snapshots__/ServiceDetail.spec.ts.snap +99 -0
  22. package/app/components/03.organisms/services/services-card/CONSUMER-STYLING.md +129 -0
  23. package/app/components/03.organisms/services/services-card/ServicesCard.vue +153 -39
  24. package/app/components/03.organisms/services/services-card/stories/ServicesCard.stories.ts +65 -0
  25. package/app/components/03.organisms/services/services-card/tests/ServicesCard.spec.ts +82 -0
  26. package/app/components/03.organisms/services/services-card/tests/__snapshots__/ServicesCard.spec.ts.snap +13 -5
  27. package/app/components/03.organisms/services/services-grids/ServicesCardGrid.vue +3 -7
  28. package/app/components/03.organisms/services/services-grids/stories/ServicesCardGrid.stories.ts +126 -2
  29. package/app/components/03.organisms/services/services-grids/stories/ServicesSectionGrid.stories.ts +6 -0
  30. package/app/components/03.organisms/services/services-grids/tests/__snapshots__/ServicesCardGrid.spec.ts.snap +51 -27
  31. package/app/types/components/breadcrumb.ts +4 -0
  32. package/app/types/components/index.ts +1 -0
  33. package/package.json +2 -2
  34. package/app/pages/auto-grid.vue +0 -328
  35. package/app/pages/banner-video.vue +0 -238
  36. package/app/pages/forms/examples/buttons/index.vue +0 -259
  37. package/app/pages/forms/examples/material/checkbox-radio-panels.vue +0 -244
  38. package/app/pages/forms/examples/material/cssbattle.vue +0 -60
  39. package/app/pages/forms/examples/material/text-fields.vue +0 -910
  40. package/app/pages/grid-stack.vue +0 -252
  41. package/app/pages/index.vue +0 -127
  42. package/app/pages/page-hero-highlights.vue +0 -204
  43. package/app/pages/samaritan.vue +0 -327
  44. package/app/pages/typography/hero-text.vue +0 -97
  45. package/app/pages/typography/index.vue +0 -39
  46. package/app/pages/typography/page-body.vue +0 -171
  47. package/app/pages/typography/page-heading.vue +0 -76
  48. package/app/pages/typography/page-link.vue +0 -103
  49. package/app/pages/ui/accordian.vue +0 -211
  50. package/app/pages/ui/anchor-scroll-tab-navigation.vue +0 -191
  51. package/app/pages/ui/anchor-scroll.vue +0 -367
  52. package/app/pages/ui/animated-svg-text.vue +0 -85
  53. package/app/pages/ui/block-decorators.vue +0 -142
  54. package/app/pages/ui/card-core.vue +0 -82
  55. package/app/pages/ui/carousel-basic.vue +0 -292
  56. package/app/pages/ui/carousel-flip.vue +0 -449
  57. package/app/pages/ui/carousel-infinite.vue +0 -260
  58. package/app/pages/ui/clipped-panels.vue +0 -101
  59. package/app/pages/ui/contact-section.vue +0 -323
  60. package/app/pages/ui/container-glow.vue +0 -106
  61. package/app/pages/ui/content-width.vue +0 -126
  62. package/app/pages/ui/deep-expanding-menu.vue +0 -138
  63. package/app/pages/ui/display-avatar.vue +0 -253
  64. package/app/pages/ui/display-banner.vue +0 -78
  65. package/app/pages/ui/display-chip.vue +0 -367
  66. package/app/pages/ui/display-details.vue +0 -171
  67. package/app/pages/ui/display-dialog.vue +0 -344
  68. package/app/pages/ui/display-pill.vue +0 -396
  69. package/app/pages/ui/display-prompt.vue +0 -284
  70. package/app/pages/ui/display-toast.vue +0 -311
  71. package/app/pages/ui/expanding-panel.vue +0 -326
  72. package/app/pages/ui/glowing-border.vue +0 -111
  73. package/app/pages/ui/layout-content-docs.vue +0 -72
  74. package/app/pages/ui/layout-grid-a.vue +0 -96
  75. package/app/pages/ui/layout-grid-b.vue +0 -132
  76. package/app/pages/ui/magnetic-navigation.vue +0 -50
  77. package/app/pages/ui/marquee-scroller.vue +0 -99
  78. package/app/pages/ui/mask-element.vue +0 -104
  79. package/app/pages/ui/masonry-columns.vue +0 -55
  80. package/app/pages/ui/masonry-grid-ordered-experiment.vue +0 -79
  81. package/app/pages/ui/masonry-grid-ordered.vue +0 -56
  82. package/app/pages/ui/masonry-grid-sorted.vue +0 -55
  83. package/app/pages/ui/masonry-grid.vue +0 -55
  84. package/app/pages/ui/navigation/navigation-horizontal.vue +0 -484
  85. package/app/pages/ui/navigation/site-navigation/about.vue +0 -36
  86. package/app/pages/ui/navigation/site-navigation/contact.vue +0 -39
  87. package/app/pages/ui/navigation/site-navigation/index.vue +0 -38
  88. package/app/pages/ui/navigation/site-navigation/portfolio.vue +0 -43
  89. package/app/pages/ui/navigation/site-navigation/services.vue +0 -42
  90. package/app/pages/ui/navigation/tab-navigation.vue +0 -493
  91. package/app/pages/ui/page-row.vue +0 -127
  92. package/app/pages/ui/price-list.vue +0 -65
  93. package/app/pages/ui/profile-section.vue +0 -142
  94. package/app/pages/ui/qr-code/[componentName].vue +0 -218
  95. package/app/pages/ui/rotating-carousel.vue +0 -154
  96. package/app/pages/ui/scroll-reveal-image.vue +0 -483
  97. package/app/pages/ui/section-parallax.vue +0 -54
  98. package/app/pages/ui/services/colour-finder.vue +0 -43
  99. package/app/pages/ui/services/services-cards.vue +0 -57
  100. package/app/pages/ui/services/services-section/[slug].vue +0 -61
  101. package/app/pages/ui/services/services-sections-compact.vue +0 -64
  102. package/app/pages/ui/settings.vue +0 -54
  103. package/app/pages/ui/simple-grid.vue +0 -55
  104. package/app/pages/ui/slider-gallery.vue +0 -261
  105. package/app/pages/ui/tabs-y.vue +0 -107
  106. package/app/pages/ui/tabs.vue +0 -189
  107. package/app/pages/ui/tooltips.vue +0 -104
  108. package/app/pages/ui/wipe-away-vertical.vue +0 -129
@@ -0,0 +1,480 @@
1
+ <template>
2
+ <component :is="tag" class="service-detail" :class="[elementClasses]" :aria-labelledby="ariaLabelledby">
3
+ <div class="service-detail__hero">
4
+ <NuxtImg
5
+ :src="serviceData.image"
6
+ :alt="serviceData.title"
7
+ :loading="imageLoading"
8
+ :fetchpriority="imageFetchPriority"
9
+ class="service-detail__hero-image"
10
+ />
11
+ <div class="service-detail__hero-overlay">
12
+ <div class="service-detail__hero-content">
13
+ <Breadcrumb :items="resolvedBreadcrumbItems" class="service-detail__breadcrumb" />
14
+ <EyebrowText font-size="large" :text-content="serviceData.subtitle" />
15
+ <HeroText
16
+ :id="headingId"
17
+ :tag="headerTag"
18
+ font-size="display"
19
+ :text-content="[{ text: serviceData.title, styleClass: 'normal' }]"
20
+ :style-class-passthrough="['mb-20']"
21
+ />
22
+ <div class="service-detail__hero-pills">
23
+ <DisplayPill :label="serviceData.duration" size="md" variant="neutral" />
24
+ <DisplayPill :label="`From ${serviceData.price}`" size="md" variant="neutral" />
25
+ </div>
26
+ </div>
27
+ </div>
28
+ </div>
29
+
30
+ <div class="service-detail__body">
31
+ <div class="service-detail__main">
32
+ <p class="page-body-normal">{{ serviceData.longDescription }}</p>
33
+
34
+ <HeroText
35
+ :tag="subheadingTag"
36
+ axis="horizontal"
37
+ font-size="subheading"
38
+ :text-content="serviceData.heroHeading"
39
+ :style-class-passthrough="['mb-20']"
40
+ />
41
+ <p class="page-body-normal">{{ serviceData.whatIsIt }}</p>
42
+
43
+ <HeroText
44
+ :tag="subheadingTag"
45
+ axis="horizontal"
46
+ font-size="subheading"
47
+ :text-content="[{ text: processHeading, styleClass: 'normal' }]"
48
+ :style-class-passthrough="['mb-20']"
49
+ />
50
+ <StepperList
51
+ tag="ol"
52
+ indicator-alignment="top"
53
+ indicator-variant="circle"
54
+ :connected="true"
55
+ :item-count="serviceData.process.length"
56
+ class="service-detail__process"
57
+ >
58
+ <template v-for="(step, i) in serviceData.process" :key="i" #[`item-${i}`]>
59
+ <p class="page-body-normal">{{ step }}</p>
60
+ </template>
61
+ </StepperList>
62
+
63
+ <HeroText
64
+ :tag="subheadingTag"
65
+ axis="horizontal"
66
+ font-size="subheading"
67
+ :text-content="[{ text: idealForHeading, styleClass: 'normal' }]"
68
+ :style-class-passthrough="['mb-20']"
69
+ />
70
+ <ul class="service-detail__ideal-for">
71
+ <li v-for="(item, i) in serviceData.idealFor" :key="i" class="service-detail__ideal-for-item">
72
+ <Icon name="mdi:diamond-stone" class="service-detail__ideal-for-icon" />
73
+ <p class="page-body-normal">{{ item }}</p>
74
+ </li>
75
+ </ul>
76
+
77
+ <HeroText
78
+ :tag="subheadingTag"
79
+ axis="horizontal"
80
+ font-size="subheading"
81
+ :text-content="[{ text: maintenanceHeading, styleClass: 'normal' }]"
82
+ :style-class-passthrough="['mb-20']"
83
+ />
84
+ <p class="page-body-normal">{{ serviceData.maintenance }}</p>
85
+
86
+ <HeroText
87
+ :tag="subheadingTag"
88
+ axis="horizontal"
89
+ font-size="subheading"
90
+ :text-content="[{ text: faqsHeading, styleClass: 'normal' }]"
91
+ :style-class-passthrough="['mb-20']"
92
+ />
93
+ <div class="service-detail__faqs">
94
+ <div v-for="(faq, i) in serviceData.faqs" :key="i" class="service-detail__faq">
95
+ <h3 class="service-detail__faq-question">{{ faq.question }}</h3>
96
+ <p class="page-body-normal">{{ faq.answer }}</p>
97
+ </div>
98
+ </div>
99
+ </div>
100
+
101
+ <aside class="service-detail__sidebar">
102
+ <GlassPanel :style-class-passthrough="['service-detail__booking-card']">
103
+ <p class="service-detail__sidebar-label">{{ bookingHeading }}</p>
104
+
105
+ <div class="service-detail__sidebar-row">
106
+ <span>{{ priceLabel }}</span>
107
+ <span>{{ serviceData.price }}</span>
108
+ </div>
109
+ <div class="service-detail__sidebar-row">
110
+ <span>{{ durationLabel }}</span>
111
+ <span>{{ serviceData.duration }}</span>
112
+ </div>
113
+ <div v-if="location" class="service-detail__sidebar-row">
114
+ <span>{{ locationLabel }}</span>
115
+ <span>{{ location }}</span>
116
+ </div>
117
+
118
+ <slot name="book-cta" :service-data="serviceData"></slot>
119
+
120
+ <div class="service-detail__sidebar-note">
121
+ <slot name="sidebar-note"></slot>
122
+ </div>
123
+ </GlassPanel>
124
+
125
+ <div v-if="relatedServices.length" class="service-detail__related">
126
+ <p class="service-detail__sidebar-label">{{ relatedServicesHeading }}</p>
127
+
128
+ <div class="service-detail__related-items">
129
+ <div v-for="(related, i) in relatedServices" :key="related.slug" class="service-detail__related-item-slot">
130
+ <slot name="related-service" :service="related" :index="i">
131
+ <div class="service-detail__related-item">
132
+ <NuxtImg
133
+ :src="related.image"
134
+ :alt="related.title"
135
+ loading="lazy"
136
+ class="service-detail__related-image"
137
+ />
138
+ <div class="service-detail__related-details">
139
+ <p class="service-detail__related-title">{{ related.title }}</p>
140
+ <p class="service-detail__related-price">{{ related.price }}</p>
141
+ </div>
142
+ </div>
143
+ </slot>
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </aside>
148
+ </div>
149
+
150
+ <div class="service-detail__final-cta">
151
+ <div class="service-detail__final-cta-copy">
152
+ <HeroText
153
+ :tag="subheadingTag"
154
+ axis="horizontal"
155
+ font-size="subheading"
156
+ :text-content="[{ text: finalCtaHeading, styleClass: 'normal' }]"
157
+ :style-class-passthrough="['mbs-0', 'mbe-8']"
158
+ />
159
+ <p class="page-body-normal">{{ finalCtaBody }}</p>
160
+ </div>
161
+ <slot name="final-cta" :service-data="serviceData"></slot>
162
+ </div>
163
+ </component>
164
+ </template>
165
+
166
+ <script setup lang="ts">
167
+ import type { Service } from "~/types/types.services";
168
+ import type { BreadcrumbItem } from "~/types/components/breadcrumb";
169
+
170
+ interface Props {
171
+ tag?: "div" | "section" | "article" | "main";
172
+ headerTag?: "h1" | "h2" | "h3";
173
+ subheadingTag?: "h2" | "h3";
174
+ serviceData: Service;
175
+ breadcrumbItems?: BreadcrumbItem[];
176
+ processHeading?: string;
177
+ idealForHeading?: string;
178
+ maintenanceHeading?: string;
179
+ faqsHeading?: string;
180
+ bookingHeading?: string;
181
+ priceLabel?: string;
182
+ durationLabel?: string;
183
+ locationLabel?: string;
184
+ location?: string;
185
+ relatedServicesHeading?: string;
186
+ relatedServices?: Service[];
187
+ finalCtaHeading?: string;
188
+ finalCtaBody?: string;
189
+ imageLoading?: "eager" | "lazy";
190
+ imageFetchPriority?: "high" | "auto" | "low";
191
+ styleClassPassthrough?: string | string[];
192
+ }
193
+
194
+ const props = withDefaults(defineProps<Props>(), {
195
+ tag: "div",
196
+ headerTag: "h1",
197
+ subheadingTag: "h2",
198
+ breadcrumbItems: undefined,
199
+ processHeading: "The Process",
200
+ idealForHeading: "Ideal For",
201
+ maintenanceHeading: "Aftercare & Maintenance",
202
+ faqsHeading: "Frequently Asked Questions",
203
+ bookingHeading: "Book This Service",
204
+ priceLabel: "Price",
205
+ durationLabel: "Duration",
206
+ locationLabel: "Location",
207
+ location: undefined,
208
+ relatedServicesHeading: "You May Also Like",
209
+ relatedServices: () => [],
210
+ finalCtaHeading: "Ready to book your appointment?",
211
+ finalCtaBody: "Get in touch to book your appointment.",
212
+ imageLoading: "eager",
213
+ imageFetchPriority: "high",
214
+ styleClassPassthrough: () => [],
215
+ });
216
+
217
+ const { headingId, ariaLabelledby } = useAriaLabelledById(() => props.tag);
218
+
219
+ // Falls back to a plain, non-linked breadcrumb built from the service's own category/title
220
+ // when the consumer doesn't pass real routes — routing is always the consumer's decision.
221
+ const resolvedBreadcrumbItems = computed<BreadcrumbItem[]>(
222
+ () => props.breadcrumbItems ?? [{ label: props.serviceData.category }, { label: props.serviceData.title }]
223
+ );
224
+
225
+ const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
226
+
227
+ watch(
228
+ () => props.styleClassPassthrough,
229
+ () => {
230
+ resetElementClasses(props.styleClassPassthrough);
231
+ }
232
+ );
233
+ </script>
234
+
235
+ <style lang="css">
236
+ @layer components {
237
+ .service-detail {
238
+ container-type: inline-size;
239
+ container-name: service-detail;
240
+
241
+ .service-detail__hero {
242
+ position: relative;
243
+ border-radius: var(--service-detail-hero-border-radius, 0.8rem);
244
+ overflow: hidden;
245
+ min-height: var(--service-detail-hero-min-height, 32rem);
246
+
247
+ .service-detail__hero-image {
248
+ display: block;
249
+ width: 100%;
250
+ height: 100%;
251
+ object-fit: cover;
252
+ position: absolute;
253
+ inset: 0;
254
+ }
255
+
256
+ .service-detail__hero-overlay {
257
+ position: relative;
258
+ display: flex;
259
+ align-items: flex-end;
260
+ min-height: var(--service-detail-hero-min-height, 32rem);
261
+ padding: var(--service-detail-hero-padding, 2.4rem);
262
+ background: var(
263
+ --service-detail-hero-scrim,
264
+ linear-gradient(0deg, rgb(0 0 0 / 70%) 0%, rgb(0 0 0 / 10%) 60%, transparent 100%)
265
+ );
266
+
267
+ .service-detail__breadcrumb {
268
+ --breadcrumb-colour: var(--service-detail-hero-text-colour, white);
269
+ margin-block-end: var(--service-detail-breadcrumb-margin-block-end, 0.8rem);
270
+ }
271
+
272
+ .eyebrow-text,
273
+ .hero-text {
274
+ color: var(--service-detail-hero-text-colour, white);
275
+ }
276
+
277
+ .service-detail__hero-pills {
278
+ display: flex;
279
+ flex-wrap: wrap;
280
+ gap: var(--service-detail-hero-pills-gap, 0.8rem);
281
+
282
+ --theme-pill-bg: var(--service-detail-hero-pill-bg, transparent);
283
+ --theme-pill-color: var(--service-detail-hero-text-colour, white);
284
+ --theme-pill-border-color: var(--service-detail-hero-pill-border-colour, currentColor);
285
+ }
286
+ }
287
+ }
288
+
289
+ .service-detail__body {
290
+ display: grid;
291
+ grid-template-columns: 1fr;
292
+ gap: var(--service-detail-body-gap, 3rem);
293
+ margin-block-start: var(--service-detail-body-margin-block-start, 3rem);
294
+
295
+ @container (width >= 900px) {
296
+ grid-template-columns: minmax(0, 1fr) minmax(28rem, 34rem);
297
+ align-items: start;
298
+ }
299
+
300
+ .service-detail__main {
301
+ min-inline-size: 0;
302
+ display: flex;
303
+ flex-direction: column;
304
+ gap: var(--service-detail-main-section-gap, 2.4rem);
305
+ }
306
+
307
+ .service-detail__process {
308
+ --stepper-list-gap: var(--service-detail-process-step-gap, 1.6rem);
309
+ --stepper-list-padding-block: var(--service-detail-process-step-padding-block, 1.6rem);
310
+ --stepper-list-connector-color: var(--service-detail-process-divider-colour, currentColor);
311
+ --stepper-list-counter-circle-text: var(--service-detail-process-index-colour, var(--colour-text-accent));
312
+ --stepper-list-counter-circle-border: var(--service-detail-process-index-colour, var(--colour-text-accent));
313
+ --stepper-list-counter-font-size: var(--service-detail-process-index-font-size, 1.4rem);
314
+ }
315
+
316
+ .service-detail__ideal-for {
317
+ list-style: none;
318
+ margin: 0;
319
+ padding: 0;
320
+ display: grid;
321
+ grid-template-columns: 1fr;
322
+ gap: var(--service-detail-ideal-for-gap, 1.2rem);
323
+
324
+ @container (width >= 500px) {
325
+ grid-template-columns: 1fr 1fr;
326
+ }
327
+
328
+ .service-detail__ideal-for-item {
329
+ display: flex;
330
+ align-items: flex-start;
331
+ gap: var(--service-detail-ideal-for-item-gap, 1rem);
332
+ padding: var(--service-detail-ideal-for-item-padding, 1.6rem);
333
+ background-color: var(--service-detail-ideal-for-item-background, var(--slate-09));
334
+ border: 1px solid var(--service-detail-ideal-for-item-border-colour, var(--slate-06));
335
+ border-radius: var(--service-detail-ideal-for-item-border-radius, 0.4rem);
336
+
337
+ .service-detail__ideal-for-icon {
338
+ flex-shrink: 0;
339
+ width: var(--service-detail-ideal-for-icon-size, 1.6rem);
340
+ height: var(--service-detail-ideal-for-icon-size, 1.6rem);
341
+ color: var(--service-detail-ideal-for-icon-colour, var(--colour-text-accent));
342
+ }
343
+
344
+ p {
345
+ margin: 0;
346
+ }
347
+ }
348
+ }
349
+
350
+ .service-detail__faqs {
351
+ display: flex;
352
+ flex-direction: column;
353
+
354
+ .service-detail__faq {
355
+ padding-block: var(--service-detail-faq-padding-block, 1.6rem);
356
+ border-block-end: 1px solid var(--service-detail-faq-divider-colour, currentColor);
357
+
358
+ &:first-child {
359
+ padding-block-start: 0;
360
+ }
361
+ &:last-child {
362
+ border-block-end: none;
363
+ }
364
+
365
+ .service-detail__faq-question {
366
+ margin: 0 0 var(--service-detail-faq-question-margin-block-end, 0.8rem);
367
+ font-size: var(--service-detail-faq-question-font-size, 1.6rem);
368
+ }
369
+ }
370
+ }
371
+ }
372
+
373
+ .service-detail__sidebar {
374
+ display: flex;
375
+ flex-direction: column;
376
+ gap: var(--service-detail-sidebar-gap, 2rem);
377
+ position: sticky;
378
+ top: var(--service-detail-sidebar-sticky-offset, 2rem);
379
+
380
+ .service-detail__sidebar-label {
381
+ margin: 0 0 var(--service-detail-sidebar-label-margin-block-end, 1.6rem);
382
+ font-size: var(--service-detail-sidebar-label-font-size, 1.2rem);
383
+ text-transform: uppercase;
384
+ letter-spacing: var(--service-detail-sidebar-label-letter-spacing, 0.05em);
385
+ opacity: var(--service-detail-muted-opacity, 0.7);
386
+ }
387
+
388
+ .service-detail__booking-card {
389
+ padding: var(--service-detail-booking-card-padding, 2.4rem);
390
+ }
391
+
392
+ .service-detail__sidebar-row {
393
+ display: flex;
394
+ justify-content: space-between;
395
+ gap: var(--service-detail-sidebar-row-gap, 1rem);
396
+ padding-block: var(--service-detail-sidebar-row-padding-block, 1rem);
397
+ border-block-start: 1px solid var(--service-detail-sidebar-row-divider-colour, currentColor);
398
+
399
+ span:first-child {
400
+ text-transform: uppercase;
401
+ font-size: var(--service-detail-sidebar-row-label-font-size, 1.2rem);
402
+ opacity: var(--service-detail-muted-opacity, 0.7);
403
+ }
404
+ }
405
+
406
+ .service-detail__sidebar-note {
407
+ margin-block-start: var(--service-detail-sidebar-note-margin-block-start, 1.2rem);
408
+ font-size: var(--service-detail-sidebar-note-font-size, 1.2rem);
409
+ opacity: var(--service-detail-muted-opacity, 0.7);
410
+
411
+ &:empty {
412
+ display: none;
413
+ }
414
+ }
415
+
416
+ .service-detail__related {
417
+ .service-detail__related-items {
418
+ display: grid;
419
+ gap: var(--service-detail-related-items-gap, 1rem);
420
+
421
+ .service-detail__related-item-slot {
422
+ background-color: var(--service-detail-related-item-background, var(--slate-09));
423
+ padding: var(--service-detail-related-item-padding, 1rem);
424
+ border: 1px solid var(--service-detail-related-item-border-colour, var(--slate-06));
425
+ border-radius: var(--service-detail-related-item-border-radius, 0.4rem);
426
+ }
427
+
428
+ .service-detail__related-item {
429
+ display: grid;
430
+ grid-template-columns: auto 1fr;
431
+ gap: var(--service-detail-related-item-gap, 1.2rem);
432
+ align-items: center;
433
+
434
+ .service-detail__related-image {
435
+ width: var(--service-detail-related-image-size, 5.6rem);
436
+ height: var(--service-detail-related-image-size, 5.6rem);
437
+ border-radius: var(--service-detail-related-image-border-radius, 0.4rem);
438
+ object-fit: cover;
439
+ display: block;
440
+ }
441
+
442
+ .service-detail__related-title,
443
+ .service-detail__related-price {
444
+ margin: 0;
445
+ }
446
+
447
+ .service-detail__related-price {
448
+ font-size: var(--service-detail-related-price-font-size, 1.2rem);
449
+ opacity: var(--service-detail-muted-opacity, 0.7);
450
+ }
451
+ }
452
+ }
453
+ }
454
+ }
455
+
456
+ .service-detail__final-cta {
457
+ display: flex;
458
+ flex-direction: column;
459
+ gap: var(--service-detail-final-cta-gap, 1.6rem);
460
+ align-items: flex-start;
461
+ justify-content: space-between;
462
+ margin-block-start: var(--service-detail-final-cta-margin-block-start, 4rem);
463
+ padding-block-start: var(--service-detail-final-cta-padding-block-start, 3.2rem);
464
+ border-block-start: 1px solid var(--service-detail-final-cta-divider-colour, currentColor);
465
+
466
+ @container (width >= 700px) {
467
+ flex-direction: row;
468
+ align-items: center;
469
+ }
470
+
471
+ .service-detail__final-cta-copy {
472
+ p {
473
+ margin: 0;
474
+ opacity: var(--service-detail-muted-opacity, 0.7);
475
+ }
476
+ }
477
+ }
478
+ }
479
+ }
480
+ </style>