import React, { useState, useEffect, useRef, useCallback } from 'react';
import { Upload, Download, Play, Settings, Type, Image as ImageIcon, Video, Loader2, AlignLeft, AlignCenter, AlignRight, MonitorPlay, Film, ArrowRight, Layers, Circle } from 'lucide-react';

// --- Utility Functions ---
const hexToRgb = (hex) => {
  let r = 0, g = 0, b = 0;
  if (hex.length === 4) {
    r = parseInt(hex[1] + hex[1], 16);
    g = parseInt(hex[2] + hex[2], 16);
    b = parseInt(hex[3] + hex[3], 16);
  } else if (hex.length === 7) {
    r = parseInt(hex.substring(1, 3), 16);
    g = parseInt(hex.substring(3, 5), 16);
    b = parseInt(hex.substring(5, 7), 16);
  }
  return [r, g, b];
};

const rgbToHex = (r, g, b) =>
  "#" + ((1 << 24) + (Math.round(r) << 16) + (Math.round(g) << 8) + Math.round(b)).toString(16).slice(1);

const interpolate = (start, end, progress) => start + (end - start) * progress;

const interpolateColor = (color1, color2, progress) => {
  const c1 = hexToRgb(color1);
  const c2 = hexToRgb(color2);
  return rgbToHex(
    interpolate(c1[0], c2[0], progress),
    interpolate(c1[1], c2[1], progress),
    interpolate(c1[2], c2[2], progress)
  );
};

const getEasedProgress = (progress, easingType) => {
  let p = progress * 2;
  if (p > 1) p = 2 - p;
  
  switch (easingType) {
    case 'linear': return p;
    case 'ease-in': return p * p * p;
    case 'ease-out': return 1 - Math.pow(1 - p, 3);
    case 'ease-in-out': return p < 0.5 ? 4 * p * p * p : 1 - Math.pow(-2 * p + 2, 3) / 2;
    case 'ease':
    default: return (Math.sin(p * Math.PI - Math.PI / 2) + 1) / 2;
  }
};

const getDimensions = (aspectRatio, resolution) => {
  const res = parseInt(resolution);
  if (aspectRatio === '16:9') return { w: res === 1080 ? 1920 : 1280, h: res };
  if (aspectRatio === '9:16') return { w: res, h: res === 1080 ? 1920 : 1280 };
  if (aspectRatio === '1:1') return { w: res, h: res };
  if (aspectRatio === '3:4') return { w: res === 1080 ? 810 : 540, h: res };
  if (aspectRatio === '4:5') return { w: res === 1080 ? 864 : 576, h: res };
  return { w: 1920, h: 1080 };
};

// --- Main Application ---
export default function App() {
  const [scriptsLoaded, setScriptsLoaded] = useState(false);
  const [text, setText] = useState('MEXICO MEXICO MEXICO MEXICO MEXICO MEXICO');
  const [fontFamily, setFontFamily] = useState('Inter');
  const [fontDataUrl, setFontDataUrl] = useState(null);
  const [duration, setDuration] = useState(6000);
  const [isExporting, setIsExporting] = useState(false);
  const [exportProgress, setExportProgress] = useState(0);
  
  // Layout & Canvas State
  const [pathMode, setPathMode] = useState('circle');
  const [textAlign, setTextAlign] = useState('center');
  const [verticalAlign, setVerticalAlign] = useState('center');
  const [singleLine, setSingleLine] = useState(true);
  const [aspectRatio, setAspectRatio] = useState('1:1');
  const [resolution, setResolution] = useState('1080');
  const [previewScale, setPreviewScale] = useState(1);
  const [canvasMargin, setCanvasMargin] = useState(50);

  // Animation & Scroll State
  const [easing, setEasing] = useState('linear');
  const [scrollType, setScrollType] = useState('cw');
  const [scrollAngle, setScrollAngle] = useState(45);

  // 3D Layers State
  const [layerCount, setLayerCount] = useState(0);
  const [layerColors, setLayerColors] = useState(['#0000ff', '#ff0000', '#ff8800', '#00ffff', '#00ff00', '#006600', '#8800ff', '#ff00ff']);
  const [layerEffect, setLayerEffect] = useState('wave');
  const [layerOffset, setLayerOffset] = useState(25);
  const [layerAngle, setLayerAngle] = useState(315);

  const previewWrapperRef = useRef(null);
  const wrapperRef = useRef(null);
  const containerRef = useRef(null);
  const layerRefs = useRef([]);
  
  // Circle Layout Refs
  const circleSvgRef = useRef(null);
  const circlePathRef = useRef(null);
  const circleWrapperRef = useRef(null);
  const circleLayerRefs = useRef([]);
  const textPathRefs = useRef([]);

  const animationRef = useRef(null);
  const textBoundsRef = useRef({ w: 0, h: 0 });

  const [config, setConfig] = useState({
    scale: { val: 80, min: 50, max: 200, animate: false, bounds: [10, 1500], step: 1, isColor: false },
    tracking: { val: 0.1, min: -0.05, max: 0.2, animate: false, bounds: [-0.2, 1], step: 0.01, isColor: false },
    leading: { val: 1.1, min: 0.8, max: 2.0, animate: false, bounds: [0.5, 3], step: 0.1, isColor: false },
    weight: { val: 900, min: 100, max: 900, animate: false, bounds: [100, 1000], step: 1, isColor: false },
    width: { val: 100, min: 50, max: 150, animate: false, bounds: [50, 200], step: 1, isColor: false },
    rotation: { val: 0, min: -180, max: 180, animate: false, bounds: [-360, 360], step: 1, isColor: false },
    circleRadius: { val: 400, min: 200, max: 600, animate: false, bounds: [50, 1500], step: 1, isColor: false },
    color: { val: '#000000', min: '#000000', max: '#ff0055', animate: false, isColor: true },
    bgColor: { val: '#ffffff', min: '#ffffff', max: '#000000', animate: false, isColor: true }
  });

  const configRef = useRef(config);
  useEffect(() => { configRef.current = config; }, [config]);

  const settingsRef = useRef({ 
    pathMode, aspectRatio, resolution, scrollType, scrollAngle, textAlign, verticalAlign, 
    canvasMargin, singleLine, layerCount, layerColors, layerEffect, layerOffset, layerAngle, easing 
  });
  
  useEffect(() => { 
    settingsRef.current = { 
      pathMode, aspectRatio, resolution, scrollType, scrollAngle, textAlign, verticalAlign, 
      canvasMargin, singleLine, layerCount, layerColors, layerEffect, layerOffset, layerAngle, easing 
    }; 
  }, [pathMode, aspectRatio, resolution, scrollType, scrollAngle, textAlign, verticalAlign, canvasMargin, singleLine, layerCount, layerColors, layerEffect, layerOffset, layerAngle, easing]);

  // Handle Resize for WYSIWYG Canvas Scaling
  useEffect(() => {
    const updateScale = () => {
      if (!previewWrapperRef.current) return;
      const { w, h } = getDimensions(aspectRatio, resolution);
      const wrapperW = previewWrapperRef.current.clientWidth;
      const wrapperH = previewWrapperRef.current.clientHeight;
      const scale = Math.min(wrapperW / w, wrapperH / h) * 0.95;
      setPreviewScale(scale);
    };
    updateScale();
    window.addEventListener('resize', updateScale);
    return () => window.removeEventListener('resize', updateScale);
  }, [aspectRatio, resolution]);

  // Load external dependencies
  useEffect(() => {
    const loadScript = (src) => new Promise((resolve) => {
      if (document.querySelector(`script[src="${src}"]`)) return resolve();
      const script = document.createElement('script');
      script.src = src;
      script.onload = resolve;
      document.head.appendChild(script);
    });

    Promise.all([
      loadScript('https://cdnjs.cloudflare.com/ajax/libs/opentype.js/1.3.4/opentype.min.js'),
      loadScript('https://cdnjs.cloudflare.com/ajax/libs/gif.js/0.2.0/gif.js')
    ]).then(() => setScriptsLoaded(true));
  }, []);

  // Main Live Animation Loop
  useEffect(() => {
    let startTime = performance.now();

    const renderLoop = (time) => {
      if (isExporting) return;

      const currentConfig = configRef.current;
      const settings = settingsRef.current;
      const { w, h } = getDimensions(settings.aspectRatio, settings.resolution);
      
      const linearProgress = ((time - startTime) % duration) / duration;
      const easedProgress = getEasedProgress(linearProgress, settings.easing);

      if (wrapperRef.current && containerRef.current) {
        textBoundsRef.current = {
          w: wrapperRef.current.offsetWidth,
          h: wrapperRef.current.offsetHeight
        };
        const tW = textBoundsRef.current.w;
        const tH = textBoundsRef.current.h;

        const cScale = currentConfig.scale.animate ? interpolate(currentConfig.scale.min, currentConfig.scale.max, easedProgress) : currentConfig.scale.val;
        const cTracking = currentConfig.tracking.animate ? interpolate(currentConfig.tracking.min, currentConfig.tracking.max, easedProgress) : currentConfig.tracking.val;
        const cLeading = currentConfig.leading.animate ? interpolate(currentConfig.leading.min, currentConfig.leading.max, easedProgress) : currentConfig.leading.val;
        const cWeight = currentConfig.weight.animate ? interpolate(currentConfig.weight.min, currentConfig.weight.max, easedProgress) : currentConfig.weight.val;
        const cWidth = currentConfig.width.animate ? interpolate(currentConfig.width.min, currentConfig.width.max, easedProgress) : currentConfig.width.val;
        const cRotation = currentConfig.rotation.animate ? interpolate(currentConfig.rotation.min, currentConfig.rotation.max, easedProgress) : currentConfig.rotation.val;
        
        const cColor = currentConfig.color.animate ? interpolateColor(currentConfig.color.min, currentConfig.color.max, easedProgress) : currentConfig.color.val;
        const cBgColor = currentConfig.bgColor.animate ? interpolateColor(currentConfig.bgColor.min, currentConfig.bgColor.max, easedProgress) : currentConfig.bgColor.val;

        // Container scroll/rotation transforms
        let translateX = 0;
        let translateY = 0;
        let scrollRotation = 0;

        if (settings.scrollType !== 'none') {
          const offX = (w + tW) / 2;
          const offY = (h + tH) / 2;
          switch (settings.scrollType) {
            case 'ltr': translateX = interpolate(-offX, offX, linearProgress); break;
            case 'rtl': translateX = interpolate(offX, -offX, linearProgress); break;
            case 'ttb': translateY = interpolate(-offY, offY, linearProgress); break;
            case 'btt': translateY = interpolate(offY, -offY, linearProgress); break;
            case 'custom':
              const rad = settings.scrollAngle * Math.PI / 180;
              const dist = (Math.sqrt(w*w + h*h) + Math.sqrt(tW*tW + tH*tH)) / 2;
              translateX = Math.cos(rad) * interpolate(-dist, dist, linearProgress);
              translateY = Math.sin(rad) * interpolate(-dist, dist, linearProgress);
              break;
            case 'cw': scrollRotation = interpolate(0, 360, linearProgress); break;
            case 'ccw': scrollRotation = interpolate(360, 0, linearProgress); break;
          }
        }
        
        const finalRotation = cRotation + scrollRotation;
        containerRef.current.style.backgroundColor = cBgColor;

        const processLayerTransforms = (i, dirX, dirY) => {
          let lTransX = 0;
          let lTransY = 0;
          let lOpacity = 1;

          if (i > 0) {
            const maxDist = settings.layerOffset * i;
            let currentDist = maxDist;

            if (settings.layerEffect === 'extrude') {
              currentDist = interpolate(0, maxDist, easedProgress);
            } else if (settings.layerEffect === 'reveal') {
              const step = 1 / settings.layerCount;
              const startP = (i - 1) * step;
              const endP = i * step;
              let phase = 0;
              if (easedProgress > startP) phase = Math.min(1, (easedProgress - startP) / (endP - startP));
              currentDist = maxDist * phase;
            } else if (settings.layerEffect === 'back_reveal') {
              const reverseI = settings.layerCount - i + 1;
              const step = 1 / settings.layerCount;
              const startP = (reverseI - 1) * step;
              const endP = reverseI * step;
              let phase = 0;
              if (easedProgress > startP) phase = Math.min(1, (easedProgress - startP) / (endP - startP));
              currentDist = maxDist * phase;
            } else if (settings.layerEffect === 'step_reveal') {
              const step = 1 / settings.layerCount;
              const startP = (i - 1) * step;
              if (easedProgress >= startP) {
                currentDist = maxDist;
              } else {
                currentDist = 0;
                lOpacity = 0;
              }
            }

            lTransX = dirX * currentDist;
            lTransY = dirY * currentDist;

            if (settings.layerEffect === 'wave') {
              const perpX = -dirY; 
              const perpY = dirX;
              const waveMag = Math.sin((linearProgress * Math.PI * 2) + (i * 0.8)) * (settings.layerOffset * 1.5);
              lTransX += perpX * waveMag;
              lTransY += perpY * waveMag;
            }
          }
          return { lTransX, lTransY, lOpacity };
        };

        const lRad = settings.layerAngle * Math.PI / 180;
        const dirX = Math.cos(lRad);
        const dirY = Math.sin(lRad);

        if (settings.pathMode === 'circle') {
          const cx = w / 2;
          const cy = h / 2;
          const cRadius = currentConfig.circleRadius.animate ? interpolate(currentConfig.circleRadius.min, currentConfig.circleRadius.max, easedProgress) : currentConfig.circleRadius.val;
          const pathD = `M ${cx},${cy} m -${cRadius}, 0 a ${cRadius},${cRadius} 0 1,1 ${cRadius * 2},0 a ${cRadius},${cRadius} 0 1,1 -${cRadius * 2},0`;

          if (circlePathRef.current) circlePathRef.current.setAttribute('d', pathD);

          for (let idx = 0; idx <= settings.layerCount; idx++) {
            const i = settings.layerCount - idx;
            const lEl = circleLayerRefs.current[i];
            if (!lEl) continue;

            lEl.style.fontSize = `${cScale}px`;
            lEl.style.letterSpacing = `${cTracking}em`;
            lEl.style.fontVariationSettings = `"wght" ${cWeight}, "wdth" ${cWidth}`;
            lEl.setAttribute('fill', i === 0 ? cColor : settings.layerColors[i - 1]);

            const { lTransX, lTransY, lOpacity } = processLayerTransforms(i, dirX, dirY);
            lEl.setAttribute('transform', `translate(${lTransX}, ${lTransY})`);
            lEl.style.opacity = lOpacity;
          }

          if (circleWrapperRef.current) {
            circleWrapperRef.current.setAttribute('transform', `translate(${translateX}, ${translateY}) rotate(${finalRotation} ${cx} ${cy})`);
          }
        } else {
          // Standard Block Mode
          for (let idx = 0; idx <= settings.layerCount; idx++) {
            const i = settings.layerCount - idx;
            const lEl = layerRefs.current[i];
            if (!lEl) continue;

            lEl.style.fontSize = `${cScale}px`;
            lEl.style.letterSpacing = `${cTracking}em`;
            lEl.style.lineHeight = cLeading;
            lEl.style.fontVariationSettings = `"wght" ${cWeight}, "wdth" ${cWidth}`;
            lEl.style.color = i === 0 ? cColor : settings.layerColors[i - 1];

            const { lTransX, lTransY, lOpacity } = processLayerTransforms(i, dirX, dirY);
            lEl.style.transform = `translate(${lTransX}px, ${lTransY}px)`;
            lEl.style.opacity = lOpacity;
          }
          wrapperRef.current.style.transform = `translate(${translateX}px, ${translateY}px) rotate(${finalRotation}deg)`;
        }
      }
      animationRef.current = requestAnimationFrame(renderLoop);
    };

    animationRef.current = requestAnimationFrame(renderLoop);
    return () => cancelAnimationFrame(animationRef.current);
  }, [duration, isExporting]);

  // Handle Custom Font Upload
  const handleFileUpload = async (e) => {
    const file = e.target.files[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = (ev) => setFontDataUrl(ev.target.result);
    reader.readAsDataURL(file);

    const arrayBuffer = await file.arrayBuffer();
    const fontName = `CustomFont_${Date.now()}`;
    const font = new FontFace(fontName, arrayBuffer);
    
    await font.load();
    document.fonts.add(font);
    setFontFamily(fontName);

    if (window.opentype) {
      if (file.name.toLowerCase().endsWith('.woff2')) {
        console.warn("WOFF2 parsing is not natively supported by opentype.js.");
      } else {
        try {
          const parsed = window.opentype.parse(arrayBuffer);
          if (parsed.tables.fvar) {
            const newConfig = { ...configRef.current };
            parsed.tables.fvar.axes.forEach(axis => {
              if (axis.tag === 'wght') newConfig.weight = { ...newConfig.weight, bounds: [axis.minValue, axis.maxValue], min: axis.minValue, max: axis.maxValue, val: axis.defaultValue };
              if (axis.tag === 'wdth') newConfig.width = { ...newConfig.width, bounds: [axis.minValue, axis.maxValue], min: axis.minValue, max: axis.maxValue, val: axis.defaultValue };
            });
            setConfig(newConfig);
          }
        } catch (err) { console.warn("Opentype parsing error:", err); }
      }
    }
  };

  // Generate Frame SVG
  const getFrameSvgDataUrl = (progress, width, height) => {
    const currentConfig = configRef.current;
    const settings = settingsRef.current;
    
    const linearProgress = progress;
    const easedProgress = getEasedProgress(linearProgress, settings.easing);

    const cScale = currentConfig.scale.animate ? interpolate(currentConfig.scale.min, currentConfig.scale.max, easedProgress) : currentConfig.scale.val;
    const cTracking = currentConfig.tracking.animate ? interpolate(currentConfig.tracking.min, currentConfig.tracking.max, easedProgress) : currentConfig.tracking.val;
    const cLeading = currentConfig.leading.animate ? interpolate(currentConfig.leading.min, currentConfig.leading.max, easedProgress) : currentConfig.leading.val;
    const cWeight = currentConfig.weight.animate ? interpolate(currentConfig.weight.min, currentConfig.weight.max, easedProgress) : currentConfig.weight.val;
    const cWidth = currentConfig.width.animate ? interpolate(currentConfig.width.min, currentConfig.width.max, easedProgress) : currentConfig.width.val;
    const cRotation = currentConfig.rotation.animate ? interpolate(currentConfig.rotation.min, currentConfig.rotation.max, easedProgress) : currentConfig.rotation.val;
    const cColor = currentConfig.color.animate ? interpolateColor(currentConfig.color.min, currentConfig.color.max, easedProgress) : currentConfig.color.val;
    const cBgColor = currentConfig.bgColor.animate ? interpolateColor(currentConfig.bgColor.min, currentConfig.bgColor.max, easedProgress) : currentConfig.bgColor.val;

    const tW = textBoundsRef.current.w || width;
    const tH = textBoundsRef.current.h || height;

    let translateX = 0;
    let translateY = 0;
    let scrollRotation = 0;

    if (settings.scrollType !== 'none') {
      const offX = (width + tW) / 2;
      const offY = (height + tH) / 2;
      switch (settings.scrollType) {
        case 'ltr': translateX = interpolate(-offX, offX, linearProgress); break;
        case 'rtl': translateX = interpolate(offX, -offX, linearProgress); break;
        case 'ttb': translateY = interpolate(-offY, offY, linearProgress); break;
        case 'btt': translateY = interpolate(offY, -offY, linearProgress); break;
        case 'custom':
          const rad = settings.scrollAngle * Math.PI / 180;
          const dist = (Math.sqrt(width*width + height*height) + Math.sqrt(tW*tW + tH*tH)) / 2;
          translateX = Math.cos(rad) * interpolate(-dist, dist, linearProgress);
          translateY = Math.sin(rad) * interpolate(-dist, dist, linearProgress);
          break;
        case 'cw': scrollRotation = interpolate(0, 360, linearProgress); break;
        case 'ccw': scrollRotation = interpolate(360, 0, linearProgress); break;
      }
    }

    const finalRotation = cRotation + scrollRotation;
    const fontFaceRule = fontDataUrl ? `@font-face { font-family: '${fontFamily}'; src: url('${fontDataUrl}'); }` : '';
    const safeText = text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
    const lRad = settings.layerAngle * Math.PI / 180;
    const dirX = Math.cos(lRad);
    const dirY = Math.sin(lRad);

    const getLayerOffset = (i) => {
      let lOpacity = 1, currentDist = settings.layerOffset * i;
      if (settings.layerEffect === 'extrude') {
        currentDist = interpolate(0, currentDist, easedProgress);
      } else if (settings.layerEffect === 'reveal' || settings.layerEffect === 'back_reveal') {
        const rev = settings.layerEffect === 'back_reveal';
        const step = 1 / settings.layerCount;
        const mappedI = rev ? (settings.layerCount - i + 1) : i;
        const startP = (mappedI - 1) * step, endP = mappedI * step;
        let phase = 0;
        if (easedProgress > startP) phase = Math.min(1, (easedProgress - startP) / (endP - startP));
        currentDist *= phase;
      } else if (settings.layerEffect === 'step_reveal') {
        const step = 1 / settings.layerCount;
        if (easedProgress < (i - 1) * step) { currentDist = 0; lOpacity = 0; }
      }
      let lTransX = dirX * currentDist, lTransY = dirY * currentDist;
      if (settings.layerEffect === 'wave') {
        const waveMag = Math.sin((linearProgress * Math.PI * 2) + (i * 0.8)) * (settings.layerOffset * 1.5);
        lTransX += -dirY * waveMag; lTransY += dirX * waveMag;
      }
      return { lTransX, lTransY, lOpacity };
    };

    let innerSvgContent = '';

    if (settings.pathMode === 'circle') {
      const circleText = safeText.replace(/\n/g, ' ');
      const cx = width / 2;
      const cy = height / 2;
      const cRadius = currentConfig.circleRadius.animate ? interpolate(currentConfig.circleRadius.min, currentConfig.circleRadius.max, easedProgress) : currentConfig.circleRadius.val;
      const pathD = `M ${cx},${cy} m -${cRadius}, 0 a ${cRadius},${cRadius} 0 1,1 ${cRadius * 2},0 a ${cRadius},${cRadius} 0 1,1 -${cRadius * 2},0`;

      let layersHtml = '';
      for (let idx = 0; idx <= settings.layerCount; idx++) {
        const i = settings.layerCount - idx;
        const { lTransX, lTransY, lOpacity } = i > 0 ? getLayerOffset(i) : { lTransX: 0, lTransY: 0, lOpacity: 1 };
        const color = i === 0 ? cColor : settings.layerColors[i - 1];
        
        layersHtml += `
          <text fill="${color}"
                style="font-size: ${cScale}px; letter-spacing: ${cTracking}em; font-variation-settings: 'wght' ${cWeight}, 'wdth' ${cWidth}; opacity: ${lOpacity}; font-family: '${fontFamily}', sans-serif; white-space: ${settings.singleLine ? 'nowrap' : 'pre-wrap'};"
                transform="translate(${lTransX}, ${lTransY})">
             <textPath href="#export-circle-path">${circleText}</textPath>
          </text>
        `;
      }

      innerSvgContent = `
        <defs>
          <path id="export-circle-path" d="${pathD}" />
        </defs>
        <g transform="translate(${translateX}, ${translateY}) rotate(${finalRotation} ${cx} ${cy})">
          ${layersHtml}
        </g>
      `;
    } else {
      const standardText = safeText.replace(/\n/g, '<br/>');
      const justifyContent = settings.scrollType !== 'none' && !['cw','ccw'].includes(settings.scrollType) ? 'center' : (settings.textAlign === 'left' ? 'flex-start' : settings.textAlign === 'right' ? 'flex-end' : 'center');
      const alignItems = settings.scrollType !== 'none' && !['cw','ccw'].includes(settings.scrollType) ? 'center' : (settings.verticalAlign === 'top' ? 'flex-start' : settings.verticalAlign === 'bottom' ? 'flex-end' : 'center');
      const whiteSpace = settings.singleLine ? 'nowrap' : 'pre-wrap';

      let layersHtml = '';
      for (let idx = 0; idx <= settings.layerCount; idx++) {
        const i = settings.layerCount - idx;
        const { lTransX, lTransY, lOpacity } = i > 0 ? getLayerOffset(i) : { lTransX: 0, lTransY: 0, lOpacity: 1 };
        const color = i === 0 ? cColor : settings.layerColors[i - 1];
        
        layersHtml += `
          <div style="
            position: ${i === 0 ? 'relative' : 'absolute'};
            top: 0; left: 0; right: 0; bottom: 0;
            font-size: ${cScale}px; letter-spacing: ${cTracking}em; line-height: ${cLeading};
            font-variation-settings: 'wght' ${cWeight}, 'wdth' ${cWidth};
            white-space: ${whiteSpace};
            color: ${color};
            display: flex;
            align-items: center;
            opacity: ${lOpacity};
            justify-content: ${settings.textAlign === 'left' ? 'flex-start' : settings.textAlign === 'right' ? 'flex-end' : 'center'};
            transform: translate(${lTransX}px, ${lTransY}px);
          ">${standardText}</div>
        `;
      }

      innerSvgContent = `
        <foreignObject width="100%" height="100%">
          <div xmlns="http://www.w3.org/1999/xhtml" style="
            display: flex; justify-content: ${justifyContent}; align-items: ${alignItems};
            width: 100%; height: 100%; margin: 0; padding: ${settings.canvasMargin}px; box-sizing: border-box;
            font-family: '${fontFamily}', sans-serif;
            text-align: ${settings.textAlign}; 
            overflow: hidden;
          ">
            <div style="transform: translate(${translateX}px, ${translateY}px) rotate(${finalRotation}deg); position: relative; flex-shrink: 0;">
              ${layersHtml}
            </div>
          </div>
        </foreignObject>
      `;
    }

    const svg = `
      <svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
        <style>${fontFaceRule}</style>
        <rect width="100%" height="100%" fill="${cBgColor}" />
        ${innerSvgContent}
      </svg>
    `;
    return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
  };

  const drawSvgToCanvas = (svgUrl, canvas, ctx) => {
    return new Promise((resolve) => {
      const img = new Image();
      img.crossOrigin = "anonymous";
      img.onload = () => {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.drawImage(img, 0, 0);
        resolve();
      };
      img.src = svgUrl;
    });
  };

  // Export GIF
  const exportGIF = async () => {
    if (!window.GIF) return alert("GIF library not loaded yet.");
    setIsExporting(true);
    setExportProgress(0);

    const { w: width, h: height } = getDimensions(aspectRatio, resolution);
    const fps = 20; 
    const frames = Math.floor((duration / 1000) * fps);
    const delay = 1000 / fps;

    const canvas = document.createElement('canvas');
    canvas.width = width; canvas.height = height;
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    const workerBlob = new Blob([`importScripts('https://cdnjs.cloudflare.com/ajax/libs/gif.js/0.2.0/gif.worker.js');`], { type: 'application/javascript' });
    const workerUrl = URL.createObjectURL(workerBlob);

    const gif = new window.GIF({
      workers: 2,
      quality: 10,
      width, height,
      workerScript: workerUrl
    });

    for (let i = 0; i < frames; i++) {
      const progress = i / frames;
      const svgUrl = getFrameSvgDataUrl(progress, width, height);
      await drawSvgToCanvas(svgUrl, canvas, ctx);
      gif.addFrame(ctx, { copy: true, delay });
      setExportProgress((i / frames) * 50);
    }

    gif.on('progress', p => setExportProgress(50 + (p * 50)));
    gif.on('finished', blob => {
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url; a.download = `typography-${aspectRatio.replace(':','x')}-${resolution}p.gif`;
      a.click();
      setIsExporting(false);
      URL.revokeObjectURL(workerUrl);
    });

    gif.render();
  };

  // Export MP4/WebM
  const exportVideo = async () => {
    setIsExporting(true);
    setExportProgress(0);

    const { w: width, h: height } = getDimensions(aspectRatio, resolution);
    const fps = 60;
    const frames = Math.floor((duration / 1000) * fps);

    const canvas = document.createElement('canvas');
    canvas.width = width; canvas.height = height;
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    let mimeType = 'video/mp4';
    if (!MediaRecorder.isTypeSupported(mimeType)) mimeType = 'video/webm;codecs=vp9';
    if (!MediaRecorder.isTypeSupported(mimeType)) mimeType = 'video/webm';

    const stream = canvas.captureStream(0);
    const track = stream.getVideoTracks()[0];
    const recorder = new MediaRecorder(stream, { mimeType, videoBitsPerSecond: 8000000 });
    const chunks = [];

    recorder.ondataavailable = e => chunks.push(e.data);
    recorder.onstop = () => {
      const blob = new Blob(chunks, { type: mimeType });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url; 
      a.download = `typography-${aspectRatio.replace(':','x')}-${resolution}p.${mimeType.includes('mp4') ? 'mp4' : 'webm'}`;
      a.click();
      setIsExporting(false);
    };

    recorder.start();

    for (let i = 0; i <= frames; i++) {
      const progress = i / frames;
      const svgUrl = getFrameSvgDataUrl(progress, width, height);
      await drawSvgToCanvas(svgUrl, canvas, ctx);
      
      track.requestFrame();
      setExportProgress((i / frames) * 100);
      await new Promise(r => setTimeout(r, 10));
    }

    recorder.stop();
  };

  // UI Components
  const updateConfig = (key, field, value) => {
    setConfig(prev => ({ ...prev, [key]: { ...prev[key], [field]: value } }));
  };

  const renderControl = (label, key) => {
    const item = config[key];
    return (
      <div className="mb-6 bg-neutral-800 p-4 rounded-xl border border-neutral-700">
        <div className="flex justify-between items-center mb-3">
          <label className="text-sm font-semibold text-neutral-200">{label}</label>
          <label className="flex items-center text-xs text-neutral-400 cursor-pointer">
            <input 
              type="checkbox" 
              checked={item.animate} 
              onChange={e => updateConfig(key, 'animate', e.target.checked)}
              className="mr-2 accent-blue-500 w-4 h-4 rounded border-neutral-600 bg-neutral-700" 
            />
            Animate
          </label>
        </div>

        {!item.isColor ? (
          <div className="space-y-3">
            {!item.animate ? (
              <div className="flex items-center gap-3">
                <span className="text-xs text-neutral-500 w-8">Val</span>
                <input type="range" min={item.bounds[0]} max={item.bounds[1]} step={item.step} value={item.val} onChange={e => updateConfig(key, 'val', parseFloat(e.target.value))} className="flex-1 accent-blue-500" />
                <span className="text-xs text-neutral-300 w-10 text-right">{item.val}</span>
              </div>
            ) : (
              <>
                <div className="flex items-center gap-3">
                  <span className="text-xs text-neutral-500 w-8">Min</span>
                  <input type="range" min={item.bounds[0]} max={item.bounds[1]} step={item.step} value={item.min} onChange={e => updateConfig(key, 'min', parseFloat(e.target.value))} className="flex-1 accent-blue-500" />
                  <span className="text-xs text-neutral-300 w-10 text-right">{item.min}</span>
                </div>
                <div className="flex items-center gap-3">
                  <span className="text-xs text-neutral-500 w-8">Max</span>
                  <input type="range" min={item.bounds[0]} max={item.bounds[1]} step={item.step} value={item.max} onChange={e => updateConfig(key, 'max', parseFloat(e.target.value))} className="flex-1 accent-blue-500" />
                  <span className="text-xs text-neutral-300 w-10 text-right">{item.max}</span>
                </div>
              </>
            )}
          </div>
        ) : (
          <div className="flex items-center gap-4">
            {!item.animate ? (
              <input type="color" value={item.val} onChange={e => updateConfig(key, 'val', e.target.value)} className="w-full h-8 rounded cursor-pointer border-0 bg-transparent" />
            ) : (
              <>
                <div className="flex-1">
                  <div className="text-[10px] text-neutral-500 mb-1 uppercase tracking-wider">Start</div>
                  <input type="color" value={item.min} onChange={e => updateConfig(key, 'min', e.target.value)} className="w-full h-8 rounded cursor-pointer border-0 bg-transparent" />
                </div>
                <div className="flex-1">
                  <div className="text-[10px] text-neutral-500 mb-1 uppercase tracking-wider">End</div>
                  <input type="color" value={item.max} onChange={e => updateConfig(key, 'max', e.target.value)} className="w-full h-8 rounded cursor-pointer border-0 bg-transparent" />
                </div>
              </>
            )}
          </div>
        )}
      </div>
    );
  };

  return (
    <div className="flex h-screen bg-neutral-950 text-white font-sans overflow-hidden">
      
      {/* Sidebar Controls */}
      <div className="w-80 flex-shrink-0 bg-neutral-900 border-r border-neutral-800 flex flex-col h-full overflow-y-auto">
        <div className="p-6 border-b border-neutral-800 flex items-center gap-3 sticky top-0 bg-neutral-900 z-20">
          <Type className="w-6 h-6 text-blue-400" />
          <h1 className="text-xl font-bold tracking-tight">Kinetic Type</h1>
        </div>

        <div className="p-6 space-y-6">
          {/* Text & Font Section */}
          <div className="space-y-4">
            <div>
              <div className="flex justify-between items-center mb-2">
                <label className="text-xs font-semibold text-neutral-500 uppercase tracking-wider block">Text</label>
                
                {/* Text Options Controls */}
                <div className="flex items-center gap-2">
                  <select 
                    value={verticalAlign} 
                    onChange={e => setVerticalAlign(e.target.value)} 
                    className="bg-neutral-800 text-xs font-medium text-neutral-300 border border-neutral-700 rounded p-1 outline-none"
                    disabled={pathMode === 'circle'}
                  >
                    <option value="top">Top</option>
                    <option value="center">Middle</option>
                    <option value="bottom">Bottom</option>
                  </select>
                  
                  <div className={`flex bg-neutral-800 rounded p-0.5 border border-neutral-700 ${pathMode === 'circle' ? 'opacity-50 pointer-events-none' : ''}`}>
                    <button onClick={() => setTextAlign('left')} className={`p-1 rounded ${textAlign === 'left' ? 'bg-neutral-600 text-white' : 'text-neutral-400 hover:text-white'}`}><AlignLeft className="w-3.5 h-3.5" /></button>
                    <button onClick={() => setTextAlign('center')} className={`p-1 rounded ${textAlign === 'center' ? 'bg-neutral-600 text-white' : 'text-neutral-400 hover:text-white'}`}><AlignCenter className="w-3.5 h-3.5" /></button>
                    <button onClick={() => setTextAlign('right')} className={`p-1 rounded ${textAlign === 'right' ? 'bg-neutral-600 text-white' : 'text-neutral-400 hover:text-white'}`}><AlignRight className="w-3.5 h-3.5" /></button>
                  </div>
                </div>
              </div>

              <div className="mb-2">
                 <label className="flex items-center text-xs text-neutral-400 cursor-pointer">
                    <input 
                      type="checkbox" 
                      checked={singleLine} 
                      onChange={e => setSingleLine(e.target.checked)}
                      className="mr-1.5 accent-blue-500 w-3.5 h-3.5 rounded border-neutral-600 bg-neutral-700" 
                    />
                    No Wrap (Single Line)
                  </label>
              </div>

              <textarea 
                value={text} 
                onChange={(e) => setText(e.target.value)}
                className="w-full bg-neutral-800 border border-neutral-700 rounded-lg p-3 text-sm text-neutral-200 focus:outline-none focus:border-blue-500 resize-none h-24"
              />
            </div>
            
            <div>
              <label className="text-xs font-semibold text-neutral-500 uppercase tracking-wider mb-2 block">Custom Font</label>
              <label className="flex items-center justify-center w-full gap-2 bg-neutral-800 hover:bg-neutral-700 border border-neutral-700 hover:border-neutral-600 transition-colors rounded-lg p-3 cursor-pointer group">
                <Upload className="w-4 h-4 text-neutral-400 group-hover:text-blue-400 transition-colors" />
                <span className="text-sm font-medium">{fontDataUrl ? fontFamily : 'Upload .ttf / .woff'}</span>
                <input type="file" accept=".ttf,.otf,.woff,.woff2" className="hidden" onChange={handleFileUpload} />
              </label>
            </div>
          </div>

          <hr className="border-neutral-800" />

          {/* Path Mode Layout Setup */}
          <div>
            <label className="flex items-center gap-2 text-xs font-semibold text-neutral-500 uppercase tracking-wider mb-4">
              <Circle className="w-4 h-4" /> Shape Path
            </label>
            <div className="flex bg-neutral-800 rounded-lg p-1 mb-4 border border-neutral-700">
              <button onClick={() => setPathMode('none')} className={`flex-1 text-xs py-1.5 rounded-md transition-colors ${pathMode === 'none' ? 'bg-neutral-600 text-white shadow-sm' : 'text-neutral-400 hover:text-white'}`}>Standard Block</button>
              <button onClick={() => setPathMode('circle')} className={`flex-1 text-xs py-1.5 rounded-md transition-colors ${pathMode === 'circle' ? 'bg-neutral-600 text-white shadow-sm' : 'text-neutral-400 hover:text-white'}`}>Circle Path</button>
            </div>
            
            {pathMode === 'circle' && (
              <div className="animate-in fade-in slide-in-from-top-2">
                {renderControl('Circle Radius (px)', 'circleRadius')}
              </div>
            )}
          </div>

          <hr className="border-neutral-800" />

          {/* 3D Layers Setup */}
          <div>
            <label className="flex items-center gap-2 text-xs font-semibold text-neutral-500 uppercase tracking-wider mb-4">
              <Layers className="w-4 h-4" /> 3D Stacked Layers
            </label>
            <div className="bg-neutral-800 p-4 rounded-xl border border-neutral-700">
              <div className="flex items-center gap-3 mb-4">
                <span className="text-xs text-neutral-400 w-12">Layers</span>
                <input type="range" min="0" max="8" step="1" value={layerCount} onChange={e => setLayerCount(parseInt(e.target.value))} className="flex-1 accent-blue-500" />
                <span className="text-xs text-neutral-300 w-4 text-right">{layerCount}</span>
              </div>
              
              {layerCount > 0 && (
                <>
                  <div className="mb-4">
                    <label className="text-[10px] text-neutral-400 mb-1 block">Animation Effect</label>
                    <select value={layerEffect} onChange={e => setLayerEffect(e.target.value)} className="w-full bg-neutral-900 border border-neutral-700 rounded p-2 text-sm text-white focus:outline-none focus:border-blue-500">
                      <option value="static">Static Block</option>
                      <option value="extrude">Extrude In/Out</option>
                      <option value="wave">Waving Stack</option>
                      <option value="reveal">Sequential Reveal</option>
                      <option value="back_reveal">Sequential Back Reveal</option>
                      <option value="step_reveal">Sequential Reveal (No Transition)</option>
                    </select>
                  </div>
                  <div className="flex items-center gap-3 mb-4">
                    <span className="text-xs text-neutral-400 w-12">Depth</span>
                    <input type="range" min="1" max="150" step="1" value={layerOffset} onChange={e => setLayerOffset(parseInt(e.target.value))} className="flex-1 accent-blue-500" />
                    <span className="text-xs text-neutral-300 w-8 text-right">{layerOffset}px</span>
                  </div>
                  <div className="flex items-center gap-3 mb-4">
                    <span className="text-xs text-neutral-400 w-12">Angle</span>
                    <input type="range" min="0" max="360" step="1" value={layerAngle} onChange={e => setLayerAngle(parseInt(e.target.value))} className="flex-1 accent-blue-500" />
                    <span className="text-xs text-neutral-300 w-8 text-right">{layerAngle}°</span>
                  </div>
                  <div className="space-y-2">
                    <label className="text-[10px] text-neutral-400 mb-1 block">Layer Colors (Front to Back)</label>
                    <div className="grid grid-cols-4 gap-2">
                      {Array.from({ length: layerCount }).map((_, i) => (
                        <input 
                          key={i} 
                          type="color" 
                          value={layerColors[i] || '#ffffff'} 
                          onChange={e => {
                            const newColors = [...layerColors];
                            newColors[i] = e.target.value;
                            setLayerColors(newColors);
                          }} 
                          className="w-full h-8 rounded cursor-pointer border-0 bg-transparent" 
                          title={`Layer ${i+1}`} 
                        />
                      ))}
                    </div>
                  </div>
                </>
              )}
            </div>
          </div>

          <hr className="border-neutral-800" />

          {/* Export Settings Setup */}
          <div>
            <label className="text-xs font-semibold text-neutral-500 uppercase tracking-wider mb-4 block">Export Setup</label>
            <div className="flex gap-3 mb-4">
              <div className="flex-1">
                <label className="text-[10px] text-neutral-400 mb-1 block">Aspect Ratio</label>
                <select value={aspectRatio} onChange={e => setAspectRatio(e.target.value)} className="w-full bg-neutral-800 border border-neutral-700 rounded p-2 text-sm text-white focus:outline-none focus:border-blue-500">
                  <option value="16:9">16:9 Landscape</option>
                  <option value="9:16">9:16 Portrait</option>
                  <option value="1:1">1:1 Square</option>
                  <option value="3:4">3:4 Portrait</option>
                  <option value="4:5">4:5 Portrait</option>
                </select>
              </div>
              <div className="flex-1">
                <label className="text-[10px] text-neutral-400 mb-1 block">Resolution</label>
                <select value={resolution} onChange={e => setResolution(e.target.value)} className="w-full bg-neutral-800 border border-neutral-700 rounded p-2 text-sm text-white focus:outline-none focus:border-blue-500">
                  <option value="720">720p</option>
                  <option value="1080">1080p</option>
                </select>
              </div>
            </div>
            <div className="mb-4">
              <label className="text-[10px] text-neutral-400 mb-1 block">Canvas Margin (px)</label>
              <div className="flex items-center gap-3">
                <input type="range" min="0" max="500" step="10" value={canvasMargin} onChange={e => setCanvasMargin(parseInt(e.target.value))} className="flex-1 accent-blue-500" />
                <span className="text-xs text-neutral-300 w-10 text-right">{canvasMargin}px</span>
              </div>
            </div>
          </div>

          <hr className="border-neutral-800" />

          {/* Animation Setup */}
          <div>
             <label className="text-xs font-semibold text-neutral-500 uppercase tracking-wider mb-4 block">Animation Loop</label>
             <div className="flex items-center gap-3 mb-4">
                <span className="text-xs text-neutral-400 w-12">Speed</span>
                <input type="range" min="500" max="10000" step="100" value={duration} onChange={e => setDuration(parseInt(e.target.value))} className="flex-1 accent-blue-500" />
                <span className="text-xs text-neutral-300 w-10 text-right">{(duration/1000).toFixed(1)}s</span>
              </div>

              <div className="mb-6">
                <label className="text-[10px] text-neutral-400 mb-1 block">Easing Progress Curve</label>
                <select value={easing} onChange={e => setEasing(e.target.value)} className="w-full bg-neutral-900 border border-neutral-700 rounded p-2 text-sm text-white focus:outline-none focus:border-blue-500">
                  <option value="ease">Ease (Smooth)</option>
                  <option value="ease-in">Ease In</option>
                  <option value="ease-out">Ease Out</option>
                  <option value="ease-in-out">Ease In-Out</option>
                  <option value="linear">Linear</option>
                </select>
              </div>
              
              {/* Continuous Scroll Settings */}
              <div className="bg-neutral-800 p-4 rounded-xl border border-neutral-700 mb-6">
                <label className="text-sm font-semibold text-neutral-200 mb-3 block">Continuous Scroll</label>
                <select value={scrollType} onChange={e => setScrollType(e.target.value)} className="w-full bg-neutral-900 border border-neutral-700 rounded p-2 text-sm text-white focus:outline-none focus:border-blue-500 mb-3">
                  <option value="none">None</option>
                  <option value="ltr">Left to Right</option>
                  <option value="rtl">Right to Left</option>
                  <option value="ttb">Top to Bottom</option>
                  <option value="btt">Bottom to Top</option>
                  <option value="custom">Custom Angle...</option>
                  <option value="cw">Spin Clockwise ↻</option>
                  <option value="ccw">Spin Counter-Clockwise ↺</option>
                </select>
                
                {scrollType === 'custom' && (
                  <div className="flex items-center gap-3">
                    <span className="text-xs text-neutral-500 w-8">Angle</span>
                    <input type="range" min="0" max="360" step="1" value={scrollAngle} onChange={e => setScrollAngle(parseInt(e.target.value))} className="flex-1 accent-blue-500" />
                    <span className="text-xs text-neutral-300 w-10 text-right">{scrollAngle}°</span>
                  </div>
                )}
              </div>
          </div>

          {/* Controls */}
          <div>
            <label className="text-xs font-semibold text-neutral-500 uppercase tracking-wider mb-4 block">Typography Settings</label>
            {renderControl('Scale (px)', 'scale')}
            {renderControl('Tracking (em)', 'tracking')}
            {renderControl('Leading', 'leading')}
            {renderControl('Rotation (deg)', 'rotation')}
          </div>

          <div>
            <label className="text-xs font-semibold text-neutral-500 uppercase tracking-wider mb-4 block">Variable Axes</label>
            {renderControl('Weight (wght)', 'weight')}
            {renderControl('Width (wdth)', 'width')}
          </div>

          <div>
            <label className="text-xs font-semibold text-neutral-500 uppercase tracking-wider mb-4 block">Colors</label>
            {renderControl('Font Color', 'color')}
            {renderControl('Background', 'bgColor')}
          </div>
        </div>
      </div>

      {/* Main Preview Area */}
      <div className="flex-1 flex flex-col relative bg-neutral-950">
        
        {/* Top bar with export actions */}
        <div className="absolute top-0 w-full p-4 flex justify-end gap-3 z-10 pointer-events-none">
          <div className="pointer-events-auto flex gap-3">
            <button 
              onClick={exportGIF} 
              disabled={isExporting || !scriptsLoaded}
              className="flex items-center gap-2 bg-neutral-800/80 backdrop-blur border border-neutral-700 hover:border-neutral-500 text-white px-4 py-2 rounded-lg text-sm font-medium transition-all disabled:opacity-50"
            >
              <ImageIcon className="w-4 h-4" /> Export GIF
            </button>
            <button 
              onClick={exportVideo} 
              disabled={isExporting || !scriptsLoaded}
              className="flex items-center gap-2 bg-blue-600/90 backdrop-blur hover:bg-blue-500 text-white px-4 py-2 rounded-lg text-sm font-medium transition-all shadow-lg disabled:opacity-50"
            >
              <Video className="w-4 h-4" /> Export MP4
            </button>
          </div>
        </div>

        {/* Export Progress Overlay */}
        {isExporting && (
          <div className="absolute inset-0 bg-black/80 backdrop-blur-sm z-50 flex items-center justify-center flex-col">
            <Loader2 className="w-12 h-12 text-blue-500 animate-spin mb-4" />
            <div className="text-lg font-bold mb-2">Rendering Animation...</div>
            <div className="text-sm text-neutral-400 mb-4">{aspectRatio.replace(':', 'x')} @ {resolution}p</div>
            <div className="w-64 bg-neutral-800 rounded-full h-2 mb-2 overflow-hidden">
              <div className="bg-blue-500 h-full transition-all duration-200" style={{ width: `${exportProgress}%` }} />
            </div>
            <div className="text-neutral-400 text-sm">{Math.round(exportProgress)}%</div>
          </div>
        )}

        {/* Scaled WYSIWYG Rendering Canvas */}
        <div ref={previewWrapperRef} className="flex-1 overflow-hidden flex items-center justify-center relative">
          
          <div className="absolute inset-0 pointer-events-none flex items-center justify-center opacity-30">
            <div style={{ width: getDimensions(aspectRatio, resolution).w * previewScale, height: getDimensions(aspectRatio, resolution).h * previewScale }} className="border border-dashed border-neutral-500 rounded-sm" />
          </div>

          <div 
            ref={containerRef}
            style={{ 
              width: getDimensions(aspectRatio, resolution).w,
              height: getDimensions(aspectRatio, resolution).h,
              transform: `scale(${previewScale})`,
              transformOrigin: 'center'
            }}
            className="flex items-center overflow-hidden shadow-2xl relative"
          >
            {/* Standard Block Rendering */}
            <div 
              style={{
                display: pathMode === 'none' ? 'flex' : 'none', 
                width: '100%', 
                height: '100%',
                padding: `${canvasMargin}px`,
                boxSizing: 'border-box',
                alignItems: scrollType !== 'none' && !['cw','ccw'].includes(scrollType) ? 'center' : (verticalAlign === 'top' ? 'flex-start' : verticalAlign === 'bottom' ? 'flex-end' : 'center'),
                justifyContent: scrollType !== 'none' && !['cw','ccw'].includes(scrollType) ? 'center' : (textAlign === 'left' ? 'flex-start' : textAlign === 'right' ? 'flex-end' : 'center'),
              }}
            >
              <div ref={wrapperRef} style={{ position: 'relative' }} className="will-change-transform flex-shrink-0">
                {Array.from({ length: layerCount + 1 }).map((_, idx) => {
                  const i = layerCount - idx;
                  return (
                    <div 
                      key={`std-${i}`}
                      ref={el => layerRefs.current[i] = el}
                      style={{ 
                        position: i === 0 ? 'relative' : 'absolute',
                        top: 0, left: 0, right: 0, bottom: 0,
                        fontFamily: fontFamily, 
                        textAlign: textAlign,
                        whiteSpace: singleLine ? 'nowrap' : 'pre-wrap',
                        display: 'flex',
                        alignItems: 'center',
                        justifyContent: textAlign === 'left' ? 'flex-start' : textAlign === 'right' ? 'flex-end' : 'center',
                      }}
                      className="will-change-transform"
                    >
                      {text}
                    </div>
                  )
                })}
              </div>
            </div>

            {/* SVG Circle Path Rendering */}
            <div style={{ display: pathMode === 'circle' ? 'block' : 'none', position: 'absolute', inset: 0 }}>
              <svg ref={circleSvgRef} width="100%" height="100%" style={{ overflow: 'visible' }}>
                <defs>
                  <path ref={circlePathRef} id="live-circle-path" />
                </defs>
                <g ref={circleWrapperRef}>
                  {Array.from({ length: layerCount + 1 }).map((_, idx) => {
                    const i = layerCount - idx;
                    return (
                      <text 
                        key={`cir-${i}`} 
                        ref={el => circleLayerRefs.current[i] = el}
                        style={{ fontFamily: fontFamily, whiteSpace: singleLine ? 'nowrap' : 'pre-wrap' }}
                      >
                        <textPath ref={el => textPathRefs.current[i] = el} href="#live-circle-path" startOffset="0%">
                          {text.replace(/\n/g, ' ')}
                        </textPath>
                      </text>
                    );
                  })}
                </g>
              </svg>
            </div>

          </div>
          
        </div>
      </div>
    </div>
  );
}