# Morphing Dialog

> A card that expands into a full dialog with shared-element morphing — premium modal open/close without jarring cuts.

**Definition:** Morphing Dialog is a components UI animation from collections.html. It is built with HTML, CSS, JavaScript, and GSAP, ships with a live preview, and is free to copy into personal and commercial projects.

## Facts
- Category: Components
- Stack: HTML, CSS, JavaScript, and GSAP
- Added: 2026-08-02
- Canonical page: https://html.bosconvertpro.com/collection/morphing-dialog
- Full-page preview: https://html.bosconvertpro.com/collection/morphing-dialog/full
- Live demo: https://html.bosconvertpro.com/demos/morphing-dialog/index.html
- Markdown mirror: https://html.bosconvertpro.com/collection/morphing-dialog/index.md
- License: https://html.bosconvertpro.com/terms

## How to use
1. Open https://html.bosconvertpro.com/collection/morphing-dialog/full to preview the animation in full screen.
2. Copy index.html, styles.css, and script.js from the code tabs on https://html.bosconvertpro.com/collection/morphing-dialog.
3. Paste the files into your project and adjust timing, easing, and content as needed.

## FAQ
### What is Morphing Dialog?

Morphing Dialog is a components UI animation from collections.html. A card that expands into a full dialog with shared-element morphing — premium modal open/close without jarring cuts.

### What is Morphing Dialog built with?

Morphing Dialog is built with HTML, CSS, JavaScript, and GSAP. The source for every file is shown on the animation page and can be copied straight into your project.

### How do I use Morphing Dialog in my project?

Open the animation page (https://html.bosconvertpro.com/collection/morphing-dialog), preview it live, then copy index.html, styles.css, and script.js from the code tabs. Paste the files into your project and adjust timing, easing, and content as needed. A standalone demo runs at https://html.bosconvertpro.com/demos/morphing-dialog/index.html.

### Is Morphing Dialog free to use?

Yes. The Morphing Dialog demo code may be used in personal and commercial projects. You may not resell or redistribute the collection itself as a competing template pack. Full terms: https://html.bosconvertpro.com/terms.

## Source — index.html
````html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Morphing Dialog — Premium</title>
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600&display=swap"
      rel="stylesheet"
    />
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <div class="preview-container">
      <div class="animation-container">
        <div class="morphing_dialog_wrapper" data-anm-morphing-dialog>
          <!-- Trigger card -->
          <button
            class="morphing_dialog_trigger"
            data-anm-morph-trigger
            type="button"
            aria-haspopup="dialog"
          >
            <div
              class="morphing_dialog_trigger_bg"
              data-anm-morph-id="dialog-bg"
            >
              <div
                class="morphing_dialog_image"
                data-anm-morph-id="product-image"
              >
                <img
                  src="https://images.unsplash.com/photo-1505740420928-5e560c06d30e?auto=format&fit=crop&w=1200&q=80"
                  alt="Noir Studio Headphones"
                  width="680"
                  height="520"
                  loading="eager"
                />
                <span
                  class="morphing_dialog_badge"
                  data-anm-morph-id="product-badge"
                  >Limited</span
                >
              </div>
              <div class="morphing_dialog_info">
                <div class="morphing_dialog_meta" data-anm-dialog-only>
                  <span class="morphing_dialog_stars" aria-hidden="true">
                    <svg viewBox="0 0 24 24" fill="currentColor">
                      <path
                        d="M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
                      />
                    </svg>
                    <svg viewBox="0 0 24 24" fill="currentColor">
                      <path
                        d="M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
                      />
                    </svg>
                    <svg viewBox="0 0 24 24" fill="currentColor">
                      <path
                        d="M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
                      />
                    </svg>
                    <svg viewBox="0 0 24 24" fill="currentColor">
                      <path
                        d="M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
                      />
                    </svg>
                    <svg viewBox="0 0 24 24" fill="currentColor">
                      <path
                        d="M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
                      />
                    </svg>
                  </span>
                  <span class="morphing_dialog_rating">4.9 · 2.4k reviews</span>
                </div>
                <h3
                  class="morphing_dialog_title"
                  data-anm-morph-id="product-title"
                >
                  Noir Studio
                </h3>
                <p
                  class="morphing_dialog_subtitle"
                  data-anm-morph-id="product-subtitle"
                >
                  Wireless Over-Ear Headphones
                </p>
                <div class="morphing_dialog_price_row">
                  <div
                    class="morphing_dialog_price"
                    data-anm-morph-id="product-price"
                  >
                    $289
                  </div>
                  <span class="morphing_dialog_price_old" data-anm-dialog-only
                    >$349</span
                  >
                </div>
                <span class="morphing_dialog_cta">
                  View details
                  <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                    aria-hidden="true"
                  >
                    <path d="M5 12h14M13 6l6 6-6 6" />
                  </svg>
                </span>
              </div>
            </div>
          </button>

          <!-- Expanded dialog -->
          <dialog
            class="morphing_dialog_content"
            data-anm-morph-dialog
            aria-labelledby="morph-dialog-title"
          >
            <div
              class="morphing_dialog_content_bg"
              data-anm-morph-id="dialog-bg"
            >
              <div
                class="morphing_dialog_image_large"
                data-anm-morph-id="product-image"
              >
                <img
                  src="https://images.unsplash.com/photo-1505740420928-5e560c06d30e?auto=format&fit=crop&w=1400&q=80"
                  alt="Noir Studio Headphones"
                  width="1400"
                  height="900"
                />
                <span
                  class="morphing_dialog_badge_large"
                  data-anm-morph-id="product-badge"
                  >Limited</span
                >
              </div>

              <div class="morphing_dialog_body">
                <div class="morphing_dialog_header">
                  <div class="morphing_dialog_title_group">
                    <div
                      class="morphing_dialog_meta_large"
                      data-anm-dialog-only
                    >
                      <span class="morphing_dialog_stars" aria-hidden="true">
                        <svg viewBox="0 0 24 24" fill="currentColor">
                          <path
                            d="M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
                          />
                        </svg>
                        <svg viewBox="0 0 24 24" fill="currentColor">
                          <path
                            d="M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
                          />
                        </svg>
                        <svg viewBox="0 0 24 24" fill="currentColor">
                          <path
                            d="M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
                          />
                        </svg>
                        <svg viewBox="0 0 24 24" fill="currentColor">
                          <path
                            d="M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
                          />
                        </svg>
                        <svg viewBox="0 0 24 24" fill="currentColor">
                          <path
                            d="M12 2l2.9 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l7.1-1.01L12 2z"
                          />
                        </svg>
                      </span>
                      <span class="morphing_dialog_rating"
                        >4.9 · 2.4k reviews</span
                      >
                    </div>
                    <h2
                      id="morph-dialog-title"
                      class="morphing_dialog_title_large"
                      data-anm-morph-id="product-title"
                    >
                      Noir Studio
                    </h2>
                    <p
                      class="morphing_dialog_subtitle_large"
                      data-anm-morph-id="product-subtitle"
                    >
                      Wireless Over-Ear Headphones
                    </p>
                    <div class="morphing_dialog_price_row_large">
                      <div
                        class="morphing_dialog_price_large"
                        data-anm-morph-id="product-price"
                      >
                        $289
                      </div>
                      <span
                        class="morphing_dialog_price_old_large"
                        data-anm-dialog-only
                        >$349</span
                      >
                      <span class="morphing_dialog_save" data-anm-dialog-only
                        >Save $60</span
                      >
                    </div>
                  </div>
                  <button
                    class="morphing_dialog_close"
                    data-anm-morph-close
                    data-anm-dialog-only
                    type="button"
                    aria-label="Close dialog"
                  >
                    <svg
                      width="18"
                      height="18"
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                    >
                      <line x1="18" y1="6" x2="6" y2="18"></line>
                      <line x1="6" y1="6" x2="18" y2="18"></line>
                    </svg>
                  </button>
                </div>

                <p class="morphing_dialog_description" data-anm-dialog-only>
                  Studio-grade wireless cans with a sculpted silhouette and
                  plush memory-foam earcups. Adaptive noise cancellation, 40-hour
                  battery, and a sound signature tuned for deep lows and airy
                  highs—made for travel, focus, and late-night sessions.
                </p>

                <div class="morphing_dialog_swatches" data-anm-dialog-only>
                  <span class="morphing_dialog_swatches_label">Color</span>
                  <div class="morphing_dialog_swatch_list" role="list">
                    <span
                      class="morphing_dialog_swatch is-active"
                      role="listitem"
                      style="background: #1a1816"
                      title="Noir"
                      aria-label="Noir"
                    ></span>
                    <span
                      class="morphing_dialog_swatch"
                      role="listitem"
                      style="background: #c4b8a8"
                      title="Sand"
                      aria-label="Sand"
                    ></span>
                    <span
                      class="morphing_dialog_swatch"
                      role="listitem"
                      style="background: #3d4f3f"
                      title="Forest"
                      aria-label="Forest"
                    ></span>
                    <span
                      class="morphing_dialog_swatch"
                      role="listitem"
                      style="background: #5c3d3a"
                      title="Merlot"
                      aria-label="Merlot"
                    ></span>
                  </div>
                </div>

                <div class="morphing_dialog_features" data-anm-dialog-only>
                  <h3 class="morphing_dialog_features_title">Highlights</h3>
                  <ul class="morphing_dialog_features_list">
                    <li class="morphing_dialog_feature_item">
                      <svg
                        class="morphing_dialog_feature_icon"
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        stroke-linecap="round"
                        stroke-linejoin="round"
                      >
                        <path d="M20 6L9 17l-5-5" />
                      </svg>
                      <span class="morphing_dialog_feature_text"
                        >Adaptive ANC with transparency mode</span
                      >
                    </li>
                    <li class="morphing_dialog_feature_item">
                      <svg
                        class="morphing_dialog_feature_icon"
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        stroke-linecap="round"
                        stroke-linejoin="round"
                      >
                        <path d="M20 6L9 17l-5-5" />
                      </svg>
                      <span class="morphing_dialog_feature_text"
                        >40-hour battery · fast charge</span
                      >
                    </li>
                    <li class="morphing_dialog_feature_item">
                      <svg
                        class="morphing_dialog_feature_icon"
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        stroke-linecap="round"
                        stroke-linejoin="round"
                      >
                        <path d="M20 6L9 17l-5-5" />
                      </svg>
                      <span class="morphing_dialog_feature_text"
                        >Hi-res Bluetooth 5.3 audio</span
                      >
                    </li>
                    <li class="morphing_dialog_feature_item">
                      <svg
                        class="morphing_dialog_feature_icon"
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        stroke-linecap="round"
                        stroke-linejoin="round"
                      >
                        <path d="M20 6L9 17l-5-5" />
                      </svg>
                      <span class="morphing_dialog_feature_text"
                        >Memory-foam leatherette cushions</span
                      >
                    </li>
                  </ul>
                </div>

                <div class="morphing_dialog_footer" data-anm-dialog-only>
                  <button
                    class="morphing_dialog_btn_secondary"
                    data-anm-morph-close
                    type="button"
                  >
                    Close
                  </button>
                  <button class="morphing_dialog_btn_primary" type="button">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                      aria-hidden="true"
                    >
                      <path
                        d="M6 6h15l-1.5 9h-12zM6 6L5 3H2M9 20a1 1 0 100-2 1 1 0 000 2zm9 0a1 1 0 100-2 1 1 0 000 2z"
                      />
                    </svg>
                    Add to bag
                  </button>
                </div>
                <p class="morphing_dialog_ship_note" data-anm-dialog-only>
                  <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                    aria-hidden="true"
                  >
                    <path d="M5 12l5 5L20 7" />
                  </svg>
                  Free shipping · 30-day returns · 2-year warranty
                </p>
              </div>
            </div>
          </dialog>
        </div>
      </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
    <script src="script.js"></script>
  </body>
</html>
````

## Source — styles.css
````css
/* Premium Morphing Dialog — warm editorial luxury */

:root {
  --md-bg: #e8e4dc;
  --md-bg-deep: #ddd7cc;
  --md-surface: #faf9f7;
  --md-surface-elevated: #ffffff;
  --md-ink: #1c1917;
  --md-ink-soft: #57534e;
  --md-ink-muted: #8a847a;
  --md-accent: #3d4f3f;
  --md-accent-hover: #2f3d32;
  --md-accent-soft: rgba(61, 79, 63, 0.1);
  --md-gold: #a68b5b;
  --md-gold-soft: rgba(166, 139, 91, 0.14);
  --md-border: rgba(28, 25, 23, 0.07);
  --md-border-strong: rgba(28, 25, 23, 0.12);
  --md-radius: 0;
  --md-radius-sm: 0;
  --md-radius-pill: 0;
  --md-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --md-shadow-card:
    0 1px 2px rgba(28, 25, 23, 0.04),
    0 8px 24px rgba(28, 25, 23, 0.06),
    0 24px 48px rgba(28, 25, 23, 0.06);
  --md-shadow-card-hover:
    0 2px 4px rgba(28, 25, 23, 0.04),
    0 16px 40px rgba(28, 25, 23, 0.1),
    0 32px 64px rgba(28, 25, 23, 0.08);
  --md-shadow-dialog:
    0 4px 8px rgba(28, 25, 23, 0.04),
    0 24px 48px rgba(28, 25, 23, 0.12),
    0 48px 96px rgba(28, 25, 23, 0.14);
  --md-font-sans: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
    sans-serif;
  --md-font-display: "Fraunces", "Georgia", serif;
}

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: var(--md-font-sans);
  background: var(--md-bg);
  color: var(--md-ink);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ============================================
   PREVIEW LAYOUT
   ============================================ */

.preview-container {
  width: 100%;
  min-height: 100vh;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 3rem;
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(
      ellipse 80% 60% at 50% 40%,
      rgba(255, 252, 247, 0.7) 0%,
      transparent 70%
    ),
    radial-gradient(
      ellipse 50% 40% at 70% 70%,
      rgba(61, 79, 63, 0.06) 0%,
      transparent 60%
    ),
    radial-gradient(
      ellipse 40% 35% at 20% 80%,
      rgba(166, 139, 91, 0.08) 0%,
      transparent 55%
    ),
    var(--md-bg);
}

.animation-container {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  z-index: 1;
}

/* ============================================
   MORPHING DIALOG — CARD
   ============================================ */

.morphing_dialog_wrapper {
  position: relative;
  display: inline-block;
}

.morphing_dialog_trigger {
  display: inline-block;
  cursor: pointer;
  border-radius: var(--md-radius);
  overflow: hidden;
  background: transparent;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: inherit;
  -webkit-tap-highlight-color: transparent;
}

.morphing_dialog_trigger:focus-visible {
  outline: 2px solid var(--md-accent);
  outline-offset: 4px;
}

.morphing_dialog_trigger_bg {
  display: flex;
  flex-direction: column;
  background: var(--md-surface);
  overflow: hidden;
  width: 340px;
  border-radius: var(--md-radius);
  border: 1px solid var(--md-border);
  box-shadow: var(--md-shadow-card);
  transition:
    transform 500ms var(--md-ease),
    box-shadow 500ms var(--md-ease);
  transform: translateZ(0);
  will-change: transform;
}

.morphing_dialog_trigger:hover .morphing_dialog_trigger_bg {
  transform: translateY(-6px);
  box-shadow: var(--md-shadow-card-hover);
}

.morphing_dialog_image {
  width: 100%;
  height: 260px;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: #1a1816;
}

.morphing_dialog_image::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(26, 24, 22, 0.35) 0%,
    transparent 45%
  );
  pointer-events: none;
  z-index: 1;
}

.morphing_dialog_image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 700ms var(--md-ease);
}

.morphing_dialog_trigger:hover .morphing_dialog_image img {
  transform: scale(1.04);
}

.morphing_dialog_badge {
  position: absolute;
  top: 1rem;
  left: 1rem;
  z-index: 2;
  padding: 0.4rem 0.75rem;
  font-size: 0.625rem;
  font-weight: 600;
  font-family: var(--md-font-sans);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  background: rgba(250, 249, 247, 0.92);
  color: var(--md-ink);
  border-radius: var(--md-radius-pill);
  border: 1px solid rgba(255, 255, 255, 0.5);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.morphing_dialog_info {
  padding: 1.35rem 1.5rem 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  text-align: left;
}

.morphing_dialog_meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.15rem;
}

.morphing_dialog_stars {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  color: var(--md-gold);
}

.morphing_dialog_stars svg {
  width: 12px;
  height: 12px;
}

.morphing_dialog_rating {
  font-size: 0.7rem;
  font-weight: 500;
  color: var(--md-ink-muted);
  letter-spacing: 0.01em;
}

.morphing_dialog_title {
  font-family: var(--md-font-display);
  font-size: 1.35rem;
  font-weight: 500;
  font-optical-sizing: auto;
  color: var(--md-ink);
  margin: 0;
  letter-spacing: -0.02em;
  line-height: 1.25;
}

.morphing_dialog_subtitle {
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--md-ink-muted);
  margin: 0;
  letter-spacing: 0.01em;
}

.morphing_dialog_price_row {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin-top: 0.65rem;
}

.morphing_dialog_price {
  font-family: var(--md-font-display);
  font-size: 1.5rem;
  font-weight: 500;
  color: var(--md-ink);
  letter-spacing: -0.02em;
}

.morphing_dialog_price_old {
  font-size: 0.875rem;
  color: var(--md-ink-muted);
  text-decoration: line-through;
}

.morphing_dialog_cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem 1.5rem;
  margin-top: 1.15rem;
  font-size: 0.8125rem;
  font-weight: 600;
  font-family: var(--md-font-sans);
  letter-spacing: 0.02em;
  color: #faf9f7;
  background: var(--md-accent);
  border-radius: var(--md-radius-pill);
  transition:
    background 400ms var(--md-ease),
    transform 400ms var(--md-ease);
  width: 100%;
}

.morphing_dialog_cta svg {
  width: 14px;
  height: 14px;
  transition: transform 400ms var(--md-ease);
}

.morphing_dialog_trigger:hover .morphing_dialog_cta {
  background: var(--md-accent-hover);
}

.morphing_dialog_trigger:hover .morphing_dialog_cta svg {
  transform: translateX(2px);
}

/* ============================================
   DIALOG
   ============================================ */

.morphing_dialog_content {
  border: none;
  padding: 0;
  margin: auto;
  background: transparent;
  max-width: none;
  max-height: none;
  border-radius: var(--md-radius);
  overflow: hidden;
}

.morphing_dialog_content::backdrop {
  background: rgba(20, 18, 16, 0.55);
  backdrop-filter: blur(12px) saturate(1.1);
  -webkit-backdrop-filter: blur(12px) saturate(1.1);
}

.morphing_dialog_content_bg {
  width: 90vw;
  max-width: 720px;
  max-height: 90vh;
  overflow-y: auto;
  padding: 0;
  background: var(--md-surface);
  border-radius: var(--md-radius);
  border: 1px solid var(--md-border);
  box-shadow: var(--md-shadow-dialog);
  transform: translateZ(0);
  scrollbar-width: thin;
  scrollbar-color: var(--md-border-strong) transparent;
}

.morphing_dialog_image_large {
  width: 100%;
  height: 380px;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: #1a1816;
}

.morphing_dialog_image_large::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(26, 24, 22, 0.25) 0%,
    transparent 40%
  );
  pointer-events: none;
  z-index: 1;
}

.morphing_dialog_image_large img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.morphing_dialog_badge_large {
  position: absolute;
  top: 1.25rem;
  left: 1.25rem;
  z-index: 2;
  padding: 0.45rem 0.9rem;
  font-size: 0.7rem;
  font-weight: 600;
  font-family: var(--md-font-sans);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  background: rgba(250, 249, 247, 0.94);
  color: var(--md-ink);
  border-radius: var(--md-radius-pill);
  border: 1px solid rgba(255, 255, 255, 0.5);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.morphing_dialog_body {
  padding: 2rem 2.25rem 2.25rem;
}

.morphing_dialog_header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 1.25rem;
  gap: 1rem;
}

.morphing_dialog_title_group {
  flex: 1;
  min-width: 0;
}

.morphing_dialog_meta_large {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.65rem;
}

.morphing_dialog_title_large {
  font-family: var(--md-font-display);
  font-size: 2rem;
  font-weight: 500;
  color: var(--md-ink);
  margin: 0 0 0.4rem 0;
  line-height: 1.15;
  letter-spacing: -0.03em;
}

.morphing_dialog_subtitle_large {
  font-size: 0.9375rem;
  color: var(--md-ink-muted);
  margin: 0 0 1rem 0;
  font-weight: 400;
}

.morphing_dialog_price_row_large {
  display: flex;
  align-items: baseline;
  gap: 0.65rem;
}

.morphing_dialog_price_large {
  font-family: var(--md-font-display);
  font-size: 1.85rem;
  font-weight: 500;
  color: var(--md-ink);
  letter-spacing: -0.02em;
}

.morphing_dialog_price_old_large {
  font-size: 1rem;
  color: var(--md-ink-muted);
  text-decoration: line-through;
}

.morphing_dialog_save {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--md-accent);
  background: var(--md-accent-soft);
  padding: 0.25rem 0.55rem;
  border-radius: 0;
}

.morphing_dialog_close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  background: var(--md-surface);
  border-radius: 0;
  color: var(--md-ink-soft);
  cursor: pointer;
  border: 1px solid var(--md-border-strong);
  transition:
    background 300ms var(--md-ease),
    color 300ms var(--md-ease),
    border-color 300ms var(--md-ease),
    transform 300ms var(--md-ease);
  flex-shrink: 0;
}

.morphing_dialog_close:hover {
  background: var(--md-ink);
  color: var(--md-surface);
  border-color: var(--md-ink);
  transform: rotate(90deg);
}

.morphing_dialog_close:focus {
  outline: none;
}

.morphing_dialog_close:focus-visible {
  outline: 2px solid var(--md-accent);
  outline-offset: 2px;
}

.morphing_dialog_description {
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--md-ink-soft);
  margin-bottom: 1.75rem;
  max-width: 52ch;
}

/* Swatches */

.morphing_dialog_swatches {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1.75rem;
}

.morphing_dialog_swatches_label {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--md-ink-muted);
}

.morphing_dialog_swatch_list {
  display: flex;
  gap: 0.5rem;
}

.morphing_dialog_swatch {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 0;
  border: 2px solid transparent;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
  cursor: default;
  transition: transform 250ms var(--md-ease);
}

.morphing_dialog_swatch.is-active {
  box-shadow:
    inset 0 0 0 1px rgba(0, 0, 0, 0.08),
    0 0 0 2px var(--md-surface),
    0 0 0 3.5px var(--md-ink);
}

.morphing_dialog_swatch:hover {
  transform: scale(1.08);
}

/* Features */

.morphing_dialog_features {
  margin-bottom: 1.75rem;
  padding: 1.25rem;
  background: rgba(232, 228, 220, 0.45);
  border-radius: var(--md-radius-sm);
  border: 1px solid var(--md-border);
}

.morphing_dialog_features_title {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--md-ink-muted);
  margin-bottom: 0.85rem;
}

.morphing_dialog_features_list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.65rem 1rem;
}

.morphing_dialog_feature_item {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  padding: 0;
  border: none;
}

.morphing_dialog_feature_icon {
  width: 1.15rem;
  height: 1.15rem;
  flex-shrink: 0;
  color: var(--md-accent);
  margin-top: 0.1rem;
}

.morphing_dialog_feature_text {
  font-size: 0.8125rem;
  color: var(--md-ink-soft);
  line-height: 1.4;
}

/* Footer */

.morphing_dialog_footer {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding-top: 0.25rem;
}

.morphing_dialog_btn_secondary {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 1rem 1.35rem;
  font-size: 0.875rem;
  font-weight: 600;
  font-family: var(--md-font-sans);
  color: var(--md-ink);
  background: transparent;
  border: 1px solid var(--md-border-strong);
  border-radius: var(--md-radius-pill);
  cursor: pointer;
  transition:
    background 300ms var(--md-ease),
    border-color 300ms var(--md-ease);
}

.morphing_dialog_btn_secondary:hover {
  background: rgba(28, 25, 23, 0.04);
  border-color: var(--md-ink);
}

.morphing_dialog_btn_primary {
  flex: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 1rem 1.5rem;
  font-size: 0.875rem;
  font-weight: 600;
  font-family: var(--md-font-sans);
  color: #faf9f7;
  background: var(--md-accent);
  border: none;
  border-radius: var(--md-radius-pill);
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(61, 79, 63, 0.25);
  transition:
    background 300ms var(--md-ease),
    box-shadow 300ms var(--md-ease),
    transform 300ms var(--md-ease);
}

.morphing_dialog_btn_primary:hover {
  background: var(--md-accent-hover);
  box-shadow: 0 6px 20px rgba(61, 79, 63, 0.32);
  transform: translateY(-1px);
}

.morphing_dialog_btn_primary svg {
  width: 16px;
  height: 16px;
}

.morphing_dialog_ship_note {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin-top: 1rem;
  font-size: 0.75rem;
  color: var(--md-ink-muted);
}

.morphing_dialog_ship_note svg {
  width: 14px;
  height: 14px;
  color: var(--md-accent);
  flex-shrink: 0;
}

/* ============================================
   VIEW TRANSITIONS
   ============================================ */

@keyframes md-vt-fade-out {
  to {
    opacity: 0;
  }
}

@keyframes md-vt-fade-in {
  from {
    opacity: 0;
  }
}

::view-transition-old(root) {
  animation: 0.3s ease-out both md-vt-fade-out;
  mix-blend-mode: normal;
}

::view-transition-new(root) {
  animation: 0.3s ease-out both md-vt-fade-in;
  mix-blend-mode: normal;
}

::view-transition-group(dialog-bg),
::view-transition-group(product-image),
::view-transition-group(product-badge),
::view-transition-group(product-title),
::view-transition-group(product-subtitle),
::view-transition-group(product-price) {
  animation-duration: 0.45s;
  animation-timing-function: cubic-bezier(0.34, 1.15, 0.64, 1);
  z-index: 2;
}

::view-transition-image-pair(dialog-bg) {
  overflow: hidden;
  border-radius: var(--md-radius);
}

::view-transition-old(dialog-bg),
::view-transition-new(dialog-bg) {
  animation: none;
  mix-blend-mode: normal;
  height: 100%;
  width: 100%;
}

::view-transition-image-pair(product-image) {
  overflow: hidden;
  border-radius: var(--md-radius) var(--md-radius) 0 0;
}

::view-transition-old(product-image),
::view-transition-new(product-image) {
  animation: none;
  mix-blend-mode: normal;
  height: 100%;
  width: 100%;
  object-fit: cover;
  object-position: center;
}

::view-transition-old(product-badge),
::view-transition-new(product-badge),
::view-transition-old(product-title),
::view-transition-new(product-title),
::view-transition-old(product-subtitle),
::view-transition-new(product-subtitle),
::view-transition-old(product-price),
::view-transition-new(product-price) {
  animation-duration: 0.28s;
  animation-timing-function: cubic-bezier(0.34, 1.15, 0.64, 1);
  mix-blend-mode: normal;
  height: 100%;
  width: 100%;
  object-fit: contain;
  object-position: top left;
}

/* ============================================
   ACCESSIBILITY + RESPONSIVE
   ============================================ */

@media (prefers-reduced-motion: reduce) {
  .morphing_dialog_trigger,
  .morphing_dialog_trigger_bg,
  .morphing_dialog_close,
  .morphing_dialog_content,
  .morphing_dialog_content::backdrop,
  .morphing_dialog_cta,
  .morphing_dialog_btn_secondary,
  .morphing_dialog_btn_primary,
  .morphing_dialog_image img {
    animation: none !important;
    transition: none !important;
  }
}

@media (prefers-contrast: high) {
  .morphing_dialog_content_bg,
  .morphing_dialog_trigger_bg {
    border-width: 2px;
    border-color: var(--md-ink);
  }

  .morphing_dialog_trigger:focus-visible,
  .morphing_dialog_close:focus-visible {
    outline-width: 3px;
  }
}

@media (max-width: 768px) {
  .preview-container {
    padding: 2rem 1.25rem;
  }

  .morphing_dialog_trigger_bg {
    width: 100%;
    max-width: 340px;
  }

  .morphing_dialog_content_bg {
    width: 95vw;
    max-height: 92vh;
  }

  .morphing_dialog_image_large {
    height: 260px;
  }

  .morphing_dialog_body {
    padding: 1.5rem;
  }

  .morphing_dialog_title_large {
    font-size: 1.5rem;
  }

  .morphing_dialog_price_large {
    font-size: 1.5rem;
  }

  .morphing_dialog_features_list {
    grid-template-columns: 1fr;
  }

  .morphing_dialog_footer {
    flex-direction: column-reverse;
  }

  .morphing_dialog_btn_secondary,
  .morphing_dialog_btn_primary {
    width: 100%;
    flex: none;
  }
}
````

## Source — script.js
````javascript
/**
 * Morphing Dialog
 * Product card morphs into a native <dialog> via the View Transitions API.
 * Native dialog provides top-layer rendering, focus trap, ESC, and ::backdrop.
 */

(function () {
  "use strict";

  function setViewTransitionNames(elements) {
    elements.forEach(function (el) {
      if (el.dataset.anmMorphId) {
        el.style.viewTransitionName = el.dataset.anmMorphId;
      }
    });
  }

  function clearViewTransitionNames(elements) {
    elements.forEach(function (el) {
      el.style.viewTransitionName = "";
    });
  }

  function setDialogOnlyOpacity(dialogOnlyEls, opacity) {
    dialogOnlyEls.forEach(function (el) {
      el.style.opacity = opacity;
    });
  }

  function initMorphingDialog() {
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
      return;
    }

    const wrappers = document.querySelectorAll("[data-anm-morphing-dialog]");
    if (!wrappers.length) return;

    wrappers.forEach(function (wrapper) {
      const trigger = wrapper.querySelector("[data-anm-morph-trigger]");
      const dialog = wrapper.querySelector("[data-anm-morph-dialog]");

      if (!trigger || !dialog) return;

      if (typeof dialog.showModal !== "function") {
        console.warn(
          "[MorphingDialog] expected a native <dialog> with showModal() - got:",
          dialog.tagName
        );
        return;
      }

      const triggerMorphEls = trigger.querySelectorAll("[data-anm-morph-id]");
      const dialogMorphEls = dialog.querySelectorAll("[data-anm-morph-id]");
      const dialogOnlyEls = dialog.querySelectorAll("[data-anm-dialog-only]");

      // Hide dialog-only content until open
      setDialogOnlyOpacity(dialogOnlyEls, "0");

      function closeDialog() {
        if (!dialog.open) return;

        // Fallback without View Transitions API
        if (!document.startViewTransition) {
          dialog.close();
          trigger.style.opacity = "";
          setDialogOnlyOpacity(dialogOnlyEls, "0");
          return;
        }

        document
          .startViewTransition(function () {
            clearViewTransitionNames(dialogMorphEls);
            setViewTransitionNames(triggerMorphEls);
            dialog.close();
            trigger.style.opacity = "";
            setDialogOnlyOpacity(dialogOnlyEls, "0");
          })
          .finished
          .then(function () {
            if (!dialog.open) {
              clearViewTransitionNames(triggerMorphEls);
              wrapper.dispatchEvent(
                new CustomEvent("anm-morph-dialog-close", {
                  detail: { dialog: dialog },
                })
              );
            }
          })
          .catch(function () {
            clearViewTransitionNames(triggerMorphEls);
          });
      }

      function openDialog() {
        if (dialog.open) return;

        // Fallback without View Transitions API
        if (!document.startViewTransition) {
          dialog.showModal();
          trigger.style.opacity = "0";
          setDialogOnlyOpacity(dialogOnlyEls, "1");
          return;
        }

        setViewTransitionNames(triggerMorphEls);

        document
          .startViewTransition(function () {
            clearViewTransitionNames(triggerMorphEls);
            setViewTransitionNames(dialogMorphEls);
            dialog.showModal();
            trigger.style.opacity = "0";
            setDialogOnlyOpacity(dialogOnlyEls, "1");
          })
          .finished
          .then(function () {
            if (dialog.open) {
              wrapper.dispatchEvent(
                new CustomEvent("anm-morph-dialog-open", {
                  detail: { dialog: dialog },
                })
              );
            }
          })
          .catch(function () {
            /* transition aborted — leave state as-is */
          });
      }

      trigger.addEventListener("click", openDialog);

      // ESC closes with morph (native cancel is prevented so we animate)
      dialog.addEventListener("cancel", function (e) {
        e.preventDefault();
        closeDialog();
      });

      // Backdrop click (clicking the dialog element itself)
      dialog.addEventListener("click", function (e) {
        if (e.target === dialog) {
          closeDialog();
        }
      });

      dialog.querySelectorAll("[data-anm-morph-close]").forEach(function (btn) {
        btn.addEventListener("click", closeDialog);
      });
    });
  }

  function boot() {
    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", initMorphingDialog);
    } else {
      initMorphingDialog();
    }
  }

  boot();

  window.Anm = window.Anm || {};
  window.Anm.MorphingDialog = { refresh: initMorphingDialog };
})();
````
