// shared.jsx — common atoms used across all ruuapi landing variants
// Components are pushed to window at the bottom so the variant scripts
// (separate Babel scopes) can pick them up.

const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ───────────────────────────────────────────────────────────── BrandMark
function useMobile(breakpoint = 720) {
  const [m, setM] = useState(() => typeof window !== 'undefined' && window.innerWidth <= breakpoint);
  useEffect(() => {
    function onResize() { setM(window.innerWidth <= breakpoint); }
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, [breakpoint]);
  return m;
}

function RuuMark({ size = 32, mono = false }) {
  // 'r' inside a notched square — the only piece of branding we hand-draw.
  const fg = mono ? 'var(--ink)' : 'var(--ink)';
  return (
    <svg width={size} height={size} viewBox="0 0 32 32" aria-label="ruuapi">
      <path d="M0 4 L0 32 L28 32 L32 28 L32 0 L4 0 Z" fill={fg}/>
      <text x="16" y="22" textAnchor="middle" fontFamily="var(--serif)" fontSize="20" fill="var(--accent)" fontStyle="italic">r</text>
    </svg>
  );
}

function RuuWordmark({ size = 24, color }) {
  const c = color || 'currentColor';
  return (
    <span style={{ display:'inline-flex', alignItems:'baseline', gap: 4, color: c, fontFamily:'var(--serif)', fontSize: size, letterSpacing:'-0.02em', lineHeight: 1 }}>
      <span style={{ fontStyle:'italic' }}>r</span>
      <span>uuapi</span>
      <span style={{ width: 6, height: 6, borderRadius: '50%', background:'var(--accent)', display:'inline-block', alignSelf:'center', marginLeft: 2 }}></span>
    </span>
  );
}

// ───────────────────────────────────────────────────────────── Marquee / Ticker
function Ticker({ items, color = 'var(--ink)', bg = 'var(--accent)', tall = false, sep = '✦' }) {
  const list = [...items, ...items, ...items];
  return (
    <div style={{ overflow:'hidden', background: bg, color, borderTop:'1px solid var(--rule)', borderBottom:'1px solid var(--rule)', padding: tall ? '18px 0' : '10px 0' }}>
      <div className="marquee-track" style={{ display:'flex', whiteSpace:'nowrap', gap: 40, fontFamily:'var(--mono)', fontWeight:500, fontSize: tall ? 22 : 13, letterSpacing:'0.02em', textTransform: tall ? 'none' : 'uppercase' }}>
        {list.map((t, i) => (
          <span key={i} style={{ display:'inline-flex', alignItems:'center', gap: 40 }}>
            <span>{t}</span>
            <span style={{ opacity: .55 }}>{sep}</span>
          </span>
        ))}
      </div>
    </div>
  );
}

// ───────────────────────────────────────────────────────────── Nature backdrop
// Cycles a few landscape photos behind dark sections, very subtly. Cross-fades
// every ~7s, with a slow Ken-Burns zoom on the current image. Sits absolutely
// inside a positioned parent — wrap your actual content in z-index:1.
const NATURE_IMAGES = [
  // Misty mountain ridges
  'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?auto=format&fit=crop&w=1600&q=70',
  // Forest from above
  'https://images.unsplash.com/photo-1441974231531-c6227db76b6e?auto=format&fit=crop&w=1600&q=70',
  // Lake and mountains
  'https://images.unsplash.com/photo-1469474968028-56623f02e42e?auto=format&fit=crop&w=1600&q=70',
  // Cliffs / coast
  'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?auto=format&fit=crop&w=1600&q=70',
  // Aurora / stars
  'https://images.unsplash.com/photo-1483347756197-71ef80e95f73?auto=format&fit=crop&w=1600&q=70',
  // Misty pine forest
  'https://images.unsplash.com/photo-1418065460487-3e41a6c84dc5?auto=format&fit=crop&w=1600&q=70',
];

// Cosmos / space images — used on light sections with a multiply-style blend.
const SPACE_IMAGES = [
  // Nebula / colored gas
  'https://images.unsplash.com/photo-1462331940025-496dfbfc7564?auto=format&fit=crop&w=1600&q=70',
  // Earth from space
  'https://images.unsplash.com/photo-1451187580459-43490279c0fa?auto=format&fit=crop&w=1600&q=70',
  // Moon close-up
  'https://images.unsplash.com/photo-1532074205216-d0e1f4b87368?auto=format&fit=crop&w=1600&q=70',
  // Milky way over silhouette
  'https://images.unsplash.com/photo-1419242902214-272b3f66ee7a?auto=format&fit=crop&w=1600&q=70',
  // Galaxy
  'https://images.unsplash.com/photo-1446776877081-d282a0f896e2?auto=format&fit=crop&w=1600&q=70',
  // Star field
  'https://images.unsplash.com/photo-1444703686981-a3abbc4d4fe3?auto=format&fit=crop&w=1600&q=70',
];

function NatureBackdrop({ opacity = 0.22, interval = 7000, blend = 'screen', images = NATURE_IMAGES, filter = 'grayscale(35%) contrast(1.05) saturate(.9)' }) {
  const [idx, setIdx] = React.useState(0);
  const [enabled, setEnabled] = React.useState(true);

  React.useEffect(() => {
    // Disable cycling if the page is in 'minimal' animation mode.
    const root = document.querySelector('.ruu');
    if (root && root.classList.contains('anim-minimal')) { setEnabled(false); return; }
    const t = setInterval(() => setIdx(i => (i + 1) % images.length), interval);
    return () => clearInterval(t);
  }, [interval, images.length]);

  return (
    <div aria-hidden="true" style={{
      position:'absolute', inset: 0, overflow:'hidden', pointerEvents:'none',
      zIndex: 0, mixBlendMode: blend,
    }}>
      {images.map((src, i) => (
        <img key={src} src={src} alt="" loading="lazy"
             style={{
               position:'absolute', inset: 0, width:'100%', height:'100%',
               objectFit:'cover',
               opacity: i === idx ? opacity : 0,
               transition: 'opacity 1.8s ease-in-out, transform ' + (interval / 1000 + 2) + 's linear',
               transform: i === idx ? 'scale(1.08)' : 'scale(1.0)',
               filter,
             }}/>
      ))}
    </div>
  );
}

Object.assign(window, { NatureBackdrop, NATURE_IMAGES, SPACE_IMAGES });

// ───────────────────────────────────────────────────────────── Reveal-on-scroll
function Reveal({ children, delay = 0, as: As = 'div', style, ...rest }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } });
    }, { threshold: 0.12 });
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);
  return (
    <As ref={ref} className={'reveal ' + (seen ? 'in' : '') + (rest.className ? ' ' + rest.className : '')} style={{ transitionDelay: delay + 'ms', ...style }}>
      {children}
    </As>
  );
}

// ───────────────────────────────────────────────────────────── Animated counter
function Counter({ to, suffix = '', duration = 1200, format }) {
  const [n, setN] = useState(0);
  const ref = useRef(null);
  useEffect(() => {
    if (!ref.current) return;
    let raf, started = null;
    const io = new IntersectionObserver(([e]) => {
      if (!e.isIntersecting) return;
      const step = (t) => {
        if (started == null) started = t;
        const p = Math.min(1, (t - started) / duration);
        const eased = 1 - Math.pow(1 - p, 3);
        setN(Math.round(to * eased));
        if (p < 1) raf = requestAnimationFrame(step);
      };
      raf = requestAnimationFrame(step);
      io.disconnect();
    }, { threshold: 0.4 });
    io.observe(ref.current);
    return () => { io.disconnect(); cancelAnimationFrame(raf); };
  }, [to, duration]);
  const text = format ? format(n) : n.toLocaleString('tr-TR');
  return <span ref={ref} style={{ fontVariantNumeric:'tabular-nums' }}>{text}{suffix}</span>;
}

// ───────────────────────────────────────────────────────────── Typewriter
function Typewriter({ phrases, pause = 1400, typing = 55, deleting = 28, className, style }) {
  const [idx, setIdx] = useState(0);
  const [sub, setSub] = useState('');
  const [del, setDel] = useState(false);
  useEffect(() => {
    const cur = phrases[idx % phrases.length];
    if (!del && sub === cur) {
      const t = setTimeout(() => setDel(true), pause); return () => clearTimeout(t);
    }
    if (del && sub === '') {
      setDel(false); setIdx(i => (i + 1) % phrases.length); return;
    }
    const t = setTimeout(() => {
      setSub(s => del ? cur.slice(0, s.length - 1) : cur.slice(0, s.length + 1));
    }, del ? deleting : typing);
    return () => clearTimeout(t);
  }, [sub, del, idx, phrases]);
  return <span className={(className || '') + ' caret'} style={style}>{sub}</span>;
}

// ───────────────────────────────────────────────────────────── CTA button
function CTA({ children, variant = 'accent', icon = '→' }) {
  return (
    <button className={'btn btn-' + variant}>
      <span>{children}</span>
      {icon && <span className="arrow" aria-hidden="true">{icon}</span>}
    </button>
  );
}

// ───────────────────────────────────────────────────────────── Comparison rows
// Row-by-row check/cross — used by all variants but rendered with per-variant chrome.
// Keys are stable slugs; actual text rendered via t() at call sites.
const COMPARE_ROW_KEYS = [
  { a: 'compare.row.01.a', b: 'compare.row.01.b' },
  { a: 'compare.row.02.a', b: 'compare.row.02.b' },
  { a: 'compare.row.03.a', b: 'compare.row.03.b' },
  { a: 'compare.row.04.a', b: 'compare.row.04.b' },
  { a: 'compare.row.05.a', b: 'compare.row.05.b' },
  { a: 'compare.row.06.a', b: 'compare.row.06.b' },
  { a: 'compare.row.07.a', b: 'compare.row.07.b' },
];
// COMPARE_ROWS keeps the EN fallback for any code that reads .a/.b directly
// (e.g. legacy consumers). The live render path uses COMPARE_ROW_KEYS + t().
const COMPARE_ROWS = [
  { a: 'Keyword research → outline → ChatGPT → manual SEO check', b: 'Type the topic → one click → published with AEO + GEO + SEO' },
  { a: 'A 15–20 item basic checklist', b: '80 CORE-EEAT checkpoints, LLM-scored automatically' },
  { a: 'Copy-paste into WordPress', b: 'WordPress + Astro / Hugo / Jekyll (Git Publisher)' },
  { a: 'Rewrite for Twitter, rewrite for newsletter', b: 'Repurpose to X / Newsletter / LinkedIn in one click' },
  { a: 'You only show up on Google (if at all)', b: 'Cited on ChatGPT · Perplexity · Google AI · Claude' },
  { a: 'No way to know if you\'re being cited', b: 'Open-source Citation Tracker — live monitoring' },
  { a: 'One model, one prompt, average output', b: '6-agent pipeline — researcher, planner, writer, editor, SEO, brand voice' },
];

function CheckIcon({ size = 18, color = 'currentColor' }) {
  return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>);
}
function CrossIcon({ size = 18, color = 'currentColor' }) {
  return (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>);
}

// ───────────────────────────────────────────────────────────── Feature data
// Stores i18n key slugs. Components call t(f.tag) etc. to render localised text.
const FEATURES = [
  { n: '01', tag: 'features.01.tag', title: 'features.01.title', body: 'features.01.body', versus: 'features.01.versus' },
  { n: '02', tag: 'features.02.tag', title: 'features.02.title', body: 'features.02.body', versus: 'features.02.versus' },
  { n: '03', tag: 'features.03.tag', title: 'features.03.title', body: 'features.03.body', versus: 'features.03.versus' },
  { n: '04', tag: 'features.04.tag', title: 'features.04.title', body: 'features.04.body', versus: 'features.04.versus' },
  { n: '05', tag: 'features.05.tag', title: 'features.05.title', body: 'features.05.body', versus: 'features.05.versus' },
  { n: '06', tag: 'features.06.tag', title: 'features.06.title', body: 'features.06.body', versus: 'features.06.versus' },
];

// ───────────────────────────────────────────────────────────── Citation sparkline
// Loop: week strip → zoom into highlighted day → draw graph → hold → zoom out →
// advance highlight to next day → repeat. Each day shows a different curve.
const SPARK_WEEK = [
  { d: '08', wd: 'Sat', pts: [2, 3, 5, 4, 7, 9, 11, 14, 16, 19, 22, 26, 30, 34],    n: 91  },
  { d: '09', wd: 'Sun', pts: [3, 4, 6, 8, 10, 13, 17, 22, 28, 33, 39, 46, 52, 60],  n: 124 },
  { d: '10', wd: 'Mon', pts: [4, 6, 5, 9, 8, 12, 14, 18, 22, 21, 28, 34, 38, 45],   n: 142 },
  { d: '11', wd: 'Tue', pts: [3, 5, 8, 12, 14, 18, 22, 28, 32, 38, 44, 52, 58, 64], n: 178 },
  { d: '12', wd: 'Wed', pts: [6, 8, 10, 14, 18, 22, 26, 32, 38, 44, 52, 60, 68, 76],n: 214 },
  { d: '13', wd: 'Thu', pts: [8, 11, 14, 18, 22, 28, 36, 44, 50, 58, 66, 74, 82, 92], n: 268 },
  { d: '14', wd: 'Fri', pts: [12, 16, 22, 28, 34, 42, 52, 60, 70, 78, 88, 98, 108, 118], n: 312 },
];
const SPARK_PHASE_MS = { week: 700, zoomin: 700, drawing: 2400, hold: 900, zoomout: 700, advance: 500 };

function CitationSparkline({ color = 'var(--accent)' }) {
  const W = 240, H = 64;
  const [highlightIdx, setHighlightIdx] = React.useState(2); // current day in week strip
  const [phase, setPhase] = React.useState('week');
  const [enabled, setEnabled] = React.useState(true);

  React.useEffect(() => {
    const root = document.querySelector('.ruu');
    if (root && root.classList.contains('anim-minimal')) { setEnabled(false); }
  }, []);

  React.useEffect(() => {
    if (!enabled) return;
    const NEXT = { week: 'zoomin', zoomin: 'drawing', drawing: 'hold', hold: 'zoomout', zoomout: 'advance', advance: 'week' };
    const t = setTimeout(() => {
      if (phase === 'advance') {
        // Advance to next day in the week (wrap: 2 → 3 → 4 → 5 → 2)
        setHighlightIdx(i => (i >= 5 ? 2 : i + 1));
      }
      setPhase(NEXT[phase]);
    }, SPARK_PHASE_MS[phase]);
    return () => clearTimeout(t);
  }, [phase, enabled]);

  const cur = SPARK_WEEK[highlightIdx];
  const step = W / (cur.pts.length - 1);
  const max = Math.max(...cur.pts) * 1.05;
  const yOf = (p) => H - (p / max) * (H - 12) - 6;
  const path = cur.pts.map((p, i) => `${i ? 'L' : 'M'} ${(i * step).toFixed(1)} ${yOf(p).toFixed(1)}`).join(' ');
  const areaPath = path + ` L ${W} ${H} L 0 ${H} Z`;

  const showCalendar = phase === 'week' || phase === 'zoomout' || phase === 'advance';
  const showSpark = phase === 'zoomin' || phase === 'drawing' || phase === 'hold';
  const drawing = phase === 'drawing';
  const drawDone = phase === 'hold';
  const labelOn = drawing || drawDone;

  // Origin of the zoom: center of the highlighted cell in the week strip
  const cellCenterPct = ((highlightIdx + 0.5) * (100 / 7)).toFixed(2) + '%';
  const drawKey = 'd-' + highlightIdx + '-' + (drawing ? 'on' : 'off');

  return (
    <div style={{ position:'relative', width: W, height: H + 28, overflow:'visible' }}>
      {/* Day label — fades in when we're zoomed-in */}
      <div className="mono" style={{
        position:'absolute', top: -18, left: 0,
        fontSize: 10, color: 'rgba(245,243,236,.7)', letterSpacing:'0.08em',
        opacity: labelOn ? 1 : 0,
        transform: labelOn ? 'translateY(0)' : 'translateY(4px)',
        transition: 'opacity .35s, transform .35s',
      }}>
        {cur.wd} {cur.d} May · <span style={{ color }}>{cur.n} citations</span>
      </div>

      {/* Sparkline layer — scales in from the highlighted cell */}
      <div style={{
        position:'absolute', inset: 0,
        opacity: showSpark ? 1 : 0,
        transform: showSpark ? 'scale(1)' : 'scale(.4)',
        transformOrigin: `${cellCenterPct} 50%`,
        transition: 'opacity .45s ease, transform .65s cubic-bezier(.3,1.25,.4,1)',
        pointerEvents:'none',
      }}>
        <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} style={{ display:'block', overflow:'visible' }}>
          <defs>
            <linearGradient id="ruu-spark-area" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={color} stopOpacity=".42"/>
              <stop offset="100%" stopColor={color} stopOpacity="0"/>
            </linearGradient>
          </defs>
          {/* Faint grid line */}
          <line x1="0" y1={H - 1} x2={W} y2={H - 1} stroke="rgba(245,243,236,.1)" strokeWidth="1"/>
          <path d={areaPath} fill="url(#ruu-spark-area)"
                opacity={drawDone ? 1 : 0}
                style={{ transition: 'opacity .55s ease' }}/>
          <path key={drawKey} d={path} fill="none" stroke={color}
                strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"
                pathLength="1"
                style={{
                  strokeDasharray: 1,
                  strokeDashoffset: drawing ? 1 : (drawDone ? 0 : 1),
                  animation: drawing ? 'ruu-spark-draw1 2.3s cubic-bezier(.4,.8,.3,1) forwards' : 'none',
                  opacity: showSpark ? 1 : 0,
                }}/>
          {/* First dot — visible from start of draw */}
          <circle cx="0" cy={yOf(cur.pts[0])} r="3" fill={color}
                  opacity={drawing || drawDone ? 1 : 0}
                  style={{ transition: 'opacity .25s' }}/>
          {/* Time cursor — sweeps right as the line draws */}
          {drawing && (
            <g key={'cursor-' + highlightIdx} style={{
              animation: 'ruu-cursor-sweep 2.3s cubic-bezier(.4,.8,.3,1) forwards',
            }}>
              <line x1="0" y1="0" x2="0" y2={H} stroke={color} strokeWidth="1" opacity=".35" strokeDasharray="2 2"/>
            </g>
          )}
          {/* End dot — appears after draw + pulses */}
          <circle cx={W} cy={yOf(cur.pts[cur.pts.length-1])} r="3.5" fill={color}
                  opacity={drawDone ? 1 : 0}
                  style={{ transition: 'opacity .3s ease .1s' }}>
            <animate attributeName="r" values="3.5;5.5;3.5" dur="1.6s" repeatCount="indefinite"/>
          </circle>
        </svg>
      </div>

      {/* Calendar week strip */}
      <div style={{
        position:'absolute', inset: 0,
        display:'grid', gridTemplateColumns:'repeat(7, 1fr)', gap: 4,
        alignItems:'stretch',
        opacity: showCalendar ? 1 : 0,
        transform: showCalendar ? 'scale(1)' : 'scale(1.18)',
        transformOrigin: `${cellCenterPct} 50%`,
        transition: 'opacity .45s ease, transform .65s cubic-bezier(.3,1.25,.4,1)',
        pointerEvents:'none',
      }}>
        {SPARK_WEEK.map((d, i) => {
          const active = i === highlightIdx;
          const past = i < highlightIdx;
          const advancing = phase === 'advance' && active;
          return (
            <div key={i} style={{
              position:'relative',
              border: `1px solid rgba(245,243,236,${active ? 0 : 0.18})`,
              borderRadius: 6,
              background: active ? color : 'transparent',
              padding: '6px 2px 4px',
              display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'space-between',
              transition: 'background .35s ease, border-color .35s ease, transform .4s cubic-bezier(.3,1.3,.4,1)',
              transform: advancing ? 'scale(1.12)' : 'scale(1)',
              boxShadow: active ? `0 0 0 2px ${color}` : 'none',
            }}>
              <span className="mono" style={{
                fontSize: 9, letterSpacing:'0.08em',
                color: active ? 'var(--ink)' : 'rgba(245,243,236,.55)',
                transition: 'color .3s',
              }}>{d.wd}</span>
              <span style={{
                fontFamily:'var(--serif)', fontSize: 18, lineHeight: 1,
                color: active ? 'var(--ink)' : (past ? 'rgba(245,243,236,.88)' : 'rgba(245,243,236,.3)'),
                transition: 'color .3s',
              }}>{d.d}</span>
              {!active && past && (
                <svg width="100%" height="8" viewBox="0 0 20 8" style={{ display:'block', marginTop: 2 }}>
                  <path d={`M 0 ${(8 - (d.n / 320) * 6).toFixed(1)} L 5 ${(8 - (d.n / 320) * 6.4).toFixed(1)} L 10 ${(8 - (d.n / 320) * 5.6).toFixed(1)} L 15 ${(8 - (d.n / 320) * 6.8).toFixed(1)} L 20 ${(8 - (d.n / 320) * 7).toFixed(1)}`}
                        fill="none" stroke="rgba(245,243,236,.5)" strokeWidth="1" strokeLinecap="round"/>
                </svg>
              )}
              {active && <span style={{ width: 5, height: 5, borderRadius:'50%', background:'var(--ink)' }}></span>}
            </div>
          );
        })}
      </div>

      {/* Phase pill */}
      <div className="mono" style={{
        position:'absolute', bottom: -20, right: 0,
        fontSize: 9, letterSpacing:'0.1em', textTransform:'uppercase',
        color: 'rgba(245,243,236,.5)',
      }}>
        {phase === 'week' && '7 days'}
        {phase === 'zoomin' && '→ zoom in'}
        {phase === 'drawing' && '● drawing'}
        {phase === 'hold' && '✓ ' + cur.n + ' citations'}
        {phase === 'zoomout' && '→ zoom out'}
        {phase === 'advance' && '→ next day'}
      </div>
    </div>
  );
}

// ───────────────────────────────────────────────────────────── Article mock
function ArticleMock({ compact = false }) {
  const { t } = useT();
  return (
    <div style={{ background:'var(--paper)', border:'1px solid var(--rule)', borderRadius: 12, padding: compact ? 16 : 22, fontFamily:'var(--sans)' }}>
      <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom: 12 }}>
        <span className="mono" style={{ fontSize: 10, letterSpacing:'0.1em', textTransform:'uppercase', color:'var(--ink-3)' }}>{t('article-mock.label')}</span>
        <span style={{ display:'inline-flex', alignItems:'center', gap: 6, fontSize: 10, color:'var(--ink-2)', fontFamily:'var(--mono)' }}>
          <span style={{ width:6, height:6, borderRadius:'50%', background:'#22c55e', boxShadow:'0 0 0 3px rgba(34,197,94,.18)' }}></span>
          {t('article-mock.score')}
        </span>
      </div>
      <div style={{ fontFamily:'var(--serif)', fontSize: compact ? 22 : 28, lineHeight: 1.05, letterSpacing:'-0.01em', marginBottom: 8 }}>
        {t('article-mock.title')}
      </div>
      <div style={{ fontSize: 12, color:'var(--ink-2)', marginBottom: 14 }}>{t('article-mock.meta')}</div>
      <div style={{ display:'grid', gap: 4 }}>
        {[100,92,84,98,76,90,70].slice(0, compact ? 4 : 7).map((w,i) => (
          <div key={i} style={{ height: 6, background:'var(--paper-2)', borderRadius: 3, overflow:'hidden' }}>
            <div style={{ width: w + '%', height:'100%', background:'var(--ink-2)', opacity: .35 }}></div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ───────────────────────────────────────────────────────────── Token bar
function TokenBar({ remaining = 4720, max = 5000 }) {
  const { t } = useT();
  const pct = Math.round((remaining / max) * 100);
  return (
    <div style={{ fontFamily:'var(--mono)' }}>
      <div style={{ display:'flex', justifyContent:'space-between', fontSize: 12, marginBottom: 6 }}>
        <span>{t('token-bar.welcome')}</span>
        <span style={{ color:'var(--ink-2)' }}>{remaining.toLocaleString()} / {max.toLocaleString()}</span>
      </div>
      <div style={{ height: 8, background:'var(--paper-2)', borderRadius: 999, overflow:'hidden', border:'1px solid var(--rule)' }}>
        <div style={{ width: pct + '%', height:'100%', background:'var(--accent)', animation:'ruu-bar-grow 1.6s cubic-bezier(.2,.7,.2,1)' }}></div>
      </div>
    </div>
  );
}

// ───────────────────────────────────────────────────────────── Agent pipeline pills
// Stores i18n key slugs. Components call t(a.name) / t(a.role) to render localised text.
const AGENTS = [
  { id: 'researcher',  name: 'agents.researcher.name',   role: 'agents.researcher.role' },
  { id: 'planner',     name: 'agents.planner.name',      role: 'agents.planner.role' },
  { id: 'writer',      name: 'agents.writer.name',       role: 'agents.writer.role' },
  { id: 'editor',      name: 'agents.editor.name',       role: 'agents.editor.role' },
  { id: 'seo',         name: 'agents.seo.name',          role: 'agents.seo.role' },
  { id: 'brand-voice', name: 'agents.brand-voice.name',  role: 'agents.brand-voice.role' },
];

function AgentPipeline({ stacked = false }) {
  const { t } = useT();
  return (
    <div style={{ display:'flex', flexDirection: stacked ? 'column' : 'row', gap: stacked ? 8 : 10, flexWrap:'wrap' }}>
      {AGENTS.map((a, i) => (
        <div key={i} style={{ display:'flex', alignItems:'center', gap: 8 }}>
          <div style={{ padding:'8px 12px', border:'1px solid var(--rule)', borderRadius: 8, background:'var(--paper)', display:'flex', flexDirection:'column', gap: 2, minWidth: 110 }}>
            <span className="mono" style={{ fontSize: 10, color:'var(--ink-3)', textTransform:'uppercase', letterSpacing:'0.08em' }}>0{i+1}</span>
            <span style={{ fontWeight: 600, fontSize: 13 }}>{t(a.name)}</span>
            <span className="mono" style={{ fontSize: 10, color:'var(--ink-2)' }}>{t(a.role)}</span>
          </div>
          {i < AGENTS.length - 1 && !stacked && <span style={{ color: 'var(--ink-3)', fontFamily:'var(--mono)' }}>→</span>}
        </div>
      ))}
    </div>
  );
}

// ───────────────────────────────────────────────────────────── Engine matrix
const ENGINES = [
  { name: 'ChatGPT', short: 'GPT', citations: 142, trend: '+18%' },
  { name: 'Perplexity', short: 'PPX', citations: 89, trend: '+44%' },
  { name: 'Google AI Overviews', short: 'AIO', citations: 68, trend: '+9%' },
  { name: 'Claude', short: 'CLD', citations: 51, trend: '+22%' },
  { name: 'Gemini', short: 'GMN', citations: 37, trend: '+12%' },
];

// ───────────────────────────────────────────────────────────── Country bar
const COUNTRIES = ['TR', 'DE', 'NL', 'US', 'UK', 'FR', 'AE', 'SA', 'AZ', 'KZ', 'BG', 'GR', 'ES', 'IT', 'PL', 'RO', 'IL', 'EG', 'MX', 'BR', 'AR'];

// Export to window so other Babel scripts can grab these.
Object.assign(window, {
  RuuMark, RuuWordmark, Ticker, Reveal, Counter, Typewriter, CTA, useMobile,
  COMPARE_ROWS, COMPARE_ROW_KEYS, CheckIcon, CrossIcon, FEATURES,
  CitationSparkline, ArticleMock, TokenBar, AgentPipeline, AGENTS, ENGINES, COUNTRIES,
});
