May 30th

Animation Configurator — Customize our animation library with ease! Animation Configurator!

Notify me

Documentation

v1.9

Premium element

Core Background

Ambient Gradient

Transform your web space into a dynamic visual experience, reacting seamlessly to user interaction with smooth, fluid color transitions.

Quick Setup

data-ambient-gradient

Required

Add this attribute to enable the gradient effect

data-ambient-gradient-auto

Optional

Sets the gradient animation to automatic without mouse-over

Available Presets

data-ambient-gradient-preset="preset-name"

Optional

sunset

fresh

peach

pastel

sunrise

sunset

twilight

twilight

autumn

We're here to help

Choose how you'd like to connect with our support team

Contact Support

Get help from our team of experts

Response within 24 hours

<!DOCTYPE html>
<html lang="en">
<head>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">

  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Ambient Gradient Configurator</title>
  <style>
    :root {
  --background: #121212;
  --card-bg: #1e1e1e;
  --card-bg-hover: #252525;
  --text-primary: #f2f2f7;
  --text-secondary: #8e8e93;
  --accent: #ef6013;
  --accent-hover: #c64c0c;
  --border: #2c2c2e;
  --shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
  --track: #2c2c2e;
  --thumb: #ef6013;
  --card-radius: 16px;
  --input-radius: 8px;
  --button-radius: 12px;
  --transition: all 0.25s ease;
  --font: 'Inter', BlinkMacSystemFont, "San Francisco", "Helvetica Neue", Helvetica, Arial, sans-serif;
}

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

body {
  font-family: var(--font);
  background-color: var(--background);
  color: var(--text-primary);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.container {
  max-width: 100%;
  margin: 0 auto;
  padding: 2.5rem 1.5rem;
}

.content {
  display: flex;
  flex-wrap: wrap;
  gap: 2.5rem;
}

.preview-section {
  flex: 1;
  min-width: 300px;
}

.controls-section {
  flex: 1;
  min-width: 300px;
  max-width: 500px;
}

.card {
  background-color: var(--card-bg);
  border-radius: var(--card-radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  margin-bottom: 2rem;
  border: 1px solid var(--border);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.card:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4);
}

.preview-container {
  height: 500px;
  width: 100%;
  position: relative;
  overflow: hidden;
  border-radius: var(--card-radius);
  background-color: #000000;
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.preview-content {
  color: white;
  text-align: center;
  font-weight: bold;
  font-size: var(--text-s);
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
}

.card-heading {
  padding: 1.25rem 1.5rem;
  font-size: var(--text-s);
  font-weight: 600;
  border-bottom: 1px solid var(--border);
  letter-spacing: 0.3px;
}

.card-content {
  padding: 1.75rem;
}

.control-group {
  margin-bottom: 1.75rem;
}

.control-group:last-child {
  margin-bottom: 0;
}

.control-label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.75rem;
}

.label-text {
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.2px;
}

.value-text {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  background-color: rgba(50, 50, 50, 0.5);
  padding: 2px 8px;
  border-radius: 4px;
}

input[type="range"] {
  -webkit-appearance: none;
  width: 100%;
  height: 4px;
  background: var(--track);
  border-radius: 2px;
  outline: none;
  margin: 0.8rem 0;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  background: var(--thumb);
  border-radius: 50%;
  cursor: pointer;
  transition: var(--transition);
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
}

input[type="range"]::-webkit-slider-thumb:hover {
  transform: scale(1.1);
  box-shadow: 0 0 8px rgba(239, 96, 19, 0.5);
}

input[type="range"]::-moz-range-thumb {
  width: 18px;
  height: 18px;
  background: var(--thumb);
  border: none;
  border-radius: 50%;
  cursor: pointer;
  transition: var(--transition);
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
}

input[type="range"]::-moz-range-thumb:hover {
  transform: scale(1.1);
  box-shadow: 0 0 8px rgba(239, 96, 19, 0.5);
}

input[type="text"],
input[type="number"],
select {
  width: 100%;
  padding: 0.8rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--input-radius);
  font-family: var(--font);
  font-size: var(--text-xs);
  color: var(--text-primary);
  background-color: rgba(30, 30, 30, 0.7);
  margin-bottom: 0.75rem;
  outline: none;
  transition: var(--transition);
}

input[type="text"]:focus,
input[type="number"]:focus,
select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px rgba(239, 96, 19, 0.2);
}

.color-mode {
  display: flex;
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.radio-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  position: relative;
  padding-left: 1.5rem;
  font-size: var(--text-xs);
}

.radio-label input {
  position: absolute;
  opacity: 0;
  cursor: pointer;
}

.radio-checkmark {
  position: absolute;
  top: 2px;
  left: 0;
  height: 16px;
  width: 16px;
  background-color: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 50%;
}

.radio-label input:checked ~ .radio-checkmark {
  background-color: var(--card-bg);
  border-color: var(--accent);
}

.radio-checkmark:after {
  content: "";
  position: absolute;
  display: none;
}

.radio-label input:checked ~ .radio-checkmark:after {
  display: block;
  top: 3px;
  left: 3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

.color-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.8rem;
  margin-bottom: 1.2rem;
}

.color-input-group {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--input-radius);
  padding: 0.4rem;
  background-color: rgba(30, 30, 30, 0.7);
  transition: var(--transition);
}

.color-input-group:hover {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px rgba(239, 96, 19, 0.1);
}

.color-preview {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  width: 24px;
  height: 24px;
  border-radius: 4px;
  pointer-events: none;
}

input[type="color"] {
  -webkit-appearance: none;
  border: none;
  width: 100%;
  height: 24px;
  cursor: pointer;
  background-color: transparent;
}

input[type="color"]::-webkit-color-swatch-wrapper {
  padding: 0;
}

input[type="color"]::-webkit-color-swatch {
  border: none;
  border-radius: 4px;
}

input[type="color"]::-moz-color-swatch {
  border: none;
  border-radius: 4px;
}

.color-text {
  padding-left: 2.5rem;
  border: none;
  background-color: transparent;
  color: var(--text-secondary);
  font-size: 0.8rem;
  letter-spacing: 0.3px;
}

.color-text:focus {
  color: var(--text-primary);
  box-shadow: none;
}

.switch-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.2rem;
  padding: 0.5rem 0;
}

.switch-label {
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.2px;
}

.switch {
  position: relative;
  display: inline-block;
  width: 52px;
  height: 28px;
}

.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: var(--track);
  transition: var(--transition);
  border-radius: 34px;
}

.slider:before {
  position: absolute;
  content: "";
  height: 20px;
  width: 20px;
  left: 4px;
  bottom: 4px;
  background-color: #f2f2f7;
  transition: var(--transition);
  border-radius: 50%;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}

input:checked + .slider {
  background-color: var(--accent);
}

input:focus + .slider {
  box-shadow: 0 0 1px var(--accent);
}

input:checked + .slider:before {
  transform: translateX(24px);
}

.btn {
  display: block;
  width: 100%;
  padding: 1rem 1.5rem;
  background-color: var(--accent);
  color: white;
  font-family: var(--font);
  font-size: var(--text-xs);
  font-weight: 600;
  text-align: center;
  border: none;
  border-radius: var(--button-radius);
  cursor: pointer;
  transition: var(--transition);
  letter-spacing: 0.3px;
}

.btn:hover {
  background-color: var(--accent-hover);
  transform: translateY(-2px);
  box-shadow: 0 5px 15px rgba(239, 96, 19, 0.3);
}

.btn:active {
  transform: translateY(0);
  box-shadow: 0 2px 8px rgba(239, 96, 19, 0.2);
}

.instructions {
  background-color: var(--card-bg);
  padding: 1.75rem;
  border-radius: var(--card-radius);
  margin-bottom: 2rem;
  box-shadow: var(--shadow);
  border: 1px solid var(--border);
}

.instructions h3 {
  font-size: var(--text-s);
  margin-bottom: 1rem;
  color: var(--text-primary);
  font-weight: 600;
  letter-spacing: 0.3px;
}

.instructions ol {
  padding-left: 1.5rem;
}

.instructions li {
  margin-bottom: 0.75rem;
  font-size: var(--text-xs);
  color: var(--text-secondary);
  line-height: 1.6;
}

.instructions code {
  background-color: rgba(50, 50, 50, 0.5);
  padding: 0.2rem 0.5rem;
  border-radius: 4px;
  font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
  font-size: var(--text-xs);
  color: #ff8c51;
}

.instructions strong {
  font-weight: 500;
  color: var(--text-primary);
}

.notice {
  background-color: rgba(239, 96, 19, 0.08);
  color: #ff8c51;
  padding: 1rem 1.2rem;
  border-radius: var(--input-radius);
  font-size: var(--text-xs);
  margin-top: 1.5rem;
  border-left: 3px solid var(--accent);
  letter-spacing: 0.2px;
  line-height: 1.6;
}

.code-modal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.8);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
  visibility: hidden;
  opacity: 0;
  transition: all 0.3s ease;
  backdrop-filter: blur(5px);
}

.code-modal.active {
  visibility: visible;
  opacity: 1;
}

.modal-content {
  width: 90%;
  max-width: 1000px;
  max-height: 90vh;
  background-color: var(--card-bg);
  border-radius: var(--card-radius);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  overflow: hidden;
  transform: translateY(20px);
  transition: all 0.3s ease;
  border: 1px solid var(--border);
}

.code-modal.active .modal-content {
  transform: translateY(0);
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.25rem 1.5rem;
  border-bottom: 1px solid var(--border);
}

.modal-title {
  font-size: var(--text-s);
  font-weight: 600;
  letter-spacing: 0.3px;
}

.close-modal {
  background: none;
  border: none;
  font-size: var(--text-s);
  cursor: pointer;
  color: var(--text-secondary);
  transition: var(--transition);
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.close-modal:hover {
  color: var(--text-primary);
  background-color: rgba(255, 255, 255, 0.1);
}

.modal-body {
  padding: 1.75rem;
  overflow-y: auto;
  max-height: calc(90vh - 130px);
}

.code-display {
  background-color: #161616;
  color: #e4e4e4;
  border-radius: var(--card-radius);
  padding: 1.5rem;
  overflow-x: auto;
  font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
  font-size: var(--text-xs);
  line-height: 1.6;
  white-space: pre;
  margin-bottom: 1rem;
  max-height: 400px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid #252525;
}

.modal-footer {
  padding: 1.25rem 1.75rem;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: flex-end;
  gap: 1rem;
}

.copy-btn,
.download-file-btn {
  padding: 0.8rem 1.2rem;
  background-color: var(--accent);
  color: white;
  font-family: var(--font);
  font-size: var(--text-xs);
  font-weight: 500;
  border: none;
  border-radius: var(--button-radius);
  cursor: pointer;
  transition: var(--transition);
  letter-spacing: 0.2px;
}

.copy-btn:hover,
.download-file-btn:hover {
  background-color: var(--accent-hover);
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(239, 96, 19, 0.3);
}

.copy-btn:active,
.download-file-btn:active {
  transform: scale(0.98);
  box-shadow: 0 2px 8px rgba(239, 96, 19, 0.2);
}

.premium-card {
  margin-top: 2rem;
  border: 1px solid var(--border);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
  background: linear-gradient(145deg, #212121, #1e1e1e);
}

.premium-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
  border-color: rgba(239, 96, 19, 0.3);
}

.premium-badge {
  display: inline-block;
  background: linear-gradient(90deg, #ef6013, #ff8c51);
  color: white;
  font-size: var(--text-xs);
  padding: 0.3rem 0.7rem;
  border-radius: 6px;
  margin-right: 0.75rem;
  font-weight: 600;
  vertical-align: middle;
  letter-spacing: 0.3px;
  box-shadow: 0 2px 8px rgba(239, 96, 19, 0.3);
}

.premium-description {
  color: var(--text-secondary);
  font-size: var(--text-xs);
  margin-bottom: 1.5rem;
  line-height: 1.7;
  letter-spacing: 0.2px;
}

.feature-list {
  list-style: none;
  padding: 0;
  margin: 0 0 1.75rem 0;
}

.feature-list li {
  position: relative;
  padding-left: 1.75rem;
  font-size: var(--text-xs);
  color: var(--text-secondary);
  margin-bottom: 0.9rem;
  letter-spacing: 0.2px;
  line-height: 1.5;
}

.feature-list li:before {
  content: "✓";
  position: absolute;
  left: 0;
  color: var(--accent);
  font-weight: bold;
}

.premium-btn {
  background: linear-gradient(90deg, #ef6013, #ff8c51);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  letter-spacing: 0.3px;
}

.premium-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(239, 96, 19, 0.4);
}

.btn-icon {
  font-size: 1.1em;
}

.gradient-direction {
  position: relative;
  width: 100%;
  height: 150px;
  border-radius: var(--input-radius);
  border: 1px solid var(--border);
  margin-bottom: 1rem;
  cursor: pointer;
  overflow: hidden;
  background-color: rgba(30, 30, 30, 0.7);
}

.direction-marker {
  position: absolute;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background-color: var(--accent);
  transform: translate(-50%, -50%);
  z-index: 2;
  cursor: move;
  box-shadow: 0 2px 8px rgba(239, 96, 19, 0.4);
}

.direction-line {
  position: absolute;
  height: 2px;
  background-color: rgba(255, 255, 255, 0.5);
  transform-origin: left center;
  pointer-events: none;
  z-index: 1;
}

.direction-value {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  text-align: center;
  margin-top: 0.5rem;
}

.responsive-options {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.8rem;
}

.responsive-option {
  font-size: var(--text-xs);
  padding: 0.75rem;
  text-align: center;
  border: 1px solid var(--border);
  border-radius: var(--input-radius);
  cursor: pointer;
  transition: var(--transition);
  background-color: rgba(30, 30, 30, 0.7);
}

.responsive-option.active {
  background-color: var(--accent);
  color: white;
  border-color: var(--accent);
  box-shadow: 0 2px 8px rgba(239, 96, 19, 0.4);
}

@media (max-width: 768px) {
  .content {
    flex-direction: column;
  }

  .premium-card {
    margin-top: 1.5rem;
  }
  
  .preview-container {
    height: 350px;
  }
}

.copy-attribute {
  display: inline-flex;
  align-items: center;
  background-color: rgba(50, 50, 50, 0.5);
  padding: 0.2rem 0.5rem;
  border-radius: 4px;
  font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
  font-size: var(--text-xs);
  color: #ff8c51;
  cursor: pointer;
  transition: var(--transition);
  margin: 0 0.2rem;
}

.copy-attribute:hover {
  background-color: rgba(239, 96, 19, 0.2);
}

.copy-icon {
  margin-left: 0.5rem;
  font-size: 0.9em;
  opacity: 0.7;
}

.copy-attribute:hover .copy-icon {
  opacity: 1;
}
  </style>
</head>
<body>
  <div class="container">
    <div class="instructions">
      <h3>How to Use in Bricks Builder</h3>
      <ol>
        <li>Design your ambient gradient effect using the controls below</li>
        <li>Click the <strong>Get Code</strong> button and copy the JavaScript</li>
        <li>In Bricks Builder, add a <strong>Code</strong> element and paste the JavaScript</li>
        <li>Add the attribute <div class="copy-attribute" data-attribute="data-ambient-gradient">data-ambient-gradient<span class="copy-icon">📋</span></div> to any section you want to apply the effect to</li>
      </ol>
      <div class="notice">This tool creates a custom script with your settings built-in. You only need to add the data attribute to see your exact configuration!</div>
    </div>

    <div class="content">
      <section class="preview-section">
        <div class="preview-container" id="gradient-preview" data-ambient-gradient="true">
          <div class="preview-content"></div>
        </div>
        
        <div class="card premium-card">
          <div class="card-heading">
            <span class="premium-badge">BricksFusion Exclusive</span>
            Get Your Custom Gradient Effect
          </div>
          <div class="card-content">
            <p class="premium-description">Create stunning interactive gradient backgrounds for your Bricks Builder projects with this custom-crafted JavaScript snippet.</p>
            <ul class="feature-list">
              <li>Easy implementation with a single attribute</li>
              <li>Interactive mouse-follow or auto-animation modes</li>
              <li>Fully customizable colors and animations</li>
              <li>Works with any Bricks Builder section</li>
            </ul>
            <button class="btn premium-btn" id="download-btn" data-protection-animation="true">
              <span class="btn-icon">⚡</span>
              Get Instant Code
            </button>
          </div>
        </div>
      </section>

      <section class="controls-section">
        <div class="card">
          <div class="card-heading">Gradient Colors</div>
          <div class="card-content">
            <div class="control-group">
              <div class="control-label">
                <span class="label-text">Color Palette</span>
              </div>
              <div class="color-grid">
                <div class="color-input-group">
                  <input type="color" id="color1" value="#ee7752">
                  <input type="text" id="color1-text" class="color-text" value="#ee7752">
                </div>
                <div class="color-input-group">
                  <input type="color" id="color2" value="#e73c7e">
                  <input type="text" id="color2-text" class="color-text" value="#e73c7e">
                </div>
                <div class="color-input-group">
                  <input type="color" id="color3" value="#23a6d5">
                  <input type="text" id="color3-text" class="color-text" value="#23a6d5">
                </div>
                <div class="color-input-group">
                  <input type="color" id="color4" value="#23d5ab">
                  <input type="text" id="color4-text" class="color-text" value="#23d5ab">
                </div>
              </div>
            </div>
            
            <div class="control-group">
              <div class="control-label">
                <span class="label-text">Gradient Angle</span>
                <span class="value-text"><span id="angle-value">45</span>°</span>
              </div>
              <input type="range" id="gradient-angle" min="0" max="360" value="45">
            </div>
            
            <div class="control-group">
              <div class="control-label">
                <span class="label-text">Background Size</span>
                <span class="value-text"><span id="bg-size-value">400</span>%</span>
              </div>
              <input type="range" id="bg-size" min="100" max="800" value="400" step="50">
            </div>
          </div>
        </div>

        <div class="card">
          <div class="card-heading">Animation Settings</div>
          <div class="card-content">
            <div class="switch-container">
              <span class="switch-label">Auto Animation</span>
              <label class="switch">
                <input type="checkbox" id="auto-animate">
                <span class="slider"></span>
              </label>
            </div>
            
            <div id="auto-animation-settings">
              <div class="control-group">
                <div class="control-label">
                  <span class="label-text">Animation Speed</span>
                  <span class="value-text" id="auto-speed-value">0.005</span>
                </div>
                <input type="range" id="auto-speed" min="0.001" max="0.01" step="0.001" value="0.005">
              </div>
            </div>
            
            <div id="mouse-animation-settings">
              <div class="control-group">
                <div class="control-label">
                  <span class="label-text">Mouse Influence</span>
                  <span class="value-text" id="mouse-influence-value">100</span>%</span>
                </div>
                <input type="range" id="mouse-influence" min="0" max="100" value="100">
              </div>
              
              <div class="control-group">
                <div class="control-label">
                  <span class="label-text">Idle Animation Speed</span>
                  <span class="value-text" id="idle-speed-value">0.05</span>
                </div>
                <input type="range" id="idle-speed" min="0.01" max="0.2" step="0.01" value="0.05">
              </div>
            </div>
            
            <div class="control-group">
              <div class="control-label">
                <span class="label-text">Transition Smoothness</span>
                <span class="value-text" id="smoothness-value">0.5</span>s</span>
              </div>
              <input type="range" id="transition-smoothness" min="0" max="2" step="0.1" value="0.5">
            </div>
          </div>
        </div>

        <div class="card">
          <div class="card-heading">Advanced Options</div>
          <div class="card-content">
            <div class="control-group">
              <div class="control-label">
                <span class="label-text">Z-Index Position</span>
                <span class="value-text" id="z-index-value">1</span>
              </div>
              <input type="range" id="z-index" min="-10" max="10" value="1" step="1">
            </div>
            
            <div class="switch-container">
              <span class="switch-label">Keep Content Centered</span>
              <label class="switch">
                <input type="checkbox" id="center-content" checked>
                <span class="slider"></span>
              </label>
            </div>
            
            <div class="switch-container">
              <span class="switch-label">Border Radius Inherit</span>
              <label class="switch">
                <input type="checkbox" id="border-radius-inherit" checked>
                <span class="slider"></span>
              </label>
            </div>
          </div>
        </div>
      </section>
    </div>
  </div>

  <div class="code-modal" id="code-modal">
    <div class="modal-content">
      <div class="modal-header">
        <h3 class="modal-title">JavaScript Code</h3>
        <button class="close-modal" id="close-modal">×</button>
      </div>
      <div class="modal-body">
        <div class="code-display" id="js-code"></div>
      </div>
      <div class="modal-footer">
        <button class="copy-btn" id="copy-btn">Copy to Clipboard</button>
        <button class="download-file-btn" id="download-file-btn">Download JS File</button>
      </div>
    </div>
  </div>

  <script>
    document.addEventListener('DOMContentLoaded', function() {
      // Configuration object for the ambient gradient
      let gradientConfig = {
        colors: ['#ee7752', '#e73c7e', '#23a6d5', '#23d5ab'],
        angle: 45,
        backgroundSize: 400, // in percentage
        autoAnimate: false,
        autoSpeed: 0.005,
        mouseInfluence: 100, // in percentage
        idleSpeed: 0.05, 
        transitionSmoothness: 0.5, // in seconds
        zIndex: 1,
        centerContent: true,
        borderRadiusInherit: true
      };
      
      let activeGradient = null;
      
      function initAmbientGradient() {
        const sections = document.querySelectorAll('[data-ambient-gradient]:not([data-ambient-initialized="true"])');
        
        sections.forEach((section) => {
          // Get configuration from data attributes or use defaults
          const isAutoAnimate = section.hasAttribute('data-ambient-gradient-auto') || gradientConfig.autoAnimate;
          
          // Parse colors from data attributes or use defaults
          let colors = [];
          for (let i = 1; i <= 4; i++) {
            const colorAttr = `data-ambient-gradient-color${i}`;
            if (section.hasAttribute(colorAttr)) {
              colors.push(section.getAttribute(colorAttr));
            }
          }
          
          if (colors.length === 0) {
            colors = gradientConfig.colors;
          }
          
          // Get other configuration options from data attributes or use defaults
          const angle = section.hasAttribute('data-ambient-gradient-angle') 
            ? parseFloat(section.getAttribute('data-ambient-gradient-angle')) 
            : gradientConfig.angle;
            
          const bgSize = section.hasAttribute('data-ambient-gradient-size') 
            ? parseFloat(section.getAttribute('data-ambient-gradient-size')) 
            : gradientConfig.backgroundSize;
            
          const autoSpeed = section.hasAttribute('data-ambient-gradient-auto-speed') 
            ? parseFloat(section.getAttribute('data-ambient-gradient-auto-speed')) 
            : gradientConfig.autoSpeed;
            
          const mouseInfluence = section.hasAttribute('data-ambient-gradient-mouse-influence') 
            ? parseFloat(section.getAttribute('data-ambient-gradient-mouse-influence')) 
            : gradientConfig.mouseInfluence / 100; // Convert from percentage to decimal
            
          const idleSpeed = section.hasAttribute('data-ambient-gradient-idle-speed') 
            ? parseFloat(section.getAttribute('data-ambient-gradient-idle-speed')) 
            : gradientConfig.idleSpeed;
            
          const transitionSmoothness = section.hasAttribute('data-ambient-gradient-transition') 
            ? parseFloat(section.getAttribute('data-ambient-gradient-transition')) 
            : gradientConfig.transitionSmoothness;
            
          const zIndex = section.hasAttribute('data-ambient-gradient-z-index') 
            ? parseInt(section.getAttribute('data-ambient-gradient-z-index')) 
            : gradientConfig.zIndex;
            
          const centerContent = section.hasAttribute('data-ambient-gradient-center') 
            ? section.getAttribute('data-ambient-gradient-center') === 'true' 
            : gradientConfig.centerContent;
            
          const borderRadiusInherit = section.hasAttribute('data-ambient-gradient-border-inherit') 
            ? section.getAttribute('data-ambient-gradient-border-inherit') === 'true' 
            : gradientConfig.borderRadiusInherit;
            
          // Create configuration object for this specific section
          const options = {
            colors,
            angle,
            backgroundSize: bgSize,
            autoAnimate: isAutoAnimate,
            autoSpeed,
            mouseInfluence,
            idleSpeed,
            transitionSmoothness,
            zIndex,
            centerContent,
            borderRadiusInherit
          };
          
          // Setup state object for tracking mouse position and animation
          const state = {
            mouseX: 0.5,
            mouseY: 0.5,
            targetX: 0.5,
            targetY: 0.5,
            isMouseInside: false,
            isAutoAnimate: isAutoAnimate
          };
          
          // Setup the gradient element
          setupGradient(section, options);
          
          // Add event listeners for mouse interaction if not in auto mode
          if (!isAutoAnimate) {
            setupEventListeners(section, state, options);
          }
          
          // Start the animation
          startAnimation(section, state, options);
          
          // Mark as initialized
          section.dataset.ambientInitialized = 'true';
          
          // Store reference to active gradient for preview purposes
          if (section.id === 'gradient-preview') {
            activeGradient = {
              element: section,
              state,
              options
            };
            
            // Update the configuration to match
            gradientConfig = {
              colors: options.colors,
              angle: options.angle,
              backgroundSize: options.backgroundSize,
              autoAnimate: options.autoAnimate,
              autoSpeed: options.autoSpeed,
              mouseInfluence: options.mouseInfluence * 100, // Convert to percentage for UI
              idleSpeed: options.idleSpeed,
              transitionSmoothness: options.transitionSmoothness,
              zIndex: options.zIndex,
              centerContent: options.centerContent,
              borderRadiusInherit: options.borderRadiusInherit
            };
          }
        });
      }
      
      function setupGradient(element, options) {
        // Create gradient element
        const gradientElement = document.createElement('div');
        
        // Set positioning styles
        gradientElement.style.position = 'absolute';
        gradientElement.style.top = '0';
        gradientElement.style.left = '0';
        gradientElement.style.width = '100%';
        gradientElement.style.height = '100%';
        
        // Set gradient styles
        gradientElement.style.background = 'linear-gradient(' + options.angle + 'deg, ' + options.colors.join(', ') + ')';
        gradientElement.style.backgroundSize = options.backgroundSize + '% ' + options.backgroundSize + '%';
        gradientElement.style.transition = 'background-position ' + options.transitionSmoothness + 's ease-out';
        gradientElement.style.zIndex = options.zIndex;
        
        // Set border radius if inherit is enabled
        if (options.borderRadiusInherit) {
          gradientElement.style.borderRadius = 'inherit';
        }
        
        // Ensure parent element has the right positioning context
        const computedStyle = window.getComputedStyle(element);
        if (computedStyle.position === 'static') {
          element.style.position = 'relative';
        }
        
        // Insert gradient element as first child
        if (element.firstChild) {
          element.insertBefore(gradientElement, element.firstChild);
        } else {
          element.appendChild(gradientElement);
        }
        
        // Store reference to gradient element
        element.gradientElement = gradientElement;
        
        // If centerContent is true, center all child elements
        if (options.centerContent) {
          Array.from(element.children).forEach(child => {
            if (child !== gradientElement) {
              if (getComputedStyle(child).position === 'static') {
                child.style.position = 'relative';
              }
              child.style.zIndex = '1';
            }
          });
        }
      }
      
      function setupEventListeners(element, state, options) {
        // Mouse move event
        element.addEventListener('mousemove', (e) => {
          const rect = element.getBoundingClientRect();
          // Calculate mouse position as a percentage of element dimensions
          state.mouseX = (e.clientX - rect.left) / rect.width;
          state.mouseY = (e.clientY - rect.top) / rect.height;
          state.isMouseInside = true;
        });
        
        // Mouse leave event
        element.addEventListener('mouseleave', () => {
          state.isMouseInside = false;
          // Set random target for idle animation
          state.targetX = Math.random();
          state.targetY = Math.random();
        });
        
        // Mouse enter event
        element.addEventListener('mouseenter', () => {
          state.isMouseInside = true;
        });
        
        // Touch events for mobile
        element.addEventListener('touchmove', (e) => {
          e.preventDefault();
          const touch = e.touches[0];
          const rect = element.getBoundingClientRect();
          state.mouseX = (touch.clientX - rect.left) / rect.width;
          state.mouseY = (touch.clientY - rect.top) / rect.height;
          state.isMouseInside = true;
        }, { passive: false });
        
        element.addEventListener('touchend', () => {
          state.isMouseInside = false;
          state.targetX = Math.random();
          state.targetY = Math.random();
        });
        
        // Focus events for accessibility
        element.addEventListener('focus', () => {
          state.isMouseInside = true;
        });
        
        element.addEventListener('blur', () => {
          state.isMouseInside = false;
          state.targetX = Math.random();
          state.targetY = Math.random();
        });
      }
      
      function startAnimation(element, state, options) {
        let animationFrameId;
        let autoAnimateTime = 0;
        
        function updateGradient() {
          // Handle auto animation mode
          if (state.isAutoAnimate) {
            autoAnimateTime += options.autoSpeed;
            // Create circular motion using sine and cosine
            state.mouseX = (Math.sin(autoAnimateTime) + 1) / 2;
            state.mouseY = (Math.cos(autoAnimateTime * 0.8) + 1) / 2;
          } 
          // Handle mouse-based animation
          else if (!state.isMouseInside) {
            // Smoothly animate to random target when mouse is not in element
            state.mouseX += (state.targetX - state.mouseX) * options.idleSpeed;
            state.mouseY += (state.targetY - state.mouseY) * options.idleSpeed;
          }
          
          // Apply mouse influence
          const effectiveX = state.mouseX * options.mouseInfluence + 0.5 * (1 - options.mouseInfluence);
          const effectiveY = state.mouseY * options.mouseInfluence + 0.5 * (1 - options.mouseInfluence);
          
          // Update background position
          const posX = effectiveX * 100;
          const posY = effectiveY * 100;
          element.gradientElement.style.backgroundPosition = posX + '% ' + posY + '%';
        }
        
        // Animation loop
        function smoothUpdate() {
          updateGradient();
          animationFrameId = requestAnimationFrame(smoothUpdate);
        }
        
        // Start animation
        smoothUpdate();
        
        // Add intersection observer to pause animation when not visible
        const observer = new IntersectionObserver((entries) => {
          entries.forEach(entry => {
            if (entry.isIntersecting) {
              // Resume animation when visible
              if (!animationFrameId) {
                smoothUpdate();
              }
            } else {
              // Pause animation when not visible
              if (animationFrameId) {
                cancelAnimationFrame(animationFrameId);
                animationFrameId = null;
              }
            }
          });
        }, { threshold: 0 });
        
        observer.observe(element);
        
        // Store cleanup function
        element._cleanupGradient = () => {
          if (animationFrameId) {
            cancelAnimationFrame(animationFrameId);
          }
          observer.disconnect();
          if (element.gradientElement && element.gradientElement.parentNode) {
            element.gradientElement.parentNode.removeChild(element.gradientElement);
          }
          element.dataset.ambientInitialized = 'false';
        };
      }
      
      function updateGradientPreview() {
        const preview = document.getElementById('gradient-preview');
        
        if (!preview) return;
        
        // If not initialized, initialize it
        if (preview.dataset.ambientInitialized !== 'true') {
          initAmbientGradient();
          return;
        }
        
        // If we have an active gradient, clean it up
        if (preview._cleanupGradient) {
          preview._cleanupGradient();
        }
        
        // Set data attributes based on current configuration
        preview.setAttribute('data-ambient-gradient', 'true');
        
        // Set auto animation attribute
        if (gradientConfig.autoAnimate) {
          preview.setAttribute('data-ambient-gradient-auto', 'true');
        } else {
          preview.removeAttribute('data-ambient-gradient-auto');
        }
        
        // Set colors
        for (let i = 0; i < gradientConfig.colors.length; i++) {
          preview.setAttribute(`data-ambient-gradient-color${i+1}`, gradientConfig.colors[i]);
        }
        
        // Set other attributes
        preview.setAttribute('data-ambient-gradient-angle', gradientConfig.angle);
        preview.setAttribute('data-ambient-gradient-size', gradientConfig.backgroundSize);
        preview.setAttribute('data-ambient-gradient-auto-speed', gradientConfig.autoSpeed);
        preview.setAttribute('data-ambient-gradient-mouse-influence', gradientConfig.mouseInfluence / 100);
        preview.setAttribute('data-ambient-gradient-idle-speed', gradientConfig.idleSpeed);
        preview.setAttribute('data-ambient-gradient-transition', gradientConfig.transitionSmoothness);
        preview.setAttribute('data-ambient-gradient-z-index', gradientConfig.zIndex);
        preview.setAttribute('data-ambient-gradient-center', gradientConfig.centerContent);
        preview.setAttribute('data-ambient-gradient-border-inherit', gradientConfig.borderRadiusInherit);
        
        // Reinitialize
        initAmbientGradient();
      }
      
      function generateJavaScriptCode() {
        // Create an array of colors
        const colors = [];
        for (let i = 1; i <= 4; i++) {
          colors.push(document.getElementById(`color${i}`).value);
        }
        
        // Get other configuration values
        const angle = document.getElementById('gradient-angle').value;
        const bgSize = document.getElementById('bg-size').value;
        const autoAnimate = document.getElementById('auto-animate').checked;
        const autoSpeed = document.getElementById('auto-speed').value;
        const mouseInfluence = document.getElementById('mouse-influence').value / 100; // Convert to decimal
        const idleSpeed = document.getElementById('idle-speed').value;
        const transitionSmoothness = document.getElementById('transition-smoothness').value;
        const zIndex = document.getElementById('z-index').value;
        const centerContent = document.getElementById('center-content').checked;
        const borderRadiusInherit = document.getElementById('border-radius-inherit').checked;
        
        return "(function() {\n" +
        "  // Configuration object for ambient gradient\n" +
        "  const defaultConfig = {\n" +
        "    colors: " + JSON.stringify(colors) + ",\n" +
        "    angle: " + angle + ",\n" +
        "    backgroundSize: " + bgSize + ",\n" +
        "    autoAnimate: " + autoAnimate + ",\n" +
        "    autoSpeed: " + autoSpeed + ",\n" +
        "    mouseInfluence: " + mouseInfluence + ",\n" +
        "    idleSpeed: " + idleSpeed + ",\n" +
        "    transitionSmoothness: " + transitionSmoothness + ",\n" +
        "    zIndex: " + zIndex + ",\n" +
        "    centerContent: " + centerContent + ",\n" +
        "    borderRadiusInherit: " + borderRadiusInherit + "\n" +
        "  };\n" +
        "  \n" +
        "  // Gradient preset colors (can be used as alternatives)\n" +
        "  const gradientPresets = {\n" +
        "    'sunset': ['#ee7752', '#e73c7e', '#23a6d5', '#23d5ab'],\n" +
        "    'fresh': ['#ff6b6b', '#4ecdc4', '#45b7d1', '#f7fff7'],\n" +
        "    'peach': ['#ff9a9e', '#fad0c4', '#ffecd2', '#fcb69f'],\n" +
        "    'pastel': ['#a8edea', '#fed6e3', '#f4d4d4', '#e2ebf0'],\n" +
        "    'lavender': ['#5ee7df', '#b490ca', '#8ea5eb', '#c3f5ef'],\n" +
        "    'spring': ['#d4fc79', '#96e6a1', '#66a6ff', '#89f7fe'],\n" +
        "    'sunrise': ['#fa709a', '#fee140', '#ffb199', '#fec84e'],\n" +
        "    'ocean': ['#43e97b', '#38f9d7', '#3f51b1', '#4a00e0'],\n" +
        "    'twilight': ['#8ec5fc', '#e0c3fc', '#fbc2eb', '#a6c1ee'],\n" +
        "    'autumn': ['#f6d365', '#fda085', '#fbc2eb', '#a6c1ee']\n" +
        "  };\n" +
        "  \n" +
        "  // Initialize ambient gradient on sections with data-ambient-gradient attribute\n" +
        "  function initAmbientGradient() {\n" +
        "    const sections = document.querySelectorAll('[data-ambient-gradient]:not([data-ambient-initialized=\"true\"])');\n" +
        "    \n" +
        "    sections.forEach((section) => {\n" +
        "      // Get configuration from data attributes or use defaults\n" +
        "      const isAutoAnimate = section.hasAttribute('data-ambient-gradient-auto') || defaultConfig.autoAnimate;\n" +
        "      \n" +
        "      // Parse colors from data attributes or use defaults\n" +
        "      let colors = [];\n" +
        "      for (let i = 1; i <= 4; i++) {\n" +
        "        const colorAttr = 'data-ambient-gradient-color' + i;\n" +
        "        if (section.hasAttribute(colorAttr)) {\n" +
        "          colors.push(section.getAttribute(colorAttr));\n" +
        "        }\n" +
        "      }\n" +
        "      \n" +
        "      // If no colors specified, check for preset or use default colors\n" +
        "      if (colors.length === 0) {\n" +
        "        const presetName = section.getAttribute('data-ambient-gradient-preset');\n" +
        "        colors = presetName && gradientPresets[presetName] \n" +
        "          ? gradientPresets[presetName] \n" +
        "          : defaultConfig.colors;\n" +
        "      }\n" +
        "      \n" +
        "      // Get other configuration options from data attributes or use defaults\n" +
        "      const angle = section.hasAttribute('data-ambient-gradient-angle') \n" +
        "        ? parseFloat(section.getAttribute('data-ambient-gradient-angle')) \n" +
        "        : defaultConfig.angle;\n" +
        "        \n" +
        "      const bgSize = section.hasAttribute('data-ambient-gradient-size') \n" +
        "        ? parseFloat(section.getAttribute('data-ambient-gradient-size')) \n" +
        "        : defaultConfig.backgroundSize;\n" +
        "        \n" +
        "      const autoSpeed = section.hasAttribute('data-ambient-gradient-auto-speed') \n" +
        "        ? parseFloat(section.getAttribute('data-ambient-gradient-auto-speed')) \n" +
        "        : defaultConfig.autoSpeed;\n" +
        "        \n" +
        "      const mouseInfluence = section.hasAttribute('data-ambient-gradient-mouse-influence') \n" +
        "        ? parseFloat(section.getAttribute('data-ambient-gradient-mouse-influence')) \n" +
        "        : defaultConfig.mouseInfluence;\n" +
        "        \n" +
        "      const idleSpeed = section.hasAttribute('data-ambient-gradient-idle-speed') \n" +
        "        ? parseFloat(section.getAttribute('data-ambient-gradient-idle-speed')) \n" +
        "        : defaultConfig.idleSpeed;\n" +
        "        \n" +
        "      const transitionSmoothness = section.hasAttribute('data-ambient-gradient-transition') \n" +
        "        ? parseFloat(section.getAttribute('data-ambient-gradient-transition')) \n" +
        "        : defaultConfig.transitionSmoothness;\n" +
        "        \n" +
        "      const zIndex = section.hasAttribute('data-ambient-gradient-z-index') \n" +
        "        ? parseInt(section.getAttribute('data-ambient-gradient-z-index')) \n" +
        "        : defaultConfig.zIndex;\n" +
        "        \n" +
        "      const centerContent = section.hasAttribute('data-ambient-gradient-center') \n" +
        "        ? section.getAttribute('data-ambient-gradient-center') === 'true' \n" +
        "        : defaultConfig.centerContent;\n" +
        "        \n" +
        "      const borderRadiusInherit = section.hasAttribute('data-ambient-gradient-border-inherit') \n" +
        "        ? section.getAttribute('data-ambient-gradient-border-inherit') === 'true' \n" +
        "        : defaultConfig.borderRadiusInherit;\n" +
        "      \n" +
        "      // Create configuration object for this specific section\n" +
        "      const options = {\n" +
        "        colors,\n" +
        "        angle,\n" +
        "        backgroundSize: bgSize,\n" +
        "        autoAnimate: isAutoAnimate,\n" +
        "        autoSpeed,\n" +
        "        mouseInfluence,\n" +
        "        idleSpeed,\n" +
        "        transitionSmoothness,\n" +
        "        zIndex,\n" +
        "        centerContent,\n" +
        "        borderRadiusInherit\n" +
        "      };\n" +
        "      \n" +
        "      // Setup state object for tracking mouse position and animation\n" +
        "      const state = {\n" +
        "        mouseX: 0.5,\n" +
        "        mouseY: 0.5,\n" +
        "        targetX: 0.5,\n" +
        "        targetY: 0.5,\n" +
        "        isMouseInside: false,\n" +
        "        isAutoAnimate: isAutoAnimate\n" +
        "      };\n" +
        "      \n" +
        "      // Setup the gradient element\n" +
        "      setupGradient(section, options);\n" +
        "      \n" +
        "      // Add event listeners for mouse interaction if not in auto mode\n" +
        "      if (!isAutoAnimate) {\n" +
        "        setupEventListeners(section, state, options);\n" +
        "      }\n" +
        "      \n" +
        "      // Start the animation\n" +
        "      startAnimation(section, state, options);\n" +
        "      \n" +
        "      // Mark as initialized\n" +
        "      section.dataset.ambientInitialized = 'true';\n" +
        "    });\n" +
        "  }\n" +
        "  \n" +
        "  function setupGradient(element, options) {\n" +
        "    // Create gradient element\n" +
        "    const gradientElement = document.createElement('div');\n" +
        "    \n" +
        "    // Set positioning styles\n" +
        "    gradientElement.style.position = 'absolute';\n" +
        "    gradientElement.style.top = '0';\n" +
        "    gradientElement.style.left = '0';\n" +
        "    gradientElement.style.width = '100%';\n" +
        "    gradientElement.style.height = '100%';\n" +
        "    \n" +
        "    // Set gradient styles\n" +
        "    gradientElement.style.background = 'linear-gradient(' + options.angle + 'deg, ' + options.colors.join(', ') + ')';\n" +
        "    gradientElement.style.backgroundSize = options.backgroundSize + '% ' + options.backgroundSize + '%';\n" +
        "    gradientElement.style.transition = 'background-position ' + options.transitionSmoothness + 's ease-out';\n" +
        "    gradientElement.style.zIndex = options.zIndex;\n" +
        "    \n" +
        "    // Set border radius if inherit is enabled\n" +
        "    if (options.borderRadiusInherit) {\n" +
        "      gradientElement.style.borderRadius = 'inherit';\n" +
        "    }\n" +
        "    \n" +
        "    // Ensure parent element has the right positioning context\n" +
        "    const computedStyle = window.getComputedStyle(element);\n" +
        "    if (computedStyle.position === 'static') {\n" +
        "      element.style.position = 'relative';\n" +
        "    }\n" +
        "    \n" +
        "    // Insert gradient element as first child\n" +
        "    if (element.firstChild) {\n" +
        "      element.insertBefore(gradientElement, element.firstChild);\n" +
        "    } else {\n" +
        "      element.appendChild(gradientElement);\n" +
        "    }\n" +
        "    \n" +
        "    // Store reference to gradient element\n" +
        "    element.gradientElement = gradientElement;\n" +
        "    \n" +
        "    // If centerContent is true, ensure all child elements are above the gradient\n" +
        "    if (options.centerContent) {\n" +
        "      Array.from(element.children).forEach(child => {\n" +
        "        if (child !== gradientElement) {\n" +
        "          if (getComputedStyle(child).position === 'static') {\n" +
        "            child.style.position = 'relative';\n" +
        "          }\n" +
        "          child.style.zIndex = '1';\n" +
        "        }\n" +
        "      });\n" +
        "    }\n" +
        "  }\n" +
        "  \n" +
        "  function setupEventListeners(element, state, options) {\n" +
        "    // Mouse move event\n" +
        "    element.addEventListener('mousemove', (e) => {\n" +
        "      const rect = element.getBoundingClientRect();\n" +
        "      state.mouseX = (e.clientX - rect.left) / rect.width;\n" +
        "      state.mouseY = (e.clientY - rect.top) / rect.height;\n" +
        "      state.isMouseInside = true;\n" +
        "    });\n" +
        "    \n" +
        "    // Mouse leave event\n" +
        "    element.addEventListener('mouseleave', () => {\n" +
        "      state.isMouseInside = false;\n" +
        "      state.targetX = Math.random();\n" +
        "      state.targetY = Math.random();\n" +
        "    });\n" +
        "    \n" +
        "    // Mouse enter event\n" +
        "    element.addEventListener('mouseenter', () => {\n" +
        "      state.isMouseInside = true;\n" +
        "    });\n" +
        "    \n" +
        "    // Touch events for mobile\n" +
        "    element.addEventListener('touchmove', (e) => {\n" +
        "      e.preventDefault();\n" +
        "      const touch = e.touches[0];\n" +
        "      const rect = element.getBoundingClientRect();\n" +
        "      state.mouseX = (touch.clientX - rect.left) / rect.width;\n" +
        "      state.mouseY = (touch.clientY - rect.top) / rect.height;\n" +
        "      state.isMouseInside = true;\n" +
        "    }, { passive: false });\n" +
        "    \n" +
        "    element.addEventListener('touchend', () => {\n" +
        "      state.isMouseInside = false;\n" +
        "      state.targetX = Math.random();\n" +
        "      state.targetY = Math.random();\n" +
        "    });\n" +
        "    \n" +
        "    // Focus events for accessibility\n" +
        "    element.addEventListener('focus', () => {\n" +
        "      state.isMouseInside = true;\n" +
        "    });\n" +
        "    \n" +
        "    element.addEventListener('blur', () => {\n" +
        "      state.isMouseInside = false;\n" +
        "      state.targetX = Math.random();\n" +
        "      state.targetY = Math.random();\n" +
        "    });\n" +
        "  }\n" +
        "  \n" +
        "  function startAnimation(element, state, options) {\n" +
        "    let animationFrameId;\n" +
        "    let autoAnimateTime = 0;\n" +
        "    \n" +
        "    function updateGradient() {\n" +
        "      // Handle auto animation mode\n" +
        "      if (state.isAutoAnimate) {\n" +
        "        autoAnimateTime += options.autoSpeed;\n" +
        "        state.mouseX = (Math.sin(autoAnimateTime) + 1) / 2;\n" +
        "        state.mouseY = (Math.cos(autoAnimateTime * 0.8) + 1) / 2;\n" +
        "      } \n" +
        "      // Handle mouse-based animation\n" +
        "      else if (!state.isMouseInside) {\n" +
        "        state.mouseX += (state.targetX - state.mouseX) * options.idleSpeed;\n" +
        "        state.mouseY += (state.targetY - state.mouseY) * options.idleSpeed;\n" +
        "      }\n" +
        "      \n" +
        "      // Apply mouse influence\n" +
        "      const effectiveX = state.mouseX * options.mouseInfluence + 0.5 * (1 - options.mouseInfluence);\n" +
        "      const effectiveY = state.mouseY * options.mouseInfluence + 0.5 * (1 - options.mouseInfluence);\n" +
        "      \n" +
        "      // Update background position\n" +
        "      const posX = effectiveX * 100;\n" +
        "      const posY = effectiveY * 100;\n" +
        "      element.gradientElement.style.backgroundPosition = posX + '% ' + posY + '%';\n" +
        "    }\n" +
        "    \n" +
        "    // Animation loop\n" +
        "    function smoothUpdate() {\n" +
        "      updateGradient();\n" +
        "      animationFrameId = requestAnimationFrame(smoothUpdate);\n" +
        "    }\n" +
        "    \n" +
        "    // Start animation\n" +
        "    smoothUpdate();\n" +
        "    \n" +
        "    // Add intersection observer to pause animation when not visible\n" +
        "    const observer = new IntersectionObserver((entries) => {\n" +
        "      entries.forEach(entry => {\n" +
        "        if (entry.isIntersecting) {\n" +
        "          // Resume animation when visible\n" +
        "          if (!animationFrameId) {\n" +
        "            smoothUpdate();\n" +
        "          }\n" +
        "        } else {\n" +
        "          // Pause animation when not visible\n" +
        "          if (animationFrameId) {\n" +
        "            cancelAnimationFrame(animationFrameId);\n" +
        "            animationFrameId = null;\n" +
        "          }\n" +
        "        }\n" +
        "      });\n" +
        "    }, { threshold: 0 });\n" +
        "    \n" +
        "    observer.observe(element);\n" +
        "    \n" +
        "    // Store cleanup function\n" +
        "    element._cleanupGradient = () => {\n" +
        "      if (animationFrameId) {\n" +
        "        cancelAnimationFrame(animationFrameId);\n" +
        "      }\n" +
        "      observer.disconnect();\n" +
        "      if (element.gradientElement && element.gradientElement.parentNode) {\n" +
        "        element.gradientElement.parentNode.removeChild(element.gradientElement);\n" +
        "      }\n" +
        "      element.dataset.ambientInitialized = 'false';\n" +
        "    };\n" +
        "  }\n" +
        "  \n" +
        "  // Initialize on DOM content loaded\n" +
        "  if (document.readyState === 'loading') {\n" +
        "    document.addEventListener('DOMContentLoaded', initAmbientGradient);\n" +
        "  } else {\n" +
        "    initAmbientGradient();\n" +
        "  }\n" +
        "  \n" +
        "  // Initialize when new content is loaded in Bricks Builder\n" +
        "  document.addEventListener('bricks-lazy-load', initAmbientGradient);\n" +
        "})();\n" +
        "\n" +
        "/* \n" +
        "To use this effect in Bricks Builder:\n" +
        "1. Add this script to a Code element\n" +
        "2. Add the attribute data-ambient-gradient=\"true\" to any section where you want the effect to be applied\n" +
        "3. Optionally add data-ambient-gradient-auto=\"true\" for automatic animation without mouse interaction\n" +
        "*/";
      }
      
      function downloadJsFile() {
        const jsCode = generateJavaScriptCode();
        const blob = new Blob([jsCode], { type: 'application/javascript' });
        const url = URL.createObjectURL(blob);
        
        const a = document.createElement('a');
        a.href = url;
        a.download = 'ambient-gradient.js';
        a.click();
        
        URL.revokeObjectURL(url);
      }
      
      function initializeUI() {
        // Initialize the preview
        initAmbientGradient();
        
        // Setup color inputs
        const colorInputs = document.querySelectorAll('input[type="color"]');
        colorInputs.forEach(input => {
          const textInput = document.getElementById(`${input.id}-text`);
          
          // When color picker changes
          input.addEventListener('input', () => {
            textInput.value = input.value;
            updateColorConfiguration();
          });
          
          // When text input changes
          if (textInput) {
            textInput.addEventListener('input', () => {
              const isValidHex = /^#[0-9A-F]{6}$/i.test(textInput.value);
              if (isValidHex) {
                input.value = textInput.value;
                updateColorConfiguration();
              }
            });
            
            textInput.addEventListener('blur', () => {
              const isValidHex = /^#[0-9A-F]{6}$/i.test(textInput.value);
              if (!isValidHex) {
                textInput.value = input.value;
              }
            });
          }
        });
        
        // Setup range inputs
        const rangeInputs = document.querySelectorAll('input[type="range"]');
        rangeInputs.forEach(input => {
          const valueElement = document.getElementById(`${input.id}-value`);
          
          // Set initial value
          if (valueElement) {
            valueElement.textContent = input.value;
          }
          
          input.addEventListener('input', () => {
            if (valueElement) {
              valueElement.textContent = input.value;
            }
            
            // Update configuration based on the slider
            switch (input.id) {
              case 'gradient-angle':
                gradientConfig.angle = parseFloat(input.value);
                break;
              case 'bg-size':
                gradientConfig.backgroundSize = parseFloat(input.value);
                break;
              case 'auto-speed':
                gradientConfig.autoSpeed = parseFloat(input.value);
                break;
              case 'mouse-influence':
                gradientConfig.mouseInfluence = parseFloat(input.value);
                break;
              case 'idle-speed':
                gradientConfig.idleSpeed = parseFloat(input.value);
                break;
              case 'transition-smoothness':
                gradientConfig.transitionSmoothness = parseFloat(input.value);
                break;
              case 'z-index':
                gradientConfig.zIndex = parseInt(input.value);
                break;
            }
            
            // Update the preview
            updateGradientPreview();
          });
        });
        
        // Setup toggle switches
        document.getElementById('auto-animate').addEventListener('change', function() {
          gradientConfig.autoAnimate = this.checked;
          
          // Toggle visibility of animation settings
          document.getElementById('auto-animation-settings').style.display = 
            this.checked ? 'block' : 'none';
          document.getElementById('mouse-animation-settings').style.display = 
            this.checked ? 'none' : 'block';
          
          // Update the preview
          updateGradientPreview();
        });
        
        document.getElementById('center-content').addEventListener('change', function() {
          gradientConfig.centerContent = this.checked;
          updateGradientPreview();
        });
        
        document.getElementById('border-radius-inherit').addEventListener('change', function() {
          gradientConfig.borderRadiusInherit = this.checked;
          updateGradientPreview();
        });
        
        // Setup initial visibility of animation settings
        document.getElementById('auto-animation-settings').style.display = 
          document.getElementById('auto-animate').checked ? 'block' : 'none';
        document.getElementById('mouse-animation-settings').style.display = 
          document.getElementById('auto-animate').checked ? 'none' : 'block';
        
        // Setup modal and download functionality
        const downloadBtn = document.getElementById('download-btn');
        const codeModal = document.getElementById('code-modal');
        const closeModal = document.getElementById('close-modal');
        const copyBtn = document.getElementById('copy-btn');
        const downloadFileBtn = document.getElementById('download-file-btn');
        
        if (downloadBtn) {
          downloadBtn.addEventListener('click', () => {
            const jsCode = generateJavaScriptCode();
            document.getElementById('js-code').textContent = jsCode;
            codeModal.classList.add('active');
          });
        }
        
        if (closeModal) {
          closeModal.addEventListener('click', () => {
            codeModal.classList.remove('active');
          });
        }
        
        if (copyBtn) {
          copyBtn.addEventListener('click', () => {
            const jsCode = document.getElementById('js-code').textContent;
            copyAttributeToClipboard(jsCode, null);
          });
        }
        
        if (downloadFileBtn) {
          downloadFileBtn.addEventListener('click', downloadJsFile);
        }
        
        if (codeModal) {
          codeModal.addEventListener('click', (e) => {
            if (e.target === codeModal) {
              codeModal.classList.remove('active');
            }
          });
        }
        
        // Inicializar los event listeners para los elementos copiables
        initCopyAttributeListeners();
      }
      
      // Nueva función para inicializar los event listeners de los elementos copiables
      function initCopyAttributeListeners() {
  // Quitamos los console.log
  const copyAttributes = document.querySelectorAll('.copy-attribute');
  
  copyAttributes.forEach(el => {
    el.addEventListener('click', function(e) {
      e.preventDefault();
      const attribute = this.getAttribute('data-attribute');
      // También quitar este console.log si existe:
      // console.log("Copy attribute clicked: " + attribute);
      copyAttributeToClipboard(attribute, this);
    });
  });
}
      
      function updateColorConfiguration() {
        // Update the colors in the configuration
        const colors = [];
        for (let i = 1; i <= 4; i++) {
          colors.push(document.getElementById(`color${i}`).value);
        }
        
        gradientConfig.colors = colors;
        
        // Update the preview
        updateGradientPreview();
      }
      
      // Función para copiar atributos al portapapeles
      function copyAttributeToClipboard(attribute, element) {
        // Solo limpiar el atributo si es un atributo HTML y no el código JavaScript completo
        let textToCopy = attribute;
        
        // Si es un atributo HTML (comienza con "data-") y tiene element, extraer solo el nombre del atributo
        if (element && typeof attribute === 'string' && attribute.startsWith('data-')) {
          textToCopy = attribute.split('=')[0];
        }
        
        navigator.clipboard.writeText(textToCopy)
          .then(() => {
            // Añadir animación directamente sobre el elemento copiado
            if (element) {
              // Guardar el texto original
              const originalText = element.innerHTML;
              
              // Crear un span para el mensaje de "Copied!"
              const copiedSpan = document.createElement('span');
              copiedSpan.textContent = "Copied!";
              copiedSpan.style.cssText = 'position:absolute; top:0; left:0; width:100%; height:100%; display:flex; align-items:center; justify-content:center; background-color:rgba(239, 96, 19, 0.9); color:white; border-radius:4px; font-weight:bold; animation: fadeInOut 1.5s ease forwards;';
              
              // Añadir estilos de animación
              const style = document.createElement('style');
              style.textContent = `
                @keyframes fadeInOut {
                  0% { opacity: 0; }
                  10% { opacity: 1; }
                  80% { opacity: 1; }
                  100% { opacity: 0; }
                }
              `;
              document.head.appendChild(style);
              
              // Asegurar que el elemento tenga posición relativa para el posicionamiento absoluto
              element.style.position = 'relative';
              element.style.overflow = 'hidden';
              
              // Añadir el span al elemento
              element.appendChild(copiedSpan);
              
              // Eliminar el span después de que termine la animación
              setTimeout(() => {
                element.removeChild(copiedSpan);
                document.head.removeChild(style);
              }, 1500);
            }
            
            // Animación mejorada de feedback visual adicional (tooltip)
            const tooltip = document.createElement('div');
            tooltip.textContent = 'Copied to clipboard!';
            tooltip.style.cssText = 'position:fixed;padding:8px 16px;background:#333;color:white;border-radius:6px;font-size:14px;z-index:9999;transition:all 0.3s ease;opacity:0;transform:translateY(10px);box-shadow:0 4px 12px rgba(0,0,0,0.2);';
            document.body.appendChild(tooltip);
            
            // Position near cursor
            tooltip.style.top = (event.clientY + 20) + 'px';
            tooltip.style.left = (event.clientX + 10) + 'px';
            
            // Show with animation
            setTimeout(() => {
              tooltip.style.opacity = '1';
              tooltip.style.transform = 'translateY(0)';
              
              // Hide with animation
              setTimeout(() => {
                tooltip.style.opacity = '0';
                tooltip.style.transform = 'translateY(-10px)';
                
                // Remove from DOM
                setTimeout(() => {
                  document.body.removeChild(tooltip);
                }, 300);
              }, 1500);
            }, 10);
          })
          .catch(err => {
            console.error('Error copying: ', err);
          });
      }
      
      // Initialize the UI
      initializeUI();
    });
  </script>
</body>
</html>