← All sections

Spotlight Bento

A bento of trust cards lit by one moving light, so every reassurance gets read.

FreeTrust & guarantees40 settingsInstall
Full screen ↗

Install

One file: sections/mf-spotlight-bento.liquid. It appears in the theme editor as EX · Spotlight bento.

  1. Connect EXPERAISE Sections to Claude (once). In Claude Code:
    terminal
    claude mcp add --transport http experaise-sections https://sections.experaise.com/api/mcp
    In the Claude app: Settings → Connectors → Add custom connector → https://sections.experaise.com/api/mcp. Full setup
  2. Ask Claude. It fetches sections/mf-spotlight-bento.liquid, pushes only that file to your theme with Shopify CLI, and tells you where to find it.
    prompt
    Install the EXPERAISE Sections section "Spotlight Bento" (spotlight-bento) on my Shopify store your-store.myshopify.com. Put it on an unpublished copy of my live theme, then tell me how to add it in the theme editor.
  3. Customize. Online Store → Themes → Customize → Add section → EX · Spotlight bento. Every text, color and product is a setting.
sections/mf-spotlight-bento.liquidDownload
{%- liquid
  assign s = section.settings
  assign heading_tag = s.heading_tag | default: 'h2'
  assign policy_link = s.link_url | default: '/policies/refund-policy'
-%}

<mf-spotlight-bento
  class="mf-bento mf-bento--{{ s.glow_style }} mf-bento--accent-{{ s.accent_style }}"
  data-follow="{{ s.glow_follow }}"
  style="--mf-bento-bg: {{ s.color_bg }}; --mf-bento-card: {{ s.color_card }}; --mf-bento-fg: {{ s.color_text }}; --mf-bento-accent: {{ s.color_accent }}; --mf-bento-pt: {{ s.padding_top }}px; --mf-bento-pb: {{ s.padding_bottom }}px; --mf-bento-cols: {{ s.columns }}; --mf-bento-row: {{ s.row_height }}px; --mf-bento-gap: {{ s.gap }}px; --mf-bento-radius: {{ s.card_radius }}px; --mf-bento-bw: {{ s.border_width }}px; --mf-bento-glow: {{ s.glow_size }}px;"
>
  <div class="mf-bento__backdrop" aria-hidden="true"></div>

  <div class="mf-bento__inner">
    <header class="mf-bento__head">
      <div class="mf-bento__intro">
        {%- if s.eyebrow != blank -%}
          <p class="mf-bento__eyebrow"><i aria-hidden="true"></i>{{ s.eyebrow | escape }}</p>
        {%- endif -%}
        <{{ heading_tag }} class="mf-bento__title">
          {{- s.heading -}}
          {%- if s.heading_accent != blank %} <span class="mf-bento__accent">{{ s.heading_accent }}</span>{% endif -%}
        </{{ heading_tag }}>
      </div>
      {%- if s.subheading != blank or s.link_label != blank -%}
        <div class="mf-bento__aside">
          {%- if s.subheading != blank -%}
            <div class="mf-bento__sub">{{ s.subheading }}</div>
          {%- endif -%}
          {%- if s.link_label != blank -%}
            <a class="mf-bento__link" href="{{ policy_link }}">{{ s.link_label | escape }} <span aria-hidden="true">→</span></a>
          {%- endif -%}
        </div>
      {%- endif -%}
    </header>

    <div class="mf-bento__stage">
    <span class="mf-bento__halo" aria-hidden="true"><i></i></span>
    <ul class="mf-bento__grid" role="list">
      {%- for block in section.blocks -%}
        {%- assign b = block.settings -%}
        {%- case block.type -%}
          {%- when 'product' -%}
            {%- liquid
              assign p = b.product
              assign variant = p.selected_or_first_available_variant
              assign media = p.featured_media
              if b.image == 'second' and p.media.size > 1
                assign media = p.media[1]
              endif
              assign p_title = p.title | default: b.title
              assign p_url = p.url | default: routes.all_products_collection_url
              assign rating = p.metafields.reviews.rating.value
              assign rating_count = p.metafields.reviews.rating_count.value | plus: 0
              assign count_label = rating_count
              if rating_count >= 1000
                assign thousands = rating_count | divided_by: 1000
                assign rest = rating_count | modulo: 1000 | prepend: '00' | slice: -3, 3
                assign count_label = thousands | append: ',' | append: rest
              endif
              assign form_id = 'mf-bento-form-' | append: section.id | append: '-' | append: block.id
            -%}
            <li class="mf-bento__card mf-bento__card--product mf-bento__card--{{ b.size }}" style="--i: {{ forloop.index0 }};" {{ block.shopify_attributes }}>
              <span class="mf-bento__ring" aria-hidden="true"><span class="mf-bento__blob"><i></i></span></span>
              <div class="mf-bento__face">
                <span class="mf-bento__spot" aria-hidden="true"></span>
                <div class="mf-bento__visual">
                  {%- if media != blank -%}
                    {{
                      media
                      | image_url: width: 1100
                      | image_tag:
                        loading: 'lazy',
                        alt: p.title,
                        sizes: '(min-width: 990px) 26vw, (min-width: 750px) 46vw, 92vw',
                        widths: '360, 540, 720, 900, 1100',
                        class: 'mf-bento__pimg'
                    }}
                  {%- else -%}
                    <span class="mf-bento__art" aria-hidden="true"><span class="mf-bento__bottle"></span></span>
                  {%- endif -%}
                  {%- if b.badge != blank -%}
                    <span class="mf-bento__chip"><i aria-hidden="true"></i>{{ b.badge | escape }}</span>
                  {%- endif -%}
                </div>
                <div class="mf-bento__pcopy">
                  {%- if b.label != blank -%}
                    <p class="mf-bento__tag">{{ b.label | escape }}</p>
                  {%- endif -%}
                  <h3 class="mf-bento__ptitle"><a href="{{ p_url }}">{{ p_title | escape }}</a></h3>
                  {%- if rating != blank -%}
                    <p class="mf-bento__rating">
                      <span class="mf-bento__stars" aria-hidden="true">★★★★★</span>
                      <span>{{ rating.rating }} / {{ rating.scale_max }}{% if rating_count > 0 %} · {{ count_label }} {{ b.reviews_label | escape }}{% endif %}</span>
                    </p>
                  {%- endif -%}
                  {%- if b.text != blank -%}
                    <p class="mf-bento__ptext">{{ b.text | escape }}</p>
                  {%- endif -%}
                  <div class="mf-bento__buy">
                    {%- if p != blank -%}
                      <p class="mf-bento__price">
                        <span class="mf-bento__now">{{ variant.price | money }}</span>
                        {%- if variant.compare_at_price > variant.price -%}
                          {%- assign saved = variant.compare_at_price | minus: variant.price | times: 100 | divided_by: variant.compare_at_price -%}
                          <s class="mf-bento__was">{{ variant.compare_at_price | money }}</s>
                          <span class="mf-bento__save">−{{ saved }}%</span>
                        {%- endif -%}
                      </p>
                      <div class="mf-bento__actions">
                        {%- if b.button_label != blank -%}
                          {%- form 'product', p, id: form_id, class: 'mf-bento__form', data-mf-bento-add: '' -%}
                            <input type="hidden" name="id" value="{{ variant.id }}">
                            <input type="hidden" name="quantity" value="1">
                            <button
                              type="submit"
                              class="mf-bento__button"
                              data-added="{{ b.added_label | escape }}"
                              {% unless variant.available %}
                                disabled
                              {% endunless %}
                            >
                              <span class="mf-bento__label">
                                {%- if variant.available -%}{{ b.button_label | escape }}{%- else -%}{{ b.soldout_label | escape }}{%- endif -%}
                              </span>
                              <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
                            </button>
                            <span class="mf-bento__status" role="status" aria-live="polite"></span>
                          {%- endform -%}
                        {%- endif -%}
                        {%- if b.link_label != blank -%}
                          <a class="mf-bento__more" href="{{ p_url }}">{{ b.link_label | escape }}</a>
                        {%- endif -%}
                      </div>
                    {%- elsif b.link_label != blank -%}
                      <div class="mf-bento__actions">
                        <a class="mf-bento__button" href="{{ p_url }}">
                          <span class="mf-bento__label">{{ b.link_label | escape }}</span>
                          <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
                        </a>
                      </div>
                    {%- endif -%}
                  </div>
                </div>
              </div>
            </li>

          {%- when 'benefit' -%}
            {%- capture icon -%}
              {%- case b.icon -%}
                {%- when 'truck' -%}
                  <path d="M2.8 6.2h11v9.6h-11z"/><path d="M13.8 9.4h3.9l3.5 3.6v2.8h-7.4"/><circle cx="7" cy="17.4" r="1.9"/><circle cx="17.2" cy="17.4" r="1.9"/>
                {%- when 'return' -%}
                  <path d="M4.2 12.4a7.8 7.8 0 1 0 2.3-5.8"/><path d="M4.4 3.8v4.6H9"/><path d="M12 8.2v4.2l2.8 1.8"/>
                {%- when 'shield' -%}
                  <path d="M12 2.9l7.6 3v5.6c0 4.6-3.2 8.3-7.6 9.6-4.4-1.3-7.6-5-7.6-9.6V5.9z"/><path d="M8.7 12.1l2.3 2.3 4.4-4.7"/>
                {%- when 'star' -%}
                  <path d="M12 3.4l2.7 5.4 5.9.9-4.3 4.2 1 5.9L12 17l-5.3 2.8 1-5.9-4.3-4.2 5.9-.9z"/>
                {%- when 'lock' -%}
                  <rect x="4.6" y="10.4" width="14.8" height="10.2" rx="2.6"/><path d="M8 10.4V7.6a4 4 0 0 1 8 0v2.8"/><path d="M12 14.4v2.4"/>
                {%- when 'leaf' -%}
                  <path d="M5 19.4C5 10.6 10.6 4.8 20 4.8c0 9.6-5.8 15-14.2 15"/><path d="M5 19.4l7.6-7.6"/>
                {%- when 'chat' -%}
                  <path d="M4.4 6.6A2.6 2.6 0 0 1 7 4h10a2.6 2.6 0 0 1 2.6 2.6v7.2A2.6 2.6 0 0 1 17 16.4h-5.6l-4.8 3.6v-3.6A2.2 2.2 0 0 1 4.4 14.2z"/><path d="M8.6 9.2h6.8M8.6 12.2h4.2"/>
                {%- else -%}
                  <rect x="3.6" y="8.4" width="16.8" height="4.2" rx="1.1"/><path d="M5.2 12.6v7.8h13.6v-7.8"/><path d="M12 8.4v12"/><path d="M12 8.4C10.6 4.9 6.6 4.4 6.6 6.8c0 1.5 2.4 1.6 5.4 1.6zM12 8.4c1.4-3.5 5.4-4 5.4-1.6 0 1.5-2.4 1.6-5.4 1.6z"/>
              {%- endcase -%}
            {%- endcapture -%}
            <li class="mf-bento__card mf-bento__card--benefit mf-bento__card--{{ b.size }}{% if b.stat != blank %} mf-bento__card--stat{% endif %}" style="--i: {{ forloop.index0 }};" {{ block.shopify_attributes }}>
              <span class="mf-bento__ring" aria-hidden="true"><span class="mf-bento__blob"><i></i></span></span>
              <div class="mf-bento__face">
                <span class="mf-bento__spot" aria-hidden="true"></span>
                <svg class="mf-bento__mark" viewBox="0 0 24 24" aria-hidden="true" focusable="false">{{ icon }}</svg>
                <span class="mf-bento__icon" aria-hidden="true">
                  <svg viewBox="0 0 24 24" focusable="false">{{ icon }}</svg>
                </span>
                <div class="mf-bento__body">
                  {%- if b.stat != blank -%}
                    <p class="mf-bento__stat">{{ b.stat | escape }}</p>
                  {%- endif -%}
                  <div class="mf-bento__words">
                    {%- if b.title != blank -%}
                      <h3 class="mf-bento__ctitle">
                        {%- if b.link != blank -%}
                          <a class="mf-bento__stretch" href="{{ b.link }}">{{ b.title | escape }}</a>
                        {%- else -%}
                          {{ b.title | escape }}
                        {%- endif -%}
                      </h3>
                    {%- endif -%}
                    {%- if b.text != blank -%}
                      <p class="mf-bento__ctext">{{ b.text | escape }}</p>
                    {%- endif -%}
                  </div>
                </div>
              </div>
            </li>
        {%- endcase -%}
      {%- endfor -%}
    </ul>
    </div>
  </div>
</mf-spotlight-bento>

{% stylesheet %}
  /* Spotlight bento. One shared light source travels over the grid: every card
     carries a masked 1-3px ring (mask-composite exclude) holding a spinning
     conic blob that is translated to the pointer position in that card's own
     coordinates, so neighbouring borders light up together as the light passes
     between them. Positions are set as --mx/--my per card by the element; the
     blob only ever moves with transform. Without JS or with reduced motion,
     each ring shows a static lit corner instead. */

  .mf-bento {
    --mf-bento-c1: #ff6fb5;
    --mf-bento-c2: #ffb35c;
    --mf-bento-c3: #6ff0c0;
    --mf-bento-c4: #6a9bff;
    position: relative;
    isolation: isolate;
    display: block;
    overflow: hidden;
    padding: var(--mf-bento-pt, 88px) 0 var(--mf-bento-pb, 88px);
    background: var(--mf-bento-bg, #07080b);
    color: var(--mf-bento-fg, #f4f2ee);
    font-family: inherit;
  }
  .mf-bento--accent {
    --mf-bento-c1: var(--mf-bento-accent);
    --mf-bento-c2: color-mix(in srgb, var(--mf-bento-accent) 55%, #ffffff);
    --mf-bento-c3: var(--mf-bento-accent);
    --mf-bento-c4: color-mix(in srgb, var(--mf-bento-accent) 70%, #000000);
  }
  .mf-bento *,
  .mf-bento *::before,
  .mf-bento *::after {
    box-sizing: border-box;
  }

  /* Atmosphere: two low, soft spectrum pools, a fading hairline grid and grain. */
  .mf-bento__backdrop {
    position: absolute;
    z-index: -1;
    inset: 0;
    pointer-events: none;
    background:
      radial-gradient(42% 38% at 18% 0%, color-mix(in srgb, var(--mf-bento-c4) 16%, transparent), transparent 70%),
      radial-gradient(36% 34% at 86% 8%, color-mix(in srgb, var(--mf-bento-c1) 11%, transparent), transparent 70%),
      radial-gradient(50% 40% at 50% 100%, color-mix(in srgb, var(--mf-bento-c3) 7%, transparent), transparent 75%);
  }
  .mf-bento__backdrop::before {
    content: "";
    position: absolute;
    inset: 0;
    background:
      linear-gradient(color-mix(in srgb, var(--mf-bento-fg) 5%, transparent) 1px, transparent 1px),
      linear-gradient(90deg, color-mix(in srgb, var(--mf-bento-fg) 5%, transparent) 1px, transparent 1px);
    background-size: 64px 64px;
    background-position: center top;
    -webkit-mask-image: radial-gradient(70% 55% at 50% 0%, #000, transparent 75%);
    mask-image: radial-gradient(70% 55% at 50% 0%, #000, transparent 75%);
    opacity: 0.7;
  }
  .mf-bento__backdrop::after {
    content: "";
    position: absolute;
    inset: 0;
    opacity: 0.16;
    background-image: radial-gradient(color-mix(in srgb, var(--mf-bento-fg) 90%, transparent) 0.5px, transparent 0.8px);
    background-size: 4px 4px;
    mix-blend-mode: soft-light;
  }

  .mf-bento__inner {
    position: relative;
    z-index: 1;
    width: min(100% - 40px, 1240px);
    margin: 0 auto;
  }

  /* Header */
  .mf-bento__head {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.65fr);
    align-items: end;
    gap: clamp(24px, 4vw, 64px);
    margin: 0 0 clamp(32px, 4vw, 52px);
  }
  .mf-bento__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 22px;
    padding: 7px 14px 7px 11px;
    border: 1px solid color-mix(in srgb, var(--mf-bento-fg) 12%, transparent);
    border-radius: 999px;
    background: color-mix(in srgb, var(--mf-bento-fg) 4%, transparent);
    color: color-mix(in srgb, var(--mf-bento-fg) 82%, transparent);
    font: 500 11px/1.3 ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: 0.16em;
    text-transform: uppercase;
  }
  .mf-bento__eyebrow i {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--mf-bento-accent);
    box-shadow: 0 0 12px var(--mf-bento-accent);
  }
  .mf-bento__title {
    margin: 0;
    max-width: 15ch;
    color: var(--mf-bento-fg);
    font-family: inherit;
    font-size: clamp(38px, 5.6vw, 76px);
    font-weight: 600;
    line-height: 0.98;
    letter-spacing: -0.045em;
    text-transform: none;
    text-wrap: balance;
  }
  .mf-bento__accent {
    display: inline;
  }
  .mf-bento--accent-plain .mf-bento__accent {
    color: color-mix(in srgb, var(--mf-bento-fg) 48%, transparent);
  }
  .mf-bento--accent-serif .mf-bento__accent {
    font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
    font-style: italic;
    font-weight: 400;
    letter-spacing: -0.03em;
  }
  .mf-bento--accent-gradient .mf-bento__accent {
    font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
    font-style: italic;
    font-weight: 400;
    letter-spacing: -0.03em;
    padding-right: 0.06em;
    color: transparent;
    background: linear-gradient(95deg, var(--mf-bento-c4) 0%, var(--mf-bento-c3) 32%, var(--mf-bento-c2) 64%, var(--mf-bento-c1) 100%);
    -webkit-background-clip: text;
    background-clip: text;
  }
  .mf-bento__aside {
    display: grid;
    justify-items: start;
    gap: 18px;
    padding-bottom: 6px;
  }
  .mf-bento__sub {
    max-width: 40ch;
    color: color-mix(in srgb, var(--mf-bento-fg) 66%, transparent);
    font-size: 16px;
    line-height: 1.6;
    letter-spacing: 0;
  }
  .mf-bento__sub p {
    margin: 0;
    color: inherit;
    font-size: inherit;
    line-height: inherit;
  }
  .mf-bento__link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 40px;
    color: var(--mf-bento-fg);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0;
    text-decoration: underline;
    text-decoration-color: color-mix(in srgb, var(--mf-bento-fg) 30%, transparent);
    text-underline-offset: 6px;
  }
  .mf-bento__link span {
    transition: transform 0.2s ease;
  }
  .mf-bento__link:hover {
    text-decoration-color: currentColor;
  }
  .mf-bento__link:hover span {
    transform: translateX(3px);
  }

  /* Grid. The halo is one soft light under the cards: it only shows in the
     gaps and around the edges, like light leaking from behind the grid. */
  .mf-bento__stage {
    position: relative;
  }
  .mf-bento__halo {
    position: absolute;
    z-index: 0;
    top: 0;
    left: 0;
    width: calc(var(--mf-bento-glow, 240px) * 2.4);
    height: calc(var(--mf-bento-glow, 240px) * 2.4);
    margin: calc(var(--mf-bento-glow, 240px) * -1.2) 0 0 calc(var(--mf-bento-glow, 240px) * -1.2);
    border-radius: 50%;
    opacity: 0;
    pointer-events: none;
    transform: translate3d(var(--mf-bento-hx, 50%), var(--mf-bento-hy, 0px), 0);
    transition: opacity 0.6s ease;
    -webkit-mask-image: radial-gradient(closest-side, #000 0%, rgba(0, 0, 0, 0.55) 40%, transparent 100%);
    mask-image: radial-gradient(closest-side, #000 0%, rgba(0, 0, 0, 0.55) 40%, transparent 100%);
  }
  .mf-bento__halo i {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: conic-gradient(from 90deg, var(--mf-bento-c1), var(--mf-bento-c2), var(--mf-bento-c3), var(--mf-bento-c4), var(--mf-bento-c1));
    animation: mf-bento-spin 9s linear infinite reverse;
  }
  .mf-bento.is-on .mf-bento__halo {
    opacity: 1;
  }
  .mf-bento__grid {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: repeat(var(--mf-bento-cols, 4), minmax(0, 1fr));
    grid-auto-rows: minmax(var(--mf-bento-row, 196px), auto);
    grid-auto-flow: dense;
    gap: var(--mf-bento-gap, 14px);
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .mf-bento__card {
    --mx: 100cqw;
    --my: 0px;
    position: relative;
    min-width: 0;
    margin: 0;
    padding: 0;
    border-radius: var(--mf-bento-radius, 22px);
    container-type: inline-size;
  }
  .mf-bento__card--wide {
    grid-column: span 2;
  }
  .mf-bento__card--tall {
    grid-row: span 2;
  }
  .mf-bento__card--large {
    grid-column: span 2;
    grid-row: span 2;
  }

  .mf-bento__face {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 14px;
    height: 100%;
    padding: clamp(20px, 1.9vw, 24px);
    overflow: hidden;
    border: 1px solid color-mix(in srgb, var(--mf-bento-fg) 8%, transparent);
    border-radius: inherit;
    background:
      radial-gradient(120% 90% at 0% 0%, color-mix(in srgb, var(--mf-bento-fg) 5%, transparent), transparent 55%),
      linear-gradient(180deg, color-mix(in srgb, var(--mf-bento-card) 92%, var(--mf-bento-fg)), var(--mf-bento-card) 40%);
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, var(--mf-bento-fg) 7%, transparent),
      0 30px 60px -36px rgba(0, 0, 0, 0.9);
  }
  .mf-bento__face > :not(.mf-bento__spot):not(.mf-bento__mark) {
    position: relative;
    z-index: 1;
  }

  /* The masked border ring and its light. */
  .mf-bento__ring {
    position: absolute;
    z-index: 3;
    inset: 0;
    padding: var(--mf-bento-bw, 2px);
    overflow: hidden;
    border-radius: inherit;
    pointer-events: none;
    -webkit-mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
    -webkit-mask-clip: content-box, border-box;
    -webkit-mask-composite: xor;
    mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
    mask-clip: content-box, border-box;
    mask-composite: exclude;
  }
  .mf-bento__ring::before {
    content: "";
    position: absolute;
    inset: 0;
    background: conic-gradient(from 200deg at var(--mf-bento-rx, 100%) var(--mf-bento-ry, 0%), var(--mf-bento-c4), var(--mf-bento-c3), var(--mf-bento-c2), var(--mf-bento-c1), var(--mf-bento-c4));
    -webkit-mask-image: radial-gradient(circle var(--mf-bento-glow, 240px) at var(--mf-bento-rx, 100%) var(--mf-bento-ry, 0%), #000 0%, rgba(0, 0, 0, 0.35) 45%, transparent 80%);
    mask-image: radial-gradient(circle var(--mf-bento-glow, 240px) at var(--mf-bento-rx, 100%) var(--mf-bento-ry, 0%), #000 0%, rgba(0, 0, 0, 0.35) 45%, transparent 80%);
    opacity: 0.85;
    transition: opacity 0.6s ease;
  }
  .mf-bento__card:nth-child(even) .mf-bento__ring::before {
    --mf-bento-rx: 0%;
    --mf-bento-ry: 100%;
  }
  .mf-bento__blob {
    position: absolute;
    top: 0;
    left: 0;
    width: calc(var(--mf-bento-glow, 240px) * 2);
    height: calc(var(--mf-bento-glow, 240px) * 2);
    margin: calc(var(--mf-bento-glow, 240px) * -1) 0 0 calc(var(--mf-bento-glow, 240px) * -1);
    border-radius: 50%;
    opacity: 0;
    transform: translate3d(var(--mx), var(--my), 0);
    transition: opacity 0.5s ease;
    -webkit-mask-image: radial-gradient(closest-side, #000 0%, #000 42%, rgba(0, 0, 0, 0.6) 68%, transparent 100%);
    mask-image: radial-gradient(closest-side, #000 0%, #000 42%, rgba(0, 0, 0, 0.6) 68%, transparent 100%);
    will-change: transform;
  }
  .mf-bento__blob i {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: conic-gradient(from 0deg, var(--mf-bento-c1), var(--mf-bento-c2), var(--mf-bento-c3), var(--mf-bento-c4), var(--mf-bento-c1));
    animation: mf-bento-spin 7s linear infinite;
  }
  .mf-bento.is-instant .mf-bento__blob,
  .mf-bento.is-instant .mf-bento__halo,
  .mf-bento.is-instant .mf-bento__ring::before {
    transition: none;
  }
  .mf-bento.is-on .mf-bento__blob {
    opacity: 1;
  }
  .mf-bento.is-on .mf-bento__ring::before {
    opacity: 0.12;
  }

  /* Inner spotlight on the card under the light. */
  .mf-bento__spot {
    position: absolute;
    z-index: 0;
    top: 0;
    left: 0;
    width: calc(var(--mf-bento-glow, 240px) * 2.6);
    height: calc(var(--mf-bento-glow, 240px) * 2.6);
    margin: calc(var(--mf-bento-glow, 240px) * -1.3) 0 0 calc(var(--mf-bento-glow, 240px) * -1.3);
    border-radius: 50%;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--mf-bento-fg) 13%, transparent), color-mix(in srgb, var(--mf-bento-c4) 13%, transparent) 36%, color-mix(in srgb, var(--mf-bento-c1) 6%, transparent) 62%, transparent 100%);
    opacity: 0;
    transform: translate3d(var(--mx), var(--my), 0);
    transition: opacity 0.45s ease;
    pointer-events: none;
  }
  .mf-bento.is-on .mf-bento__card.is-lit .mf-bento__spot {
    opacity: 1;
  }

  /* Benefit cards */
  .mf-bento__icon {
    display: grid;
    flex: none;
    place-items: center;
    width: 42px;
    height: 42px;
    border: 1px solid color-mix(in srgb, var(--mf-bento-fg) 12%, transparent);
    border-radius: 12px;
    background: linear-gradient(180deg, color-mix(in srgb, var(--mf-bento-fg) 10%, transparent), color-mix(in srgb, var(--mf-bento-fg) 2%, transparent));
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, var(--mf-bento-fg) 16%, transparent),
      0 10px 24px -12px rgba(0, 0, 0, 0.9);
    color: var(--mf-bento-fg);
  }
  .mf-bento__icon svg,
  .mf-bento__mark {
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  .mf-bento__icon svg {
    width: 22px;
    height: 22px;
  }
  .mf-bento__mark {
    display: none;
    position: absolute;
    z-index: 0;
    right: -18px;
    bottom: -26px;
    width: clamp(150px, 15vw, 210px);
    height: clamp(150px, 15vw, 210px);
    color: var(--mf-bento-fg);
    opacity: 0.045;
    stroke-width: 0.9;
    pointer-events: none;
  }
  .mf-bento__card--wide .mf-bento__mark,
  .mf-bento__card--tall .mf-bento__mark {
    display: block;
  }
  .mf-bento__body {
    display: grid;
    gap: 10px;
    margin-top: auto;
  }
  .mf-bento__stat {
    margin: 0;
    padding-bottom: 0.06em;
    color: transparent;
    background: linear-gradient(180deg, var(--mf-bento-fg) 30%, color-mix(in srgb, var(--mf-bento-fg) 52%, transparent));
    -webkit-background-clip: text;
    background-clip: text;
    font-size: clamp(32px, 3.2vw, 44px);
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.05em;
    text-transform: none;
    font-variant-numeric: tabular-nums;
  }
  .mf-bento__words {
    display: grid;
    gap: 6px;
  }
  .mf-bento__ctitle {
    margin: 0;
    color: var(--mf-bento-fg);
    font-family: inherit;
    font-size: 16px;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -0.01em;
    text-transform: none;
  }
  .mf-bento__stretch {
    color: inherit;
    text-decoration: none;
  }
  .mf-bento__stretch::after {
    content: "";
    position: absolute;
    z-index: 4;
    inset: 0;
    border-radius: var(--mf-bento-radius, 22px);
  }
  .mf-bento__stretch:focus-visible {
    outline: none;
  }
  .mf-bento__stretch:focus-visible::after {
    outline: 2px solid var(--mf-bento-accent);
    outline-offset: 3px;
  }
  .mf-bento__ctext {
    max-width: 46ch;
    margin: 0;
    color: color-mix(in srgb, var(--mf-bento-fg) 62%, transparent);
    font-size: 14px;
    line-height: 1.55;
    letter-spacing: 0;
  }
  .mf-bento__card--wide.mf-bento__card--stat .mf-bento__body {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: end;
    column-gap: clamp(20px, 2.6vw, 36px);
  }
  .mf-bento__card--wide .mf-bento__stat,
  .mf-bento__card--tall .mf-bento__stat {
    font-size: clamp(46px, 5.2vw, 72px);
    letter-spacing: -0.06em;
  }
  .mf-bento__card--wide .mf-bento__stat {
    line-height: 0.86;
  }

  /* Product hero card */
  .mf-bento__card--product .mf-bento__face {
    flex-direction: row-reverse;
    gap: 0;
    padding: 0;
  }
  .mf-bento__pcopy {
    display: flex;
    flex: 1 1 46%;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
    padding: clamp(22px, 2.2vw, 30px);
  }
  .mf-bento__visual {
    position: relative;
    flex: 1 1 54%;
    min-width: 0;
    margin: 10px;
    overflow: hidden;
    border-radius: max(0px, calc(var(--mf-bento-radius, 22px) - 8px));
    background:
      radial-gradient(70% 60% at 50% 45%, color-mix(in srgb, var(--mf-bento-c2) 30%, transparent), transparent 70%),
      linear-gradient(160deg, color-mix(in srgb, var(--mf-bento-fg) 9%, var(--mf-bento-card)), var(--mf-bento-card));
  }
  .mf-bento__visual::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mf-bento-fg) 10%, transparent);
    background: linear-gradient(180deg, transparent 62%, rgba(0, 0, 0, 0.38));
    pointer-events: none;
  }
  .mf-bento__pimg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
  }
  .mf-bento__card--product:hover .mf-bento__pimg {
    transform: scale(1.04);
  }
  .mf-bento__art {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background:
      radial-gradient(40% 32% at 50% 56%, color-mix(in srgb, var(--mf-bento-c1) 38%, transparent), transparent 72%),
      radial-gradient(60% 45% at 50% 88%, rgba(0, 0, 0, 0.45), transparent 70%);
  }
  .mf-bento__bottle {
    position: relative;
    width: 30%;
    max-width: 130px;
    aspect-ratio: 0.56;
    margin-top: 12%;
    border-radius: 26% 26% 18% 18% / 16% 16% 10% 10%;
    background:
      linear-gradient(90deg, rgba(255, 255, 255, 0.22), transparent 22%, transparent 70%, rgba(0, 0, 0, 0.25)),
      linear-gradient(170deg, var(--mf-bento-c2), var(--mf-bento-c1) 55%, var(--mf-bento-c4));
    box-shadow: 0 40px 50px -22px rgba(0, 0, 0, 0.8), inset 0 0 0 1px rgba(255, 255, 255, 0.18);
  }
  .mf-bento__bottle::before {
    content: "";
    position: absolute;
    left: 32%;
    right: 32%;
    bottom: 100%;
    height: 34%;
    border-radius: 6px 6px 2px 2px;
    background: linear-gradient(90deg, #1a1b20, #3a3c45 45%, #121317);
  }
  .mf-bento__bottle::after {
    content: "";
    position: absolute;
    left: 18%;
    right: 18%;
    top: 34%;
    height: 26%;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.82);
  }
  .mf-bento__chip {
    position: absolute;
    z-index: 2;
    left: 14px;
    bottom: 14px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    max-width: calc(100% - 28px);
    padding: 8px 13px 8px 11px;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 999px;
    background: rgba(12, 13, 17, 0.58);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    color: #f6f5f2;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: 0;
  }
  .mf-bento__chip i {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--mf-bento-c3);
    box-shadow: 0 0 10px var(--mf-bento-c3);
  }
  .mf-bento__tag {
    align-self: flex-start;
    margin: 0;
    padding: 6px 11px;
    border: 1px solid color-mix(in srgb, var(--mf-bento-accent) 45%, transparent);
    border-radius: 999px;
    background: color-mix(in srgb, var(--mf-bento-accent) 10%, transparent);
    color: var(--mf-bento-accent);
    font-size: 11px;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 0.12em;
    text-transform: uppercase;
  }
  .mf-bento__ptitle {
    margin: 6px 0 0;
    color: var(--mf-bento-fg);
    font-family: inherit;
    font-size: clamp(26px, 2.6vw, 36px);
    font-weight: 600;
    line-height: 1.02;
    letter-spacing: -0.04em;
    text-transform: none;
  }
  .mf-bento__ptitle a {
    color: inherit;
    text-decoration: none;
  }
  .mf-bento__ptitle a:hover {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 5px;
  }
  .mf-bento__rating {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 0;
    color: color-mix(in srgb, var(--mf-bento-fg) 70%, transparent);
    font-size: 13px;
    line-height: 1.4;
    letter-spacing: 0;
  }
  .mf-bento__stars {
    color: var(--mf-bento-accent);
    font-size: 12px;
    letter-spacing: 2px;
  }
  .mf-bento__ptext {
    margin: 0;
    color: color-mix(in srgb, var(--mf-bento-fg) 62%, transparent);
    font-size: 14px;
    line-height: 1.55;
    letter-spacing: 0;
  }
  .mf-bento__buy {
    display: grid;
    gap: 16px;
    margin-top: auto;
  }
  .mf-bento__price {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 10px;
    margin: 0;
    color: var(--mf-bento-fg);
    line-height: 1;
    letter-spacing: 0;
  }
  .mf-bento__now {
    font-size: 26px;
    font-weight: 600;
    letter-spacing: -0.03em;
  }
  .mf-bento__was {
    color: color-mix(in srgb, var(--mf-bento-fg) 45%, transparent);
    font-size: 15px;
  }
  .mf-bento__save {
    align-self: center;
    padding: 4px 8px;
    border-radius: 6px;
    background: color-mix(in srgb, var(--mf-bento-c3) 16%, transparent);
    color: var(--mf-bento-c3);
    font-size: 12px;
    font-weight: 700;
  }
  .mf-bento__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 18px;
  }
  .mf-bento__form {
    display: contents;
  }
  .mf-bento__button {
    -webkit-appearance: none;
    appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    min-height: 48px;
    margin: 0;
    padding: 0 20px 0 22px;
    border: 0;
    border-radius: 999px;
    background: var(--mf-bento-fg);
    color: var(--mf-bento-bg);
    cursor: pointer;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0;
    text-decoration: none;
    text-transform: none;
    box-shadow: 0 14px 30px -14px color-mix(in srgb, var(--mf-bento-fg) 50%, transparent);
    transition: transform 0.2s ease, opacity 0.2s ease;
  }
  .mf-bento__button svg {
    width: 16px;
    height: 16px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    transition: transform 0.2s ease;
  }
  .mf-bento__button:hover {
    transform: translateY(-2px);
  }
  .mf-bento__button:hover svg {
    transform: translateX(3px);
  }
  .mf-bento__button[disabled] {
    cursor: not-allowed;
    opacity: 0.5;
    transform: none;
  }
  .mf-bento__button.is-added {
    background: var(--mf-bento-c3);
    color: #06140e;
  }
  .mf-bento__status {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .mf-bento__more {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    color: var(--mf-bento-fg);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0;
    text-decoration: underline;
    text-decoration-color: color-mix(in srgb, var(--mf-bento-fg) 30%, transparent);
    text-underline-offset: 6px;
  }
  .mf-bento__more:hover {
    text-decoration-color: currentColor;
  }
  .mf-bento__link:focus-visible,
  .mf-bento__button:focus-visible,
  .mf-bento__more:focus-visible,
  .mf-bento__ptitle a:focus-visible {
    outline: 2px solid var(--mf-bento-accent);
    outline-offset: 4px;
  }

  .mf-bento__card--product.mf-bento__card--tall .mf-bento__face {
    flex-direction: column;
  }
  .mf-bento__card--product.mf-bento__card--tall .mf-bento__visual {
    flex: 1 1 52%;
    min-height: 200px;
  }
  .mf-bento__card--product.mf-bento__card--wide .mf-bento__ptext,
  .mf-bento__card--product.mf-bento__card--wide .mf-bento__rating {
    display: none;
  }

  /* Entrance: cards rise in sequence once the grid is in view. */
  .mf-bento.is-armed .mf-bento__card {
    opacity: 0;
    transform: translateY(24px) scale(0.985);
  }
  .mf-bento.is-armed.is-in .mf-bento__card {
    opacity: 1;
    transform: none;
    transition:
      opacity 0.8s cubic-bezier(0.2, 0.7, 0.2, 1) calc(var(--i, 0) * 70ms),
      transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1) calc(var(--i, 0) * 70ms);
  }

  @keyframes mf-bento-spin {
    to {
      transform: rotate(1turn);
    }
  }

  @media screen and (max-width: 989px) {
    .mf-bento__head {
      grid-template-columns: minmax(0, 1fr);
      align-items: start;
    }
    .mf-bento__grid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  @media screen and (max-width: 749px) {
    .mf-bento {
      padding: calc(var(--mf-bento-pt, 88px) * 0.7) 0 calc(var(--mf-bento-pb, 88px) * 0.7);
    }
    .mf-bento__inner {
      width: min(100% - 32px, 1240px);
    }
    .mf-bento__head {
      gap: 18px;
      margin-bottom: 28px;
    }
    .mf-bento__eyebrow {
      margin-bottom: 18px;
      font-size: 10px;
    }
    .mf-bento__title {
      font-size: clamp(36px, 10.6vw, 52px);
      line-height: 1;
    }
    .mf-bento__sub {
      font-size: 15px;
    }
    .mf-bento__grid {
      grid-auto-rows: minmax(0, auto);
      gap: 10px;
    }
    .mf-bento__card--tall {
      grid-row: auto;
    }
    .mf-bento__card--large,
    .mf-bento__card--product {
      grid-column: 1 / -1;
      grid-row: auto;
    }
    .mf-bento__face {
      gap: 14px;
      min-height: 172px;
      padding: 18px;
    }
    .mf-bento__icon {
      width: 38px;
      height: 38px;
      border-radius: 11px;
    }
    .mf-bento__icon svg {
      width: 19px;
      height: 19px;
    }
    .mf-bento__stat {
      font-size: 30px;
    }
    .mf-bento__card--normal .mf-bento__body,
    .mf-bento__card--tall .mf-bento__body {
      margin-top: 4px;
    }
    .mf-bento__card--wide .mf-bento__stat,
    .mf-bento__card--tall .mf-bento__stat {
      font-size: 44px;
    }
    .mf-bento__ctitle {
      font-size: 15px;
    }
    .mf-bento__ctext {
      font-size: 13px;
      line-height: 1.5;
    }
    .mf-bento__card--tall .mf-bento__mark {
      display: none;
    }
    .mf-bento__mark {
      width: 132px;
      height: 132px;
      right: -14px;
      bottom: -20px;
    }
    .mf-bento__card--product .mf-bento__face,
    .mf-bento__card--product.mf-bento__card--tall .mf-bento__face {
      flex-direction: column;
      min-height: 0;
      padding: 0;
    }
    .mf-bento__card--product .mf-bento__visual {
      flex: none;
      height: auto;
      aspect-ratio: 1 / 0.92;
      margin: 8px 8px 0;
    }
    .mf-bento__pcopy {
      gap: 10px;
      padding: 20px 20px 22px;
    }
    .mf-bento__ptitle {
      margin-top: 4px;
      font-size: 30px;
    }
    .mf-bento__card--product.mf-bento__card--wide .mf-bento__ptext,
    .mf-bento__card--product.mf-bento__card--wide .mf-bento__rating {
      display: flex;
    }
    .mf-bento__buy {
      margin-top: 6px;
    }
    .mf-bento__actions .mf-bento__button {
      flex: 1 1 auto;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .mf-bento__blob i,
    .mf-bento__halo i {
      animation: none;
    }
    .mf-bento.is-armed .mf-bento__card,
    .mf-bento.is-armed.is-in .mf-bento__card {
      opacity: 1;
      transform: none;
      transition: none;
    }
    .mf-bento__blob,
    .mf-bento__halo,
    .mf-bento__spot,
    .mf-bento__ring::before,
    .mf-bento__pimg,
    .mf-bento__button,
    .mf-bento__button svg,
    .mf-bento__link span {
      transition: none;
    }
    .mf-bento__card--product:hover .mf-bento__pimg,
    .mf-bento__button:hover,
    .mf-bento__button:hover svg,
    .mf-bento__link:hover span {
      transform: none;
    }
  }
{% endstylesheet %}

{% javascript %}
  if (!customElements.get('mf-spotlight-bento')) {
    customElements.define('mf-spotlight-bento', class extends HTMLElement {
      connectedCallback() {
        this._grid = this.querySelector('.mf-bento__grid');
        this._halo = this.querySelector('.mf-bento__halo');
        this._cards = Array.prototype.slice.call(this.querySelectorAll('.mf-bento__card'));
        this._preview = window.__MF_PREVIEW__ === true;
        this._visible = true;
        this._raf = 0;

        this._onSubmit = this._submit.bind(this);
        this.addEventListener('submit', this._onSubmit);

        if (!this._grid || !this._cards.length) return;
        const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

        // Entrance once in view (and pause the light loop while off-screen).
        if ('IntersectionObserver' in window) {
          // The library preview shows the grid complete from the first frame.
          if (!reduce && !this._preview) this.classList.add('is-armed');
          this._io = new IntersectionObserver((entries) => {
            entries.forEach((entry) => {
              this._visible = entry.isIntersecting;
              if (entry.isIntersecting) {
                this.classList.add('is-in');
                this._kick();
              }
            });
          }, { threshold: 0.08 });
          this._io.observe(this);
        }

        // The light: off with reduced motion or when the merchant turns it off.
        // The static lit corners from CSS remain.
        if (reduce || this.dataset.follow === 'false') return;
        this.classList.add('is-live');

        this._measure();
        if ('ResizeObserver' in window) {
          this._ro = new ResizeObserver(() => this._measure());
          this._ro.observe(this._grid);
        }
        // Start where the scripted demo starts: on the seam between the hero
        // card and its neighbours, so several borders are lit at once.
        this._x = this._tx = this._w * 0.55;
        this._y = this._ty = this._h * 0.55;
        this._mode = this._preview ? 'demo' : 'idle';
        this._t0 = performance.now();

        // Desktop: the cursor is the light source.
        this._onMove = (event) => {
          if (event.pointerType === 'touch') return;
          const r = this._grid.getBoundingClientRect();
          this._tx = event.clientX - r.left;
          this._ty = event.clientY - r.top;
          this._mode = 'pointer';
          this._on(true);
          this._kick();
        };
        this._onLeave = (event) => {
          if (event.pointerType === 'touch') return;
          this._mode = this._preview ? 'demo' : 'idle';
          if (!this._preview) this._on(false);
          this._kick();
        };
        this.addEventListener('pointermove', this._onMove);
        this.addEventListener('pointerleave', this._onLeave);

        // Touch screens: the light rides the middle of the viewport, so cards
        // light up one after another as the visitor scrolls through them.
        const fine = window.matchMedia('(hover: hover) and (pointer: fine)').matches;
        if (!fine && !this._preview) {
          this._mode = 'scroll';
          this._onScroll = () => this._kick();
          window.addEventListener('scroll', this._onScroll, { passive: true });
        }

        if (this._mode === 'demo') {
          this.classList.add('is-instant');
          this._on(true);
          requestAnimationFrame(() => requestAnimationFrame(() => this.classList.remove('is-instant')));
        }
        this._kick();
      }

      disconnectedCallback() {
        this.removeEventListener('submit', this._onSubmit);
        if (this._onMove) this.removeEventListener('pointermove', this._onMove);
        if (this._onLeave) this.removeEventListener('pointerleave', this._onLeave);
        if (this._onScroll) window.removeEventListener('scroll', this._onScroll);
        if (this._io) this._io.disconnect();
        if (this._ro) this._ro.disconnect();
        if (this._raf) cancelAnimationFrame(this._raf);
        this._raf = 0;
        clearTimeout(this._doneTimer);
      }

      _measure() {
        this._w = this._grid.clientWidth || 1;
        this._h = this._grid.clientHeight || 1;
        this._boxes = this._cards.map((card) => ({
          x: card.offsetLeft,
          y: card.offsetTop,
          w: card.offsetWidth,
          h: card.offsetHeight
        }));
        this._kick();
      }

      _on(state) {
        this.classList.toggle('is-on', state);
      }

      _kick() {
        if (!this._raf && this._boxes && this._visible) {
          this._raf = requestAnimationFrame((now) => this._tick(now));
        }
      }

      _tick(now) {
        this._raf = 0;
        let ease = 0.2;
        let loop = false;

        if (this._mode === 'demo') {
          // Scripted cursor for the library preview: a slow figure-eight that
          // sweeps across every card boundary.
          const t = (now - this._t0) / 1000;
          this._tx = this._w * (0.5 + 0.47 * Math.sin(t * 0.42 + 0.106));
          this._ty = this._h * (0.5 + 0.46 * Math.sin(t * 0.84 + 0.109));
          ease = 0.12;
          loop = true;
        } else if (this._mode === 'scroll') {
          const r = this._grid.getBoundingClientRect();
          const mid = window.innerHeight * 0.5 - r.top;
          const p = mid / this._h;
          this._ty = mid;
          this._tx = this._w * (0.5 + 0.38 * Math.sin(p * Math.PI * 2.2));
          this._on(mid > -60 && mid < this._h + 60);
          ease = 0.16;
        }

        this._x += (this._tx - this._x) * ease;
        this._y += (this._ty - this._y) * ease;
        const x = this._x;
        const y = this._y;

        if (this._halo) {
          this._halo.style.setProperty('--mf-bento-hx', x.toFixed(1) + 'px');
          this._halo.style.setProperty('--mf-bento-hy', y.toFixed(1) + 'px');
        }
        for (let i = 0; i < this._cards.length; i += 1) {
          const card = this._cards[i];
          const box = this._boxes[i];
          if (!box) continue;
          card.style.setProperty('--mx', (x - box.x).toFixed(1) + 'px');
          card.style.setProperty('--my', (y - box.y).toFixed(1) + 'px');
          const inside = x >= box.x && x <= box.x + box.w && y >= box.y && y <= box.y + box.h;
          if (inside !== card.classList.contains('is-lit')) card.classList.toggle('is-lit', inside);
        }

        const moving = Math.abs(this._tx - this._x) > 0.4 || Math.abs(this._ty - this._y) > 0.4;
        if (loop || moving) this._kick();
      }

      _submit(event) {
        const form = event.target;
        if (!form || !form.hasAttribute('data-mf-bento-add') || !window.fetch) return;
        event.preventDefault();
        const button = form.querySelector('.mf-bento__button');
        const label = form.querySelector('.mf-bento__label');
        const status = form.querySelector('.mf-bento__status');
        const original = label ? label.textContent : '';
        const done = (item) => {
          const added = (button && button.dataset.added) || original;
          if (button) {
            button.disabled = false;
            button.classList.add('is-added');
          }
          if (label) label.textContent = added;
          if (status) status.textContent = added;
          document.dispatchEvent(new CustomEvent('cart:refresh', { bubbles: true }));
          document.dispatchEvent(new CustomEvent('mf:cart:added', { bubbles: true, detail: item || null }));
          clearTimeout(this._doneTimer);
          this._doneTimer = setTimeout(() => {
            if (button) button.classList.remove('is-added');
            if (label) label.textContent = original;
            if (status) status.textContent = '';
          }, 2600);
        };

        if (this._preview) {
          done(null);
          return;
        }
        if (button) button.disabled = true;
        const root = (window.Shopify && window.Shopify.routes && window.Shopify.routes.root) || '/';
        fetch(root + 'cart/add.js', {
          method: 'POST',
          headers: { Accept: 'application/json' },
          body: new FormData(form)
        })
          .then((response) => {
            if (!response.ok) throw new Error('cart/add failed');
            return response.json();
          })
          .then((item) => done(item))
          .catch(() => {
            form.removeAttribute('data-mf-bento-add');
            form.submit();
          });
      }
    });
  }
{% endjavascript %}

{% schema %}
{
  "name": "EX · Spotlight bento",
  "tag": "section",
  "class": "mf-section",
  "disabled_on": {
    "groups": ["header", "footer"]
  },
  "settings": [
    {
      "type": "header",
      "content": "Content"
    },
    {
      "type": "text",
      "id": "eyebrow",
      "label": "Eyebrow",
      "default": "Shop without second thoughts"
    },
    {
      "type": "inline_richtext",
      "id": "heading",
      "label": "Heading",
      "default": "Every doubt answered,"
    },
    {
      "type": "inline_richtext",
      "id": "heading_accent",
      "label": "Heading accent",
      "default": "before checkout."
    },
    {
      "type": "select",
      "id": "accent_style",
      "label": "Accent style",
      "options": [
        { "value": "plain", "label": "Muted" },
        { "value": "serif", "label": "Italic serif" },
        { "value": "gradient", "label": "Gradient serif" }
      ],
      "default": "gradient"
    },
    {
      "type": "select",
      "id": "heading_tag",
      "label": "Heading HTML tag",
      "info": "Use H1 only when this is the first section of the page.",
      "options": [
        { "value": "h1", "label": "H1" },
        { "value": "h2", "label": "H2" }
      ],
      "default": "h2"
    },
    {
      "type": "richtext",
      "id": "subheading",
      "label": "Subheading",
      "default": "<p>Free tracked shipping, free 30-day returns and a guarantee that outlasts the bottle. Everything that matters, in one glance.</p>"
    },
    {
      "type": "text",
      "id": "link_label",
      "label": "Link label",
      "default": "Shipping and returns policy"
    },
    {
      "type": "url",
      "id": "link_url",
      "label": "Link",
      "info": "Leave empty to link to your refund policy."
    },
    {
      "type": "header",
      "content": "Spotlight"
    },
    {
      "type": "checkbox",
      "id": "glow_follow",
      "label": "Light follows the cursor",
      "info": "On phones the light follows the scroll. Off, or with reduced motion, each card keeps a still lit corner.",
      "default": true
    },
    {
      "type": "select",
      "id": "glow_style",
      "label": "Light color",
      "options": [
        { "value": "spectrum", "label": "Spectrum" },
        { "value": "accent", "label": "Accent color" }
      ],
      "default": "spectrum"
    },
    {
      "type": "range",
      "id": "glow_size",
      "label": "Light radius",
      "min": 120,
      "max": 360,
      "step": 10,
      "unit": "px",
      "default": 280
    },
    {
      "type": "range",
      "id": "border_width",
      "label": "Glowing border width",
      "min": 1,
      "max": 4,
      "step": 1,
      "unit": "px",
      "default": 2
    },
    {
      "type": "header",
      "content": "Layout"
    },
    {
      "type": "select",
      "id": "columns",
      "label": "Columns on desktop",
      "options": [
        { "value": "3", "label": "3" },
        { "value": "4", "label": "4" }
      ],
      "default": "4"
    },
    {
      "type": "range",
      "id": "row_height",
      "label": "Row height",
      "min": 160,
      "max": 300,
      "step": 4,
      "unit": "px",
      "default": 200
    },
    {
      "type": "range",
      "id": "gap",
      "label": "Gap between cards",
      "min": 6,
      "max": 24,
      "step": 2,
      "unit": "px",
      "default": 14
    },
    {
      "type": "range",
      "id": "card_radius",
      "label": "Card corner radius",
      "min": 0,
      "max": 32,
      "step": 2,
      "unit": "px",
      "default": 22
    },
    {
      "type": "range",
      "id": "padding_top",
      "label": "Top spacing",
      "min": 0,
      "max": 160,
      "step": 4,
      "unit": "px",
      "default": 88
    },
    {
      "type": "range",
      "id": "padding_bottom",
      "label": "Bottom spacing",
      "min": 0,
      "max": 160,
      "step": 4,
      "unit": "px",
      "default": 88
    },
    {
      "type": "header",
      "content": "Colors"
    },
    {
      "type": "color",
      "id": "color_bg",
      "label": "Background",
      "default": "#07080b"
    },
    {
      "type": "color",
      "id": "color_card",
      "label": "Cards",
      "default": "#0e1015"
    },
    {
      "type": "color",
      "id": "color_text",
      "label": "Text",
      "default": "#f4f2ee"
    },
    {
      "type": "color",
      "id": "color_accent",
      "label": "Accent",
      "info": "Eyebrow dot, stars and the product tag.",
      "default": "#ffc46b"
    }
  ],
  "blocks": [
    {
      "type": "product",
      "name": "Product card",
      "limit": 2,
      "settings": [
        {
          "type": "product",
          "id": "product",
          "label": "Product"
        },
        {
          "type": "select",
          "id": "size",
          "label": "Card size",
          "options": [
            { "value": "large", "label": "Large (2 × 2)" },
            { "value": "wide", "label": "Wide (2 × 1)" },
            { "value": "tall", "label": "Tall (1 × 2)" }
          ],
          "default": "large"
        },
        {
          "type": "select",
          "id": "image",
          "label": "Product image",
          "options": [
            { "value": "first", "label": "Main image" },
            { "value": "second", "label": "Second image (often lifestyle)" }
          ],
          "default": "first"
        },
        {
          "type": "text",
          "id": "label",
          "label": "Tag",
          "default": "Most loved"
        },
        {
          "type": "text",
          "id": "title",
          "label": "Title when no product is selected",
          "default": "Our bestseller"
        },
        {
          "type": "text",
          "id": "text",
          "label": "Short pitch",
          "default": "Visibly brighter skin in 14 days, or your money back."
        },
        {
          "type": "text",
          "id": "badge",
          "label": "Badge on the image",
          "default": "In stock, ships today"
        },
        {
          "type": "text",
          "id": "reviews_label",
          "label": "Reviews word",
          "info": "Shown after the review count from your reviews app metafields.",
          "default": "reviews"
        },
        {
          "type": "text",
          "id": "button_label",
          "label": "Add to cart label",
          "info": "Leave empty to hide the add to cart button.",
          "default": "Add to cart"
        },
        {
          "type": "text",
          "id": "added_label",
          "label": "Added label",
          "default": "Added to cart"
        },
        {
          "type": "text",
          "id": "soldout_label",
          "label": "Sold out label",
          "default": "Sold out"
        },
        {
          "type": "text",
          "id": "link_label",
          "label": "Product link label",
          "default": "View details"
        }
      ]
    },
    {
      "type": "benefit",
      "name": "Benefit card",
      "settings": [
        {
          "type": "select",
          "id": "icon",
          "label": "Icon",
          "options": [
            { "value": "truck", "label": "Delivery truck" },
            { "value": "return", "label": "Returns" },
            { "value": "shield", "label": "Guarantee shield" },
            { "value": "star", "label": "Star rating" },
            { "value": "lock", "label": "Secure lock" },
            { "value": "leaf", "label": "Leaf" },
            { "value": "chat", "label": "Support chat" },
            { "value": "gift", "label": "Gift" }
          ],
          "default": "truck"
        },
        {
          "type": "select",
          "id": "size",
          "label": "Card size",
          "options": [
            { "value": "normal", "label": "Normal (1 × 1)" },
            { "value": "wide", "label": "Wide (2 × 1)" },
            { "value": "tall", "label": "Tall (1 × 2)" }
          ],
          "default": "normal"
        },
        {
          "type": "text",
          "id": "stat",
          "label": "Stat",
          "info": "Short figure shown large, like 30 days or 4.9/5. Optional.",
          "default": "48h"
        },
        {
          "type": "text",
          "id": "title",
          "label": "Title",
          "default": "Free tracked shipping"
        },
        {
          "type": "textarea",
          "id": "text",
          "label": "Text",
          "default": "Free over €50, dispatched within 24 hours."
        },
        {
          "type": "url",
          "id": "link",
          "label": "Link",
          "info": "Optional. Makes the whole card clickable, for example to a policy page."
        }
      ]
    }
  ],
  "max_blocks": 12,
  "presets": [
    {
      "name": "EX · Spotlight bento",
      "blocks": [
        {
          "type": "product",
          "settings": {
            "size": "large"
          }
        },
        {
          "type": "benefit",
          "settings": {
            "icon": "truck",
            "size": "normal",
            "stat": "48h",
            "title": "Free tracked shipping",
            "text": "Free over €50, dispatched within 24 hours."
          }
        },
        {
          "type": "benefit",
          "settings": {
            "icon": "return",
            "size": "normal",
            "stat": "30 days",
            "title": "Free returns",
            "text": "Changed your mind? Send it back, even opened."
          }
        },
        {
          "type": "benefit",
          "settings": {
            "icon": "shield",
            "size": "wide",
            "stat": "100%",
            "title": "The glow guarantee",
            "text": "No visible difference in 30 days? We refund every cent. No forms, no questions."
          }
        },
        {
          "type": "benefit",
          "settings": {
            "icon": "star",
            "size": "wide",
            "stat": "4.9/5",
            "title": "Rated by 40,000+ customers",
            "text": "Verified reviews from real orders, published unfiltered."
          }
        },
        {
          "type": "benefit",
          "settings": {
            "icon": "lock",
            "size": "normal",
            "stat": "256-bit",
            "title": "Secure checkout",
            "text": "Shop Pay, Apple Pay, cards and PayPal."
          }
        },
        {
          "type": "benefit",
          "settings": {
            "icon": "chat",
            "size": "normal",
            "stat": "< 2h",
            "title": "Real humans",
            "text": "Skin experts reply 7 days a week."
          }
        }
      ]
    }
  ]
}
{% endschema %}
Why it converts

Answer objections at a glance: shipping, returns, guarantee and proof grouped in one scannable block next to the product.

Specs

File: sections/mf-spotlight-bento.liquidIn the theme editor: EX · Spotlight bentoBest on: index, product, page templatesSettings: 40 · blocks: Product card, Benefit cardValidated: Shopify Theme Check, no external assets

About this section

Spotlight Bento is a Shopify Online Store 2.0 trust section that gathers the answers shoppers look for before buying into one bento grid of dark cards. A single light source travels across the grid: every card border glows where the light passes, so neighbouring cards light up together, and the card under the light gets a soft inner spotlight. On desktop the light follows the cursor; on phones it follows the scroll, lighting each card as it crosses the middle of the screen. Benefit card blocks hold an icon chosen from eight line icons, an optional large stat such as 30 days or 4.9/5, a title, a short text, an optional link and a normal, wide or tall size. A product card block spans two by two cells and shows a product chosen in the theme editor with its main or second image, a tag, its rating from review app metafields, price and compare-at price, a real add to cart form with AJAX enhancement and a link to the product page; without a product it shows designed bottle art. Settings cover the eyebrow, a two-line heading with a muted, serif or gradient accent, subheading and policy link, light color, radius and border width, columns, row height, gap, corner radius, spacing and four colors. The conversion principle is objection handling at a glance: shipping, returns, guarantee and proof sit together near the decision point. With reduced motion the light stops and each card keeps a still lit corner. One self-contained .liquid file, no libraries or external assets.

Questions

How does the glowing border work?

Each card has a thin masked ring that holds a rotating gradient light. The section moves that light to the cursor position in every card's own coordinates, so borders near the cursor glow at once, even across the gaps between cards. Only transforms are animated.

What happens on phones and with reduced motion?

On touch screens the light follows the scroll and lights each card as it passes the middle of the screen, and the grid becomes two columns with the product card on top at full width. With reduced motion the light stays still and every card keeps a static lit corner.

How do I build my own grid in the theme editor?

Add Benefit card blocks, pick an icon, a stat, a title and a text, and choose Normal, Wide or Tall for each. Add one Product card block and pick a product. The grid fills gaps automatically, so 12 cells (for example one large card, four normal and two wide) give a complete four-column block.

Does the add to cart button work with my theme's cart?

Yes. It is a standard Shopify product form with the variant id, so it works without JavaScript. With JavaScript it adds through the Cart API, shows the added label and dispatches cart:refresh so themes that listen can update the cart count or drawer.

More sections