// ===========================================================
// Analytics — data model
// Single fictional client: Bloemerij (e-commerce, premium bloemen + planten).
// All numbers are mock but internally consistent.
// ===========================================================

// ---- Connectors (master list) ----
// Required = MUST be connected for all clients (vlaggenschip-data komt hier vandaan).
// Optional = SER-managed extras voor diepere analyses.
const CONNECTORS = [
  { id: 'ga4',     label: 'Google Analytics 4',  category: 'Web analytics',  required: true,  vendor: 'google',   icon: 'ga' },
  { id: 'gads',    label: 'Google Ads',           category: 'Paid media',     required: true,  vendor: 'google',   icon: 'gads' },
  { id: 'gsc',     label: 'Search Console',       category: 'SEO',            required: true,  vendor: 'google',   icon: 'gsc' },
  { id: 'semrush', label: 'Semrush',              category: 'SEO',            required: true,  vendor: 'semrush',  icon: 'semrush' },
  { id: 'meta',    label: 'Meta Ads',             category: 'Paid media',     required: false, vendor: 'meta',     icon: 'meta' },
  { id: 'tiktok',  label: 'TikTok Ads',           category: 'Paid media',     required: false, vendor: 'tiktok',   icon: 'tiktok' },
  { id: 'linkedin',label: 'LinkedIn Ads',         category: 'Paid media',     required: false, vendor: 'linkedin', icon: 'linkedin' },
  { id: 'shopify', label: 'Shopify',              category: 'E-commerce',     required: false, vendor: 'shopify',  icon: 'shop' },
  { id: 'woo',     label: 'WooCommerce',          category: 'E-commerce',     required: false, vendor: 'woo',      icon: 'woo' },
  { id: 'magento', label: 'Magento / Adobe Cmce', category: 'E-commerce',     required: false, vendor: 'adobe',    icon: 'magento' },
  { id: 'hubspot', label: 'HubSpot CRM',          category: 'CRM',            required: false, vendor: 'hubspot',  icon: 'hubspot' },
  { id: 'salesforce',label: 'Salesforce',         category: 'CRM',            required: false, vendor: 'sf',       icon: 'sf' },
  { id: 'klaviyo', label: 'Klaviyo',              category: 'E-mail',         required: false, vendor: 'klaviyo',  icon: 'klaviyo' },
  { id: 'mailchimp',label:'Mailchimp',            category: 'E-mail',         required: false, vendor: 'mc',       icon: 'mc' },
  { id: 'ahrefs',  label: 'Ahrefs',               category: 'SEO',            required: false, vendor: 'ahrefs',   icon: 'ahrefs' },
  { id: 'serpapi', label: 'SerpAPI',              category: 'SEO',            required: false, vendor: 'serp',     icon: 'serp' },
  { id: 'bq',      label: 'BigQuery (custom)',    category: 'Data warehouse', required: false, vendor: 'google',   icon: 'bq' },
  { id: 'snowflake',label:'Snowflake',            category: 'Data warehouse', required: false, vendor: 'snow',     icon: 'snow' },
  { id: 'google_merchant', label: 'Google Merchant Center', category: 'E-commerce',     required: false, vendor: 'google', icon: 'shop' },
  { id: 'bing_ads',        label: 'Microsoft Ads (Bing)',   category: 'Paid media',     required: false, vendor: 'ms',     icon: 'bolt' },
  { id: 'ga4_bq',          label: 'GA4 → BigQuery',         category: 'Data warehouse', required: false, vendor: 'google', icon: 'harvest' },
];

// ---- SER PROPRIETARY SIGNALS ----
const PROPRIETARY_SIGNALS = [
  {
    id: 'aio-monitor',
    label: 'AIO-monitor',
    category: 'SER · proprietary',
    sub: 'AI Overview tracking',
    desc: 'Dagelijkse scrape van Google SERPs op 12k+ keywords. Detecteert wanneer AI Overviews triggeren, welke bronnen worden geciteerd, en hoe de positie van de klant verschuift.',
    sample: '38% van top-100 KWs trigger AIO · Bloemerij genoemd in 21%',
    method: 'SerpAPI + custom scraper · headless Chrome · captcha-rotation',
    refresh: 'Dagelijks 03:00 · 14k SERPs',
    exclusive: true,
    icon: 'spark',
  },
  {
    id: 'comp-price',
    label: 'Concurrent prijsmonitor',
    category: 'SER · proprietary',
    sub: 'Competitive pricing scrape',
    desc: 'Volgt prijzen van top-5 concurrenten op de 200 belangrijkste SKUs van de klant. Detecteert prijscampagnes, kortingscycli en out-of-stock signalen.',
    sample: 'Bloomon Direct: -15% op weekboeketten sinds 8 feb',
    method: 'Playwright scraper · 5x daags · price-history database',
    refresh: '4x per dag · ~1k SKUs',
    exclusive: true,
    icon: 'sword',
  },
  {
    id: 'sov-tracker',
    label: 'Share-of-voice index',
    category: 'SER · proprietary',
    sub: 'Multi-source SoV',
    desc: 'Combineert organische + paid SERP-aanwezigheid + display-impressies + social mentions tot één SoV-score. Vergelijkt met top-10 spelers in de niche.',
    sample: 'Bloemerij SoV 19% (-9pp YoY) · markt-positie #3',
    method: 'Eigen weegformule over 6 datapunten · Brandwatch + Semrush + Ahrefs',
    refresh: 'Wekelijks',
    exclusive: true,
    icon: 'globe',
  },
  {
    id: 'review-mining',
    label: 'Review-mining',
    category: 'SER · proprietary',
    sub: 'Klant-sentiment NLP',
    desc: 'Scraped reviews van Trustpilot, Google Reviews, Kiyoh en eigen platform. NLP extraheert thema\'s (bezorging, kwaliteit, prijs, service) en signaleert pieken in negatief sentiment.',
    sample: '142 reviews afgelopen 30d · sentiment 4.1/5 · "verpakking" daalt',
    method: 'Eigen NLP-pipeline · Claude Sonnet voor thema-extractie',
    refresh: 'Dagelijks',
    exclusive: true,
    icon: 'users',
  },
  {
    id: 'tech-audit',
    label: 'Tech-audit signalen',
    category: 'SER · proprietary',
    sub: 'Site health monitor',
    desc: 'Continue Lighthouse-audits + custom checks op CMS-changes, broken links, schema-validiteit en third-party scripts. Alerts bij regressie.',
    sample: 'LCP P75 mobiel 3.4s (was 2.1s) · 18 broken links sinds 11 mrt',
    method: 'Lighthouse CI + eigen audit-runner · 3x daags',
    refresh: '3x per dag',
    exclusive: true,
    icon: 'gauge',
  },
  {
    id: 'demand-trends',
    label: 'Demand-trends',
    category: 'SER · proprietary',
    sub: 'Markt-vraag voorspelling',
    desc: 'Combineert Google Trends, weer-API, social mentions en historische verkoop tot een 14-daagse vraagvoorspelling per categorie.',
    sample: 'Tuinplanten -22% volgende 14d · Pioenen +14% (Moederdag)',
    method: 'Eigen ML-model (XGBoost) · 18 features',
    refresh: 'Dagelijks',
    exclusive: true,
    icon: 'trend',
  },
];

// ---- AI providers (admin-configureerbaar) ----
const AI_PROVIDERS = [
  {
    id: 'claude',
    label: 'Anthropic Claude',
    sub: 'Aanbevolen · primair voor business cases',
    models: ['claude-sonnet-4.5', 'claude-opus-4', 'claude-haiku-4.5'],
    defaultModel: 'claude-sonnet-4.5',
    status: 'connected',
    apiKeyMask: 'sk-ant-•••••••••••••••••3a92',
    monthlyCost: '€ 142',
    monthlyTokens: '4.2M tokens',
    addedAt: '2025-08-12',
    usage: { businesscases: true, briefings: true, insights: true, chat: true },
    docsUrl: 'https://docs.anthropic.com',
    primary: true,
  },
  {
    id: 'openai',
    label: 'OpenAI',
    sub: 'Backup · voor specifieke use-cases',
    models: ['gpt-5', 'gpt-5-mini', 'o3'],
    defaultModel: 'gpt-5',
    status: 'connected',
    apiKeyMask: 'sk-•••••••••••••••2f81',
    monthlyCost: '€ 38',
    monthlyTokens: '0.8M tokens',
    addedAt: '2025-09-04',
    usage: { businesscases: false, briefings: false, insights: false, chat: false, fallback: true },
    docsUrl: 'https://platform.openai.com',
  },
  {
    id: 'gemini',
    label: 'Google Gemini',
    sub: 'Niet geconfigureerd',
    models: ['gemini-2.5-pro', 'gemini-2.5-flash'],
    status: 'disconnected',
    apiKeyMask: null,
    monthlyCost: '—',
    monthlyTokens: '—',
    docsUrl: 'https://ai.google.dev',
  },
  {
    id: 'mistral',
    label: 'Mistral AI',
    sub: 'EU-gehoste optie',
    models: ['mistral-large', 'mistral-medium'],
    status: 'disconnected',
    apiKeyMask: null,
    docsUrl: 'https://mistral.ai',
  },
];

const ANALYTICS_CLIENTS = [];

// ---- Business Cases ----
const BUSINESS_CASES = [];
// Business case structuur met confidence + bandbreedte:
// { id, title, cause, severity, status, aiGenerated, aiConfidence: 0-100,
//   summary, hypothesis, steps: [{t, who, days, done}],
//   investment: { low, mid, high },          // bandbreedte €
//   monthlyUplift: { low, mid, high },       // bandbreedte €/mnd
//   runtimeMonths, horizon12mGain: { low, mid, high },
//   confidence: { score: 0-100, sources: int, historical: bool, pValue: float, freshness: int },
//   confidenceBreakdown: { sources: 0-100, historical: 0-100, significance: 0-100, freshness: 0-100 },
//   risks, kpis, aiNotes }

// ---- DASHBOARDS index ----
const DASHBOARDS = [
  { id: 'overview',    label: 'Overview',             icon: 'home',     status: 'live', clientVisible: true },
  { id: 'revenue',     label: 'Omzet & Marge',        icon: 'trend',    status: 'live', flagship: true, clientVisible: true },
  { id: 'cases',       label: 'Business Cases',       icon: 'case',     status: 'live', clientVisible: true, aiPowered: true },
  { id: 'strategy',    label: 'Strategie & Merk',     icon: 'compass',  status: 'beta', clientVisible: true, aiPowered: true },
  { id: 'campaigns',   label: 'Campagne-radar',       icon: 'radar',    status: 'beta', clientVisible: true },
  { id: 'competition', label: 'Concurrentie & Markt', icon: 'globe',    status: 'beta', clientVisible: true },
  { id: 'funnel',      label: 'Funnel & Conversie',   icon: 'funnel',   status: 'beta', clientVisible: true },
  { id: 'cohort',      label: 'Klant & Cohort',       icon: 'users',    status: 'beta', clientVisible: true },
  { id: 'ai',          label: 'AI-kansen',            icon: 'spark',    status: 'beta', clientVisible: true },
  { id: 'briefing',    label: 'Executive Briefing',   icon: 'doc',      status: 'beta', clientVisible: true },
];

const ADMIN_SECTIONS = [
  { id: 'admin-klanten',     label: 'Klanten & Koppelingen', icon: 'users' },
  { id: 'admin-users',       label: 'Toegang & rollen',    icon: 'shield' },
  { id: 'admin-docs',        label: 'Documentatie',        icon: 'doc' },
];

const DATA_SOURCES = [
  { id: 'ga4',     label: 'GA4',                 status: 'ok',   freshness: 'live (12 min)',  rows: '1.2M events / dag' },
  { id: 'gsc',     label: 'Search Console',      status: 'ok',   freshness: 'gisteren 23:50', rows: '48k queries' },
  { id: 'gads',    label: 'Google Ads',          status: 'ok',   freshness: 'live (4 min)',   rows: '€ 38k / mnd' },
  { id: 'shop',    label: 'Shopify',             status: 'ok',   freshness: 'live',           rows: '8.4k orders / mnd' },
  { id: 'bq',      label: 'BigQuery (orders)',   status: 'ok',   freshness: 'live',           rows: '2.1M rows' },
  { id: 'crm',     label: 'HubSpot CRM',         status: 'warn', freshness: '6 uur achter',   rows: '24k contacts' },
  { id: 'ahrefs',  label: 'Ahrefs',              status: 'ok',   freshness: 'gisteren',       rows: '12k keywords' },
  { id: 'serp',    label: 'SerpAPI',             status: 'ok',   freshness: 'live (8 min)',   rows: '4.2k SERPs / dag' },
];

const REVENUE_SERIES = (() => {
  const days = 90;
  const arr = [];
  for (let i = 0; i < days; i++) {
    const t = i / (days - 1);
    const seasonal = 1 + 0.18 * Math.sin((i + 4) / 7 * Math.PI);
    const trend = 1 - 0.10 * Math.max(0, t - 0.45);
    const noise = 1 + (Math.sin(i * 1.7) + Math.cos(i * 0.9)) * 0.04;
    const valNow  = 14000 * seasonal * trend * noise;
    const valPrev = 14000 * seasonal * (1 + 0.05 * t) * (1 + Math.sin(i * 1.3) * 0.04);
    arr.push({ d: i, now: Math.round(valNow), prev: Math.round(valPrev) });
  }
  return arr;
})();

const CAUSES = [
  {
    id: 'internal',
    label: 'Intern',
    icon: 'wrench',
    color: '#1e1e5a',
    impact: -58200,
    severity: 'high',
    summary: 'Site-issues + voorraad zijn de grootste interne kostenposten. Vooral de checkout-bug van 18 mrt en out-of-stock op de top-3 SKUs.',
    findings: [
      'Checkout JS-error op iOS Safari (18–24 mrt) — 1.2k sessies geblokkeerd',
      'Out-of-stock op "Pioenboeket M" (15 dagen, top-3 SKU)',
      'Prijsverhoging plant-categorie +6% zonder communicatie',
    ],
  },
  {
    id: 'sitespeed',
    label: 'Sitespeed',
    icon: 'gauge',
    color: '#7c5cff',
    impact: -18400,
    severity: 'med',
    summary: 'Mobile LCP is in 6 weken van 2.1s naar 3.4s gegaan. PDP\'s laden 41% trager — conversie-impact zichtbaar in funnel.',
    findings: [
      'LCP P75 mobiel: 3.4s (was 2.1s) — drempel rood',
      'Hero-image niet preloaded sinds CMS-update 11 mrt',
      'Third-party tags: 1.8s blokkerende JS',
    ],
  },
  {
    id: 'competition',
    label: 'Concurrentie',
    icon: 'sword',
    color: '#e53935',
    impact: -34800,
    severity: 'high',
    summary: 'Twee nieuwe spelers (Bloomon Direct, FloraBox) draaien sinds februari een agressieve prijscampagne. Share-of-voice op generieke termen daalde van 28% → 19%.',
    findings: [
      'Bloomon Direct: -15% prijs op weekboeketten (sinds 8 feb)',
      'FloraBox: top-3 op 142 high-intent keywords gewonnen',
      'Eigen SoV (generiek) 28% → 19% (-9pp)',
    ],
  },
  {
    id: 'market',
    label: 'Markt & seizoen',
    icon: 'cloud',
    color: '#5a5e7a',
    impact: -12600,
    severity: 'low',
    summary: 'Late lente: weekendweer 4 weken op rij regenachtig. Categorie "tuinplanten" -22% over heel NL — niet een Bloemerij-probleem.',
    findings: [
      'NL bloemen-zoekvolume -8% YoY (KvK Trend)',
      'Pasen viel 11 dagen later — piek nog niet binnen',
      'Tuinplanten markt-breed -22%',
    ],
  },
  {
    id: 'campaigns',
    label: 'Eigen acties',
    icon: 'megaphone',
    color: '#f5a523',
    impact: 8200,
    severity: 'low',
    summary: 'De "Lentebox" e-mail-campagne is sterk (ROAS 6.2). Google Ads op brand draait stabiel. Géén actief verlies, maar ook geen offset voor de daling.',
    findings: [
      'Lentebox e-mail (15 mrt): +€ 14k incremental',
      'Google Ads non-brand: ROAS 1.4 — verlies € 5.8k',
      'Geen Mother\'s-Day campagne klaar (vorig jaar +€ 32k)',
    ],
  },
  {
    id: 'serp',
    label: 'Google / AIO',
    icon: 'search',
    color: '#00b4a0',
    impact: -22400,
    severity: 'med',
    summary: 'AI Overviews trigger op 38% van top-100 keywords (was 12%). Bloemerij wordt in 21% van AIOs genoemd — netto -29% organic CTR op informational queries.',
    findings: [
      'AIO trigger: 38% van top-100 keywords (+26pp YoY)',
      'Bloemerij in AIO: 21% van triggers (mid-pack)',
      'Organic CTR informational: 4.1% → 2.9%',
    ],
  },
  {
    id: 'tracking',
    label: 'Tracking & data',
    icon: 'shield',
    color: '#a8acc0',
    impact: -4200,
    severity: 'low',
    summary: 'GA4 consent-mode v2 update. ~7% van de orders mist user-id; modeled traffic vult dat deels op. Niet alle "verloren" omzet is écht verloren.',
    findings: [
      'Consent rate gedaald van 81% → 74%',
      'Modeled conversies +4.8% van totaal',
      '"Direct" channel +12% — overrapportage',
    ],
  },
];

const CHANNELS = [
  { id: 'organic',  label: 'Organic',     rev: 1180400, deltaPct: -14.2, sessions: 412000, sov: 19, color: '#00b4a0' },
  { id: 'paid',     label: 'Paid Search', rev:  892100, deltaPct:  -2.8, sessions: 184000, sov: null, color: '#f5a523' },
  { id: 'social',   label: 'Social',      rev:  324800, deltaPct:  +4.1, sessions: 142000, sov: null, color: '#ec4899' },
  { id: 'email',    label: 'E-mail',      rev:  482900, deltaPct: +12.4, sessions:  68000, sov: null, color: '#7c5cff' },
  { id: 'direct',   label: 'Direct',      rev:  398200, deltaPct: +12.0, sessions: 122000, sov: null, color: '#5a5e7a' },
  { id: 'affil',    label: 'Affiliate',   rev:   84300, deltaPct: -18.0, sessions:  18400, sov: null, color: '#2563eb' },
];

const SCENARIOS = [
  {
    id: 'donothing',
    title: 'Niets doen',
    desc: 'Lopende koers vasthouden. Concurrentie wint marktaandeel, AIOs blijven CTR drukken.',
    outcome: '-€ 286k',
    outcomeKind: 'neg',
    confidence: '82%',
    timeframe: 'Q3 2026',
    roi: '—',
    items: ['Marktaandeel -3pp', 'Marge 18.4% → 16.1%', 'Geen recovery'],
  },
  {
    id: 'recover',
    title: 'Quick wins (Site + Speed + AIO)',
    desc: 'Checkout fixen, LCP terug naar 2.0s, AIO-content voor top-50 informational queries.',
    outcome: '+€ 168k',
    outcomeKind: 'pos',
    confidence: '76%',
    timeframe: '12 weken',
    roi: '4.8x',
    items: ['Checkout-bug → +€ 32k / mnd', 'LCP fix → +1.4pp CR', '50 AIO-pagina\'s → +€ 22k / mnd'],
    recommended: true,
  },
  {
    id: 'attack',
    title: 'Aanvallen op concurrentie',
    desc: 'Pricing-match op weekboeketten, paid push op concurrent-brand-terms, retentie-loyaltyprogramma.',
    outcome: '+€ 312k',
    outcomeKind: 'pos',
    confidence: '54%',
    timeframe: '24 weken',
    roi: '2.1x',
    items: ['Marge -2pp door pricing-match', 'Investering € 145k', 'Risico: prijsoorlog'],
  },
];

const ACTIONS = [
  {
    rank: 1,
    title: 'Fix iOS Safari checkout — JS-error in PaymentRequest API',
    why: 'Repro\'d op 4 devices. Blokkeert ~12% van iOS-orders sinds 18 mrt.',
    impact: '+ € 32k / mnd',
    effort: '1 dev-dag',
    cause: 'internal',
  },
  {
    rank: 2,
    title: 'Hero-image preloaden + WebP serving op PDPs',
    why: 'LCP P75 mobiel daalt van 3.4s naar verwachte 2.0s. Funnel CR + 1.4pp.',
    impact: '+ € 28k / mnd',
    effort: '0.5 dev-dag',
    cause: 'sitespeed',
  },
  {
    rank: 3,
    title: 'AIO-content sprint: top-50 informational queries',
    why: 'Bloemerij wordt nu maar in 21% van AIOs genoemd. Met FAQ-blokken + schema.org → schatting 38%.',
    impact: '+ € 22k / mnd',
    effort: '2 weken content',
    cause: 'serp',
  },
  {
    rank: 4,
    title: 'Mother\'s-Day campagne reactiveren (Lentebox 2025-template)',
    why: 'Vorig jaar +€ 32k incremental. Doelgroep + creatives staan al klaar in HubSpot.',
    impact: '+ € 32k incidenteel',
    effort: '3 dagen team',
    cause: 'campaigns',
  },
  {
    rank: 5,
    title: 'Reactiveer 4.2k churned customers (60-90d window)',
    why: 'Cohort 2025-Q4 toont 38% repeat-purchase als binnen 90d retargeted. Window sluit deze maand.',
    impact: '+ € 18k incidenteel',
    effort: '1 dag setup',
    cause: 'campaigns',
  },
];

const FUNNEL = [
  { step: 'Sessies',         val: 962400, pct: 100,  delta: -3.2 },
  { step: 'PDP-view',        val: 412800, pct: 42.9, delta: -1.4 },
  { step: 'Add to cart',     val:  78400, pct:  8.1, delta: -0.6 },
  { step: 'Checkout-start',  val:  41200, pct:  4.3, delta: -0.8 },
  { step: 'Order',           val:  28400, pct:  2.95, delta: -0.41 },
];

const COMPETITORS = [
  { name: 'Bloomon Direct',  sov: 24, deltaSov: +5.2, rank: 1, threat: 'high' },
  { name: 'FloraBox',        sov: 21, deltaSov: +3.8, rank: 2, threat: 'high' },
  { name: 'Bloemerij',       sov: 19, deltaSov: -9.0, rank: 3, threat: '—', self: true },
  { name: 'GreenGarden',     sov: 12, deltaSov: -1.1, rank: 4, threat: 'low' },
  { name: 'Tuinwereld',      sov:  9, deltaSov:  0.0, rank: 5, threat: 'low' },
];

const COHORTS = (() => {
  const months = ['Okt \'25','Nov \'25','Dec \'25','Jan \'26','Feb \'26','Mrt \'26','Apr \'26'];
  const data = months.map((m, i) => {
    const row = [];
    for (let j = 0; j <= i; j++) {
      const decay = Math.max(0, 100 - j*22 - Math.random()*8);
      row.push(Math.round(decay));
    }
    return { month: m, retention: row, size: 1200 + Math.round(Math.random()*400) };
  });
  return data;
})();

const Icons = {
  home: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2h-4v-7h-6v7H5a2 2 0 0 1-2-2z"/></svg>,
  trend: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 17 9 11 13 15 21 7"/><polyline points="14 7 21 7 21 14"/></svg>,
  radar: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><path d="M12 12L19 5"/><circle cx="19" cy="5" r="1.5" fill="currentColor"/></svg>,
  globe: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15 15 0 0 1 0 20M12 2a15 15 0 0 0 0 20"/></svg>,
  funnel: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M22 3H2l8 9v7l4 2v-9z"/></svg>,
  users: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/></svg>,
  spark: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 2l2 6 6 2-6 2-2 6-2-6-6-2 6-2z"/></svg>,
  doc: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>,
  wrench: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>,
  gauge: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 14l4-4M21 12a9 9 0 1 1-9-9"/><path d="M12 21a9 9 0 0 0 9-9"/></svg>,
  sword: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M14.5 17.5L3 6V3h3l11.5 11.5M13 19l6-6M16 16l4 4M19 21l2-2"/></svg>,
  cloud: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/></svg>,
  megaphone: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 11l18-8v18l-18-8zM11 15v4a2 2 0 0 0 4 0v-3"/></svg>,
  search: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>,
  shield: <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 2l9 4v6c0 5-3.5 9-9 10-5.5-1-9-5-9-10V6z"/></svg>,
  case: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="7" width="18" height="13" rx="2"/><path d="M8 7V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M3 13h18"/></svg>,
  plug: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22v-5M9 8V2M15 8V2M5 8h14v3a7 7 0 0 1-14 0z"/></svg>,
  building: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="4" y="2" width="16" height="20" rx="1"/><path d="M9 6h2M13 6h2M9 10h2M13 10h2M9 14h2M13 14h2M10 22v-4h4v4"/></svg>,
  link: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10 13a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1"/><path d="M14 11a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1"/></svg>,
  receipt: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M4 2v20l3-2 3 2 3-2 3 2 3-2V2zM8 7h8M8 11h8M8 15h5"/></svg>,
  check: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="5 12 10 17 19 7"/></svg>,
  plus: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>,
  edit: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4z"/></svg>,
  compass: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/></svg>,
};

// =====================================================================
// STRATEGIE & MERK (BETA)
// =====================================================================

const PROP_CLAIMS = [
  { id: 'fresh',   claim: 'Vers van de teler — binnen 24u bezorgd',     surfaces: ['hero','footer','about'], strength: 92 },
  { id: 'local',   claim: 'Lokale Hollandse bloemen, geen import',       surfaces: ['hero','about'],          strength: 78 },
  { id: 'craft',   claim: 'Met de hand gebonden door bloemisten',         surfaces: ['hero','PDP'],            strength: 85 },
  { id: 'sustain', claim: 'Duurzaam — geen vliegrozen, FSC-papier',       surfaces: ['footer','about'],        strength: 64 },
  { id: 'gift',    claim: 'Dé cadeauwinkel voor elk moment',               surfaces: ['hero'],                  strength: 71 },
];

const PROP_ACTIONS = [
  { id: 'fresh',   alignment: 'aligned',  evidence: '34% van Ads-budget op "verse bloemen" termen, 22 PDPs met versheids-USP',  delta: +6 },
  { id: 'local',   alignment: 'mismatch', evidence: '12% van bestsellers zijn import-rozen uit Kenia. Geen "lokaal" in Ads.',     delta: -38 },
  { id: 'craft',   alignment: 'aligned',  evidence: 'Foto-content laat handen zien. UGC-stream ondersteunt.',                     delta: +2 },
  { id: 'sustain', alignment: 'weak',     evidence: 'Geen duurzaamheids-pagina. 0% van paid spend. Concurrent (Greenflor) wel.',  delta: -22 },
  { id: 'gift',    alignment: 'mismatch', evidence: 'Top-10 SKUs zijn rouw-bloemen, niet cadeau. Persona-mismatch met homepage.', delta: -41 },
];

const BRAND_PERCEPTION = {
  scores: [
    { id: 'trust',     label: 'Vertrouwen',           value: 72, benchmark: 78, note: 'Reviews zichtbaar, maar geen Trustpilot-widget op PDP.' },
    { id: 'premium',   label: 'Premium-gevoel',       value: 58, benchmark: 70, note: 'Prijs zegt premium (€42 gem.), foto\'s ogen middensegment.' },
    { id: 'warmth',    label: 'Warmte / persoonlijk', value: 81, benchmark: 65, note: 'Sterk punt — handgeschreven kaartjes, eigenaar zichtbaar.' },
    { id: 'modern',    label: 'Modern / hedendaags',  value: 49, benchmark: 68, note: 'Site-design oogt 2019. Typografie matcht niet met Insta.' },
    { id: 'clarity',   label: 'Duidelijkheid USP',    value: 64, benchmark: 75, note: 'Hero zegt drie dingen tegelijk — kies één.' },
    { id: 'consistency', label: 'Consistentie kanalen', value: 53, benchmark: 72, note: 'Tone-of-voice op IG vs site verschilt sterk.' },
  ],
  voiceTone: {
    site:      ['professioneel','ietwat formeel','algemeen'],
    instagram: ['speels','persoonlijk','eigenwijs'],
    ads:       ['transactioneel','prijs-gedreven','generiek'],
    email:     ['warm','verhalend','op maat'],
  },
  audienceMatch: 71,
};

const BCG_ITEMS = [
  { id: 'rouw',       label: 'Rouw-arrangementen',  share: 0.78, growth: 0.04, revenue: 184000, margin: 0.42, quad: 'cash' },
  { id: 'bruids',     label: 'Bruidsboeketten',     share: 0.31, growth: 0.18, revenue: 92000,  margin: 0.51, quad: 'star' },
  { id: 'abo',        label: 'Bloemen-abonnement',  share: 0.12, growth: 0.42, revenue: 38000,  margin: 0.38, quad: 'question' },
  { id: 'cadeau',     label: 'Cadeau-boeketten',    share: 0.42, growth: 0.09, revenue: 156000, margin: 0.34, quad: 'cash' },
  { id: 'planten',    label: 'Kamerplanten',        share: 0.18, growth: 0.22, revenue: 64000,  margin: 0.29, quad: 'question' },
  { id: 'droog',      label: 'Droogbloemen',        share: 0.08, growth: 0.31, revenue: 22000,  margin: 0.46, quad: 'question' },
  { id: 'snij',       label: 'Losse snijbloemen',   share: 0.62, growth: -0.06, revenue: 78000, margin: 0.21, quad: 'dog' },
  { id: 'kerst',      label: 'Seizoen — Kerst',     share: 0.24, growth: -0.02, revenue: 41000, margin: 0.33, quad: 'dog' },
];

const SWOT = {
  strengths: [
    { t: 'Bruidsboeketten groeien 18% YoY met 51% marge — sterkste segment',  src: 'BCG · Shopify' },
    { t: 'Brand-warmth score 81/100, ver boven benchmark 65',                   src: 'Brand-scan · reviews' },
    { t: 'NPS 64 onder repeat-klanten — basis voor word-of-mouth',              src: 'CRM · post-purchase' },
    { t: 'Email-kanaal converteert 4.2% (sector 1.8%)',                          src: 'GA4 · Klaviyo' },
  ],
  weaknesses: [
    { t: 'Site-snelheid LCP 4.1s mobiel — kost ~€18k/mnd in dropoff',            src: 'CrUX · GA4' },
    { t: 'Propositie-mismatch: roept "lokaal" maar 12% import-aandeel',          src: 'Site-scrape · Shopify' },
    { t: 'Modern-perceptie 49/100 — site oogt 2019',                              src: 'Brand-scan · UX-review' },
    { t: 'Kerst-categorie krimpt -2% YoY met dalende marge',                      src: 'BCG · Shopify' },
  ],
  opportunities: [
    { t: 'Abonnement groeit 42% — onder-investering in paid (€340/mnd)',          src: 'BCG · Ads' },
    { t: 'Duurzaamheid: zoekvraag +28% YoY, geen content-aanbod bij ons',          src: 'GSC · Ahrefs' },
    { t: 'Greenflor verloor 4% SoV — venster om te claimen op "lokaal"',           src: 'Concurrentie · SoV' },
    { t: 'AI-search (AIO) toont concurrenten — kans op zero-click positioning',    src: 'SerpAPI · GSC' },
  ],
  threats: [
    { t: 'Bloomon herlanceert abo-propositie met €5 lagere instap',                src: 'Concurrentie · scrape' },
    { t: 'Google AIO neemt 31% van top-funnel queries weg',                         src: 'GSC · SerpAPI' },
    { t: 'Tracking-uitval na consent-banner update — 14% blind',                   src: 'GA4 · CMP' },
    { t: 'Veiling-prijzen rozen +18% — drukt marge op cadeau-cat.',                 src: 'Markt-feed' },
  ],
};

const STRAT_PILLARS = [
  { id: 'p1', label: 'Vers & lokaal',            target: 0.35, actual: 0.18, signal: 'under', note: 'Roepen we hard, investeren we weinig.' },
  { id: 'p2', label: 'Premium handwerk',          target: 0.20, actual: 0.24, signal: 'ok',    note: 'In balans.' },
  { id: 'p3', label: 'Cadeau-momenten',           target: 0.25, actual: 0.41, signal: 'over',  note: 'Hier zit het meeste budget — terwijl rouw de cash-cow is.' },
  { id: 'p4', label: 'Abonnement (groei)',        target: 0.15, actual: 0.04, signal: 'under', note: '42% groei, 4% van budget. Mismatch.' },
  { id: 'p5', label: 'Duurzaamheid',              target: 0.05, actual: 0.00, signal: 'under', note: 'Wel geclaimd, niet uitgevoerd.' },
];

const STRAT_MOVES = [
  { id: 'm1', title: 'Herijk hero-propositie naar één belofte',
    rationale: 'Hero zegt nu vers + lokaal + handgemaakt + cadeau. Te veel. Brand-clarity 64/100.',
    expected: '+0.4–1.1pt CVR', effort: 'M', horizon: '2 wk', confidence: 0.62 },
  { id: 'm2', title: 'Stop import-rozen of stop "lokaal"-claim',
    rationale: 'Mismatch ondergraaft trust. Of de claim moet weg, of de inkoop verandert.',
    expected: 'Risico-mitigatie + +3pt trust-score', effort: 'L', horizon: '1 kwart.', confidence: 0.78 },
  { id: 'm3', title: 'Verdubbel investering in Bloemen-abo (Star/Question)',
    rationale: '42% groei, slechts 4% van budget. Onder-investering in groeisegment.',
    expected: '+€18–32k MRR over 6 mnd', effort: 'M', horizon: '6 wk', confidence: 0.71 },
  { id: 'm4', title: 'Snij Kerst-categorie strategisch terug',
    rationale: 'Krimpt -2%, marge daalt. Klassieke dog. Capaciteit naar Bruids/Abo.',
    expected: 'Margin-mix +1.4pt', effort: 'L', horizon: '1 seizoen', confidence: 0.55 },
  { id: 'm5', title: 'Bouw duurzaamheids-content hub',
    rationale: 'Geclaimd in footer, niet ondersteund. Zoekvraag +28% YoY.',
    expected: '+€6–14k organisch / mnd na 3 mnd', effort: 'M', horizon: '8 wk', confidence: 0.48 },
  { id: 'm6', title: 'Sync tone-of-voice site ↔ Instagram',
    rationale: 'Consistency-score 53. Insta is speels, site is stug. Kost je merk-warmte.',
    expected: 'Brand-coherentie +12pt', effort: 'S', horizon: '3 wk', confidence: 0.66 },
];

window.ANALYTICS_STRATEGY = {
  PROP_CLAIMS, PROP_ACTIONS, BRAND_PERCEPTION, BCG_ITEMS, SWOT, STRAT_PILLARS, STRAT_MOVES,
};

window.ANALYTICS_DATA = {
  ANALYTICS_CLIENTS, DASHBOARDS, ADMIN_SECTIONS, CONNECTORS, DATA_SOURCES,
  PROPRIETARY_SIGNALS, AI_PROVIDERS,
  REVENUE_SERIES, CAUSES, CHANNELS, SCENARIOS, ACTIONS,
  FUNNEL, COMPETITORS, COHORTS, BUSINESS_CASES, Icons,
};
