@runwell/shopify-toolkit 0.17.4 → 0.21.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/bin/runwell-shopify +14 -2
- package/lib/list.js +133 -0
- package/lib/qa-bundles.js +117 -0
- package/lib/qa.js +147 -13
- package/modules/INDEX.md +65 -23
- package/modules/_shared/css-tokens/assets/runwell-tokens.css +24 -4
- package/modules/_shared/css-tokens/module.json +2 -2
- package/modules/_shared/css-typography/assets/runwell-typography.css +14 -6
- package/modules/_shared/css-typography/module.json +2 -2
- package/modules/bundle-builder/README.md +6 -1
- package/modules/bundle-builder/module.json +5 -1
- package/modules/care-coaching-medvi/README.md +46 -0
- package/modules/care-coaching-medvi/assets/runwell-care-coaching-medvi.css +241 -0
- package/modules/care-coaching-medvi/module.json +80 -0
- package/modules/care-coaching-medvi/sections/runwell-care-coaching-medvi.liquid +274 -0
- package/modules/care-coaching-medvi/snippets/runwell-care-coaching-medvi-circular-text.liquid +25 -0
- package/modules/cart-cross-sell/snippets/runwell-cart-xsell.liquid +16 -0
- package/modules/collection-block-medvi/README.md +50 -0
- package/modules/collection-block-medvi/assets/runwell-collection-block-medvi.css +242 -0
- package/modules/collection-block-medvi/module.json +83 -0
- package/modules/collection-block-medvi/sections/runwell-collection-block-medvi.liquid +355 -0
- package/modules/product-trio-medvi/README.md +35 -0
- package/modules/product-trio-medvi/assets/runwell-product-trio-medvi.css +119 -0
- package/modules/product-trio-medvi/module.json +48 -0
- package/modules/product-trio-medvi/sections/runwell-product-trio-medvi.liquid +188 -0
- package/modules/runwell-bundle-system/README.md +35 -0
- package/modules/runwell-bundle-system/admin-metafields.json +46 -0
- package/modules/runwell-bundle-system/assets/runwell-bundle-system.css +861 -0
- package/modules/runwell-bundle-system/assets/runwell-bundle-system.js +287 -0
- package/modules/runwell-bundle-system/module.json +126 -0
- package/modules/runwell-bundle-system/qa/mobile-checklist.md +105 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-cart-xsell.liquid +59 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-collection.liquid +121 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-home-stacks.liquid +77 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-pdp-banner.liquid +50 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-pdp-pairs-with.liquid +72 -0
- package/modules/runwell-bundle-system/sections/runwell-bundle-pdp.liquid +105 -0
- package/modules/runwell-bundle-system/settings.json +25 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-card.liquid +70 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-cross-supplier.liquid +18 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-data.liquid +67 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-fomo.liquid +32 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-free-gift.liquid +34 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-multi-product.liquid +86 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-pricing.liquid +30 -0
- package/modules/runwell-bundle-system/snippets/runwell-bundle-quantity-tiers.liquid +73 -0
- package/modules/testimonials-medvi/README.md +44 -0
- package/modules/testimonials-medvi/assets/runwell-testimonials-medvi.css +239 -0
- package/modules/testimonials-medvi/module.json +68 -0
- package/modules/testimonials-medvi/sections/runwell-testimonials-medvi.liquid +355 -0
- package/package.json +2 -2
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-free-gift.liquid.
|
|
3
|
+
Wraps the gift-with-purchase module. The bundle's free-gift handle is
|
|
4
|
+
passed in. Display only here; the actual auto-add to cart logic lives
|
|
5
|
+
in the gift-with-purchase module's runwell-gwp.js.
|
|
6
|
+
|
|
7
|
+
Inputs:
|
|
8
|
+
bundle_free_gift_handle (product handle of the gift)
|
|
9
|
+
{%- endcomment -%}
|
|
10
|
+
|
|
11
|
+
{%- if bundle_free_gift_handle != blank -%}
|
|
12
|
+
{%- assign gift_product = all_products[bundle_free_gift_handle] -%}
|
|
13
|
+
{%- if gift_product != blank -%}
|
|
14
|
+
<div class="runwell-bundle-system__free-gift" data-runwell-bundle-free-gift data-gift-handle="{{ bundle_free_gift_handle }}">
|
|
15
|
+
<p class="runwell-bundle-system__free-gift-label">Plus a free gift:</p>
|
|
16
|
+
<div class="runwell-bundle-system__free-gift-product">
|
|
17
|
+
{%- if gift_product.featured_image -%}
|
|
18
|
+
{{ gift_product.featured_image | image_url: width: 80 | image_tag:
|
|
19
|
+
width: 60,
|
|
20
|
+
height: 60,
|
|
21
|
+
loading: 'lazy',
|
|
22
|
+
class: 'runwell-bundle-system__free-gift-thumb',
|
|
23
|
+
alt: gift_product.title
|
|
24
|
+
}}
|
|
25
|
+
{%- endif -%}
|
|
26
|
+
<span class="runwell-bundle-system__free-gift-name">{{ gift_product.title }}</span>
|
|
27
|
+
<span class="runwell-bundle-system__free-gift-price">
|
|
28
|
+
<s>{{ gift_product.price | money }}</s>
|
|
29
|
+
<strong>Free</strong>
|
|
30
|
+
</span>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
{%- endif -%}
|
|
34
|
+
{%- endif -%}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-multi-product.liquid.
|
|
3
|
+
Mode B render. Lists the bundle's component products (thumbnail, qty,
|
|
4
|
+
name, individual price), the bundle pricing block (delegated to
|
|
5
|
+
runwell-bundle-pricing), and the single Add to Cart button that adds
|
|
6
|
+
the bundle product as one line item.
|
|
7
|
+
|
|
8
|
+
Inputs:
|
|
9
|
+
product
|
|
10
|
+
bundle_pricing_model
|
|
11
|
+
bundle_components (array of {product_handle, qty})
|
|
12
|
+
bundle_subtotal (sum of component prices)
|
|
13
|
+
bundle_price (the bundle product's price)
|
|
14
|
+
bundle_savings_amount
|
|
15
|
+
bundle_savings_pct
|
|
16
|
+
{%- endcomment -%}
|
|
17
|
+
|
|
18
|
+
{% render 'runwell-bundle-pricing',
|
|
19
|
+
bundle_pricing_model: bundle_pricing_model,
|
|
20
|
+
bundle_price: bundle_price,
|
|
21
|
+
bundle_subtotal: bundle_subtotal,
|
|
22
|
+
bundle_savings_amount: bundle_savings_amount,
|
|
23
|
+
bundle_savings_pct: bundle_savings_pct
|
|
24
|
+
%}
|
|
25
|
+
|
|
26
|
+
<div class="runwell-bundle-system__components">
|
|
27
|
+
<p class="runwell-bundle-system__components-heading">Includes:</p>
|
|
28
|
+
<ul class="runwell-bundle-system__components-list" role="list">
|
|
29
|
+
{%- if bundle_components and bundle_components.size > 0 -%}
|
|
30
|
+
{%- for component in bundle_components -%}
|
|
31
|
+
{%- assign comp_product = all_products[component.product_handle] -%}
|
|
32
|
+
{%- assign comp_qty = component.qty | default: 1 -%}
|
|
33
|
+
<li class="runwell-bundle-system__component">
|
|
34
|
+
{%- if comp_product != blank and comp_product.featured_image -%}
|
|
35
|
+
{{ comp_product.featured_image | image_url: width: 120 | image_tag:
|
|
36
|
+
width: 60,
|
|
37
|
+
height: 60,
|
|
38
|
+
loading: 'lazy',
|
|
39
|
+
class: 'runwell-bundle-system__component-thumb',
|
|
40
|
+
alt: comp_product.title
|
|
41
|
+
}}
|
|
42
|
+
{%- else -%}
|
|
43
|
+
<span class="runwell-bundle-system__component-thumb runwell-bundle-system__component-thumb--placeholder" aria-hidden="true"></span>
|
|
44
|
+
{%- endif -%}
|
|
45
|
+
|
|
46
|
+
<span class="runwell-bundle-system__component-qty">{{ comp_qty }}x</span>
|
|
47
|
+
|
|
48
|
+
<span class="runwell-bundle-system__component-name">
|
|
49
|
+
{%- if comp_product != blank -%}
|
|
50
|
+
{{ comp_product.title }}
|
|
51
|
+
{%- else -%}
|
|
52
|
+
<em>(unavailable)</em>
|
|
53
|
+
{%- endif -%}
|
|
54
|
+
</span>
|
|
55
|
+
|
|
56
|
+
{%- if comp_product != blank -%}
|
|
57
|
+
<span class="runwell-bundle-system__component-price">{{ comp_product.price | money }}</span>
|
|
58
|
+
{%- endif -%}
|
|
59
|
+
</li>
|
|
60
|
+
{%- endfor -%}
|
|
61
|
+
{%- else -%}
|
|
62
|
+
<li class="runwell-bundle-system__component runwell-bundle-system__component--empty">
|
|
63
|
+
<em>No components configured. Set the runwell.bundle_components metafield on this bundle product.</em>
|
|
64
|
+
</li>
|
|
65
|
+
{%- endif -%}
|
|
66
|
+
</ul>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
{%- form 'product', product, class: 'runwell-bundle-system__form', novalidate: 'novalidate' -%}
|
|
70
|
+
<input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
|
|
71
|
+
<input type="hidden" name="quantity" value="1">
|
|
72
|
+
<button
|
|
73
|
+
type="submit"
|
|
74
|
+
name="add"
|
|
75
|
+
class="runwell-bundle-system__atc button button--primary button--full-width"
|
|
76
|
+
{% if product.available == false %}disabled{% endif %}
|
|
77
|
+
>
|
|
78
|
+
<span class="runwell-bundle-system__atc-label">
|
|
79
|
+
{%- if product.available -%}
|
|
80
|
+
Add bundle to cart
|
|
81
|
+
{%- else -%}
|
|
82
|
+
Sold out
|
|
83
|
+
{%- endif -%}
|
|
84
|
+
</span>
|
|
85
|
+
</button>
|
|
86
|
+
{%- endform -%}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-pricing.liquid.
|
|
3
|
+
Shared price + strikethrough subtotal + savings badge. Used by Mode B
|
|
4
|
+
(multi-product) and bundle cards on Surfaces 1 to 5.
|
|
5
|
+
|
|
6
|
+
Inputs:
|
|
7
|
+
bundle_price (the bundle product's selling price, in cents)
|
|
8
|
+
bundle_subtotal (sum of component prices, in cents; 0 if not multi-product)
|
|
9
|
+
bundle_savings_amount (subtotal - price, in cents; 0 if no savings)
|
|
10
|
+
bundle_savings_pct (savings_amount / subtotal * 100; 0 if no savings)
|
|
11
|
+
bundle_pricing_model (used to choose dollar vs percent badge format)
|
|
12
|
+
{%- endcomment -%}
|
|
13
|
+
|
|
14
|
+
<div class="runwell-bundle-system__pricing">
|
|
15
|
+
<span class="runwell-bundle-system__pricing-current">{{ bundle_price | money }}</span>
|
|
16
|
+
|
|
17
|
+
{%- if bundle_subtotal > bundle_price -%}
|
|
18
|
+
<span class="runwell-bundle-system__pricing-strikethrough">{{ bundle_subtotal | money }}</span>
|
|
19
|
+
{%- endif -%}
|
|
20
|
+
|
|
21
|
+
{%- if bundle_savings_amount > 0 -%}
|
|
22
|
+
<span class="runwell-bundle-system__pricing-badge">
|
|
23
|
+
{%- if bundle_pricing_model == 'percent_off_subtotal' -%}
|
|
24
|
+
Save {{ bundle_savings_pct }}%
|
|
25
|
+
{%- else -%}
|
|
26
|
+
Save {{ bundle_savings_amount | money_without_trailing_zeros }}
|
|
27
|
+
{%- endif -%}
|
|
28
|
+
</span>
|
|
29
|
+
{%- endif -%}
|
|
30
|
+
</div>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
runwell-bundle-system: runwell-bundle-quantity-tiers.liquid.
|
|
3
|
+
Mode A radio picker. Renders one row per tier in bundle_quantity_tiers
|
|
4
|
+
metafield. Default selection is the highest discount_pct tier (last in
|
|
5
|
+
the array, by convention). Display only; the discount itself is applied
|
|
6
|
+
by a Shopify Function (see module.json admin_steps:
|
|
7
|
+
configure-quantity-tier-discount-function).
|
|
8
|
+
|
|
9
|
+
Inputs (passed via render):
|
|
10
|
+
product
|
|
11
|
+
bundle_pricing_model
|
|
12
|
+
bundle_quantity_tiers (array of {qty, discount_pct})
|
|
13
|
+
section
|
|
14
|
+
{%- endcomment -%}
|
|
15
|
+
|
|
16
|
+
{%- if bundle_quantity_tiers and bundle_quantity_tiers.size > 0 -%}
|
|
17
|
+
{%- assign default_tier_index = bundle_quantity_tiers.size | minus: 1 -%}
|
|
18
|
+
|
|
19
|
+
{%- form 'product', product, class: 'runwell-bundle-system__form', novalidate: 'novalidate' -%}
|
|
20
|
+
<fieldset class="runwell-bundle-system__tiers" aria-label="Choose quantity">
|
|
21
|
+
<legend class="visually-hidden">Choose quantity</legend>
|
|
22
|
+
{%- for tier in bundle_quantity_tiers -%}
|
|
23
|
+
{%- assign discount_amount = product.price | times: tier.discount_pct | divided_by: 100 -%}
|
|
24
|
+
{%- assign per_unit_price = product.price | minus: discount_amount -%}
|
|
25
|
+
{%- assign total_price = per_unit_price | times: tier.qty -%}
|
|
26
|
+
{%- assign full_price = product.price | times: tier.qty -%}
|
|
27
|
+
{%- assign savings = full_price | minus: total_price -%}
|
|
28
|
+
|
|
29
|
+
<label class="runwell-bundle-system__tier" data-qty="{{ tier.qty }}" data-discount-pct="{{ tier.discount_pct }}">
|
|
30
|
+
<input
|
|
31
|
+
type="radio"
|
|
32
|
+
name="quantity"
|
|
33
|
+
value="{{ tier.qty }}"
|
|
34
|
+
class="runwell-bundle-system__tier-input"
|
|
35
|
+
{% if forloop.index0 == default_tier_index %}checked{% endif %}
|
|
36
|
+
>
|
|
37
|
+
<span class="runwell-bundle-system__tier-row">
|
|
38
|
+
<span class="runwell-bundle-system__tier-qty">{{ tier.qty }}{% if tier.qty == 1 %} unit{% else %} units{% endif %}</span>
|
|
39
|
+
{%- if tier.discount_pct > 0 -%}
|
|
40
|
+
<span class="runwell-bundle-system__tier-savings-badge">Save {{ tier.discount_pct }}%</span>
|
|
41
|
+
{%- endif -%}
|
|
42
|
+
</span>
|
|
43
|
+
<span class="runwell-bundle-system__tier-row runwell-bundle-system__tier-row--prices">
|
|
44
|
+
<span class="runwell-bundle-system__tier-total">{{ total_price | money }}</span>
|
|
45
|
+
{%- if tier.discount_pct > 0 -%}
|
|
46
|
+
<span class="runwell-bundle-system__tier-strikethrough">{{ full_price | money }}</span>
|
|
47
|
+
{%- endif -%}
|
|
48
|
+
<span class="runwell-bundle-system__tier-per-unit">{{ per_unit_price | money }} / unit</span>
|
|
49
|
+
</span>
|
|
50
|
+
</label>
|
|
51
|
+
{%- endfor -%}
|
|
52
|
+
</fieldset>
|
|
53
|
+
|
|
54
|
+
<input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
|
|
55
|
+
|
|
56
|
+
<button
|
|
57
|
+
type="submit"
|
|
58
|
+
name="add"
|
|
59
|
+
class="runwell-bundle-system__atc button button--primary button--full-width"
|
|
60
|
+
{% if product.selected_or_first_available_variant.available == false %}disabled{% endif %}
|
|
61
|
+
>
|
|
62
|
+
<span class="runwell-bundle-system__atc-label">
|
|
63
|
+
{%- if product.selected_or_first_available_variant.available -%}
|
|
64
|
+
Add to cart
|
|
65
|
+
{%- else -%}
|
|
66
|
+
Sold out
|
|
67
|
+
{%- endif -%}
|
|
68
|
+
</span>
|
|
69
|
+
</button>
|
|
70
|
+
{%- endform -%}
|
|
71
|
+
{%- else -%}
|
|
72
|
+
<p class="runwell-bundle-system__empty">No quantity tiers configured for this bundle.</p>
|
|
73
|
+
{%- endif -%}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# testimonials-medvi
|
|
2
|
+
|
|
3
|
+
Interleaved photo card + quote card mosaic in a CSS grid. Magazine-spread feel. Blocks of type `quote` and `photo` are user-droppable in the Theme Editor; the designer controls visual rhythm by ordering blocks.
|
|
4
|
+
|
|
5
|
+
Category: `social-proof`
|
|
6
|
+
|
|
7
|
+
## Files
|
|
8
|
+
|
|
9
|
+
- `sections/runwell-testimonials-medvi.liquid`
|
|
10
|
+
- `assets/runwell-testimonials-medvi.css`
|
|
11
|
+
|
|
12
|
+
## Layout
|
|
13
|
+
|
|
14
|
+
- Header: centered eyebrow + 2-color split headline + lede.
|
|
15
|
+
- Grid: responsive 1/2/4 columns at 320 / 768 / 1024 px breakpoints. Each cell has a 5:6 aspect ratio; photos and quote cards line up.
|
|
16
|
+
- Cells flow naturally; designer arranges blocks in the Theme Editor for the photo + quote interleave.
|
|
17
|
+
- Up to 12 blocks (max_blocks).
|
|
18
|
+
|
|
19
|
+
## Tokens consumed
|
|
20
|
+
|
|
21
|
+
Brand: `--runwell-oat`, `--runwell-primary`, `--runwell-tertiary`. Design system: `--runwell-radius-lg`. Typography: `--runwell-eyebrow-size`, `--runwell-h2-size`, `--runwell-body-size`, `--runwell-meta-size`, `--runwell-cta-size`.
|
|
22
|
+
|
|
23
|
+
## Block types
|
|
24
|
+
|
|
25
|
+
- **quote**: author, rating (range 0 to 5), quote (richtext). Renders as padded card with author + star rating row + quote body.
|
|
26
|
+
- **photo**: image (uploaded) with image_asset fallback, image_focal (center / top / bottom). Renders as full-bleed portrait card with `object-fit: cover` driven by focal point.
|
|
27
|
+
|
|
28
|
+
## Lineage
|
|
29
|
+
|
|
30
|
+
Extracted from `https://home.medvi.org/` on 2026-05-06. Framer label: `What Our Clients Say Parallax Scroll Section`. Scrape path: `_clients/capital-v/lushi/research/medvi-reference/site-scrape/`.
|
|
31
|
+
|
|
32
|
+
The medvi reference uses an interleaved row pattern: row 1 = `[photo, quote, quote, quote]`, row 2 = `[quote, quote, photo, quote]`. We keep the layout flexible (CSS grid plus block order) rather than encoding the pattern in code; designers reproduce the rhythm by ordering blocks.
|
|
33
|
+
|
|
34
|
+
## Tenant overrides
|
|
35
|
+
|
|
36
|
+
- `runwell.config.json` brand block: rewires the global tokens.
|
|
37
|
+
- Per-instance Theme Editor: header copy, accent color, card background, star color, bg band, plus block ordering and content.
|
|
38
|
+
|
|
39
|
+
## Notes
|
|
40
|
+
|
|
41
|
+
- Photo focal point: medvi crops portraits tight with face at top of frame. Default is `center`; use `top` for headshots and `bottom` for full-body shots where the bottom should anchor the visual.
|
|
42
|
+
- Star rating: ASCII `★` glyph in the configured color. Zero rating hides the star row.
|
|
43
|
+
- Default preset includes 6 quote cards + 2 photo placeholders, using medvi's reference quotes (with anonymised first names). Tenants replace the preset content with their own customer testimonials post-launch.
|
|
44
|
+
- Mobile: grid collapses to 1 column, then 2 columns at 768px, then 4 columns at 1024px.
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/* Runwell testimonials-medvi.
|
|
2
|
+
|
|
3
|
+
Two horizontal marquee rows. Each row scrolls continuously; row 2
|
|
4
|
+
reverses direction. Cards are landscape (~16:9), ~400px wide. Photos
|
|
5
|
+
fill cards with object-fit cover. Quote cards have tinted background,
|
|
6
|
+
padded interior with author + star row + quote body.
|
|
7
|
+
|
|
8
|
+
Loop: each row's content rendered twice in DOM. CSS animation
|
|
9
|
+
translates by -50% (one full set width) over the configured duration
|
|
10
|
+
(--rw-tm-duration). When set 1 leaves viewport, set 2 has taken its
|
|
11
|
+
place; loop is seamless.
|
|
12
|
+
|
|
13
|
+
Accessibility: pause on hover and on focus-within for users navigating
|
|
14
|
+
with keyboard. Stops entirely on prefers-reduced-motion.
|
|
15
|
+
|
|
16
|
+
Tokens: --runwell-oat, --runwell-primary, --runwell-tertiary,
|
|
17
|
+
--runwell-radius-lg.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
.runwell-testimonials-medvi {
|
|
21
|
+
padding: clamp(3rem, 8vw, 7rem) 0;
|
|
22
|
+
font-family: var(--font-body-family, inherit);
|
|
23
|
+
color: var(--runwell-tertiary, #0B3D38);
|
|
24
|
+
|
|
25
|
+
/* css custom properties driven from Liquid; defaults below are fallbacks */
|
|
26
|
+
--rw-tm-duration: 60s;
|
|
27
|
+
--rw-tm-card-w: 400px;
|
|
28
|
+
--rw-tm-gap: 20px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.runwell-testimonials-medvi--bg-white {
|
|
32
|
+
background: #ffffff;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.runwell-testimonials-medvi--bg-oat {
|
|
36
|
+
background: var(--runwell-oat, #F5F0EE);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.runwell-testimonials-medvi--bg-celadon-tint {
|
|
40
|
+
background: color-mix(in srgb, var(--runwell-celadon, #ADDDBD) 18%, white);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* ----- Header ----- */
|
|
44
|
+
|
|
45
|
+
.runwell-testimonials-medvi__header {
|
|
46
|
+
max-width: 760px;
|
|
47
|
+
margin: 0 auto clamp(2rem, 5vw, 4rem);
|
|
48
|
+
padding: 0 clamp(1.5rem, 4vw, 3rem);
|
|
49
|
+
text-align: center;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.runwell-testimonials-medvi__eyebrow {
|
|
53
|
+
font-size: var(--runwell-eyebrow-size, 0.78rem);
|
|
54
|
+
letter-spacing: 0.16em;
|
|
55
|
+
text-transform: uppercase;
|
|
56
|
+
font-weight: 600;
|
|
57
|
+
margin: 0 0 1rem;
|
|
58
|
+
opacity: 0.85;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.runwell-testimonials-medvi__headline {
|
|
62
|
+
font-family: var(--font-heading-family, inherit);
|
|
63
|
+
font-size: var(--runwell-h2-size, clamp(3rem, 5vw, 4.8rem));
|
|
64
|
+
font-weight: 700;
|
|
65
|
+
line-height: 1.1;
|
|
66
|
+
margin: 0;
|
|
67
|
+
letter-spacing: -0.01em;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.runwell-testimonials-medvi__headline-pre,
|
|
71
|
+
.runwell-testimonials-medvi__headline-post {
|
|
72
|
+
display: inline;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.runwell-testimonials-medvi__lede {
|
|
76
|
+
font-size: var(--runwell-body-size, 1.6rem);
|
|
77
|
+
line-height: 1.5;
|
|
78
|
+
opacity: 0.85;
|
|
79
|
+
margin: 1rem auto 0;
|
|
80
|
+
max-width: 50ch;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* ----- Marquee rows ----- */
|
|
84
|
+
|
|
85
|
+
.runwell-testimonials-medvi__rows {
|
|
86
|
+
display: flex;
|
|
87
|
+
flex-direction: column;
|
|
88
|
+
gap: clamp(0.75rem, 1.5vw, 1.25rem);
|
|
89
|
+
width: 100%;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.runwell-testimonials-medvi__row {
|
|
93
|
+
position: relative;
|
|
94
|
+
width: 100%;
|
|
95
|
+
overflow: hidden; /* clip the moving track at viewport edges */
|
|
96
|
+
-webkit-mask-image: linear-gradient(to right, transparent 0, black 4%, black 96%, transparent 100%);
|
|
97
|
+
mask-image: linear-gradient(to right, transparent 0, black 4%, black 96%, transparent 100%);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.runwell-testimonials-medvi__track {
|
|
101
|
+
list-style: none;
|
|
102
|
+
margin: 0;
|
|
103
|
+
padding: 0;
|
|
104
|
+
display: flex;
|
|
105
|
+
flex-wrap: nowrap;
|
|
106
|
+
align-items: center;
|
|
107
|
+
gap: var(--rw-tm-gap, 20px);
|
|
108
|
+
width: max-content;
|
|
109
|
+
animation: runwell-tm-marquee var(--rw-tm-duration, 60s) linear infinite;
|
|
110
|
+
will-change: transform;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* Row 2 direction: same (default, medvi-faithful) keeps both rows scrolling left.
|
|
114
|
+
`reverse` flips row 2 to create visual rhythm. */
|
|
115
|
+
.runwell-testimonials-medvi__rows--row2-reverse .runwell-testimonials-medvi__row--2 .runwell-testimonials-medvi__track {
|
|
116
|
+
animation-direction: reverse;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.runwell-testimonials-medvi__row:hover .runwell-testimonials-medvi__track,
|
|
120
|
+
.runwell-testimonials-medvi__row:focus-within .runwell-testimonials-medvi__track {
|
|
121
|
+
animation-play-state: paused;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@keyframes runwell-tm-marquee {
|
|
125
|
+
from { transform: translateX(0); }
|
|
126
|
+
to { transform: translateX(calc(-50% - var(--rw-tm-gap, 20px) / 2)); }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@media (prefers-reduced-motion: reduce) {
|
|
130
|
+
.runwell-testimonials-medvi__track {
|
|
131
|
+
animation: none;
|
|
132
|
+
transform: none;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* ----- Items + cards ----- */
|
|
137
|
+
|
|
138
|
+
.runwell-testimonials-medvi__item {
|
|
139
|
+
flex: 0 0 auto;
|
|
140
|
+
width: var(--rw-tm-card-w, 400px);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.runwell-testimonials-medvi__card {
|
|
144
|
+
margin: 0;
|
|
145
|
+
border-radius: var(--runwell-radius-lg, 20px);
|
|
146
|
+
overflow: hidden;
|
|
147
|
+
display: flex;
|
|
148
|
+
flex-direction: column;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* Per-card aspect ratios: photos default 16:9 (medvi-faithful native landscape),
|
|
152
|
+
quotes default 5:3 (taller for multi-line text). Either can be overridden
|
|
153
|
+
per-instance via section settings. */
|
|
154
|
+
.runwell-testimonials-medvi__rows--photo-aspect-16-9 .runwell-testimonials-medvi__card--photo { aspect-ratio: 16 / 9; }
|
|
155
|
+
.runwell-testimonials-medvi__rows--photo-aspect-5-3 .runwell-testimonials-medvi__card--photo { aspect-ratio: 5 / 3; }
|
|
156
|
+
.runwell-testimonials-medvi__rows--photo-aspect-4-3 .runwell-testimonials-medvi__card--photo { aspect-ratio: 4 / 3; }
|
|
157
|
+
.runwell-testimonials-medvi__rows--photo-aspect-1-1 .runwell-testimonials-medvi__card--photo { aspect-ratio: 1 / 1; }
|
|
158
|
+
|
|
159
|
+
.runwell-testimonials-medvi__rows--quote-aspect-16-9 .runwell-testimonials-medvi__card--quote { aspect-ratio: 16 / 9; }
|
|
160
|
+
.runwell-testimonials-medvi__rows--quote-aspect-5-3 .runwell-testimonials-medvi__card--quote { aspect-ratio: 5 / 3; }
|
|
161
|
+
.runwell-testimonials-medvi__rows--quote-aspect-4-3 .runwell-testimonials-medvi__card--quote { aspect-ratio: 4 / 3; }
|
|
162
|
+
.runwell-testimonials-medvi__rows--quote-aspect-1-1 .runwell-testimonials-medvi__card--quote { aspect-ratio: 1 / 1; }
|
|
163
|
+
|
|
164
|
+
/* Quote card */
|
|
165
|
+
.runwell-testimonials-medvi__card--quote {
|
|
166
|
+
padding: clamp(1.5rem, 2.2vw, 2rem) clamp(1.75rem, 2.6vw, 2.25rem);
|
|
167
|
+
justify-content: flex-start;
|
|
168
|
+
gap: 0.85rem;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.runwell-testimonials-medvi__card-head {
|
|
172
|
+
display: flex;
|
|
173
|
+
align-items: center;
|
|
174
|
+
justify-content: space-between;
|
|
175
|
+
gap: 1rem;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.runwell-testimonials-medvi__card-author {
|
|
179
|
+
font-family: var(--font-heading-family, inherit);
|
|
180
|
+
font-size: var(--runwell-body-size, 1.6rem);
|
|
181
|
+
font-weight: 700;
|
|
182
|
+
margin: 0;
|
|
183
|
+
line-height: 1.2;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.runwell-testimonials-medvi__card-rating {
|
|
187
|
+
display: inline-flex;
|
|
188
|
+
gap: 0.15em;
|
|
189
|
+
font-size: var(--runwell-body-size, 1.6rem);
|
|
190
|
+
letter-spacing: 0.05em;
|
|
191
|
+
line-height: 1;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.runwell-testimonials-medvi__star {
|
|
195
|
+
line-height: 1;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.runwell-testimonials-medvi__card-quote {
|
|
199
|
+
font-size: var(--runwell-cta-size, 1.5rem);
|
|
200
|
+
line-height: 1.5;
|
|
201
|
+
opacity: 0.85;
|
|
202
|
+
flex: 1 1 auto;
|
|
203
|
+
display: -webkit-box;
|
|
204
|
+
-webkit-line-clamp: 6;
|
|
205
|
+
-webkit-box-orient: vertical;
|
|
206
|
+
overflow: hidden;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.runwell-testimonials-medvi__card-quote p {
|
|
210
|
+
margin: 0 0 0.4em;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.runwell-testimonials-medvi__card-quote p:last-child {
|
|
214
|
+
margin-bottom: 0;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* Photo card */
|
|
218
|
+
.runwell-testimonials-medvi__card--photo {
|
|
219
|
+
background: var(--runwell-oat, #F5F0EE);
|
|
220
|
+
padding: 0;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.runwell-testimonials-medvi__card--photo img {
|
|
224
|
+
display: block;
|
|
225
|
+
width: 100%;
|
|
226
|
+
height: 100%;
|
|
227
|
+
object-fit: cover;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.runwell-testimonials-medvi__card--photo-focal-center img { object-position: center; }
|
|
231
|
+
.runwell-testimonials-medvi__card--photo-focal-top img { object-position: 50% 25%; }
|
|
232
|
+
.runwell-testimonials-medvi__card--photo-focal-bottom img { object-position: 50% 75%; }
|
|
233
|
+
|
|
234
|
+
/* Mobile: smaller card width but keep marquee */
|
|
235
|
+
@media (max-width: 767px) {
|
|
236
|
+
.runwell-testimonials-medvi {
|
|
237
|
+
--rw-tm-card-w: 280px;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "testimonials-medvi",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"category": "social-proof",
|
|
5
|
+
"source": "medvi",
|
|
6
|
+
"base": "testimonials",
|
|
7
|
+
"qualifier": null,
|
|
8
|
+
"description": "Two horizontal marquee rows of testimonial cards. Cards are landscape (16:9), ~400px wide. Photos and quote cards are auto-split across two rows; row 2 scrolls in reverse for visual rhythm. Pauses on hover or focus; stops on prefers-reduced-motion.",
|
|
9
|
+
"replaces": null,
|
|
10
|
+
"files": {
|
|
11
|
+
"sections": [
|
|
12
|
+
"sections/runwell-testimonials-medvi.liquid"
|
|
13
|
+
],
|
|
14
|
+
"snippets": [],
|
|
15
|
+
"assets": [
|
|
16
|
+
"assets/runwell-testimonials-medvi.css"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"config": {
|
|
20
|
+
"schema": {
|
|
21
|
+
"section_eyebrow": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"default": "THOSE WHO CHOSE US",
|
|
24
|
+
"label": "Section eyebrow"
|
|
25
|
+
},
|
|
26
|
+
"headline_pre": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"default": "There's a reason people are",
|
|
29
|
+
"label": "Headline first part"
|
|
30
|
+
},
|
|
31
|
+
"headline_post": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"default": "raving about us.",
|
|
34
|
+
"label": "Headline accent part"
|
|
35
|
+
},
|
|
36
|
+
"headline_accent_color": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"default": "{{brand.primary}}",
|
|
39
|
+
"label": "Accent color for headline post"
|
|
40
|
+
},
|
|
41
|
+
"lede": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"default": "Join the multitude of people who have trusted us to help change their lives.",
|
|
44
|
+
"label": "Centered lede paragraph"
|
|
45
|
+
},
|
|
46
|
+
"card_bg": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"default": "{{brand.oat}}",
|
|
49
|
+
"label": "Quote card background"
|
|
50
|
+
},
|
|
51
|
+
"star_color": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"default": "{{brand.primary}}",
|
|
54
|
+
"label": "Star rating color"
|
|
55
|
+
},
|
|
56
|
+
"bg_band": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"default": "white",
|
|
59
|
+
"label": "Background band: white, oat, celadon-tint"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"lineage": {
|
|
64
|
+
"extracted_from": "https://home.medvi.org/",
|
|
65
|
+
"scrape_path": "_clients/capital-v/lushi/research/medvi-reference/site-scrape/",
|
|
66
|
+
"framer_label": "What Our Clients Say Parallax Scroll Section"
|
|
67
|
+
}
|
|
68
|
+
}
|