+
+ Accepts:
+ settings: {block.settings || section.settings}
+{%- endcomment -%}
+
+--padding-block-start: {{ settings.padding-block-start | default: 0 }}px; --padding-block-end:{{- settings.padding-block-end | default: 0 -}}px;
+--padding-inline-start:{{ settings.padding-inline-start | default: 0 }}px; --padding-inline-end:{{- settings.padding-inline-end | default: 0 -}}px;
diff --git a/snippets/spacing-style.liquid b/snippets/spacing-style.liquid
new file mode 100644
index 000000000..bfbc62173
--- /dev/null
+++ b/snippets/spacing-style.liquid
@@ -0,0 +1,36 @@
+{%- doc -%}
+ Renders CSS variables for spacing (padding and margin) styles with responsive scaling.
+ Intended for blocks and sections that provide values for all the referenced settings.
+
+ @param {object} settings - The block or section settings object containing spacing values
+
+ @example
+
+{%- enddoc -%}
+{%- liquid
+ assign scale_min = 20
+ assign keys = 'padding-block-start,padding-block-end,padding-inline-start,padding-inline-end' | split: ','
+
+ for key in keys
+ assign value = settings[key]
+
+ if value != blank
+ echo '--'
+ echo key
+ echo ': '
+
+ if value > scale_min
+ echo 'max('
+ echo scale_min
+ echo 'px, calc(var(--spacing-scale) * '
+ echo value
+ echo 'px))'
+ else
+ echo value
+ echo 'px'
+ endif
+
+ echo ';'
+ endif
+ endfor
+-%}
diff --git a/strikethrough-variant.liquid b/strikethrough-variant.liquid
new file mode 100644
index 000000000..f5e85ee2a
--- /dev/null
+++ b/strikethrough-variant.liquid
@@ -0,0 +1,11 @@
+{% unless product_option.available %}
+
+ {% # 25deg %}
+
+
+{% endunless %}
diff --git a/stylesheets.liquid b/stylesheets.liquid
new file mode 100644
index 000000000..88668ee40
--- /dev/null
+++ b/stylesheets.liquid
@@ -0,0 +1,2 @@
+{{ 'overflow-list.css' | asset_url | preload_tag: as: 'style' }}
+{{ 'base.css' | asset_url | stylesheet_tag: preload: true }}
diff --git a/submenu-font-styles.liquid b/submenu-font-styles.liquid
new file mode 100644
index 000000000..92d071c7c
--- /dev/null
+++ b/submenu-font-styles.liquid
@@ -0,0 +1,48 @@
+{%- comment -%}
+ Derives CSS variables from the menu typography settings for 2nd and 3rd level menu items.
+ Accepts:
+ settings: {block.settings}
+{%- endcomment -%}
+
+--menu-parent-font-family: var(--font-{{ settings.type_font_primary_link }}--family); --menu-parent-font-style:
+var(--font-
+{{- settings.type_font_primary_link -}}
+--style); --menu-parent-font-weight: var(--font-
+{{- settings.type_font_primary_link -}}
+--weight); --menu-parent-font-case:
+{% if settings.type_case_primary_link == 'uppercase' %}uppercase{% else %}none{% endif %};
+{% case settings.menu_font_style %}
+ {% when 'regular' %}
+ --menu-parent-font-size: var(--menu-font-md--size); --menu-parent-font-line-height:
+ var(--menu-font-md--line-height); --menu-parent-font-color: var(--color-foreground);
+ --menu-parent-active-font-color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text));
+ {% when 'inverse' %}
+ --menu-parent-font-size: var(--menu-font-sm--size); --menu-parent-font-line-height:
+ var(--menu-font-sm--line-height); --menu-parent-font-color: rgb(var(--color-foreground-rgb) /
+ var(--opacity-subdued-text)); --menu-parent-active-font-color: var(--color-foreground);
+ {% when 'inverse_large' %}
+ --menu-parent-font-size: var(--menu-font-sm--size); --menu-parent-font-line-height:
+ var(--menu-font-sm--line-height); --menu-parent-font-color: rgb(var(--color-foreground-rgb) /
+ var(--opacity-subdued-text)); --menu-parent-active-font-color: var(--color-foreground);
+{% endcase %}
+--menu-child-font-family: var(--font-{{ settings.type_font_primary_link }}--family); --menu-child-font-style:
+var(--font-
+{{- settings.type_font_primary_link -}}
+--style); --menu-child-font-weight: var(--font-
+{{- settings.type_font_primary_link -}}
+--weight); --menu-child-font-case:
+{% if settings.type_case_primary_link == 'uppercase' %}uppercase{% else %}none{% endif %};
+{% case settings.menu_font_style %}
+ {% when 'regular' %}
+ --menu-child-font-size: var(--menu-font-sm--size); --menu-child-font-line-height: var(--menu-font-sm--line-height);
+ --menu-child-font-color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text));
+ --menu-child-active-font-color: var(--color-foreground);
+ {% when 'inverse' %}
+ --menu-child-font-size: var(--menu-font-md--size); --menu-child-font-line-height: var(--menu-font-md--line-height);
+ --menu-child-font-color: var(--color-foreground); --menu-child-active-font-color: rgb(var(--color-foreground-rgb) /
+ var(--opacity-subdued-text));
+ {% when 'inverse_large' %}
+ --menu-child-font-size: var(--menu-font-xl--size); --menu-child-font-line-height: var(--menu-font-xl--line-height);
+ --menu-child-font-color: var(--color-foreground); --menu-child-active-font-color: rgb(var(--color-foreground-rgb) /
+ var(--opacity-subdued-text));
+{% endcase %}
diff --git a/swatch.liquid b/swatch.liquid
new file mode 100644
index 000000000..a8bf87d28
--- /dev/null
+++ b/swatch.liquid
@@ -0,0 +1,41 @@
+{%- doc -%}
+ Renders a swatch
+
+ @param {object} swatch - a swatch object
+ @param {object} [variant_image] - an alternate image
+ @param {string} [mode] - one of 'unscaled' or 'filter'
+
+ @example
+ {% render 'swatch', swatch: swatch, variant_image: variant_image, mode: 'unscaled' %}
+{%- enddoc -%}
+
+{% liquid
+ assign swatch_value = null
+ if settings.show_variant_image and variant_image
+ assign swatch_image_width = settings.variant_swatch_width | times: 2
+ assign swatch_image_url = variant_image | image_url: width: swatch_image_width
+ assign swatch_value = 'url(' | append: swatch_image_url | append: ')'
+ elsif swatch.image
+ assign swatch_image_url = swatch.image | image_url: width: 80
+ assign swatch_value = 'url(' | append: swatch_image_url | append: ')'
+ elsif swatch.color
+ assign swatch_value = 'rgb(' | append: swatch.color.rgb | append: ')'
+ endif
+
+ case mode
+ when 'unscaled'
+ assign extra_classes = ' swatch--unscaled'
+ when 'filter'
+ assign extra_classes = ' swatch--filter'
+ when 'pill'
+ assign extra_classes = ' swatch--pill'
+ else
+ assign extra_classes = ''
+ endcase
+%}
+
+
diff --git a/tax-info.liquid b/tax-info.liquid
new file mode 100644
index 000000000..3c16eaee0
--- /dev/null
+++ b/tax-info.liquid
@@ -0,0 +1,84 @@
+{%- comment -%}
+ Intended for use in a block similar to the text block.
+
+ Accepts:
+ has_discounts_enabled: {boolean} - whether discounts are enabled
+{%- endcomment -%}
+
+
+ {%- if cart.duties_included and cart.taxes_included -%}
+ {%- if shop.shipping_policy.body == blank -%}
+ {%- if has_discounts_enabled -%}
+ {{ 'content.duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts' | t }}
+ {%- else -%}
+ {{ 'content.duties_and_taxes_included_shipping_at_checkout_without_policy' | t }}
+ {%- endif -%}
+ {%- else -%}
+ {%- if has_discounts_enabled -%}
+ {{
+ 'content.duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- else -%}
+ {{
+ 'content.duties_and_taxes_included_shipping_at_checkout_with_policy_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- endif -%}
+ {%- endif -%}
+ {%- elsif cart.duties_included == false and cart.taxes_included -%}
+ {%- if shop.shipping_policy.body == blank -%}
+ {%- if has_discounts_enabled -%}
+ {{ 'content.duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts' | t }}
+ {%- else -%}
+ {{ 'content.taxes_included_shipping_at_checkout_without_policy' | t }}
+ {%- endif -%}
+ {%- else -%}
+ {%- if has_discounts_enabled -%}
+ {{
+ 'content.duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- else -%}
+ {{ 'content.taxes_included_shipping_at_checkout_with_policy_html' | t: link: shop.shipping_policy.url }}
+ {%- endif -%}
+ {%- endif -%}
+ {%- elsif cart.duties_included and cart.taxes_included == false -%}
+ {%- if shop.shipping_policy.body == blank -%}
+ {%- if has_discounts_enabled -%}
+ {{ 'content.duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts' | t }}
+ {%- else -%}
+ {{ 'content.duties_included_taxes_at_checkout_shipping_at_checkout_without_policy' | t }}
+ {%- endif -%}
+ {%- else -%}
+ {%- if has_discounts_enabled -%}
+ {{
+ 'content.duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- else -%}
+ {{
+ 'content.duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- endif -%}
+ {%- endif -%}
+ {%- elsif cart.duties_included == false and cart.taxes_included == false -%}
+ {%- if shop.shipping_policy.body == blank -%}
+ {%- if has_discounts_enabled -%}
+ {{ 'content.taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts' | t }}
+ {%- else -%}
+ {{ 'content.taxes_at_checkout_shipping_at_checkout_without_policy' | t }}
+ {%- endif -%}
+ {%- else -%}
+ {%- if has_discounts_enabled -%}
+ {{
+ 'content.taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- else -%}
+ {{ 'content.taxes_at_checkout_shipping_at_checkout_with_policy_html' | t: link: shop.shipping_policy.url }}
+ {%- endif -%}
+ {%- endif -%}
+ {%- endif -%}
+
diff --git a/text.liquid b/text.liquid
new file mode 100644
index 000000000..f5526be2e
--- /dev/null
+++ b/text.liquid
@@ -0,0 +1,218 @@
+{%- doc -%}
+ Intended for use in a block similar to the text block.
+
+ @param {string} [class] - custom class to define in addition to text-block classes
+ @param {string} [fallback_text] - fallback text if settings.text does not exist
+ @param {object} [block] - The block object
+ @param {string} [width] - width of the text block
+{%- enddoc -%}
+
+{% liquid
+ assign block_settings = block.settings
+ assign plain_text = block_settings.text | strip_newlines | strip_html | strip
+ assign text_width = width | default: block_settings.width
+
+ if block_settings.font_size contains 'heading-lg' or block_settings.font_size contains 'heading-xl'
+ assign type = 'display'
+ elsif block_settings.font_size contains 'heading'
+ assign type = 'heading'
+ else
+ assign type = 'body'
+ endif
+ if block_settings.type_preset == 'rte' or block_settings.type_preset == 'paragraph'
+ assign is_rte = true
+ endif
+
+ capture text_block_classes
+ if text_width == '100%'
+ echo 'text-block--align-' | append: block_settings.alignment
+ if block_settings.max_width == 'none'
+ echo ' text-block--full-width '
+ endif
+ endif
+ if block_settings.type_preset == 'custom'
+ echo ' custom-typography '
+ if block_settings.font_size != ''
+ echo ' custom-font-size '
+ endif
+ if block_settings.color != ''
+ echo ' custom-color '
+ endif
+ endif
+ if block_settings.background
+ echo ' text-block--background '
+ endif
+ if is_rte
+ echo ' rte '
+ endif
+ endcapture
+%}
+
+{% capture attributes %}
+ class="{{ class }} spacing-style text-block text-block--{{ block.id }} {{ block_settings.type_preset }}
+ {{ text_block_classes }}
+ "
+
+ style="
+ {% render 'spacing-padding', settings: block_settings %}
+ {% render 'typography-style', settings: block_settings %}
+ --width: {{ text_width }};
+ --max-width: var(--max-width--{{ type }}-{{ block_settings.max_width }});
+ {% if text_width == "100%" %}
+ --text-align: {{ block_settings.alignment }};
+ {% endif %}
+ {% if block_settings.background %}
+ --text-background-color: {{ block_settings.background_color | default: 'rgb(255 255 255 / 1.0)' }};
+ --text-corner-radius: {{ block_settings.corner_radius }}px;
+ --text-padding: max(var(--padding-2xs), calc((var(--text-corner-radius) + var(--padding-xs)) * (1 - cos(45deg))));
+ {% endif %}
+ "
+
+ {{ block.shopify_attributes }}
+{% endcapture %}
+{% liquid
+ # {{ attributes }} must be on the immediate HTML parent of the text to preserve
+ # the click-to-edit connection in the theme editor. Any break between the text,
+ # including if-statements, will break the connection.
+
+ assign element = 'div'
+ if is_rte
+ assign element = 'rte-formatter'
+ endif
+%}
+
+{% if fallback_text != blank and plain_text == blank %}
+
+ {{ fallback_text }}
+
+{% elsif plain_text != blank %}
+ <{{ element }} {{ attributes }}>
+ {{ block.settings.text }}
+ {{ element }}>
+{% endif %}
+
+{% stylesheet %}
+ :root {
+ --text-align-default: left;
+ }
+
+ [style*='--horizontal-alignment: center'] .text-block {
+ --text-align-default: center;
+ }
+
+ [style*='--horizontal-alignment: flex-end'] .text-block {
+ --text-align-default: right;
+ }
+
+ [style*='--horizontal-alignment: flex-start'] > .text-block {
+ --text-align-default: left;
+ }
+
+ [style*='--horizontal-alignment: center'] > .text-block {
+ --text-align-default: center;
+ }
+
+ [style*='--horizontal-alignment: flex-end'] > .text-block {
+ --text-align-default: right;
+ }
+
+ .text-block {
+ width: var(--width);
+ max-width: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: var(--horizontal-alignment);
+ }
+
+ .text-block > * {
+ width: var(--width);
+ max-width: var(--max-width, 100%);
+ text-align: var(--text-align, var(--text-align-default));
+ text-wrap: var(--text-wrap);
+ }
+
+ .text-block:not(.text-block--full-width).rte,
+ .text-block:not(.text-block--full-width).paragraph {
+ /* Safari doesn't support pretty, so fallback to balance */
+ text-wrap: balance;
+ text-wrap: pretty;
+ }
+
+ .text-block:not(.text-block--full-width):is(.h1, .h2, .h3, .h4, .h5, .h6) {
+ text-wrap: balance;
+ }
+
+ /* Hide underline unless text is using paragraph styles. */
+ .text-block:is(.h1, .h2, .h3, .h4, .h5, .h6) a {
+ text-decoration-color: transparent;
+ }
+
+ .text-block h1,
+ .text-block.h1 > * {
+ margin-block: var(--font-h1--spacing);
+ }
+
+ .text-block h2,
+ .text-block.h2 > * {
+ margin-block: var(--font-h2--spacing);
+ }
+
+ .text-block h3,
+ .text-block.h3 > * {
+ margin-block: var(--font-h3--spacing);
+ }
+
+ .text-block h4,
+ .text-block.h4 > * {
+ margin-block: var(--font-h4--spacing);
+ }
+
+ .text-block h5,
+ .text-block.h5 > * {
+ margin-block: var(--font-h5--spacing);
+ }
+
+ .text-block h6,
+ .text-block.h6 > * {
+ margin-block: var(--font-h6--spacing);
+ }
+
+ .text-block p,
+ .text-block.p > * {
+ margin-block: var(--font-paragraph--spacing);
+ }
+
+ .text-block > *:first-child {
+ margin-block-start: 0;
+ }
+
+ .text-block > *:last-child {
+ margin-block-end: 0;
+ }
+
+ .text-block--align-center,
+ .text-block--align-center > * {
+ margin-inline: auto;
+ }
+
+ .text-block--align-right,
+ .text-block--align-right > * {
+ margin-inline-start: auto;
+ }
+
+ .text-block--background {
+ background-color: var(--text-background-color);
+ border-radius: var(--text-corner-radius);
+
+ /* To avoid text being cropped when using a border radius we add a minimum padding. */
+ padding-block-start: max(var(--text-padding), var(--padding-block-start, 0));
+ padding-block-end: max(var(--text-padding), var(--padding-block-end, 0));
+ padding-inline-start: max(var(--text-padding), var(--padding-inline-start, 0));
+ padding-inline-end: max(var(--text-padding), var(--padding-inline-end, 0));
+ }
+
+ .custom-color,
+ .custom-color > :is(h1, h2, h3, h4, h5, h6, p, *) {
+ color: var(--color);
+ }
+{% endstylesheet %}
diff --git a/theme-editor.liquid b/theme-editor.liquid
new file mode 100644
index 000000000..c34f0907d
--- /dev/null
+++ b/theme-editor.liquid
@@ -0,0 +1,5 @@
+
diff --git a/theme-styles-variables.liquid b/theme-styles-variables.liquid
new file mode 100644
index 000000000..ed70669ab
--- /dev/null
+++ b/theme-styles-variables.liquid
@@ -0,0 +1,591 @@
+{% style %}
+
+ {%- liquid
+ assign primary_font_bold = settings.type_body_font | font_modify: 'weight', 'bold'
+ assign primary_font_italic = settings.type_body_font | font_modify: 'style', 'italic'
+ assign primary_font_bold_italic = primary_font_bold | font_modify: 'style', 'italic'
+ %}
+
+ {{ settings.type_body_font | font_face: font_display: 'swap' }}
+ {{ primary_font_bold | font_face: font_display: 'swap' }}
+ {{ primary_font_italic | font_face: font_display: 'swap' }}
+ {{ primary_font_bold_italic | font_face: font_display: 'swap' }}
+
+ {% if settings.type_subheading_font != settings.type_body_font %}
+ {%- liquid
+ assign secondary_font_bold = settings.type_subheading_font | font_modify: 'weight', 'bold'
+ assign secondary_font_italic = settings.type_subheading_font | font_modify: 'style', 'italic'
+ assign secondary_font_bold_italic = secondary_font_bold | font_modify: 'style', 'italic'
+ %}
+
+ {{ settings.type_subheading_font | font_face: font_display: 'swap' }}
+ {{ secondary_font_bold | font_face: font_display: 'swap' }}
+ {{ secondary_font_italic | font_face: font_display: 'swap' }}
+ {{ secondary_font_bold_italic | font_face: font_display: 'swap' }}
+ {% endif %}
+
+ {% if settings.type_heading_font != settings.type_body_font and settings.type_heading_font != settings.type_subheading_font %}
+ {%- liquid
+ assign tertiary_font_bold = settings.type_heading_font | font_modify: 'weight', 'bold'
+ assign tertiary_font_italic = settings.type_heading_font | font_modify: 'style', 'italic'
+ assign tertiary_font_bold_italic = tertiary_font_bold | font_modify: 'style', 'italic'
+ %}
+
+ {{ settings.type_heading_font | font_face: font_display: 'swap' }}
+ {{ tertiary_font_bold | font_face: font_display: 'swap' }}
+ {{ tertiary_font_italic | font_face: font_display: 'swap' }}
+ {{ tertiary_font_bold_italic | font_face: font_display: 'swap' }}
+ {% endif %}
+
+ {% if settings.type_accent_font != settings.type_body_font and settings.type_accent_font != settings.type_subheading_font and settings.type_accent_font != settings.type_heading_font %}
+ {%- liquid
+ assign accent_font_bold = settings.type_accent_font | font_modify: 'weight', 'bold'
+ assign accent_font_italic = settings.type_accent_font | font_modify: 'style', 'italic'
+ assign accent_font_bold_italic = accent_font_bold | font_modify: 'style', 'italic'
+ %}
+
+ {{ settings.type_accent_font | font_face: font_display: 'swap' }}
+ {{ accent_font_bold | font_face: font_display: 'swap' }}
+ {{ accent_font_italic | font_face: font_display: 'swap' }}
+ {{ accent_font_bold_italic | font_face: font_display: 'swap' }}
+ {% endif %}
+
+ :root {
+ /* Page Layout */
+ --sidebar-width: 25rem;
+ --narrow-content-width: 36rem;
+ --normal-content-width: 42rem;
+ --wide-content-width: 46rem;
+ --narrow-page-width: 90rem;
+ --normal-page-width: 120rem;
+ --wide-page-width: 150rem;
+
+ /* Section Heights */
+ --section-height-small: 15rem;
+ --section-height-medium: 25rem;
+ --section-height-large: 35rem;
+
+ @media screen and (min-width: 40em) {
+ --section-height-small: 40svh;
+ --section-height-medium: 55svh;
+ --section-height-large: 70svh;
+ }
+
+ @media screen and (min-width: 60em) {
+ --section-height-small: 50svh;
+ --section-height-medium: 65svh;
+ --section-height-large: 80svh;
+ }
+
+ /* Letter spacing */
+ --letter-spacing-sm: 0.06em;
+ --letter-spacing-md: 0.13em;
+
+ /* Font families */
+ --font-body--family: {{ settings.type_body_font.family }}, {{ settings.type_body_font.fallback_families }};
+ --font-body--style: {{ settings.type_body_font.style }};
+ --font-body--weight: {{ settings.type_body_font.weight }};
+ --font-subheading--family: {{ settings.type_subheading_font.family }}, {{ settings.type_subheading_font.fallback_families }};
+ --font-subheading--style: {{ settings.type_subheading_font.style }};
+ --font-subheading--weight: {{ settings.type_subheading_font.weight }};
+ --font-heading--family: {{ settings.type_heading_font.family }}, {{ settings.type_heading_font.fallback_families }};
+ --font-heading--style: {{ settings.type_heading_font.style }};
+ --font-heading--weight: {{ settings.type_heading_font.weight }};
+ --font-accent--family: {{ settings.type_accent_font.family }}, {{ settings.type_accent_font.fallback_families }};
+ --font-accent--style: {{ settings.type_accent_font.style }};
+ --font-accent--weight: {{ settings.type_accent_font.weight }};
+
+ /* Margin sizes */
+ --font-h1--spacing: 0.25em;
+ --font-h2--spacing: 0.25em;
+ --font-h3--spacing: 0.25em;
+ --font-h4--spacing: 0.25em;
+ --font-h5--spacing: 0.25em;
+ --font-h6--spacing: 0.25em;
+ --font-paragraph--spacing: 0.5em;
+
+ /* Heading colors */
+ --font-h1--color: var(--color-foreground-heading);
+ --font-h2--color: var(--color-foreground-heading);
+ --font-h3--color: var(--color-foreground-heading);
+ --font-h4--color: var(--color-foreground-heading);
+ --font-h5--color: var(--color-foreground-heading);
+ --font-h6--color: var(--color-foreground-heading);
+
+ /** Z-Index / Layering */
+ --layer-section-background: -2;
+ --layer-lowest: -1;
+ --layer-base: 0;
+ --layer-flat: 1;
+ --layer-raised: 2;
+ --layer-heightened: 4;
+ --layer-sticky: 8;
+ --layer-window-overlay: 10;
+ --layer-header-menu: 12;
+ --layer-overlay: 16;
+ --layer-menu-drawer: 18;
+ --layer-temporary: 20;
+
+ /* Max-width / Measure */
+ --max-width--body-normal: 50ch;
+ --max-width--body-narrow: 35ch;
+
+ --max-width--heading-normal: 50ch;
+ --max-width--heading-narrow: 30ch;
+
+ --max-width--display-normal: 20ch;
+ --max-width--display-narrow: 15ch;
+ --max-width--display-tight: 5ch;
+
+ /* Letter-spacing / Tracking */
+ --letter-spacing--display-tight: -0.03em;
+ --letter-spacing--display-normal: 0em;
+ --letter-spacing--display-loose: 0.03em;
+
+ --letter-spacing--heading-tight: -0.03em;
+ --letter-spacing--heading-normal: 0em;
+ --letter-spacing--heading-loose: 0.03em;
+
+ --letter-spacing--body-tight: -0.03em;
+ --letter-spacing--body-normal: 0em;
+ --letter-spacing--body-loose: 0.03em;
+
+ /* Line height / Leading */
+ --line-height: 1;
+
+ --line-height--display-tight: 1;
+ --line-height--display-normal: 1.1;
+ --line-height--display-loose: 1.2;
+
+ --line-height--heading-tight: 1.15;
+ --line-height--heading-normal: 1.25;
+ --line-height--heading-loose: 1.35;
+
+ --line-height--body-tight: 1.2;
+ --line-height--body-normal: 1.4;
+ --line-height--body-loose: 1.6;
+
+ /* Typography presets */
+ {% liquid
+ assign font_sizes = "paragraph, h1, h2, h3, h4, h5, h6" | split: ", "
+ assign fluid_size_cutoff = 48
+ assign absolute_font_size_min = 10
+
+ comment
+ Build an array of font sizes and sort it
+ endcomment
+ assign font_size_values = ''
+ for font_size in font_sizes
+ assign size_setting = 'type_size_[font_size]' | replace: '[font_size]', font_size
+ assign size_setting_value = settings[size_setting] | times: 1
+
+ comment
+ If the font size is less than 100, pad it with a 0
+ This is because we end up with an array of strings, which | sort filter can't order "correctly")
+ endcomment
+ if size_setting_value < 100
+ assign size_setting_value = '0[size_setting_value]' | replace: '[size_setting_value]', size_setting_value
+ endif
+
+ assign font_size_values = font_size_values | append: '[size_setting_value],' | replace: '[size_setting_value]', size_setting_value
+ endfor
+
+ assign font_size_values = font_size_values | split: ',' | uniq | sort_natural
+
+ comment
+ For each font size S, find the next smaller size S-1, and determine the minimum for S
+ The calculation depends on the size of S-1 (over or under the cutoff)
+ endcomment
+ for font_size in font_sizes
+ assign size_setting = 'type_size_[font_size]' | replace: '[font_size]', font_size
+ assign font_size_value = settings[size_setting] | times: 1
+ assign font_size_string = '[font_size_value]' | replace: '[font_size_value]', font_size_value
+ assign index = font_size_values | find_index: font_size_string
+
+ if font_size_value >= fluid_size_cutoff
+
+ comment
+ Calculate the minimum size for each font size
+ endcomment
+ assign fluid_font_size_min = font_size_value
+
+ if index == 0
+ assign fluid_font_size_min = absolute_font_size_min
+ else
+ assign next_font_size_index = index | minus: 1
+ assign next_font_size_value = font_size_values[next_font_size_index]
+ assign next_font_size_value_number = next_font_size_value | times: 1
+
+ comment
+ If the next bigger font size under the fluid cutoff, we use keep a 4px buffer
+ endcomment
+ if next_font_size_value_number < fluid_size_cutoff
+ assign fluid_font_size_min = next_font_size_value_number | plus: 4
+ if font_size_value < fluid_font_size_min
+ assign fluid_font_size_min = font_size_value
+ endif
+ else
+ assign fluid_font_size_min = next_font_size_value | times: 1
+ endif
+ endif
+
+ comment
+ Calculate the fluid and maximum size for each font size
+ endcomment
+ assign fluid_size_min_rem = fluid_font_size_min | divided_by: 16.0
+ assign fluid_size = font_size_value | times: 0.1
+ assign fluid_size_max_rem = font_size_value | divided_by: 16.0
+
+ echo '--font-size--[font_size]: clamp([fluid_size_min_rem]rem, [fluid_size]vw, [fluid_size_max_rem]rem);' | replace: '[font_size]', font_size | replace: '[fluid_size_min_rem]', fluid_size_min_rem | replace: '[fluid_size]', fluid_size | replace: '[fluid_size_max_rem]', fluid_size_max_rem
+ else
+ assign fluid_size_rem = font_size_value | divided_by: 16.0
+ echo '--font-size--[font_size]: [fluid_size_rem]rem;' | replace: '[font_size]', font_size | replace: '[fluid_size_rem]', fluid_size_rem
+ endif
+ endfor
+
+ assign type_presets = "paragraph, h1, h2, h3, h4, h5, h6" | split: ", "
+
+ for preset_name in type_presets
+ assign preset_size = '--font-size--[preset_name]' | replace: '[preset_name]', preset_name
+ assign preset_line_height = 'type_line_height_[preset_name]' | replace: '[preset_name]', preset_name
+
+ if preset_name == 'paragraph'
+ assign preset_font = '--font-body--family'
+ assign preset_style = '--font-body--style'
+ assign preset_weight = '400'
+ assign preset_case = '--font-body--case'
+ assign preset_letter_spacing = 'body-normal'
+
+ echo '--font-[preset_name]--weight: [preset_weight];' | replace: '[preset_name]', preset_name | replace: '[preset_weight]', preset_weight
+ echo '--font-[preset_name]--letter-spacing: var(--letter-spacing--[preset_letter_spacing]);' | replace: '[preset_name]', preset_name | replace: '[preset_letter_spacing]', preset_letter_spacing
+ else
+ assign preset_font_id = 'type_font_[preset_name]' | replace: '[preset_name]', preset_name
+ assign preset_font = '--font-[preset_font]--family' | replace: '[preset_font]', settings[preset_font_id]
+ assign preset_style = '--font-[preset_font]--style' | replace: '[preset_font]', settings[preset_font_id]
+ assign preset_weight = '--font-[preset_font]--weight' | replace: '[preset_font]', settings[preset_font_id]
+ assign preset_case = 'type_case_[preset_name]' | replace: '[preset_name]', preset_name
+ assign preset_letter_spacing = 'type_letter_spacing_[preset_name]' | replace: '[preset_name]', preset_name
+
+ echo '--font-[preset_name]--weight: var([preset_weight]);' | replace: '[preset_name]', preset_name | replace: '[preset_weight]', preset_weight
+ echo '--font-[preset_name]--letter-spacing: var(--letter-spacing--[preset_letter_spacing]);' | replace: '[preset_name]', preset_name | replace: '[preset_letter_spacing]', settings[preset_letter_spacing]
+ endif
+
+ echo '--font-[preset_name]--size: var([preset_size]);' | replace: '[preset_name]', preset_name | replace: '[preset_size]', preset_size
+ echo '--font-[preset_name]--family: var([preset_font]);' | replace: '[preset_name]', preset_name | replace: '[preset_font]', preset_font
+ echo '--font-[preset_name]--style: var([preset_style]);' | replace: '[preset_name]', preset_name | replace: '[preset_style]', preset_style
+ echo '--font-[preset_name]--case: [preset_case];' | replace: '[preset_name]', preset_name | replace: '[preset_case]', settings[preset_case]
+ echo '--font-[preset_name]--line-height: var(--line-height--[preset_line_height]);' | replace: '[preset_name]', preset_name | replace: '[preset_line_height]', settings[preset_line_height]
+ endfor
+ %}
+
+ /* Hardcoded font sizes */
+ --font-size--2xs: 0.625rem;
+ --font-size--xs: 0.8125rem;
+ --font-size--sm: 0.875rem;
+ --font-size--md: 1rem;
+ --font-size--lg: 1.125rem;
+ --font-size--xl: 1.25rem;
+ --font-size--2xl: 1.5rem;
+ --font-size--3xl: 2rem;
+ --font-size--4xl: 2.5rem;
+ --font-size--5xl: 3rem;
+ --font-size--6xl: 3.5rem;
+
+ /* Menu font sizes */
+ --menu-font-sm--size: 0.875rem;
+ --menu-font-sm--line-height: calc(1.1 + 0.5 * min(16 / 14));
+ --menu-font-md--size: 1rem;
+ --menu-font-md--line-height: calc(1.1 + 0.5 * min(16 / 16));
+ --menu-font-lg--size: 1.125rem;
+ --menu-font-lg--line-height: calc(1.1 + 0.5 * min(16 / 18));
+ --menu-font-xl--size: 1.25rem;
+ --menu-font-xl--line-height: calc(1.1 + 0.5 * min(16 / 20));
+ --menu-font-2xl--size: 1.75rem;
+ --menu-font-2xl--line-height: calc(1.1 + 0.5 * min(16 / 28));
+
+ /* Colors */
+ --color-error: #8B0000;
+ --color-success: #006400;
+ --color-white: #FFFFFF;
+ --color-white-rgb: 255 255 255;
+ --color-black: #000000;
+ --color-instock: #3ED660;
+ --color-lowstock: #EE9441;
+ --color-outofstock: #C8C8C8;
+
+ /* Opacity */
+ --opacity-5: 0.05;
+ --opacity-8: 0.08;
+ --opacity-10: 0.1;
+ --opacity-15: 0.15;
+ --opacity-20: 0.2;
+ --opacity-25: 0.25;
+ --opacity-30: 0.3;
+ --opacity-40: 0.4;
+ --opacity-50: 0.5;
+ --opacity-60: 0.6;
+ --opacity-70: 0.7;
+ --opacity-80: 0.8;
+ --opacity-85: 0.85;
+ --opacity-90: 0.9;
+ --opacity-subdued-text: var(--opacity-70);
+
+ --shadow-button: 0 2px 3px rgb(0 0 0 / 20%);
+ --gradient-image-overlay: linear-gradient(to top, rgb(0 0 0 / 0.5), transparent);
+
+ /* Spacing */
+ --margin-3xs: 0.125rem;
+ --margin-2xs: 0.3rem;
+ --margin-xs: 0.5rem;
+ --margin-sm: 0.7rem;
+ --margin-md: 0.8rem;
+ --margin-lg: 1rem;
+ --margin-xl: 1.25rem;
+ --margin-2xl: 1.5rem;
+ --margin-3xl: 1.75rem;
+ --margin-4xl: 2rem;
+ --margin-5xl: 3rem;
+ --margin-6xl: 5rem;
+
+ --scroll-margin: 50px;
+
+ --padding-3xs: 0.125rem;
+ --padding-2xs: 0.25rem;
+ --padding-xs: 0.5rem;
+ --padding-sm: 0.7rem;
+ --padding-md: 0.8rem;
+ --padding-lg: 1rem;
+ --padding-xl: 1.25rem;
+ --padding-2xl: 1.5rem;
+ --padding-3xl: 1.75rem;
+ --padding-4xl: 2rem;
+ --padding-5xl: 3rem;
+ --padding-6xl: 4rem;
+
+ --gap-3xs: 0.125rem;
+ --gap-2xs: 0.3rem;
+ --gap-xs: 0.5rem;
+ --gap-sm: 0.7rem;
+ --gap-md: 0.9rem;
+ --gap-lg: 1rem;
+ --gap-xl: 1.25rem;
+ --gap-2xl: 2rem;
+ --gap-3xl: 3rem;
+
+ --spacing-scale-sm: 0.6;
+ --spacing-scale-md: 0.7;
+ --spacing-scale-default: 1.0;
+
+ /* Checkout buttons gap */
+ --checkout-button-gap: 10px;
+
+ /* Borders */
+ --style-border-width: 1px;
+ --style-border-radius-xs: 0.2rem;
+ --style-border-radius-sm: 0.6rem;
+ --style-border-radius-md: 0.8rem;
+ --style-border-radius-50: 50%;
+ --style-border-radius-lg: 1rem;
+ --style-border-radius-pills: {{ settings.pills_border_radius }}px;
+ --style-border-radius-inputs: {{ settings.inputs_border_radius }}px;
+ --style-border-radius-buttons-primary: {{ settings.button_border_radius_primary }}px;
+ --style-border-radius-buttons-secondary: {{ settings.button_border_radius_secondary }}px;
+ --style-border-width-primary: {{ settings.primary_button_border_width }}px;
+ --style-border-width-secondary: {{ settings.secondary_button_border_width }}px;
+ --style-border-width-inputs: {{ settings.input_border_width }}px;
+ --style-border-radius-popover: {{ settings.popover_border_radius }}px;
+ --style-border-popover: {{ settings.popover_border_width }}px {{ settings.popover_border }} rgb(var(--color-border-rgb) / {{ settings.popover_border_opacity }}%);
+ --style-border-drawer: {{ settings.drawer_border_width }}px {{ settings.drawer_border }} rgb(var(--color-border-rgb) / {{ settings.drawer_border_opacity }}%);
+ --style-border-swatch-opacity: {{ settings.variant_swatch_border_opacity }}%;
+ --style-border-swatch-width: {{ settings.variant_swatch_border_width }}px;
+ --style-border-swatch-style: {{ settings.variant_swatch_border_style }};
+
+ /* Animation */
+ --ease-out-cubic: cubic-bezier(0.33, 1, 0.68, 1);
+ --ease-out-quad: cubic-bezier(0.32, 0.72, 0, 1);
+ --animation-speed-fast: 0.0625s;
+ --animation-speed: 0.125s;
+ --animation-speed-slow: 0.2s;
+ --animation-speed-medium: 0.15s;
+ --animation-easing: ease-in-out;
+ --animation-slideshow-easing: cubic-bezier(0.4, 0, 0.2, 1);
+ --drawer-animation-speed: 0.2s;
+ --animation-values-slow: var(--animation-speed-slow) var(--animation-easing);
+ --animation-values: var(--animation-speed) var(--animation-easing);
+ --animation-values-fast: var(--animation-speed-fast) var(--animation-easing);
+ --animation-values-allow-discrete: var(--animation-speed) var(--animation-easing) allow-discrete;
+ --animation-timing-hover: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+ --animation-timing-active: cubic-bezier(0.5, 0, 0.75, 0);
+ --animation-timing-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
+ --animation-timing-default: cubic-bezier(0, 0, 0.2, 1);
+ --animation-timing-fade-in: cubic-bezier(0.16, 1, 0.3, 1);
+ --animation-timing-fade-out: cubic-bezier(0.4, 0, 0.2, 1);
+
+ /* View transitions */
+ /* View transition old */
+ --view-transition-old-main-content: var(--animation-speed) var(--animation-easing) both fadeOut;
+
+ /* View transition new */
+ --view-transition-new-main-content: var(--animation-speed) var(--animation-easing) both fadeIn, var(--animation-speed) var(--animation-easing) both slideInTopViewTransition;
+
+ /* Focus */
+ --focus-outline-width: 0.09375rem;
+ --focus-outline-offset: 0.2em;
+
+ /* Badges */
+ --badge-blob-padding-block: 1px;
+ --badge-blob-padding-inline: 12px 8px;
+ --badge-rectangle-padding-block: 1px;
+ --badge-rectangle-padding-inline: 6px;
+ @media screen and (min-width: 750px) {
+ --badge-blob-padding-block: 4px;
+ --badge-blob-padding-inline: 16px 12px;
+ --badge-rectangle-padding-block: 4px;
+ --badge-rectangle-padding-inline: 10px;
+ }
+
+ /* Icons */
+ --icon-size-2xs: 0.6rem;
+ --icon-size-xs: 0.85rem;
+ --icon-size-sm: 1.25rem;
+ --icon-size-md: 1.375rem;
+ --icon-size-lg: 1.5rem;
+ --icon-stroke-width: {% if settings.icon_stroke == 'thin' %}1px{% elsif settings.icon_stroke == 'heavy' %}2px{% else %}1.5px{% endif %};
+
+ /* Input */
+ --input-email-min-width: 200px;
+ --input-search-max-width: 650px;
+ --input-padding-y: 0.8rem;
+ --input-padding-x: 0.8rem;
+ --input-padding: var(--input-padding-y) var(--input-padding-x);
+ --input-box-shadow-width: var(--style-border-width-inputs);
+ --input-box-shadow: 0 0 0 var(--input-box-shadow-width) var(--color-input-border);
+ --input-box-shadow-focus: 0 0 0 calc(var(--input-box-shadow-width) + 0.5px) var(--color-input-border);
+ --input-disabled-background-color: rgb(var(--color-foreground-rgb) / var(--opacity-10));
+ --input-disabled-border-color: rgb(var(--color-foreground-rgb) / var(--opacity-5));
+ --input-disabled-text-color: rgb(var(--color-foreground-rgb) / var(--opacity-50));
+ --input-textarea-min-height: 55px;
+
+ /* Button size */
+ --button-size-sm: 30px;
+ --button-size-md: 36px;
+ --button-size: var(--minimum-touch-target);
+ --button-padding-inline: 24px;
+ --button-padding-block: 16px;
+
+ /* Button font-family */
+ --button-font-family-primary: var(--font-{{ settings.type_font_button_primary }}--family);
+ --button-font-family-secondary: var(--font-{{ settings.type_font_button_secondary }}--family);
+
+ /* Button text case */
+ --button-text-case: {{ settings.button_text_case }};
+ --button-text-case-primary: {{ settings.button_text_case_primary }};
+ --button-text-case-secondary: {{ settings.button_text_case_secondary }};
+
+ /* Borders */
+ --border-color: rgb(var(--color-border-rgb) / var(--opacity-50));
+ --border-width-sm: 1px;
+ --border-width-md: 2px;
+ --border-width-lg: 5px;
+
+ /* Drawers */
+ --drawer-inline-padding: 25px;
+ --drawer-menu-inline-padding: 2.5rem;
+ --drawer-header-block-padding: 20px;
+ --drawer-content-block-padding: 10px;
+ --drawer-header-desktop-top: 0rem;
+ --drawer-padding: calc(var(--padding-sm) + 7px);
+ --drawer-height: 100dvh;
+ --drawer-width: 95vw;
+ --drawer-max-width: 500px;
+
+ /* Variant Picker Swatches */
+ --variant-picker-swatch-width-unitless: {{ settings.variant_swatch_width }};
+ --variant-picker-swatch-height-unitless: {{ settings.variant_swatch_height }};
+ --variant-picker-swatch-width: {{ settings.variant_swatch_width | append: 'px' }};
+ --variant-picker-swatch-height: {{ settings.variant_swatch_height | append: 'px' }};
+ --variant-picker-swatch-radius: {{ settings.variant_swatch_radius | append: 'px' }};
+ --variant-picker-border-width: {{ settings.variant_swatch_border_width | append: 'px' }};
+ --variant-picker-border-style: {{ settings.variant_swatch_border_style }};
+ --variant-picker-border-opacity: {{ settings.variant_swatch_border_opacity | append: '%' }};
+
+ /* Variant Picker Buttons */
+ --variant-picker-button-radius: {{ settings.variant_button_radius | append: 'px' }};
+ --variant-picker-button-border-width: {{ settings.variant_button_border_width | append: 'px' }};
+
+ /* Slideshow */
+ --slideshow-controls-size: 3.5rem;
+ --slideshow-controls-icon: 2rem;
+ --peek-next-slide-size: 3rem;
+
+ /* Utilities */
+ --backdrop-opacity: 0.15;
+ --backdrop-color-rgb: var(--color-shadow-rgb);
+ --minimum-touch-target: 44px;
+ --disabled-opacity: 0.5;
+ --skeleton-opacity: 0.025;
+
+ /* Shapes */
+ --shape--circle: circle(50% at center);
+ --shape--sunburst: polygon(100% 50%,94.62% 55.87%,98.3% 62.94%,91.57% 67.22%,93.3% 75%,85.7% 77.39%,85.36% 85.36%,77.39% 85.7%,75% 93.3%,67.22% 91.57%,62.94% 98.3%,55.87% 94.62%,50% 100%,44.13% 94.62%,37.06% 98.3%,32.78% 91.57%,25% 93.3%,22.61% 85.7%,14.64% 85.36%,14.3% 77.39%,6.7% 75%,8.43% 67.22%,1.7% 62.94%,5.38% 55.87%,0% 50%,5.38% 44.13%,1.7% 37.06%,8.43% 32.78%,6.7% 25%,14.3% 22.61%,14.64% 14.64%,22.61% 14.3%,25% 6.7%,32.78% 8.43%,37.06% 1.7%,44.13% 5.38%,50% 0%,55.87% 5.38%,62.94% 1.7%,67.22% 8.43%,75% 6.7%,77.39% 14.3%,85.36% 14.64%,85.7% 22.61%,93.3% 25%,91.57% 32.78%,98.3% 37.06%,94.62% 44.13%);
+ --shape--diamond: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
+ --shape--blob: polygon(85.349% 11.712%, 87.382% 13.587%, 89.228% 15.647%, 90.886% 17.862%, 92.359% 20.204%, 93.657% 22.647%, 94.795% 25.169%, 95.786% 27.752%, 96.645% 30.382%, 97.387% 33.048%, 98.025% 35.740%, 98.564% 38.454%, 99.007% 41.186%, 99.358% 43.931%, 99.622% 46.685%, 99.808% 49.446%, 99.926% 52.210%, 99.986% 54.977%, 99.999% 57.744%, 99.975% 60.511%, 99.923% 63.278%, 99.821% 66.043%, 99.671% 68.806%, 99.453% 71.565%, 99.145% 74.314%, 98.724% 77.049%, 98.164% 79.759%, 97.433% 82.427%, 96.495% 85.030%, 95.311% 87.529%, 93.841% 89.872%, 92.062% 91.988%, 89.972% 93.796%, 87.635% 95.273%, 85.135% 96.456%, 82.532% 97.393%, 79.864% 98.127%, 77.156% 98.695%, 74.424% 99.129%, 71.676% 99.452%, 68.918% 99.685%, 66.156% 99.844%, 63.390% 99.942%, 60.624% 99.990%, 57.856% 99.999%, 55.089% 99.978%, 52.323% 99.929%, 49.557% 99.847%, 46.792% 99.723%, 44.031% 99.549%, 41.273% 99.317%, 38.522% 99.017%, 35.781% 98.639%, 33.054% 98.170%, 30.347% 97.599%, 27.667% 96.911%, 25.024% 96.091%, 22.432% 95.123%, 19.907% 93.994%, 17.466% 92.690%, 15.126% 91.216%, 12.902% 89.569%, 10.808% 87.761%, 8.854% 85.803%, 7.053% 83.703%, 5.418% 81.471%, 3.962% 79.119%, 2.702% 76.656%, 1.656% 74.095%, 0.846% 71.450%, 0.294% 68.740%, 0.024% 65.987%, 0.050% 63.221%, 0.343% 60.471%, 0.858% 57.752%, 1.548% 55.073%, 2.370% 52.431%, 3.283% 49.819%, 4.253% 47.227%, 5.249% 44.646%, 6.244% 42.063%, 7.211% 39.471%, 8.124% 36.858%, 8.958% 34.220%, 9.711% 31.558%, 10.409% 28.880%, 11.083% 26.196%, 11.760% 23.513%, 12.474% 20.839%, 13.259% 18.186%, 14.156% 15.569%, 15.214% 13.012%, 16.485% 10.556%, 18.028% 8.261%, 19.883% 6.211%, 22.041% 4.484%, 24.440% 3.110%, 26.998% 2.057%, 29.651% 1.275%, 32.360% 0.714%, 35.101% 0.337%, 37.859% 0.110%, 40.624% 0.009%, 43.391% 0.016%, 46.156% 0.113%, 48.918% 0.289%, 51.674% 0.533%, 54.425% 0.837%, 57.166% 1.215%, 59.898% 1.654%, 62.618% 2.163%, 65.322% 2.750%, 68.006% 3.424%, 70.662% 4.197%, 73.284% 5.081%, 75.860% 6.091%, 78.376% 7.242%, 80.813% 8.551%, 83.148% 10.036%, 85.349% 11.712%);
+
+ /* Buy buttons */
+ --height-buy-buttons: calc(var(--padding-lg) * 2 + var(--icon-size-sm));
+
+ /* Card image width and height variables */
+ --card-width-small: 10rem;
+
+ --height-small: 10rem;
+ --height-medium: 11.5rem;
+ --height-large: 13rem;
+ --height-full: 100vh;
+
+ @media screen and (min-width: 750px) {
+ --height-small: 17.5rem;
+ --height-medium: 21.25rem;
+ --height-large: 25rem;
+ }
+
+ /* Modal */
+ --modal-max-height: 65dvh;
+
+ /* Card styles for search */
+ --card-bg-hover: rgb(var(--color-foreground-rgb) / var(--opacity-5));
+ --card-border-hover: rgb(var(--color-foreground-rgb) / var(--opacity-30));
+ --card-border-focus: rgb(var(--color-foreground-rgb) / var(--opacity-10));
+
+ /* Cart */
+ --cart-primary-font-family: var(--font-body--family);
+ --cart-primary-font-style: var(--font-body--style);
+ --cart-primary-font-weight: var(--font-body--weight);
+ --cart-secondary-font-family: var(--font-{{ settings.cart_price_font }}--family);
+ --cart-secondary-font-style: var(--font-{{ settings.cart_price_font }}--style);
+ --cart-secondary-font-weight: var(--font-{{ settings.cart_price_font }}--weight);
+ }
+
+/* 1) Load your custom font file */
+@font-face {
+ font-family: 'Gangster Grotesk';
+ src: url('{{ "GangsterGrotesk-Regular.woff" | asset_url }}') format('woff');
+ font-weight: 400;
+ font-style: normal;
+ font-display: swap;
+}
+
+/* 2) Override the theme CSS variables to use your family */
+:root {
+ --font-body--family: 'Gangster Grotesk', sans-serif;
+ --font-subheading--family: 'Gangster Grotesk', sans-serif;
+ --font-heading--family: 'Gangster Grotesk', sans-serif;
+ --font-accent--family: 'Gangster Grotesk', sans-serif;
+
+ /* optional if the theme reads these */
+ --font-body--weight: 400;
+ --font-subheading--weight: 400;
+ --font-heading--weight: 400;
+ --font-accent--weight: 400;
+}
+
+{% endstyle %}
diff --git a/timeline-scope.liquid b/timeline-scope.liquid
new file mode 100644
index 000000000..67c1cfe02
--- /dev/null
+++ b/timeline-scope.liquid
@@ -0,0 +1,11 @@
+{%- liquid
+ assign timeline_scope = ''
+
+ for index in (1..count)
+ assign scope = '--prefix-index, ' | replace: 'prefix', prefix | replace: 'index', index
+ assign timeline_scope = timeline_scope | append: scope
+ endfor
+
+ assign timeline_scope = timeline_scope | strip | split: ',' | compact | join: ','
+-%}
+{{- timeline_scope -}}
From 6f357592890bf56fd9c965b1004c5c57e4a603a8 Mon Sep 17 00:00:00 2001
From: Morg <32440777+morgpork@users.noreply.github.com>
Date: Tue, 21 Oct 2025 11:52:54 +1300
Subject: [PATCH 003/752] Add files via upload
---
snippets/strikethrough-variant.liquid | 11 +
snippets/stylesheets.liquid | 2 +
snippets/submenu-font-styles.liquid | 48 ++
snippets/swatch.liquid | 41 ++
snippets/tax-info.liquid | 84 +++
snippets/text.liquid | 218 +++++++
snippets/theme-editor.liquid | 5 +
snippets/theme-styles-variables.liquid | 591 ++++++++++++++++++
snippets/timeline-scope.liquid | 11 +
snippets/typography-style.liquid | 75 +++
snippets/unit-price.liquid | 16 +
snippets/util-autofill-img-size-attr.liquid | 75 +++
snippets/util-mega-menu-img-sizes-attr.liquid | 87 +++
snippets/util-product-grid-card-size.liquid | 45 ++
snippets/util-product-media-sizes-attr.liquid | 142 +++++
snippets/variant-main-picker.liquid | 512 +++++++++++++++
snippets/variant-quick-add.liquid | 101 +++
snippets/variant-swatches.liquid | 165 +++++
snippets/video.liquid | 216 +++++++
19 files changed, 2445 insertions(+)
create mode 100644 snippets/strikethrough-variant.liquid
create mode 100644 snippets/stylesheets.liquid
create mode 100644 snippets/submenu-font-styles.liquid
create mode 100644 snippets/swatch.liquid
create mode 100644 snippets/tax-info.liquid
create mode 100644 snippets/text.liquid
create mode 100644 snippets/theme-editor.liquid
create mode 100644 snippets/theme-styles-variables.liquid
create mode 100644 snippets/timeline-scope.liquid
create mode 100644 snippets/typography-style.liquid
create mode 100644 snippets/unit-price.liquid
create mode 100644 snippets/util-autofill-img-size-attr.liquid
create mode 100644 snippets/util-mega-menu-img-sizes-attr.liquid
create mode 100644 snippets/util-product-grid-card-size.liquid
create mode 100644 snippets/util-product-media-sizes-attr.liquid
create mode 100644 snippets/variant-main-picker.liquid
create mode 100644 snippets/variant-quick-add.liquid
create mode 100644 snippets/variant-swatches.liquid
create mode 100644 snippets/video.liquid
diff --git a/snippets/strikethrough-variant.liquid b/snippets/strikethrough-variant.liquid
new file mode 100644
index 000000000..f5e85ee2a
--- /dev/null
+++ b/snippets/strikethrough-variant.liquid
@@ -0,0 +1,11 @@
+{% unless product_option.available %}
+
+ {% # 25deg %}
+
+
+{% endunless %}
diff --git a/snippets/stylesheets.liquid b/snippets/stylesheets.liquid
new file mode 100644
index 000000000..88668ee40
--- /dev/null
+++ b/snippets/stylesheets.liquid
@@ -0,0 +1,2 @@
+{{ 'overflow-list.css' | asset_url | preload_tag: as: 'style' }}
+{{ 'base.css' | asset_url | stylesheet_tag: preload: true }}
diff --git a/snippets/submenu-font-styles.liquid b/snippets/submenu-font-styles.liquid
new file mode 100644
index 000000000..92d071c7c
--- /dev/null
+++ b/snippets/submenu-font-styles.liquid
@@ -0,0 +1,48 @@
+{%- comment -%}
+ Derives CSS variables from the menu typography settings for 2nd and 3rd level menu items.
+ Accepts:
+ settings: {block.settings}
+{%- endcomment -%}
+
+--menu-parent-font-family: var(--font-{{ settings.type_font_primary_link }}--family); --menu-parent-font-style:
+var(--font-
+{{- settings.type_font_primary_link -}}
+--style); --menu-parent-font-weight: var(--font-
+{{- settings.type_font_primary_link -}}
+--weight); --menu-parent-font-case:
+{% if settings.type_case_primary_link == 'uppercase' %}uppercase{% else %}none{% endif %};
+{% case settings.menu_font_style %}
+ {% when 'regular' %}
+ --menu-parent-font-size: var(--menu-font-md--size); --menu-parent-font-line-height:
+ var(--menu-font-md--line-height); --menu-parent-font-color: var(--color-foreground);
+ --menu-parent-active-font-color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text));
+ {% when 'inverse' %}
+ --menu-parent-font-size: var(--menu-font-sm--size); --menu-parent-font-line-height:
+ var(--menu-font-sm--line-height); --menu-parent-font-color: rgb(var(--color-foreground-rgb) /
+ var(--opacity-subdued-text)); --menu-parent-active-font-color: var(--color-foreground);
+ {% when 'inverse_large' %}
+ --menu-parent-font-size: var(--menu-font-sm--size); --menu-parent-font-line-height:
+ var(--menu-font-sm--line-height); --menu-parent-font-color: rgb(var(--color-foreground-rgb) /
+ var(--opacity-subdued-text)); --menu-parent-active-font-color: var(--color-foreground);
+{% endcase %}
+--menu-child-font-family: var(--font-{{ settings.type_font_primary_link }}--family); --menu-child-font-style:
+var(--font-
+{{- settings.type_font_primary_link -}}
+--style); --menu-child-font-weight: var(--font-
+{{- settings.type_font_primary_link -}}
+--weight); --menu-child-font-case:
+{% if settings.type_case_primary_link == 'uppercase' %}uppercase{% else %}none{% endif %};
+{% case settings.menu_font_style %}
+ {% when 'regular' %}
+ --menu-child-font-size: var(--menu-font-sm--size); --menu-child-font-line-height: var(--menu-font-sm--line-height);
+ --menu-child-font-color: rgb(var(--color-foreground-rgb) / var(--opacity-subdued-text));
+ --menu-child-active-font-color: var(--color-foreground);
+ {% when 'inverse' %}
+ --menu-child-font-size: var(--menu-font-md--size); --menu-child-font-line-height: var(--menu-font-md--line-height);
+ --menu-child-font-color: var(--color-foreground); --menu-child-active-font-color: rgb(var(--color-foreground-rgb) /
+ var(--opacity-subdued-text));
+ {% when 'inverse_large' %}
+ --menu-child-font-size: var(--menu-font-xl--size); --menu-child-font-line-height: var(--menu-font-xl--line-height);
+ --menu-child-font-color: var(--color-foreground); --menu-child-active-font-color: rgb(var(--color-foreground-rgb) /
+ var(--opacity-subdued-text));
+{% endcase %}
diff --git a/snippets/swatch.liquid b/snippets/swatch.liquid
new file mode 100644
index 000000000..a8bf87d28
--- /dev/null
+++ b/snippets/swatch.liquid
@@ -0,0 +1,41 @@
+{%- doc -%}
+ Renders a swatch
+
+ @param {object} swatch - a swatch object
+ @param {object} [variant_image] - an alternate image
+ @param {string} [mode] - one of 'unscaled' or 'filter'
+
+ @example
+ {% render 'swatch', swatch: swatch, variant_image: variant_image, mode: 'unscaled' %}
+{%- enddoc -%}
+
+{% liquid
+ assign swatch_value = null
+ if settings.show_variant_image and variant_image
+ assign swatch_image_width = settings.variant_swatch_width | times: 2
+ assign swatch_image_url = variant_image | image_url: width: swatch_image_width
+ assign swatch_value = 'url(' | append: swatch_image_url | append: ')'
+ elsif swatch.image
+ assign swatch_image_url = swatch.image | image_url: width: 80
+ assign swatch_value = 'url(' | append: swatch_image_url | append: ')'
+ elsif swatch.color
+ assign swatch_value = 'rgb(' | append: swatch.color.rgb | append: ')'
+ endif
+
+ case mode
+ when 'unscaled'
+ assign extra_classes = ' swatch--unscaled'
+ when 'filter'
+ assign extra_classes = ' swatch--filter'
+ when 'pill'
+ assign extra_classes = ' swatch--pill'
+ else
+ assign extra_classes = ''
+ endcase
+%}
+
+
diff --git a/snippets/tax-info.liquid b/snippets/tax-info.liquid
new file mode 100644
index 000000000..3c16eaee0
--- /dev/null
+++ b/snippets/tax-info.liquid
@@ -0,0 +1,84 @@
+{%- comment -%}
+ Intended for use in a block similar to the text block.
+
+ Accepts:
+ has_discounts_enabled: {boolean} - whether discounts are enabled
+{%- endcomment -%}
+
+
+ {%- if cart.duties_included and cart.taxes_included -%}
+ {%- if shop.shipping_policy.body == blank -%}
+ {%- if has_discounts_enabled -%}
+ {{ 'content.duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts' | t }}
+ {%- else -%}
+ {{ 'content.duties_and_taxes_included_shipping_at_checkout_without_policy' | t }}
+ {%- endif -%}
+ {%- else -%}
+ {%- if has_discounts_enabled -%}
+ {{
+ 'content.duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- else -%}
+ {{
+ 'content.duties_and_taxes_included_shipping_at_checkout_with_policy_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- endif -%}
+ {%- endif -%}
+ {%- elsif cart.duties_included == false and cart.taxes_included -%}
+ {%- if shop.shipping_policy.body == blank -%}
+ {%- if has_discounts_enabled -%}
+ {{ 'content.duties_and_taxes_included_shipping_at_checkout_without_policy_without_discounts' | t }}
+ {%- else -%}
+ {{ 'content.taxes_included_shipping_at_checkout_without_policy' | t }}
+ {%- endif -%}
+ {%- else -%}
+ {%- if has_discounts_enabled -%}
+ {{
+ 'content.duties_and_taxes_included_shipping_at_checkout_with_policy_without_discounts_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- else -%}
+ {{ 'content.taxes_included_shipping_at_checkout_with_policy_html' | t: link: shop.shipping_policy.url }}
+ {%- endif -%}
+ {%- endif -%}
+ {%- elsif cart.duties_included and cart.taxes_included == false -%}
+ {%- if shop.shipping_policy.body == blank -%}
+ {%- if has_discounts_enabled -%}
+ {{ 'content.duties_included_taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts' | t }}
+ {%- else -%}
+ {{ 'content.duties_included_taxes_at_checkout_shipping_at_checkout_without_policy' | t }}
+ {%- endif -%}
+ {%- else -%}
+ {%- if has_discounts_enabled -%}
+ {{
+ 'content.duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- else -%}
+ {{
+ 'content.duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- endif -%}
+ {%- endif -%}
+ {%- elsif cart.duties_included == false and cart.taxes_included == false -%}
+ {%- if shop.shipping_policy.body == blank -%}
+ {%- if has_discounts_enabled -%}
+ {{ 'content.taxes_at_checkout_shipping_at_checkout_without_policy_without_discounts' | t }}
+ {%- else -%}
+ {{ 'content.taxes_at_checkout_shipping_at_checkout_without_policy' | t }}
+ {%- endif -%}
+ {%- else -%}
+ {%- if has_discounts_enabled -%}
+ {{
+ 'content.taxes_at_checkout_shipping_at_checkout_with_policy_without_discounts_html'
+ | t: link: shop.shipping_policy.url
+ }}
+ {%- else -%}
+ {{ 'content.taxes_at_checkout_shipping_at_checkout_with_policy_html' | t: link: shop.shipping_policy.url }}
+ {%- endif -%}
+ {%- endif -%}
+ {%- endif -%}
+
diff --git a/snippets/text.liquid b/snippets/text.liquid
new file mode 100644
index 000000000..f5526be2e
--- /dev/null
+++ b/snippets/text.liquid
@@ -0,0 +1,218 @@
+{%- doc -%}
+ Intended for use in a block similar to the text block.
+
+ @param {string} [class] - custom class to define in addition to text-block classes
+ @param {string} [fallback_text] - fallback text if settings.text does not exist
+ @param {object} [block] - The block object
+ @param {string} [width] - width of the text block
+{%- enddoc -%}
+
+{% liquid
+ assign block_settings = block.settings
+ assign plain_text = block_settings.text | strip_newlines | strip_html | strip
+ assign text_width = width | default: block_settings.width
+
+ if block_settings.font_size contains 'heading-lg' or block_settings.font_size contains 'heading-xl'
+ assign type = 'display'
+ elsif block_settings.font_size contains 'heading'
+ assign type = 'heading'
+ else
+ assign type = 'body'
+ endif
+ if block_settings.type_preset == 'rte' or block_settings.type_preset == 'paragraph'
+ assign is_rte = true
+ endif
+
+ capture text_block_classes
+ if text_width == '100%'
+ echo 'text-block--align-' | append: block_settings.alignment
+ if block_settings.max_width == 'none'
+ echo ' text-block--full-width '
+ endif
+ endif
+ if block_settings.type_preset == 'custom'
+ echo ' custom-typography '
+ if block_settings.font_size != ''
+ echo ' custom-font-size '
+ endif
+ if block_settings.color != ''
+ echo ' custom-color '
+ endif
+ endif
+ if block_settings.background
+ echo ' text-block--background '
+ endif
+ if is_rte
+ echo ' rte '
+ endif
+ endcapture
+%}
+
+{% capture attributes %}
+ class="{{ class }} spacing-style text-block text-block--{{ block.id }} {{ block_settings.type_preset }}
+ {{ text_block_classes }}
+ "
+
+ style="
+ {% render 'spacing-padding', settings: block_settings %}
+ {% render 'typography-style', settings: block_settings %}
+ --width: {{ text_width }};
+ --max-width: var(--max-width--{{ type }}-{{ block_settings.max_width }});
+ {% if text_width == "100%" %}
+ --text-align: {{ block_settings.alignment }};
+ {% endif %}
+ {% if block_settings.background %}
+ --text-background-color: {{ block_settings.background_color | default: 'rgb(255 255 255 / 1.0)' }};
+ --text-corner-radius: {{ block_settings.corner_radius }}px;
+ --text-padding: max(var(--padding-2xs), calc((var(--text-corner-radius) + var(--padding-xs)) * (1 - cos(45deg))));
+ {% endif %}
+ "
+
+ {{ block.shopify_attributes }}
+{% endcapture %}
+{% liquid
+ # {{ attributes }} must be on the immediate HTML parent of the text to preserve
+ # the click-to-edit connection in the theme editor. Any break between the text,
+ # including if-statements, will break the connection.
+
+ assign element = 'div'
+ if is_rte
+ assign element = 'rte-formatter'
+ endif
+%}
+
+{% if fallback_text != blank and plain_text == blank %}
+
+ {{ fallback_text }}
+
+{% elsif plain_text != blank %}
+ <{{ element }} {{ attributes }}>
+ {{ block.settings.text }}
+ {{ element }}>
+{% endif %}
+
+{% stylesheet %}
+ :root {
+ --text-align-default: left;
+ }
+
+ [style*='--horizontal-alignment: center'] .text-block {
+ --text-align-default: center;
+ }
+
+ [style*='--horizontal-alignment: flex-end'] .text-block {
+ --text-align-default: right;
+ }
+
+ [style*='--horizontal-alignment: flex-start'] > .text-block {
+ --text-align-default: left;
+ }
+
+ [style*='--horizontal-alignment: center'] > .text-block {
+ --text-align-default: center;
+ }
+
+ [style*='--horizontal-alignment: flex-end'] > .text-block {
+ --text-align-default: right;
+ }
+
+ .text-block {
+ width: var(--width);
+ max-width: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: var(--horizontal-alignment);
+ }
+
+ .text-block > * {
+ width: var(--width);
+ max-width: var(--max-width, 100%);
+ text-align: var(--text-align, var(--text-align-default));
+ text-wrap: var(--text-wrap);
+ }
+
+ .text-block:not(.text-block--full-width).rte,
+ .text-block:not(.text-block--full-width).paragraph {
+ /* Safari doesn't support pretty, so fallback to balance */
+ text-wrap: balance;
+ text-wrap: pretty;
+ }
+
+ .text-block:not(.text-block--full-width):is(.h1, .h2, .h3, .h4, .h5, .h6) {
+ text-wrap: balance;
+ }
+
+ /* Hide underline unless text is using paragraph styles. */
+ .text-block:is(.h1, .h2, .h3, .h4, .h5, .h6) a {
+ text-decoration-color: transparent;
+ }
+
+ .text-block h1,
+ .text-block.h1 > * {
+ margin-block: var(--font-h1--spacing);
+ }
+
+ .text-block h2,
+ .text-block.h2 > * {
+ margin-block: var(--font-h2--spacing);
+ }
+
+ .text-block h3,
+ .text-block.h3 > * {
+ margin-block: var(--font-h3--spacing);
+ }
+
+ .text-block h4,
+ .text-block.h4 > * {
+ margin-block: var(--font-h4--spacing);
+ }
+
+ .text-block h5,
+ .text-block.h5 > * {
+ margin-block: var(--font-h5--spacing);
+ }
+
+ .text-block h6,
+ .text-block.h6 > * {
+ margin-block: var(--font-h6--spacing);
+ }
+
+ .text-block p,
+ .text-block.p > * {
+ margin-block: var(--font-paragraph--spacing);
+ }
+
+ .text-block > *:first-child {
+ margin-block-start: 0;
+ }
+
+ .text-block > *:last-child {
+ margin-block-end: 0;
+ }
+
+ .text-block--align-center,
+ .text-block--align-center > * {
+ margin-inline: auto;
+ }
+
+ .text-block--align-right,
+ .text-block--align-right > * {
+ margin-inline-start: auto;
+ }
+
+ .text-block--background {
+ background-color: var(--text-background-color);
+ border-radius: var(--text-corner-radius);
+
+ /* To avoid text being cropped when using a border radius we add a minimum padding. */
+ padding-block-start: max(var(--text-padding), var(--padding-block-start, 0));
+ padding-block-end: max(var(--text-padding), var(--padding-block-end, 0));
+ padding-inline-start: max(var(--text-padding), var(--padding-inline-start, 0));
+ padding-inline-end: max(var(--text-padding), var(--padding-inline-end, 0));
+ }
+
+ .custom-color,
+ .custom-color > :is(h1, h2, h3, h4, h5, h6, p, *) {
+ color: var(--color);
+ }
+{% endstylesheet %}
diff --git a/snippets/theme-editor.liquid b/snippets/theme-editor.liquid
new file mode 100644
index 000000000..c34f0907d
--- /dev/null
+++ b/snippets/theme-editor.liquid
@@ -0,0 +1,5 @@
+
diff --git a/snippets/theme-styles-variables.liquid b/snippets/theme-styles-variables.liquid
new file mode 100644
index 000000000..ed70669ab
--- /dev/null
+++ b/snippets/theme-styles-variables.liquid
@@ -0,0 +1,591 @@
+{% style %}
+
+ {%- liquid
+ assign primary_font_bold = settings.type_body_font | font_modify: 'weight', 'bold'
+ assign primary_font_italic = settings.type_body_font | font_modify: 'style', 'italic'
+ assign primary_font_bold_italic = primary_font_bold | font_modify: 'style', 'italic'
+ %}
+
+ {{ settings.type_body_font | font_face: font_display: 'swap' }}
+ {{ primary_font_bold | font_face: font_display: 'swap' }}
+ {{ primary_font_italic | font_face: font_display: 'swap' }}
+ {{ primary_font_bold_italic | font_face: font_display: 'swap' }}
+
+ {% if settings.type_subheading_font != settings.type_body_font %}
+ {%- liquid
+ assign secondary_font_bold = settings.type_subheading_font | font_modify: 'weight', 'bold'
+ assign secondary_font_italic = settings.type_subheading_font | font_modify: 'style', 'italic'
+ assign secondary_font_bold_italic = secondary_font_bold | font_modify: 'style', 'italic'
+ %}
+
+ {{ settings.type_subheading_font | font_face: font_display: 'swap' }}
+ {{ secondary_font_bold | font_face: font_display: 'swap' }}
+ {{ secondary_font_italic | font_face: font_display: 'swap' }}
+ {{ secondary_font_bold_italic | font_face: font_display: 'swap' }}
+ {% endif %}
+
+ {% if settings.type_heading_font != settings.type_body_font and settings.type_heading_font != settings.type_subheading_font %}
+ {%- liquid
+ assign tertiary_font_bold = settings.type_heading_font | font_modify: 'weight', 'bold'
+ assign tertiary_font_italic = settings.type_heading_font | font_modify: 'style', 'italic'
+ assign tertiary_font_bold_italic = tertiary_font_bold | font_modify: 'style', 'italic'
+ %}
+
+ {{ settings.type_heading_font | font_face: font_display: 'swap' }}
+ {{ tertiary_font_bold | font_face: font_display: 'swap' }}
+ {{ tertiary_font_italic | font_face: font_display: 'swap' }}
+ {{ tertiary_font_bold_italic | font_face: font_display: 'swap' }}
+ {% endif %}
+
+ {% if settings.type_accent_font != settings.type_body_font and settings.type_accent_font != settings.type_subheading_font and settings.type_accent_font != settings.type_heading_font %}
+ {%- liquid
+ assign accent_font_bold = settings.type_accent_font | font_modify: 'weight', 'bold'
+ assign accent_font_italic = settings.type_accent_font | font_modify: 'style', 'italic'
+ assign accent_font_bold_italic = accent_font_bold | font_modify: 'style', 'italic'
+ %}
+
+ {{ settings.type_accent_font | font_face: font_display: 'swap' }}
+ {{ accent_font_bold | font_face: font_display: 'swap' }}
+ {{ accent_font_italic | font_face: font_display: 'swap' }}
+ {{ accent_font_bold_italic | font_face: font_display: 'swap' }}
+ {% endif %}
+
+ :root {
+ /* Page Layout */
+ --sidebar-width: 25rem;
+ --narrow-content-width: 36rem;
+ --normal-content-width: 42rem;
+ --wide-content-width: 46rem;
+ --narrow-page-width: 90rem;
+ --normal-page-width: 120rem;
+ --wide-page-width: 150rem;
+
+ /* Section Heights */
+ --section-height-small: 15rem;
+ --section-height-medium: 25rem;
+ --section-height-large: 35rem;
+
+ @media screen and (min-width: 40em) {
+ --section-height-small: 40svh;
+ --section-height-medium: 55svh;
+ --section-height-large: 70svh;
+ }
+
+ @media screen and (min-width: 60em) {
+ --section-height-small: 50svh;
+ --section-height-medium: 65svh;
+ --section-height-large: 80svh;
+ }
+
+ /* Letter spacing */
+ --letter-spacing-sm: 0.06em;
+ --letter-spacing-md: 0.13em;
+
+ /* Font families */
+ --font-body--family: {{ settings.type_body_font.family }}, {{ settings.type_body_font.fallback_families }};
+ --font-body--style: {{ settings.type_body_font.style }};
+ --font-body--weight: {{ settings.type_body_font.weight }};
+ --font-subheading--family: {{ settings.type_subheading_font.family }}, {{ settings.type_subheading_font.fallback_families }};
+ --font-subheading--style: {{ settings.type_subheading_font.style }};
+ --font-subheading--weight: {{ settings.type_subheading_font.weight }};
+ --font-heading--family: {{ settings.type_heading_font.family }}, {{ settings.type_heading_font.fallback_families }};
+ --font-heading--style: {{ settings.type_heading_font.style }};
+ --font-heading--weight: {{ settings.type_heading_font.weight }};
+ --font-accent--family: {{ settings.type_accent_font.family }}, {{ settings.type_accent_font.fallback_families }};
+ --font-accent--style: {{ settings.type_accent_font.style }};
+ --font-accent--weight: {{ settings.type_accent_font.weight }};
+
+ /* Margin sizes */
+ --font-h1--spacing: 0.25em;
+ --font-h2--spacing: 0.25em;
+ --font-h3--spacing: 0.25em;
+ --font-h4--spacing: 0.25em;
+ --font-h5--spacing: 0.25em;
+ --font-h6--spacing: 0.25em;
+ --font-paragraph--spacing: 0.5em;
+
+ /* Heading colors */
+ --font-h1--color: var(--color-foreground-heading);
+ --font-h2--color: var(--color-foreground-heading);
+ --font-h3--color: var(--color-foreground-heading);
+ --font-h4--color: var(--color-foreground-heading);
+ --font-h5--color: var(--color-foreground-heading);
+ --font-h6--color: var(--color-foreground-heading);
+
+ /** Z-Index / Layering */
+ --layer-section-background: -2;
+ --layer-lowest: -1;
+ --layer-base: 0;
+ --layer-flat: 1;
+ --layer-raised: 2;
+ --layer-heightened: 4;
+ --layer-sticky: 8;
+ --layer-window-overlay: 10;
+ --layer-header-menu: 12;
+ --layer-overlay: 16;
+ --layer-menu-drawer: 18;
+ --layer-temporary: 20;
+
+ /* Max-width / Measure */
+ --max-width--body-normal: 50ch;
+ --max-width--body-narrow: 35ch;
+
+ --max-width--heading-normal: 50ch;
+ --max-width--heading-narrow: 30ch;
+
+ --max-width--display-normal: 20ch;
+ --max-width--display-narrow: 15ch;
+ --max-width--display-tight: 5ch;
+
+ /* Letter-spacing / Tracking */
+ --letter-spacing--display-tight: -0.03em;
+ --letter-spacing--display-normal: 0em;
+ --letter-spacing--display-loose: 0.03em;
+
+ --letter-spacing--heading-tight: -0.03em;
+ --letter-spacing--heading-normal: 0em;
+ --letter-spacing--heading-loose: 0.03em;
+
+ --letter-spacing--body-tight: -0.03em;
+ --letter-spacing--body-normal: 0em;
+ --letter-spacing--body-loose: 0.03em;
+
+ /* Line height / Leading */
+ --line-height: 1;
+
+ --line-height--display-tight: 1;
+ --line-height--display-normal: 1.1;
+ --line-height--display-loose: 1.2;
+
+ --line-height--heading-tight: 1.15;
+ --line-height--heading-normal: 1.25;
+ --line-height--heading-loose: 1.35;
+
+ --line-height--body-tight: 1.2;
+ --line-height--body-normal: 1.4;
+ --line-height--body-loose: 1.6;
+
+ /* Typography presets */
+ {% liquid
+ assign font_sizes = "paragraph, h1, h2, h3, h4, h5, h6" | split: ", "
+ assign fluid_size_cutoff = 48
+ assign absolute_font_size_min = 10
+
+ comment
+ Build an array of font sizes and sort it
+ endcomment
+ assign font_size_values = ''
+ for font_size in font_sizes
+ assign size_setting = 'type_size_[font_size]' | replace: '[font_size]', font_size
+ assign size_setting_value = settings[size_setting] | times: 1
+
+ comment
+ If the font size is less than 100, pad it with a 0
+ This is because we end up with an array of strings, which | sort filter can't order "correctly")
+ endcomment
+ if size_setting_value < 100
+ assign size_setting_value = '0[size_setting_value]' | replace: '[size_setting_value]', size_setting_value
+ endif
+
+ assign font_size_values = font_size_values | append: '[size_setting_value],' | replace: '[size_setting_value]', size_setting_value
+ endfor
+
+ assign font_size_values = font_size_values | split: ',' | uniq | sort_natural
+
+ comment
+ For each font size S, find the next smaller size S-1, and determine the minimum for S
+ The calculation depends on the size of S-1 (over or under the cutoff)
+ endcomment
+ for font_size in font_sizes
+ assign size_setting = 'type_size_[font_size]' | replace: '[font_size]', font_size
+ assign font_size_value = settings[size_setting] | times: 1
+ assign font_size_string = '[font_size_value]' | replace: '[font_size_value]', font_size_value
+ assign index = font_size_values | find_index: font_size_string
+
+ if font_size_value >= fluid_size_cutoff
+
+ comment
+ Calculate the minimum size for each font size
+ endcomment
+ assign fluid_font_size_min = font_size_value
+
+ if index == 0
+ assign fluid_font_size_min = absolute_font_size_min
+ else
+ assign next_font_size_index = index | minus: 1
+ assign next_font_size_value = font_size_values[next_font_size_index]
+ assign next_font_size_value_number = next_font_size_value | times: 1
+
+ comment
+ If the next bigger font size under the fluid cutoff, we use keep a 4px buffer
+ endcomment
+ if next_font_size_value_number < fluid_size_cutoff
+ assign fluid_font_size_min = next_font_size_value_number | plus: 4
+ if font_size_value < fluid_font_size_min
+ assign fluid_font_size_min = font_size_value
+ endif
+ else
+ assign fluid_font_size_min = next_font_size_value | times: 1
+ endif
+ endif
+
+ comment
+ Calculate the fluid and maximum size for each font size
+ endcomment
+ assign fluid_size_min_rem = fluid_font_size_min | divided_by: 16.0
+ assign fluid_size = font_size_value | times: 0.1
+ assign fluid_size_max_rem = font_size_value | divided_by: 16.0
+
+ echo '--font-size--[font_size]: clamp([fluid_size_min_rem]rem, [fluid_size]vw, [fluid_size_max_rem]rem);' | replace: '[font_size]', font_size | replace: '[fluid_size_min_rem]', fluid_size_min_rem | replace: '[fluid_size]', fluid_size | replace: '[fluid_size_max_rem]', fluid_size_max_rem
+ else
+ assign fluid_size_rem = font_size_value | divided_by: 16.0
+ echo '--font-size--[font_size]: [fluid_size_rem]rem;' | replace: '[font_size]', font_size | replace: '[fluid_size_rem]', fluid_size_rem
+ endif
+ endfor
+
+ assign type_presets = "paragraph, h1, h2, h3, h4, h5, h6" | split: ", "
+
+ for preset_name in type_presets
+ assign preset_size = '--font-size--[preset_name]' | replace: '[preset_name]', preset_name
+ assign preset_line_height = 'type_line_height_[preset_name]' | replace: '[preset_name]', preset_name
+
+ if preset_name == 'paragraph'
+ assign preset_font = '--font-body--family'
+ assign preset_style = '--font-body--style'
+ assign preset_weight = '400'
+ assign preset_case = '--font-body--case'
+ assign preset_letter_spacing = 'body-normal'
+
+ echo '--font-[preset_name]--weight: [preset_weight];' | replace: '[preset_name]', preset_name | replace: '[preset_weight]', preset_weight
+ echo '--font-[preset_name]--letter-spacing: var(--letter-spacing--[preset_letter_spacing]);' | replace: '[preset_name]', preset_name | replace: '[preset_letter_spacing]', preset_letter_spacing
+ else
+ assign preset_font_id = 'type_font_[preset_name]' | replace: '[preset_name]', preset_name
+ assign preset_font = '--font-[preset_font]--family' | replace: '[preset_font]', settings[preset_font_id]
+ assign preset_style = '--font-[preset_font]--style' | replace: '[preset_font]', settings[preset_font_id]
+ assign preset_weight = '--font-[preset_font]--weight' | replace: '[preset_font]', settings[preset_font_id]
+ assign preset_case = 'type_case_[preset_name]' | replace: '[preset_name]', preset_name
+ assign preset_letter_spacing = 'type_letter_spacing_[preset_name]' | replace: '[preset_name]', preset_name
+
+ echo '--font-[preset_name]--weight: var([preset_weight]);' | replace: '[preset_name]', preset_name | replace: '[preset_weight]', preset_weight
+ echo '--font-[preset_name]--letter-spacing: var(--letter-spacing--[preset_letter_spacing]);' | replace: '[preset_name]', preset_name | replace: '[preset_letter_spacing]', settings[preset_letter_spacing]
+ endif
+
+ echo '--font-[preset_name]--size: var([preset_size]);' | replace: '[preset_name]', preset_name | replace: '[preset_size]', preset_size
+ echo '--font-[preset_name]--family: var([preset_font]);' | replace: '[preset_name]', preset_name | replace: '[preset_font]', preset_font
+ echo '--font-[preset_name]--style: var([preset_style]);' | replace: '[preset_name]', preset_name | replace: '[preset_style]', preset_style
+ echo '--font-[preset_name]--case: [preset_case];' | replace: '[preset_name]', preset_name | replace: '[preset_case]', settings[preset_case]
+ echo '--font-[preset_name]--line-height: var(--line-height--[preset_line_height]);' | replace: '[preset_name]', preset_name | replace: '[preset_line_height]', settings[preset_line_height]
+ endfor
+ %}
+
+ /* Hardcoded font sizes */
+ --font-size--2xs: 0.625rem;
+ --font-size--xs: 0.8125rem;
+ --font-size--sm: 0.875rem;
+ --font-size--md: 1rem;
+ --font-size--lg: 1.125rem;
+ --font-size--xl: 1.25rem;
+ --font-size--2xl: 1.5rem;
+ --font-size--3xl: 2rem;
+ --font-size--4xl: 2.5rem;
+ --font-size--5xl: 3rem;
+ --font-size--6xl: 3.5rem;
+
+ /* Menu font sizes */
+ --menu-font-sm--size: 0.875rem;
+ --menu-font-sm--line-height: calc(1.1 + 0.5 * min(16 / 14));
+ --menu-font-md--size: 1rem;
+ --menu-font-md--line-height: calc(1.1 + 0.5 * min(16 / 16));
+ --menu-font-lg--size: 1.125rem;
+ --menu-font-lg--line-height: calc(1.1 + 0.5 * min(16 / 18));
+ --menu-font-xl--size: 1.25rem;
+ --menu-font-xl--line-height: calc(1.1 + 0.5 * min(16 / 20));
+ --menu-font-2xl--size: 1.75rem;
+ --menu-font-2xl--line-height: calc(1.1 + 0.5 * min(16 / 28));
+
+ /* Colors */
+ --color-error: #8B0000;
+ --color-success: #006400;
+ --color-white: #FFFFFF;
+ --color-white-rgb: 255 255 255;
+ --color-black: #000000;
+ --color-instock: #3ED660;
+ --color-lowstock: #EE9441;
+ --color-outofstock: #C8C8C8;
+
+ /* Opacity */
+ --opacity-5: 0.05;
+ --opacity-8: 0.08;
+ --opacity-10: 0.1;
+ --opacity-15: 0.15;
+ --opacity-20: 0.2;
+ --opacity-25: 0.25;
+ --opacity-30: 0.3;
+ --opacity-40: 0.4;
+ --opacity-50: 0.5;
+ --opacity-60: 0.6;
+ --opacity-70: 0.7;
+ --opacity-80: 0.8;
+ --opacity-85: 0.85;
+ --opacity-90: 0.9;
+ --opacity-subdued-text: var(--opacity-70);
+
+ --shadow-button: 0 2px 3px rgb(0 0 0 / 20%);
+ --gradient-image-overlay: linear-gradient(to top, rgb(0 0 0 / 0.5), transparent);
+
+ /* Spacing */
+ --margin-3xs: 0.125rem;
+ --margin-2xs: 0.3rem;
+ --margin-xs: 0.5rem;
+ --margin-sm: 0.7rem;
+ --margin-md: 0.8rem;
+ --margin-lg: 1rem;
+ --margin-xl: 1.25rem;
+ --margin-2xl: 1.5rem;
+ --margin-3xl: 1.75rem;
+ --margin-4xl: 2rem;
+ --margin-5xl: 3rem;
+ --margin-6xl: 5rem;
+
+ --scroll-margin: 50px;
+
+ --padding-3xs: 0.125rem;
+ --padding-2xs: 0.25rem;
+ --padding-xs: 0.5rem;
+ --padding-sm: 0.7rem;
+ --padding-md: 0.8rem;
+ --padding-lg: 1rem;
+ --padding-xl: 1.25rem;
+ --padding-2xl: 1.5rem;
+ --padding-3xl: 1.75rem;
+ --padding-4xl: 2rem;
+ --padding-5xl: 3rem;
+ --padding-6xl: 4rem;
+
+ --gap-3xs: 0.125rem;
+ --gap-2xs: 0.3rem;
+ --gap-xs: 0.5rem;
+ --gap-sm: 0.7rem;
+ --gap-md: 0.9rem;
+ --gap-lg: 1rem;
+ --gap-xl: 1.25rem;
+ --gap-2xl: 2rem;
+ --gap-3xl: 3rem;
+
+ --spacing-scale-sm: 0.6;
+ --spacing-scale-md: 0.7;
+ --spacing-scale-default: 1.0;
+
+ /* Checkout buttons gap */
+ --checkout-button-gap: 10px;
+
+ /* Borders */
+ --style-border-width: 1px;
+ --style-border-radius-xs: 0.2rem;
+ --style-border-radius-sm: 0.6rem;
+ --style-border-radius-md: 0.8rem;
+ --style-border-radius-50: 50%;
+ --style-border-radius-lg: 1rem;
+ --style-border-radius-pills: {{ settings.pills_border_radius }}px;
+ --style-border-radius-inputs: {{ settings.inputs_border_radius }}px;
+ --style-border-radius-buttons-primary: {{ settings.button_border_radius_primary }}px;
+ --style-border-radius-buttons-secondary: {{ settings.button_border_radius_secondary }}px;
+ --style-border-width-primary: {{ settings.primary_button_border_width }}px;
+ --style-border-width-secondary: {{ settings.secondary_button_border_width }}px;
+ --style-border-width-inputs: {{ settings.input_border_width }}px;
+ --style-border-radius-popover: {{ settings.popover_border_radius }}px;
+ --style-border-popover: {{ settings.popover_border_width }}px {{ settings.popover_border }} rgb(var(--color-border-rgb) / {{ settings.popover_border_opacity }}%);
+ --style-border-drawer: {{ settings.drawer_border_width }}px {{ settings.drawer_border }} rgb(var(--color-border-rgb) / {{ settings.drawer_border_opacity }}%);
+ --style-border-swatch-opacity: {{ settings.variant_swatch_border_opacity }}%;
+ --style-border-swatch-width: {{ settings.variant_swatch_border_width }}px;
+ --style-border-swatch-style: {{ settings.variant_swatch_border_style }};
+
+ /* Animation */
+ --ease-out-cubic: cubic-bezier(0.33, 1, 0.68, 1);
+ --ease-out-quad: cubic-bezier(0.32, 0.72, 0, 1);
+ --animation-speed-fast: 0.0625s;
+ --animation-speed: 0.125s;
+ --animation-speed-slow: 0.2s;
+ --animation-speed-medium: 0.15s;
+ --animation-easing: ease-in-out;
+ --animation-slideshow-easing: cubic-bezier(0.4, 0, 0.2, 1);
+ --drawer-animation-speed: 0.2s;
+ --animation-values-slow: var(--animation-speed-slow) var(--animation-easing);
+ --animation-values: var(--animation-speed) var(--animation-easing);
+ --animation-values-fast: var(--animation-speed-fast) var(--animation-easing);
+ --animation-values-allow-discrete: var(--animation-speed) var(--animation-easing) allow-discrete;
+ --animation-timing-hover: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+ --animation-timing-active: cubic-bezier(0.5, 0, 0.75, 0);
+ --animation-timing-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
+ --animation-timing-default: cubic-bezier(0, 0, 0.2, 1);
+ --animation-timing-fade-in: cubic-bezier(0.16, 1, 0.3, 1);
+ --animation-timing-fade-out: cubic-bezier(0.4, 0, 0.2, 1);
+
+ /* View transitions */
+ /* View transition old */
+ --view-transition-old-main-content: var(--animation-speed) var(--animation-easing) both fadeOut;
+
+ /* View transition new */
+ --view-transition-new-main-content: var(--animation-speed) var(--animation-easing) both fadeIn, var(--animation-speed) var(--animation-easing) both slideInTopViewTransition;
+
+ /* Focus */
+ --focus-outline-width: 0.09375rem;
+ --focus-outline-offset: 0.2em;
+
+ /* Badges */
+ --badge-blob-padding-block: 1px;
+ --badge-blob-padding-inline: 12px 8px;
+ --badge-rectangle-padding-block: 1px;
+ --badge-rectangle-padding-inline: 6px;
+ @media screen and (min-width: 750px) {
+ --badge-blob-padding-block: 4px;
+ --badge-blob-padding-inline: 16px 12px;
+ --badge-rectangle-padding-block: 4px;
+ --badge-rectangle-padding-inline: 10px;
+ }
+
+ /* Icons */
+ --icon-size-2xs: 0.6rem;
+ --icon-size-xs: 0.85rem;
+ --icon-size-sm: 1.25rem;
+ --icon-size-md: 1.375rem;
+ --icon-size-lg: 1.5rem;
+ --icon-stroke-width: {% if settings.icon_stroke == 'thin' %}1px{% elsif settings.icon_stroke == 'heavy' %}2px{% else %}1.5px{% endif %};
+
+ /* Input */
+ --input-email-min-width: 200px;
+ --input-search-max-width: 650px;
+ --input-padding-y: 0.8rem;
+ --input-padding-x: 0.8rem;
+ --input-padding: var(--input-padding-y) var(--input-padding-x);
+ --input-box-shadow-width: var(--style-border-width-inputs);
+ --input-box-shadow: 0 0 0 var(--input-box-shadow-width) var(--color-input-border);
+ --input-box-shadow-focus: 0 0 0 calc(var(--input-box-shadow-width) + 0.5px) var(--color-input-border);
+ --input-disabled-background-color: rgb(var(--color-foreground-rgb) / var(--opacity-10));
+ --input-disabled-border-color: rgb(var(--color-foreground-rgb) / var(--opacity-5));
+ --input-disabled-text-color: rgb(var(--color-foreground-rgb) / var(--opacity-50));
+ --input-textarea-min-height: 55px;
+
+ /* Button size */
+ --button-size-sm: 30px;
+ --button-size-md: 36px;
+ --button-size: var(--minimum-touch-target);
+ --button-padding-inline: 24px;
+ --button-padding-block: 16px;
+
+ /* Button font-family */
+ --button-font-family-primary: var(--font-{{ settings.type_font_button_primary }}--family);
+ --button-font-family-secondary: var(--font-{{ settings.type_font_button_secondary }}--family);
+
+ /* Button text case */
+ --button-text-case: {{ settings.button_text_case }};
+ --button-text-case-primary: {{ settings.button_text_case_primary }};
+ --button-text-case-secondary: {{ settings.button_text_case_secondary }};
+
+ /* Borders */
+ --border-color: rgb(var(--color-border-rgb) / var(--opacity-50));
+ --border-width-sm: 1px;
+ --border-width-md: 2px;
+ --border-width-lg: 5px;
+
+ /* Drawers */
+ --drawer-inline-padding: 25px;
+ --drawer-menu-inline-padding: 2.5rem;
+ --drawer-header-block-padding: 20px;
+ --drawer-content-block-padding: 10px;
+ --drawer-header-desktop-top: 0rem;
+ --drawer-padding: calc(var(--padding-sm) + 7px);
+ --drawer-height: 100dvh;
+ --drawer-width: 95vw;
+ --drawer-max-width: 500px;
+
+ /* Variant Picker Swatches */
+ --variant-picker-swatch-width-unitless: {{ settings.variant_swatch_width }};
+ --variant-picker-swatch-height-unitless: {{ settings.variant_swatch_height }};
+ --variant-picker-swatch-width: {{ settings.variant_swatch_width | append: 'px' }};
+ --variant-picker-swatch-height: {{ settings.variant_swatch_height | append: 'px' }};
+ --variant-picker-swatch-radius: {{ settings.variant_swatch_radius | append: 'px' }};
+ --variant-picker-border-width: {{ settings.variant_swatch_border_width | append: 'px' }};
+ --variant-picker-border-style: {{ settings.variant_swatch_border_style }};
+ --variant-picker-border-opacity: {{ settings.variant_swatch_border_opacity | append: '%' }};
+
+ /* Variant Picker Buttons */
+ --variant-picker-button-radius: {{ settings.variant_button_radius | append: 'px' }};
+ --variant-picker-button-border-width: {{ settings.variant_button_border_width | append: 'px' }};
+
+ /* Slideshow */
+ --slideshow-controls-size: 3.5rem;
+ --slideshow-controls-icon: 2rem;
+ --peek-next-slide-size: 3rem;
+
+ /* Utilities */
+ --backdrop-opacity: 0.15;
+ --backdrop-color-rgb: var(--color-shadow-rgb);
+ --minimum-touch-target: 44px;
+ --disabled-opacity: 0.5;
+ --skeleton-opacity: 0.025;
+
+ /* Shapes */
+ --shape--circle: circle(50% at center);
+ --shape--sunburst: polygon(100% 50%,94.62% 55.87%,98.3% 62.94%,91.57% 67.22%,93.3% 75%,85.7% 77.39%,85.36% 85.36%,77.39% 85.7%,75% 93.3%,67.22% 91.57%,62.94% 98.3%,55.87% 94.62%,50% 100%,44.13% 94.62%,37.06% 98.3%,32.78% 91.57%,25% 93.3%,22.61% 85.7%,14.64% 85.36%,14.3% 77.39%,6.7% 75%,8.43% 67.22%,1.7% 62.94%,5.38% 55.87%,0% 50%,5.38% 44.13%,1.7% 37.06%,8.43% 32.78%,6.7% 25%,14.3% 22.61%,14.64% 14.64%,22.61% 14.3%,25% 6.7%,32.78% 8.43%,37.06% 1.7%,44.13% 5.38%,50% 0%,55.87% 5.38%,62.94% 1.7%,67.22% 8.43%,75% 6.7%,77.39% 14.3%,85.36% 14.64%,85.7% 22.61%,93.3% 25%,91.57% 32.78%,98.3% 37.06%,94.62% 44.13%);
+ --shape--diamond: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
+ --shape--blob: polygon(85.349% 11.712%, 87.382% 13.587%, 89.228% 15.647%, 90.886% 17.862%, 92.359% 20.204%, 93.657% 22.647%, 94.795% 25.169%, 95.786% 27.752%, 96.645% 30.382%, 97.387% 33.048%, 98.025% 35.740%, 98.564% 38.454%, 99.007% 41.186%, 99.358% 43.931%, 99.622% 46.685%, 99.808% 49.446%, 99.926% 52.210%, 99.986% 54.977%, 99.999% 57.744%, 99.975% 60.511%, 99.923% 63.278%, 99.821% 66.043%, 99.671% 68.806%, 99.453% 71.565%, 99.145% 74.314%, 98.724% 77.049%, 98.164% 79.759%, 97.433% 82.427%, 96.495% 85.030%, 95.311% 87.529%, 93.841% 89.872%, 92.062% 91.988%, 89.972% 93.796%, 87.635% 95.273%, 85.135% 96.456%, 82.532% 97.393%, 79.864% 98.127%, 77.156% 98.695%, 74.424% 99.129%, 71.676% 99.452%, 68.918% 99.685%, 66.156% 99.844%, 63.390% 99.942%, 60.624% 99.990%, 57.856% 99.999%, 55.089% 99.978%, 52.323% 99.929%, 49.557% 99.847%, 46.792% 99.723%, 44.031% 99.549%, 41.273% 99.317%, 38.522% 99.017%, 35.781% 98.639%, 33.054% 98.170%, 30.347% 97.599%, 27.667% 96.911%, 25.024% 96.091%, 22.432% 95.123%, 19.907% 93.994%, 17.466% 92.690%, 15.126% 91.216%, 12.902% 89.569%, 10.808% 87.761%, 8.854% 85.803%, 7.053% 83.703%, 5.418% 81.471%, 3.962% 79.119%, 2.702% 76.656%, 1.656% 74.095%, 0.846% 71.450%, 0.294% 68.740%, 0.024% 65.987%, 0.050% 63.221%, 0.343% 60.471%, 0.858% 57.752%, 1.548% 55.073%, 2.370% 52.431%, 3.283% 49.819%, 4.253% 47.227%, 5.249% 44.646%, 6.244% 42.063%, 7.211% 39.471%, 8.124% 36.858%, 8.958% 34.220%, 9.711% 31.558%, 10.409% 28.880%, 11.083% 26.196%, 11.760% 23.513%, 12.474% 20.839%, 13.259% 18.186%, 14.156% 15.569%, 15.214% 13.012%, 16.485% 10.556%, 18.028% 8.261%, 19.883% 6.211%, 22.041% 4.484%, 24.440% 3.110%, 26.998% 2.057%, 29.651% 1.275%, 32.360% 0.714%, 35.101% 0.337%, 37.859% 0.110%, 40.624% 0.009%, 43.391% 0.016%, 46.156% 0.113%, 48.918% 0.289%, 51.674% 0.533%, 54.425% 0.837%, 57.166% 1.215%, 59.898% 1.654%, 62.618% 2.163%, 65.322% 2.750%, 68.006% 3.424%, 70.662% 4.197%, 73.284% 5.081%, 75.860% 6.091%, 78.376% 7.242%, 80.813% 8.551%, 83.148% 10.036%, 85.349% 11.712%);
+
+ /* Buy buttons */
+ --height-buy-buttons: calc(var(--padding-lg) * 2 + var(--icon-size-sm));
+
+ /* Card image width and height variables */
+ --card-width-small: 10rem;
+
+ --height-small: 10rem;
+ --height-medium: 11.5rem;
+ --height-large: 13rem;
+ --height-full: 100vh;
+
+ @media screen and (min-width: 750px) {
+ --height-small: 17.5rem;
+ --height-medium: 21.25rem;
+ --height-large: 25rem;
+ }
+
+ /* Modal */
+ --modal-max-height: 65dvh;
+
+ /* Card styles for search */
+ --card-bg-hover: rgb(var(--color-foreground-rgb) / var(--opacity-5));
+ --card-border-hover: rgb(var(--color-foreground-rgb) / var(--opacity-30));
+ --card-border-focus: rgb(var(--color-foreground-rgb) / var(--opacity-10));
+
+ /* Cart */
+ --cart-primary-font-family: var(--font-body--family);
+ --cart-primary-font-style: var(--font-body--style);
+ --cart-primary-font-weight: var(--font-body--weight);
+ --cart-secondary-font-family: var(--font-{{ settings.cart_price_font }}--family);
+ --cart-secondary-font-style: var(--font-{{ settings.cart_price_font }}--style);
+ --cart-secondary-font-weight: var(--font-{{ settings.cart_price_font }}--weight);
+ }
+
+/* 1) Load your custom font file */
+@font-face {
+ font-family: 'Gangster Grotesk';
+ src: url('{{ "GangsterGrotesk-Regular.woff" | asset_url }}') format('woff');
+ font-weight: 400;
+ font-style: normal;
+ font-display: swap;
+}
+
+/* 2) Override the theme CSS variables to use your family */
+:root {
+ --font-body--family: 'Gangster Grotesk', sans-serif;
+ --font-subheading--family: 'Gangster Grotesk', sans-serif;
+ --font-heading--family: 'Gangster Grotesk', sans-serif;
+ --font-accent--family: 'Gangster Grotesk', sans-serif;
+
+ /* optional if the theme reads these */
+ --font-body--weight: 400;
+ --font-subheading--weight: 400;
+ --font-heading--weight: 400;
+ --font-accent--weight: 400;
+}
+
+{% endstyle %}
diff --git a/snippets/timeline-scope.liquid b/snippets/timeline-scope.liquid
new file mode 100644
index 000000000..67c1cfe02
--- /dev/null
+++ b/snippets/timeline-scope.liquid
@@ -0,0 +1,11 @@
+{%- liquid
+ assign timeline_scope = ''
+
+ for index in (1..count)
+ assign scope = '--prefix-index, ' | replace: 'prefix', prefix | replace: 'index', index
+ assign timeline_scope = timeline_scope | append: scope
+ endfor
+
+ assign timeline_scope = timeline_scope | strip | split: ',' | compact | join: ','
+-%}
+{{- timeline_scope -}}
diff --git a/snippets/typography-style.liquid b/snippets/typography-style.liquid
new file mode 100644
index 000000000..c7aff6a36
--- /dev/null
+++ b/snippets/typography-style.liquid
@@ -0,0 +1,75 @@
+{%- comment -%}
+ Intended for blocks and sections that provide values for all the referenced settings.
+
+
+
+ Accepts:
+ settings: {settings || section.settings}
+{%- endcomment -%}
+
+{% assign preset = preset | default: settings.type_preset %}
+
+{%- capture variables -%}
+ {%- if preset != 'rte' and settings.color != "" -%}
+ --color: {{ settings.color }};
+ {%- endif -%}
+ {%- if preset == 'custom' -%}
+ {% liquid
+ unless type
+ comment
+ When choosing to customize the font, picking a specific font size
+ determines the type of text block.
+ endcomment
+ if settings.font_size != ''
+ assign font_size_value = settings.font_size | split: 'rem' | first | times: 1.0
+
+ if font_size_value > 4.5
+ assign type = 'display'
+ elsif font_size_value > 3.5
+ assign type = 'heading'
+ else
+ assign type = 'body'
+ endif
+ endif
+ endunless
+ %}
+ {%- if settings.font_size != blank -%}
+ {%- liquid
+ assign font_size_rem = settings.font_size | split: 'rem' | first | times: 1.0
+ assign fluid_size_cutoff_rem = 3.0
+
+ if font_size_rem >= fluid_size_cutoff_rem
+ assign target_viewport = 1400
+ assign vw_value = font_size_rem | times: 16 | divided_by: target_viewport | times: 100
+
+ assign scale_factor = font_size_rem | divided_by: fluid_size_cutoff_rem
+ assign base_min_rem = 3.0
+ assign scaling_bonus_rem = scale_factor | minus: 1 | times: 0.25
+ assign dynamic_min_rem = base_min_rem | plus: scaling_bonus_rem
+ endif
+ -%}
+ {%- if font_size_rem >= fluid_size_cutoff_rem -%}
+ --font-size: clamp({{ dynamic_min_rem }}rem, {{ vw_value }}vw, {{ settings.font_size }});
+ {%- else -%}
+ --font-size: {{ settings.font_size }};
+ {%- endif -%}
+ {%- endif -%}
+ {%- if settings.weight != blank -%}
+ --font-weight: {{ settings.weight }};
+ {% else %}
+ --font-weight: {{ settings.font | replace: 'family', 'weight' }};
+ {%- endif -%}
+ --font-family: {{ settings.font }};
+ --text-transform: {{ settings.case }};
+ --text-wrap: {{ settings.wrap }};
+ {% if settings.type_preset == 'custom' and settings.font_size == blank %}
+ --line-height--display: var(--line-height--display-{{ settings.line_height }});
+ --line-height--heading: var(--line-height--heading-{{ settings.line_height }});
+ --line-height--body: var(--line-height--body-{{ settings.line_height }});
+ {% else %}
+ --line-height: var(--line-height--{{ type }}-{{ settings.line_height }});
+ {% endif %}
+ --letter-spacing: var(--letter-spacing--{{ type }}-{{ settings.letter_spacing }});
+ {%- endif -%}
+{%- endcapture -%}
+{{- variables | strip | strip_newlines -}}
diff --git a/snippets/unit-price.liquid b/snippets/unit-price.liquid
new file mode 100644
index 000000000..6d9ba4d59
--- /dev/null
+++ b/snippets/unit-price.liquid
@@ -0,0 +1,16 @@
+{%- doc -%}
+ Renders the unit price, including its measurement.
+
+ @param {object} price - The unit price (money or string).
+ @param {object} measurement - The unit_price_measurement object.
+
+ @example
+ {% render 'unit-price', price: variant.unit_price, measurement: variant.unit_price_measurement %}
+
+ @example
+ {% render 'unit-price', price: line_item.unit_price | money_with_currency, measurement: line_item.unit_price_measurement }
+{%- enddoc -%}
+
+ {{ 'accessibility.unit_price' | t }}
+ {{ price | unit_price_with_measurement: measurement }}
+
diff --git a/snippets/util-autofill-img-size-attr.liquid b/snippets/util-autofill-img-size-attr.liquid
new file mode 100644
index 000000000..79dbf1e40
--- /dev/null
+++ b/snippets/util-autofill-img-size-attr.liquid
@@ -0,0 +1,75 @@
+{%- doc -%}
+ Echo a sizes attribute for an
tag based on a minimum image size.
+
+ @param {number} card_size - The minimum pixel-width of the product card.
+ @param {number} [card_gap] - The pixel-width of the gap between product cards.
+ @param {number} [max_breakpoint] - The maximum pixel-width to calculate breakpoints for.
+ @param {number} [min_breakpoint] - The minimum pixel-width before defaulting to 50vw.
+
+ @example
+ {% capture size_attribute %}
+ {% render 'util-autofill-img-size-attr' card_size: 400 %}
+ {% endcapture %}
+ {% assign size_attribute = size_attribute | strip %}
+ {{ image_url | image_tag: sizes: size_attribute }}
+{%- enddoc -%}
+
+{% liquid
+ # Defense: ensure card_size and card_gap are numbers
+ assign card_size = card_size | strip | replace: 'px', '' | plus: 0
+
+ if card_gap
+ assign card_gap = card_gap | strip | replace: 'px', '' | plus: 0
+ else
+ assign card_gap = 0
+ endif
+
+ assign card_size_with_gap = card_size | plus: card_gap
+
+ assign max_breakpoint = max_breakpoint | default: 2000
+
+ assign min_breakpoint = min_breakpoint | default: 750
+
+ # Calculate maximum number of columns at max width
+ assign max_cols = max_breakpoint | divided_by: card_size_with_gap | floor
+
+ assign sizes_attr = ''
+
+ # Calculate breakpoints dynamically based on card size
+ # Start with max columns and work down
+ for i in (1..max_cols)
+ # Current number of columns we're calculating for
+ assign current_cols = max_cols | minus: i | plus: 1
+
+ # Skip if we're down to 1 column
+ if current_cols < 2
+ break
+ endif
+
+ # Calculate the minimum width needed for this many columns
+ assign min_width_needed = current_cols | times: card_size_with_gap
+
+ if min_width_needed < min_breakpoint
+ break
+ endif
+
+ assign percentage = 100 | divided_by: current_cols
+
+ # Build up the sizes attribute
+ if sizes_attr != ''
+ assign sizes_attr = sizes_attr | append: ', '
+ endif
+ assign sizes_attr = sizes_attr | append: '(min-width: ' | append: min_width_needed | append: 'px) ' | append: percentage | append: 'vw'
+ endfor
+
+ # Add tablet size (50vw) and mobile size (100vw) fallbacks
+ if sizes_attr != ''
+ assign sizes_attr = sizes_attr | append: ', '
+ endif
+ assign sizes_attr = sizes_attr | append: '(min-width: ' | append: min_breakpoint | append: 'px) 50vw'
+
+ assign sizes_attr = sizes_attr | append: ', 100vw'
+
+ # Echo the sizes attribute
+ echo sizes_attr
+%}
diff --git a/snippets/util-mega-menu-img-sizes-attr.liquid b/snippets/util-mega-menu-img-sizes-attr.liquid
new file mode 100644
index 000000000..a8ce818a5
--- /dev/null
+++ b/snippets/util-mega-menu-img-sizes-attr.liquid
@@ -0,0 +1,87 @@
+{%- doc -%}
+ Calculate the sizes attribute for mega menu images based on menu type and grid configuration.
+
+ @param {string} menu_content_type - Type of menu: 'collection_images', 'featured_products', or 'featured_collections'
+ @param {object} settings - Theme settings object containing page width configuration
+ @param {number} [grid_columns] - Number of grid columns for the mega menu
+ @param {number} [grid_columns_tablet] - Number of grid columns for tablet view
+ @param {number} [grid_columns_collection_images] - Grid columns when menu_content_type is 'collection_images' with < 5 items
+ @param {number} [parent_links_size] - Number of parent links (for collection images special case)
+ @param {number} [columns_per_item] - Columns each item occupies (2 for collection images, 1 for products)
+
+ @example
+ {% capture image_sizes %}
+ {% render 'util-mega-menu-img-sizes-attr',
+ menu_content_type: 'collection_images',
+ settings: settings,
+ grid_columns: 8,
+ grid_columns_tablet: 4,
+ columns_per_item: 2
+ %}
+ {% endcapture %}
+
+ {{ image | image_url: width: 1024 | image_tag: sizes: image_sizes }}
+{%- enddoc -%}
+
+{% liquid
+ # Early exit for featured collections
+ if menu_content_type == 'featured_collections'
+ echo '300px'
+ break
+ endif
+
+ # Define breakpoints and max widths based on page width setting
+ case settings.page_width
+ when 'narrow'
+ assign page_max_width = '90rem'
+ assign breakpoint = '95rem'
+ when 'normal'
+ assign page_max_width = '120rem'
+ assign breakpoint = '125rem'
+ when 'wide'
+ assign page_max_width = '150rem'
+ assign breakpoint = '155rem'
+ endcase
+
+ # Common values
+ # Gap between items in pixels (numeric for calculations)
+ # Page margins (with unit for direct use in calc())
+ assign gap = 20
+ assign margins = '80px'
+ assign grid_tablet = grid_columns_tablet | default: 4
+
+ # Set up grid configuration based on menu type
+ case menu_content_type
+ when 'collection_images'
+ assign cols_per_item = columns_per_item | default: 2
+ assign grid_desktop = grid_columns | default: 8
+
+ # Special case: fewer than 5 collection images
+ if parent_links_size < 5
+ assign grid_desktop = grid_columns_collection_images | default: grid_desktop
+ endif
+
+ when 'featured_products'
+ assign cols_per_item = 1
+ assign grid_desktop = grid_columns | default: 6
+ endcase
+
+ # Calculate gaps for each breakpoint
+ assign items_desktop = grid_desktop | divided_by: cols_per_item
+ assign items_tablet = grid_tablet | divided_by: cols_per_item
+ assign gaps_desktop_px = items_desktop | minus: 1 | times: gap | append: 'px'
+ assign gaps_tablet_px = items_tablet | minus: 1 | times: gap | append: 'px'
+%}
+
+{%- capture sizes -%}
+ {%- comment -%} Large viewports with fixed page width {%- endcomment -%}
+ (min-width: {{ breakpoint }}) calc(({{ page_max_width }} - {{ margins }} - {{ gaps_desktop_px }}) * {{ cols_per_item }} / {{ grid_desktop }}),
+
+ {%- comment -%} Desktop viewports {%- endcomment -%}
+ (min-width: 990px) calc((100vw - {{ margins }} - {{ gaps_desktop_px }}) * {{ cols_per_item }} / {{ grid_desktop }}),
+
+ {%- comment -%} Tablet {%- endcomment -%}
+ calc((100vw - {{ margins }} - {{ gaps_tablet_px }}) / {{ grid_tablet }})
+{%- endcapture -%}
+
+{{ sizes | strip_newlines | strip }}
diff --git a/snippets/util-product-grid-card-size.liquid b/snippets/util-product-grid-card-size.liquid
new file mode 100644
index 000000000..fdbcd0f42
--- /dev/null
+++ b/snippets/util-product-grid-card-size.liquid
@@ -0,0 +1,45 @@
+{%- doc -%}
+ Output the minimum product card size for cards in a product grid (main collection and search results).
+
+ @param {object} section - Section object that contains the product card block.
+
+ @example
+ {% capture product_card_size %}
+ {% render 'util-product-grid-card-size' section: section %}
+ {% endcapture %}
+{%- enddoc -%}
+
+{% liquid
+ if section.settings.layout_type == 'organic'
+ if section.settings.product_grid_width == 'centered'
+ assign product_card_size = '250px'
+ else
+ assign product_card_size = '260px'
+ endif
+ elsif section.settings.product_grid_width == 'centered'
+ # Hardcoded values for product card size when width set to 'centered'
+ case section.settings.product_card_size
+ when 'small'
+ assign product_card_size = '165px'
+ when 'medium'
+ assign product_card_size = '250px'
+ when 'large'
+ assign product_card_size = '340px'
+ when 'extra-large'
+ assign product_card_size = '480px'
+ endcase
+ else
+ # Hardcoded values for product card size when width set to 'full-width'
+ case section.settings.product_card_size
+ when 'small'
+ assign product_card_size = '180px'
+ when 'medium'
+ assign product_card_size = '260px'
+ when 'large'
+ assign product_card_size = '365px'
+ when 'extra-large'
+ assign product_card_size = '530px'
+ endcase
+ endif
+ echo product_card_size
+%}
diff --git a/snippets/util-product-media-sizes-attr.liquid b/snippets/util-product-media-sizes-attr.liquid
new file mode 100644
index 000000000..8458af158
--- /dev/null
+++ b/snippets/util-product-media-sizes-attr.liquid
@@ -0,0 +1,142 @@
+{%- doc -%}
+ Calculate the sizes attribute for product media images in the product media gallery.
+
+ @param {object} block - Block object containing media gallery settings
+ @param {object} section - Section object containing layout settings
+ @param {object} settings - Theme settings object containing page width configuration
+ @param {boolean} [is_first_image] - Whether this is the first image (for large_first_image mode)
+ @param {boolean} [is_single_column] - Whether the layout is single column (carousel or one-column grid)
+ @param {boolean} [needs_both_sizes] - Whether we need to calculate different sizes for first and other images
+
+ @example
+ {% capture media_sizes %}
+ {% render 'util-product-media-sizes-attr', block: block, section: section, settings: settings, is_single_column: is_single_column %}
+ {% endcapture %}
+ {% assign media_sizes = media_sizes | strip %}
+ {{ media | image_url: width: 800 | image_tag: sizes: media_sizes }}
+{%- enddoc -%}
+
+{%- liquid
+ assign block_settings = block.settings
+ # Constants
+ assign page_margin = '40px'
+ # Section gap divided by 2 (used for single column layouts)
+ assign gap_half = section.settings.gap | divided_by: 2 | append: 'px'
+ # Section gap divided by 4 (used for two column layouts where each column gets half of the half gap)
+ assign gap_quarter = section.settings.gap | divided_by: 4 | append: 'px'
+ # Image gap divided by 2 (space between images in grid)
+ assign image_gap_half = block_settings.image_gap | divided_by: 2 | append: 'px'
+
+ assign is_single_column = is_single_column | default: false
+ assign needs_both_sizes = needs_both_sizes | default: false
+
+ # Determine which size calculation to use
+ assign calculate_single_column = false
+ assign calculate_grid_column = false
+
+ if needs_both_sizes
+ if is_first_image
+ assign calculate_single_column = true
+ else
+ assign calculate_grid_column = true
+ endif
+ elsif is_single_column
+ assign calculate_single_column = true
+ else
+ assign calculate_grid_column = true
+ endif
+
+ # Set up default sizes
+ if calculate_single_column
+ # Default for carousel or single column grid (or first image in large_first_image mode)
+ if section.settings.equal_columns == false
+ assign default_sizes = '(min-width: 750px) calc(100vw - 25rem - [gap_half]), 100vw' | replace: '[gap_half]', gap_half
+ else
+ assign default_sizes = '(min-width: 750px) calc(50vw - [gap_half]), 100vw' | replace: '[gap_half]', gap_half
+ endif
+ else
+ # Default for two column grid - includes image gap and quarter section gap
+ if section.settings.equal_columns == false
+ assign default_sizes = '(min-width: 750px) calc((100vw - 25rem) / 2 - [gap_quarter] - [image_gap_half]), 100vw' | replace: '[gap_quarter]', gap_quarter | replace: '[image_gap_half]', image_gap_half
+ else
+ assign default_sizes = '(min-width: 750px) calc(50vw / 2 - [gap_quarter] - [image_gap_half]), 100vw' | replace: '[gap_quarter]', gap_quarter | replace: '[image_gap_half]', image_gap_half
+ endif
+ endif
+
+ # Override for center-aligned content
+ if section.settings.content_width == 'content-center-aligned'
+ # Define breakpoints and base sizes based on page width
+ # Breakpoints are the page width setting + margin (where 2 x margin is 80px = 5rem)
+ case settings.page_width
+ when 'narrow'
+ assign breakpoint = '95rem'
+ assign media_base_size_equal_columns = '45rem'
+ assign media_base_size_unequal_columns = '65rem'
+ when 'normal'
+ assign breakpoint = '125rem'
+ assign media_base_size_equal_columns = '60rem'
+ assign media_base_size_unequal_columns = '95rem'
+ when 'wide'
+ assign breakpoint = '155rem'
+ assign media_base_size_equal_columns = '75rem'
+ assign media_base_size_unequal_columns = '125rem'
+ endcase
+
+ # Select the appropriate base size
+ if section.settings.equal_columns
+ assign media_base_size = media_base_size_equal_columns
+ else
+ assign media_base_size = media_base_size_unequal_columns
+ endif
+
+ # Calculate large screen size base
+ if block_settings.extend_media
+ assign large_size_base = '[media_base_size] + (100vw - [breakpoint])' | replace: '[media_base_size]', media_base_size | replace: '[breakpoint]', breakpoint
+ else
+ assign large_size_base = media_base_size
+ endif
+
+ # Calculate medium screen size
+ if section.settings.equal_columns
+ assign medium_base = '50vw'
+ else
+ assign medium_base = '100vw - 25rem'
+ endif
+
+ # Build calculation based on column type
+ if calculate_grid_column
+ # Grid column calculation - includes image gap
+ assign medium_base = '([medium_base]) / 2' | replace: '[medium_base]', medium_base
+ # Build the complete large size expression
+ assign large_size_expr = '([large_size_base]) / 2 - [image_gap_half]' | replace: '[large_size_base]', large_size_base | replace: '[image_gap_half]', image_gap_half
+ assign large_size = 'calc([large_size_expr])' | replace: '[large_size_expr]', large_size_expr
+
+ if block_settings.extend_media
+ assign medium_size = 'calc([medium_base] - [page_margin] - [gap_quarter] - [image_gap_half] + [page_margin])' | replace: '[medium_base]', medium_base | replace: '[page_margin]', page_margin | replace: '[gap_quarter]', gap_quarter | replace: '[image_gap_half]', image_gap_half
+ else
+ assign medium_size = 'calc([medium_base] - [page_margin] - [gap_quarter] - [image_gap_half])' | replace: '[medium_base]', medium_base | replace: '[page_margin]', page_margin | replace: '[gap_quarter]', gap_quarter | replace: '[image_gap_half]', image_gap_half
+ endif
+ assign sizes = '(min-width: [breakpoint]) [large_size], (min-width: 750px) [medium_size], 100vw' | replace: '[breakpoint]', breakpoint | replace: '[large_size]', large_size | replace: '[medium_size]', medium_size
+ else
+ # Single column calculation
+ if block_settings.extend_media
+ assign large_size = 'calc([large_size_base])' | replace: '[large_size_base]', large_size_base
+ else
+ assign large_size = large_size_base
+ endif
+
+ if block_settings.extend_media
+ assign medium_size = 'calc([medium_base] - [page_margin] - [gap_half])' | replace: '[medium_base]', medium_base | replace: '[page_margin]', page_margin | replace: '[gap_half]', gap_half
+ else
+ assign medium_size = 'calc([medium_base] - [page_margin] - [gap_half] - [page_margin])' | replace: '[medium_base]', medium_base | replace: '[page_margin]', page_margin | replace: '[gap_half]', gap_half
+ endif
+ assign sizes = '(min-width: [breakpoint]) [large_size], (min-width: 750px) [medium_size], 100vw' | replace: '[breakpoint]', breakpoint | replace: '[large_size]', large_size | replace: '[medium_size]', medium_size
+ endif
+ else
+ # Use default sizes
+ assign sizes = default_sizes
+ endif
+
+ # Echo the sizes attribute
+ echo sizes
+-%}
diff --git a/snippets/variant-main-picker.liquid b/snippets/variant-main-picker.liquid
new file mode 100644
index 000000000..b29424a74
--- /dev/null
+++ b/snippets/variant-main-picker.liquid
@@ -0,0 +1,512 @@
+{%- doc -%}
+ Renders a default variant picker, used to display the variant picker in the variants block.
+
+ @param {object} product_resource - The product object.
+ @param {object} [block] - The block object
+{%- enddoc -%}
+
+{% assign block_settings = block.settings %}
+
+{% unless product_resource.has_only_default_variant %}
+ {% liquid
+ assign button_background_brightness = section.settings.color_scheme.settings.foreground | color_brightness
+ if button_background_brightness < 105
+ assign strikethrough_color_mix = '#000'
+ else
+ assign strikethrough_color_mix = '#fff'
+ endif
+ %}
+
+
+
+{% endunless %}
+
+{% stylesheet %}
+ .variant-picker {
+ width: 100%;
+ }
+
+ .variant-picker__form {
+ display: flex;
+ flex-direction: column;
+ gap: var(--padding-lg);
+ width: 100%;
+ }
+
+ .variant-picker[data-shopify-visual-preview] {
+ min-width: 300px;
+ padding-inline-start: max(4px, var(--padding-inline-start));
+ }
+
+ .variant-option {
+ --options-border-radius: var(--variant-picker-button-radius);
+ --options-border-width: var(--variant-picker-button-border-width);
+ --variant-option-padding-inline: var(--padding-md);
+ }
+
+ .variant-option--swatches {
+ --options-border-radius: var(--variant-picker-swatch-radius);
+
+ width: 100%;
+ }
+
+ .variant-option--swatches-disabled {
+ pointer-events: none;
+ cursor: not-allowed;
+ }
+
+ .variant-option--swatches > overflow-list {
+ justify-content: var(--product-swatches-alignment);
+
+ @media (max-width: 749px) {
+ justify-content: var(--product-swatches-alignment-mobile);
+ }
+ }
+
+ .variant-option--buttons {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--gap-sm);
+ margin: 0;
+ padding: 0;
+ border: none;
+ }
+
+ .variant-option--buttons legend {
+ padding: 0;
+ margin-block-end: var(--margin-xs);
+ }
+
+ .variant-option__swatch-value {
+ padding-inline-start: var(--padding-xs);
+ color: rgb(var(--color-foreground-rgb) / var(--opacity-70));
+ }
+
+ .variant-option__button-label {
+ --variant-picker-stroke-color: var(--color-variant-border);
+
+ display: flex;
+ flex: 0 0 calc(3ch + 1.3em);
+ align-items: center;
+ position: relative;
+ padding-block: var(--padding-sm);
+ padding-inline: var(--padding-lg);
+ border: var(--style-border-width) solid var(--color-variant-border);
+ border-radius: var(--options-border-radius);
+ border-width: var(--options-border-width);
+ overflow: clip;
+ justify-content: center;
+ min-height: calc(3ch + 1.3em);
+ min-width: fit-content;
+ white-space: nowrap;
+ background-color: var(--color-variant-background);
+ color: var(--color-variant-text);
+ transition: background-color var(--animation-speed) var(--animation-easing),
+ border-color var(--animation-speed) var(--animation-easing);
+
+ &:hover {
+ background-color: var(--color-variant-hover-background);
+ border-color: var(--color-variant-hover-border);
+ color: var(--color-variant-hover-text);
+ }
+
+ @media screen and (min-width: 750px) {
+ padding: var(--padding-xs) var(--variant-option-padding-inline);
+ }
+ }
+
+ .variant-option__button-label__text {
+ text-align: left;
+ text-wrap: auto;
+ }
+
+ .variant-option--equal-width-buttons {
+ --variant-min-width: clamp(44px, calc(var(--variant-option-padding-inline) * 2 + var(--variant-ch)), 100%);
+
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(var(--variant-min-width), 1fr));
+
+ .variant-option__button-label {
+ min-width: var(--variant-min-width);
+ }
+
+ .variant-option__button-label__text {
+ text-align: center;
+ text-wrap: balance;
+ }
+ }
+
+ .variant-option__button-label:has(:focus-visible) {
+ --variant-picker-stroke-color: var(--color-foreground);
+
+ border-color: var(--color-foreground);
+ outline: var(--focus-outline-width) solid var(--color-foreground);
+ outline-offset: var(--focus-outline-offset);
+ }
+
+ .variant-option__button-label--has-swatch {
+ --focus-outline-radius: var(--variant-picker-swatch-radius);
+
+ padding: 0;
+ border: none;
+ display: block;
+ flex-basis: auto;
+ min-height: auto;
+ }
+
+ .variant-option__button-label:has(:checked) {
+ color: var(--color-selected-variant-text);
+ background-color: var(--color-selected-variant-background);
+ border-color: var(--color-selected-variant-border);
+ transition: background-color var(--animation-speed) var(--animation-easing),
+ border-color var(--animation-speed) var(--animation-easing);
+
+ &:hover {
+ background-color: var(--color-selected-variant-hover-background);
+ border-color: var(--color-selected-variant-hover-border);
+ color: var(--color-selected-variant-hover-text);
+ }
+ }
+
+ .variant-option__button-label:has([data-option-available='false']) {
+ color: rgb(var(--color-variant-text-rgb) / var(--opacity-60));
+ }
+
+ .facets__inputs-list--swatches-grid .variant-option__button-label--has-swatch:hover .swatch {
+ --focus-outline: var(--focus-outline-width) solid rgb(var(--color-foreground-rgb) / var(--opacity-35-55));
+
+ outline: var(--focus-outline);
+ outline-offset: var(--focus-outline-offset);
+ }
+
+ .facets__inputs-list--swatches-grid .variant-option__button-label:has(:focus-visible) .swatch {
+ --focus-outline: var(--focus-outline-width) solid currentcolor;
+
+ outline: var(--focus-outline);
+ outline-offset: var(--focus-outline-offset);
+ }
+
+ .facets__inputs-list--swatches-grid .variant-option__button-label:has(:focus-visible) {
+ outline: none;
+ }
+
+ .facets__inputs-list--swatches-grid .variant-option__button-label--has-swatch:hover {
+ outline: none;
+ }
+
+ .variant-option__button-label--has-swatch:hover {
+ outline: var(--focus-outline-width) solid rgb(var(--color-foreground-rgb) / var(--opacity-35-55));
+ outline-offset: var(--focus-outline-offset);
+ }
+
+ .facets__inputs-list--swatches-grid .variant-option__button-label--has-swatch:has(:checked) {
+ --focus-outline: none;
+ }
+
+ .facets__inputs-list--swatches-grid .variant-option__button-label--has-swatch:has(:checked) .swatch {
+ outline: var(--focus-outline);
+ outline-offset: var(--focus-outline-offset);
+ }
+
+ .variant-option__button-label--has-swatch:has(:checked) {
+ --focus-outline: var(--focus-outline-width) solid var(--color-foreground);
+
+ outline: var(--focus-outline);
+ outline-offset: var(--focus-outline-offset);
+ }
+
+ /* This triggers iOS < 16.4. The outline bug is not recognized as a lack of @supports */
+ @supports not (background-color: rgb(from red 150 g b / alpha)) {
+ /** There is a bug in safari < 16.4 that causes the outline to not follow the elements border radius. This is a workaround. **/
+ .variant-option__button-label--has-swatch:has(:checked),
+ .variant-option__button-label:has(:focus-visible) .swatch,
+ .facets__inputs-list--swatches-grid .variant-option__button-label--has-swatch:hover .swatch {
+ outline: none;
+ position: relative;
+ overflow: visible;
+ }
+
+ .variant-option__button-label--has-swatch:has(:checked)::after,
+ .variant-option__button-label:has(:focus-visible) .swatch::after,
+ .facets__inputs-list--swatches-grid .variant-option__button-label--has-swatch:hover .swatch::after {
+ content: '';
+ position: absolute;
+ inset: calc(-1 * var(--focus-outline-offset));
+ border: var(--focus-outline);
+ border-radius: var(--focus-outline-radius, 50%);
+ background-color: transparent;
+ display: inherit;
+ }
+ }
+
+ .variant-option__button-label:has([data-option-available='false']):has(:checked) {
+ --variant-picker-stroke-color: rgb(var(--color-variant-text-rgb) / var(--opacity-60));
+
+ background-color: inherit;
+ color: rgb(var(--color-variant-text-rgb) / var(--opacity-60));
+ border-color: var(--color-selected-variant-border);
+ }
+
+ .variant-option__button-label input,
+ .variant-option--images input {
+ /* remove the checkbox from the page flow */
+ position: absolute;
+
+ /* set the dimensions to match those of the label */
+ inset: 0;
+
+ /* hide it */
+ opacity: 0;
+ margin: 0;
+ cursor: pointer;
+ width: 100%;
+ height: 100%;
+ }
+
+ .variant-option__button-label svg {
+ position: absolute;
+ top: 0;
+ left: 0;
+ cursor: pointer;
+ pointer-events: none;
+ stroke-width: var(--style-border-width);
+ stroke: var(--variant-picker-stroke-color);
+ }
+
+ .variant-option__select-wrapper {
+ display: flex;
+ position: relative;
+ border: var(--style-border-width-inputs) solid var(--color-border);
+ border-radius: var(--style-border-radius-inputs);
+ align-items: center;
+ margin-top: var(--margin-2xs);
+ overflow: clip;
+ transition: background-color var(--animation-speed) var(--animation-easing),
+ border-color var(--animation-speed) var(--animation-easing);
+ }
+
+ .variant-option__select-wrapper:has(.swatch) {
+ --variant-picker-swatch-width: 20px;
+ --variant-picker-swatch-height: 20px;
+ }
+
+ .variant-option__select-wrapper:hover {
+ border-color: var(--color-variant-hover-border);
+ }
+
+ .variant-option__select:focus-visible {
+ outline: var(--focus-outline-width) solid currentcolor;
+ outline-offset: var(--focus-outline-offset);
+ }
+
+ .variant-option__select {
+ padding-block: var(--padding-md);
+ padding-inline: var(--padding-lg) calc(var(--padding-lg) + var(--icon-size-2xs));
+ appearance: none;
+ border: 0;
+ width: 100%;
+ margin: 0;
+ cursor: pointer;
+ }
+
+ .variant-option__select-wrapper .icon {
+ position: absolute;
+ right: var(--padding-md);
+ top: 50%;
+ transform: translateY(-50%);
+ width: var(--icon-size-2xs);
+ height: var(--icon-size-2xs);
+ pointer-events: none;
+ }
+
+ .variant-option__select--has-swatch {
+ padding-inline-start: calc((2 * var(--padding-sm)) + var(--variant-picker-swatch-width));
+ }
+
+ .variant-option__select-wrapper .swatch {
+ position: absolute;
+ top: 50%;
+ left: var(--padding-md);
+ transform: translateY(-50%);
+ }
+
+ .variant-picker--center,
+ .variant-picker--center .variant-option {
+ text-align: center;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ }
+
+ .variant-picker--right,
+ .variant-picker--right .variant-option {
+ text-align: right;
+ justify-content: right;
+ }
+{% endstylesheet %}
diff --git a/snippets/variant-quick-add.liquid b/snippets/variant-quick-add.liquid
new file mode 100644
index 000000000..d67f086ad
--- /dev/null
+++ b/snippets/variant-quick-add.liquid
@@ -0,0 +1,101 @@
+{%- doc -%}
+ Renders a quick-add variant picker, used to display the variant picker in the quick-add modal.
+
+ @param {object} product_resource - The product object.
+{%- enddoc -%}
+
+
+ {%- for product_option in product_resource.options_with_values -%}
+ {%- liquid
+ assign swatch_count = product_option.values | map: 'swatch' | compact | size
+ assign variant_style = ''
+
+ if swatch_count > 0
+ assign variant_style = 'swatch'
+ else
+ assign fieldset_id = section.id | append: '-' | append: product_resource.id | append: '-' | append: product_option.name | handleize
+ assign option_id_attribute = 'data-option-id="' | append: fieldset_id | append: '"'
+ assign longest_value = 0
+ endif
+ -%}
+
+
+
+ {{ product_option.name | escape -}}
+ {%- if variant_style == 'swatch' and product_resource.options_with_values.size > 1 -%}
+ {{ product_option.selected_value }}
+ {%- endif %}
+
+ {%- for product_option_value in product_option.values -%}
+ {% if product_option_value.size > longest_value and option_id_attribute %}
+ {% assign longest_value = product_option_value.size %}
+ {% endif %}
+
+ {% liquid
+ assign featured_media = product_option_value.variant.featured_media
+
+ # If the variant has no featured media, and we have a combined listing product, then fall back to using the
+ # featured media of the child product that is linked to this option value.
+ if featured_media == blank and product_option_value.product_url
+ assign featured_media = product_option_value.variant.product.featured_media
+ endif
+ %}
+
+
+
+ {% if variant_style == 'swatch' %}
+ {% render 'swatch', swatch: product_option_value.swatch, variant_image: featured_media %}
+ {% else %}
+ {{ product_option_value | escape }}
+ {% endif %}
+ {% render 'strikethrough-variant', product_option: product_option_value %}
+
+ {%- endfor -%}
+ {% if option_id_attribute %}
+ {% style %}
+ [data-option-id="{{ fieldset_id }}"] {
+ --variant-ch: {{ longest_value }}ch;
+ }
+ {% endstyle %}
+ {% endif %}
+
+ {%- endfor -%}
+
+
+
diff --git a/snippets/variant-swatches.liquid b/snippets/variant-swatches.liquid
new file mode 100644
index 000000000..6380efaf1
--- /dev/null
+++ b/snippets/variant-swatches.liquid
@@ -0,0 +1,165 @@
+{%- doc -%}
+ Renders a swatches variant picker, used within the product-swatches block.
+
+ @param {object} product_resource - The product object, which contains variants and options.
+ @param {boolean} [has_option_selected] - Whether an option is already selected.
+
+ @example
+ {% render 'variant-swatches', product_resource: product %}
+{%- enddoc -%}
+
+
+
+
diff --git a/snippets/video.liquid b/snippets/video.liquid
new file mode 100644
index 000000000..36e8a0fd9
--- /dev/null
+++ b/snippets/video.liquid
@@ -0,0 +1,216 @@
+{%- doc -%}
+ Renders a video element, from a video object (
element) or a video URL (
{{- 'blogs.comment_form.heading' | t -}}
- - {%- if form.errors -%} - - -- {%- for field in form.errors -%} --
- {%- if form.errors.translated_fields[field] contains 'author' -%}
-
- {{- 'blogs.comment_form.name' | t -}}
-
- {%- elsif form.errors.translated_fields[field] contains 'body' -%}
-
- {{- 'blogs.comment_form.message' | t -}}
-
- {%- else -%}
-
- {{- form.errors.translated_fields[field] | capitalize -}}
-
- {%- endif -%}
- {{ form.errors.messages[field] }}
-
- {%- endfor -%}
-
- {%- elsif form.posted_successfully? -%} - - {%- endif -%} - -- {{- 'blogs.comment_form.moderated' | t -}} -
- {% endif %} - - -