<!DOCTYPE html>
<html lang="uk" data-valid="true">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Simple Preloader V1.0 – a preloader screen generator for Construct 2 and Construct 3 engines.</title>
<script>
(function() {
  'use strict';

  document.addEventListener('keydown', function(e) {
    if (e.key === 'F12' || 
        (e.ctrlKey && e.shiftKey && ['I', 'J', 'C'].includes(e.key)) ||
        (e.ctrlKey && e.key === 'u')) {
      e.preventDefault();
      e.stopImmediatePropagation();
    }
  }, true);


  document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
    e.stopImmediatePropagation();
  }, true);


  Object.defineProperty(window, 'console', {
    value: {},
    writable: false,
    configurable: false
  });


  setInterval(function() {
    const start = Date.now();
    debugger;
    if (Date.now() - start > 0.41) {

    }
  }, 0);
})();
</script>
    <link rel="stylesheet" href="css/all.min.css">
    
        :root {
            --primary: #0062ff;
            --secondary: #4caf50;
            --dark: #212529;
            --light: #f8f9fa;
            --success: #4cc9f0;
            --danger: #f72585;
            --active-bg: #e9ecef;
            --tab-height: 40px;
        }
        
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body {
            font-family: 'Segoe UI', system-ui, sans-serif !important;
            background-color: #f5f7fa;
            color: var(--dark);
            line-height: 1.6;
            max-width: 1800px;
            margin: 0 auto;
            padding: 10px;
            height: 100vh;
            display: flex;
            flex-direction: column;
			animation: fadeInStart 1s ease-in-out forwards;
        }
		@keyframes fadeInStart {
			from {
				opacity: 0;
			}
			to {
				opacity: 1;
			}
		}
        .app-container {
            display: grid;
            grid-template-columns: 1fr 350px;
            gap: 10px;
            flex: 1;
            min-height: 0;
        }
        
        /* Preview Area */
        .preview-area {
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
            display: flex;
            flex-direction: column;
            height: 100%;
            overflow:hidden;
			min-height:720px;
        }
        
        .preview-header {
            padding: 10px 15px;
            border-bottom: 1px solid #e2e8f0;
            flex-shrink: 0;
        }
        
        .preview-header h2,
        .settings-header h2 {
            font-size: 1.3rem;
        }
        
        .preview-container {
            position: relative;
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            background: white;
            overflow: hidden;
			
        }
		
        .preview-footer {
            padding: 10px;
            border-top: 1px solid #e2e8f0;
            flex-shrink: 0;
            display: flex;
            gap: 10px;
        }
        
        #preview-preloader {
            position: absolute;
            inset: 0;
            background: #3a0ca3;
            color: #fff;
            z-index: 9999;
            font-family: sans-serif;
			min-height:10vmin;
        }
        
        /* Settings Sidebar */
        .settings-sidebar {
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
            display: flex;
            flex-direction: column;
            height: 100%;
            min-height:270px;
        }
        
        .settings-header {
            padding: 10px 15px;
            border-bottom: 1px solid #e2e8f0;
            flex-shrink: 0;
        }
        
        .settings-tabs {
            display: flex;
            border-bottom: 1px solid #e2e8f0;
            flex-shrink: 0;
        }
        
        .settings-tab {
            padding: 10px 15px;
            cursor: pointer;
            border-bottom: 2px solid transparent;
            transition: all 0.2s;
            font-size: 14px;
			font-weight: 500;
        }
        
        .settings-tab.active {
            border-bottom-color: var(--primary);
            color: var(--primary);
        }
        
        .settings-content {
            flex: 1;
            overflow-y: auto;
            padding: 15px;
        }
        
        .settings-group {
            margin-bottom: 15px;
        }
        
        .settings-footer {
            padding: 10px;
            border-top: 1px solid #e2e8f0;
            flex-shrink: 0;
            display: flex;
            gap: 10px;
        }
        
        .form-control {
            margin-bottom: 15px;
        }
        
        .form-control label {
            display: block;
            margin-bottom: 5px;
            font-size: 14px;
            color: #495057;
        }
        
        .form-control input[type="text"],
        .form-control input[type="number"],
        .form-control select {
            width: 100%;
            padding: 8px 12px;
            border: 1px solid #ced4da;
            border-radius: 4px;
            font-size: 14px;
        }
        
        .form-control input[type="color"] {
            width: 100%;
            height: 40px;
            padding: 2px;
            border: 1px solid #ced4da;
            border-radius: 4px;
        }
        
        .form-control input[type="range"] {
            width: 100%;
        }
		
/* Додати після існуючих стилів для .form-control */
.gradient-control {
    transition: all 0.3s ease;
}
     
        .range-value {
            display: inline-block;
            margin-left: 10px;
            font-size: 14px;
            color: var(--secondary);
        }
        
        .position-grid {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 8px;
            margin-bottom: 15px;
        }
        
        .position-option {
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 8px;
            border: 1px solid #ced4da;
            border-radius: 4px;
            cursor: pointer;
            text-align: center;
            font-size: 12px;
        }
        
        .position-option.selected {
            border-color: var(--primary);
            background-color: rgba(67, 97, 238, 0.1);
        }
        
        .position-option i {
            font-size: 20px;
            margin-bottom: 4px;
        }
        
        /* Buttons */
        .btn {
            padding: 8px 12px;
            border-radius: 6px;
            border: none;
            font-size: 14px;
            cursor: pointer;
            transition: all 0.2s;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            flex: 1;
            white-space: nowrap;
        }
        
        .btn i {
            margin-right: 6px;
        }
        
        .btn-primary {
            background-color: var(--primary);
            color: white;
        }
        
        .btn-primary:hover {
            background-color: var(--secondary);
        }
        
        .btn-outline {
            background-color: transparent;
            border: 1px solid #ced4da;
            color: #495057;
        }
        
        .btn-outline:hover {
            background-color: #f1f3f5;
        }
        
        /* Preview elements styles */
        .preview-spinner-wrap {
            display: flex;
            align-items: center;
            justify-content: center;
            position: absolute;
        }
        
        .preview-spinner {
            width: 8vmin;
            height: 8vmin;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-shrink: 0;
			aspect-ratio: 1/1;
        }
        
        .preview-spinner-inner {
            width: 100%;
            height: 100%;
            aspect-ratio: 1/1;
            border: ${size/8}vmin solid rgba(255,255,255,.2);
            border-top: ${size/8}vmin solid #fff;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        
        .preview-progress-text {
            font-size: 2.5vmin;
            position: absolute;
			text-align:center;
        }
        
        .preview-logo {
            position: absolute;
        }
        
        @keyframes spin {
            to { transform: rotate(360deg); }
        }
        
        /* Додайте ці стилі в розділ CSS */
        input[type="range"] {
            -webkit-appearance: none;
            width: 100%;
            height: 8px;
            background: #e9ecef;
            border-radius: 4px;
            margin-top: 8px;
            background-image: linear-gradient(var(--primary), var(--primary));
            background-size: 0% 100%;
            background-repeat: no-repeat;
        }

        input[type="range"]::-webkit-slider-runnable-track {
            -webkit-appearance: none;
            box-shadow: none;
            border: none;
            background: transparent;
        }

        input[type="range"]::-moz-range-track {
            box-shadow: none;
            border: none;
            background: transparent;
        }

        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 18px;
            height: 18px;
            background: var(--primary);
            border-radius: 50%;
            cursor: pointer;
            position: relative;
            z-index: 1;
        }

        input[type="range"]::-moz-range-thumb {
            width: 18px;
            height: 18px;
            background: var(--primary);
            border-radius: 50%;
            cursor: pointer;
            position: relative;
            z-index: 1;
        }
		
/* Додати до існуючих стилів для .form-control */
.form-control label input[type="checkbox"] {
    margin-right: 8px;
    vertical-align: middle;
}
		
		
/* Pulse spinner */
.preview-spinner-pulse {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-color: currentColor;
    opacity: 1;
    animation: pulse 1.5s infinite ease-in-out;
    flex-shrink: 0;
}

@keyframes pulse {
    0%, 100% { transform: scale(0.8); opacity: 0.5; }
    50% { transform: scale(1.2); opacity: 1; }
}

/* Dots spinner */
.preview-spinner-dots {
    display: flex;
    align-items: center;
    justify-content: space-around;
    width: 100%;
    height: 100%;
}

.preview-spinner-dots span {
    width: 25%;
    height: 25%;
    background-color: currentColor;
    border-radius: 50%;
    display: inline-block;
    animation: dots-animation 1.4s infinite ease-in-out both;
    flex-shrink: 0;
}

.preview-spinner-dots span:nth-child(1) { animation-delay: -0.32s; }
.preview-spinner-dots span:nth-child(2) { animation-delay: -0.16s; }

@keyframes dots-animation {
    0%, 80%, 100% { transform: scale(0); } 
    40% { transform: scale(1); }
}






.preview-spinner-circle-pulse-ring {
  width: 100%;
  height: 100%;
  position: relative;
}

.preview-spinner-circle-pulse-ring div {
  position: absolute;
  width: 20%;
  height: 20%;
  background: currentColor;
  border-radius: 50%;
  animation: spin-circle-pulse-ring 2s linear infinite;
}

.preview-spinner-circle-pulse-ring div:nth-child(1) { top: 0; left: 40%; animation-delay: 0s; }
.preview-spinner-circle-pulse-ring div:nth-child(2) { top: 10%; left: 10%; animation-delay: -0.5s; }
.preview-spinner-circle-pulse-ring div:nth-child(3) { top: 40%; left: 0; animation-delay: -1s; }
.preview-spinner-circle-pulse-ring div:nth-child(4) { top: 70%; left: 10%; animation-delay: -1.5s; }
.preview-spinner-circle-pulse-ring div:nth-child(5) { top: 80%; left: 40%; animation-delay: -2s; }
.preview-spinner-circle-pulse-ring div:nth-child(6) { top: 70%; left: 70%; animation-delay: -2.5s; }
.preview-spinner-circle-pulse-ring div:nth-child(7) { top: 40%; left: 80%; animation-delay: -3s; }
.preview-spinner-circle-pulse-ring div:nth-child(8) { top: 10%; left: 70%; animation-delay: -3.5s; }

@keyframes spin-circle-pulse-ring {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.3; transform: scale(0.5); }
}





.preview-spinner-dual-line-ring {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  border: 0.25em solid transparent;
  border-top-color: currentColor;
  border-bottom-color: currentColor;
  border-radius: 50%;
  animation: spin-dual-line-ring 1.5s linear infinite;
}

@keyframes spin-dual-line-ring {
  to { transform: rotate(360deg); }
}



.preview-spinner-grid-pulse-blocks {
  width: 100%;
  height: 100%;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10%;
}

.preview-spinner-grid-pulse-blocks div {
  background-color: currentColor;
  border-radius: 2px;
  animation: pulse-grid-pb 1.2s infinite ease-in-out;
  width: 100%;
  height: 100%;
}

.preview-spinner-grid-pulse-blocks div:nth-child(1) { animation-delay: 0s; }
.preview-spinner-grid-pulse-blocks div:nth-child(2) { animation-delay: 0.2s; }
.preview-spinner-grid-pulse-blocks div:nth-child(3) { animation-delay: 0.4s; }
.preview-spinner-grid-pulse-blocks div:nth-child(4) { animation-delay: 0.2s; }
.preview-spinner-grid-pulse-blocks div:nth-child(5) { animation-delay: 0.4s; }
.preview-spinner-grid-pulse-blocks div:nth-child(6) { animation-delay: 0.6s; }
.preview-spinner-grid-pulse-blocks div:nth-child(7) { animation-delay: 0.4s; }
.preview-spinner-grid-pulse-blocks div:nth-child(8) { animation-delay: 0.6s; }
.preview-spinner-grid-pulse-blocks div:nth-child(9) { animation-delay: 0.8s; }

@keyframes pulse-grid-pb {
  0%, 100% { transform: scale(0.3); opacity: 0.5; }
  50% { transform: scale(1); opacity: 1; }
}



.preview-spinner-corner-pulse-dots {
  width: 100%;
  height: 100%;
  position: relative;
}

.preview-spinner-corner-pulse-dots div {
  position: absolute;
  width: 24%;
  height: 24%;
  background-color: currentColor;
  border-radius: 50%;
  animation: corner-pulse 1.2s linear infinite;
}

.preview-spinner-corner-pulse-dots div:nth-child(1) {
  top: 12%;
  left: 12%;
  animation-delay: 0s;
}
.preview-spinner-corner-pulse-dots div:nth-child(2) {
  top: 12%;
  right: 12%;
  animation-delay: -0.4s;
}
.preview-spinner-corner-pulse-dots div:nth-child(3) {
  bottom: 12%;
  left: 12%;
  animation-delay: -0.4s;
}
.preview-spinner-corner-pulse-dots div:nth-child(4) {
  bottom: 12%;
  right: 12%;
  animation-delay: -0.8s;
}

@keyframes corner-pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(0.5); }
}




.preview-spinner-bouncing-dots {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0; /* не використовуємо */
  width: 100%;
  height: 100%;
}

.preview-spinner-bouncing-dots div {
  width: 20%;
  aspect-ratio: 1 / 1;
  margin: 0 5%;
  border-radius: 50%;
  background-color: currentColor;
  animation: bounce-bdots 0.6s infinite alternate;
}

.preview-spinner-bouncing-dots div:nth-child(1) { animation-delay: 0s; }
.preview-spinner-bouncing-dots div:nth-child(2) { animation-delay: 0.1s; }
.preview-spinner-bouncing-dots div:nth-child(3) { animation-delay: 0.2s; }

@keyframes bounce-bdots {
  from { transform: translateY(0); }
  to   { transform: translateY(-30%); }
}



.preview-spinner-square-pulse-morph {
  width: 100%;
  height: 100%;
  background-color: currentColor;
  animation: morph-square-pulse 0.7s ease-in-out infinite alternate;
}

@keyframes morph-square-pulse {
  from { transform: scale(1); border-radius: 0; }
  to   { transform: scale(1.5); border-radius: 50%; }
}


.preview-spinner-grid-scale-squares {
  display: grid;
  grid-template-columns: repeat(2, 48%);
  gap: 4%;
  width: 100%;
  height: 100%;
}

.preview-spinner-grid-scale-squares div {
  width: 100%;
  aspect-ratio: 1 / 1;
  background-color: currentColor;
  animation: scale-grid-ssq 1s ease-in-out infinite;
}

.preview-spinner-grid-scale-squares div:nth-child(1) { animation-delay: 0.2s; }
.preview-spinner-grid-scale-squares div:nth-child(2) { animation-delay: 0.4s; }
.preview-spinner-grid-scale-squares div:nth-child(3) { animation-delay: 0.6s; }
.preview-spinner-grid-scale-squares div:nth-child(4) { animation-delay: 0.8s; }

@keyframes scale-grid-ssq {
  0%, 100% { transform: scale(1); }
  50%     { transform: scale(0.5); }
}


.preview-spinner-card-flip {
  width: 100%;
  height: 100%;
  perspective: 200px;
  position: relative;
}

.preview-spinner-card-flip .front,
.preview-spinner-card-flip .back {
  width: 100%;
  height: 100%;
  background-color: currentColor;
  backface-visibility: hidden;
  position: absolute;
  animation: flip-card-anim 1.5s ease-in-out infinite;
}

.preview-spinner-card-flip .back {
  transform: rotateY(180deg);
}

@keyframes flip-card-anim {
  0%, 100% { transform: rotateY(0deg); }
  50%     { transform: rotateY(180deg); }
}



.preview-spinner-bars-equalizer {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8%;
  width: 100%;
  height: 100%;
}

.preview-spinner-bars-equalizer div {
  width: 15%;
  height: 30%;
  background-color: currentColor;
  animation: bars-eq-grow 1s ease-in-out infinite;
}

.preview-spinner-bars-equalizer div:nth-child(2) { animation-delay: 0.1s; }
.preview-spinner-bars-equalizer div:nth-child(3) { animation-delay: 0.2s; }
.preview-spinner-bars-equalizer div:nth-child(4) { animation-delay: 0.3s; }

@keyframes bars-eq-grow {
  0%, 100% { height: 20%; }
  50%      { height: 80%; }
}





.preview-spinner-matrix-pulse-dots {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10%;
  width: 100%;
  height: 100%;
}

.preview-spinner-matrix-pulse-dots div {
  width: 100%;
  aspect-ratio: 1 / 1;
  background-color: currentColor;
  border-radius: 50%;
  animation: matrix-pulse 1.2s ease-in-out infinite;
}

.preview-spinner-matrix-pulse-dots div:nth-child(odd)  { animation-delay: 0s; }
.preview-spinner-matrix-pulse-dots div:nth-child(even) { animation-delay: 0.6s; }

@keyframes matrix-pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50%      { transform: scale(0.5); opacity: 0.5; }
}





.preview-spinner-dots-fade-trail {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12%;
  width: 100%;
  height: 100%;
}

.preview-spinner-dots-fade-trail div {
  width: 20%;
  aspect-ratio: 1 / 1;
  background-color: currentColor;
  border-radius: 50%;
  animation: fade-trail 1s ease-in-out infinite;
}

.preview-spinner-dots-fade-trail div:nth-child(2) { animation-delay: 0.2s; }
.preview-spinner-dots-fade-trail div:nth-child(3) { animation-delay: 0.4s; }

@keyframes fade-trail {
  0%, 100% { opacity: 0.3; }
  50%      { opacity: 1; }
}




.preview-spinner-double-ring-rotate {
  position: relative;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
}

.preview-spinner-double-ring-rotate .one,
.preview-spinner-double-ring-rotate .two {
  position: absolute;
  border: 0.25em solid transparent;
  border-radius: 50%;
  box-sizing: border-box;
}

.preview-spinner-double-ring-rotate .one {
  width: 100%;
  height: 100%;
  border-top-color: currentColor;
  animation: spin-double-ring-one 1s linear infinite;
}

.preview-spinner-double-ring-rotate .two {
  width: 60%;
  height: 60%;
  top: 20%;
  left: 20%;
  border-bottom-color: currentColor;
  animation: spin-double-ring-two 1.2s linear infinite reverse;
}

@keyframes spin-double-ring-one {
  to { transform: rotate(360deg); }
}
@keyframes spin-double-ring-two {
  to { transform: rotate(360deg); }
}





.preview-spinner-dots-circle-fade {
  width: 100%;
  height: 100%;
  position: relative;
}

.preview-spinner-dots-circle-fade div {
  position: absolute;
  width: 16%;
  height: 16%;
  background: currentColor;
  border-radius: 50%;
  top: 50%;
  left: 50%;
  margin-top: -8%; /* Половина висоти */
  margin-left: -8%; /* Половина ширини */
  transform-origin: center;
  animation: fade-dot-circle 1.2s ease-in-out infinite;
}

.preview-spinner-dots-circle-fade div:nth-child(1) {
  transform: rotate(0deg) translate(0, -240%);
  animation-delay: 0s;
}
.preview-spinner-dots-circle-fade div:nth-child(2) {
  transform: rotate(60deg) translate(0, -240%);
  animation-delay: 0.2s;
}
.preview-spinner-dots-circle-fade div:nth-child(3) {
  transform: rotate(120deg) translate(0, -240%);
  animation-delay: 0.4s;
}
.preview-spinner-dots-circle-fade div:nth-child(4) {
  transform: rotate(180deg) translate(0, -240%);
  animation-delay: 0.6s;
}
.preview-spinner-dots-circle-fade div:nth-child(5) {
  transform: rotate(240deg) translate(0, -240%);
  animation-delay: 0.8s;
}
.preview-spinner-dots-circle-fade div:nth-child(6) {
  transform: rotate(300deg) translate(0, -240%);
  animation-delay: 1s;
}

@keyframes fade-dot-circle {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}




.preview-spinner-double-dot-rotate {
    position: relative;
    width: 100%;
    height: 100%;
    animation: rotate-double-dot 1s linear infinite;
}

.preview-spinner-double-dot-rotate::before,
.preview-spinner-double-dot-rotate::after {
    content: '';
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    width: 25%;
    height: 25%;
    background: currentColor;
    border-radius: 50%;
}

.preview-spinner-double-dot-rotate::after {
    top: 50%;
}

@keyframes rotate-double-dot {
    to { transform: rotate(360deg); }
}




.preview-spinner-grid-expand-blocks {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10%;
    width: 100%;
    height: 100%;
}

.preview-spinner-grid-expand-blocks div {
    background-color: currentColor;
    width: 100%;
    height: 100%;
    animation: expand-grid-block 1s ease-in-out infinite;
}

.preview-spinner-grid-expand-blocks div:nth-child(odd) {
    animation-delay: 0s;
}
.preview-spinner-grid-expand-blocks div:nth-child(even) {
    animation-delay: 0.5s;
}

@keyframes expand-grid-block {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(0.5); }
}






.preview-spinner-sliding-bar {
    width: 100%;
    height: 20%;
    background: rgba(255, 255, 255, 0.3);
    position: relative;
    overflow: hidden;
    border-radius: 999px;
}

.preview-spinner-sliding-bar::before {
    content: '';
    position: absolute;
    left: -25%;
    width: 25%;
    height: 100%;
    background-color: currentColor;
    animation: move-sliding-bar 1s linear infinite;
}

@keyframes move-sliding-bar {
    to { left: 100%; }
}





.preview-spinner-ellipsis-dots {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 100%;
}

.preview-spinner-ellipsis-dots div {
    width: 20%;
    aspect-ratio: 1 / 1;
    margin: 0 5%;
    border-radius: 50%;
    background-color: currentColor;
    animation: ellipsis-fade 1.2s infinite ease-in-out;
    opacity: 0;
}

.preview-spinner-ellipsis-dots div:nth-child(2) { animation-delay: 0.2s; }
.preview-spinner-ellipsis-dots div:nth-child(3) { animation-delay: 0.4s; }

@keyframes ellipsis-fade {
    0%, 80%, 100% { opacity: 0; }
    40% { opacity: 1; }
}




.preview-spinner-border-pulse-ring {
    width: 100%;
    height: 100%;
    border: 12.5%;
    border-style: solid;
    border-color: currentColor;
    border-radius: 50%;
    animation: border-pulse-ring 1s ease-in-out infinite;
    box-sizing: border-box;
}

@keyframes border-pulse-ring {
    0%   {transform: scale(1); }
    50%  {transform: scale(0.8); }
    100% {transform: scale(1); }
}





.preview-spinner-radial-pulse-expand {
    border-radius: 50%;
    background-color: currentColor;
    animation: radial-expand 1.5s ease-out infinite;
    opacity: 0;
}
@keyframes radial-expand {
    0% {
        width: 0%;
        height: 0%;
        opacity: 1;
    }
    100% {
        width: 100%;
        height: 100%;
        opacity: 0;
    }
}




.preview-spinner-bouncing-dot-box {
    position: relative;
    width: 100%;
    height: 100%;
    border: 0.15em solid currentColor;
    box-sizing: border-box;
}

.preview-spinner-bouncing-dot-box div {
    position: absolute;
    width: 25%;
    height: 25%;
    background-color: currentColor;
    border-radius: 50%;
    animation: bounce-dot-box 1s ease-in-out infinite;
}

@keyframes bounce-dot-box {
    0%, 100% { top: 0%; left: 0%; }
    25% { top: 0%; left: 75%; }
    50% { top: 75%; left: 75%; }
    75% { top: 75%; left: 0%; }
}





.preview-spinner-morph-rotate-shape {
    width: 100%;
    height: 100%;
    background-color: currentColor;
    border-radius: 0%;
    animation: morph-rotate 1.2s ease-in-out infinite alternate;
}

@keyframes morph-rotate {
    0% {
        border-radius: 0%;
        transform: rotate(0deg);
    }
    100% {
        border-radius: 50%;
        transform: rotate(180deg);
    }
}




.preview-spinner-cube-3d-rotate {
    width: 100%;
    height: 100%;
    position: relative;
    transform-style: preserve-3d;
    animation: rotate-cube-3d 2s infinite linear;
}

.preview-spinner-cube-3d-rotate div {
    position: absolute;
    width: 90%;
    height: 90%;
    background-color: currentColor;
    border: 0.1em solid #fff;
}

.preview-spinner-cube-3d-rotate .front  { transform: translateZ(45%); }
.preview-spinner-cube-3d-rotate .back   { transform: rotateY(180deg) translateZ(45%); }
.preview-spinner-cube-3d-rotate .right  { transform: rotateY(90deg) translateZ(45%); }
.preview-spinner-cube-3d-rotate .left   { transform: rotateY(-90deg) translateZ(45%); }
.preview-spinner-cube-3d-rotate .top    { transform: rotateX(90deg) translateZ(45%); }
.preview-spinner-cube-3d-rotate .bottom { transform: rotateX(-90deg) translateZ(45%); }

@keyframes rotate-cube-3d {
    from { transform: rotateX(0deg) rotateY(0deg); }
    to { transform: rotateX(360deg) rotateY(360deg); }
}


@keyframes ripple-wave {
    0% {
        width: 0%;
        height: 0%;
        opacity: 1;
        transform: translate(-50%, -50%);
    }
    100% {
        width: 100%;
        height: 100%;
        opacity: 0;
        transform: translate(-50%, -50%);
    }
}


.preview-spinner-ripple-dual-waves {
    position: relative;
    width: 100%;
	height: 100%;
    aspect-ratio: 1 / 1;
}

.preview-spinner-ripple-dual-waves div {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 0%;
    height: 0%;
    border: 0.8vmin solid currentColor;
    background: transparent;
    border-radius: 50%;
    opacity: 0;
    animation: ripple-wave 1.5s infinite;
    box-sizing: border-box; /* ✅ ДОДАЙ ЦЕ */
}


.preview-spinner-ripple-dual-waves div:nth-child(2) {
    animation-delay: 0.75s;
}




.preview-spinner-bars-folding {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 10%;
    width: 100%;
    height: 100%;
}

.preview-spinner-bars-folding div {
    width: 20%;
    height: 100%;
    background-color: currentColor;
    transform-origin: bottom center;
    animation: fold-bars 1s ease-in-out infinite;
}

.preview-spinner-bars-folding div:nth-child(2) {
    animation-delay: 0.2s;
}
.preview-spinner-bars-folding div:nth-child(3) {
    animation-delay: 0.4s;
}

@keyframes fold-bars {
    0%, 100% { transform: scaleY(1); }
    50% { transform: scaleY(0.2); }
}




.preview-spinner-orbit-square {
    position: relative;
    width: 100%;
    height: 100%;
}

.preview-spinner-orbit-square div {
    position: absolute;
    width: 20%;
    height: 20%;
    border-radius: 50%;
    background: currentColor;
    animation: orbit-square-move 1.2s linear infinite;
}

.preview-spinner-orbit-square div:nth-child(2) {
    animation-delay: 0.6s;
}

@keyframes orbit-square-move {
    0%   { top: 0%;   left: 0%; }
    25%  { top: 0%;   left: 80%; }
    50%  { top: 80%;  left: 80%; }
    75%  { top: 80%;  left: 0%; }
    100% { top: 0%;   left: 0%; }
}





.preview-spinner-cube-bounce-2 {
    position: relative;
    width: 100%;
    height: 100%;
}

.preview-spinner-cube-bounce-2 div {
    position: absolute;
    width: 50%;
    height: 50%;
    background-color: currentColor;
    animation: cube-move-2 1.8s ease-in-out infinite;
}

.preview-spinner-cube-bounce-2 div:nth-child(2) {
    animation-delay: -0.9s;
}

@keyframes cube-move-2 {
    25%  { transform: translateX(100%); }
    50%  { transform: translateX(100%) translateY(100%); }
    75%  { transform: translateY(100%); }
    100% { transform: translateX(0%) translateY(0%); }
}




/* Progress bar spinner */
.preview-spinner-progress-bar {
    width: 100%;
    height: 100%;
    background-color: rgba(255,255,255,0.2);
    border-radius:2vmin;
    overflow: hidden;
    position: relative;
}

.preview-spinner-progress-bar-fill {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 30%; /* Початкове значення для прев'ю */
    background-color: currentColor;
    transition: width 0.3s ease;
}




.bg-color-control, .gradient-control {
    transition: all 0.3s ease;
}


.gradient-colors-container {
    display: flex;
    gap: 10px;
    margin-top: 8px;
}

.color-picker-group {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
}

.color-picker-group label {
    font-size: 12px;
    color: #495057;
}




.toast-close {
    background: none;
    border: none;
    color: white;
    cursor: pointer;
    font-size: 16px;
    opacity: 0.8;
    transition: opacity 0.2s;
    flex-shrink: 0;
    padding: 0;
    margin-left: 8px;
}

.toast-close:hover {
    opacity: 1;
}

/* Стилі для тоста */
.toast-content {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-right: 12px;
    overflow: hidden;
}

.toast-icon {
    font-size: 18px;
    flex-shrink: 0;
}

.toast-text {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}


		
        
        .progress-text {
            font-size: ${textSize}vmin;
            text-align:center;
        }
        
        .preloader-group {
            display: flex;
            gap: 4vmin;
            align-items: center;
			   width: auto;
        }
        
        .preloader-with-logo {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: ${logoGap}vmin;
        }
		
		
.google-font-control, .custom-font-control {
    transition: all 0.3s ease;
}


.header {
    display: flex;
    flex-wrap: wrap; /* Дозволяє переносити елементи на малих екранах */
    gap: 15px; /* Відступи між елементами при переносі */
    justify-content: space-between;
    align-items: center;
    padding: 15px 20px;
    background: white;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
    margin-bottom: 15px;
}

.header-brand {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-shrink: 0; /* Забороняє стискання */
    min-width: max-content; /* Мінімальна ширина по вмісту */
}

.header-icon {
    font-size: 24px;
    width: 40px;
    height: 40px;
    background: var(--primary);
    color: white;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: bold;
    flex-shrink: 0; /* Забороняє стискання */
    /*animation: spin 1.5s linear infinite;*/
}

@keyframes spin {
    to { transform: rotate(360deg); }
}

.header-title {
    font-size: 1.5rem;
    font-weight: bold;
    color: var(--dark);
    display: flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap; /* Забороняє переніс тексту */
}

.header-version {
    font-size: 0.9rem;
    color: #666;
    font-weight: normal;
}


        
        /* Responsive */
        @media (max-width: 768px) {
            .app-container {
                grid-template-columns: 1fr;
            }
            
            .position-option {
                padding: 6px;
            }
            
            .preview-header h2,
            .settings-header h2 {
                font-size: 1.1rem;
            }
			
    .header {
        justify-content: center; /* Центруємо елементи на малих екранах */
    }
	.header-title {font-size:1.3rem}
    

        .preview-area {
			min-height:640px;
        }

        }
		
@media (max-width: 480px) {
    .toast-message {
        width: calc(100% - 32px) !important;
        max-width: none !important;
        padding: 12px !important;
    }
    
    .toast-text {
        white-space: normal;
        font-size: 14px;
    }
    
    .toast-icon {
        font-size: 16px;
    }
    
    .toast-close {
        font-size: 14px;
    }
	
        .preview-area {
			min-height:480px;
        }
	
}
@media (max-width: 320px) {
	
        .preview-area {
			min-height:320px;
        }
	
}

#email-link {text-decoration:none; white-space:normal}
		
    
	<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <script src="js/jszip.min.js"></script>
	
</head>
<body oncontextmenu="return false" onselectstart="return false" ondragstart="return false">


<header class="header">
    <div class="header-brand">
        <div class="header-icon"><i class="fas fa-spinner"></i></div>
        <h1 class="header-title">
            Simple Preloader
            <span class="header-version">1.0</span>
        </h1>
    </div>
    
</header>




    <div class="app-container">
	
        <!-- Preview Area -->
        <div class="preview-area">
            <div class="preview-container">
                <div id="preview-preloader"></div>
            </div>
            <div class="preview-footer">
                    <a id="email-link" href="#" onclick="return false;" class="btn btn-outline"><i class="fas fa-copyright"></i>2025 Created by Taras kyrnasivskyj • All rights reserved • Contact Me</a>
            </div>
        </div>
        
        <!-- Settings Sidebar -->
        <div class="settings-sidebar">
            <div class="settings-header">
                <h2>Settings</h2>
            </div>
            
            <div class="settings-tabs" id="settings-tabs">
                <div class="settings-tab active" data-tab="colors">
                    <i class="fas fa-palette"></i> Colors
                </div>
                <div class="settings-tab" data-tab="spinner">
                    <i class="fas fa-spinner"></i> Spinner
                </div>
                <div class="settings-tab" data-tab="text">
                    <i class="fas fa-font"></i> Text
                </div>
                <div class="settings-tab" data-tab="logo">
                    <i class="fas fa-image"></i> Logo
                </div>
            </div>
            
<div class="settings-content" id="settings-content">
    <!-- Colors Tab -->
    <div class="settings-group" data-tab-content="colors">
        
        <div class="form-control">
            <label for="bg-type">Background Type</label>
            <select id="bg-type">
                <option value="color">Color</option>
                <option value="linear-gradient">Linear Gradient</option>
                <option value="radial-gradient">Radial Gradient</option>
            </select>
        </div>
    
        <div class="form-control bg-color-control">
            <label for="bg-color">Background Color</label>
            <input type="color" id="bg-color" value="#0062ff">
        </div>
        <div class="form-control spinner-track-color-control">
            <label for="spinner-track-color">Spinner Track Color</label>
            <input type="color" id="spinner-track-color" value="#4da9fe">
        </div>
        <div class="form-control">
            <label for="spinner-color">Spinner Color</label>
            <input type="color" id="spinner-color" value="#ffffff">
        </div>
        <div class="form-control">
            <label for="text-color">Text Color</label>
            <input type="color" id="text-color" value="#ffffff">
        </div>

        <div class="form-control gradient-control gradient-type-control" style="display:none;">
            <label>Gradient Colors</label>
            <div class="gradient-colors-container">
                <div class="color-picker-group">
                    <label>Start:</label>
                    <input type="color" class="gradient-color" data-index="0" value="#3a0ca3">
                </div>
                <div class="color-picker-group">
                    <label>Middle:</label>
                    <input type="color" class="gradient-color" data-index="1" value="#4361ee">
                </div>
                <div class="color-picker-group">
                    <label>End:</label>
                    <input type="color" class="gradient-color" data-index="2" value="#4cc9f0">
                </div>
            </div>
        </div>

        <div class="form-control gradient-control gradient-direction-control" style="display:none;">
            <label>Gradient Direction</label>
            <div class="position-grid" id="gradient-direction">
                <div class="position-option" data-pos="to top left" title="Top left"><span>↖</span> Top Left</div>
                <div class="position-option" data-pos="to top" title="Top"><span>↑</span>To Top</div>
                <div class="position-option" data-pos="to top right" title="Top right"><span>↗</span> Top Right</div>
                <div class="position-option" data-pos="to left" title="Left"><span>←</span> To Left</div>
                <div class="position-option" title="Center"><span>⟳</span> Reset</div>
                <div class="position-option" data-pos="to right" title="Right"><span>→</span> To Right</div>
                <div class="position-option" data-pos="to bottom left" title="Bottom left"><span>↙</span> Bottom Left</div>
                <div class="position-option" data-pos="to bottom" title="Bottom"><span>↓</span> To Bottom</div>
                <div class="position-option" data-pos="to bottom right" title="Bottom right"><span>↘</span> Bottom Right</div>
            </div>
        </div>

        
    </div>
    
    <!-- Spinner Tab -->
    <div class="settings-group" data-tab-content="spinner" style="display:none;">
    
    
        <div class="form-control" id="spinner-type-control">
            <label for="spinner-type">Spinner Type</label>
            <select id="spinner-type">
                <option value="circle">Classic Circular</option>
                <option value="progress-bar">Progress Bar</option>
                <option value="pulse">Pulsing Circle</option>
                <option value="dots">Fading Dots</option>
                
                <option value="circle-pulse-ring">Pulsing Dot Ring</option>
                <option value="dual-line-ring">Dual Ring</option>
                <option value="grid-pulse-blocks">Pulsing Grid</option>
                <option value="corner-pulse-dots">Pulsing Corner Dots</option>
                <option value="bouncing-dots">Bouncing Dots</option>
                <option value="square-pulse-morph">Pulsing Square</option>
                <option value="grid-scale-squares">Scaling Grid</option>
                <option value="card-flip">Flip Card</option>
                <option value="bars-equalizer">Equalizer (Pulsing Bars)</option>
                <option value="matrix-pulse-dots">Pulsing Dot Matrix</option>
                <option value="dots-fade-trail">Fading Dots (fade trail)</option>
                <option value="double-ring-rotate">Rotating Double Ring</option>
                <option value="dots-circle-fade">Circle Fading Dots</option>
                <option value="double-dot-rotate">Rotating Double Dot</option>
                <option value="grid-expand-blocks">Expanding Grid</option>
                <option value="sliding-bar">Sliding Bar</option>
                <option value="ellipsis-dots">Ellipsis</option>
                <option value="border-pulse-ring">Pulsing Border Ring</option>
                <option value="radial-pulse-expand">Radial Circle Expansion</option>
                <option value="bouncing-dot-box">Dot Bouncing in Box</option>
                <option value="morph-rotate-shape">Shape Morphing with Rotation</option>

                <option value="cube-3d-rotate">3D Rotating Cube</option>
                <option value="ripple-dual-waves">Dual Wave (Ripple)</option>
                <option value="bars-folding">Folding Vertical Bars</option>

                <option value="orbit-square">Orbital Dots (Square)</option>
                <option value="cube-bounce-2">Square Bouncing on Orbit</option>
            </select>
        </div>
        <div class="form-control">
            <label>Spinner Position</label>
            <div class="position-grid" id="spinner-position">
                <div class="position-option" data-pos="position-top-left"><span>↖</span> Top Left</div>
                <div class="position-option" data-pos="position-top-center"><span>↑</span> Top Center</div>
                <div class="position-option" data-pos="position-top-right"><span>↗</span> Top Right</div>
                <div class="position-option" data-pos="position-left-in-center"><span>← ●</span> Left In Center</div>
                <div class="position-option selected" data-pos="position-center"><span>●</span> Center</div>
                <div class="position-option" data-pos="position-right-in-center"><span>● →</span> Right In Center</div>
                <div class="position-option" data-pos="position-bottom-left"><span>↙</span> Bottom Left</div>
                <div class="position-option" data-pos="position-bottom-center"><span>↓</span> Bottom Center</div>
                <div class="position-option" data-pos="position-bottom-right"><span>↘</span> Bottom Right</div>
            </div>
        </div>
        <div class="form-control">
            <label for="spinner-size">Spinner Size</label>
            <input type="range" id="spinner-size" value="12" min="1" max="20" step="1">
        </div>
        <div class="form-control">
            <label for="spinner-speed">Animation Speed (sec)</label>
            <input type="range" id="spinner-speed" value="1" min="0.1" max="5" step="0.1">
        </div>
        <div class="form-control">
            <label for="spinner-gap">Gap Between Spinner and Text</label>
            <input type="range" id="spinner-gap" value="4" min="0" max="10" step="0.5">
        </div>
        
    </div>
    
    <!-- Text Tab -->
    <div class="settings-group" data-tab-content="text" style="display:none;">
        <div class="form-control" id="show-text-control">
            <label>
                <input type="checkbox" id="show-text" checked>
                Show Loading Text
            </label>
        </div>
        <div class="form-control">
            <label>Text Position</label>
            <div class="position-grid" id="text-position">
                <div class="position-option" data-pos="position-top-left"><span>↖</span> Top Left</div>
                <div class="position-option" data-pos="position-top-center"><span>↑</span> Top Center</div>
                <div class="position-option" data-pos="position-top-right"><span>↗</span> Top Right</div>
                <div class="position-option" data-pos="position-left-in-center"><span>← ●</span> Left In Center</div>
                <div class="position-option selected" data-pos="position-center"><span>●</span> Center</div>
                <div class="position-option" data-pos="position-right-in-center"><span>● →</span> Right In Center</div>
                <div class="position-option" data-pos="position-bottom-left"><span>↙</span> Bottom Left</div>
                <div class="position-option" data-pos="position-bottom-center"><span>↓</span> Bottom Center</div>
                <div class="position-option" data-pos="position-bottom-right"><span>↘</span> Bottom Right</div>
            </div>
        </div>
        <div class="form-control">
            <label for="text-content">Loading Text</label>
            <input type="text" id="text-content" value="Loading...">
        </div>
        <div class="form-control">
            <label for="text-size">Text Size</label>
            <input type="range" id="text-size" value="3.75" min="1" max="10" step="0.1">
        </div>
        <div class="form-control">
            <label for="font-source">Font Source:</label>
            <select id="font-source">
                <option value="system">System Font</option>
                <option selected value="google">Google Fonts</option>
                <option value="custom">Upload File</option>
            </select>
        </div>

        <div class="form-control google-font-control" style="display:block;">
            <label for="google-font-name">Google Font Name:</label>
            <input type="text" id="google-font-name" placeholder="Example: Roboto" value="Madimi One">
        </div>

        <div class="form-control custom-font-control" style="display:none;">
            <label for="font-upload">Upload Font:</label>
            <input type="file" id="font-upload" accept=".ttf,.woff,.woff2,.otf">
        </div>
    </div>
    
    <!-- Logo Tab -->
    <div class="settings-group" data-tab-content="logo" style="display:none;">
        <div class="form-control">
            <label>
                <input type="checkbox" id="show-logo" checked>
                Show Logo
            </label>
        </div>
        <div class="form-control">
            <label for="logo-upload">Upload Logo</label>
            <input type="file" id="logo-upload" accept="image/*">
        </div>
        <div class="form-control">
            <label for="logo-size">Logo Size</label>
            <input type="range" id="logo-size" value="20" min="5" max="50" step="1">
        </div>
        <div class="form-control">
            <label for="logo-border-radius">Logo Corner Radius (%)</label>
            <input type="range" id="logo-border-radius" value="0" min="0" max="50" step="1">
        </div>
        <div class="form-control">
            <label for="logo-gap">Logo Bottom Gap</label>
            <input type="range" id="logo-gap" value="6" min="0" max="20" step="0.5">
        </div>
    </div>
</div>

<div class="settings-footer">
    <button class="btn btn-outline" id="reset-btn">
        <i class="fas fa-undo"></i> Reset
    </button>
    <button class="btn btn-primary" id="copy-btn">
        <i class="fas fa-download"></i> Download
    </button>
</div>


<script>
(function() {
  // Список дозволених доменів
  const trustedDomains = [
    'buy-instant-html5games.com'
  ];

  const currentHost = window.location.hostname;

  // Спосіб 1: Перевірка локального середовища
  const isLocal = window.location.protocol === 'file:' || 
                 currentHost === 'localhost' || 
                 currentHost === '127.0.0.1' ||
                 currentHost === '';

  // Спосіб 2: Перевірка через Node (наприклад, Electron)
  const isNode = typeof process !== 'undefined' && 
                 typeof process.versions !== 'undefined' && 
                 typeof process.versions.node !== 'undefined';

  // Спосіб 3: Перевірка, чи хостинг дозволений
  const isTrustedHost = trustedDomains.includes(currentHost);

  const isHosted = !isLocal && !isNode && !isTrustedHost && 
                  currentHost !== '' && 
                  !currentHost.includes('.local');

  if (isHosted) {
    // ⚠️ Виявлено недозволене хостування — блокуємо
    document.body.innerHTML = `... (тут залишаєш свою існуючу розмітку) ...`;

    let count = 10;
    const timer = setInterval(() => {
      count--;
      const el = document.getElementById('countdown');
      if (el) el.textContent = count;
      if (count <= 0) {
        clearInterval(timer);
        document.body.innerHTML = '<h1 style="color:red">PAGE DESTROYED</h1>';
        document.open();
        document.close();
      }
    }, 1000);

    throw new Error("Hosting violation detected");
  }

  // Додатковий захист цілісності файлу
  if (!document.documentElement.hasAttribute('data-valid')) {
    document.body.innerHTML = '<h1 style="color:red">FILE TAMPERING DETECTED</h1>';
    throw new Error("File integrity check failed");
  }
})();
</script>


.demo-disabled {
    opacity: 0.6;
    cursor: not-allowed;
    background-color: #ccc !important;
}
.btn[disabled] {
    pointer-events: none;
    background-color: #ccc !important;
    color: #666 !important;
    cursor: not-allowed;
}


<script>
    document.addEventListener('DOMContentLoaded', function() {
	
	
// DEMO mode: block export
const isDemo = true;

if (isDemo) {
    const copyBtn = document.getElementById('copy-btn');
    copyBtn.disabled = true;
    copyBtn.style.opacity = 0.6;
    copyBtn.innerHTML = '<i class="fas fa-lock"></i> Buy to Export';
    copyBtn.addEventListener('click', function(e) {
        e.preventDefault();
        alert('This is a demo version. Purchase full access to export.');
    });
}


function hardObfuscate(code) {

  // Додаємо випадковий "сміттяний" код
  const junk = `var _0x${Math.random().toString(16).substr(2)}='junk';`;
  const encoded = btoa(unescape(encodeURIComponent(junk + code)));

  // 1. Кодуємо код у base64
  const base64 = btoa(unescape(encodeURIComponent(code)));
  
  // 2. Ділимо на частини та "перемішуємо"
  const parts = [
    base64.slice(0, 20),
    base64.slice(20, 40),
    base64.slice(40)
  ].reverse();
  
  // 3. Повертаємо обфускований код, який сам себе розшифровує
  return `
  (function() {
    const p = ['${parts.join("','")}'].reverse();
    const c = atob(p.join(''));
    eval(decodeURIComponent(escape(c)));
  })();
  `;
}


        // Tab switching
        const tabs = document.querySelectorAll('.settings-tab');
        tabs.forEach(tab => {
            tab.addEventListener('click', function() {
                tabs.forEach(t => t.classList.remove('active'));
                document.querySelectorAll('[data-tab-content]').forEach(c => c.style.display = 'none');
                
                this.classList.add('active');
                document.querySelector(`[data-tab-content="${this.dataset.tab}"]`).style.display = 'block';
            });
        });

        const rangeInputs = document.querySelectorAll('input[type="range"]');

        rangeInputs.forEach(input => {
            const updateRange = () => {
                const percent = (input.value - input.min) / (input.max - input.min) * 100;
                input.style.backgroundSize = `${percent}% 100%`;
            };
            updateRange();
            input.addEventListener('input', updateRange);
        });
        
        function isCenterPosition(pos) {
            return ['position-center', 'position-left-in-center', 'position-right-in-center'].includes(pos);
        }

        // Position selector
        function setupPositionSelector(selectorId) {
            const buttons = document.querySelectorAll(`#${selectorId} .position-option`);
            const isSpinner = selectorId === 'spinner-position';
            
            buttons.forEach(btn => {
                btn.addEventListener('click', function() {
                    const pos = this.dataset.pos;
                    const centerPositions = ['position-center', 'position-left-in-center', 'position-right-in-center'];
                    
                    const activeSpinnerPos = document.querySelector('#spinner-position .position-option.selected').dataset.pos;
                    const activeTextPos = document.querySelector('#text-position .position-option.selected').dataset.pos;
                    
                    const otherInCenter = isSpinner 
                        ? centerPositions.includes(activeTextPos)
                        : centerPositions.includes(activeSpinnerPos);
                    
                    if (pos === 'position-right-in-center' && otherInCenter) {
                        const otherSelector = isSpinner ? '#text-position' : '#spinner-position';
                        const otherBtn = document.querySelector(`${otherSelector} .position-option[data-pos="position-left-in-center"]`);
                        if (otherBtn) otherBtn.click();
                    } 
                    else if (pos === 'position-left-in-center' && otherInCenter) {
                        const otherSelector = isSpinner ? '#text-position' : '#spinner-position';
                        const otherBtn = document.querySelector(`${otherSelector} .position-option[data-pos="position-right-in-center"]`);
                        if (otherBtn) otherBtn.click();
                    }
                    else if (pos === 'position-center' && otherInCenter) {
                        const otherSelector = isSpinner ? '#text-position' : '#spinner-position';
                        const otherBtn = document.querySelector(`${otherSelector} .position-option[data-pos="position-center"]`);
                        if (otherBtn) otherBtn.click();
                    }
                    
                    buttons.forEach(b => b.classList.remove('selected'));
                    this.classList.add('selected');
                    
                    updatePreview();
                    updatePositionButtons();
                });
            });
        }


		// Gradient direction buttons handler
		const gradientDirectionButtons = document.querySelectorAll('#gradient-direction .position-option');
		gradientDirectionButtons.forEach(btn => {
			btn.addEventListener('click', function() {
				document.querySelectorAll('#gradient-direction .position-option').forEach(b => b.classList.remove('selected'));
				this.classList.add('selected');
				updatePreview();
			});
		});

		// Select default direction on load
		document.querySelector('#gradient-direction .position-option[data-pos="to right"]')?.classList.add('selected');

        setupPositionSelector('spinner-position');
        setupPositionSelector('text-position');

        // Input changes
        const inputs = document.querySelectorAll('input, select');
        inputs.forEach(input => {
            input.addEventListener('change', updatePreview);
            input.addEventListener('input', updatePreview);
        });

        // Generate template
        document.getElementById('copy-btn').addEventListener('click', downloadZip);
        document.getElementById('reset-btn').addEventListener('click', resetSettings);

        // Image handling
        const logoUpload = document.getElementById('logo-upload');
        
        logoUpload.addEventListener('change', function(e) {
            const file = e.target.files[0];
            if (file) {
                convertImageToBase64(file, function(base64) {
                    logoUpload.dataset.base64 = base64;
                    updatePreview();
                });
            }
        });
        

        // Initial preview
        updatePreview();

        function convertImageToBase64(file, callback) {
            const reader = new FileReader();
            reader.onload = function(e) {
                callback(e.target.result);
            };
            reader.readAsDataURL(file);
        }
		
		
function applyFontToPreview() {
    const fontSource = document.getElementById('font-source').value;
    const preview = document.getElementById('preview-preloader');
    
    // Видаляємо попередній стиль, якщо він є
    const oldStyle = document.getElementById('custom-font-style');
    if (oldStyle) oldStyle.remove();
    
    // Видаляємо попередній Google Fonts link
    const oldFontLink = document.querySelector('link[href*="fonts.googleapis.com"]');
    if (oldFontLink) oldFontLink.remove();

    if (fontSource === 'google') {
        const fontName = document.getElementById('google-font-name').value.trim();
        if (fontName) {
            // Додаємо Google Fonts
            const link = document.createElement('link');
            link.href = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(fontName)}&display=swap`;
            link.rel = 'stylesheet';
            document.head.appendChild(link);
            
            // Застосовуємо шрифт до прев'ю
            preview.style.fontFamily = `'${fontName}', sans-serif`;
        } else {
            preview.style.fontFamily = 'sans-serif';
        }
    }
    else if (fontSource === 'custom') {
        const fontFile = document.getElementById('font-upload').files[0];
        if (fontFile) {
            const fontName = fontFile.name.replace(/\.[^/.]+$/, "");
            const reader = new FileReader();
            
            reader.onload = function(e) {
                const style = document.createElement('style');
                style.id = 'custom-font-style';
                style.textContent = `
                    @font-face {
                        font-family: '${fontName}';
                        src: url(${e.target.result});
                        font-display: swap;
                    }
                `;
                document.head.appendChild(style);
                
                // Застосовуємо шрифт до прев'ю
                preview.style.fontFamily = `'${fontName}', sans-serif`;
            };
            
            reader.readAsDataURL(fontFile);
        } else {
            preview.style.fontFamily = 'sans-serif';
        }
    }
    else {
        // Системний шрифт
        preview.style.fontFamily = 'sans-serif';
    }
}
		

function updatePreview() {

	applyFontToPreview();

    const bgType = document.getElementById('bg-type')?.value || 'color';
    const gradientTypeControl = document.querySelector('.gradient-type-control');
    const gradientDirectionControl = document.querySelector('.gradient-direction-control');
    const bgColorControl = document.querySelector('.bg-color-control');
	



    if (bgType === 'color') {
        gradientTypeControl.style.display = 'none';
        gradientDirectionControl.style.display = 'none';
        bgColorControl.style.display = 'block';
    } else if (bgType === 'linear-gradient') {
        gradientTypeControl.style.display = 'block';
        gradientDirectionControl.style.display = 'block';
        bgColorControl.style.display = 'none';
    } else { // radial-gradient
        gradientTypeControl.style.display = 'block';
        gradientDirectionControl.style.display = 'none';
        bgColorControl.style.display = 'none';
    }

    const preview = document.getElementById('preview-preloader');
    const bgColor = document.getElementById('bg-color').value;
    const textColor = document.getElementById('text-color').value;
    const spinnerType = document.getElementById('spinner-type').value;
    const trackColorControl = document.querySelector('.spinner-track-color-control');
	
    const isProgressBar = spinnerType === 'progress-bar';
    
    // Автокорекція позиції для прогресбара
	if (isProgressBar) {
		const spinnerPos = document.querySelector('#spinner-position .position-option.selected').dataset.pos;
		const allowedPositions = ['position-center', 'position-top-center', 'position-bottom-center'];
		
		if (!allowedPositions.includes(spinnerPos)) {
			document.querySelector('#spinner-position .position-option[data-pos="position-center"]').click();
			return;
		}
	}
    
    // Показувати поле тільки для спінерів, які мають фон
    const spinnersWithTrack = ['circle', 'sliding-bar', 'progress-bar'];
    if (spinnersWithTrack.includes(spinnerType)) {
        trackColorControl.style.display = 'block';
    } else {
        trackColorControl.style.display = 'none';
    }
    
    const spinnerPos = document.querySelector('#spinner-position .position-option.selected').dataset.pos;
    const spinnerSize = document.getElementById('spinner-size').value;
    const spinnerColor = document.getElementById('spinner-color').value;
    const spinnerTrackColor = document.getElementById('spinner-track-color').value;
    const spinnerSpeed = document.getElementById('spinner-speed').value;
    const spinnerGap = document.getElementById('spinner-gap').value;
    
    const textPos = document.querySelector('#text-position .position-option.selected').dataset.pos;
    const textContent = document.getElementById('text-content').value;
    const textSize = document.getElementById('text-size').value;
    
    const logoSize = document.getElementById('logo-size').value;
    const logoGap = document.getElementById('logo-gap').value;
	const logoBorderRadius = document.getElementById('logo-border-radius').value;
	const showLogo = document.getElementById('show-logo').checked;
    const logoUpload = document.getElementById('logo-upload');
	const hasLogo      = (logoUpload.files.length > 0 && logoUpload.dataset.base64);
    const showText = document.getElementById('show-text').checked;
    preview.innerHTML = '';
	
    
    const gradientDirection = document.querySelector('#gradient-direction .position-option.selected')?.dataset.pos || 'to right';
    
    let bgStyleValue;
    if (bgType === 'color') {
        bgStyleValue = bgColor;
    } else {
        const colorInputs = document.querySelectorAll('.gradient-color');
        const colors = [];
        colorInputs.forEach(input => colors.push(input.value));
        
        if (colors.length < 2) {
            colors.push('#3a0ca3', '#4361ee', '#4cc9f0');
        }

        if (bgType === 'linear-gradient') {
            bgStyleValue = `linear-gradient(${gradientDirection}, ${colors.join(', ')})`;
        } else {
            bgStyleValue = `radial-gradient(circle, ${colors.join(', ')})`;
        }
    }

    preview.style.background = bgStyleValue;
    preview.style.color = textColor;

    if (hasLogo && showLogo) {
        const logo = document.createElement('div');
        logo.className = 'preview-logo position-center';
        const img = document.createElement('img');
        
		if (logoUpload.files.length > 0 && logoUpload.dataset.base64) {
		  img.src = logoUpload.dataset.base64;
		}
        
        img.alt = 'Logo';
        img.style.height = logoSize + 'vmin';
		img.style.borderRadius = logoBorderRadius + '%'; // Додаємо border-radius
        logo.appendChild(img);
        preview.appendChild(logo);
    }
    
    // Додаємо текст тільки якщо він увімкнений і це не прогресбар
    if (showText) {
        const text = document.createElement('div');
        text.className = `preview-progress-text ${textPos}`;
        text.textContent = textContent;
        text.style.fontSize = textSize + 'vmin';
        preview.appendChild(text);
    }
    
    const spinnerWrap = document.createElement('div');
    spinnerWrap.className = `preview-spinner-wrap ${spinnerPos}`;
    
	
	
	
    let spinnerElement;

    // Для progress‑bar повертаємо готовий елемент без додаткової обгортки
    if (spinnerType === 'progress-bar') {
        spinnerElement = createSpinnerByType(
            spinnerType, spinnerSize, spinnerColor,
            spinnerTrackColor, spinnerSpeed
        );
    } else {
        spinnerElement = document.createElement('div');
        spinnerElement.className = 'preview-spinner';
        spinnerElement.style.width  = spinnerSize + 'vmin';
        spinnerElement.style.height = spinnerSize + 'vmin';

       const inner = createSpinnerByType(
            spinnerType, spinnerSize, spinnerColor,
            spinnerTrackColor, spinnerSpeed
        );
        spinnerElement.appendChild(inner);
    }

    spinnerWrap.appendChild(spinnerElement);
    preview.appendChild(spinnerWrap);

    const oldStyles = preview.querySelectorAll('style');
    oldStyles.forEach(style => style.remove());
    
    const style = document.createElement('style');
    style.textContent = generateSpinnerCSS(spinnerType, spinnerSpeed, spinnerSize);
    preview.appendChild(style);
    
    applyOriginalPositioning(spinnerSize, spinnerGap, logoGap);
    updatePositionButtons();
}



function createSpinnerByType(type, size, color, trackColor, speed) {
    if (type === 'circle') {
        const spinnerInner = document.createElement('div');
        spinnerInner.className = 'preview-spinner-inner';
        spinnerInner.style.width = '100%';
        spinnerInner.style.height = '100%';
        spinnerInner.style.aspectRatio = '1/1';
        spinnerInner.style.border = `${size/8}vmin solid ${trackColor}`;
        spinnerInner.style.borderTop = `${size/8}vmin solid ${color}`;
        spinnerInner.style.borderRadius = '50%';
        spinnerInner.style.animation = `spin ${speed}s linear infinite`;
        return spinnerInner;
    }
	else if (type === 'progress-bar') {
	
		const spinner = document.createElement('div');
		spinner.className = 'preview-spinner';
		spinner.style.width = size * 3 + 'vmin';  // Ширина в 3 рази більша за розмір
		spinner.style.height = size * 0.2 + 'vmin'; // Висота 20% від розміру
		
		const progressBar = document.createElement('div');
		progressBar.className = 'preview-spinner-progress-bar';
		
		progressBar.style.width = '100%';
		progressBar.style.height = '100%';
		progressBar.style.backgroundColor = trackColor;
		progressBar.style.borderRadius = '2vmin';
		progressBar.style.overflow = 'hidden';
		progressBar.style.position = 'relative';
		
		const progressFill = document.createElement('div');
		progressFill.className = 'preview-spinner-progress-bar-fill';
		progressFill.style.backgroundColor = color;
		progressFill.style.width = '30%';
		progressFill.style.height = '100%';
		progressFill.style.position = 'absolute';
		progressFill.style.top = '0';
		progressFill.style.left = '0';
		
		progressBar.appendChild(progressFill);
		
		spinner.appendChild(progressBar);
		return spinner;
	}
	else if (type === 'pulse') {
		const spinnerInner = document.createElement('div');
		spinnerInner.className = 'preview-spinner-pulse';
		spinnerInner.style.backgroundColor = color;
		spinnerInner.style.width = '100%';
		spinnerInner.style.height = '100%';
		spinnerInner.style.borderRadius = '50%';
		spinnerInner.style.animation = `pulse ${speed}s infinite ease-in-out`;
		return spinnerInner;
		}
else if (type === 'dots') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-dots';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
    spinnerInner.style.display = 'flex';
    spinnerInner.style.alignItems = 'center';
    spinnerInner.style.justifyContent = 'space-between';

    for (let i = 0; i < 3; i++) {
        const dot = document.createElement('span');
        dot.style.width = '25%';
        dot.style.height = '25%';
        dot.style.backgroundColor = color;
        dot.style.borderRadius = '50%';
        dot.style.display = 'inline-block';
        dot.style.animation = `dots-animation ${speed}s infinite ease-in-out both`;
        dot.style.animationDelay = i === 0 ? '-0.32s' : i === 1 ? '-0.16s' : '0s';
        spinnerInner.appendChild(dot);
    }

    return spinnerInner;
}
	else if (type === 'circle-pulse-ring') {
		const spinnerInner = document.createElement('div');
		spinnerInner.className = 'preview-spinner-circle-pulse-ring';
		spinnerInner.style.color = color;
		spinnerInner.style.position = 'relative';
		spinnerInner.style.width = '100%';
		spinnerInner.style.height = '100%';

		for (let i = 0; i < 8; i++) {
			const dot = document.createElement('div');
			dot.style.animationDuration = `${speed}s`;
			spinnerInner.appendChild(dot);
		}

		return spinnerInner;
	}
	else if (type === 'dual-line-ring') {
		const spinnerInner = document.createElement('div');
		spinnerInner.className = 'preview-spinner-dual-line-ring';
		spinnerInner.style.width = '100%';
		spinnerInner.style.height = '100%';
		spinnerInner.style.border = `${size / 8}vmin solid transparent`;
		spinnerInner.style.borderTopColor = color;
		spinnerInner.style.borderBottomColor = color;
		spinnerInner.style.borderRadius = '50%';
		spinnerInner.style.animation = `spin-dual-line-ring ${speed}s linear infinite`;
		return spinnerInner;
	}
else if (type === 'grid-pulse-blocks') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-grid-pulse-blocks';
    spinnerInner.style.color = color;
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
    spinnerInner.style.display = 'grid';
    spinnerInner.style.gridTemplateColumns = 'repeat(3, 1fr)';
    spinnerInner.style.gap = '10%';

    for (let i = 0; i < 9; i++) {
        const cell = document.createElement('div');
        cell.style.animationDuration = `${speed}s`;
        spinnerInner.appendChild(cell);
    }

    return spinnerInner;
}

else if (type === 'corner-pulse-dots') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-corner-pulse-dots';
    spinnerInner.style.color = color;
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
    spinnerInner.style.position = 'relative';

    for (let i = 0; i < 4; i++) {
        const dot = document.createElement('div');
        dot.style.animationDuration = `${speed}s`;
        spinnerInner.appendChild(dot);
    }

    return spinnerInner;
}
else if (type === 'bouncing-dots') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-bouncing-dots';
    spinnerInner.style.color = color;
    spinnerInner.style.display = 'flex';
    spinnerInner.style.justifyContent = 'center';
    spinnerInner.style.alignItems = 'center';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';

    for (let i = 0; i < 3; i++) {
        const dot = document.createElement('div');
        dot.style.animationDuration = `${speed * 0.3}s`;
        dot.style.width = '20%';
        dot.style.aspectRatio = '1/1';
        dot.style.margin = '0 5%';
        spinnerInner.appendChild(dot);
    }

    return spinnerInner;
}
else if (type === 'square-pulse-morph') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-square-pulse-morph';
    spinnerInner.style.backgroundColor = color;
    spinnerInner.style.animationDuration = `${speed * 0.35}s`;
    return spinnerInner;
}
else if (type === 'grid-scale-squares') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-grid-scale-squares';
    spinnerInner.style.color = color;
    spinnerInner.style.display = 'grid';
    spinnerInner.style.gridTemplateColumns = 'repeat(2, 48%)';
    spinnerInner.style.gap = '4%';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';

    for (let i = 0; i < 4; i++) {
        const square = document.createElement('div');
        square.style.animationDuration = `${speed * 0.5}s`;
        spinnerInner.appendChild(square);
    }

    return spinnerInner;
}
else if (type === 'card-flip') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-card-flip';
    spinnerInner.style.perspective = '200px';

    const front = document.createElement('div');
    front.className = 'front';
    front.style.backgroundColor = color;
    front.style.animationDuration = `${speed * 0.75}s`;

    const back = document.createElement('div');
    back.className = 'back';
    back.style.backgroundColor = color;
    back.style.animationDuration = `${speed * 0.75}s`;

    spinnerInner.appendChild(front);
    spinnerInner.appendChild(back);

    return spinnerInner;
}
else if (type === 'bars-equalizer') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-bars-equalizer';
    spinnerInner.style.color = color;
    spinnerInner.style.display = 'flex';
    spinnerInner.style.justifyContent = 'center';
    spinnerInner.style.alignItems = 'center';
    spinnerInner.style.gap = '8%';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';

    for (let i = 0; i < 4; i++) {
        const bar = document.createElement('div');
        bar.style.animationDuration = `${speed * 0.5}s`;
        spinnerInner.appendChild(bar);
    }

    return spinnerInner;
}
else if (type === 'matrix-pulse-dots') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-matrix-pulse-dots';
    spinnerInner.style.color = color;
    spinnerInner.style.display = 'grid';
    spinnerInner.style.gridTemplateColumns = 'repeat(3, 1fr)';
    spinnerInner.style.gap = '10%';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';

    for (let i = 0; i < 9; i++) {
        const dot = document.createElement('div');
        dot.style.animationDuration = `${speed}s`; // Точне використання твоїх 1.2s
        dot.style.animationDelay = i % 2 === 0 ? '0s' : `${speed / 2}s`;
        spinnerInner.appendChild(dot);
    }

    return spinnerInner;
}
else if (type === 'dots-fade-trail') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-dots-fade-trail';
    spinnerInner.style.color = color;
    spinnerInner.style.display = 'flex';
    spinnerInner.style.justifyContent = 'center';
    spinnerInner.style.alignItems = 'center';
    spinnerInner.style.gap = '12%';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';

    for (let i = 0; i < 3; i++) {
        const dot = document.createElement('div');
        dot.style.animationDuration = `${speed * 0.5}s`;
        dot.style.animationDelay = `${i * 0.2}s`;
        spinnerInner.appendChild(dot);
    }

    return spinnerInner;
}
else if (type === 'double-ring-rotate') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-double-ring-rotate';
    spinnerInner.style.position = 'relative';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
    spinnerInner.style.boxSizing = 'border-box';

    const one = document.createElement('div');
    one.className = 'one';
    one.style.border = `${size / 8}vmin solid transparent`;
    one.style.borderTopColor = color;
    one.style.animation = `spin-double-ring-one ${speed}s linear infinite`;
    one.style.boxSizing = 'border-box';

    const two = document.createElement('div');
    two.className = 'two';
    two.style.border = `${size / 8}vmin solid transparent`;
    two.style.borderBottomColor = color;
    two.style.animation = `spin-double-ring-two ${speed * 1.2}s linear infinite reverse`;
    two.style.boxSizing = 'border-box';

    spinnerInner.appendChild(one);
    spinnerInner.appendChild(two);

    return spinnerInner;
}
else if (type === 'dots-circle-fade') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-dots-circle-fade';
    spinnerInner.style.color = color;
    spinnerInner.style.position = 'relative';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';

    for (let i = 0; i < 6; i++) {
        const angle = i * 60;
        const delay = i * 0.2; // Виправлені затримки

        const dot = document.createElement('div');
        dot.style.position = 'absolute';
        dot.style.width = '16%';
        dot.style.height = '16%';
        dot.style.borderRadius = '50%';
        dot.style.backgroundColor = 'currentColor';
        dot.style.top = '50%';
        dot.style.left = '50%';
        dot.style.marginTop = '-8%';
        dot.style.marginLeft = '-8%';
        dot.style.transform = `rotate(${angle}deg) translate(0, -240%)`;
        dot.style.transformOrigin = 'center';
        dot.style.animation = `fade-dot-circle ${speed}s ease-in-out infinite`;
        dot.style.animationDelay = `${delay}s`;

        spinnerInner.appendChild(dot);
    }

    return spinnerInner;
}
else if (type === 'double-dot-rotate') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-double-dot-rotate';
    spinnerInner.style.animation = `rotate-double-dot ${speed}s linear infinite`;

    const dotSize = size * 0.25;

    spinnerInner.style.position = 'relative';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
	spinnerInner.style.color = color;

    spinnerInner.style.setProperty('--dot-size', `${dotSize}vmin`);

    // Псевдоелементи в CSS відповідають ::before та ::after

    return spinnerInner;
}

else if (type === 'grid-expand-blocks') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-grid-expand-blocks';
    spinnerInner.style.color = color;
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
    spinnerInner.style.display = 'grid';
    spinnerInner.style.gridTemplateColumns = 'repeat(3, 1fr)';
    spinnerInner.style.gap = '10%';

    for (let i = 0; i < 9; i++) {
        const block = document.createElement('div');
        block.style.animationDuration = `${speed}s`;
        spinnerInner.appendChild(block);
    }

    return spinnerInner;
}
else if (type === 'sliding-bar') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-sliding-bar';
    spinnerInner.style.background = trackColor;
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = `${size * 0.2}vmin`; // 20% від height
    spinnerInner.style.position = 'relative';
    spinnerInner.style.overflow = 'hidden';
    spinnerInner.style.borderRadius = '999px';
    spinnerInner.style.color = color;
    spinnerInner.style.setProperty('--speed', `${speed}s`);

    const style = document.createElement('style');
    style.textContent = `
        .preview-spinner-sliding-bar::before {
            animation-duration: ${speed}s;
			
        }
    `;
    spinnerInner.appendChild(style);

    return spinnerInner;
}
else if (type === 'ellipsis-dots') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-ellipsis-dots';
    spinnerInner.style.color = color;
    spinnerInner.style.display = 'flex';
    spinnerInner.style.justifyContent = 'center';
    spinnerInner.style.alignItems = 'center';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';

    for (let i = 0; i < 3; i++) {
        const dot = document.createElement('div');
        dot.style.width = `${size * 0.2}vmin`;
        dot.style.height = `${size * 0.2}vmin`;
        dot.style.margin = `0 ${size * 0.05}vmin`;
        dot.style.borderRadius = '50%';
        dot.style.backgroundColor = 'currentColor';
        dot.style.animation = `ellipsis-fade ${speed}s infinite ease-in-out`;
        dot.style.opacity = 0;
        dot.style.animationDelay = `${i * 0.2}s`;
        spinnerInner.appendChild(dot);
    }

    return spinnerInner;
}
else if (type === 'border-pulse-ring') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-border-pulse-ring';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
    spinnerInner.style.borderColor = color;
    spinnerInner.style.borderStyle = 'solid';
    spinnerInner.style.borderRadius = '50%';
    spinnerInner.style.animation = `border-pulse-ring ${speed}s ease-in-out infinite`;
    spinnerInner.style.boxSizing = 'border-box';
    spinnerInner.style.borderWidth = `${size * 0.125}vmin`;

    return spinnerInner;
}
else if (type === 'radial-pulse-expand') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-radial-pulse-expand';
    spinnerInner.style.backgroundColor = color;
    spinnerInner.style.borderRadius = '50%';
    spinnerInner.style.animation = `radial-expand ${speed}s ease-out infinite`;
    spinnerInner.style.width = '0%';
    spinnerInner.style.height = '0%';

    return spinnerInner;
}
else if (type === 'bouncing-dot-box') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-bouncing-dot-box';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
    spinnerInner.style.border = `${size * 0.075}vmin solid ${color}`;
    spinnerInner.style.boxSizing = 'border-box';
    spinnerInner.style.position = 'relative';

    const dot = document.createElement('div');
    dot.style.width = `${size * 0.25}vmin`;
    dot.style.height = `${size * 0.25}vmin`;
    dot.style.backgroundColor = color;
    dot.style.borderRadius = '50%';
    dot.style.position = 'absolute';
    dot.style.animation = `bounce-dot-box ${speed}s ease-in-out infinite`;

    spinnerInner.appendChild(dot);
    return spinnerInner;
}
else if (type === 'morph-rotate-shape') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-morph-rotate-shape';
    spinnerInner.style.backgroundColor = color;
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
    spinnerInner.style.animation = `morph-rotate ${speed}s ease-in-out infinite alternate`;

    return spinnerInner;
}
else if (type === 'cube-3d-rotate') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-cube-3d-rotate';
    spinnerInner.style.animation = `rotate-cube-3d ${speed}s linear infinite`;
    spinnerInner.style.color = color;

    const faces = ['front', 'back', 'right', 'left', 'top', 'bottom'];
    for (const face of faces) {
        const faceDiv = document.createElement('div');
        faceDiv.className = face;
        spinnerInner.appendChild(faceDiv);
    }

    return spinnerInner;
}
else if (type === 'ripple-dual-waves') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-ripple-dual-waves';
    spinnerInner.style.position = 'relative';
    spinnerInner.style.width = '100%';
    spinnerInner.style.aspectRatio = '1 / 1';
    spinnerInner.style.color = color;

    for (let i = 0; i < 2; i++) {
        const ripple = document.createElement('div');
        ripple.style.position = 'absolute';
        ripple.style.top = '50%';
        ripple.style.left = '50%';
        ripple.style.transform = 'translate(-50%, -50%)';
        ripple.style.width = '0%';
        ripple.style.height = '0%';
        ripple.style.border = `${size * 0.08}vmin solid currentColor`;
        ripple.style.borderRadius = '50%';
        ripple.style.background = 'transparent';
        ripple.style.boxSizing = 'border-box';
        ripple.style.opacity = '0';
        ripple.style.animation = `ripple-wave ${speed}s ease-out ${i * speed / 2}s infinite`;
        spinnerInner.appendChild(ripple);
    }

    return spinnerInner;
}
else if (type === 'bars-folding') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-bars-folding';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
    spinnerInner.style.display = 'flex';
    spinnerInner.style.justifyContent = 'center';
    spinnerInner.style.alignItems = 'center';
    spinnerInner.style.gap = '10%';
    spinnerInner.style.color = color;

    for (let i = 0; i < 3; i++) {
        const bar = document.createElement('div');
        bar.style.width = '20%';
        bar.style.height = '100%';
        bar.style.backgroundColor = 'currentColor';
        bar.style.transformOrigin = 'bottom center';
        bar.style.animation = `fold-bars ${speed}s ease-in-out ${i * 0.2}s infinite`;
        spinnerInner.appendChild(bar);
    }

    return spinnerInner;
}
else if (type === 'orbit-square') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-orbit-square';
    spinnerInner.style.position = 'relative';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
    spinnerInner.style.color = color;

    for (let i = 0; i < 2; i++) {
        const dot = document.createElement('div');
        dot.style.position = 'absolute';
        dot.style.width = '20%';
        dot.style.height = '20%';
        dot.style.borderRadius = '50%';
        dot.style.background = 'currentColor';
        dot.style.animation = `orbit-square-move ${speed}s linear ${i * speed / 2}s infinite`;
        spinnerInner.appendChild(dot);
    }

    return spinnerInner;
}
else if (type === 'cube-bounce-2') {
    const spinnerInner = document.createElement('div');
    spinnerInner.className = 'preview-spinner-cube-bounce-2';
    spinnerInner.style.position = 'relative';
    spinnerInner.style.width = '100%';
    spinnerInner.style.height = '100%';
    spinnerInner.style.color = color;

    for (let i = 0; i < 2; i++) {
        const cube = document.createElement('div');
        cube.style.position = 'absolute';
        cube.style.width = '50%';
        cube.style.height = '50%';
        cube.style.backgroundColor = 'currentColor';
        cube.style.animation = `cube-move-2 ${speed}s ease-in-out ${i === 1 ? `-${speed / 2}s` : '0s'} infinite`;
        spinnerInner.appendChild(cube);
    }

    return spinnerInner;
}








    return document.createElement('div');
}

        function generateSpinnerCSS(type, speed, size) {
            return ``;
        }

function applyOriginalPositioning(spinnerSize, spinnerGap, logoGap) {
    const preview = document.getElementById('preview-preloader');
    const spinnerWrap = preview.querySelector('.preview-spinner-wrap');
    const progressText = preview.querySelector('.preview-progress-text');
    const logo = preview.querySelector('.preview-logo');
    
    const hasSpinner = !!spinnerWrap;
    const hasText = !!progressText;
    const hasLogo = !!logo;
    
    if (!hasSpinner && !hasText) return;
    
    const spinnerPos = spinnerWrap ? Array.from(spinnerWrap.classList).find(c => c.startsWith('position-')) : null;
    const textPos = progressText ? Array.from(progressText.classList).find(c => c.startsWith('position-')) : null;
    
    const central = ['position-center','position-left-in-center','position-right-in-center'];
    const spinCent = hasSpinner && central.includes(spinnerPos);
    const textCent = hasText && central.includes(textPos);
    
    if (spinCent || textCent) {
        const groupPos = spinCent ? spinnerPos : textPos;
        const groupArr = [];
        
        if (spinCent) {
            spinnerWrap.style.position = 'static';
            groupArr.push(spinnerWrap);
        }
        if (textCent) {
            progressText.style.position = 'static';
            groupArr.push(progressText);
        }
        
        const wrap = document.createElement('div');
        wrap.style.position = 'absolute';
        applyPositionStyle(wrap, groupPos);
        
        const inner = document.createElement('div');
        inner.className = 'preloader-group';
        inner.style.display = 'flex';
        inner.style.gap = spinnerGap + 'vmin';
        
        if (groupPos === 'position-center') {
            inner.style.flexDirection = 'column';
            inner.style.alignItems = 'center';
			inner.style.gap = spinnerGap + 'vmin';
        } else {
            inner.style.flexDirection = 'row';
            inner.style.alignItems = 'center';
			inner.style.gap = spinnerGap + 'vmin';
            if (groupPos === 'position-right-in-center') groupArr.reverse();
        }
        
        if (hasLogo) {
            const logoWrap = document.createElement('div');
            logoWrap.className = 'preloader-with-logo';
            logoWrap.style.position = 'absolute';
            logoWrap.style.display = 'flex';
            logoWrap.style.flexDirection = 'column';
            logoWrap.style.alignItems = 'center';
            logoWrap.style.gap = logoGap + 'vmin';
            applyPositionStyle(logoWrap, groupPos);
            
            logo.style.position = 'static';
            logoWrap.appendChild(logo);
            
            groupArr.forEach(el => inner.appendChild(el));
            logoWrap.appendChild(inner);
            preview.appendChild(logoWrap);
        } else {
            groupArr.forEach(el => inner.appendChild(el));
            wrap.appendChild(inner);
            preview.appendChild(wrap);
        }
        
        if (!spinCent && hasSpinner) {
            spinnerWrap.style.position = 'absolute';
            spinnerWrap.style.width = spinnerSize + 'vmin';
            spinnerWrap.style.height = spinnerSize + 'vmin';
            applyPositionStyle(spinnerWrap, spinnerPos);
        }
        if (!textCent && hasText) {
            progressText.style.position = 'absolute';
            applyPositionStyle(progressText, textPos);
        }
    }
    else if (hasSpinner && hasText && spinnerPos === textPos) {
        const pc = spinnerPos;
        const wrap = document.createElement('div');
        wrap.className = 'preloader-group';
        wrap.style.position = 'absolute';
        wrap.style.display = 'flex';
        wrap.style.alignItems = 'center';
        wrap.style.gap = spinnerGap + 'vmin';
        applyPositionStyle(wrap, pc);
        
        const H = {
            'position-top-left': [spinnerWrap, progressText],
            'position-bottom-left': [spinnerWrap, progressText],
            'position-top-right': [progressText, spinnerWrap],
            'position-bottom-right': [progressText, spinnerWrap]
        };
        const V = {
            'position-bottom-center': [spinnerWrap, progressText],
            'position-top-center': [progressText, spinnerWrap]
        };
        
        if (H[pc]) {
            wrap.style.flexDirection = 'row';
            H[pc].forEach(e => {
                e.style.position = 'static';
                wrap.appendChild(e);
            });
        } else if (V[pc]) {
            wrap.style.flexDirection = 'column';
            V[pc].forEach(e => {
                e.style.position = 'static';
                wrap.appendChild(e);
            });
        }
        
        preview.appendChild(wrap);
        
        if (hasLogo) {
            logo.style.position = 'absolute';
            applyPositionStyle(logo, 'position-center');
        }
    }
    else {
        if (hasSpinner) {
            spinnerWrap.style.position = 'absolute';
            spinnerWrap.style.width = spinnerSize + 'vmin';
            spinnerWrap.style.height = spinnerSize + 'vmin';
            applyPositionStyle(spinnerWrap, spinnerPos);
        }
        if (hasText) {
            progressText.style.position = 'absolute';
            applyPositionStyle(progressText, textPos);
        }
        if (hasLogo) {
            logo.style.position = 'absolute';
            applyPositionStyle(logo, 'position-center');
        }
    }
}

        function applyPositionStyle(element, position) {
            const positions = {
                "position-top-left": {top: "3vmin", left: "3vmin"},
                "position-top-center": {top: "3vmin", left: "50%", transform: "translateX(-50%)"},
                "position-top-right": {top: "3vmin", right: "3vmin"},
                "position-bottom-left": {bottom: "3vmin", left: "2vmin"},
                "position-bottom-center": {bottom: "3vmin", left: "50%", transform: "translateX(-50%)"},
                "position-bottom-right": {bottom: "3vmin", right: "3vmin"},
                "position-left-in-center": {top: "50%", left: "50%", transform: "translate(-50%,-50%)"},
                "position-right-in-center": {top: "50%", left: "50%", transform: "translate(-50%,-50%)"},
                "position-center": {top: "50%", left: "50%", transform: "translate(-50%,-50%)"}
            };
            Object.assign(element.style, positions[position] || {});
        }
        
        function getPositionStyle(position, elementType = null, spinnerSize = null) {
            const positions = {
				"position-top-left": {
					spinner: "top:3vmin;left:3vmin;",
					text: "top:3vmin;left:3vmin;",
					logo: "top:50%;left:50%;transform:translate(-50%,-50%);"
				},
                "position-top-center": "top:3vmin;left:50%;transform:translateX(-50%);",
                "position-top-right": "top:3vmin;right:3vmin;",
                "position-bottom-left": "bottom:3vmin;left:3vmin;",
                "position-bottom-center": "bottom:3vmin;left:50%;transform:translateX(-50%);",
                "position-bottom-right": "bottom:3vmin;right:3vmin;",
                "position-left-in-center": "top:50%;left:50%;transform:translate(-50%,-50%);",
                "position-right-in-center": "top:50%;left:50%;transform:translate(-50%,-50%);",
                "position-center": "top:50%;left:50%;transform:translate(-50%,-50%);"
            };
            return positions[position] || "";
        }
		
		

	
async function generateTemplate(version = 'c2') {


    const bgType = document.getElementById('bg-type')?.value || 'color';
    const bgColor = document.getElementById('bg-color').value;
    const textColor = document.getElementById('text-color').value;
    const spinnerType = document.getElementById('spinner-type').value;
    const spinnerPos = document.querySelector('#spinner-position .position-option.selected').dataset.pos;
    const spinnerSize = document.getElementById('spinner-size').value;
    const spinnerColor = document.getElementById('spinner-color').value;
    const spinnerTrackColor = document.getElementById('spinner-track-color').value;
    const spinnerSpeed = document.getElementById('spinner-speed').value;
    const spinnerGap = document.getElementById('spinner-gap').value;
    const textPos = document.querySelector('#text-position .position-option.selected').dataset.pos;
    const textContent = document.getElementById('text-content').value;
    const textSize = document.getElementById('text-size').value;
    const logoBorderRadius = document.getElementById('logo-border-radius').value;
    const showLogo = document.getElementById('show-logo').checked;
    const logoSize = document.getElementById('logo-size').value;
    const logoGap = document.getElementById('logo-gap').value;
    const logoUpload = document.getElementById('logo-upload');
    const showText = document.getElementById('show-text').checked;
    
    // Отримуємо налаштування шрифту
    const fontSource = document.getElementById('font-source').value;
    let fontFamily = 'sans-serif';
    let fontCss = '';
    let fontFiles = [];
    
    if (fontSource === 'google') {
        const fontName = document.getElementById('google-font-name').value.trim();
        if (fontName) {
            fontFamily = `'${fontName}', sans-serif`;
            fontCss = `<link href="https://fonts.googleapis.com/css2?family=${encodeURIComponent(fontName)}&display=swap" rel="stylesheet">`;
        }
    } 
    else if (fontSource === 'custom') {
        const fontFile = document.getElementById('font-upload').files[0];
        if (fontFile) {
            const fontExt = fontFile.name.split('.').pop().toLowerCase();
            const fontName = fontFile.name.replace(/\.[^/.]+$/, "");
            fontFamily = `'${fontName}', sans-serif`;
            
            // Для C2 - шлях до файлу в папці fonts
            const fontPath = version === 'c2' 
                ? `fonts/${fontName}.${fontExt}`
                : `fonts/${fontName}.${fontExt}`;
            
            fontCss = `
                @font-face {
                    font-family: '${fontName}';
                    src: url('${fontPath}') format('${getFontFormat(fontExt)}');
                    font-display: swap;
                }
            `;
            
            // Додаємо файл шрифту до архіву
            const fontData = await readFileAsDataURL(fontFile);
            fontFiles.push({
                name: `${fontName}.${fontExt}`,
                data: fontData
            });
        }
    }

    const logoPath = version === 'c2'
        ? 'loading-logo.png'
        : 'icons/loading-logo.png';
    
    // Змінено: перевіряємо чи є лого і чи включений показ лого
    let hasLogo = showLogo && (logoUpload.files.length > 0 && logoUpload.dataset.base64);

    let bgStyleValue;
    if (bgType === 'color') {
        bgStyleValue = `background: ${bgColor};`;
    } else {
        const colorInputs = document.querySelectorAll('.gradient-color');
        const colors = Array.from(colorInputs).map(input => input.value);
        
        if (bgType === 'linear-gradient') {
            const direction = document.querySelector('#gradient-direction .position-option.selected')?.dataset.pos || 'to right';
            bgStyleValue = `background: linear-gradient(${direction}, ${colors.join(', ')});`;
        } else {
            bgStyleValue = `background: radial-gradient(circle, ${colors.join(', ')});`;
        }
    }
    
    const spinnerCSS = generateCurrentSpinnerCSS(spinnerType, spinnerSize, spinnerColor, spinnerTrackColor, spinnerSpeed, spinnerGap);

    const hasText = showText;
    let preloaderContent = '';
    
    const central = ['position-center','position-left-in-center','position-right-in-center'];
    const hasSpinner = true;
    const spinCent = hasSpinner && central.includes(spinnerPos);
    const textCent = hasText && central.includes(textPos);
    
    // Визначаємо groupPos тільки якщо потрібно
    const groupPos = spinCent ? spinnerPos : textPos;

    // Використовуємо тільки коли визначено
    const groupStyle = (spinCent || textCent) ? getPositionStyle(groupPos) : '';

    if (spinCent || textCent) {
        const groupPos = spinCent ? spinnerPos : textPos;
        const groupArr = [];
        
        if (spinCent) {
            groupArr.push(`
                <div class="spinner-wrap ${spinnerPos}" style="position:static;">
                    ${generateSpinnerHTML(spinnerType, spinnerSize, spinnerColor, spinnerTrackColor, spinnerSpeed, spinnerGap)}
                </div>`);
        }
        if (textCent) {
            groupArr.push(`
                <div class="progress-text ${textPos}" style="position:static;text-align:center">${textContent}</div>`);
        }
        
        let inner = `
            <div class="preloader-group" style="display:flex; gap:${spinnerGap}vmin; ${groupPos === 'position-center' ? 
                'flex-direction:column; align-items:center;' : 
                'flex-direction:row; align-items:center;'}">
                ${groupPos === 'position-right-in-center' ? groupArr.reverse().join('') : groupArr.join('')}
            </div>`;
        
        if (hasLogo) {
            preloaderContent += `
                <div class="preloader-with-logo" style="position:absolute; display:flex; flex-direction:column; align-items:center; gap:${logoGap}vmin; ${getPositionStyle(groupPos)}">
                    <div class="logo" style="position:static;">
                        <img src="${logoPath}" alt="Logo" style="height:${logoSize}vmin; border-radius:${logoBorderRadius}%;">
                    </div>
                    ${inner}
                </div>`;
        } else {
            preloaderContent += `
                <div style="position:absolute; ${getPositionStyle(groupPos)}">
                    ${inner}
                </div>`;
        }
        
        if (!spinCent && hasSpinner) {
            preloaderContent += `
                <div class="spinner-wrap ${spinnerPos}" style="position:absolute;width:${spinnerSize}vmin;height:${spinnerSize}vmin;${getPositionStyle(spinnerPos)}">
                    ${generateSpinnerHTML(spinnerType, spinnerSize, spinnerColor, spinnerTrackColor, spinnerSpeed, spinnerGap)}
                </div>`;
        }
        if (!textCent && hasText) {
            preloaderContent += `
                <div class="progress-text ${textPos}" style="${getPositionStyle(textPos)}">${textContent}</div>`;
        }
    }
    else if (hasSpinner && hasText && spinnerPos === textPos) {
        const pc = spinnerPos;
        
        const H = {
            'position-top-left': ['spinner', 'text'],
            'position-bottom-left': ['spinner', 'text'],
            'position-top-right': ['text', 'spinner'],
            'position-bottom-right': ['text', 'spinner']
        };
        const V = {
            'position-bottom-center': ['spinner', 'text'],
            'position-top-center': ['text', 'spinner']
        };
        
        let groupContent = '';
        if (H[pc]) {
            groupContent = `
                <div class="spinner-wrap" style="position:static;">
                    ${generateSpinnerHTML(spinnerType, spinnerSize, spinnerColor, spinnerTrackColor, spinnerSpeed, spinnerGap)}
                </div>
                <div class="progress-text" style="position:static;text-align:center">${textContent}</div>`;
        } else if (V[pc]) {
            groupContent = `
                <div style="display:flex; flex-direction:column; gap:${spinnerGap}vmin;">
                    ${V[pc][0] === 'spinner' ? `
                    <div class="spinner-wrap" style="position:static;">
                        ${generateSpinnerHTML(spinnerType, spinnerSize, spinnerColor, spinnerTrackColor, spinnerSpeed, spinnerGap)}
                    </div>
                    <div class="progress-text" style="position:static;text-align:center">${textContent}</div>
                    ` : `
                    <div class="progress-text" style="position:static;text-align:center">${textContent}</div>
                    <div class="spinner-wrap" style="position:static;">
                        ${generateSpinnerHTML(spinnerType, spinnerSize, spinnerColor, spinnerTrackColor, spinnerSpeed, spinnerGap)}
                    </div>
                    `}
                </div>`;
        }
        
        preloaderContent += `
            <div class="preloader-group" style="position:absolute; display:flex; align-items:center; gap:${spinnerGap}vmin; ${getPositionStyle(pc)}">
                ${groupContent}
            </div>`;
        
        if (hasLogo) {
            preloaderContent += `
                <div class="logo" style="position:absolute; ${getPositionStyle('position-center')}">
                    <img src="${logoPath}" alt="Logo" style="height:${logoSize}vmin; border-radius:${logoBorderRadius}%;">
                </div>`;
        }
    }
    else {
        if (hasSpinner) {
            preloaderContent += `
                <div class="spinner-wrap ${spinnerPos}" style="position:absolute;width:${spinnerSize}vmin;height:${spinnerSize}vmin;${getPositionStyle(spinnerPos)}">
                    ${generateSpinnerHTML(spinnerType, spinnerSize, spinnerColor, spinnerTrackColor, spinnerSpeed, spinnerGap)}
                </div>`;
        }
        if (hasText) {
            preloaderContent += `
                <div class="progress-text ${textPos}" style="${getPositionStyle(textPos)}">${textContent}</div>`;
        }
        if (hasLogo) {
            preloaderContent += `
                <div class="logo" style="position:absolute; ${getPositionStyle('position-center')}">
                    <img src="${logoPath}" alt="Logo" style="height:${logoSize}vmin; border-radius:${logoBorderRadius}%;">
                </div>`;
        }
    }

    const template = `    
<div id="custom-preloader" style="${bgStyleValue} color:${textColor}; font-family: ${fontFamily} !important;">
    ${preloaderContent}
    ${fontSource === 'google' ? fontCss : ''}
    
        
        #custom-preloader {
            position: fixed;
            inset: 0;
            z-index: 9999;
            font-family: ${fontFamily} !important;
        }
        ${fontSource === 'custom' ? fontCss : ''}
        
        .progress-group {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: ${spinnerGap}vmin;
                    position: absolute;
        }

        .spinner-wrap {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: ${spinnerGap}vmin;
        }
        
        .spinner {
            width: ${spinnerSize}vmin;
            height: ${spinnerSize}vmin;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-shrink: 0;
            aspect-ratio:1/1;
            opacity: 0;
            animation: fadeIn 0.5s ease-in-out forwards;
        }

        .progress-text {
            font-size: ${textSize}vmin;
            text-align:center;
                position: absolute;
            opacity: 0;
            animation: fadeIn 0.5s ease-in-out forwards;
        }

        
        .preloader-with-logo {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: ${logoGap}vmin;
            animation: fadeIn 0.5s ease-in-out forwards;
        }
        
        @keyframes fadeIn {
            from {
                opacity: 0;
            }
            to {
                opacity: 1;
            }
        }
        
        ${spinnerCSS}  
        
    
</div>`;

    return { template, fontFiles };
}


function getFontFormat(ext) {
    const formats = {
        'ttf': 'truetype',
        'otf': 'opentype',
        'woff': 'woff',
        'woff2': 'woff2',
        'eot': 'embedded-opentype',
        'svg': 'svg'
    };
    return formats[ext.toLowerCase()] || 'truetype';
}

function readFileAsDataURL(file) {
    return new Promise((resolve) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
        reader.readAsDataURL(file);
    });
}

function generateCurrentSpinnerCSS(type, size, color, trackColor, speed, gap) {
    if (type === 'circle') {
        return `
            .spinner {
                width: ${size}vmin;
                height: ${size}vmin;
                display: flex;
                align-items: center;
                justify-content: center;
				aspect-ratio: 1/1;
            }
            
            .spinner-inner {
                width: 100%;
                height: 100%;
                aspect-ratio: 1/1;
                border: ${size/8}vmin solid ${trackColor};
                border-top: ${size/8}vmin solid ${color};
                border-radius: 50%;
                animation: spin ${speed}s linear infinite;
				box-sizing:border-box;
            }
            
            @keyframes spin {
                to { transform: rotate(360deg); }
            }
        `;
    } else if (type === 'progress-bar') {
		return `
			.spinner {
				width: ${size * 3}vmin;
				height: ${size * 0.2}vmin;
				display: flex;
				align-items: center;
				justify-content: center;
			}
			
			.spinner-progress-bar {
				width: 100%;
				height: 100%;
				background-color: ${trackColor};
				border-radius: 2vmin;
				overflow: hidden;
				position: relative;
			}
			
			.spinner-progress-bar-fill {
				position: absolute;
				top: 0;
				left: 0;
				height: 100%;
				width:0;
				background-color: ${color};
				transition: width 0.3s ease;
			}
		`;
	} else if (type === 'pulse') {
        return `
            .spinner {
                width: ${size}vmin;
                height: ${size}vmin;
                display: flex;
                align-items: center;
                justify-content: center;
				aspect-ratio: 1/1;
            }
            
            .spinner-pulse {
                width: 100%;
                height: 100%;
                border-radius: 50%;
                background-color: ${color};
                opacity: 1;
                animation: pulse ${speed}s infinite ease-in-out;
            }
            
            @keyframes pulse {
                0%, 100% { transform: scale(0.8); opacity: 0.5; }
                50% { transform: scale(1.2); opacity: 1; }
            }
        `;
    } else if (type === 'dots') {
        return `
            .spinner-dots {
                display: flex;
                align-items: center;
                justify-content: space-between;
                width: ${size}vmin;
                height: ${size}vmin;
				aspect-ratio: 1/1;
            }
            
            .spinner-dots span {
                width: 25%;
                height: 25%;
                background-color: ${color};
                border-radius: 50%;
                display: inline-block;
                animation: dots-animation ${speed}s infinite ease-in-out both;
            }
            
            .spinner-dots span:nth-child(1) { animation-delay: -0.32s; }
            .spinner-dots span:nth-child(2) { animation-delay: -0.16s; }
            
            @keyframes dots-animation {
                0%, 80%, 100% { transform: scale(0); } 
                40% { transform: scale(1); }
            }
        `;
    } else if (type === 'circle-pulse-ring') {
        return `
            .spinner-circle-pulse-ring {
                width: ${size}vmin;
                height: ${size}vmin;
                position: relative;
				aspect-ratio: 1/1;
            }
            
            .spinner-circle-pulse-ring div {
                position: absolute;
                width: 20%;
                height: 20%;
                background-color: ${color};
                border-radius: 50%;
                animation: spin-circle-pulse-ring ${speed}s linear infinite;
            }
            
            .spinner-circle-pulse-ring div:nth-child(1) { top: 0; left: 40%; animation-delay: 0s; }
            .spinner-circle-pulse-ring div:nth-child(2) { top: 10%; left: 10%; animation-delay: -0.5s; }
            .spinner-circle-pulse-ring div:nth-child(3) { top: 40%; left: 0; animation-delay: -1s; }
            .spinner-circle-pulse-ring div:nth-child(4) { top: 70%; left: 10%; animation-delay: -1.5s; }
            .spinner-circle-pulse-ring div:nth-child(5) { top: 80%; left: 40%; animation-delay: -2s; }
            .spinner-circle-pulse-ring div:nth-child(6) { top: 70%; left: 70%; animation-delay: -2.5s; }
            .spinner-circle-pulse-ring div:nth-child(7) { top: 40%; left: 80%; animation-delay: -3s; }
            .spinner-circle-pulse-ring div:nth-child(8) { top: 10%; left: 70%; animation-delay: -3.5s; }
            
            @keyframes spin-circle-pulse-ring {
                0%, 100% { opacity: 1; transform: scale(1); }
                50% { opacity: 0.3; transform: scale(0.5); }
            }
        `;
    } else if (type === 'dual-line-ring') {
        return `
            .spinner-dual-line-ring {
                width: ${size}vmin;
                height: ${size}vmin;
                box-sizing: border-box;
                border: ${size/8}vmin solid transparent;
                border-top-color: ${color};
                border-bottom-color: ${color};
                border-radius: 50%;
                animation: spin-dual-line-ring ${speed}s linear infinite;
				aspect-ratio: 1/1;
            }
            
            @keyframes spin-dual-line-ring {
                to { transform: rotate(360deg); }
            }
        `;
    } else if (type === 'grid-pulse-blocks') {
        return `
            .spinner-grid-pulse-blocks {
                width: ${size}vmin;
                height: ${size}vmin;
                display: grid;
                grid-template-columns: repeat(3, 1fr);
                gap: 10%;
				aspect-ratio: 1/1;
            }
            
            .spinner-grid-pulse-blocks div {
                width: 100%;
                height: 100%;
                background-color: ${color};
                border-radius: 2px;
                animation: pulse-grid-pb ${speed}s infinite ease-in-out;
            }
            
            .spinner-grid-pulse-blocks div:nth-child(1) { animation-delay: 0s; }
            .spinner-grid-pulse-blocks div:nth-child(2) { animation-delay: 0.2s; }
            .spinner-grid-pulse-blocks div:nth-child(3) { animation-delay: 0.4s; }
            .spinner-grid-pulse-blocks div:nth-child(4) { animation-delay: 0.2s; }
            .spinner-grid-pulse-blocks div:nth-child(5) { animation-delay: 0.4s; }
            .spinner-grid-pulse-blocks div:nth-child(6) { animation-delay: 0.6s; }
            .spinner-grid-pulse-blocks div:nth-child(7) { animation-delay: 0.4s; }
            .spinner-grid-pulse-blocks div:nth-child(8) { animation-delay: 0.6s; }
            .spinner-grid-pulse-blocks div:nth-child(9) { animation-delay: 0.8s; }
            
            @keyframes pulse-grid-pb {
                0%, 100% { transform: scale(0.3); opacity: 0.5; }
                50% { transform: scale(1); opacity: 1; }
            }
        `;
    } else if (type === 'corner-pulse-dots') {
        return `
            .spinner-corner-pulse-dots {
                width: ${size}vmin;
                height: ${size}vmin;
                position: relative;
				aspect-ratio: 1/1;
            }
            
            .spinner-corner-pulse-dots div {
                position: absolute;
                width: 24%;
                height: 24%;
                background-color: ${color};
                border-radius: 50%;
                animation: corner-pulse ${speed}s linear infinite;
            }
            
            .spinner-corner-pulse-dots div:nth-child(1) {
                top: 12%;
                left: 12%;
                animation-delay: 0s;
            }
            .spinner-corner-pulse-dots div:nth-child(2) {
                top: 12%;
                right: 12%;
                animation-delay: -0.4s;
            }
            .spinner-corner-pulse-dots div:nth-child(3) {
                bottom: 12%;
                left: 12%;
                animation-delay: -0.4s;
            }
            .spinner-corner-pulse-dots div:nth-child(4) {
                bottom: 12%;
                right: 12%;
                animation-delay: -0.8s;
            }
            
            @keyframes corner-pulse {
                0%, 100% { transform: scale(1); }
                50% { transform: scale(0.5); }
            }
        `;
    } else if (type === 'bouncing-dots') {
        return `
            .spinner-bouncing-dots {
                width: ${size}vmin;
                height: ${size}vmin;
                display: flex;
                justify-content: center;
                align-items: center;
				aspect-ratio: 1/1;
            }
            
            .spinner-bouncing-dots div {
                width: 20%;
                aspect-ratio: 1 / 1;
                margin: 0 5%;
                border-radius: 50%;
                background-color: ${color};
                animation: bounce-bdots ${speed*0.3}s infinite alternate;
            }
            
            .spinner-bouncing-dots div:nth-child(1) { animation-delay: 0s; }
            .spinner-bouncing-dots div:nth-child(2) { animation-delay: 0.1s; }
            .spinner-bouncing-dots div:nth-child(3) { animation-delay: 0.2s; }
            
            @keyframes bounce-bdots {
                from { transform: translateY(0); }
                to   { transform: translateY(-30%); }
            }
        `;
    } else if (type === 'square-pulse-morph') {
        return `
            .spinner-square-pulse-morph {
                width: ${size}vmin;
                height: ${size}vmin;
                background-color: ${color};
                animation: morph-square-pulse ${speed*0.35}s ease-in-out infinite alternate;
				aspect-ratio: 1/1;
            }
            
            @keyframes morph-square-pulse {
                from { transform: scale(1); border-radius: 0; }
                to   { transform: scale(1.5); border-radius: 50%; }
            }
        `;
    } else if (type === 'grid-scale-squares') {
        return `
            .spinner-grid-scale-squares {
                width: ${size}vmin;
                height: ${size}vmin;
                display: grid;
                grid-template-columns: repeat(2, 48%);
                gap: 4%;
				aspect-ratio: 1/1;
            }
            
            .spinner-grid-scale-squares div {
                width: 100%;
                aspect-ratio: 1 / 1;
                background-color: ${color};
                animation: scale-grid-ssq ${speed*0.5}s ease-in-out infinite;
            }
            
            .spinner-grid-scale-squares div:nth-child(1) { animation-delay: 0.2s; }
            .spinner-grid-scale-squares div:nth-child(2) { animation-delay: 0.4s; }
            .spinner-grid-scale-squares div:nth-child(3) { animation-delay: 0.6s; }
            .spinner-grid-scale-squares div:nth-child(4) { animation-delay: 0.8s; }
            
            @keyframes scale-grid-ssq {
                0%, 100% { transform: scale(1); }
                50%     { transform: scale(0.5); }
            }
        `;
    } else if (type === 'card-flip') {
        return `
            .spinner-card-flip {
                width: ${size}vmin;
                height: ${size}vmin;
                perspective: 200px;
                position: relative;
				aspect-ratio: 1/1;
            }
            
            .spinner-card-flip .front,
            .spinner-card-flip .back {
                width: 100%;
                height: 100%;
                position: absolute;
                backface-visibility: hidden;
                background-color: ${color};
                animation: flip-card-anim ${speed*0.75}s ease-in-out infinite;
            }
            
            .spinner-card-flip .back {
                transform: rotateY(180deg);
            }
            
            @keyframes flip-card-anim {
                0%, 100% { transform: rotateY(0deg); }
                50%     { transform: rotateY(180deg); }
            }
        `;
    } else if (type === 'bars-equalizer') {
        return `
            .spinner-bars-equalizer {
                width: ${size}vmin;
                height: ${size}vmin;
                display: flex;
                justify-content: center;
                align-items: center;
                gap: 8%;
				aspect-ratio: 1/1;
            }
            
            .spinner-bars-equalizer div {
                width: 15%;
                height: 30%;
                background-color: ${color};
                animation: bars-eq-grow ${speed*0.5}s ease-in-out infinite;
            }
            
            .spinner-bars-equalizer div:nth-child(2) { animation-delay: 0.1s; }
            .spinner-bars-equalizer div:nth-child(3) { animation-delay: 0.2s; }
            .spinner-bars-equalizer div:nth-child(4) { animation-delay: 0.3s; }
            
            @keyframes bars-eq-grow {
                0%, 100% { height: 20%; }
                50%      { height: 80%; }
            }
        `;
    } else if (type === 'matrix-pulse-dots') {
        return `
            .spinner-matrix-pulse-dots {
                width: ${size}vmin;
                height: ${size}vmin;
                display: grid;
                grid-template-columns: repeat(3, 1fr);
                gap: 10%;
				aspect-ratio: 1/1;
            }
            
            .spinner-matrix-pulse-dots div {
                width: 100%;
                aspect-ratio: 1 / 1;
                background-color: ${color};
                border-radius: 50%;
                animation: matrix-pulse ${speed}s ease-in-out infinite;
            }
            
            .spinner-matrix-pulse-dots div:nth-child(odd)  { animation-delay: 0s; }
            .spinner-matrix-pulse-dots div:nth-child(even) { animation-delay: ${speed/2}s; }
            
            @keyframes matrix-pulse {
                0%, 100% { transform: scale(1); opacity: 1; }
                50%      { transform: scale(0.5); opacity: 0.5; }
            }
        `;
    } else if (type === 'dots-fade-trail') {
        return `
            .spinner-dots-fade-trail {
                width: ${size}vmin;
                height: ${size}vmin;
                display: flex;
                justify-content: center;
                align-items: center;
                gap: 12%;
				aspect-ratio: 1/1;
            }
            
            .spinner-dots-fade-trail div {
                width: 20%;
                aspect-ratio: 1 / 1;
                background-color: ${color};
                border-radius: 50%;
                animation: fade-trail ${speed*0.5}s ease-in-out infinite;
            }
            
            .spinner-dots-fade-trail div:nth-child(1) { animation-delay: 0s; }
            .spinner-dots-fade-trail div:nth-child(2) { animation-delay: 0.2s; }
            .spinner-dots-fade-trail div:nth-child(3) { animation-delay: 0.4s; }
            
            @keyframes fade-trail {
                0%, 100% { opacity: 0.3; }
                50%      { opacity: 1; }
            }
        `;
    } else if (type === 'double-ring-rotate') {
        return `
            .spinner-double-ring-rotate {
                width: ${size}vmin;
                height: ${size}vmin;
                position: relative;
                box-sizing: border-box;
				aspect-ratio: 1/1;
            }
            
            .spinner-double-ring-rotate .one,
            .spinner-double-ring-rotate .two {
                position: absolute;
                border-radius: 50%;
                box-sizing: border-box;
            }
            
            .spinner-double-ring-rotate .one {
                width: 100%;
                height: 100%;
                border: ${size/8}vmin solid transparent;
                border-top-color: ${color};
                animation: spin-double-ring-one ${speed}s linear infinite;
            }
            
            .spinner-double-ring-rotate .two {
                width: 60%;
                height: 60%;
                top: 20%;
                left: 20%;
                border: ${size/8}vmin solid transparent;
                border-bottom-color: ${color};
                animation: spin-double-ring-two ${speed*1.2}s linear infinite reverse;
            }
            
            @keyframes spin-double-ring-one {
                to { transform: rotate(360deg); }
            }
            @keyframes spin-double-ring-two {
                to { transform: rotate(360deg); }
            }
        `;
    } else if (type === 'dots-circle-fade') {
		return `
			.spinner-dots-circle-fade {
				width: ${size}vmin;
				height: ${size}vmin;
				position: relative;
				aspect-ratio: 1/1;
			}
			
			.spinner-dots-circle-fade div {
				position: absolute;
				width: 16%;
				height: 16%;
				background: ${color};
				border-radius: 50%;
				top: 50%;
				left: 50%;
				margin-top: -8%;
				margin-left: -8%;
				transform-origin: center;
				animation: fade-dot-circle ${speed}s ease-in-out infinite;
			}
			
			.spinner-dots-circle-fade div:nth-child(1) {
				transform: rotate(0deg) translate(0, -240%);
				animation-delay: 0s;
			}
			.spinner-dots-circle-fade div:nth-child(2) {
				transform: rotate(60deg) translate(0, -240%);
				animation-delay: 0.2s;
			}
			.spinner-dots-circle-fade div:nth-child(3) {
				transform: rotate(120deg) translate(0, -240%);
				animation-delay: 0.4s;
			}
			.spinner-dots-circle-fade div:nth-child(4) {
				transform: rotate(180deg) translate(0, -240%);
				animation-delay: 0.6s;
			}
			.spinner-dots-circle-fade div:nth-child(5) {
				transform: rotate(240deg) translate(0, -240%);
				animation-delay: 0.8s;
			}
			.spinner-dots-circle-fade div:nth-child(6) {
				transform: rotate(300deg) translate(0, -240%);
				animation-delay: 1s;
			}
			
			@keyframes fade-dot-circle {
				0%, 100% { opacity: 1; }
				50% { opacity: 0; }
			}
		`;
	} else if (type === 'double-dot-rotate') {
        return `
            .spinner-double-dot-rotate {
                width: ${size}vmin;
                height: ${size}vmin;
                position: relative;
                animation: rotate-double-dot ${speed}s linear infinite;
				aspect-ratio: 1/1;
            }
            
            .spinner-double-dot-rotate::before,
            .spinner-double-dot-rotate::after {
                content: '';
                position: absolute;
                left: 50%;
                transform: translateX(-50%);
                width: ${size*0.25}vmin;
                height: ${size*0.25}vmin;
                background: ${color};
                border-radius: 50%;
            }
            
            .spinner-double-dot-rotate::after {
                top: 50%;
            }
            
            @keyframes rotate-double-dot {
                to { transform: rotate(360deg); }
            }
        `;
    } else if (type === 'grid-expand-blocks') {
        return `
            .spinner-grid-expand-blocks {
                width: ${size}vmin;
                height: ${size}vmin;
                display: grid;
                grid-template-columns: repeat(3, 1fr);
                gap: 10%;
				aspect-ratio: 1/1;
            }
            
            .spinner-grid-expand-blocks div {
                background-color: ${color};
                width: 100%;
                height: 100%;
                animation: expand-grid-block ${speed}s ease-in-out infinite;
            }
            
            .spinner-grid-expand-blocks div:nth-child(odd) {
                animation-delay: 0s;
            }
            .spinner-grid-expand-blocks div:nth-child(even) {
                animation-delay: 0.5s;
            }
            
            @keyframes expand-grid-block {
                0%, 100% { transform: scale(1); }
                50%      { transform: scale(0.5); }
            }
        `;
    } else if (type === 'sliding-bar') {
        return `
            .spinner-sliding-bar {
                width: ${size}vmin;
                height: ${size*0.2}vmin;
                background: ${trackColor};
                position: relative;
                overflow: hidden;
                border-radius: 999px;
				aspect-ratio: 1/1;
            }
            
            .spinner-sliding-bar::before {
                content: '';
                position: absolute;
                left: -25%;
                width: 25%;
                height: 100%;
                background-color: ${color};
                animation: move-sliding-bar ${speed}s linear infinite;
            }
            
            @keyframes move-sliding-bar {
                to { left: 100%; }
            }
        `;
    } else if (type === 'ellipsis-dots') {
        return `
            .spinner-ellipsis-dots {
                width: ${size}vmin;
                height: ${size}vmin;
                display: flex;
                justify-content: center;
                align-items: center;
				aspect-ratio: 1/1;
            }
            
            .spinner-ellipsis-dots div {
                width: ${size*0.2}vmin;
                aspect-ratio: 1 / 1;
                margin: 0 ${size*0.05}vmin;
                border-radius: 50%;
                background-color: ${color};
                animation: ellipsis-fade ${speed}s infinite ease-in-out;
                opacity: 0;
            }
            
            .spinner-ellipsis-dots div:nth-child(2) { animation-delay: 0.2s; }
            .spinner-ellipsis-dots div:nth-child(3) { animation-delay: 0.4s; }
            
            @keyframes ellipsis-fade {
                0%, 80%, 100% { opacity: 0; }
                40% { opacity: 1; }
            }
        `;
    } else if (type === 'border-pulse-ring') {
        return `
            .spinner-border-pulse-ring {
                width: ${size}vmin;
                height: ${size}vmin;
                border: ${size * 0.125}vmin solid ${color};
                border-radius: 50%;
                animation: border-pulse-ring ${speed}s ease-in-out infinite;
                box-sizing: border-box;
            }
            
            @keyframes border-pulse-ring {
                0%   {transform: scale(1); }
                50%  {transform: scale(0.8); }
                100% {transform: scale(1); }
            }
        `;
    } else if (type === 'radial-pulse-expand') {
        return `
            .spinner-radial-pulse-expand {
                border-radius: 50%;
                background-color: ${color};
                animation: radial-expand ${speed}s ease-out infinite;
                opacity: 0;
				aspect-ratio: 1/1;
            }
            
            @keyframes radial-expand {
                0% {
                    width: 0%;
                    height: 0%;
                    opacity: 1;
                }
                100% {
                    width: 100%;
                    height: 100%;
                    opacity: 0;
                }
            }
        `;
    } else if (type === 'bouncing-dot-box') {
        return `
            .spinner-bouncing-dot-box {
                width: ${size}vmin;
                height: ${size}vmin;
                position: relative;
                border: ${size*0.075}vmin solid ${color};
                box-sizing: border-box;
				aspect-ratio: 1/1;
            }
            
            .spinner-bouncing-dot-box div {
                position: absolute;
                width: ${size*0.25}vmin;
                height: ${size*0.25}vmin;
                background-color: ${color};
                border-radius: 50%;
                animation: bounce-dot-box ${speed}s ease-in-out infinite;
            }
            
            @keyframes bounce-dot-box {
                0%, 100% { top: 0%; left: 0%; }
                25% { top: 0%; left: 75%; }
                50% { top: 75%; left: 75%; }
                75% { top: 75%; left: 0%; }
            }
        `;
    } else if (type === 'morph-rotate-shape') {
        return `
            .spinner-morph-rotate-shape {
                width: ${size}vmin;
                height: ${size}vmin;
                background-color: ${color};
                animation: morph-rotate ${speed}s ease-in-out infinite alternate;
				aspect-ratio: 1/1;
            }
            
            @keyframes morph-rotate {
                0% {
                    border-radius: 0%;
                    transform: rotate(0deg);
                }
                100% {
                    border-radius: 50%;
                    transform: rotate(180deg);
                }
            }
        `;
    } else if (type === 'cube-3d-rotate') {
        return `
            .spinner-cube-3d-rotate {
                width: ${size}vmin;
                height: ${size}vmin;
                position: relative;
                transform-style: preserve-3d;
                animation: rotate-cube-3d ${speed}s linear infinite;
				aspect-ratio: 1/1;
            }
            
            .spinner-cube-3d-rotate div {
                position: absolute;
                width: 90%;
                height: 90%;
                background-color: ${color};
                border: 0.1em solid #fff;
            }
            
            .spinner-cube-3d-rotate .front  { transform: translateZ(45%); }
            .spinner-cube-3d-rotate .back   { transform: rotateY(180deg) translateZ(45%); }
            .spinner-cube-3d-rotate .right  { transform: rotateY(90deg) translateZ(45%); }
            .spinner-cube-3d-rotate .left   { transform: rotateY(-90deg) translateZ(45%); }
            .spinner-cube-3d-rotate .top    { transform: rotateX(90deg) translateZ(45%); }
            .spinner-cube-3d-rotate .bottom { transform: rotateX(-90deg) translateZ(45%); }
            
            @keyframes rotate-cube-3d {
                from { transform: rotateX(0deg) rotateY(0deg); }
                to { transform: rotateX(360deg) rotateY(360deg); }
            }
        `;
    } else if (type === 'ripple-dual-waves') {
        return `
            .spinner-ripple-dual-waves {
                width: ${size}vmin;
                height: ${size}vmin;
                position: relative;
				aspect-ratio: 1/1;
            }
            
            .spinner-ripple-dual-waves div {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                width: 0%;
                height: 0%;
                border: ${size*0.08}vmin solid ${color};
                border-radius: 50%;
                background: transparent;
                box-sizing: border-box;
                opacity: 0;
                animation: ripple-wave ${speed}s ease-out infinite;
            }
            
            .spinner-ripple-dual-waves div:nth-child(2) {
                animation-delay: ${speed/2}s;
            }
            
            @keyframes ripple-wave {
                0% {
                    width: 0%;
                    height: 0%;
                    opacity: 1;
                    transform: translate(-50%, -50%);
                }
                100% {
                    width: 100%;
                    height: 100%;
                    opacity: 0;
                    transform: translate(-50%, -50%);
                }
            }
        `;
    } else if (type === 'bars-folding') {
        return `
            .spinner-bars-folding {
                width: ${size}vmin;
                height: ${size}vmin;
                display: flex;
                justify-content: center;
                align-items: center;
                gap: 10%;
				aspect-ratio: 1/1;
            }
            
            .spinner-bars-folding div {
                width: 20%;
                height: 100%;
                background-color: ${color};
                transform-origin: bottom center;
                animation: fold-bars ${speed}s ease-in-out infinite;
            }
            
            .spinner-bars-folding div:nth-child(2) { animation-delay: 0.2s; }
            .spinner-bars-folding div:nth-child(3) { animation-delay: 0.4s; }
            
            @keyframes fold-bars {
                0%, 100% { transform: scaleY(1); }
                50% { transform: scaleY(0.2); }
            }
        `;
    } else if (type === 'orbit-square') {
        return `
            .spinner-orbit-square {
                width: ${size}vmin;
                height: ${size}vmin;
                position: relative;
				aspect-ratio: 1/1;
            }
            
            .spinner-orbit-square div {
                position: absolute;
                width: 20%;
                height: 20%;
                border-radius: 50%;
                background: ${color};
                animation: orbit-square-move ${speed}s linear infinite;
            }
            
            .spinner-orbit-square div:nth-child(2) {
                animation-delay: ${speed/2}s;
            }
            
            @keyframes orbit-square-move {
                0%   { top: 0%;   left: 0%; }
                25%  { top: 0%;   left: 80%; }
                50%  { top: 80%;  left: 80%; }
                75%  { top: 80%;  left: 0%; }
                100% { top: 0%;   left: 0%; }
            }
        `;
    } else if (type === 'cube-bounce-2') {
        return `
            .spinner-cube-bounce-2 {
                width: ${size}vmin;
                height: ${size}vmin;
                position: relative;
				aspect-ratio: 1/1;
            }
            
            .spinner-cube-bounce-2 div {
                position: absolute;
                width: 50%;
                height: 50%;
                background-color: ${color};
                animation: cube-move-2 ${speed}s ease-in-out infinite;
            }
            
            .spinner-cube-bounce-2 div:nth-child(2) {
                animation-delay: -${speed/2}s;
            }
            
            @keyframes cube-move-2 {
                25%  { transform: translateX(100%); }
                50%  { transform: translateX(100%) translateY(100%); }
                75%  { transform: translateY(100%); }
                100% { transform: translateX(0%) translateY(0%); }
            }
        `;
    }
    
    return '';
}

function generateSpinnerHTML(type, size, color, trackColor, speed, gap) {
    if (type === 'circle') {
        return `
            <div class="spinner">
                <div class="spinner-inner"></div>
            </div>
        `;
    } else if (type === 'progress-bar') {
		return `
			<div class="spinner">
				<div class="spinner-progress-bar">
					<div class="spinner-progress-bar-fill"></div>
				</div>
			</div>
		`;
	} else if (type === 'pulse') {
        return `
            <div class="spinner">
                <div class="spinner-pulse"></div>
            </div>
        `;
    } else if (type === 'dots') {
        return `
            <div class="spinner">
                <div class="spinner-dots">
                    <span></span>
                    <span></span>
                    <span></span>
                </div>
            </div>
        `;
    } else if (type === 'circle-pulse-ring') {
        return `
            <div class="spinner">
                <div class="spinner-circle-pulse-ring">
                    ${Array(8).fill('<div></div>').join('')}
                </div>
            </div>
        `;
    } else if (type === 'dual-line-ring') {
        return `
            <div class="spinner">
                <div class="spinner-dual-line-ring"></div>
            </div>
        `;
    } else if (type === 'grid-pulse-blocks') {
        return `
            <div class="spinner">
                <div class="spinner-grid-pulse-blocks">
                    ${Array(9).fill('<div></div>').join('')}
                </div>
            </div>
        `;
    } else if (type === 'corner-pulse-dots') {
        return `
            <div class="spinner">
                <div class="spinner-corner-pulse-dots">
                    ${Array(4).fill('<div></div>').join('')}
                </div>
            </div>
        `;
    } else if (type === 'bouncing-dots') {
        return `
            <div class="spinner">
                <div class="spinner-bouncing-dots">
                    ${Array(3).fill('<div></div>').join('')}
                </div>
            </div>
        `;
    } else if (type === 'square-pulse-morph') {
        return `
            <div class="spinner">
                <div class="spinner-square-pulse-morph"></div>
            </div>
        `;
    } else if (type === 'grid-scale-squares') {
        return `
            <div class="spinner">
                <div class="spinner-grid-scale-squares">
                    ${Array(4).fill('<div></div>').join('')}
                </div>
            </div>
        `;
    } else if (type === 'card-flip') {
        return `
            <div class="spinner">
                <div class="spinner-card-flip">
                    <div class="front"></div>
                    <div class="back"></div>
                </div>
            </div>
        `;
    } else if (type === 'bars-equalizer') {
        return `
            <div class="spinner">
                <div class="spinner-bars-equalizer">
                    ${Array(4).fill('<div></div>').join('')}
                </div>
            </div>
        `;
    } else if (type === 'matrix-pulse-dots') {
        return `
            <div class="spinner">
                <div class="spinner-matrix-pulse-dots">
                    ${Array(9).fill('<div></div>').join('')}
                </div>
            </div>
        `;
    } else if (type === 'dots-fade-trail') {
        return `
            <div class="spinner">
                <div class="spinner-dots-fade-trail">
                    ${Array(3).fill('<div></div>').join('')}
                </div>
            </div>
        `;
    } else if (type === 'double-ring-rotate') {
        return `
            <div class="spinner">
                <div class="spinner-double-ring-rotate">
                    <div class="one"></div>
                    <div class="two"></div>
                </div>
            </div>
        `;
    } else if (type === 'dots-circle-fade') {
		const dots = Array(6).fill(0).map((_, i) => 
			`<div style="transform: rotate(${i*60}deg) translate(0, -240%); animation-delay: ${i*0.2}s;"></div>`
		).join('');
		
		return `
			<div class="spinner">
				<div class="spinner-dots-circle-fade">
					${dots}
				</div>
			</div>
		`;
    } else if (type === 'double-dot-rotate') {
        return `
            <div class="spinner">
                <div class="spinner-double-dot-rotate"></div>
            </div>
        `;
    } else if (type === 'grid-expand-blocks') {
        return `
            <div class="spinner">
                <div class="spinner-grid-expand-blocks">
                    ${Array(9).fill('<div></div>').join('')}
                </div>
            </div>
        `;
    } else if (type === 'sliding-bar') {
        return `
            <div class="spinner">
                <div class="spinner-sliding-bar"></div>
            </div>
        `;
    } else if (type === 'ellipsis-dots') {
        return `
            <div class="spinner">
                <div class="spinner-ellipsis-dots">
                    ${Array(3).fill('<div></div>').join('')}
                </div>
            </div>
        `;
    } else if (type === 'border-pulse-ring') {
        return `
            <div class="spinner">
                <div class="spinner-border-pulse-ring"></div>
            </div>
        `;
    } else if (type === 'radial-pulse-expand') {
        return `
            <div class="spinner">
                <div class="spinner-radial-pulse-expand"></div>
            </div>
        `;
    } else if (type === 'bouncing-dot-box') {
        return `
            <div class="spinner">
                <div class="spinner-bouncing-dot-box">
                    <div></div>
                </div>
            </div>
        `;
    } else if (type === 'morph-rotate-shape') {
        return `
            <div class="spinner">
                <div class="spinner-morph-rotate-shape"></div>
            </div>
        `;
    } else if (type === 'cube-3d-rotate') {
        return `
            <div class="spinner">
                <div class="spinner-cube-3d-rotate">
                    <div class="front"></div>
                    <div class="back"></div>
                    <div class="right"></div>
                    <div class="left"></div>
                    <div class="top"></div>
                    <div class="bottom"></div>
                </div>
            </div>
        `;
    } else if (type === 'ripple-dual-waves') {
        return `
            <div class="spinner">
                <div class="spinner-ripple-dual-waves">
                    <div></div>
                    <div></div>
                </div>
            </div>
        `;
    } else if (type === 'bars-folding') {
        return `
            <div class="spinner">
                <div class="spinner-bars-folding">
                    ${Array(3).fill('<div></div>').join('')}
                </div>
            </div>
        `;
    } else if (type === 'orbit-square') {
        return `
            <div class="spinner">
                <div class="spinner-orbit-square">
                    <div></div>
                    <div></div>
                </div>
            </div>
        `;
    } else if (type === 'cube-bounce-2') {
        return `
            <div class="spinner">
                <div class="spinner-cube-bounce-2">
                    <div></div>
                    <div></div>
                </div>
            </div>
        `;
    }
    
    return '';
}


function generateC2PreloaderJS(template) {
  const tpl = JSON.stringify(template);
  
  const code = `/* Оптимізований C2 прелоадер з підтримкою шрифтів v2.1 */
(() => {
  const TEMPLATE_HTML = ${tpl};
  const FONT_LOAD_TIMEOUT = 3000;
  const MIN_DISPLAY_TIME = 1000;

  /* Допоміжні функції */
  const fadeOut = (el) => {
    el.style.transition = 'opacity .5s ease';
    el.style.opacity = 0;
    setTimeout(() => el.remove(), 500);
  };
  
  const rand = (min, max) => Math.random() * (max - min) + min;
  
  /* Функція завантаження шрифтів */
  const loadFonts = () => {
    return new Promise((resolve) => {
      // Знаходимо всі унікальні шрифти в шаблоні
      const fontMatches = TEMPLATE_HTML.match(/font-family:\s*['"]([^'"]+)['"]/gi) || [];
      const fontFamilies = [...new Set(
        fontMatches.map(f => f.replace(/font-family:\s*['"]|['"]/gi, ''))
      )].filter(f => !f.includes('sans-serif'));
      
      if (fontFamilies.length === 0) return resolve();

      let loadedCount = 0;
      const totalFonts = fontFamilies.length;
      const startTime = Date.now();

      const checkFont = (fontName) => {
        return new Promise((fontResolve) => {
          if (document.fonts.check('12px "' + fontName + '"')) {
            return fontResolve();
          }

          const timer = setTimeout(() => {
            console.warn('Font load timeout:', fontName);
            fontResolve();
          }, FONT_LOAD_TIMEOUT);

          document.fonts.load('12px "' + fontName + '"').then(() => {
            clearTimeout(timer);
            fontResolve();
          }).catch(() => {
            clearTimeout(timer);
            console.warn('Font load failed:', fontName);
            fontResolve();
          });
        });
      };

      const loadNextFont = async () => {
        const fontName = fontFamilies[loadedCount];
        await checkFont(fontName);
        
        loadedCount++;
        if (loadedCount >= totalFonts) {
          const elapsed = Date.now() - startTime;
          if (elapsed < MIN_DISPLAY_TIME) {
            setTimeout(resolve, MIN_DISPLAY_TIME - elapsed);
          } else {
            resolve();
          }
        } else {
          loadNextFont();
        }
      };

      loadNextFont();
    });
  };

  /* Основна функція вставки прелоадера */
  const insertPreloader = async () => {
    // Встановлюємо фон для HTML перед показом прелоадера
    const bgStyle = TEMPLATE_HTML.match(/<div[^>]+style="([^"]*background:[^;"]+)/i);
    if (bgStyle && bgStyle[1]) {
      document.documentElement.style.cssText = bgStyle[1] + '; overflow: hidden;';
    }

    // Створюємо контейнер
    const wrap = document.createElement('div');
    wrap.innerHTML = TEMPLATE_HTML;
    const preloader = wrap.firstElementChild;
    if (!preloader) return;
    
    // Встановлюємо тимчасовий шрифт
    preloader.style.fontFamily = 'sans-serif';
    preloader.style.opacity = '0';
    preloader.style.transition = 'opacity 0.3s ease';
    document.body.insertBefore(preloader, document.body.firstChild);
    
    // Завантажуємо шрифти
    try {
      await loadFonts();
    } catch (e) {
      console.warn('Font loading error:', e);
    }
    
    // Показуємо прелоадер
    preloader.style.opacity = '1';
    
    // Елементи прогресу
    const progressText = preloader.querySelector('.progress-text');
    const progressBar = preloader.querySelector('.spinner-progress-bar-fill');
    
    let shownProgress = 0;
    let targetProgress = 0;
    const progressCap = Math.floor(rand(90, 95));
    let intervalId;
    let finishTriggered = false;

    /* Оновлення прогресу */
    const updateProgress = () => {
      if (shownProgress < targetProgress) {
        shownProgress = Math.min(targetProgress, shownProgress + rand(1.2, 2.5));
        if (progressText) progressText.textContent = Math.floor(shownProgress) + '%';
        if (progressBar) progressBar.style.width = shownProgress + '%';
      }
    };

    /* Трекер прогресу C2 */
    const trackProgress = () => {
      intervalId = setInterval(() => {
        const runtime = window.cr_getC2Runtime?.();
        if (!runtime) return;
        
        let rawProgress = Math.floor((runtime.progress || 0) * 100);
        if (rawProgress > progressCap) rawProgress = progressCap;
        targetProgress = Math.max(targetProgress, rawProgress);
        updateProgress();
        
        if (shownProgress + 0.8 < progressCap) {
          shownProgress += rand(0.5, 1);
          if (progressText) progressText.textContent = Math.floor(shownProgress) + '%';
          if (progressBar) progressBar.style.width = shownProgress + '%';
        }
      }, 60);
      
      setTimeout(() => clearInterval(intervalId), 30000);
    };

    /* Перехоплення завершення завантаження */
    const hookFinish = () => {
      const runtime = window.cr_getC2Runtime?.();
      if (!runtime || typeof runtime.go_loading_finished !== 'function') {
        return setTimeout(hookFinish, 50);
      }
      
      const originalFinish = runtime.go_loading_finished.bind(runtime);
      runtime.go_loading_finished = function() {
        try { originalFinish(); } catch(e) { console.error(e); }
        finishTriggered = true;
        clearInterval(intervalId);
        
        // Плавне завершення до 100%
        const finishAnimation = () => {
          if (shownProgress < 100) {
            shownProgress = Math.min(100, shownProgress + rand(3, 7));
            if (progressText) progressText.textContent = Math.floor(shownProgress) + '%';
            if (progressBar) progressBar.style.width = shownProgress + '%';
            setTimeout(finishAnimation, 110);
          } else {
            // Видаляємо фон з HTML після завершення
            document.documentElement.style.cssText = '';
            hidePreloader(preloader);
          }
        };
        
        finishAnimation();
      };
      
      trackProgress();
    };

    /* Приховування прелоадера */
    const hidePreloader = (preloaderEl) => {
      const stdPreloader = document.querySelector('#c2-splash, #loader-wrapper, #c2-loader, .c2-splash, .c2-loader');
      if (!stdPreloader || getComputedStyle(stdPreloader).display === 'none') {
        fadeOut(preloaderEl);
      } else {
        const observer = new MutationObserver(() => {
          if (stdPreloader.offsetParent === null) {
            observer.disconnect();
            fadeOut(preloaderEl);
          }
        });
        observer.observe(stdPreloader, { attributes: true, attributeFilter: ['style'] });
      }
    };

    hookFinish();
  };

  /* Ініціалізація */
  if (document.body) {
    insertPreloader();
  } else {
    const observer = new MutationObserver((_, obs) => {
      if (document.body) {
        obs.disconnect();
        insertPreloader();
      }
    });
    observer.observe(document.documentElement, { childList: true });
  }
})();`;
  return hardObfuscate(code);
}

function generateC3PreloaderJS(template) {
  const tpl = JSON.stringify(template);
  
  const code = `/* Оптимізований C3 прелоадер з підтримкою шрифтів v2.1 */
(() => {
  const TEMPLATE_HTML = ${tpl};
  const FONT_LOAD_TIMEOUT = 3000;
  const MIN_DISPLAY_TIME = 1000;

  /* Допоміжні функції */
  const fadeOut = (el) => {
    el.style.transition = 'opacity .5s ease';
    el.style.opacity = 0;
    setTimeout(() => el.remove(), 500);
  };
  
  const rand = (min, max) => Math.random() * (max - min) + min;
  
  /* Функція завантаження шрифтів */
  const loadFonts = () => {
    return new Promise((resolve) => {
      // Знаходимо всі унікальні шрифти в шаблоні
      const fontMatches = TEMPLATE_HTML.match(/font-family:\s*['"]([^'"]+)['"]/gi) || [];
      const fontFamilies = [...new Set(
        fontMatches.map(f => f.replace(/font-family:\s*['"]|['"]/gi, ''))
      )].filter(f => !f.includes('sans-serif'));
      
      if (fontFamilies.length === 0) return resolve();

      let loadedCount = 0;
      const totalFonts = fontFamilies.length;
      const startTime = Date.now();

      const checkFont = (fontName) => {
        return new Promise((fontResolve) => {
          if (document.fonts.check('12px "' + fontName + '"')) {
            return fontResolve();
          }

          const timer = setTimeout(() => {
            console.warn('Font load timeout:', fontName);
            fontResolve();
          }, FONT_LOAD_TIMEOUT);

          document.fonts.load('12px "' + fontName + '"').then(() => {
            clearTimeout(timer);
            fontResolve();
          }).catch(() => {
            clearTimeout(timer);
            console.warn('Font load failed:', fontName);
            fontResolve();
          });
        });
      };

      const loadNextFont = async () => {
        const fontName = fontFamilies[loadedCount];
        await checkFont(fontName);
        
        loadedCount++;
        if (loadedCount >= totalFonts) {
          const elapsed = Date.now() - startTime;
          if (elapsed < MIN_DISPLAY_TIME) {
            setTimeout(resolve, MIN_DISPLAY_TIME - elapsed);
          } else {
            resolve();
          }
        } else {
          loadNextFont();
        }
      };

      loadNextFont();
    });
  };

  /* Основна функція вставки прелоадера */
  const insertPreloader = async () => {
    // Встановлюємо фон для HTML перед показом прелоадера
    const bgStyle = TEMPLATE_HTML.match(/<div[^>]+style="([^"]*background:[^;"]+)/i);
    if (bgStyle && bgStyle[1]) {
      document.documentElement.style.cssText = bgStyle[1] + '; overflow: hidden;';
    }

    // Створюємо контейнер
    const wrap = document.createElement('div');
    wrap.innerHTML = TEMPLATE_HTML;
    const preloader = wrap.firstElementChild;
    if (!preloader) return;
    
    // Встановлюємо тимчасовий шрифт
    preloader.style.fontFamily = 'sans-serif';
    preloader.style.opacity = '0';
    preloader.style.transition = 'opacity 0.3s ease';
    document.body.insertBefore(preloader, document.body.firstChild);
    
    // Завантажуємо шрифти
    try {
      await loadFonts();
    } catch (e) {
      console.warn('Font loading error:', e);
    }
    
    // Показуємо прелоадер
    preloader.style.opacity = '1';
    
    // Елементи прогресу
    const progressText = preloader.querySelector('.progress-text');
    const progressBar = preloader.querySelector('.spinner-progress-bar-fill');
    
    let shownProgress = 0;
    let targetProgress = 0;
    const progressCap = Math.floor(rand(90, 95));
    let finishTriggered = false;

    /* Оновлення прогресу */
    const updateProgress = () => {
      if (shownProgress < targetProgress) {
        shownProgress = Math.min(targetProgress, shownProgress + rand(1.2, 2.5));
        if (progressText) progressText.textContent = Math.floor(shownProgress) + '%';
        if (progressBar) progressBar.style.width = shownProgress + '%';
      }
      
      if (!finishTriggered) {
        requestAnimationFrame(updateProgress);
      }
    };

    /* Ініціалізація завантаження */
	const initLoading = () => {
	  if (typeof runOnStartup !== 'function') {
		return requestAnimationFrame(initLoading); // Оптимізована перевірка
	  }
	  
	  runOnStartup((runtime) => {
		// Трекер прогресу
		const progressInterval = setInterval(() => {
		  const rawProgress = Math.floor((runtime.loadingProgress || 0) * 100);
		  if (!finishTriggered) {
			targetProgress = Math.min(rawProgress, progressCap);
		  }
		}, 60);
		
		// Обробник завершення
		runtime.addEventListener('beforeprojectstart', () => {
		  finishTriggered = true;
		  clearInterval(progressInterval);
		  
		  // Анімація завершення (залишаємо як було)
		  const finishAnimation = () => {
			if (shownProgress < 100) {
			  shownProgress = Math.min(100, shownProgress + rand(3, 7));
			  if (progressText) progressText.textContent = Math.floor(shownProgress) + '%';
			  if (progressBar) progressBar.style.width = shownProgress + '%';
			  setTimeout(finishAnimation, 110); // Фіксована затримка для плавності
			} else {
			  // Видаляємо фон з HTML після завершення
			  document.documentElement.style.cssText = '';
			  fadeOut(preloader);
			}
		  };
		  
		  finishAnimation();
		});
		
		updateProgress();
	  });
	};

    initLoading();
  };

  /* Ініціалізація */
  if (document.body) {
    insertPreloader();
  } else {
    const observer = new MutationObserver((_, obs) => {
      if (document.body) {
        obs.disconnect();
        insertPreloader();
      }
    });
    observer.observe(document.documentElement, { childList: true });
  }
})();`;
  return hardObfuscate(code);
}





async function optimizeImage(imageData, maxSize = 512) {
  try {
    const img = await createImageBitmap(await (await fetch(imageData)).blob());
    
    // Масштабування зображення якщо воно більше maxSize
    let width = img.width;
    let height = img.height;
    
    if (width > maxSize || height > maxSize) {
      const ratio = Math.min(maxSize / width, maxSize / height);
      width = Math.floor(width * ratio);
      height = Math.floor(height * ratio);
    }
    
    // Створення canvas для оптимізації
    const canvas = new OffscreenCanvas(width, height);
    const ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, width, height);
    
    // Конвертація в PNG з якістю 90%
    const blob = await canvas.convertToBlob({type: 'image/png', quality: 0.9});
    return await new Promise((resolve) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.readAsDataURL(blob);
    });
  } catch (error) {
    console.error('Image optimization error:', error);
    return imageData; // Повертаємо оригінал у разі помилки
  }
}


async function downloadZip() {
  if (typeof JSZip === 'undefined') {
    console.error('JSZip не завантажено!');
    showToast('Error: Compression library not loaded', true);
    return;
  }

  try {
        const { template: tplC2, fontFiles } = await generateTemplate('c2');
        const { template: tplC3 } = await generateTemplate('c3');
    
    // Генеруємо коди для обох версій
    const c2Code = generateC2PreloaderJS(tplC2);
	const c3Code = generateC3PreloaderJS(tplC3);

    // Отримуємо лого (якщо є)
    const logoUpload = document.getElementById('logo-upload');
    let optimizedLogo = null;
	const showLogo = document.getElementById('show-logo').checked;
    
    if (showLogo && logoUpload.files.length > 0 && logoUpload.dataset.base64) {
      optimizedLogo = await optimizeImage(logoUpload.dataset.base64);
    }

    // Створюємо ZIP архів
    const zip = new JSZip();
    
    // Створюємо папки для обох версій
    const c2Folder = zip.folder("c2preloader");
    const c3Folder = zip.folder("c3preloader");
    const c3IconsFolder = c3Folder.folder("icons");
	const c3FontsFolder = c3Folder.folder("fonts");
	
        // Додаємо файли шрифтів (якщо є)
        fontFiles.forEach(font => {
            c2Folder.file(`fonts/${font.name}`, font.data.split(',')[1], { base64: true });
            c3FontsFolder.file(font.name, font.data.split(',')[1], { base64: true });
        });

    // Додаємо JS файли для обох версій
    c2Folder.file("c2_preloader.js", c2Code);
    c3Folder.file("c3_preloader.js", c3Code);

    // Додаємо лого та іконки (якщо є)
    if (showLogo && optimizedLogo) {
      const logoBlob = await fetch(optimizedLogo).then(r => r.blob());
      
      // Для C2 - в корінь папки
      c2Folder.file("loading-logo.png", logoBlob);
      
      // Для C3 - в папку icons
      c3IconsFolder.file("loading-logo.png", logoBlob);
      
      // Додаємо стандартні іконки
      const iconSizes = [256, 128, 114, 32, 16];
      for (const size of iconSizes) {
        const iconData = await generateIcon(optimizedLogo, size);
        const iconBlob = await fetch(iconData).then(r => r.blob());
        c2Folder.file(`icon-${size}.png`, iconBlob);
        c3IconsFolder.file(`icon-${size}.png`, iconBlob);
      }
    }

    // Генеруємо ZIP
    zip.generateAsync({type: "blob"})
      .then(content => {
        const url = URL.createObjectURL(content);
        const link = document.createElement('a');
        link.href = url;
        link.download = 'preloaders.zip';
        
        link.addEventListener('click', function() {
          setTimeout(() => {
            document.body.removeChild(link);
            URL.revokeObjectURL(url);
            showToast('ZIP archive downloaded successfully.');
          }, 100);
        }, {once: true});
        
        document.body.appendChild(link);
        link.click();
      })
      .catch(error => {
        console.error('ZIP generation error:', error);
        showToast('Archive creation error', true);
      });

  } catch (error) {
    console.error('General error:', error);
    showToast('An error occurred: ' + error.message, true);
  }
}

// Допоміжна функція для генерації іконок
async function generateIcon(imageData, size) {
  try {
    // Завантажуємо зображення
    const img = await createImageBitmap(await (await fetch(imageData)).blob());
    
    // Створюємо canvas
    const canvas = new OffscreenCanvas(size, size);
    const ctx = canvas.getContext('2d');
    
    // Очищаємо canvas (робимо його повністю прозорим)
    ctx.clearRect(0, 0, size, size);
    
    // Розраховуємо розміри для збереження пропорцій
    const ratio = Math.min(size / img.width, size / img.height);
    const width = img.width * ratio;
    const height = img.height * ratio;
    const x = (size - width) / 2;
    const y = (size - height) / 2;
    
    // Малюємо зображення
    ctx.drawImage(img, x, y, width, height);
    
    // Конвертуємо в PNG з прозорістю
    const blob = await canvas.convertToBlob({
      type: 'image/png',
      quality: 0.9,
      transparency: true
    });
    
    return await new Promise((resolve) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.readAsDataURL(blob);
    });
  } catch (error) {
    console.error('Error generating icon:', error);
    return imageData; // Повертаємо оригінал у разі помилки
  }
}

let toastTimeout;

function showToast(message, isSuccess = true) {
    // Видаляємо попередній toast, якщо він є
    const existingToast = document.querySelector('.toast-message');
    if (existingToast) {
        clearTimeout(toastTimeout);
        existingToast.remove();
    }
    
    const toast = document.createElement('div');
    toast.className = 'toast-message';
    const iconClass = isSuccess ? 'fa-circle-check' : 'fa-circle-xmark';
    const bgColor = isSuccess ? '#4caf50' : '#f44336';
    
    toast.innerHTML = `
        <div class="toast-content">
            <i class="fas ${iconClass} toast-icon"></i>
            <span class="toast-text">${message}</span>
        </div>
        <button class="toast-close">
            <i class="fas fa-times"></i>
        </button>
    `;
    
    // Додаємо стилі безпосередньо до елемента
    Object.assign(toast.style, {
        position: 'fixed',
        top: '20px',
        left: '50%',
        transform: 'translateX(-50%)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'space-between',
        padding: '14px 16px',
        background: bgColor,
        color: 'white',
        borderRadius: '8px',
        boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
        zIndex: '10001',
        opacity: '0',
        transition: 'all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)',
        fontFamily: 'Arial, sans-serif',
        fontSize: '16px',
        maxWidth: 'calc(100% - 40px)',
        width: 'auto',
        minWidth: '280px',
        boxSizing: 'border-box'
    });
    
    document.body.appendChild(toast);
    
    // Анімація появи
    setTimeout(() => {
        toast.style.opacity = '1';
        toast.style.top = '30px';
    }, 10);
    
    // Обробник кліку на хрестик
    const closeBtn = toast.querySelector('.toast-close');
    closeBtn.addEventListener('click', () => {
        clearTimeout(toastTimeout);
        toast.style.opacity = '0';
        toast.style.top = '20px';
        setTimeout(() => toast.remove(), 300);
    });
    
    // Автоматичне закриття через 3 секунди
    toastTimeout = setTimeout(() => {
        if (toast.parentNode) {
            toast.style.opacity = '0';
            toast.style.top = '20px';
            setTimeout(() => toast.remove(), 300);
        }
    }, 3000);
}     








function resetSettings() {
    // Створюємо модальне вікно
    const modal = document.createElement('div');
    modal.style.position = 'fixed';
    modal.style.top = '0';
    modal.style.left = '0';
    modal.style.right = '0';
    modal.style.bottom = '0';
    modal.style.backgroundColor = 'rgba(0,0,0,0.5)';
    modal.style.display = 'flex';
    modal.style.justifyContent = 'center';
    modal.style.alignItems = 'center';
    modal.style.zIndex = '10000';
    modal.style.opacity = '0';
    modal.style.transition = 'opacity 0.3s ease';
    
    // Контент модального вікна
    const modalContent = document.createElement('div');
    modalContent.style.background = 'white';
    modalContent.style.padding = '25px';
    modalContent.style.borderRadius = '10px';
    modalContent.style.width = '90%';
    modalContent.style.maxWidth = '400px';
    modalContent.style.boxShadow = '0 5px 15px rgba(0,0,0,0.3)';
    modalContent.style.transform = 'translateY(-20px)';
    modalContent.style.transition = 'transform 0.3s ease';
    
    modalContent.innerHTML = `
		<div style="text-align: center; margin-bottom: 20px;">
			<i class="fas fa-exclamation-triangle" style="font-size: 48px; color: #ff9800;"></i>
			<h3 style="margin: 15px 0 10px; color: #333;">Reset settings?</h3>
			<p style="color: #666; margin-bottom: 20px;">
				This will reset all settings to default.
			</p>
		</div>
		<div style="display: flex; gap: 10px; justify-content: center;">
			<button id="confirm-reset" style="
				padding: 10px 20px;
				background: #f44336;
				color: white;
				border: none;
				border-radius: 5px;
				cursor: pointer;
				transition: background 0.2s;
				flex: 1;
			">
				<i class="fas fa-trash-alt"></i> Reset
			</button>
			<button id="cancel-reset" style="
				padding: 10px 20px;
				background: #e0e0e0;
				color: #333;
				border: none;
				border-radius: 5px;
				cursor: pointer;
				transition: background 0.2s;
				flex: 1;
			">
				<i class="fas fa-times"></i> Cancel
			</button>
		</div>
    `;
    
    modal.appendChild(modalContent);
    document.body.appendChild(modal);
    
    // Анімація появи
    setTimeout(() => {
        modal.style.opacity = '1';
        modalContent.style.transform = 'translateY(0)';
    }, 10);
    

    // Обробник для кнопки скидання
    document.getElementById('confirm-reset').addEventListener('click', () => {
        // Скидаємо всі input, select елементи до значень за замовчуванням
        document.querySelectorAll('input, select').forEach(element => {
            if (element.type === 'checkbox') {
                // Для чекбоксів встановлюємо значення за замовчуванням (true для show-logo і show-text)
                if (element.id === 'show-logo' || element.id === 'show-text') {
                    element.checked = true;
                } else {
                    element.checked = element.defaultChecked;
                }
            } 
            else if (element.type !== 'file') { // Не скидаємо file input
                // Для select використовуємо перший option як значення за замовчуванням
                if (element.tagName === 'SELECT') {
                    element.selectedIndex = 0;
                } else {
                    element.value = element.defaultValue;
                }
                
                // Оновлюємо background-size для range-інпутів
                if (element.type === 'range') {
                    updateRangeBackground(element);
                }
            }
        });
        
        // У функції resetSettings():
        document.getElementById('font-source').selectedIndex = 1;
        document.getElementById('google-font-name').value = 'Madimi One';
        document.getElementById('font-upload').value = '';
        document.querySelector('.google-font-control').style.display = 'none';
        document.querySelector('.custom-font-control').style.display = 'none';
        
        // Явно скидаємо тип фону до "color" (перший option)
        document.getElementById('bg-type').selectedIndex = 0;
        
        // Явно скидаємо тип спінера до "circle" (перший option)
        document.getElementById('spinner-type').selectedIndex = 0;
        
        // Скидаємо завантаження логотипу
        document.getElementById('logo-upload').value = '';
        delete document.getElementById('logo-upload').dataset.base64;
        
        // Скидаємо вибрані позиції до значень за замовчуванням
        document.querySelectorAll('.position-option.selected').forEach(el => {
            el.classList.remove('selected');
        });
        
        // Встановлюємо позиції за замовчуванням (центр)
        document.querySelector('#spinner-position .position-option[data-pos="position-center"]').classList.add('selected');
        document.querySelector('#text-position .position-option[data-pos="position-center"]').classList.add('selected');
        
        // Встановлюємо напрямок градієнта за замовчуванням (to right)
        document.querySelectorAll('#gradient-direction .position-option').forEach(el => {
            el.classList.remove('selected');
        });
        document.querySelector('#gradient-direction .position-option[data-pos="to right"]').classList.add('selected');
        
        // Оновлюємо прев'ю
        updatePreview();
        
        // Закриваємо модальне вікно
        modal.style.opacity = '0';
        modalContent.style.transform = 'translateY(-20px)';
        
        setTimeout(() => {
            document.body.removeChild(modal);
        }, 300);
        
        // Показуємо тост про успішне скидання
        showToast('Settings reset to default.', true);
    });
        
    // Обробник для кнопки скасування
    document.getElementById('cancel-reset').addEventListener('click', () => {
        // Анімація закриття
        modal.style.opacity = '0';
        modalContent.style.transform = 'translateY(-20px)';
        
        setTimeout(() => {
            document.body.removeChild(modal);
        }, 300);
    });
}




        function updateRangeBackground(input) {
            const percent = (input.value - input.min) / (input.max - input.min) * 100;
            input.style.backgroundSize = `${percent}% 100%`;
        }

        // Ініціалізація range-інпутів при завантаженні сторінки
        document.addEventListener('DOMContentLoaded', function() {
            document.querySelectorAll('input[type="range"]').forEach(input => {
                updateRangeBackground(input);
            });
        });

                
function updatePositionButtons() {
    const spinnerType = document.getElementById('spinner-type').value;
    const spinnerPos = document.querySelector('#spinner-position .position-option.selected').dataset.pos;
    const textPos = document.querySelector('#text-position .position-option.selected').dataset.pos;
    
    const centerPositions = ['position-center', 'position-top-center', 'position-bottom-center'];
    const sideCenterPositions = ['position-left-in-center', 'position-right-in-center'];
    const isProgressBar = spinnerType === 'progress-bar';
    
    // Обробка позицій для спінера
    const spinnerPositionButtons = document.querySelectorAll('#spinner-position .position-option');
    
    spinnerPositionButtons.forEach(btn => {
        const pos = btn.dataset.pos;
        
        if (isProgressBar) {
            // Для прогресбара - активуємо тільки центральні позиції
            if (centerPositions.includes(pos)) {
                btn.style.opacity = '1';
                btn.style.pointerEvents = 'auto';
                btn.style.cursor = 'pointer';
            } else {
                btn.style.opacity = '0.5';
                btn.style.pointerEvents = 'none';
                btn.style.cursor = 'not-allowed';
                
                // Автовибір центру, якщо обрано недозволену позицію
                if (spinnerPos === pos) {
                    document.querySelector('#spinner-position .position-option[data-pos="position-center"]').click();
                }
            }
        } else {
            // Для інших типів - всі позиції доступні
            btn.style.opacity = '1';
            btn.style.pointerEvents = 'auto';
            btn.style.cursor = 'pointer';
        }
    });
    
    // Обробка позицій для тексту
    const textPositionButtons = document.querySelectorAll('#text-position .position-option');
    const showText = document.getElementById('show-text').checked;
    
    textPositionButtons.forEach(btn => {
        const pos = btn.dataset.pos;
        
        // Включаємо/виключаємо кнопки в залежності від того, чи показується текст
        btn.style.opacity = showText ? '1' : '0.5';
        btn.style.pointerEvents = showText ? 'auto' : 'none';
        btn.style.cursor = showText ? 'pointer' : 'not-allowed';
        
        // Якщо це progress-bar, додатково обмежуємо вибір позицій
        if (isProgressBar && showText) {
            if (centerPositions.includes(pos)) {
                btn.style.opacity = '1';
                btn.style.pointerEvents = 'auto';
                btn.style.cursor = 'pointer';
            } else {
                btn.style.opacity = '0.5';
                btn.style.pointerEvents = 'none';
                btn.style.cursor = 'not-allowed';
                
                // Автовибір центру, якщо обрано недозволену позицію
                if (textPos === pos) {
                    document.querySelector('#text-position .position-option[data-pos="position-center"]').click();
                }
            }
        }
    });
    
    // Обробка бічних центрів (лівий/правий)
    const shouldEnableSideCenter = !isProgressBar && (
        centerPositions.includes(spinnerPos) || 
        centerPositions.includes(textPos)
    );
    
    const sideCenterButtons = document.querySelectorAll(`
        #spinner-position .position-option[data-pos="position-left-in-center"],
        #spinner-position .position-option[data-pos="position-right-in-center"],
        #text-position .position-option[data-pos="position-left-in-center"],
        #text-position .position-option[data-pos="position-right-in-center"]
    `);
    
    sideCenterButtons.forEach(btn => {
        if (shouldEnableSideCenter) {
            btn.style.opacity = '1';
            btn.style.pointerEvents = 'auto';
            btn.style.cursor = 'pointer';
        } else {
            if (!btn.classList.contains('selected')) {
                btn.style.opacity = '0.5';
                btn.style.pointerEvents = 'none';
                btn.style.cursor = 'not-allowed';
            }
        }
    });
}
		
		document.getElementById('bg-type').addEventListener('change', updatePreview);
		document.querySelectorAll('.gradient-color').forEach(input => {
			input.addEventListener('input', updatePreview);
		});

	updatePositionButtons();	
		
document.getElementById('spinner-type').addEventListener('change', function() {
    updatePositionButtons();
    updatePreview();
});

// При зміні позиції спінера
document.querySelector('#spinner-position').addEventListener('click', function(e) {
    if (e.target.closest('.position-option')) {
        setTimeout(() => {
            updatePositionButtons();
            updatePreview();
        }, 10);
    }
});

// При зміні позиції тексту
document.querySelector('#text-position').addEventListener('click', function(e) {
    if (e.target.closest('.position-option')) {
        setTimeout(() => {
            updatePositionButtons();
            updatePreview();
        }, 10);
    }
});

// При зміні стану чекбоксу "Показувати текст"
document.getElementById('show-text').addEventListener('change', function() {
    updatePositionButtons();
    updatePreview();
});



// Додаємо обробник для вибору джерела шрифту
document.getElementById('font-source').addEventListener('change', function() {
    const source = this.value;
    
    // Очищаємо попередній шрифт
    const preview = document.getElementById('preview-preloader');
    preview.style.fontFamily = 'sans-serif';
    
    // Видаляємо всі попередні ресурси шрифтів
    document.querySelectorAll('link[href*="fonts.googleapis.com"], style[data-font]').forEach(el => el.remove());
    
    // Показуємо/ховаємо відповідні контроли
    document.querySelector('.google-font-control').style.display = 
        source === 'google' ? 'block' : 'none';
    document.querySelector('.custom-font-control').style.display = 
        source === 'custom' ? 'block' : 'none';
    
    // Якщо переключилися на Google Fonts і вже є введена назва - завантажуємо
    if (source === 'google') {
        const fontName = document.getElementById('google-font-name').value.trim();
        if (fontName) {
            const link = document.createElement('link');
            link.href = `https://fonts.googleapis.com/css?family=${encodeURIComponent(fontName)}&display=swap`;
            link.rel = 'stylesheet';
            link.onload = updatePreview;
            link.onerror = () => preview.style.fontFamily = 'sans-serif';
            document.head.appendChild(link);
        }
    }
    applyFontToPreview();
    updatePreview();
});

document.getElementById('google-font-name').addEventListener('input', function() {
    const fontName = this.value.trim();
    if (fontName) {
        // Remove the previous Google Font link if it exists
        const oldLink = document.querySelector('link[href*="fonts.googleapis.com"]');
        if (oldLink) oldLink.remove();
        
        const link = document.createElement('link');
        link.href = `https://fonts.googleapis.com/css?family=${encodeURIComponent(fontName)}&display=swap`;
        link.rel = 'stylesheet';
        
        link.onload = function() {
            console.log('Font loaded:', fontName);
            showToast(`Font "${fontName}" loaded successfully`, true);
            updatePreview();
        };
        
        link.onerror = function() {
            console.error('Error loading font:', fontName);
            showToast(`Error: font "${fontName}" not found`, false);
            // Revert to default font on error
            document.getElementById('preview-preloader').style.fontFamily = 'sans-serif';
        };
        
        document.head.appendChild(link);
    } else {
        // If input is empty, revert to default font
        document.getElementById('preview-preloader').style.fontFamily = 'sans-serif';
        updatePreview();
    }
});

document.getElementById('font-upload').addEventListener('change', updatePreview);



// Додати після інших обробників подій
document.getElementById('show-logo').addEventListener('change', updatePreview);
document.getElementById('logo-border-radius').addEventListener('input', updatePreview);




document.getElementById('email-link').addEventListener('click', function(e) {
  e.preventDefault();
  
  // Розбиваємо email на частини для більшої безпеки
  const parts = {
    name: 'kyrnasivskyj',
    domain: 'gmail',
    tld: 'com'
  };
  
  // Збираємо email
  const email = parts.name + '@' + parts.domain + '.' + parts.tld;
  const mailto = 'mailto:' + email;

  // Створюємо модальне вікно
  const modal = document.createElement('div');
  modal.style.position = 'fixed';
  modal.style.top = '0';
  modal.style.left = '0';
  modal.style.right = '0';
  modal.style.bottom = '0';
  modal.style.backgroundColor = 'rgba(0,0,0,0.5)';
  modal.style.display = 'flex';
  modal.style.justifyContent = 'center';
  modal.style.alignItems = 'center';
  modal.style.zIndex = '10000';
  modal.style.opacity = '0';
  modal.style.transition = 'opacity 0.3s ease';
  
  // Контент модального вікна
  const modalContent = document.createElement('div');
  modalContent.style.background = 'white';
  modalContent.style.padding = '25px';
  modalContent.style.borderRadius = '10px';
  modalContent.style.width = '90%';
  modalContent.style.maxWidth = '400px';
  modalContent.style.boxShadow = '0 5px 15px rgba(0,0,0,0.3)';
  modalContent.style.transform = 'translateY(-20px)';
  modalContent.style.transition = 'transform 0.3s ease';
  modalContent.style.textAlign = 'center';
  
  modalContent.innerHTML = `
    <div style="margin-bottom: 20px;">
      <i class="fas fa-envelope" style="font-size: 48px; color: var(--primary);"></i>
      <h3 style="margin: 15px 0 10px; color: #333;">Contact Email</h3>
      <div style="display: flex; align-items: center; justify-content: center; gap: 8px; margin-bottom: 20px;">
        <div style="
          padding: 10px 15px;
          background: #f5f7fa;
          border-radius: 6px;
          font-size: 18px;
          word-break: break-all;
          flex-grow: 1;
          text-align: center;
        ">${email}</div>
        <button id="copy-email-btn" style="
          padding: 10px 15px;
          background: var(--secondary);
          color: white;
          border: none;
          border-radius: 6px;
          cursor: pointer;
          transition: background 0.2s;
          flex-shrink: 0;
        ">
          <i class="fas fa-copy"></i>
        </button>
      </div>
      <div class="toast-message" id="email-toast" style="display: none; margin: 10px auto; max-width: 100%;"></div>
    </div>
    <div style="display: flex; gap: 10px; justify-content: center;">
      <a href="${mailto}" id="send-email-btn" style="
          padding: 10px 20px;
          background: var(--primary);
          color: white;
          border: none;
          border-radius: 5px;
          cursor: pointer;
          transition: background 0.2s;
          text-decoration: none;
          flex: 1;
          text-align: center;
		  font-size:13px;
      ">
        <i class="fas fa-paper-plane"></i> Send Email
      </a>
      <button id="close-email-modal" style="
          padding: 10px 20px;
          background: #e0e0e0;
          color: #333;
          border: none;
          border-radius: 5px;
          cursor: pointer;
          transition: background 0.2s;
          flex: 1;
		  font-size:13px;
      ">
        <i class="fas fa-times"></i> Close
      </button>
    </div>
  `;
  
  modal.appendChild(modalContent);
  document.body.appendChild(modal);
  
  // Анімація появи
  setTimeout(() => {
    modal.style.opacity = '1';
    modalContent.style.transform = 'translateY(0)';
  }, 10);
  
  let isProcessing = false;
  
  // Обробник для кнопки "Написати"
  document.getElementById('send-email-btn').addEventListener('click', function(e) {
    if (isProcessing) return;
    isProcessing = true;
    
    // Відкриваємо mailto посилання
    window.location.href = mailto;
    
    // Якщо через 1 секунду нічого не відкрилося, показуємо повідомлення
    setTimeout(() => {
      if (!document.hidden) { // Якщо вікно браузера все ще активне
        showToast('Email client not found. Email copied to clipboard.', false);
        
        // Копіюємо email в буфер
        copyToClipboard(email);
      }
      isProcessing = false;
    }, 1000);
    
    e.preventDefault();
  });
  
  // Обробник для кнопки "Копіювати"
  document.getElementById('copy-email-btn').addEventListener('click', function() {
    if (isProcessing) return;
    isProcessing = true;
    
    copyToClipboard(email);
    showToast('Email copied to clipboard!', true);
    
    setTimeout(() => {
      isProcessing = false;
    }, 1000);
  });
  
  // Обробник для кнопки закриття
  document.getElementById('close-email-modal').addEventListener('click', () => {
    // Анімація закриття
    modal.style.opacity = '0';
    modalContent.style.transform = 'translateY(-20px)';
    
    setTimeout(() => {
      document.body.removeChild(modal);
    }, 300);
  });
  
  // Функція для копіювання в буфер обміну
  function copyToClipboard(text) {
    const textarea = document.createElement('textarea');
    textarea.value = text;
    textarea.style.position = 'fixed';  // Щоб не прокручувало сторінку
    document.body.appendChild(textarea);
    textarea.select();
    
    try {
      document.execCommand('copy');
    } catch (err) {
      console.error('Copy error:', err);
    }
    
    document.body.removeChild(textarea);
  }
});

		

    });
</script>

</div>
</body>
</html>