// shared.jsx — common hooks, icons, and atoms
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// Lucide icon wrapper — uses lucide UMD with createIcons after mount
function Icon({ name, size = 18, className = "", style = {}, strokeWidth = 1.75 }) {
  const ref = useRef(null);
  useEffect(() => {
    if (ref.current && window.lucide) {
      ref.current.innerHTML = "";
      const el = document.createElement('i');
      el.setAttribute('data-lucide', name);
      ref.current.appendChild(el);
      window.lucide.createIcons({ attrs: { width: size, height: size, 'stroke-width': strokeWidth } });
    }
  }, [name, size, strokeWidth]);
  return <span ref={ref} className={"inline-flex items-center justify-center " + className} style={{ width: size, height: size, ...style }} />;
}

// Reveal on scroll
function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll('.reveal');
    const obs = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          e.target.classList.add('in');
          obs.unobserve(e.target);
        }
      });
    }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
    els.forEach(el => obs.observe(el));
    return () => obs.disconnect();
  });
}

// Counter
function Counter({ to, duration = 1600, prefix = "", suffix = "", className = "", decimals = 0 }) {
  const [val, setVal] = useState(0);
  const ref = useRef(null);
  const started = useRef(false);
  useEffect(() => {
    if (!ref.current) return;
    const obs = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting && !started.current) {
          started.current = true;
          const start = performance.now();
          const tick = (now) => {
            const t = Math.min(1, (now - start) / duration);
            const eased = 1 - Math.pow(1 - t, 3);
            setVal(to * eased);
            if (t < 1) requestAnimationFrame(tick);
            else setVal(to);
          };
          requestAnimationFrame(tick);
        }
      });
    }, { threshold: 0.4 });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, [to, duration]);
  return <span ref={ref} className={className}>{prefix}{val.toLocaleString('es-AR', { maximumFractionDigits: decimals })}{suffix}</span>;
}

// Section wrapper
function Section({ id, children, className = "", style = {} }) {
  return (
    <section id={id} className={"relative w-full " + className} style={style}>
      {children}
    </section>
  );
}

// Container
function Container({ children, className = "" }) {
  return <div className={"max-w-[1280px] mx-auto px-5 md:px-8 " + className}>{children}</div>;
}

// Section header
function SectionHeader({ eyebrow, title, subtitle, align = "center" }) {
  const alignCls = align === "center" ? "text-center mx-auto" : "text-left";
  return (
    <div className={"reveal max-w-3xl " + alignCls}>
      {eyebrow && (
        <div className={"inline-flex items-center gap-2 px-3 py-1.5 rounded-full font-mono text-[11px] tracking-[0.18em] uppercase mb-5 " + (align === 'center' ? '' : '')} style={{ background: 'rgba(0,212,255,0.08)', border: '1px solid rgba(0,212,255,0.25)', color: '#7fe5ff' }}>
          <span className="w-1.5 h-1.5 rounded-full" style={{ background: '#00d4ff', boxShadow: '0 0 8px #00d4ff' }}></span>
          {eyebrow}
        </div>
      )}
      <h2 className="font-display text-[34px] sm:text-[44px] md:text-[56px] leading-[1.05] font-bold tracking-tight">
        {title}
      </h2>
      {subtitle && (
        <p className="mt-5 text-[15.5px] md:text-[17px] leading-relaxed" style={{ color: 'var(--text-dim)' }}>
          {subtitle}
        </p>
      )}
    </div>
  );
}

// Live market badge
function LiveBadge() {
  return (
    <div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full glass font-mono text-[11px] tracking-[0.16em] uppercase" style={{ borderColor: 'rgba(239,68,68,0.35)' }}>
      <span className="relative w-2 h-2 rounded-full anim-pulse-red" style={{ background: '#ef4444' }}></span>
      <span style={{ color: '#ffb3b3' }}>Mercado en vivo</span>
    </div>
  );
}

// Candlestick chart SVG (decorative, animated)
function CandlesArt({ className = "" }) {
  // ====== ANIMATED LIVE CANDLES (rAF-based, no CSS dependency) ======
  const VISIBLE = 30;
  const BUFFER = 2;
  const TOTAL = VISIBLE + BUFFER;
  const w = 720;
  const h = 280;
  const cw = w / VISIBLE;       // 24
  const TICK_MS = 1500;         // ms per candle slide

  // Initial seed
  const buildInitial = () => {
    const arr = [];
    let p = 50;
    let id = 0;
    const spikes = new Set([10, 20]);
    const drops = new Set([14, 26]);
    for (let i = 0; i < TOTAL; i++) {
      const o = p;
      let c;
      if (spikes.has(i)) c = p + 18 + Math.random() * 4;
      else if (drops.has(i)) c = p - 14 - Math.random() * 3;
      else c = p + (Math.random() - 0.5) * 5;
      const hi = Math.max(o, c) + Math.random() * 2 + 0.5;
      const lo = Math.min(o, c) - Math.random() * 2 - 0.5;
      arr.push({ o, c, h: hi, l: lo, id: id++ });
      p = c;
    }
    return arr;
  };

  const generateNext = (prevPrice, id) => {
    const r = Math.random();
    const o = prevPrice;
    let c;
    if (r < 0.05)      c = prevPrice + 16 + Math.random() * 5;
    else if (r < 0.09) c = prevPrice - 13 - Math.random() * 4;
    else               c = prevPrice + (Math.random() - 0.5) * 5;
    if (prevPrice > 90) c -= 8;
    if (prevPrice < 10) c += 8;
    const hi = Math.max(o, c) + Math.random() * 2 + 0.5;
    const lo = Math.min(o, c) - Math.random() * 2 - 0.5;
    return { o, c, h: hi, l: lo, id };
  };

  const [data, setData] = useState(buildInitial);
  const groupRef = useRef(null);
  const idRef = useRef(TOTAL);
  const startRef = useRef(null);
  const rafRef = useRef(null);

  // Smooth rAF-based slide. Sets transform directly on the SVG <g> via setAttribute.
  // No CSS keyframes needed → works reliably across browsers and SPA re-renders.
  useEffect(() => {
    let mounted = true;

    const step = (timestamp) => {
      if (!mounted) return;
      if (startRef.current === null) startRef.current = timestamp;
      const elapsed = timestamp - startRef.current;
      const progress = Math.min(elapsed / TICK_MS, 1);
      const offset = -cw * progress;

      if (groupRef.current) {
        groupRef.current.setAttribute('transform', 'translate(' + offset + ', 0)');
      }

      if (progress >= 1) {
        // Shift data: drop leftmost, append new candle on the right
        setData(prev => {
          const last = prev[prev.length - 1];
          return [...prev.slice(1), generateNext(last.c, idRef.current++)];
        });
        startRef.current = null;
      }

      rafRef.current = requestAnimationFrame(step);
    };

    rafRef.current = requestAnimationFrame(step);
    return () => {
      mounted = false;
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
    };
  }, [cw]);

  // Live formation pulse for the in-buffer candle (CSS-independent)
  const [pulse, setPulse] = useState(0);
  useEffect(() => {
    let raf;
    const tick = (t) => {
      setPulse((Math.sin(t / 350) + 1) / 2); // 0..1
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  // Compute scale on each render
  const min = Math.min(...data.map(d => d.l)) - 4;
  const max = Math.max(...data.map(d => d.h)) + 4;
  const scaleY = (v) => h - ((v - min) / (max - min)) * h;
  const cxAt = (i) => (i - 1) * cw + cw / 2;

  return (
    <svg viewBox={'0 0 ' + w + ' ' + h} className={className} preserveAspectRatio="none">
      <defs>
        <linearGradient id="cgradUp" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor="#10b981" />
          <stop offset="100%" stopColor="#059669" />
        </linearGradient>
        <linearGradient id="cgradDown" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor="#ef4444" />
          <stop offset="100%" stopColor="#b91c1c" />
        </linearGradient>
        <linearGradient id="lineGrad" x1="0" x2="1" y1="0" y2="0">
          <stop offset="0%" stopColor="#0070ff" stopOpacity="0" />
          <stop offset="50%" stopColor="#00d4ff" stopOpacity="0.7" />
          <stop offset="100%" stopColor="#0070ff" stopOpacity="0" />
        </linearGradient>
        <clipPath id="candleClip">
          <rect x="0" y="0" width={w} height={h} />
        </clipPath>
      </defs>
      {/* grid — static, outside the animated group */}
      {[0.25, 0.5, 0.75].map(p => (
        <line key={p} x1="0" x2={w} y1={h * p} y2={h * p} stroke="rgba(255,255,255,0.04)" strokeDasharray="3 6" />
      ))}
      {/* Animated group — transform updated each frame via rAF */}
      <g clipPath="url(#candleClip)">
        <g ref={groupRef}>
          {/* connecting line */}
          <path
            d={data.map((d, i) => (i === 0 ? 'M' : 'L') + ' ' + cxAt(i) + ' ' + scaleY((d.o + d.c) / 2)).join(' ')}
            stroke="url(#lineGrad)"
            strokeWidth="1.2"
            fill="none"
          />
          {data.map((d, i) => {
            const up = d.c >= d.o;
            const cx = cxAt(i);
            const bodyTop = scaleY(Math.max(d.o, d.c));
            const bodyH = Math.abs(scaleY(d.o) - scaleY(d.c)) || 1;
            const isLive = i === TOTAL - 2;
            const liveOpacity = isLive ? (0.7 + 0.3 * pulse) : 0.95;
            return (
              <g key={d.id}>
                <line x1={cx} x2={cx} y1={scaleY(d.h)} y2={scaleY(d.l)} stroke={up ? '#10b981' : '#ef4444'} strokeWidth="1" opacity="0.6" />
                <rect
                  x={cx - cw * 0.32}
                  y={bodyTop}
                  width={cw * 0.64}
                  height={bodyH}
                  fill={up ? 'url(#cgradUp)' : 'url(#cgradDown)'}
                  opacity={liveOpacity}
                  rx="0.5"
                />
              </g>
            );
          })}
        </g>
      </g>
    </svg>
  );
}

// Mini sparkline
function Sparkline({ points = 24, trend = "up", color = "#10b981", className = "", height = 40 }) {
  const data = useMemo(() => {
    const arr = [];
    let v = 50;
    for (let i = 0; i < points; i++) {
      const drift = trend === "up" ? 1.2 : trend === "down" ? -1.2 : 0;
      v += drift + (Math.random() - 0.5) * 6;
      arr.push(v);
    }
    return arr;
  }, [points, trend]);
  const min = Math.min(...data) - 2;
  const max = Math.max(...data) + 2;
  const w = 120;
  const sy = (v) => height - ((v - min) / (max - min)) * height;
  const path = data.map((v, i) => `${i === 0 ? 'M' : 'L'} ${(i / (data.length - 1)) * w} ${sy(v)}`).join(' ');
  const area = path + ` L ${w} ${height} L 0 ${height} Z`;
  return (
    <svg viewBox={`0 0 ${w} ${height}`} className={className} preserveAspectRatio="none" style={{ width: '100%', height }}>
      <defs>
        <linearGradient id={`spk-${color.replace('#','')}`} x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.35" />
          <stop offset="100%" stopColor={color} stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={area} fill={`url(#spk-${color.replace('#','')})`} />
      <path d={path} fill="none" stroke={color} strokeWidth="1.6" strokeLinecap="round" />
    </svg>
  );
}

// Animated particles canvas
function Particles() {
  const ref = useRef(null);
  useEffect(() => {
    const c = ref.current;
    if (!c) return;
    const ctx = c.getContext('2d');
    let raf;
    const dpi = Math.min(window.devicePixelRatio || 1, 2);
    const resize = () => {
      c.width = c.offsetWidth * dpi;
      c.height = c.offsetHeight * dpi;
    };
    resize();
    window.addEventListener('resize', resize);
    const N = 70;
    const dots = Array.from({ length: N }, () => ({
      x: Math.random() * c.width,
      y: Math.random() * c.height,
      vx: (Math.random() - 0.5) * 0.18 * dpi,
      vy: (Math.random() - 0.5) * 0.18 * dpi,
      r: (Math.random() * 1.2 + 0.4) * dpi,
      hue: Math.random() > 0.5 ? 200 : 195,
      a: Math.random() * 0.5 + 0.2,
    }));
    const tick = () => {
      ctx.clearRect(0, 0, c.width, c.height);
      // connections
      for (let i = 0; i < N; i++) {
        for (let j = i + 1; j < N; j++) {
          const dx = dots[i].x - dots[j].x;
          const dy = dots[i].y - dots[j].y;
          const d = Math.sqrt(dx * dx + dy * dy);
          if (d < 120 * dpi) {
            ctx.strokeStyle = `rgba(0,212,255,${(1 - d / (120 * dpi)) * 0.10})`;
            ctx.lineWidth = 0.6 * dpi;
            ctx.beginPath();
            ctx.moveTo(dots[i].x, dots[i].y);
            ctx.lineTo(dots[j].x, dots[j].y);
            ctx.stroke();
          }
        }
      }
      dots.forEach(d => {
        d.x += d.vx; d.y += d.vy;
        if (d.x < 0 || d.x > c.width) d.vx *= -1;
        if (d.y < 0 || d.y > c.height) d.vy *= -1;
        ctx.fillStyle = `hsla(${d.hue}, 100%, 70%, ${d.a})`;
        ctx.shadowColor = `hsla(${d.hue}, 100%, 70%, 0.8)`;
        ctx.shadowBlur = 6 * dpi;
        ctx.beginPath();
        ctx.arc(d.x, d.y, d.r, 0, Math.PI * 2);
        ctx.fill();
        ctx.shadowBlur = 0;
      });
      raf = requestAnimationFrame(tick);
    };
    tick();
    return () => { cancelAnimationFrame(raf); window.removeEventListener('resize', resize); };
  }, []);
  return <canvas ref={ref} className="absolute inset-0 w-full h-full" style={{ pointerEvents: 'none' }} />;
}

// Ticker of market data
function MarketTicker() {
  const items = [
    { sym: 'BOOM 1000', price: '8,432.51', chg: '+1.24%', up: true },
    { sym: 'CRASH 500', price: '6,128.04', chg: '-0.86%', up: false },
    { sym: 'VOL 75', price: '402,118', chg: '+2.41%', up: true },
    { sym: 'VOL 100', price: '1,284.92', chg: '+0.55%', up: true },
    { sym: 'JUMP 25', price: '7,402.10', chg: '-0.32%', up: false },
    { sym: 'STEP IDX', price: '9,128.30', chg: '+0.74%', up: true },
    { sym: 'BOOM 500', price: '12,891.66', chg: '+1.92%', up: true },
    { sym: 'VOL 25', price: '278,402', chg: '-1.04%', up: false },
    { sym: 'VOL 10', price: '8,234.05', chg: '+0.41%', up: true },
  ];
  const row = [...items, ...items];
  return (
    <div className="ticker-wrap py-3 border-y" style={{ borderColor: 'var(--border)', background: 'rgba(13,13,26,0.6)' }}>
      <div className="ticker font-mono text-[12.5px]">
        {row.map((it, i) => (
          <div key={i} className="inline-flex items-center gap-3">
            <span style={{ color: 'var(--text-dim)' }}>{it.sym}</span>
            <span className="text-white">{it.price}</span>
            <span style={{ color: it.up ? '#10b981' : '#ef4444' }}>{it.chg}</span>
            <span style={{ color: 'var(--border-soft)' }}>|</span>
          </div>
        ))}
      </div>
    </div>
  );
}

// Broker / partner strip
function BrokerStrip({ compact = false }) {
  const brokers = [
    { src: 'img/deriv.svg', name: 'Deriv', h: compact ? 22 : 28 },
    { src: 'img/weltrade.svg', name: 'Weltrade', h: compact ? 22 : 28 },
    { src: 'img/bridgemarkets.svg', name: 'Bridge Markets', h: compact ? 28 : 34 },
  ];
  return (
    <Section className={compact ? "py-8" : "py-12 md:py-16"}>
      <Container>
        <div className="flex flex-col md:flex-row items-center gap-6 md:gap-12">
          <div className="shrink-0 text-center md:text-left">
            <div className="font-mono text-[10.5px] tracking-[0.22em] uppercase" style={{ color: 'var(--text-mute)' }}>
              Brokers que nos respaldan
            </div>
            <div className="font-display text-[14px] mt-1.5" style={{ color: 'var(--text-dim)' }}>
              Trabajamos con plataformas reguladas
            </div>
          </div>
          <div className="hidden md:block flex-1 h-px" style={{ background: 'linear-gradient(90deg, var(--border), transparent)' }}></div>
          <div className="flex flex-wrap items-center justify-center md:justify-end gap-x-10 gap-y-6">
            {brokers.map(b => (
              <img
                key={b.name}
                src={b.src}
                alt={b.name}
                title={b.name}
                className="logo-fade"
                style={{ height: b.h, width: 'auto' }}
              />
            ))}
          </div>
        </div>
      </Container>
    </Section>
  );
}

// ============================================================
// Premium Countdown — animated countdown to the next Premium opening
// ============================================================
function PremiumCountdown({
  target = '2026-06-16T00:00:00-03:00',
  supportUrl = 'https://t.me/barbieshark',
}) {
  const targetMs = useMemo(() => new Date(target).getTime(), [target]);
  const [now, setNow] = useState(() => Date.now());

  useEffect(() => {
    const id = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(id);
  }, []);

  const diff = Math.max(0, targetMs - now);
  const d = Math.floor(diff / 86400000);
  const h = Math.floor((diff % 86400000) / 3600000);
  const m = Math.floor((diff % 3600000) / 60000);
  const s = Math.floor((diff % 60000) / 1000);

  const cells = [
    { v: d, l: 'Días' },
    { v: h, l: 'Horas' },
    { v: m, l: 'Min' },
    { v: s, l: 'Seg' },
  ];

  const dateLabel = useMemo(() => {
    const dt = new Date(targetMs);
    const months = ['ENE','FEB','MAR','ABR','MAY','JUN','JUL','AGO','SEP','OCT','NOV','DIC'];
    return `${String(dt.getDate()).padStart(2,'0')} · ${months[dt.getMonth()]} · ${dt.getFullYear()}`;
  }, [targetMs]);

  return (
    <div className="reveal premium-countdown relative rounded-3xl overflow-hidden" style={{
      background: 'linear-gradient(135deg, rgba(212,160,23,0.10) 0%, rgba(20,20,40,0.65) 45%, rgba(13,13,26,0.85) 100%)',
      border: '1px solid rgba(212,160,23,0.30)',
      boxShadow: '0 0 0 1px rgba(212,160,23,0.10), 0 30px 80px -30px rgba(212,160,23,0.45), inset 0 1px 0 rgba(255,255,255,0.04)',
    }}>
      {/* tech grid overlay */}
      <div className="absolute inset-0 tech-grid-fine opacity-50 pointer-events-none"></div>
      {/* radial glow */}
      <div className="absolute inset-0 pointer-events-none" style={{
        background: 'radial-gradient(ellipse 800px 320px at 90% 0%, rgba(212,160,23,0.18), transparent 60%), radial-gradient(ellipse 600px 280px at 0% 100%, rgba(0,212,255,0.10), transparent 60%)',
      }}></div>
      {/* sweep shine */}
      <div className="absolute inset-y-0 -left-1/3 w-1/3 pointer-events-none opacity-50" style={{
        background: 'linear-gradient(110deg, transparent 30%, rgba(247,213,107,0.18) 50%, transparent 70%)',
        animation: 'sweep 6s ease-in-out infinite',
      }}></div>

      <div className="relative p-6 sm:p-8 md:p-10 grid lg:grid-cols-[1.1fr_1.4fr] gap-8 items-center">
        {/* LEFT — status + date */}
        <div>
          <div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full font-mono text-[10.5px] tracking-[0.2em] uppercase" style={{
            background: 'rgba(16,185,129,0.10)',
            border: '1px solid rgba(16,185,129,0.35)',
            color: '#5ee9b8',
          }}>
            <span className="relative w-1.5 h-1.5 rounded-full" style={{ background: '#10b981', boxShadow: '0 0 10px #10b981' }}>
              <span className="absolute inset-0 rounded-full anim-pulse-red" style={{ background: '#10b981', animationName: 'pulseGreen' }}></span>
            </span>
            Premium activo · cupo cerrado
          </div>

          <h3 className="font-display font-bold text-[28px] sm:text-[34px] md:text-[40px] leading-[1.02] tracking-tight mt-5">
            Próxima apertura del <span className="grad-text-amber">Premium</span>
          </h3>
          <p className="mt-3 text-[14px] md:text-[15px] leading-relaxed max-w-md" style={{ color: 'var(--text-dim)' }}>
            Hay un Premium activo en este momento. La próxima ventana para sumarse abre el <span className="text-white font-semibold">16 de junio de 2026</span>. Dejá tu lugar antes y entrá en cuanto se libere el cupo.
          </p>

          <div className="mt-5 inline-flex items-center gap-3 px-3.5 py-2 rounded-lg" style={{
            background: 'rgba(212,160,23,0.08)',
            border: '1px solid rgba(212,160,23,0.30)',
          }}>
            <Icon name="calendar-clock" size={16} style={{ color: '#f7d56b' }} />
            <span className="font-mono text-[12px] tracking-[0.18em] uppercase" style={{ color: '#f7d56b' }}>
              {dateLabel}
            </span>
          </div>

          <div className="mt-6 flex flex-wrap gap-3">
            <a href={supportUrl} target="_blank" rel="noopener noreferrer" className="btn btn-outline-amber text-[13.5px] py-2.5 px-4">
              <Icon name="bell" size={14} /> Notificarme cuando abra
            </a>
          </div>
        </div>

        {/* RIGHT — countdown grid */}
        <div>
          <div className="font-mono text-[10.5px] tracking-[0.22em] uppercase mb-3 flex items-center gap-2" style={{ color: 'var(--text-mute)' }}>
            <span className="w-1.5 h-1.5 rounded-full anim-blink" style={{ background: '#f7d56b', boxShadow: '0 0 8px #f7d56b' }}></span>
            Tiempo restante para el próximo acceso
          </div>
          <div className="grid grid-cols-4 gap-2 sm:gap-3">
            {cells.map((c, i) => (
              <CountCell key={i} value={c.v} label={c.l} />
            ))}
          </div>
          <div className="mt-3 font-mono text-[10.5px] tracking-[0.18em] uppercase text-center" style={{ color: 'var(--text-mute)' }}>
            Hora local · cuenta sincronizada al segundo
          </div>
        </div>
      </div>

      {/* bottom hairline */}
      <div className="absolute left-0 right-0 bottom-0 h-px" style={{ background: 'linear-gradient(90deg, transparent, rgba(212,160,23,0.5), transparent)' }}></div>
    </div>
  );
}

function CountCell({ value, label }) {
  const v = String(Math.max(0, value)).padStart(2, '0');
  return (
    <div className="relative rounded-xl overflow-hidden" style={{
      background: 'linear-gradient(180deg, rgba(30,28,18,0.85), rgba(13,13,26,0.85))',
      border: '1px solid rgba(212,160,23,0.25)',
      boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.04), inset 0 -10px 30px rgba(212,160,23,0.06)',
    }}>
      {/* glare line in the middle */}
      <div className="absolute left-0 right-0 top-1/2 h-px pointer-events-none" style={{
        background: 'linear-gradient(90deg, transparent, rgba(0,0,0,0.6) 30%, rgba(0,0,0,0.7) 70%, transparent)',
      }}></div>
      <div className="relative px-2 pt-3 pb-2.5 sm:pt-4 sm:pb-3 text-center">
        <div className="flex justify-center gap-0.5 sm:gap-1 font-mono font-bold leading-none tabular-nums text-[34px] sm:text-[44px] md:text-[58px]" style={{
          color: '#fff',
          textShadow: '0 0 18px rgba(247,213,107,0.35), 0 0 1px rgba(247,213,107,0.6)',
        }}>
          <FlipDigit ch={v[0]} />
          <FlipDigit ch={v[1]} />
        </div>
        <div className="font-mono text-[9.5px] sm:text-[10px] tracking-[0.22em] uppercase mt-1.5 sm:mt-2" style={{ color: 'var(--text-dim)' }}>
          {label}
        </div>
      </div>
    </div>
  );
}

function FlipDigit({ ch }) {
  const [prev, setPrev] = useState(ch);
  const [flipping, setFlipping] = useState(false);
  useEffect(() => {
    if (ch !== prev) {
      setFlipping(true);
      const t = setTimeout(() => {
        setPrev(ch);
        setFlipping(false);
      }, 380);
      return () => clearTimeout(t);
    }
  }, [ch, prev]);
  return (
    <span className="relative inline-block" style={{ width: '0.62em' }}>
      <span className={"flip-digit-cur " + (flipping ? 'flipping' : '')}>{prev}</span>
      {flipping && <span className="flip-digit-next">{ch}</span>}
    </span>
  );
}

Object.assign(window, {
  Icon, useReveal, Counter, Section, Container, SectionHeader,
  LiveBadge, CandlesArt, Sparkline, Particles, MarketTicker, BrokerStrip,
  PremiumCountdown,
});
