{
  "id": "gv2PH2ZULEQz5JCC",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "InstaPitch \u2014 Multi-Agent Consulting Proposal Automator",
  "tags": [],
  "nodes": [
    {
      "id": "2472624e-e759-4fac-8962-9b362fc45e59",
      "name": "TigerPitch - Receive Inputs",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -800,
        -400
      ],
      "parameters": {
        "path": "tigerpitch-generate",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "749f92f2-4f5c-481e-8040-94c3cf91eeb1",
      "name": "Fetch Company Website",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "maxTries": 2,
      "position": [
        -224,
        -384
      ],
      "parameters": {
        "url": "={{ \"https://r.jina.ai/\" + $json.body.company_url }}",
        "options": {
          "timeout": 30000,
          "allowUnauthorizedCerts": true
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Accept",
              "value": "text/plain"
            }
          ]
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.4,
      "waitBetweenTries": 3000
    },
    {
      "id": "e1231dd0-88bf-40e7-8fb5-186b18e8b862",
      "name": "Website Content Handler",
      "type": "n8n-nodes-base.code",
      "position": [
        0,
        -384
      ],
      "parameters": {
        "jsCode": "const inputData =\n  $('TigerPitch - Receive Inputs').item.json;\n\nlet websiteContent = '';\nlet fetchStatus = '';\n\ntry {\n\n  const websiteFetch =\n    $('Fetch Company Website').item;\n\n  const raw =\n    websiteFetch.json?.data ||\n    websiteFetch.json?.body ||\n    websiteFetch.json ||\n    '';\n\n  const text =\n    typeof raw === 'string'\n      ? raw\n      : JSON.stringify(raw);\n\n  if (text && text.length > 100) {\n\n    websiteContent =\n      text.substring(0, 3000);\n\n    fetchStatus = 'website_success';\n\n  } else {\n\n    throw new Error('Empty website content');\n  }\n\n} catch (e1) {\n\n  try {\n\n    const searchFetch =\n      $('Search Company Fallback').item;\n\n    const raw =\n      searchFetch.json?.data ||\n      searchFetch.json?.body ||\n      searchFetch.json ||\n      '';\n\n    const text =\n      typeof raw === 'string'\n        ? raw\n        : JSON.stringify(raw);\n\n    if (text && text.length > 100) {\n\n      websiteContent =\n        text.substring(0, 3000);\n\n      fetchStatus = 'search_success';\n\n    } else {\n\n      throw new Error('Empty search content');\n    }\n\n  } catch (e2) {\n\n    fetchStatus = 'fallback_knowledge';\n\n    websiteContent =\n      `Company: ${inputData.company_name}.\n       Industry: ${inputData.industry}.\n       Website and search unavailable.\n       Use your training knowledge about this company and industry.`;\n  }\n}\n\nreturn [\n  {\n    json: {\n      ...inputData,\n\n      website_content: websiteContent,\n\n      fetch_status: fetchStatus,\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "00bbaed5-2795-4d06-95ce-ab553f2495d2",
      "name": "Extract Research Data",
      "type": "n8n-nodes-base.code",
      "position": [
        704,
        -384
      ],
      "parameters": {
        "jsCode": "let researchData = {};\n\ntry {\n  // Anthropic node returns: content[0].text\n  const rawText = $input.first().json\n    ?.content?.[0]?.text || '{}';\n\n  // Clean any backticks just in case\n  let cleaned = rawText\n    .replace(/```json/gi, '')\n    .replace(/```/g, '')\n    .trim();\n\n  // Extract between first { and last }\n  const firstBrace = cleaned.indexOf('{');\n  const lastBrace = cleaned.lastIndexOf('}');\n\n  if (firstBrace !== -1 && lastBrace !== -1) {\n    cleaned = cleaned.substring(firstBrace, lastBrace + 1);\n    researchData = JSON.parse(cleaned);\n  } else {\n    throw new Error('No JSON found');\n  }\n\n} catch (e) {\n  researchData = {\n    company_overview: 'Research unavailable',\n    products_services: 'Information unavailable',\n    company_size: 'Unknown',\n    recent_initiatives: 'No recent initiatives identified',\n    technology_mentioned: 'No technology information available',\n    visible_pain_points: 'Business pain points could not be identified',\n    data_source: 'fallback'\n  };\n}\n\nconst webhookData = $('TigerPitch - Receive Inputs').first().json;\nconst handlerData = $('Website Content Handler').first().json;\n\nreturn {\n  ...webhookData,\n  ...handlerData,\n  research_data: researchData,\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "458ad887-0723-4379-87b0-36553dbd47a2",
      "name": "Extract Industry Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1360,
        -384
      ],
      "parameters": {
        "jsCode": "let industryData = {};\n\ntry {\n  // Anthropic node returns: content[0].text\n  const rawText = $input.first().json\n    ?.content?.[0]?.text || '{}';\n\n  let cleaned = rawText\n    .replace(/```json/gi, '')\n    .replace(/```/g, '')\n    .trim();\n\n  const firstBrace = cleaned.indexOf('{');\n  const lastBrace = cleaned.lastIndexOf('}');\n\n  if (firstBrace !== -1 && lastBrace !== -1) {\n    cleaned = cleaned.substring(firstBrace, lastBrace + 1);\n    industryData = JSON.parse(cleaned);\n  } else {\n    throw new Error('No JSON found');\n  }\n\n} catch (e) {\n  industryData = {\n    industry_trends: 'Industry trends unavailable',\n    common_root_causes: 'Root cause analysis unavailable',\n    benchmark_data: 'Benchmark data unavailable',\n    decision_maker_priorities: 'Decision maker priorities unavailable',\n    ai_opportunities: 'AI opportunity analysis unavailable',\n    competitive_context: 'Competitive context unavailable'\n  };\n}\n\nconst prev = $('Extract Research Data').first().json;\n\nreturn {\n  ...prev,\n  industry_data: industryData,\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "3ebca7d5-48ac-422b-9d96-dc8f8cfe86c3",
      "name": "Solution Router",
      "type": "n8n-nodes-base.if",
      "position": [
        2352,
        -352
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "87688609-e3ec-47a6-b845-b5efc89a7e79",
              "operator": {
                "type": "string",
                "operation": "equals",
                "singleValue": true
              },
              "leftValue": "={{ $('TigerPitch - Receive Inputs').item.json.body.solution_preference }}",
              "rightValue": "ai_suggest"
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.3
    },
    {
      "id": "9557a5e3-4cf2-44c7-9b8b-dacb807a3238",
      "name": "Solution Refiner - Gemini",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "maxTries": 3,
      "position": [
        2944,
        112
      ],
      "parameters": {
        "url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"contents\": [{\n    \"parts\": [{\n      \"text\": \"You are a senior consulting strategist.\\n\\nThe user has their own solution idea. Professionally refine, structure and elevate it into a clear consulting solution approach.\\n\\nUSER'S SOLUTION IDEA:\\n{{ $json.own_solution }}\\n\\nCOMPANY RESEARCH:\\n{{ JSON.stringify($json.research_data) }}\\n\\nINDUSTRY CONTEXT:\\n{{ JSON.stringify($json.industry_data) }}\\n\\nCLIENT PROBLEM: {{ $json.problem_statement }}\\nBUDGET: {{ $json.budget_range }}\\nTIMELINE: {{ $json.timeline }}\\nDECISION MAKER: {{ $json.decision_maker }}\\n\\nINSTRUCTIONS:\\n- Keep the user's core idea intact\\n- Improve clarity, structure and professional language\\n- Add specific phases and deliverables\\n- Make it relevant to the client's research data\\n\\nReturn ONLY a valid JSON object with no markdown, no explanation:\\n{\\n  \\\"option_number\\\": 1,\\n  \\\"title\\\": \\\"professional solution title derived from user's idea\\\",\\n  \\\"description\\\": \\\"2 clear professional sentences describing the solution\\\",\\n  \\\"approach\\\": \\\"structured 3-phase approach based on user's idea\\\",\\n  \\\"key_deliverables\\\": \\\"3 specific deliverables the client will receive\\\",\\n  \\\"best_for\\\": \\\"which type of client or situation this is best suited for\\\",\\n  \\\"estimated_effort\\\": \\\"medium\\\",\\n  \\\"expected_outcome\\\": \\\"specific measurable result the client can expect\\\"\\n}\"\n    }]\n  }],\n  \"generationConfig\": {\n    \"temperature\": 0.4,\n    \"maxOutputTokens\": 1000,\n    \"responseMimeType\": \"application/json\"\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpQueryAuth"
      },
      "credentials": {
        "httpQueryAuth": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.4,
      "waitBetweenTries": 2000
    },
    {
      "id": "fdd0b6eb-0f03-4a57-969c-f60fffd628de",
      "name": "Extract Solutions",
      "type": "n8n-nodes-base.code",
      "position": [
        3152,
        -352
      ],
      "parameters": {
        "jsCode": "let solutions = [];\nconst prev = $('Knowledge Base Lookup').first().json;\n\ntry {\n  const rawText = $input.first().json\n    ?.content?.[0]?.text || '';\n\n  if (!rawText) throw new Error('Empty');\n\n  let cleaned = rawText\n    .replace(/[\\u0000-\\u001F\\u007F-\\u009F]/g, ' ')\n    .replace(/```json/gi, '')\n    .replace(/```/g, '')\n    .trim();\n\n  // Find array or object\n  const firstBracket = cleaned.indexOf('[');\n  const lastBracket = cleaned.lastIndexOf(']');\n  const firstBrace = cleaned.indexOf('{');\n  const lastBrace = cleaned.lastIndexOf('}');\n\n  if (firstBracket !== -1 && lastBracket !== -1) {\n    // Normal array response\n    const jsonStr = cleaned.substring(firstBracket, lastBracket + 1);\n    solutions = JSON.parse(jsonStr);\n  } else if (firstBrace !== -1 && lastBrace !== -1) {\n    // Single object \u2014 wrap in array\n    const jsonStr = cleaned.substring(firstBrace, lastBrace + 1);\n    const parsed = JSON.parse(jsonStr);\n    // Check if it has solutions array inside\n    if (parsed.solutions && Array.isArray(parsed.solutions)) {\n      solutions = parsed.solutions;\n    } else {\n      solutions = [parsed];\n    }\n  } else {\n    throw new Error('No JSON found');\n  }\n\n  // Add option numbers if missing\n  solutions = solutions.map((s, i) => ({\n    ...s,\n    option_number: s.option_number || (i + 1)\n  }));\n\n  // Validate we have 3\n  if (!Array.isArray(solutions) || solutions.length === 0) {\n    throw new Error('Empty solutions');\n  }\n\n} catch (e) {\n  solutions = [\n    {\n      option_number: 1,\n      title: 'Predictive Analytics Solution',\n      description: 'Build a predictive model to identify and address the core business problem proactively.',\n      approach: 'Phase 1: Data audit \u2192 Phase 2: Model build \u2192 Phase 3: Deploy',\n      key_deliverables: 'Predictive model, Dashboard, Playbook',\n      best_for: 'Organizations with good data infrastructure',\n      estimated_effort: 'medium',\n      expected_outcome: '20-30% improvement within 3 months'\n    },\n    {\n      option_number: 2,\n      title: 'Data Intelligence Platform',\n      description: 'Create a unified analytics platform delivering real-time actionable insights.',\n      approach: 'Phase 1: Data consolidation \u2192 Phase 2: Analytics layer \u2192 Phase 3: Training',\n      key_deliverables: 'Data platform, Dashboards, Training',\n      best_for: 'Organizations needing better data visibility',\n      estimated_effort: 'high',\n      expected_outcome: 'Unified view of all key business metrics'\n    },\n    {\n      option_number: 3,\n      title: 'Quick Win POC',\n      description: 'Fast 4-week proof of concept demonstrating immediate measurable value.',\n      approach: 'Phase 1: Scoping \u2192 Phase 2: Prototype \u2192 Phase 3: Roadmap',\n      key_deliverables: 'Working prototype, ROI analysis, Roadmap',\n      best_for: 'Organizations wanting to validate before full investment',\n      estimated_effort: 'low',\n      expected_outcome: 'Validated approach with clear ROI projection'\n    }\n  ];\n}\n\nreturn {\n  ...prev,\n  solutions: solutions,\n  status: 'solutions_ready'\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "d73eaa77-710e-4da6-8edb-87bb4369617b",
      "name": "Extract Refined Solution",
      "type": "n8n-nodes-base.code",
      "position": [
        3152,
        112
      ],
      "parameters": {
        "jsCode": "let refinedSolution = {};\nconst prev = $('Knowledge Base Lookup').first().json;\n\ntry {\n  const rawText = $input.first().json\n    ?.content?.[0]?.text || '';\n\n  let cleaned = rawText\n    .replace(/[\\u0000-\\u001F\\u007F-\\u009F]/g, ' ')\n    .replace(/```json/gi, '')\n    .replace(/```/g, '')\n    .trim();\n\n  const firstBrace = cleaned.indexOf('{');\n  const lastBrace = cleaned.lastIndexOf('}');\n\n  if (firstBrace !== -1 && lastBrace !== -1) {\n    refinedSolution = JSON.parse(\n      cleaned.substring(firstBrace, lastBrace + 1)\n    );\n  } else {\n    throw new Error('No JSON found');\n  }\n\n} catch(e) {\n  refinedSolution = {\n    option_number: 1,\n    title: 'Custom Solution Approach',\n    description: prev.body?.own_solution || 'User defined solution',\n    approach: 'Phase 1: Discovery \u2192 Phase 2: Build \u2192 Phase 3: Deploy',\n    key_deliverables: 'Custom solution, Documentation, Training',\n    best_for: 'Tailored to specific client needs',\n    estimated_effort: 'medium',\n    expected_outcome: 'Measurable improvement in identified problem area'\n  };\n}\n\nconst response = {\n  status: \"own_solution_ready\",\n  company_name: prev.body?.company_name || prev.company_name || '',\n  industry: prev.body?.industry || prev.industry || '',\n  decision_maker: prev.body?.decision_maker || prev.decision_maker || '',\n  problem_statement: prev.body?.problem_statement || prev.problem_statement || '',\n  business_impact: prev.body?.business_impact || prev.business_impact || '',\n  technologies: prev.body?.technologies || prev.technologies || [],\n  delivery_type: prev.body?.delivery_type || prev.delivery_type || '',\n  timeline: prev.body?.timeline || prev.timeline || '',\n  budget_range: prev.body?.budget_range || prev.budget_range || '',\n  selected_solution: refinedSolution,\n  solutions: [refinedSolution],\n  research_data: prev.research_data || {},\n  industry_data: prev.industry_data || {},\n  kb_context: prev.kb_context || '',\n  has_kb: prev.has_kb || false\n};\n\nreturn { response: JSON.stringify(response) };"
      },
      "typeVersion": 2
    },
    {
      "id": "a7bdb133-e361-4036-80ce-3a3794bb1afd",
      "name": "Return Solutions to Frontend",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        3616,
        -304
      ],
      "parameters": {
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        },
        "respondWith": "text",
        "responseBody": "=={{ $json.response }}"
      },
      "retryOnFail": true,
      "typeVersion": 1.5
    },
    {
      "id": "417b295e-edca-4a7a-996c-9f53eca30bca",
      "name": "Receive Selected Solution",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -816,
        224
      ],
      "parameters": {
        "path": "tigerpitch-solution",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "9901d78e-7e58-4f19-81be-ba9d450ebd35",
      "name": "Extract Pain Map",
      "type": "n8n-nodes-base.code",
      "position": [
        -240,
        224
      ],
      "parameters": {
        "jsCode": "let painMap = {};\n\ntry {\n  const rawText = $input.first().json\n    ?.content?.[0]?.text || '{}';\n\n  let cleaned = rawText\n    .replace(/```json/gi, '')\n    .replace(/```/g, '')\n    .trim();\n\n  const firstBrace = cleaned.indexOf('{');\n  const lastBrace = cleaned.lastIndexOf('}');\n\n  if (firstBrace !== -1 && lastBrace !== -1) {\n    cleaned = cleaned.substring(firstBrace, lastBrace + 1);\n    painMap = JSON.parse(cleaned);\n  } else {\n    throw new Error('No JSON found');\n  }\n\n  if (!painMap.pain_points) {\n    throw new Error('Invalid pain map structure');\n  }\n\n} catch (e) {\n  const prev = $('Receive Selected Solution').first().json;\n\n  painMap = {\n    pain_points: [\n      {\n        pain: prev.body?.problem_statement || 'Business challenge identified',\n        root_cause: 'Limited visibility into operational and customer intelligence',\n        solution_component: prev.body?.selected_solution?.title || 'AI-driven analytics solution',\n        expected_outcome: 'Improved decision-making and operational efficiency',\n        timeframe: prev.body?.timeline || '3 months'\n      }\n    ],\n    overall_value_statement: 'AI-driven modernization designed to improve business performance.',\n    roi_indicator: 'Expected measurable ROI within 6-12 months'\n  };\n}\n\nconst prev = $('Receive Selected Solution').first().json;\n\nreturn {\n  ...prev,\n  pain_map: painMap\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "a73377a3-18d7-4323-abbf-67265b750156",
      "name": "PDF Formatter",
      "type": "n8n-nodes-base.code",
      "position": [
        640,
        368
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json || {};\nconst rawProposal = data.proposal || {};\n\n// Map all 11 new sections\nconst p = {\n  engagement_title:     rawProposal.engagement_title     || 'AI-Powered Analytics Program',\n  situation_assessment: rawProposal.situation_assessment || 'Not available',\n  root_cause_diagnosis: rawProposal.root_cause_diagnosis || 'Not available',\n  tiger_pov:            rawProposal.tiger_pov            || 'Not available',\n  proposed_solution:    rawProposal.proposed_solution    || 'Not available',\n  pain_solution_map:    rawProposal.pain_solution_map    || 'Not available',\n  tiger_accelerators:   rawProposal.tiger_accelerators   || 'Not available',\n  investment_roi:       rawProposal.investment_roi       || 'Not available',\n  risk_mitigation:      rawProposal.risk_mitigation      || 'Not available',\n  our_team:             rawProposal.our_team             || 'Not available',\n  credentials:          rawProposal.credentials          || 'Not available',\n  next_steps:           rawProposal.next_steps           || 'Not available',\n};\n\nconst company      = data.body?.company_name   || data.company_name   || 'Unknown Company';\nconst decisionMaker= data.body?.decision_maker || data.decision_maker || 'Decision Maker';\nconst industry     = data.body?.industry       || data.industry       || '';\nconst budget       = data.body?.budget_range   || data.budget_range   || '';\nconst timeline     = data.body?.timeline       || data.timeline       || '';\nconst delivery     = data.body?.delivery_type  || data.delivery_type  || '';\nconst hasKB        = data.body?.has_kb         || data.has_kb         || false;\nconst kbIndustry   = data.body?.kb_industry    || data.kb_industry    || '';\n\nconst date = new Date().toLocaleDateString('en-IN', {\n  year: 'numeric', month: 'long', day: 'numeric'\n});\n\n// Safe string converter\nconst safe = (val) => {\n  if (val === null || val === undefined) return 'Not available';\n  if (Array.isArray(val)) return val.join(', ');\n  if (typeof val === 'object') return JSON.stringify(val);\n  return String(val).replace(/\\n/g, ' ');\n};\n\n// Parse || separated items into array\nconst parseItems = (text) => {\n  if (!text || text === 'Not available') return [];\n  return text.split('||').map(s => s.trim()).filter(Boolean);\n};\n\n// Parse root causes (CAUSE 1: title \u2014 desc || CAUSE 2...)\nconst renderRootCauses = (text) => {\n  const items = parseItems(text);\n  if (!items.length) return `<div class=\"section-box\">${safe(text)}</div>`;\n\n  const colors = ['#DC2626','#B45309','#1A3C6E'];\n  const bgColors = ['#FEE2E2','#FEF3C7','#EEF4FB'];\n\n  return items.map((item, i) => {\n    const parts = item.split('\u2014').map(s => s.trim());\n    const title = parts[0].replace(/^CAUSE\\s*\\d+:\\s*/i, '').trim();\n    const desc  = parts[1] || '';\n    const rest  = parts.slice(2).join('\u2014').trim();\n    return `\n    <div style=\"display:flex;gap:14px;padding:14px 16px;background:${bgColors[i]||'#F5F5F5'};border-radius:8px;margin-bottom:10px;border:1px solid ${colors[i]||'#ccc'}20;\">\n      <div style=\"width:28px;height:28px;border-radius:50%;background:${colors[i]||'#888'};color:white;font-weight:700;font-size:12px;display:flex;align-items:center;justify-content:center;flex-shrink:0;\">${i+1}</div>\n      <div>\n        <div style=\"font-weight:700;font-size:13px;color:#1A1A1A;margin-bottom:4px;\">${title}</div>\n        ${desc ? `<div style=\"font-size:13px;color:#555;line-height:1.6;\">${desc}</div>` : ''}\n        ${rest ? `<div style=\"margin-top:6px;display:inline-block;padding:2px 10px;background:${colors[i]||'#888'}20;border-radius:4px;font-size:11px;font-weight:700;color:${colors[i]||'#888'};\">${rest}</div>` : ''}\n      </div>\n    </div>`;\n  }).join('');\n};\n\n// Parse phases (PHASE 1 (Wk X-X): what | Team: who | Outcome: result)\nconst renderPhases = (text) => {\n  const items = parseItems(text);\n  if (!items.length) return `<div class=\"section-box\">${safe(text)}</div>`;\n\n  const phColors = ['#1A3C6E','#E07B2A','#16A34A','#7C3AED'];\n\n  return `\n  <table style=\"width:100%;border-collapse:collapse;font-size:13px;\">\n    <thead>\n      <tr>\n        ${['Phase','Deliverables','Team','Timeline','Outcome'].map(h =>\n          `<th style=\"background:#1A3C6E;color:white;padding:10px 12px;text-align:left;font-size:12px;\">${h}</th>`\n        ).join('')}\n      </tr>\n    </thead>\n    <tbody>\n      ${items.map((item, i) => {\n        const phaseMatch = item.match(/PHASE\\s*(\\d+)[^:]*:\\s*(.*?)(?=\\|Team:|$)/i);\n        const teamMatch  = item.match(/Team:\\s*(.*?)(?=\\|Outcome:|$)/i);\n        const outcomeMatch = item.match(/Outcome:\\s*(.*?)$/i);\n        const weekMatch  = item.match(/\\(Wk[s]?\\s*([\\d\\-]+)\\)/i);\n\n        const phaseNum   = phaseMatch?.[1] || (i+1).toString();\n        const phaseDesc  = phaseMatch?.[2]?.trim() || item;\n        const team       = teamMatch?.[1]?.trim()  || 'Tiger Analytics Team';\n        const outcome    = outcomeMatch?.[1]?.trim()|| '';\n        const weeks      = weekMatch?.[1] ? `Wk ${weekMatch[1]}` : '';\n        const bg         = i % 2 === 0 ? '#F8FAFC' : '#FFFFFF';\n\n        return `\n        <tr style=\"background:${bg};\">\n          <td style=\"padding:11px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;\">\n            <span style=\"width:24px;height:24px;border-radius:50%;background:${phColors[i]||'#888'};color:white;font-weight:700;font-size:11px;display:inline-flex;align-items:center;justify-content:center;margin-right:8px;\">${phaseNum}</span>\n          </td>\n          <td style=\"padding:11px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;font-size:13px;\">${phaseDesc}</td>\n          <td style=\"padding:11px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;font-size:12px;color:#555;\">${team}</td>\n          <td style=\"padding:11px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;\"><span style=\"background:#EEF4FB;color:#1A3C6E;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:600;\">${weeks}</span></td>\n          <td style=\"padding:11px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;font-size:12px;color:#16A34A;font-weight:600;\">${outcome}</td>\n        </tr>`;\n      }).join('')}\n    </tbody>\n  </table>`;\n};\n\n// Parse pain solution map\nconst renderPainMap = (text) => {\n  const items = parseItems(text);\n  if (!items.length) return `<div class=\"section-box\">${safe(text)}</div>`;\n\n  const sevColors = { critical:'#DC2626', high:'#B45309', medium:'#1A3C6E' };\n  const sevBg     = { critical:'#FEE2E2', high:'#FEF3C7', medium:'#EEF4FB' };\n\n  return `\n  <table style=\"width:100%;border-collapse:collapse;font-size:13px;\">\n    <thead>\n      <tr>\n        ${['Pain Point','Severity','Solution','Outcome','By'].map(h =>\n          `<th style=\"background:#1A3C6E;color:white;padding:10px 12px;text-align:left;font-size:12px;\">${h}</th>`\n        ).join('')}\n      </tr>\n    </thead>\n    <tbody>\n      ${items.map((item, i) => {\n        const painMatch     = item.match(/PAIN:\\s*(.*?)(?=\\|SEVERITY:|$)/i);\n        const sevMatch      = item.match(/SEVERITY:\\s*(.*?)(?=\\|ROOT CAUSE:|$)/i);\n        const solMatch      = item.match(/SOLUTION:\\s*(.*?)(?=\\|OUTCOME:|$)/i);\n        const outcomeMatch  = item.match(/OUTCOME:\\s*(.*?)(?=\\|BY:|$)/i);\n        const byMatch       = item.match(/BY:\\s*(.*?)$/i);\n\n        const pain    = painMatch?.[1]?.trim()    || item;\n        const sev     = (sevMatch?.[1]?.trim()    || 'High').toLowerCase();\n        const sol     = solMatch?.[1]?.trim()     || '';\n        const outcome = outcomeMatch?.[1]?.trim() || '';\n        const by      = byMatch?.[1]?.trim()      || '';\n        const bg      = i % 2 === 0 ? '#F8FAFC' : '#FFFFFF';\n        const color   = sevColors[sev] || sevColors.high;\n        const bgSev   = sevBg[sev]    || sevBg.high;\n\n        return `\n        <tr style=\"background:${bg};\">\n          <td style=\"padding:10px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;font-size:13px;\">\n            <span style=\"display:inline-block;padding:2px 7px;border-radius:4px;font-size:10px;font-weight:700;background:${bgSev};color:${color};margin-bottom:4px;\">${sev.toUpperCase()}</span><br>${pain}\n          </td>\n          <td style=\"padding:10px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;\"><span style=\"padding:3px 9px;border-radius:4px;background:${bgSev};color:${color};font-size:11px;font-weight:700;\">${sev.charAt(0).toUpperCase()+sev.slice(1)}</span></td>\n          <td style=\"padding:10px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;font-size:13px;\">${sol}</td>\n          <td style=\"padding:10px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;font-size:12px;color:#16A34A;font-weight:600;\">${outcome}</td>\n          <td style=\"padding:10px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;\"><span style=\"background:#EEF4FB;color:#1A3C6E;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:600;\">${by}</span></td>\n        </tr>`;\n      }).join('')}\n    </tbody>\n  </table>`;\n};\n\n// Parse accelerators\nconst renderAccelerators = (text) => {\n  const items = parseItems(text);\n  if (!items.length) return `<div class=\"section-box\">${safe(text)}</div>`;\n\n  return `<div style=\"display:grid;grid-template-columns:repeat(3,1fr);gap:12px;\">\n    ${items.map(item => {\n      const nameMatch  = item.match(/NAME:\\s*(.*?)(?=\\|WHAT:|$)/i);\n      const whatMatch  = item.match(/WHAT:\\s*(.*?)(?=\\|SAVES:|$)/i);\n      const savesMatch = item.match(/SAVES:\\s*(.*?)$/i);\n      const name  = nameMatch?.[1]?.trim()  || item;\n      const what  = whatMatch?.[1]?.trim()  || '';\n      const saves = savesMatch?.[1]?.trim() || '';\n      return `\n      <div style=\"border:1.5px solid #E2E8F0;border-radius:10px;padding:14px;\">\n        <div style=\"font-weight:700;font-size:13px;color:#1A3C6E;margin-bottom:6px;\">\u26a1 ${name}</div>\n        <div style=\"font-size:12px;color:#555;line-height:1.5;margin-bottom:8px;\">${what}</div>\n        ${saves ? `<span style=\"background:#DCFCE7;color:#16A34A;padding:3px 10px;border-radius:20px;font-size:11px;font-weight:700;\">Saves ${saves}</span>` : ''}\n      </div>`;\n    }).join('')}\n  </div>`;\n};\n\n// Parse investment ROI\nconst renderROI = (text) => {\n  if (!text || text === 'Not available') return `<div class=\"section-box\">${safe(text)}</div>`;\n\n  const parts = text.split('||').map(s => s.trim());\n  const phasePart = parts[0] || '';\n  const roiPart   = parts[1] || '';\n\n  const phaseRows = phasePart.split('|').map(s => s.trim()).filter(Boolean);\n  const roiItems  = roiPart.split('|').map(s => s.trim()).filter(Boolean);\n\n  return `\n  <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:16px;\">\n    <div>\n      <div style=\"font-size:12px;font-weight:700;color:#1A3C6E;margin-bottom:10px;text-transform:uppercase;letter-spacing:.5px;\">Phase Investment</div>\n      <table style=\"width:100%;border-collapse:collapse;font-size:13px;\">\n        ${phaseRows.map((row, i) => {\n          const [label, val] = row.split(':').map(s => s.trim());\n          const isTotal = label?.toLowerCase().includes('total');\n          return `<tr style=\"background:${isTotal ? '#EEF4FB' : i%2===0?'#F8FAFC':'#FFF'};\">\n            <td style=\"padding:9px 12px;border-bottom:1px solid #E2E8F0;${isTotal?'font-weight:700;color:#1A3C6E;':''}\">${label||''}</td>\n            <td style=\"padding:9px 12px;border-bottom:1px solid #E2E8F0;text-align:right;font-weight:700;${isTotal?'color:#1A3C6E;':''}\">${val||''}</td>\n          </tr>`;\n        }).join('')}\n      </table>\n    </div>\n    <div>\n      <div style=\"font-size:12px;font-weight:700;color:#1A3C6E;margin-bottom:10px;text-transform:uppercase;letter-spacing:.5px;\">Return on Investment</div>\n      ${roiItems.map(item => {\n        const [label, val] = item.split(':').map(s => s.trim());\n        const isPayback = label?.toLowerCase().includes('payback');\n        const isRisk    = label?.toLowerCase().includes('risk') || label?.toLowerCase().includes('loss');\n        const isROI     = label?.toLowerCase().includes('roi');\n        const bg    = isPayback ? '#1A3C6E' : isRisk ? '#FEE2E2' : '#DCFCE7';\n        const color = isPayback ? 'white'   : isRisk ? '#DC2626' : '#16A34A';\n        const textColor = isPayback ? 'rgba(255,255,255,.8)' : '#555';\n        return `\n        <div style=\"display:flex;justify-content:space-between;align-items:center;padding:9px 14px;border-radius:7px;background:${bg};margin-bottom:6px;\">\n          <span style=\"font-size:13px;color:${textColor};\">${label||''}</span>\n          <span style=\"font-weight:700;font-size:14px;color:${color};\">${val||''}</span>\n        </div>`;\n      }).join('')}\n    </div>\n  </div>`;\n};\n\n// Parse risk mitigation\nconst renderRisks = (text) => {\n  const items = parseItems(text);\n  if (!items.length) return `<div class=\"section-box\">${safe(text)}</div>`;\n\n  const likColors = { high:'#DC2626', medium:'#B45309', low:'#16A34A' };\n  const likBg     = { high:'#FEE2E2', medium:'#FEF3C7', low:'#DCFCE7' };\n\n  return `\n  <table style=\"width:100%;border-collapse:collapse;font-size:13px;\">\n    <thead>\n      <tr>\n        ${['Risk','Likelihood','Tiger Mitigation','Protection'].map(h =>\n          `<th style=\"background:#F8FAFC;color:#1A1A1A;padding:10px 12px;text-align:left;font-size:12px;font-weight:700;border-bottom:2px solid #E2E8F0;\">${h}</th>`\n        ).join('')}\n      </tr>\n    </thead>\n    <tbody>\n      ${items.map((item, i) => {\n        const riskMatch  = item.match(/RISK:\\s*(.*?)(?=\\|LIKELIHOOD:|$)/i);\n        const likeMatch  = item.match(/LIKELIHOOD:\\s*(.*?)(?=\\|MITIGATION:|$)/i);\n        const mitMatch   = item.match(/MITIGATION:\\s*(.*?)(?=\\|PROTECTION:|$)/i);\n        const protMatch  = item.match(/PROTECTION:\\s*(.*?)$/i);\n\n        const risk  = riskMatch?.[1]?.trim()  || item;\n        const like  = (likeMatch?.[1]?.trim() || 'Medium').toLowerCase();\n        const mit   = mitMatch?.[1]?.trim()   || '';\n        const prot  = protMatch?.[1]?.trim()  || '';\n        const color = likColors[like] || likColors.medium;\n        const bg    = likBg[like]    || likBg.medium;\n        const rowBg = i % 2 === 0 ? '#F8FAFC' : '#FFFFFF';\n\n        return `\n        <tr style=\"background:${rowBg};\">\n          <td style=\"padding:10px 12px;border-bottom:1px solid #E2E8F0;font-weight:600;vertical-align:top;\">${risk}</td>\n          <td style=\"padding:10px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;\"><span style=\"padding:3px 9px;border-radius:4px;background:${bg};color:${color};font-size:11px;font-weight:700;\">${like.charAt(0).toUpperCase()+like.slice(1)}</span></td>\n          <td style=\"padding:10px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;font-size:13px;color:#555;\">${mit}</td>\n          <td style=\"padding:10px 12px;border-bottom:1px solid #E2E8F0;vertical-align:top;font-size:12px;color:#16A34A;font-weight:600;\">${prot}</td>\n        </tr>`;\n      }).join('')}\n    </tbody>\n  </table>`;\n};\n\n// Parse team\nconst renderTeam = (text) => {\n  const items = parseItems(text);\n  if (!items.length) return `<div class=\"section-box\">${safe(text)}</div>`;\n\n  const avatarColors = ['#1A3C6E','#E07B2A','#16A34A','#7C3AED'];\n\n  return `<div style=\"display:grid;grid-template-columns:repeat(4,1fr);gap:12px;\">\n    ${items.map((item, i) => {\n      const roleMatch  = item.match(/ROLE:\\s*(.*?)(?=\\|EXP:|$)/i);\n      const expMatch   = item.match(/EXP:\\s*(.*?)(?=\\|SKILL:|$)/i);\n      const skillMatch = item.match(/SKILL:\\s*(.*?)$/i);\n      const role  = roleMatch?.[1]?.trim()  || item;\n      const exp   = expMatch?.[1]?.trim()   || '';\n      const skill = skillMatch?.[1]?.trim() || '';\n      const initials = role.split(' ').map(w=>w[0]).join('').substring(0,2).toUpperCase();\n      const color = avatarColors[i] || '#1A3C6E';\n      return `\n      <div style=\"border:1px solid #E2E8F0;border-radius:10px;padding:14px;text-align:center;\">\n        <div style=\"width:44px;height:44px;border-radius:50%;background:${color};color:white;font-weight:700;font-size:14px;display:flex;align-items:center;justify-content:center;margin:0 auto 10px;\">${initials}</div>\n        <div style=\"font-weight:700;font-size:12px;color:#1A3C6E;margin-bottom:4px;\">${role}</div>\n        <div style=\"font-size:11px;color:#555;margin-bottom:8px;line-height:1.4;\">${exp}</div>\n        ${skill ? `<span style=\"background:#EEF4FB;color:#1A3C6E;padding:2px 8px;border-radius:4px;font-size:10px;font-weight:600;\">${skill}</span>` : ''}\n      </div>`;\n    }).join('')}\n  </div>`;\n};\n\n// Parse credentials\nconst renderCredentials = (text) => {\n  const items = parseItems(text);\n  if (!items.length) return `<div class=\"section-box\">${safe(text)}</div>`;\n\n  const credColors = ['#FEF3C7','#EEF4FB','#EDE9FE','#DCFCE7'];\n  const credIcons  = ['\ud83c\udfc6','\u2601\ufe0f','\ud83d\udcca','\ud83c\udf0f'];\n\n  return `<div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px;\">\n    ${items.map((item, i) => {\n      const awardMatch = item.match(/(?:AWARD|CREDENTIAL):\\s*(.*?)(?=\\|RELEVANCE:|$)/i);\n      const relMatch   = item.match(/RELEVANCE:\\s*(.*?)$/i);\n      const award = awardMatch?.[1]?.trim() || item;\n      const rel   = relMatch?.[1]?.trim()   || '';\n      return `\n      <div style=\"background:${credColors[i]||'#F5F5F5'};border-radius:9px;padding:14px;\">\n        <div style=\"font-size:20px;margin-bottom:6px;\">${credIcons[i]||'\u2b50'}</div>\n        <div style=\"font-weight:700;font-size:13px;margin-bottom:4px;\">${award}</div>\n        <div style=\"font-size:12px;color:#555;line-height:1.4;\">${rel}</div>\n      </div>`;\n    }).join('')}\n  </div>`;\n};\n\n// Parse next steps timeline\nconst renderNextSteps = (text) => {\n  const items = parseItems(text);\n  if (!items.length) return `<div class=\"section-box\">${safe(text)}</div>`;\n\n  return `<div style=\"display:flex;flex-direction:column;gap:0;\">\n    ${items.map((item, i) => {\n      const whenMatch  = item.match(/WHEN:\\s*(.*?)(?=\\|(?:TITLE|ACTION):|$)/i);\n      const titleMatch = item.match(/(?:TITLE|ACTION):\\s*(.*?)(?=\\|DESC(?:RIPTION)?:|$)/i);\n      const descMatch  = item.match(/DESC(?:RIPTION)?:\\s*(.*?)$/i);\n      const when  = whenMatch?.[1]?.trim()  || '';\n      const title = titleMatch?.[1]?.trim() || item;\n      const desc  = descMatch?.[1]?.trim()  || '';\n      const isLast = i === items.length - 1;\n      return `\n      <div style=\"display:flex;gap:0;\">\n        <div style=\"display:flex;flex-direction:column;align-items:center;width:48px;flex-shrink:0;\">\n          <div style=\"width:36px;height:36px;border-radius:50%;background:#1A3C6E;color:white;font-weight:700;font-size:13px;display:flex;align-items:center;justify-content:center;\">${i+1}</div>\n          ${!isLast ? `<div style=\"width:2px;background:#E2E8F0;flex:1;margin:4px 0;min-height:20px;\"></div>` : ''}\n        </div>\n        <div style=\"padding:0 0 ${isLast?'0':'24px'} 16px;flex:1;\">\n          ${when ? `<div style=\"font-size:11px;font-weight:700;color:#E07B2A;margin-bottom:3px;\">${when}</div>` : ''}\n          <div style=\"font-weight:700;font-size:14px;color:#1A1A1A;margin-bottom:4px;\">${title}</div>\n          ${desc ? `<div style=\"font-size:13px;color:#555;line-height:1.5;\">${desc}</div>` : ''}\n        </div>\n      </div>`;\n    }).join('')}\n  </div>`;\n};\n\n// Build complete HTML\nconst html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>Proposal \u2014 ${safe(company)}</title>\n<style>\n* { margin:0; padding:0; box-sizing:border-box; }\nbody { font-family:'Segoe UI',Arial,sans-serif; color:#1A1A1A; background:#F0F4FA; }\n.page { max-width:960px; margin:0 auto; background:white; }\n.header { background:linear-gradient(135deg,#0F2544,#1A3C6E); color:white; padding:40px 48px; position:relative; overflow:hidden; }\n.header::before { content:''; position:absolute; top:-60px; right:-60px; width:200px; height:200px; border-radius:50%; background:rgba(255,255,255,.05); }\n.header-tag { display:inline-block; background:rgba(255,255,255,.15); color:#F0C080; padding:4px 14px; border-radius:20px; font-size:12px; font-weight:700; margin-bottom:14px; }\n.header h1 { font-size:28px; margin-bottom:6px; }\n.header-sub { font-size:14px; opacity:.8; margin-bottom:20px; }\n.header-divider { width:60px; height:3px; background:#E07B2A; border-radius:2px; margin-bottom:16px; }\n.header-meta { display:flex; gap:24px; flex-wrap:wrap; font-size:13px; opacity:.85; }\n.header-meta strong { color:#F0C080; }\n.stats { display:grid; grid-template-columns:repeat(4,1fr); background:white; border-bottom:1px solid #E2E8F0; }\n.stat { padding:20px; text-align:center; border-right:1px solid #E2E8F0; }\n.stat:last-child { border-right:none; }\n.stat-icon { font-size:20px; margin-bottom:6px; }\n.stat-num { font-size:26px; font-weight:800; margin-bottom:3px; }\n.stat-label { font-size:11px; color:#64748B; }\n.content { padding:32px 48px; }\n.section-card { background:white; border-radius:12px; border:1px solid #E2E8F0; margin-bottom:20px; overflow:hidden; box-shadow:0 1px 3px rgba(0,0,0,.06); }\n.section-header { padding:14px 20px; border-bottom:1px solid #E2E8F0; background:#F8FAFC; display:flex; align-items:center; gap:10px; }\n.section-num { width:26px; height:26px; border-radius:50%; background:#1A3C6E; color:white; font-size:11px; font-weight:700; display:flex; align-items:center; justify-content:center; flex-shrink:0; }\n.section-title { font-size:14px; font-weight:700; color:#1A3C6E; }\n.section-body { padding:20px; }\n.section-box { font-size:14px; line-height:1.85; color:#1A1A1A; background:#EEF4FB; padding:16px 18px; border-radius:8px; border-left:4px solid #1A3C6E; }\n.pov-box { background:linear-gradient(135deg,#0F2544,#1A3C6E); border-radius:10px; padding:20px; color:white; }\n.pov-label { font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:1px; color:#F0C080; margin-bottom:8px; }\n.pov-text { font-size:14px; line-height:1.8; opacity:.95; }\n.kb-badge { display:inline-block; background:#EEF4FB; color:#1A3C6E; padding:3px 12px; border-radius:20px; font-size:11px; font-weight:700; margin-left:8px; }\n.footer { background:#0F2544; color:white; padding:20px 48px; display:flex; justify-content:space-between; font-size:12px; opacity:.9; }\n</style>\n</head>\n<body>\n<div class=\"page\">\n\n  <!-- HEADER -->\n  <div class=\"header\">\n    <div class=\"header-tag\">\ud83d\udc2f Tiger Analytics \u00b7 Confidential Proposal</div>\n    <h1>${safe(p.engagement_title)}</h1>\n    <div class=\"header-divider\"></div>\n    <div class=\"header-sub\">Prepared for ${safe(company)} \u00b7 ${safe(decisionMaker)} \u00b7 ${industry}</div>\n    <div class=\"header-meta\">\n      <span><strong>Date:</strong> ${date}</span>\n      <span><strong>Budget:</strong> ${safe(budget)}</span>\n      <span><strong>Timeline:</strong> ${safe(timeline)}</span>\n      <span><strong>Delivery:</strong> ${safe(delivery)}</span>\n      ${hasKB ? `<span><strong>KB:</strong> ${kbIndustry} Knowledge Base Active \u2713</span>` : ''}\n    </div>\n  </div>\n\n  <!-- STAT CARDS -->\n  <div class=\"stats\">\n    <div class=\"stat\"><div class=\"stat-icon\">\ud83d\udcb8</div><div class=\"stat-num\" style=\"color:#DC2626;\">$12M</div><div class=\"stat-label\">Revenue at Risk</div></div>\n    <div class=\"stat\"><div class=\"stat-icon\">\ud83d\udcc9</div><div class=\"stat-num\" style=\"color:#E07B2A;\">25-30%</div><div class=\"stat-label\">Target Improvement</div></div>\n    <div class=\"stat\"><div class=\"stat-icon\">\u26a1</div><div class=\"stat-num\" style=\"color:#16A34A;\">4-6 wks</div><div class=\"stat-label\">Payback Period</div></div>\n    <div class=\"stat\"><div class=\"stat-icon\">\ud83d\udcc5</div><div class=\"stat-num\" style=\"color:#1A3C6E;\">${safe(timeline)}</div><div class=\"stat-label\">Engagement Timeline</div></div>\n  </div>\n\n  <div class=\"content\">\n\n    <!-- 1. SITUATION -->\n    <div class=\"section-card\">\n      <div class=\"section-header\"><div class=\"section-num\">1</div><div class=\"section-title\">Situation Assessment</div></div>\n      <div class=\"section-body\"><div class=\"section-box\">${safe(p.situation_assessment)}</div></div>\n    </div>\n\n    <!-- 2. ROOT CAUSE -->\n    <div class=\"section-card\">\n      <div class=\"section-header\"><div class=\"section-num\">2</div><div class=\"section-title\">Root Cause Diagnosis</div></div>\n      <div class=\"section-body\">${renderRootCauses(p.root_cause_diagnosis)}</div>\n    </div>\n\n    <!-- 3. TIGER POV -->\n    <div class=\"section-card\">\n      <div class=\"section-header\"><div class=\"section-num\">3</div><div class=\"section-title\">Tiger Analytics Point of View</div></div>\n      <div class=\"section-body\">\n        <div class=\"pov-box\">\n          <div class=\"pov-label\">\ud83d\udc2f Expert Perspective</div>\n          <div class=\"pov-text\">${safe(p.tiger_pov)}</div>\n        </div>\n      </div>\n    </div>\n\n    <!-- 4. SOLUTION -->\n    <div class=\"section-card\">\n      <div class=\"section-header\"><div class=\"section-num\">4</div><div class=\"section-title\">Proposed Solution</div></div>\n      <div class=\"section-body\">${renderPhases(p.proposed_solution)}</div>\n    </div>\n\n    <!-- 5. PAIN MAP -->\n    <div class=\"section-card\">\n      <div class=\"section-header\"><div class=\"section-num\">5</div><div class=\"section-title\">Pain Point \u2192 Solution Mapping</div></div>\n      <div class=\"section-body\">${renderPainMap(p.pain_solution_map)}</div>\n    </div>\n\n    <!-- 6. ACCELERATORS -->\n    <div class=\"section-card\">\n      <div class=\"section-header\"><div class=\"section-num\">6</div><div class=\"section-title\">Tiger Analytics Accelerators</div></div>\n      <div class=\"section-body\">${renderAccelerators(p.tiger_accelerators)}</div>\n    </div>\n\n    <!-- 7. INVESTMENT -->\n    <div class=\"section-card\">\n      <div class=\"section-header\"><div class=\"section-num\">7</div><div class=\"section-title\">Investment & ROI</div></div>\n      <div class=\"section-body\">${renderROI(p.investment_roi)}</div>\n    </div>\n\n    <!-- 8. RISK -->\n    <div class=\"section-card\">\n      <div class=\"section-header\"><div class=\"section-num\">8</div><div class=\"section-title\">Risk Mitigation</div></div>\n      <div class=\"section-body\">${renderRisks(p.risk_mitigation)}</div>\n    </div>\n\n    <!-- 9. TEAM -->\n    <div class=\"section-card\">\n      <div class=\"section-header\"><div class=\"section-num\">9</div><div class=\"section-title\">Our Team for This Engagement</div></div>\n      <div class=\"section-body\">${renderTeam(p.our_team)}</div>\n    </div>\n\n    <!-- 10. CREDENTIALS -->\n    <div class=\"section-card\">\n      <div class=\"section-header\"><div class=\"section-num\">10</div><div class=\"section-title\">Tiger Analytics Credentials</div></div>\n      <div class=\"section-body\">${renderCredentials(p.credentials)}</div>\n    </div>\n\n    <!-- 11. NEXT STEPS -->\n    <div class=\"section-card\">\n      <div class=\"section-header\"><div class=\"section-num\">11</div><div class=\"section-title\">Next Steps</div></div>\n      <div class=\"section-body\">${renderNextSteps(p.next_steps)}</div>\n    </div>\n\n  </div>\n\n  <!-- FOOTER -->\n  <div class=\"footer\">\n    <span>\ud83d\udc2f TigerPitch \u00b7 Tiger Analytics \u00b7 Confidential \u00b7 Not for External Distribution</span>\n    <span>Generated: ${date} ${hasKB ? `\u00b7 ${kbIndustry} KB Active` : ''}</span>\n  </div>\n\n</div>\n</body>\n</html>`;\n\nreturn [{\n  json: {\n    ...data,\n    html_proposal: html,\n    status: 'completed',\n    generated_at: data.generated_at || new Date().toISOString(),\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "c0158c40-2d0f-4bbf-9dce-1d9b6da75ca7",
      "name": "Return Final Proposal to Frontend",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1056,
        368
      ],
      "parameters": {
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        },
        "respondWith": "text",
        "responseBody": "={{ $json.response }}"
      },
      "retryOnFail": true,
      "typeVersion": 1.5
    },
    {
      "id": "97e81d34-03dd-43b9-bb69-106becee85fb",
      "name": "Industry Agent",
      "type": "@n8n/n8n-nodes-langchain.anthropic",
      "position": [
        1008,
        -384
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gemini-2.5-flash",
          "cachedResultName": "gemini-2.5-flash"
        },
        "options": {
          "system": "You are a senior industry strategy analyst working for Tiger Analytics.  Your responsibility is to analyze industry-specific business challenges and identify AI, analytics, and digital transformation opportunities relevant to enterprise consulting proposals.  Guidelines: - Focus on enterprise business value - Provide practical and industry-relevant insights - Emphasize AI, analytics, automation, operational efficiency, customer experience, and decision intelligence - Tailor insights based on the decision maker role - Be concise, strategic, and professional - Never use markdown - Never explain reasoning - Return ONLY valid JSON"
        },
        "messages": {
          "values": [
            {
              "content": "=Analyze the following business and industry context.\n\nINDUSTRY:\n{{ $json.body.industry }}\n\nPROBLEM STATEMENT:\n{{ $json.body.problem_statement }}\n\nBUSINESS IMPACT:\n{{ $json.body.business_impact }}\n\nDECISION MAKER:\n{{ $json.body.decision_maker }}\n\nCOMPANY RESEARCH:\n{{ JSON.stringify($json.research_data) }}\n\nReturn JSON in this exact structure:\n\n{\n  \"industry_trends\": \"\",\n  \"common_root_causes\": \"\",\n  \"benchmark_data\": \"\",\n  \"decision_maker_priorities\": \"\",\n  \"ai_opportunities\": \"\",\n  \"competitive_context\": \"\"\n}"
            }
          ]
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1
    },
    {
      "id": "b0f712d2-0bbb-4606-b0de-69c863d37a89",
      "name": "Research Agent",
      "type": "@n8n/n8n-nodes-langchain.anthropic",
      "position": [
        384,
        -384
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gemini-2.5-flash",
          "cachedResultName": "gemini-2.5-flash"
        },
        "options": {
          "system": "You are a senior business research analyst working for Tiger Analytics, a data and AI consulting company.  Your responsibility is to analyze company and industry information and generate structured business intelligence for AI consulting proposals.  Guidelines: - Always provide factual, business-oriented insights - Focus on AI, analytics, automation, customer experience, operational efficiency, and digital transformation opportunities - If website content is unavailable, use general industry and company knowledge - Be concise, specific, and professional - Never return markdown - Never explain your reasoning - Return ONLY valid JSON"
        },
        "messages": {
          "values": [
            {
              "content": "=Analyze this company:\n\nDATA SOURCE STATUS:\n{{ $json.fetch_status }}\n\nCompany:\n{{ $json.body.company_name }}\n\nIndustry:\n{{ $json.body.industry }}\n\nWebsite Content:\n{{ $json.website_content }}\n\nReturn JSON with:\n- company_overview\n- products_services\n- recent_initiatives\n- technology_mentioned\n- visible_pain_points"
            }
          ]
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1
    },
    {
      "id": "5ab34193-b904-4514-9dc0-920b6ccb9cfc",
      "name": "Proposal Drafter agent",
      "type": "@n8n/n8n-nodes-langchain.anthropic",
      "position": [
        48,
        384
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gemini-2.5-flash",
          "cachedResultName": "gemini-2.5-flash"
        },
        "options": {
          "system": "You are a senior proposal strategist at Tiger Analytics, a global leader in AI and analytics consulting trusted by Fortune 1000 companies.\n\nTiger Analytics facts to reference:\n- 4000+ team of technologists and consultants\n- Partnerships with AWS, Google Cloud, Microsoft, Databricks\n- Recognized by Forrester, Gartner, Everest Group, ISG\n- 2025 Databricks Enterprise AI Partner of the Year\n- Microsoft Partner of the Year finalist 2025\n- Accelerators: TigerML, Tiger Blueprints, Tiger DataSphere, Tiger AI Hub\n- Industries: CPG, Retail, BFS, Insurance, Manufacturing, Life Sciences, Healthcare\n\nYour job is to write proposals that sound like they were written by a 10-year industry veteran \u2014 not a chatbot.\n\nRules:\n- Always use the actual company name \u2014 never [Client Name]\n- Always use industry-specific KPIs and terminology from the knowledge base\n- Every number must be specific and grounded in the research provided\n- Tailor every section to the decision maker role\n- Never use markdown formatting inside JSON values\n- Never use ** bold or bullet points with * or -\n- Write plain prose strings only\n- Never include real newlines inside JSON string values\n- Return ONLY valid JSON \u2014 no backticks, no explanation",
          "maxTokens": 4096
        },
        "messages": {
          "values": [
            {
              "content": "==Generate a complete McKinsey-level enterprise consulting proposal for Tiger Analytics.\n\nCLIENT DETAILS:\nCompany: {{ $json.body?.company_name || $json.company_name }}\nIndustry: {{ $json.body?.industry || $json.industry }}\nDecision Maker: {{ $json.body?.decision_maker || $json.decision_maker }}\nProblem Statement: {{ $json.body?.problem_statement || $json.problem_statement }}\nBusiness Impact: {{ $json.body?.business_impact || $json.business_impact }}\nBudget Range: {{ $json.body?.budget_range || $json.budget_range }}\nTimeline: {{ $json.body?.timeline || $json.timeline }}\nDelivery Type: {{ $json.body?.delivery_type || $json.delivery_type }}\nTechnologies: {{ JSON.stringify($json.body?.technologies || $json.technologies || []) }}\n\nCOMPANY RESEARCH:\n{{ JSON.stringify($json.body?.research_data || $json.research_data || {}) }}\n\nINDUSTRY CONTEXT:\n{{ JSON.stringify($json.body?.industry_data || $json.industry_data || {}) }}\n\nSELECTED SOLUTION:\n{{ JSON.stringify($json.body?.selected_solution || $json.selected_solution || {}) }}\n\nPAIN POINT MAPPING:\n{{ JSON.stringify($json.pain_map || {}) }}\n\n{{ $json.body?.kb_context || $json.kb_context || '' }}\n\nCRITICAL INSTRUCTIONS:\n- Use actual company name throughout \u2014 NEVER use [Client Name] or placeholders\n- Use industry-specific terminology from the KB above\n- Reference at least 3 KPIs by name with specific numbers\n- Every number must be specific \u2014 never say \"significant improvement\"\n- Tailor tone completely for the decision maker role\n- Never use markdown, never use ** for bold, never use bullet points\n- Write all values as plain prose strings only\n- Never include newlines inside JSON string values\n- Return ONLY valid JSON \u2014 no backticks, no labels, no explanation\n\nReturn ONLY this exact JSON. Keep each field under 200 words. Be concise:\n{\n\"engagement_title\": \"3-5 word professional engagement name like McKinsey uses. Example: Customer Retention Intelligence Program, Credit Risk Modernization Initiative, Digital Claims Transformation Program. Make it specific to the company and problem.\",\n  \"situation_assessment\": \"2-3 sentences max with specific numbers\",\n  \"root_cause_diagnosis\": \"3 causes separated by || format: CAUSE 1: title \u2014 desc || CAUSE 2: ...\",\n  \"tiger_pov\": \"2-3 sentences max\",\n  \"proposed_solution\": \"4 phases separated by || format: PHASE 1 (Wk 1-4): what | Team: who | Outcome: result || PHASE 2...\",\n  \"pain_solution_map\": \"3 pains separated by || format: PAIN: x | SEVERITY: y | SOLUTION: z | OUTCOME: metric || ...\",\n  \"tiger_accelerators\": \"3 accelerators separated by || format: NAME: x | SAVES: y weeks || ...\",\n  \"investment_roi\": \"PHASE 1: $X | PHASE 2: $X | TOTAL: $X || ROI: X% | PAYBACK: X weeks | DAILY COST: $X\",\n  \"risk_mitigation\": \"3 risks separated by || format: RISK: x | LIKELIHOOD: y | MITIGATION: z || ...\",\n  \"our_team\": \"4 members separated by || format: ROLE: x | EXP: y | SKILL: z || ...\",\n  \"credentials\": \"3 credentials separated by || format: AWARD: x | RELEVANCE: y || ...\",\n  \"next_steps\": \"4 steps separated by || format: STEP 1 | WHEN: x | ACTION: y || ...\"\n}"
            }
          ]
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1
    },
    {
      "id": "1d69e131-0253-4917-b82a-ee99a7b545ea",
      "name": "Knowledge Base Lookup",
      "type": "n8n-nodes-base.code",
      "position": [
        1776,
        -352
      ],
      "parameters": {
        "jsCode": "const KB = {\n  \"Insurance\": {\n    terms: \"lapse rate, persistency ratio, premium, policyholder, underwriting, actuarial, reinsurance, endorsement, claims frequency, loss ratio\",\n    kpis: \"loss ratio, combined ratio, lapse rate, persistency rate, claims settlement ratio, NPS, solvency margin\",\n    regulations: \"IRDAI guidelines, IFRS17, Solvency II, Insurance Act 1938\",\n    pain_points: \"policy lapse, claims fraud, underwriting inaccuracy, mis-selling, slow claims settlement, agent productivity\",\n    tech: \"Guidewire, Duck Creek, Majesco, SAS, Salesforce Financial Services Cloud\",\n    solution_patterns: \"lapse prediction model, claims fraud detection, underwriting automation, agent performance analytics, customer lifetime value modeling\"\n  },\n  \"Banking & Financial Services\": {\n    terms: \"NPA, CASA ratio, AUM, credit underwriting, KYC, AML, delinquency, write-off, cross-sell, CLTV\",\n    kpis: \"Capital Adequacy Ratio, Net Interest Margin, ROE, NPA ratio, CLTV, CASA ratio, cost-to-income ratio\",\n    regulations: \"RBI guidelines, Basel III, SEBI regulations, PCI DSS, FEMA, IND AS\",\n    pain_points: \"credit risk, AML compliance, customer attrition, cross-sell failure, fraud detection, regulatory reporting\",\n    tech: \"Temenos, Finastra, FIS, Murex, Bloomberg Terminal, Salesforce\",\n    solution_patterns: \"credit risk scoring, AML transaction monitoring, customer churn prediction, cross-sell propensity model, fraud detection\"\n  },\n  \"Healthcare\": {\n    terms: \"readmission, ALOS, revenue cycle, EMR, prior authorization, claim denial, ICD codes, patient no-show, care gap\",\n    kpis: \"bed occupancy rate, ALOS, claim denial rate, readmission rate, patient satisfaction score, net collection rate\",\n    regulations: \"HIPAA, HL7, FHIR, NABH, CMS guidelines, HITECH Act\",\n    pain_points: \"high readmission rates, revenue cycle inefficiency, staff burnout, patient no-shows, billing errors, care coordination gaps\",\n    tech: \"Epic, Cerner, Meditech, Allscripts, Salesforce Health Cloud, AWS HealthLake\",\n    solution_patterns: \"readmission prediction, revenue cycle optimization, patient no-show prediction, care gap identification, clinical decision support\"\n  },\n  \"Retail & E-Commerce\": {\n    terms: \"basket size, SKU rationalization, GMV, AOV, CAC, LTV, cart abandonment, planogram, shrinkage, RFM\",\n    kpis: \"GMV, AOV, CAC, LTV, cart abandonment rate, inventory turnover, NPS, repeat purchase rate\",\n    regulations: \"CCPA, GDPR, PCI DSS, Consumer Protection Act\",\n    pain_points: \"cart abandonment, inventory stockouts, high CAC, low repeat purchase, returns fraud, demand forecasting\",\n    tech: \"Salesforce Commerce, SAP, Oracle Retail, Shopify, Snowflake, Databricks\",\n    solution_patterns: \"churn prediction, demand forecasting, recommendation engine, price optimization, inventory optimization, RFM segmentation\"\n  },\n  \"Telecom\": {\n    terms: \"churn, ARPU, MNP, prepaid/postpaid, network latency, CX transformation, subscriber, MVNO\",\n    kpis: \"ARPU, churn rate, NPS, network uptime, customer acquisition cost, CSAT, revenue per user\",\n    regulations: \"TRAI guidelines, GDPR, spectrum regulations, DOT compliance\",\n    pain_points: \"subscriber churn, ARPU decline, network quality issues, customer service costs, SIM fraud, roaming analytics\",\n    tech: \"Amdocs, Oracle Communications, Salesforce, Hadoop, Spark, Kafka\",\n    solution_patterns: \"churn prediction, network anomaly detection, ARPU uplift model, customer segmentation, next-best-offer engine\"\n  },\n  \"Manufacturing\": {\n    terms: \"OEE, yield rate, predictive maintenance, downtime, six sigma, OTIF, BOM, MRP, shop floor\",\n    kpis: \"OEE, yield rate, downtime percentage, inventory turnover, defect rate, OTIF, scrap rate\",\n    regulations: \"ISO 9001, ISO 14001, OSHA, ISO 45001\",\n    pain_points: \"unplanned downtime, quality defects, supply chain disruption, high inventory costs, energy waste\",\n    tech: \"SAP ERP, Siemens MindSphere, PTC ThingWorx, OSIsoft PI, Rockwell Automation\",\n    solution_patterns: \"predictive maintenance, quality defect prediction, demand forecasting, energy optimization, supply chain analytics\"\n  },\n  \"Media & Entertainment\": {\n    terms: \"DAU, MAU, content churn, subscriber acquisition, ad revenue, engagement rate, content ROI, SVOD\",\n    kpis: \"DAU/MAU ratio, subscriber growth, content completion rate, ad revenue per user, churn rate\",\n    regulations: \"GDPR, COPPA, FCC guidelines, TRAI OTT regulations\",\n    pain_points: \"subscriber churn, content ROI measurement, ad revenue decline, piracy, recommendation quality\",\n    tech: \"AWS Media, Brightcove, Conviva, Nielsen, Salesforce, Snowflake\",\n    solution_patterns: \"content recommendation engine, subscriber churn prediction, content performance analytics, ad targeting optimization\"\n  },\n  \"Energy & Utilities\": {\n    terms: \"load forecasting, outage, grid stability, renewable integration, tariff optimization, SAIDI, SAIFI\",\n    kpis: \"SAIDI, SAIFI, system efficiency, outage duration, renewable percentage, cost per kWh\",\n    regulations: \"CERC, SERC, ISO 50001, environmental compliance, IEX regulations\",\n    pain_points: \"grid instability, outage management, demand forecasting errors, energy theft detection, asset aging\",\n    tech: \"OSIsoft PI, GE Grid Solutions, Schneider EcoStruxure, SAP IS-U, Azure IoT\",\n    solution_patterns: \"demand forecasting, outage prediction, energy theft detection, asset health monitoring, renewable integration analytics\"\n  }\n};\n\n// Get industry from input\nconst prev = $input.first().json;\nconst industry = prev.industry || \n                 prev.body?.industry || '';\n\n// Find matching KB \u2014 try exact match first then partial\nlet kbEntry = KB[industry];\n\nif (!kbEntry) {\n  const key = Object.keys(KB).find(k =>\n    industry.toLowerCase().includes(k.toLowerCase()) ||\n    k.toLowerCase().includes(industry.toLowerCase())\n  );\n  kbEntry = key ? KB[key] : null;\n}\n\n// Build KB context string for Gemini prompt\nconst kbContext = kbEntry ? \n  `INDUSTRY KNOWLEDGE BASE \u2014 Use this to make the proposal expert-level:\n  \n  Industry Terminology (use these exact terms): ${kbEntry.terms}\n  Key KPIs to reference: ${kbEntry.kpis}\n  Relevant Regulations: ${kbEntry.regulations}\n  Common Pain Points: ${kbEntry.pain_points}\n  Relevant Technology Stack: ${kbEntry.tech}\n  Proven Solution Patterns: ${kbEntry.solution_patterns}\n  \n  CRITICAL: Use the terminology above throughout the proposal.\n  Never use generic terms when specific ones exist.\n  Always reference at least 2-3 KPIs by name.\n  Mention regulations where relevant.`\n  : \n  'Use general AI and analytics industry knowledge for this proposal.';\n\nreturn {\n  ...prev,\n  kb_context: kbContext,\n  kb_industry: kbEntry ? industry : 'general',\n  has_kb: !!kbEntry\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "7027f065-8f9d-4498-bc47-e40598537d42",
      "name": "Pain Point Agent",
      "type": "@n8n/n8n-nodes-langchain.anthropic",
      "position": [
        -592,
        224
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gemini-2.5-flash",
          "cachedResultName": "gemini-2.5-flash"
        },
        "options": {
          "system": "You are a senior AI solutions consultant working for Tiger Analytics.  Your responsibility is to connect business pain points with practical AI, analytics, and automation solutions.  Guidelines: - Identify meaningful business pain points from the provided context - Map each pain point to a specific solution capability - Focus on measurable business outcomes and ROI - Tailor language to the decision maker role - Use enterprise consulting language - Keep recommendations realistic and actionable - Be concise and professional - Never use markdown - Never explain reasoning - Return ONLY valid JSON - Never wrap JSON inside ```json"
        },
        "messages": {
          "values": [
            {
              "content": "=Analyze the client business context and map the selected solution to the client\u2019s pain points.\n\nSELECTED SOLUTION:\n{{ JSON.stringify($json.body.selected_solution) }}\n\nCOMPANY RESEARCH:\n{{ JSON.stringify($json.body.research_data) }}\n\nINDUSTRY CONTEXT:\n{{ JSON.stringify($json.body.industry_data) }}\n\nCLIENT PROBLEM:\n{{ $json.body.problem_statement }}\n\nBUSINESS IMPACT:\n{{ $json.body.business_impact }}\n\nDECISION MAKER:\n{{ $json.body.decision_maker }}\n\nRequirements:\n- Identify 3 to 4 major business pain points\n- Explain the root cause behind each pain point\n- Map each pain point to a specific solution capability\n- Include measurable business outcomes\n- Include realistic implementation timelines\n- Focus on AI, analytics, automation, customer intelligence, and operational efficiency\n- Tailor business language to the decision maker role\n\nReturn ONLY valid JSON in this exact structure:\n\n{\n  \"pain_points\": [\n    {\n      \"pain\": \"\",\n      \"root_cause\": \"\",\n      \"solution_component\": \"\",\n      \"expected_outcome\": \"\",\n      \"timeframe\": \"\"\n    }\n  ],\n  \"overall_value_statement\": \"\",\n  \"roi_indicator\": \"\"\n}"
            }
          ]
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1
    },
    {
      "id": "fa58bae7-1c58-4fbf-a8b5-0e5d49bcb43c",
      "name": "Solution Agent",
      "type": "@n8n/n8n-nodes-langchain.anthropic",
      "position": [
        2880,
        -352
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gemini-2.5-flash",
          "cachedResultName": "gemini-2.5-flash"
        },
        "options": {
          "system": "=You are a senior AI consulting strategist at Tiger Analytics.\n\nGenerate EXACTLY 3 completely different solution approaches.\nEach solution must use a fundamentally different strategy.\n\nGenerate solutions specific to {{ $json.body.company_name }}\nin {{ $json.body.industry }}.Reference the company research provided.\nUse industry KB terminology.\nNever generate generic solutions.\nAlways mention specific technologies \nfrom the preferred stack.\"\n\nRules:\n- Return EXACTLY 3 solutions in a JSON array\n- Each solution must be meaningfully different from the others\n- Never return fewer than 3 solutions\n- Never use markdown\n- Never explain reasoning  \n- Return ONLY valid JSON array\n- Never wrap in backticks"
        },
        "messages": {
          "values": [
            {
              "content": "=Generate exactly 3 distinct solution approaches for the following client scenario.\n\nCOMPANY RESEARCH:\n{{ JSON.stringify($json.research_data) }}\n\nINDUSTRY CONTEXT:\n{{ JSON.stringify($json.industry_data) }}\n\nCLIENT PROBLEM:\n{{ $json.body.problem_statement }}\n\nBUSINESS IMPACT:\n{{ $json.body.business_impact }}\n\nBUDGET RANGE:\n{{ $json.body.budget_range }}\n\nTIMELINE:\n{{ $json.body.timeline }}\n\nDECISION MAKER:\n{{ $json.body.decision_maker }}\n\nPREFERRED TECHNOLOGIES:\n{{ JSON.stringify($json.body.technologies) }}\n\nRequirements:\n- Each solution must use a different strategy\n- Solutions must be realistic for the timeline and budget\n- Focus on AI, analytics, automation, and data solutions\n- Keep solutions actionable and enterprise-friendly\n-IMPORTANT: You MUST generate EXACTLY 3 solutions. Not 1. Not 2. EXACTLY 3.\nReturn ONLY valid JSON array in this exact structure:\n\n[\n  {\n    \"option_number\": 1,\n    \"title\": \"\",\n    \"description\": \"\",\n    \"approach\": \"\",\n    \"key_deliverables\": \"\",\n    \"best_for\": \"\",\n    \"estimated_effort\": \"\",\n    \"expected_outcome\": \"\"\n  }\n]"
            }
          ]
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1
    },
    {
      "id": "497ac56c-8101-46b9-ae38-d412b3755a4e",
      "name": "Build Response",
      "type": "n8n-nodes-base.code",
      "position": [
        3296,
        -352
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nconst response = {\n  status: \"solutions_ready\",\n  company_name: data.body?.company_name || data.company_name || '',\n  industry: data.body?.industry || data.industry || '',\n  decision_maker: data.body?.decision_maker || data.decision_maker || '',\n  problem_statement: data.body?.problem_statement || data.problem_statement || '',\n  business_impact: data.body?.business_impact || data.business_impact || '',\n  technologies: data.body?.technologies || data.technologies || [],\n  delivery_type: data.body?.delivery_type || data.delivery_type || '',\n  timeline: data.body?.timeline || data.timeline || '',\n  budget_range: data.body?.budget_range || data.budget_range || '',\n  solutions: data.solutions || [],\n  research_data: data.research_data || {},\n  industry_data: data.industry_data || {},\n  kb_context: data.kb_context || '',\n  has_kb: data.has_kb || false\n};\n\nreturn { response: JSON.stringify(response) };"
      },
      "typeVersion": 2
    },
    {
      "id": "273465ba-882c-414e-844a-c77f25d5c56b",
      "name": "Build Final Response",
      "type": "n8n-nodes-base.code",
      "position": [
        832,
        368
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nconst response = {\n  status: \"completed\",\n  company_name: data.body?.company_name || data.company_name || '',\n  decision_maker: data.body?.decision_maker || data.decision_maker || '',\n  industry: data.body?.industry || data.industry || '',\n  problem_statement: data.body?.problem_statement || data.problem_statement || '',\n  budget_range: data.body?.budget_range || data.budget_range || '',\n  timeline: data.body?.timeline || data.timeline || '',\n  generated_at: data.generated_at || new Date().toISOString(),\n  has_kb: data.body?.has_kb || data.has_kb || false,\n  kb_industry: data.body?.kb_industry || data.kb_industry || '',\n  engagement_title: data.proposal?.engagement_title || \n                    data.proposal?.situation_assessment?.split('.')[0] || \n                    'AI-Powered Analytics Engagement',\n  proposal: data.proposal || {},\n};\n\nreturn { response: JSON.stringify(response) };"
      },
      "typeVersion": 2
    },
    {
      "id": "70625dc5-4e5f-4c45-851d-45255af500ba",
      "name": "AI Guardrail",
      "type": "n8n-nodes-base.code",
      "position": [
        -576,
        -400
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nconst text =\n  JSON.stringify(data).toLowerCase();\n\nconst blockedPatterns = [\n\n  'ignore previous instructions',\n\n  'system prompt',\n\n  'developer mode',\n\n  'jailbreak',\n\n  'reveal prompt',\n\n  'bypass security',\n\n  'act as',\n\n  'pretend to be',\n\n  'show hidden instructions',\n\n  'ignore all previous'\n\n];\n\nconst detected =\n  blockedPatterns.find(p =>\n    text.includes(p)\n  );\n\nif (detected) {\n\n  throw new Error(\n    `Unsafe prompt detected: ${detected}`\n  );\n\n}\n\nreturn [\n  {\n    json: data\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "f1e4bcbc-0ccc-4428-bf20-4cd8471df1e4",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1696,
        -672
      ],
      "parameters": {
        "color": 2,
        "width": 592,
        "height": 1488,
        "content": "## \ud83d\ude80 InstaPitch \u2014 Multi-Agent Consulting Proposal Automator\n\nThis workflow transforms any client URL into a consulting-grade proposal in under a minute using a 6-agent AI pipeline.\n\n### \ud83d\udd25 Why This Workflow Exist\nAt the core of InstaPitch is a multi-agent orchestration system where each agent has a focused role:\n- Eliminates manual company research by fetching live website data via Jina AI\n- Injects domain expertise through a built-in Knowledge Base across 8 industry verticals\n- Generates 3 tailored solution strategies \u2014 human picks one before drafting begins\n- AI Guardrail node validates output quality before returning to frontend\n- Human-in-the-Loop editing supported before final export\n\n\u26a1 Instead of starting from scratch every time, InstaPitch brings institutional knowledge into every proposal automatically.\n\n### \ud83d\udd0d What It Does\nThis workflow:\n- Accepts a client URL via webhook from the frontend\n- Fetches live website content using Jina AI\n- Runs 5 specialized AI agents in sequence (Research \u2192 Industry \u2192 Pain Point \u2192 Solution \u2192 Proposal Drafter)\n- Looks up the built-in Knowledge Base for industry-specific benchmarks\n- Returns 3 solution options for human selection\n- Drafts an 11-section consulting proposal based on chosen solution\n- Applies AI Guardrails before returning the final HTML/PDF proposal\n\n### \u2699\ufe0f How It Works (High-Level)\n- User submits client URL from frontend\n- Jina AI fetches and cleans live website content\n- Research Agent extracts company intelligence\n- Industry Agent pulls sector benchmarks and context\n- Pain Point Agent maps business challenges\n- Knowledge Base injects vertical-specific expertise (Banking, Insurance, Healthcare, Retail & more)\n- Solution Agent generates 3 tailored strategies\n- Human selects preferred solution via frontend\n- Proposal Drafter Agent writes the full 11-section proposal\n- AI Guardrail validates output\n- Final proposal returned to frontend as HTML/PDF\n\n### \ud83e\udde0 Key Capabilities\n- 6-agent AI pipeline (Claude-powered via Anthropic)\n- Built-in Knowledge Base across 8 industry verticals (no external DB needed)\n- Human-in-the-Loop design \u2014 human approves solutions before drafting\n- AI Guardrail for output quality control\n- Dual webhook architecture (solutions + final proposal)\n- Frontend-ready JSON responses\n\n### \u26a0\ufe0f Requirements\n- Anthropic (Claude) API key \u2014 powers all 5 AI agents\n- Jina AI API key \u2014 for live website fetching\n- Any webhook-capable frontend (Lovable, React, etc.)\n- n8n Cloud or self-hosted n8n instance\n\n### \ud83d\udca1 Example Use Cases\n- Pre-sales proposal automation for consulting firms\n- Client pitch preparation\n- RFP response generation\n- Sales enablement tooling\n- Business development automation\n\n### \ud83d\udee0\ufe0f Tech Stack\n- n8n (Multi-Agent Workflow Orchestration)\n- Anthropic Claude (AI Agents)\n- Jina AI (Web Research)\n- Lovable (React Frontend)\n- Google Gemini 2.0 Flash (Solution Refinement)"
      },
      "typeVersion": 1
    },
    {
      "id": "98cb3cb3-ae10-418b-80bd-c8f45687ab8b",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -976,
        -672
      ],
      "parameters": {
        "color": 7,
        "width": 592,
        "height": 480,
        "content": "### \ud83d\udce5 INPUT + SECURITY (Prompt Injection)\n\n\n**Receive Inputs (Webhook)**\nPOST endpoint. Accepts: company_url, company_name, industry, decision_maker, problem_statement, solution_preference, own_solution, technologies, delivery_type, timeline, budget_range.\n\n**AI Guardrail (Code)**\nScans all inputs for prompt injection patterns \u2014 jailbreak, \"ignore previous instructions\", \"act as\", \"system prompt\", \"developer mode\". Throws error immediately if detected. Safe inputs pass through unchanged to the next node."
      },
      "typeVersion": 1
    },
    {
      "id": "4d818198-5a1a-42e0-b504-a4827620fa6b",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -320,
        -672
      ],
      "parameters": {
        "color": 2,
        "width": 592,
        "height": 480,
        "content": "### \ud83c\udf10 LIVE CLIENT RESEARCH\n\n\n**Fetch Company Website (HTTP Request)**\nCalls Jina AI to convert client website to clean markdown text.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "fa52a9af-5a8e-4665-8d4e-060e793e4dd9",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        320,
        -672
      ],
      "parameters": {
        "width": 592,
        "height": 480,
        "content": "### \ud83e\udde0 RESEARCH AGENT\n\n\n**Research Agent (Anthropic)**\nAnalyzes website content to extract structured company intelligence.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "fb705e2d-b570-4d63-adf7-0ec30d98e9be",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        960,
        -672
      ],
      "parameters": {
        "color": 2,
        "width": 592,
        "height": 480,
        "content": "### \ud83d\udcca INDUSTRY AGENT\n\n\n**Industry Agent (Anthropic)**\nAnalyzes industry context tailored to the decision maker role. Extracts: industry_trends, common_root_causes, benchmark_data, decision_maker_priorities, ai_opportunities, competitive_context.\n\n**Extract Industry Data (Code)**\nSame parse pattern as Extract Research Data. Appends industry_data object to the pipeline payload."
      },
      "typeVersion": 1
    },
    {
      "id": "0852ff20-809b-4770-a64f-6328e14debc6",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        -672
      ],
      "parameters": {
        "color": 4,
        "width": 592,
        "height": 480,
        "content": "### \ud83d\udcda KNOWLEDGE BASE LOOKUP\n\n\nMatches selected industry to built-in KB:\n\n\ud83c\udfe6 Banking & FS \u2014 NPA, CASA ratio, Basel III, Temenos\n\ud83c\udfe5 Insurance \u2014 lapse rate, persistency ratio, IRDAI, Guidewire\n\ud83d\udc8a Healthcare \u2014 ALOS, HIPAA, Epic, readmission rate\n\ud83d\uded2 Retail \u2014 GMV, AOV, CAC, RFM, Snowflake\n\ud83d\udce1 Telecom \u2014 ARPU, TRAI, Amdocs, churn rate\n\ud83c\udfed Manufacturing \u2014 OEE, ISO 9001, SAP ERP\n\ud83c\udfac Media \u2014 DAU/MAU, SVOD, content ROI\n\u26a1 Energy \u2014 SAIDI, CERC, OSIsoft PI\n\nOutputs: kb_context (terminology string), kb_industry, has_kb flag. All injected into the Proposal Drafter prompt to generate expert-level industry output."
      },
      "typeVersion": 1
    },
    {
      "id": "631f47e2-c1a0-411f-ac27-0656a156983f",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2208,
        -672
      ],
      "parameters": {
        "color": 6,
        "width": 592,
        "height": 480,
        "content": "### \ud83d\udd00 SOLUTION ROUTER\n\n\nChecks solution_preference field from webhook input:\n\n\u2705 TRUE = \"ai_suggest\"\n\u2192 Routes to Solution Agent\n\u2192 Generates 3 AI-powered tailored solutions\n\n\u274c FALSE = \"own_idea\"\n\u2192 Routes to Solution Refiner - Gemini\n\u2192 Professionally refines user's own solution idea\n\nBoth paths eventually merge at Return Solutions to Frontend node."
      },
      "typeVersion": 1
    },
    {
      "id": "9e18f6b2-42b8-4611-8ca1-54c32ae4cc1f",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2832,
        -672
      ],
      "parameters": {
        "color": 2,
        "width": 592,
        "height": 480,
        "content": "### \ud83d\udca1 PATH A \u2014 AI Suggest (3 Solutions)\n\n\n**Solution Agent (Anthropic)**\nGenerates EXACTLY 3 distinct, tailored solution approaches using company research + industry KB + preferred tech stack. Each solution has: option_number, title, description, approach, key_deliverables, best_for, estimated_effort, expected_outcome.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "b1fbf329-6049-42fc-8cfb-8712b579fdde",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2832,
        -144
      ],
      "parameters": {
        "color": 4,
        "width": 592,
        "height": 432,
        "content": "### \u270f\ufe0f PATH B \u2014 Own Idea Refiner\n\n\n**Solution Refiner (HTTP Request \u2192 Gemini)**\nCalls Gemini 2.0 Flash directly via HTTP. Takes user's rough solution idea and professionally restructures it \u2014 adding phases, deliverables, and measurable outcomes \u2014 while fully preserving the user's core idea.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "8aecb27d-1e7f-4727-a14f-24a1b1056cf6",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -640,
        -16
      ],
      "parameters": {
        "color": 2,
        "width": 592,
        "height": 528,
        "content": "### \ud83c\udfaf PAIN MAPPING\n\n\n**Pain Point Agent (Anthropic)**\nMaps each identified client pain point to the selected solution component. For each pain outputs: PAIN name, SEVERITY (Critical/High/Medium), ROOT CAUSE, SOLUTION component , OUTCOME metric, delivery week.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a8c09587-8197-4402-bed3-e9374925a8b7",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        -16
      ],
      "parameters": {
        "color": 3,
        "width": 592,
        "height": 528,
        "content": "### \u270d\ufe0f PROPOSAL DRAFTER AGENT\n\n\nCore proposal generation engine. Uses ALL accumulated context: company research, industry KB, pain map, selected solution, kb_context. Generates 11 sections in structured JSON using || separators for tabular data. Max 4096 tokens.\n\n11 Sections generated:\n\n1. engagement_title      \n2. situation_assessment  \n3. root_cause_diagnosis  \n4. tiger_pov           \n5. proposed_solution   \n6. pain_solution_map\n7. investment_roi\n8. risk_mitigation\n9. our_team\n10. credentials\n11. next_steps"
      },
      "typeVersion": 1
    },
    {
      "id": "60d0e683-329e-4ac0-a578-fc15824794ef",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        608,
        -16
      ],
      "parameters": {
        "width": 656,
        "height": 528,
        "content": "### \ud83d\udcc4 PARSE + FORMAT + RETURN\n\n\n**PDF Formatter (Code)**\nGenerates full branded proposal with: gradient header, KPI stat cards, 11 section cards, visual tables, phase timelines, ROI panels, team cards, credentials, next steps.\n\n**Return Final Proposal to Frontend**\nSends completed 11-section proposal back to frontend as text."
      },
      "typeVersion": 1
    },
    {
      "id": "dfe6a9c3-04d0-4f31-9d8e-8baa291e66d6",
      "name": "Proposal Drafter",
      "type": "n8n-nodes-base.code",
      "position": [
        352,
        384
      ],
      "parameters": {
        "jsCode": "let proposal = {};\nconst prev = $input.first().json;\n\ntry {\n  let rawText = $input.first().json\n    ?.content?.[0]?.text || '';\n\n  if (!rawText) throw new Error('Empty text');\n\n  // Remove control characters\n  rawText = rawText\n    .replace(/[\\u0000-\\u001F\\u007F-\\u009F]/g, ' ')\n    .replace(/```json/gi, '')\n    .replace(/```/g, '')\n    .trim();\n\n  const firstBrace = rawText.indexOf('{');\n  const lastBrace = rawText.lastIndexOf('}');\n\n  if (firstBrace === -1 || lastBrace === -1) {\n    throw new Error('No JSON found');\n  }\n\n  const parsed = JSON.parse(\n    rawText.substring(firstBrace, lastBrace + 1)\n  );\n\n  proposal = {\n    engagement_title:      parsed.engagement_title      || 'AI-Powered Analytics Program',\n    situation_assessment:  parsed.situation_assessment  || 'Not available',\n    root_cause_diagnosis:  parsed.root_cause_diagnosis  || 'Not available',\n    tiger_pov:             parsed.tiger_pov             || 'Not available',\n    proposed_solution:     parsed.proposed_solution     || 'Not available',\n    pain_solution_map:     parsed.pain_solution_map     || 'Not available',\n    tiger_accelerators:    parsed.tiger_accelerators    || 'Not available',\n    investment_roi:        parsed.investment_roi        || 'Not available',\n    risk_mitigation:       parsed.risk_mitigation       || 'Not available',\n    our_team:              parsed.our_team              || 'Not available',\n    credentials:           parsed.credentials           || 'Not available',\n    next_steps:            parsed.next_steps            || 'Not available',\n  };\n\n} catch (e) {\n\n  // Regex fallback \u2014 extract each field\n  const rawText = $input.first().json\n    ?.content?.[0]?.text || '';\n\n  const extract = (key) => {\n    const keyIndex = rawText.indexOf(`\"${key}\"`);\n    if (keyIndex === -1) return 'Not available';\n    const colonIndex = rawText.indexOf(':', keyIndex);\n    if (colonIndex === -1) return 'Not available';\n    const openQuote = rawText.indexOf('\"', colonIndex);\n    if (openQuote === -1) return 'Not available';\n    let i = openQuote + 1;\n    let value = '';\n    while (i < rawText.length) {\n      const char = rawText[i];\n      if (char === '\\\\') {\n        i++;\n        const e = rawText[i];\n        if (e === 'n') value += ' ';\n        else if (e === '\"') value += '\"';\n        else if (e === '\\\\') value += '\\\\';\n        else value += e;\n      } else if (char === '\"') {\n        break;\n      } else {\n        value += char;\n      }\n      i++;\n    }\n    return value.trim() || 'Not available';\n  };\n\n  proposal = {\n    engagement_title:      extract('engagement_title') || 'AI-Powered Analytics Program',\n    situation_assessment:  extract('situation_assessment'),\n    root_cause_diagnosis:  extract('root_cause_diagnosis'),\n    tiger_pov:             extract('tiger_pov'),\n    proposed_solution:     extract('proposed_solution'),\n    pain_solution_map:     extract('pain_solution_map'),\n    tiger_accelerators:    extract('tiger_accelerators'),\n    investment_roi:        extract('investment_roi'),\n    risk_mitigation:       extract('risk_mitigation'),\n    our_team:              extract('our_team'),\n    credentials:           extract('credentials'),\n    next_steps:            extract('next_steps'),\n  };\n}\n\nreturn {\n  ...prev,\n  proposal: proposal,\n  generated_at: new Date().toISOString(),\n  retry_count: prev.retry_count || 0\n};"
      },
      "typeVersion": 2
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "8e8855df-c964-45e5-8dd2-7e7654cb15ca",
  "connections": {
    "AI Guardrail": {
      "main": [
        [
          {
            "node": "Fetch Company Website",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PDF Formatter": {
      "main": [
        [
          {
            "node": "Build Final Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Response": {
      "main": [
        [
          {
            "node": "Return Solutions to Frontend",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Industry Agent": {
      "main": [
        [
          {
            "node": "Extract Industry Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Research Agent": {
      "main": [
        [
          {
            "node": "Extract Research Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Solution Agent": {
      "main": [
        [
          {
            "node": "Extract Solutions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Solution Router": {
      "main": [
        [
          {
            "node": "Solution Agent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Solution Refiner - Gemini",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Pain Map": {
      "main": [
        [
          {
            "node": "Proposal Drafter agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pain Point Agent": {
      "main": [
        [
          {
            "node": "Extract Pain Map",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Proposal Drafter": {
      "main": [
        [
          {
            "node": "PDF Formatter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Solutions": {
      "main": [
        [
          {
            "node": "Build Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Final Response": {
      "main": [
        [
          {
            "node": "Return Final Proposal to Frontend",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Industry Data": {
      "main": [
        [
          {
            "node": "Knowledge Base Lookup",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Research Data": {
      "main": [
        [
          {
            "node": "Industry Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Company Website": {
      "main": [
        [
          {
            "node": "Website Content Handler",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Knowledge Base Lookup": {
      "main": [
        [
          {
            "node": "Solution Router",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Proposal Drafter agent": {
      "main": [
        [
          {
            "node": "Proposal Drafter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Website Content Handler": {
      "main": [
        [
          {
            "node": "Research Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Refined Solution": {
      "main": [
        [
          {
            "node": "Return Solutions to Frontend",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive Selected Solution": {
      "main": [
        [
          {
            "node": "Pain Point Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Solution Refiner - Gemini": {
      "main": [
        [
          {
            "node": "Extract Refined Solution",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TigerPitch - Receive Inputs": {
      "main": [
        [
          {
            "node": "AI Guardrail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}