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

/* ── Language & Translations ─────────────────────────────────────────── */
const LANG = (document.documentElement.lang || 'en').split('-')[0];
const STRINGS = {
  en: {
    eyebrow: 'Indonesia Market Intelligence · Ideoworks',
    headline: 'Know your Indonesia\nposition before\nyou commit.',
    subhead: '35 global brands. Most lost market position within 18 months.\nThe difference between them was not budget. It was entry intelligence.',
    cta: 'Run My Indonesia Analysis',
    submitBtn: 'Get My Indonesia Market Assessment',
    creds: ['Jakarta-based. Operating since 2010. Not consulting from Singapore.', 'Every score benchmarked against campaigns this team has run in Indonesia.', 'Channel, KOL, and platform costs from live Indonesia market data.'],
    statLabels: ['Market Size','Reference Set','Turnaround'],
    statUnits: ['Consumers','Brands Mapped','Setup'],
    scopeEyebrow: '',
    scopeTitle: 'Six dimensions.',
    scopeEm: 'Each one is a specific entry failure mode.',
    whoEyebrow: '· Who We Are',
    whoTitle: 'A Jakarta integrated marketing agency ',
    whoTitleEm: 'global brands have trusted since 2010.',
    trustedBy: 'Global brands we have taken into Indonesia',
    trustStat: '9 global brands · 8 industries · 15+ countries',
    recognizedBy: 'Recognized by',
    upgradeStripPreview: 'This is your URL preview. Complete your details to get the full market entry assessment: typically 15 to 25 points sharper, plus your buyer personas, GTM sequence, and budget framework.',
    upgradeStripVerified: 'One step away. Add the optional inputs to complete your market entry assessment: typically 5 to 12 points sharper, with buyer personas, GTM sequence, and budget breakdown unlocked.',
    confidenceLabel: ['Initial Score','Refined Score','Full Score','Full Score'],
    dataInputsLabel: 'DATA INPUTS',
    dataInputDots: ['URL','Email','Country','Socials','Budget','Category'],
    lockedNeedsInput: 'needs your inputs',
    lockedPersona: '2 buyer personas identified · locked',
    lockedGtm: 'Entry window narrow for your category · locked',
    lockedBudget: 'Budget variance high · locked',
    bridgeH2High: 'Your {score}/100 means there is a real entry to plan here. The full assessment shows exactly how we would structure it.',
    bridgeH2Mid: 'Your {score}/100 is the URL view. Complete your details for the full campaign picture.',
    bridgeH2Low: 'Your {score}/100 has gaps to close before entry succeeds. The full assessment shows which to fix first and what it costs.',
    bridgePersonaVisible: 'Your 2 highest-probability buyers in Indonesia are Tier-{N} urban professionals aged {a} to {b} with',
    bridgeGtmVisible: 'Recommended entry path: Jakarta first',
    bridgeBudgetVisible: 'Minimum viable monthly spend for your category:',
    bridgeLocked: 'Unlocks with your full assessment',
    bridgeCta: 'Get my full assessment →',
    bridgeDelivery: ['Your Indonesia Market Entry Assessment', 'Built by the team that executes it', 'In your inbox within 90 seconds'],
    bridgeTicker: [
      '4 brands mapped today · Last: Korean SaaS · Score 71',
      '4 brands mapped today · Last: UK fintech · Score 64',
      '5 brands mapped today · Last: German fashion · Score 78',
      '5 brands mapped today · Last: Japanese hospitality · Score 69',
      '5 brands mapped today · Last: Singapore B2B SaaS · Score 73',
    ],
    toastVerified: 'Category added. Score updated. +{delta} points.',
    toastComplete: 'Score locked. Your assessment is heading to your inbox.',
    toastSkip: 'Your assessment is heading to your inbox now.',
    stickyScoreStrong: 'Your {score}/100. Assessment ready.',
    stickyScoreSub: 'Where do we send it?',
    stickyScoreBtn: 'Send →',
    formEyebrow: 'Your Assessment',
    formTitle: 'Your Indonesia Market Entry Assessment.',
    formDoneTitle: 'Your Market Entry Assessment is on its way.',
    fName: 'Full Name', fNamePh: 'Your name',
    fCompany: 'Company Name', fCompanyPh: 'Acme Global Inc.',
    fEmail: 'Work Email', fEmailPh: 'jane@acme.com',
    fPhone: 'Phone', fPhonePh: '+1 555 000 0000',
    fWebsite: 'Website URL', fWebsitePh: 'https://yourwebsite.com',
    fWebsiteHelper: 'We scan this to build your assessment. The more complete your site, the sharper the output.',
    fCountry: 'Where is your brand based?',
    fBudget: 'Monthly Budget',
    fService: 'Services of Interest',
    fLinkedin: 'LinkedIn Company Page', fLinkedinPh: 'https://linkedin.com/company/…',
    fMeta: 'Meta / Instagram Page', fMetaPh: 'https://instagram.com/yourbrand',
    fTikTok: 'TikTok Profile', fTikTokPh: 'https://tiktok.com/@yourbrand',
    optional: 'optional',
    selectCountry: 'Select country', selectRange: 'Select range',
    freeNote: 'Free. No sales call unless you ask for one.',
    privacyNote: 'Used only to prepare and deliver your Indonesia Market Entry Assessment.',
    procTitle: 'Building your market entry assessment',
    procDesc: 'Mapping your Indonesia opportunity. This takes about 60 seconds.',
    procSteps: [
      'Reading your website and digital presence',
      'Benchmarking your brand against Indonesia market expectations',
      'Mapping your Indonesia opportunity by city tier',
      'Identifying active competitors in your category',
      'Building your GTM plan and budget framework',
    ],
    successTitle: 'Brief sent',
    successDesc: 'Your Indonesia Market Entry Assessment is on its way to',
    successSpam: 'Check spam or promotions if you do not see it within 90 seconds.',
    successBook: 'Book a free campaign call →',
    successAnother: 'Map another brand',
    step1Title:'Submit', step2Title:'Build', step3Title:'Receive',
    stickyStrong: 'See where your brand stands.',
    stickySub: '90-second diagnostic. No pitch.',
    stickyBtn: 'Start',
    whoLede: 'Ideoworks is a marketing agency based in Jakarta, operating in Indonesia since 2010. This team has executed campaigns for HSBC, GoPro, Mayo Clinic, Park Hyatt, and Goodyear across fintech, healthcare, hospitality, consumer brands, and B2B services. Every score this tool produces is benchmarked against campaigns this team has run in Indonesia, at real channel costs, against real competitors.',
    proofLabels: ['Years operating in Indonesia', 'Campaigns executed', 'Best ROAS on record'],
    heroUrlPh: 'yourbrand.com',
    heroUrlBtn: '→',
    heroUrlHelper: 'Scored against campaigns we have actually run here · No commitment required',
    heroUrlError: 'Could not reach that domain. Try with https:// or check the URL.',
    heroUrlCrawlBlock: 'We could not crawl this domain directly. Here is how brands in your category typically perform in Indonesia. Get the full assessment for the complete picture.',
    heroLocked: 'Persona Mapping · GTM Strategy · Budget',
    heroLockedSub: 'Locked. Get the full assessment by email.',
    heroLockedCta: 'Get my full assessment →',
    step1Cta: 'Get my Indonesia market assessment →',
    step2Head: 'Your assessment is being built. Help us make it sharper.',
    step2Sub: 'Optional. Skip if you would rather receive the standard assessment.',
    step2PhoneTag: 'optional',
    step2Btn: 'Personalise my assessment →',
    step2Skip: 'Send me the standard assessment',
    wizardCatQ: 'What is your brand category?',
    wizardCountryQ: 'Where is your brand based?',
    wizardBudgetQ: 'What is your monthly marketing budget?',
    wizardEmailQ: 'Where do we send your Indonesia Market Entry Assessment?',
    wizardEmailSub: 'Built by the team that executes Indonesia campaigns every week. Here is what lands in your inbox:',
    wizardEmailBullets: [
      'Your brand scored across 6 Indonesia-specific dimensions. Each gap ranked by what it costs you at entry.',
      '2-3 buyer personas built for your exact category, city tier, and price point. Not extrapolated from APAC averages.',
      'A 90-day Indonesia entry sequence: city order, channel priority, KOL tier, budget allocation.',
      'Three budget tiers at real Indonesia market rates. What minimum viable entry, competitive launch, and aggressive capture actually cost in your category right now.',
    ],
    wizardSocialsQ: 'Make your report sharper.',
    wizardSocialsNote: 'Optional. Each profile we scan adds more specific personas, competitors, and GTM depth.',
    wizardSocialsBtn: 'Add to my report →',
    wizardContinue: 'Continue →',
    wizardSkip: 'Skip',
    wizardSend: 'Send my assessment →',
    wizardDoneTitle: 'Your Market Entry Assessment is on its way.',
    wizardBudgets: [['Under $10K','Testing the market'],['$10K – $30K','Competitive entry'],['$30K – $70K','Serious market play'],['$70K+','Category leadership']],
    scopeCards: [
      ['Brand Readiness', 'How your name, identity, and pricing signal to Indonesian consumers in your category. What reads premium in Seoul reads differently in Surabaya. This score identifies the gap before your first media spend.'],
      ['Opportunity Score', 'Category penetration and growth velocity by city tier. Entry timing in Indonesia is category-specific. A six-month delay in a fast-moving segment carries a compounding cost in first-mover position.'],
      ['Persona Mapping', 'Two to three buyer profiles built from Indonesian income data, platform behavior, and purchase triggers specific to your category. Not extrapolated from APAC averages. Specific to city tier and price point.'],
      ['Competitive Analysis', 'Which brands currently hold real market grip in your Indonesia category. Local incumbents are consistently underestimated by global brands entering without local intelligence. This score maps the terrain before you step onto it.'],
      ['GTM Strategy', 'A 90-day entry sequence covering city order, channel priority, KOL tier, and budget allocation for your category and competitive set. Jakarta\'s TikTok Shop operates differently from Surabaya\'s SaaS partner channel. This plan reflects that.'],
      ['Budget Framework', 'Three spend tiers calibrated to current Indonesia market rates. Agency fees, CPMs, and KOL costs here bear no relationship to global benchmarks. These numbers come from campaigns run in the last 90 days.'],
    ],
  },
  ko: {
    eyebrow: '인도네시아 시장 인텔리전스 / Ideoworks',
    headline: '인도네시아\n브랜드 감사.\n한눈에 확인.',
    subhead: '귀사 브랜드의 인도네시아 시장 위치를 정확히 파악하세요.',
    cta: '감사 시작',
    submitBtn: '인도네시아 브랜드 분석 시작',
    creds: ['자카르타 현지 팀', '카테고리별 규제 및 라이선스 준비도 점수화', '인도네시아 채널 및 파트너십 비용 벤치마크'],
    statLabels: ['시장 규모','분석 기준','처리 시간'],
    statUnits: ['소비자','분석된 브랜드','설정'],
    scopeEyebrow: '',
    scopeTitle: '여섯 가지 차원.',
    scopeEm: '인도네시아에 한 달러를 쓰기 전에 각각이 중요합니다.',
    whoEyebrow: '· Ideoworks 소개',
    whoTitle: '2010년부터 ',
    whoTitleEm: '글로벌 브랜드가 신뢰해온 인도네시아 에이전시.',
    trustedBy: '우리와 함께한 글로벌 브랜드',
    trustStat: '9개 글로벌 브랜드 · 8개 산업 · 15개국 이상',
    recognizedBy: '인증',
    upgradeStripPreview: '⚡ 이것은 URL 전용 미리보기입니다. 아래 정보를 입력하면 전체 인도네시아 브랜드 감사를 받을 수 있습니다: 일반적으로 15–25 포인트의 추가 정확도, 페르소나 매핑, GTM 시퀀스, 예산 기준 포함.',
    upgradeStripVerified: '⚡ 한 단계만 더. 아래 선택 정보를 입력하면 전체 감사를 받을 수 있습니다: 일반적으로 5–12 포인트 더, 페르소나 매핑, GTM 시퀀스, 예산 기준 공개 포함.',
    confidenceLabel: ['URL 전용 미리보기','검증됨','표준','완료'],
    dataInputsLabel: '데이터 입력',
    dataInputDots: ['URL','이메일','국가','소셜','예산','카테고리'],
    lockedNeedsInput: '🔒 입력 필요',
    lockedPersona: '페르소나 매핑',
    lockedGtm: 'GTM 시퀀스',
    lockedBudget: '예산 기준',
    bridgeH2High: '{score}/100은 강력한 시작입니다. 전체 감사는 일반적으로 15–25 포인트의 추가 정확도를 제공합니다.',
    bridgeH2Mid: '{score}/100은 URL 전용 미리보기입니다. 전체 그림을 보려면 데이터를 완성하세요.',
    bridgeH2Low: '{score}/100에는 수정 가능한 부분이 있습니다. 전체 감사가 방법을 보여줍니다.',
    bridgePersonaVisible: '인도네시아에서 구매 가능성이 가장 높은 2명의 바이어는 {a}–{b}세 Tier-{N} 도시 전문가입니다.',
    bridgeGtmVisible: '권장 진입 경로: 자카르타 →',
    bridgeBudgetVisible: '귀사 카테고리의 최소 월 지출 기준:',
    bridgeLocked: '🔒 전체 보고서로 잠금 해제',
    bridgeCta: '전체 보고서 잠금 해제 →',
    bridgeDelivery: ['📄 전체 브랜드 보고서','🎯 카테고리별 벤치마크','⏱ 2분 이내 수신'],
    bridgeTicker: [
      '● 오늘 4개 브랜드가 감사를 실행했습니다 · 마지막: 한국 SaaS · 점수 71',
      '● 오늘 4개 브랜드가 감사를 실행했습니다 · 마지막: 영국 핀테크 · 점수 64',
      '● 오늘 5개 브랜드가 감사를 실행했습니다 · 마지막: 독일 패션 · 점수 78',
      '● 오늘 5개 브랜드가 감사를 실행했습니다 · 마지막: 일본 호스피탈리티 · 점수 69',
      '● 오늘 5개 브랜드가 감사를 실행했습니다 · 마지막: 싱가포르 B2B SaaS · 점수 73',
    ],
    toastVerified: '카테고리 맥락으로 점수가 조정되었습니다. ▲ +{delta} 포인트.',
    toastComplete: '점수가 확정되었습니다. 전체 보고서가 받은 편지함으로 전송됩니다.',
    toastSkip: '표준 보고서가 받은 편지함으로 전송됩니다.',
    stickyScoreStrong: '{score}/100 보고서를 전송할 준비가 되었습니다.',
    stickyScoreSub: '어디로 보내드릴까요?',
    stickyScoreBtn: '전송 →',
    formEyebrow: '감사 시작',
    formTitle: '무료 인도네시아 브랜드 분석 받기.',
    formDoneTitle: '보고서가 전송되었습니다.',
    fName: '이름', fNamePh: '성명',
    fCompany: '회사명', fCompanyPh: 'Acme Global Inc.',
    fEmail: '업무용 이메일', fEmailPh: 'jane@acme.com',
    fPhone: '전화 / 왓츠앱', fPhonePh: '811 1846 466',
    fWebsite: '웹사이트 URL', fWebsitePh: 'https://yourwebsite.com',
    fWebsiteHelper: '보고서 작성을 위해 크롤링됩니다. 더 완성된 사이트일수록 좋습니다.',
    fCountry: '브랜드 본사 소재지',
    fBudget: '월 예산',
    fService: '관심 서비스',
    fLinkedin: 'LinkedIn 회사 페이지', fLinkedinPh: 'https://linkedin.com/company/…',
    fMeta: 'Meta / 인스타그램 페이지', fMetaPh: 'https://instagram.com/yourbrand',
    fTikTok: '틱톡 프로필', fTikTokPh: 'https://tiktok.com/@yourbrand',
    optional: '선택',
    selectCountry: '국가 선택', selectRange: '범위 선택',
    freeNote: '무료. 요청하지 않으면 영업 전화 없음.',
    privacyNote: '인도네시아 브랜드 감사 보고서 준비 및 제공 목적으로만 사용됩니다.',
    procTitle: '브랜드 분석 중',
    procDesc: '인도네시아 기회를 매핑하고 있습니다. 30–60초 소요됩니다.',
    procSteps: [
      '웹사이트 및 디지털 자산 크롤링 중',
      '브랜드 포지셔닝 및 시장 적합성 분석 중',
      '인도네시아 TAM 및 도시 타겟팅 매핑 중',
      '인도네시아 내 카테고리 경쟁사 파악 중',
      'GTM 청사진 및 예산 프레임워크 작성 중',
    ],
    successTitle: '보고서 전송 완료',
    successDesc: '귀사의 인도네시아 분석이 전송되었습니다:',
    successSpam: '2분 이내에 받지 못하셨다면 스팸 또는 프로모션 폴더를 확인해 주세요.',
    successBook: '무료 전략 상담 예약 →',
    successAnother: '다른 브랜드 분석하기',
    step1Title:'제출', step2Title:'분석', step3Title:'수신',
    stickyStrong: '2분 설정.',
    stickySub: '무료. 영업 전화 없음.',
    stickyBtn: '신청',
    whoLede: 'Ideoworks는 Calvin Klein, HSBC, GoPro, Park Hyatt를 포함한 글로벌 브랜드의 인도네시아 시장 진출과 성장을 이끌어 온 자카르타 기반 통합 디지털 마케팅 에이전시입니다. 자카르타 현지에서 핀테크, SaaS, 호스피탈리티, 소비자 브랜드 및 B2B 서비스 분야에 걸쳐 수행해온 프로젝트들이 이 리포트 분석의 기반을 이룹니다.',
    proofLabels: ['인도네시아 경력 연수', '지금까지 처리된 브랜드', '최고 ROAS · iBox × Shopee'],
    heroUrlPh: 'yourbrand.com',
    heroUrlBtn: '라이브 감사 실행 →',
    heroUrlHelper: '라이브 미리보기 · 이메일 불필요.',
    heroUrlError: '해당 URL에 접근할 수 없습니다. https://를 포함하거나 다른 도메인을 시도해보세요.',
    heroUrlCrawlBlock: '도메인을 크롤링하지 못했지만, 귀사 카테고리 브랜드의 일반적인 성과를 보여드립니다. 자세한 감사를 위해 전체 보고서를 받아보세요 →',
    heroLocked: '페르소나 매핑 · GTM 전략 · 예산',
    heroLockedSub: '잠금됨. 이메일로 전체 보고서를 받으세요.',
    heroLockedCta: '전체 보고서 잠금 해제 →',
    step1Cta: '인도네시아 브랜드 감사 받기 →',
    step2Head: '보고서가 준비 중입니다. 기다리는 동안, 맞춤 설정을 도와주세요.',
    step2Sub: '선택사항입니다. 표준 보고서를 받으시려면 건너뛰세요.',
    step2PhoneTag: '선택 · 제공 시 더 빠른 처리',
    step2Btn: '맞춤형 버전 보내기 →',
    step2Skip: '건너뛰기. 표준 보고서만 받기',
    wizardCatQ: '브랜드 카테고리를 선택해 주세요.',
    wizardCountryQ: '브랜드 본사는 어디에 있나요?',
    wizardBudgetQ: '월 마케팅 예산은 얼마인가요?',
    wizardEmailQ: '전체 인도네시아 보고서를 어디로 보낼까요?',
    wizardEmailSub: '맞춤형 인도네시아 브랜드 보고서 · 2분 이내에 받으실 수 있습니다.',
    wizardContinue: '다음 →',
    wizardSkip: '건너뛰기',
    wizardSend: '보고서 받기 →',
    wizardDoneTitle: '보고서가 전송 중입니다.',
    wizardBudgets: [['$10K 미만','시장 탐색'],['$10K – $30K','경쟁적 진입'],['$30K – $70K','본격적인 시장 공략'],['$70K+','카테고리 리더십']],
    scopeCards: [
      ['브랜드 준비도', '귀사의 브랜드 이름, 비주얼 아이덴티티, 메시지를 인도네시아의 문화적, 종교적, 언어적 기준에 맞춰 점수화합니다. 서울에서 프리미엄으로 읽히는 포지셔닝이 수라바야에서는 차갑게 읽힐 수 있으며, 이 점수는 그 격차를 드러냅니다.'],
      ['기회 점수', '인도네시아 2억 7천만 소비자 시장에서 귀사 카테고리의 성장률과 채널별 침투도를 도시 등급별로 분석합니다. 여기서 진입 시기는 카테고리별로 다르며, 빠르게 성장하는 세그먼트도 귀사 브랜드에 맞는 가격대에서는 이미 포화 상태일 수 있습니다.'],
      ['페르소나 매핑', '인도네시아 소득 계층, 플랫폼 행동 패턴, 카테고리별 구매 또는 도입 유발 요인을 기반으로 가장 구매 확률이 높은 2~3개 구매자 프로필을 도출합니다. 인도네시아에서는 도시 등급에 따라 소비자 행동이 크게 다르며, 자카르타 중심부에서 전환되는 프로필이 90분 거리의 반둥에는 존재하지 않을 수 있습니다.'],
      ['경쟁 분석', '귀사 카테고리에서 활동 중인 3~5개 경쟁사를 파악하고 인도네시아에서의 가격, 채널, 점유율에 대한 지배력을 점수화합니다. 드러나는 공백은 글로벌 데이터 모델이 아닌, 이 시장에서 비교 가능한 브랜드 런칭을 추적한 실제 경험에서 비롯됩니다.'],
      ['GTM 전략', '귀사 카테고리에 특화된 도시 순서 선정, 채널 우선순위, KOL 등급, 예산 배분을 포함한 90일 진입 계획을 제공합니다. 자카르타의 틱톡샵, 수라바야의 SaaS 파트너 채널, 또는 BSD의 기업 조달팀에서 효과적인 방식이 같은 전략으로 통하지 않습니다. 이 플랜은 그 차이를 반영합니다.'],
      ['예산 프레임워크', '최소 진입부터 공격적 시장 확보까지, 귀사 카테고리와 경쟁 환경에 맞게 조정된 세 가지 지출 단계를 제공합니다. 인도네시아의 에이전시 요금, 플랫폼 CPM, 채널 파트너 수수료 및 KOL 비용은 글로벌 기준을 따르지 않으며, 이 수치는 현재 실제 시장 비용을 반영합니다.'],
    ],
  },
  zh: {
    eyebrow: '印度尼西亚市场情报 / Ideoworks',
    headline: '印尼品牌\n诊断报告。\n一目了然。',
    subhead: '精准了解您的品牌在印尼市场的定位。',
    cta: '开始审计',
    submitBtn: '分析我的印尼品牌',
    creds: ['雅加达本地团队', '类别专属监管与许可准备度评分', '印尼渠道与合作伙伴费用基准数据'],
    statLabels: ['市场规模','参考样本','处理时间'],
    statUnits: ['消费者','已分析品牌','设置'],
    scopeEyebrow: '',
    scopeTitle: '六个维度。',
    scopeEm: '在印尼投入第一分钱之前，每一项都至关重要。',
    whoEyebrow: '· 关于我们',
    whoTitle: '自2010年以来， ',
    whoTitleEm: '全球品牌信赖的印尼本土数字代理商。',
    trustedBy: '信任我们的品牌',
    trustStat: '9个全球品牌 · 8个行业 · 15+个国家',
    recognizedBy: '认证',
    upgradeStripPreview: '⚡ 这是您的仅URL预览。请完成以下输入以解锁完整的印尼品牌审计: 通常提升15–25分的精准度，包括用户画像、GTM序列和预算基准。',
    upgradeStripVerified: '⚡ 还差一步。完成以下可选信息以获取完整审计: 通常再提升5–12分，并解锁用户画像、GTM序列和预算基准。',
    confidenceLabel: ['仅URL预览','已验证','标准','完整'],
    dataInputsLabel: '数据输入',
    dataInputDots: ['URL','邮箱','国家','社媒','预算','类别'],
    lockedNeedsInput: '🔒 需要您的输入',
    lockedPersona: '用户画像',
    lockedGtm: 'GTM 序列',
    lockedBudget: '预算基准',
    bridgeH2High: '您的 {score}/100 是个不错的开始。完整审计通常能揭示额外15–25分的精准度。',
    bridgeH2Mid: '您的 {score}/100 是仅URL预览。补充数据以查看完整图景。',
    bridgeH2Low: '您的 {score}/100 存在可修正的差距。完整审计将指出方向。',
    bridgePersonaVisible: '在印尼，您2位最高概率买家是 Tier-{N} 城市专业人士，年龄 {a}–{b} 岁',
    bridgeGtmVisible: '推荐进入路径：雅加达 →',
    bridgeBudgetVisible: '您所在类别的最低月度支出基准：',
    bridgeLocked: '🔒 完整报告解锁后可见',
    bridgeCta: '解锁我的完整报告 →',
    bridgeDelivery: ['📄 完整品牌报告','🎯 类别专属基准','⏱ 2分钟内到达邮箱'],
    bridgeTicker: [
      '● 今天有4个品牌完成了审计 · 最新：韩国SaaS · 评分71',
      '● 今天有4个品牌完成了审计 · 最新：英国金融科技 · 评分64',
      '● 今天有5个品牌完成了审计 · 最新：德国时尚 · 评分78',
      '● 今天有5个品牌完成了审计 · 最新：日本酒店 · 评分69',
      '● 今天有5个品牌完成了审计 · 最新：新加坡B2B SaaS · 评分73',
    ],
    toastVerified: '已结合类别背景调整评分。▲ +{delta} 分。',
    toastComplete: '评分已最终确定。完整报告正发送至您的邮箱。',
    toastSkip: '标准报告正发送至您的邮箱。',
    stickyScoreStrong: '您的 {score}/100 报告已准备好发送。',
    stickyScoreSub: '发送至哪里？',
    stickyScoreBtn: '发送 →',
    formEyebrow: '开始审计',
    formTitle: '获取您的免费印尼品牌分析。',
    formDoneTitle: '您的报告正在发送。',
    fName: '全名', fNamePh: '您的姓名',
    fCompany: '公司名称', fCompanyPh: 'Acme Global Inc.',
    fEmail: '工作邮箱', fEmailPh: 'jane@acme.com',
    fPhone: '电话 / WhatsApp', fPhonePh: '811 1846 466',
    fWebsite: '网站 URL', fWebsitePh: 'https://yourwebsite.com',
    fWebsiteHelper: '我们将抓取此页面生成报告，越完整越好。',
    fCountry: '品牌总部所在地',
    fBudget: '月度预算',
    fService: '感兴趣的服务',
    fLinkedin: 'LinkedIn 公司主页', fLinkedinPh: 'https://linkedin.com/company/…',
    fMeta: 'Meta / Instagram 主页', fMetaPh: 'https://instagram.com/yourbrand',
    fTikTok: 'TikTok 个人资料', fTikTokPh: 'https://tiktok.com/@yourbrand',
    optional: '选填',
    selectCountry: '选择国家', selectRange: '选择范围',
    freeNote: '免费。除非您要求，否则不会有销售电话。',
    privacyNote: '仅用于准备和发送您的印尼品牌审计报告。',
    procTitle: '正在分析您的品牌',
    procDesc: '正在绘制您的印尼市场机会。需要30–60秒。',
    procSteps: [
      '正在抓取您的网站和数字资产',
      '正在分析品牌定位和市场契合度',
      '正在绘制您的印尼TAM和城市定位',
      '正在识别印尼市场内的竞争对手',
      '正在编制GTM蓝图和预算框架',
    ],
    successTitle: '报告已发送',
    successDesc: '您的印尼分析已发送至',
    successSpam: '如果2分钟内未收到，请检查垃圾邮件或促销文件夹。',
    successBook: '预约免费策略咨询 →',
    successAnother: '分析另一个品牌',
    step1Title:'提交', step2Title:'分析', step3Title:'接收',
    stickyStrong: '2分钟设置。',
    stickySub: '免费。无销售电话。',
    stickyBtn: '申请',
    whoLede: 'Ideoworks是一家总部位于雅加达的整合数字营销代理商，曾主导Calvin Klein、HSBC、GoPro、Park Hyatt等全球品牌进入印尼市场并实现增长。所有项目均在雅加达本地执行，覆盖金融科技、SaaS、酒店餐饮、消费品牌及B2B服务领域，这正是本报告分析的底层数据来源。',
    proofLabels: ['深耕印尼年数', '迄今服务品牌', '最高ROAS · iBox × Shopee'],
    heroUrlPh: 'yourbrand.com',
    heroUrlBtn: '运行实时审计 →',
    heroUrlHelper: '实时预览 · 无需邮件。',
    heroUrlError: '无法访问该网址。请尝试添加https://或使用其他域名。',
    heroUrlCrawlBlock: '我们无法实时抓取该域名，但这是您所在类别品牌的典型表现。获取完整深度分析 →',
    heroLocked: '用户画像 · GTM策略 · 预算',
    heroLockedSub: '已锁定。通过邮件获取完整报告。',
    heroLockedCta: '解锁完整报告 →',
    step1Cta: '获取我的印尼品牌审计 →',
    step2Head: '您的报告正在准备中。请在等待期间帮助我们为您定制。',
    step2Sub: '可选。如果您只想接收报告，请跳过。',
    step2PhoneTag: '可选 · 提供后处理更快',
    step2Btn: '发送定制版本 →',
    step2Skip: '跳过，只发送标准报告',
    wizardCatQ: '您的品牌属于哪个类别？',
    wizardCountryQ: '您的品牌总部在哪里？',
    wizardBudgetQ: '您的月度营销预算是多少？',
    wizardEmailQ: '我们将完整的印尼报告发送到哪里？',
    wizardEmailSub: '您的专属印尼品牌报告 · 2分钟内到达邮箱。',
    wizardContinue: '继续 →',
    wizardSkip: '跳过',
    wizardSend: '发送我的报告 →',
    wizardDoneTitle: '报告正在发送。',
    wizardBudgets: [['$10K以下','市场试探'],['$10K – $30K','竞争性进入'],['$30K – $70K','认真布局市场'],['$70K+','品类领导力']],
    scopeCards: [
      ['品牌准备度', '我们根据印尼的文化、宗教和语言标准，对您的品牌名称、视觉形象和信息传达进行评分。同样的高端定位在首尔有效，在泗水却可能显得疏远，这项评分会指出差距所在。'],
      ['机会评分', '我们按城市层级，衡量您所在品类在印尼2.7亿消费者市场中的增长速度和渠道渗透深度。这里的入市时机因品类而异，增长快速的细分市场在适合贵品牌的价格带上往往已趋于饱和。'],
      ['用户画像', '我们根据印尼收入层级、平台行为和品类购买或采用触发因素，梳理出2至3个购买概率最高的买家画像。印尼各城市层级间的消费者行为差异显著，在雅加达核心区转化的画像，在90分钟车程外的万隆可能根本不存在。'],
      ['竞争分析', '我们梳理您品类中3至5家活跃竞争对手，评估其在印尼市场价格、渠道和声量上的把控力。我们所呈现的市场空白，来自对该市场同类品牌实际入场情况的追踪，而非全球数据建模。'],
      ['GTM策略', '我们输出一份90天入场计划，涵盖针对您品类的城市推进顺序、渠道优先级、KOL层级和预算分配。无论是在雅加达的TikTok Shop、泗水的SaaS合作伙伴渠道，还是BSD的企业采购团队，有效的方法都不尽相同。本计划已将这一差异纳入考量。'],
      ['预算框架', '我们输出三个支出档位，从最低可行入场到激进市场扩张，均根据您的品类和竞争格局进行校准。印尼的代理商费率、平台CPM、渠道合作伙伴费用和KOL费用均不遵循全球基准，这些数字反映的是当前真实的本地市场成本。'],
    ],
  },
  ms: {
    eyebrow: 'Risikan Pasaran Indonesia / Ideoworks',
    headline: 'Audit jenama\nIndonesia anda.\nSerta-merta.',
    subhead: 'Ketahui tepat kedudukan jenama anda di pasaran Indonesia.',
    cta: 'Mula Audit',
    submitBtn: 'Analisis Jenama Saya untuk Indonesia',
    creds: ['Berpusat di Jakarta', 'Kesediaan peraturan & pelesenan dinilai mengikut kategori anda', 'Kos saluran & perkongsian Indonesia dibandingkan'],
    statLabels: ['Saiz Pasaran','Set Rujukan','Masa Siap'],
    statUnits: ['Pengguna','Jenama Dianalisis','Persediaan'],
    scopeEyebrow: '',
    scopeTitle: 'Enam dimensi.',
    scopeEm: 'Setiap satunya penting sebelum anda membelanjakan satu sen di sini.',
    whoEyebrow: '· Siapa Kami',
    whoTitle: 'Agensi Indonesia yang ',
    whoTitleEm: 'dipercayai jenama global sejak 2010.',
    trustedBy: 'Jenama yang mempercayai kami',
    trustStat: '9 jenama global · 8 industri · 15+ negara',
    recognizedBy: 'Diiktiraf oleh',
    upgradeStripPreview: '⚡ Ini adalah pratonton URL sahaja anda. Lengkapkan input di bawah untuk membuka kunci audit jenama Indonesia penuh anda: biasanya 15–25 mata ketepatan tambahan, ditambah pemetaan persona, urutan GTM, dan lantai belanjawan.',
    upgradeStripVerified: '⚡ Satu langkah lagi. Lengkapkan input pilihan di bawah untuk audit penuh anda: biasanya 5–12 mata lagi, ditambah pemetaan persona, urutan GTM, dan lantai belanjawan yang didedahkan.',
    confidenceLabel: ['Pratonton URL sahaja','Disahkan','Standard','Lengkap'],
    dataInputsLabel: 'INPUT DATA',
    dataInputDots: ['URL','E-mel','Negara','Sosial','Belanjawan','Kategori'],
    lockedNeedsInput: '🔒 memerlukan input anda',
    lockedPersona: 'PEMETAAN PERSONA',
    lockedGtm: 'URUTAN GTM',
    lockedBudget: 'LANTAI BELANJAWAN',
    bridgeH2High: '{score}/100 anda adalah permulaan yang kukuh. Audit penuh biasanya mendedahkan 15–25 mata ketepatan tambahan.',
    bridgeH2Mid: '{score}/100 anda adalah pratonton URL sahaja anda. Lengkapkan data anda untuk melihat gambaran penuh.',
    bridgeH2Low: '{score}/100 anda mempunyai jurang yang boleh diperbaiki. Audit penuh menunjukkan laluan itu.',
    bridgePersonaVisible: '2 pembeli berkemungkinan tertinggi anda di Indonesia adalah profesional bandar Tier-{N} berusia {a}–{b} dengan',
    bridgeGtmVisible: 'Laluan masuk yang disyorkan: Jakarta →',
    bridgeBudgetVisible: 'Perbelanjaan bulanan minimum yang berdaya maju untuk kategori anda:',
    bridgeLocked: '🔒 Dibuka kunci dengan laporan penuh',
    bridgeCta: 'Buka kunci laporan penuh saya →',
    bridgeDelivery: ['📄 Laporan jenama penuh anda','🎯 Penanda aras khusus kategori','⏱ Dalam peti masuk dalam 2 minit'],
    bridgeTicker: [
      '● 4 jenama menjalankan audit ini hari ini · Terakhir: SaaS Korea · Skor 71',
      '● 4 jenama menjalankan audit ini hari ini · Terakhir: Fintech UK · Skor 64',
      '● 5 jenama menjalankan audit ini hari ini · Terakhir: Fesyen Jerman · Skor 78',
      '● 5 jenama menjalankan audit ini hari ini · Terakhir: Hospitaliti Jepun · Skor 69',
      '● 5 jenama menjalankan audit ini hari ini · Terakhir: B2B SaaS Singapura · Skor 73',
    ],
    toastVerified: 'Skor disesuaikan dengan konteks kategori. ▲ +{delta} mata.',
    toastComplete: 'Skor dimuktamadkan. Laporan penuh sedang dihantar ke peti masuk anda sekarang.',
    toastSkip: 'Laporan standard sedang dihantar ke peti masuk anda.',
    stickyScoreStrong: 'Laporan {score}/100 anda sedia untuk dihantar.',
    stickyScoreSub: 'Ke mana?',
    stickyScoreBtn: 'Hantar →',
    formEyebrow: 'Mula Audit',
    formTitle: 'Dapatkan analisis jenama Indonesia percuma anda.',
    formDoneTitle: 'Laporan anda sedang dalam perjalanan.',
    fName: 'Nama Penuh', fNamePh: 'Nama anda',
    fCompany: 'Nama Syarikat', fCompanyPh: 'Acme Global Inc.',
    fEmail: 'E-mel Kerja', fEmailPh: 'jane@acme.com',
    fPhone: 'Telefon / WhatsApp', fPhonePh: '811 1846 466',
    fWebsite: 'URL Laman Web', fWebsitePh: 'https://yourwebsite.com',
    fWebsiteHelper: 'Kami merangkak ini untuk membina laporan anda. Semakin lengkap semakin baik.',
    fCountry: 'Di mana ibu pejabat jenama anda?',
    fBudget: 'Belanjawan Bulanan',
    fService: 'Perkhidmatan yang Diminati',
    fLinkedin: 'Halaman Syarikat LinkedIn', fLinkedinPh: 'https://linkedin.com/company/…',
    fMeta: 'Halaman Meta / Instagram', fMetaPh: 'https://instagram.com/yourbrand',
    fTikTok: 'Profil TikTok', fTikTokPh: 'https://tiktok.com/@yourbrand',
    optional: 'pilihan',
    selectCountry: 'Pilih negara', selectRange: 'Pilih julat',
    freeNote: 'Percuma. Tiada panggilan jualan melainkan anda meminta.',
    privacyNote: 'Digunakan hanya untuk menyediakan dan menghantar laporan audit jenama Indonesia anda.',
    procTitle: 'Menganalisis jenama anda',
    procDesc: 'Memetakan peluang Indonesia anda. Ini mengambil masa 30–60 saat.',
    procSteps: [
      'Merangkak laman web dan aset digital anda',
      'Menganalisis kedudukan jenama dan penyesuaian pasaran',
      'Memetakan TAM Indonesia dan sasaran bandar anda',
      'Mengenal pasti pesaing dalam kategori di Indonesia',
      'Mengkompil pelan GTM dan rangka kerja belanjawan',
    ],
    successTitle: 'Laporan dihantar',
    successDesc: 'Analisis Indonesia anda sedang dalam perjalanan ke',
    successSpam: 'Semak spam atau promosi jika anda tidak menerimanya dalam masa 2 minit.',
    successBook: 'Tempah Panggilan Strategi Percuma →',
    successAnother: 'Analisis Jenama Lain',
    step1Title:'Hantar', step2Title:'Analisis', step3Title:'Terima',
    stickyStrong: 'Persediaan 2 minit.',
    stickySub: 'Percuma. Tiada panggilan jualan.',
    stickyBtn: 'Minta',
    whoLede: 'Ideoworks ialah agensi pemasaran digital bersepadu berpusat di Jakarta yang telah memimpin kemasukan pasaran dan pertumbuhan jenama global termasuk Calvin Klein, HSBC, GoPro, dan Park Hyatt. Penglibatan tersebut, yang dijalankan di lapangan di Jakarta merentasi fintech, SaaS, hospitaliti, jenama pengguna, dan perkhidmatan B2B, menjadi asas kepada analisis dalam laporan ini.',
    proofLabels: ['Tahun di Indonesia', 'Jenama yang dikendalikan setakat ini', 'ROAS terbaik · iBox × Shopee'],
    heroUrlPh: 'yourbrand.com',
    heroUrlBtn: 'Jalankan Audit Langsung →',
    heroUrlHelper: 'Pratonton langsung · Tiada e-mel diperlukan.',
    heroUrlError: 'Kami tidak dapat mencapai URL itu. Cuba dengan https:// atau domain yang berbeza.',
    heroUrlCrawlBlock: 'Kami tidak dapat merangkak domain ini, tetapi ini adalah prestasi tipikal jenama dalam kategori anda. Dapatkan audit penuh →',
    heroLocked: 'Pemetaan Persona · Strategi GTM · Belanjawan',
    heroLockedSub: 'Terkunci. Dapatkan laporan penuh melalui e-mel.',
    heroLockedCta: 'Buka kunci laporan penuh saya →',
    step1Cta: 'Dapatkan Audit Jenama Indonesia Saya →',
    step2Head: 'Laporan anda sedang disediakan. Sementara menunggu, bantu kami menyesuaikannya.',
    step2Sub: 'Pilihan. Langkau jika anda lebih suka menerima laporan standard.',
    step2PhoneTag: 'pilihan · proses lebih pantas jika diberikan',
    step2Btn: 'Hantar versi yang disesuaikan →',
    step2Skip: 'Langkau. Hantar sahaja laporan standard',
    wizardCatQ: 'Apakah kategori jenama anda?',
    wizardCountryQ: 'Di mana ibu pejabat jenama anda?',
    wizardBudgetQ: 'Berapakah belanjawan pemasaran bulanan anda?',
    wizardEmailQ: 'Ke mana kami hantar laporan Indonesia penuh anda?',
    wizardEmailSub: 'Laporan jenama Indonesia anda · Dalam peti masuk dalam 2 minit.',
    wizardContinue: 'Teruskan →',
    wizardSkip: 'Langkau',
    wizardSend: 'Hantar laporan saya →',
    wizardDoneTitle: 'Laporan sedang dalam perjalanan.',
    wizardBudgets: [['Bawah $10K','Menjelajah pasaran'],['$10K – $30K','Kemasukan berdaya saing'],['$30K – $70K','Permainan pasaran serius'],['$70K+','Kepimpinan kategori']],
    scopeCards: [
      ['Kesediaan Jenama', 'Kami menilai nama jenama, identiti visual, dan pemesejan anda berdasarkan jangkaan budaya, agama, dan bahasa Indonesia. Penentuan kedudukan yang membawa mesej premium di Seoul boleh kelihatan dingin di Surabaya, dan skor ini memberitahu anda di mana jurang itu.'],
      ['Skor Peluang', 'Kami mengukur kadar pertumbuhan dan kedalaman penembusan saluran kategori anda dalam pasaran 270 juta pengguna Indonesia, dipecahkan mengikut peringkat bandar. Masa kemasukan di sini khusus mengikut kategori, dan segmen yang berkembang pesat mungkin sudah sesak pada harga yang sesuai untuk jenama anda.'],
      ['Pemetaan Persona', 'Kami memetakan 2 hingga 3 profil pembeli dengan kebarangkalian tertinggi berdasarkan peringkat pendapatan Indonesia, tingkah laku platform, dan pencetus pembelian atau penggunaan khusus kategori. Tingkah laku pengguna berubah dengan ketara antara peringkat bandar di sini, dan profil yang menukar di Central Jakarta mungkin tidak wujud 90 minit jauhnya di Bandung.'],
      ['Analisis Persaingan', 'Kami memetakan 3 hingga 5 pesaing aktif dalam kategori anda dan menilai pegangan mereka pada harga, saluran, dan bahagian suara di Indonesia. Jurang yang kami dedahkan diambil daripada apa yang kami jejaki merentasi pelancaran jenama yang setanding di pasaran ini, bukan dimodelkan daripada set data global.'],
      ['Strategi GTM', 'Kami menghasilkan pelan kemasukan 90 hari dengan urutan bandar, keutamaan saluran, peringkat KOL, dan peruntukan belanjawan khusus untuk kategori anda. Apa yang berkesan di TikTok Shop Jakarta, di saluran rakan kongsi SaaS di Surabaya, atau bersama pasukan perolehan perusahaan di BSD tidak mengikut buku panduan yang sama. Pelan ini mengambil kira perkara itu.'],
      ['Rangka Kerja Belanjawan', 'Kami menghasilkan tiga peringkat perbelanjaan yang ditentukur mengikut kategori dan set persaingan anda di Indonesia, daripada kemasukan minimum yang berdaya maju hingga tangkapan pasaran yang agresif. Kadar agensi, CPM platform, yuran rakan kongsi saluran, dan kos KOL di sini tidak mengikut penanda aras global, dan angka-angka ini mencerminkan kos pasaran sebenar sekarang.'],
    ],
  },
  th: {
    eyebrow: 'ข้อมูลตลาดอินโดนีเซีย / Ideoworks',
    headline: 'ตรวจสอบแบรนด์\nอินโดนีเซียของคุณ\nได้ทันที',
    subhead: 'ค้นหาตำแหน่งที่แน่ชัดของแบรนด์คุณในอินโดนีเซีย',
    cta: 'เริ่มตรวจสอบ',
    submitBtn: 'วิเคราะห์แบรนด์ของฉันสำหรับอินโดนีเซีย',
    creds: ['ทีมในจาการ์ตา', 'ประเมินความพร้อมด้านกฎระเบียบและใบอนุญาตสำหรับหมวดหมู่ของคุณ', 'เปรียบเทียบต้นทุนช่องทางและการเป็นพันธมิตรของอินโดนีเซีย'],
    statLabels: ['ขนาดตลาด','ชุดอ้างอิง','เวลาตอบสนอง'],
    statUnits: ['ผู้บริโภค','แบรนด์ที่วิเคราะห์','การตั้งค่า'],
    scopeEyebrow: '',
    scopeTitle: 'หกมิติ',
    scopeEm: 'แต่ละอย่างสำคัญก่อนที่คุณจะใช้เงินบาทแรกที่นี่',
    whoEyebrow: '· เกี่ยวกับเรา',
    whoTitle: 'เอเจนซีอินโดนีเซียที่ ',
    whoTitleEm: 'แบรนด์ระดับโลกไว้วางใจตั้งแต่ปี 2010',
    trustedBy: 'แบรนด์ที่ไว้วางใจเรา',
    trustStat: '9 แบรนด์ระดับโลก · 8 อุตสาหกรรม · 15+ ประเทศ',
    recognizedBy: 'ได้รับการรับรองโดย',
    upgradeStripPreview: '⚡ นี่คือการดูตัวอย่าง URL เท่านั้นของคุณ กรอกข้อมูลด้านล่างเพื่อปลดล็อกการตรวจสอบแบรนด์อินโดนีเซียฉบับเต็ม: โดยทั่วไปมีความแม่นยำเพิ่มขึ้น 15–25 คะแนน พร้อมการแมปบุคลิก ลำดับ GTM และงบประมาณขั้นต่ำ',
    upgradeStripVerified: '⚡ อีกขั้นเดียว กรอกข้อมูลเสริมด้านล่างเพื่อรับการตรวจสอบฉบับเต็ม: โดยทั่วไปเพิ่มอีก 5–12 คะแนน พร้อมการแมปบุคลิก ลำดับ GTM และงบประมาณขั้นต่ำที่เปิดเผย',
    confidenceLabel: ['ดูตัวอย่าง URL เท่านั้น','ยืนยันแล้ว','มาตรฐาน','ครบถ้วน'],
    dataInputsLabel: 'ข้อมูลที่ป้อน',
    dataInputDots: ['URL','อีเมล','ประเทศ','โซเชียล','งบประมาณ','หมวดหมู่'],
    lockedNeedsInput: '🔒 ต้องการข้อมูลของคุณ',
    lockedPersona: 'การแมปบุคลิก',
    lockedGtm: 'ลำดับ GTM',
    lockedBudget: 'งบประมาณขั้นต่ำ',
    bridgeH2High: '{score}/100 ของคุณเป็นจุดเริ่มต้นที่แข็งแกร่ง การตรวจสอบฉบับเต็มมักเผยให้เห็นความแม่นยำเพิ่มขึ้น 15–25 คะแนน',
    bridgeH2Mid: '{score}/100 ของคุณคือการดูตัวอย่าง URL เท่านั้น กรอกข้อมูลให้ครบเพื่อดูภาพรวมทั้งหมด',
    bridgeH2Low: '{score}/100 ของคุณมีช่องว่างที่แก้ไขได้ การตรวจสอบฉบับเต็มแสดงเส้นทางแก้ไข',
    bridgePersonaVisible: 'ผู้ซื้อที่มีความน่าจะเป็นสูงสุด 2 รายของคุณในอินโดนีเซียคือผู้เชี่ยวชาญในเมือง Tier-{N} อายุ {a}–{b} ปี ที่มี',
    bridgeGtmVisible: 'เส้นทางการเข้าที่แนะนำ: จาการ์ตา →',
    bridgeBudgetVisible: 'การใช้จ่ายรายเดือนขั้นต่ำที่ทำได้สำหรับหมวดหมู่ของคุณ:',
    bridgeLocked: '🔒 ปลดล็อกด้วยรายงานฉบับเต็ม',
    bridgeCta: 'ปลดล็อกรายงานฉบับเต็มของฉัน →',
    bridgeDelivery: ['📄 รายงานแบรนด์ฉบับเต็มของคุณ','🎯 เกณฑ์มาตรฐานเฉพาะหมวดหมู่','⏱ ในกล่องจดหมายภายใน 2 นาที'],
    bridgeTicker: [
      '● 4 แบรนด์เรียกใช้การตรวจสอบนี้วันนี้ · ล่าสุด: SaaS เกาหลี · คะแนน 71',
      '● 4 แบรนด์เรียกใช้การตรวจสอบนี้วันนี้ · ล่าสุด: ฟินเทค UK · คะแนน 64',
      '● 5 แบรนด์เรียกใช้การตรวจสอบนี้วันนี้ · ล่าสุด: แฟชั่นเยอรมัน · คะแนน 78',
      '● 5 แบรนด์เรียกใช้การตรวจสอบนี้วันนี้ · ล่าสุด: การบริการที่พักญี่ปุ่น · คะแนน 69',
      '● 5 แบรนด์เรียกใช้การตรวจสอบนี้วันนี้ · ล่าสุด: B2B SaaS สิงคโปร์ · คะแนน 73',
    ],
    toastVerified: 'ปรับคะแนนด้วยบริบทหมวดหมู่แล้ว ▲ +{delta} คะแนน',
    toastComplete: 'คะแนนสุดท้ายแล้ว กำลังส่งรายงานฉบับเต็มไปยังกล่องจดหมายของคุณ',
    toastSkip: 'กำลังส่งรายงานมาตรฐานไปยังกล่องจดหมายของคุณ',
    stickyScoreStrong: 'รายงาน {score}/100 ของคุณพร้อมส่งแล้ว',
    stickyScoreSub: 'ส่งไปที่ไหน?',
    stickyScoreBtn: 'ส่ง →',
    formEyebrow: 'เริ่มตรวจสอบ',
    formTitle: 'รับการวิเคราะห์แบรนด์อินโดนีเซียฟรีของคุณ',
    formDoneTitle: 'รายงานของคุณกำลังมา',
    fName: 'ชื่อเต็ม', fNamePh: 'ชื่อของคุณ',
    fCompany: 'ชื่อบริษัท', fCompanyPh: 'Acme Global Inc.',
    fEmail: 'อีเมลงาน', fEmailPh: 'jane@acme.com',
    fPhone: 'โทรศัพท์ / WhatsApp', fPhonePh: '811 1846 466',
    fWebsite: 'URL เว็บไซต์', fWebsitePh: 'https://yourwebsite.com',
    fWebsiteHelper: 'เราจะรวบรวมข้อมูลจากที่นี่เพื่อสร้างรายงาน ยิ่งครบถ้วนยิ่งดี',
    fCountry: 'สำนักงานใหญ่แบรนด์ของคุณอยู่ที่ไหน?',
    fBudget: 'งบประมาณรายเดือน',
    fService: 'บริการที่สนใจ',
    fLinkedin: 'หน้าบริษัท LinkedIn', fLinkedinPh: 'https://linkedin.com/company/…',
    fMeta: 'หน้า Meta / Instagram', fMetaPh: 'https://instagram.com/yourbrand',
    fTikTok: 'โปรไฟล์ TikTok', fTikTokPh: 'https://tiktok.com/@yourbrand',
    optional: 'ไม่บังคับ',
    selectCountry: 'เลือกประเทศ', selectRange: 'เลือกช่วง',
    freeNote: 'ฟรี ไม่มีการโทรขายเว้นแต่คุณขอ',
    privacyNote: 'ใช้เพื่อจัดเตรียมและส่งรายงานการตรวจสอบแบรนด์อินโดนีเซียของคุณเท่านั้น',
    procTitle: 'กำลังวิเคราะห์แบรนด์ของคุณ',
    procDesc: 'กำลังทำแผนที่โอกาสในอินโดนีเซียของคุณ ใช้เวลา 30–60 วินาที',
    procSteps: [
      'กำลังรวบรวมข้อมูลเว็บไซต์และสินทรัพย์ดิจิทัลของคุณ',
      'กำลังวิเคราะห์การวางตำแหน่งแบรนด์และความเหมาะสมกับตลาด',
      'กำลังทำแผนที่ TAM อินโดนีเซียและการกำหนดเป้าหมายเมือง',
      'กำลังระบุคู่แข่งในหมวดหมู่เดียวกันในอินโดนีเซีย',
      'กำลังจัดทำแผน GTM และกรอบงบประมาณ',
    ],
    successTitle: 'ส่งรายงานแล้ว',
    successDesc: 'การวิเคราะห์อินโดนีเซียของคุณกำลังส่งไปที่',
    successSpam: 'ตรวจสอบสแปมหรือโปรโมชันหากคุณไม่เห็นภายใน 2 นาที',
    successBook: 'จองสายกลยุทธ์ฟรี →',
    successAnother: 'วิเคราะห์แบรนด์อื่น',
    step1Title:'ส่ง', step2Title:'วิเคราะห์', step3Title:'รับ',
    stickyStrong: 'ตั้งค่า 2 นาที',
    stickySub: 'ฟรี ไม่มีโทรหาเพื่อขาย',
    stickyBtn: 'ขอ',
    whoLede: 'Ideoworks คือเอเจนซีการตลาดดิจิทัลแบบบูรณาการที่ตั้งอยู่ในจาการ์ตา ซึ่งนำทางการเข้าสู่ตลาดและการเติบโตให้แบรนด์ระดับโลกอย่าง Calvin Klein, HSBC, GoPro และ Park Hyatt โครงการเหล่านั้นดำเนินการโดยตรงในจาการ์ตา ครอบคลุมฟินเทค SaaS การบริการที่พัก แบรนด์ผู้บริโภค และบริการ B2B ซึ่งเป็นพื้นฐานของการวิเคราะห์ในรายงานนี้',
    proofLabels: ['ปีในอินโดนีเซีย', 'แบรนด์ที่ดูแลมาถึงปัจจุบัน', 'ROAS สูงสุด · iBox × Shopee'],
    heroUrlPh: 'yourbrand.com',
    heroUrlBtn: 'เรียกใช้การตรวจสอบสด →',
    heroUrlHelper: 'ดูตัวอย่างสด · ไม่ต้องใช้อีเมล',
    heroUrlError: 'เราไม่สามารถเข้าถึง URL นั้น ลองใช้ https:// หรือโดเมนอื่น',
    heroUrlCrawlBlock: 'เราไม่สามารถรวบรวมข้อมูลโดเมนนี้ได้ แต่นี่คือประสิทธิภาพทั่วไปของแบรนด์ในหมวดหมู่ของคุณ รับการตรวจสอบเต็มรูปแบบ →',
    heroLocked: 'การแมปบุคลิก · กลยุทธ์ GTM · งบประมาณ',
    heroLockedSub: 'ล็อกอยู่ รับรายงานฉบับเต็มทางอีเมล',
    heroLockedCta: 'ปลดล็อกรายงานฉบับเต็มของฉัน →',
    step1Cta: 'รับการตรวจสอบแบรนด์อินโดนีเซียของฉัน →',
    step2Head: 'กำลังเตรียมรายงานของคุณ ระหว่างรอ ช่วยเราปรับแต่งให้ตรงกับคุณ',
    step2Sub: 'ไม่บังคับ ข้ามได้หากต้องการรับรายงานมาตรฐาน',
    step2PhoneTag: 'ไม่บังคับ · ดำเนินการเร็วขึ้นหากให้ข้อมูล',
    step2Btn: 'ส่งเวอร์ชันที่ปรับแต่งแล้ว →',
    step2Skip: 'ข้าม ส่งรายงานมาตรฐานให้ฉัน',
    wizardCatQ: 'หมวดหมู่ใดที่อธิบายแบรนด์ของคุณได้ดีที่สุด?',
    wizardCountryQ: 'แบรนด์ของคุณมีสำนักงานใหญ่ที่ไหน?',
    wizardBudgetQ: 'งบประมาณการตลาดรายเดือนของคุณคือเท่าไหร่?',
    wizardEmailQ: 'เราจะส่งรายงานอินโดนีเซียฉบับเต็มไปที่ไหน?',
    wizardEmailSub: 'รายงานแบรนด์อินโดนีเซียของคุณ · ในกล่องจดหมายภายใน 2 นาที',
    wizardContinue: 'ดำเนินการต่อ →',
    wizardSkip: 'ข้าม',
    wizardSend: 'ส่งรายงานของฉัน →',
    wizardDoneTitle: 'รายงานกำลังส่งไป',
    wizardBudgets: [['ต่ำกว่า $10K','ทดสอบตลาด'],['$10K – $30K','เข้าตลาดอย่างแข่งขัน'],['$30K – $70K','เล่นตลาดอย่างจริงจัง'],['$70K+','นำตลาดในหมวดหมู่']],
    scopeCards: [
      ['ความพร้อมของแบรนด์', 'เราประเมินชื่อแบรนด์ อัตลักษณ์ทางสายตา และการสื่อสารของคุณโดยเทียบกับความคาดหวังทางวัฒนธรรม ศาสนา และภาษาของอินโดนีเซีย การวางตำแหน่งที่อ่านว่าพรีเมียมในโซลสามารถอ่านว่าเย็นชาในสุราบายา และคะแนนนี้บอกคุณว่าช่องว่างอยู่ที่ไหน'],
      ['คะแนนโอกาส', 'เราวัดอัตราการเติบโตและความลึกของการเจาะช่องทางของหมวดหมู่คุณในตลาดผู้บริโภค 270 ล้านคนของอินโดนีเซีย แยกตามระดับเมือง จังหวะการเข้าตลาดที่นี่เฉพาะเจาะจงตามหมวดหมู่ และเซกเมนต์ที่เติบโตเร็วอาจอิ่มตัวในจุดราคาที่เหมาะกับแบรนด์คุณแล้ว'],
      ['การแมปบุคลิก', 'เราระบุโปรไฟล์ผู้ซื้อที่มีความน่าจะเป็นสูงสุด 2 ถึง 3 โปรไฟล์ตามระดับรายได้ของอินโดนีเซีย พฤติกรรมบนแพลตฟอร์ม และตัวกระตุ้นการซื้อหรือการนำไปใช้เฉพาะหมวดหมู่ พฤติกรรมผู้บริโภคเปลี่ยนแปลงอย่างชัดเจนระหว่างระดับเมืองที่นี่ และโปรไฟล์ที่แปลงใน Central Jakarta อาจไม่มีอยู่ในบันดุง 90 นาทีจากที่นั่น'],
      ['การวิเคราะห์การแข่งขัน', 'เราระบุคู่แข่งที่ใช้งานอยู่ 3 ถึง 5 รายในหมวดหมู่คุณและให้คะแนนความแข็งแกร่งของพวกเขาในด้านราคา ช่องทาง และส่วนแบ่งเสียงในอินโดนีเซีย ช่องว่างที่เราเปิดเผยมาจากสิ่งที่เราติดตามในการเปิดตัวแบรนด์ที่เทียบเคียงได้ในตลาดนี้ ไม่ใช่การจำลองจากชุดข้อมูลระดับโลก'],
      ['กลยุทธ์ GTM', 'เราส่งออกแผนการเข้าสู่ตลาด 90 วันพร้อมลำดับเมือง ลำดับความสำคัญของช่องทาง ระดับ KOL และการจัดสรรงบประมาณเฉพาะสำหรับหมวดหมู่คุณ สิ่งที่ได้ผลบน TikTok Shop ในจาการ์ตา บนช่องทางพาร์ทเนอร์ SaaS ในสุราบายา หรือกับทีมจัดซื้อองค์กรใน BSD ไม่ได้ใช้แนวทางเดียวกัน แผนนี้คำนึงถึงเรื่องนั้น'],
      ['กรอบงบประมาณ', 'เราส่งออกสามระดับการใช้จ่ายที่ปรับเทียบตามหมวดหมู่และชุดการแข่งขันของคุณในอินโดนีเซีย ตั้งแต่การเข้าตลาดแบบ minimum viable จนถึงการยึดตลาดแบบ aggressive อัตราเอเจนซี CPM ของแพลตฟอร์ม ค่าธรรมเนียมพาร์ทเนอร์ช่องทาง และค่า KOL ที่นี่ไม่ได้ปฏิบัติตามมาตรฐานระดับโลก และตัวเลขเหล่านี้สะท้อนต้นทุนตลาดท้องถิ่นที่แท้จริงในปัจจุบัน'],
    ],
  },
};
const T = STRINGS[LANG] || STRINGS.en;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent":               "#E8192C",
  "headline":             "Indonesia won't\nwait for your\nbrand to be ready.",
  "subhead":              "In the last 5 years, the top 35 global brands all lost market share in Indonesia. Type your URL. In 90 seconds we show you exactly where your brand stands and what entry would actually take.",
  "showScanLine":         true,
  "showCursorOrb":        true,
  "showCalibrationNodes": true,
  "showDotGrid":          true,
  "showStats":            true,
  "showHistory":          true,
  "ctaLabel":             "Begin Audit",
  "submitLabel":          "Analyze My Brand for Indonesia",
  "headlineSize":         66,
  "dotGridOpacity":       3,
  "scanLineSpeed":        8,
  "wordRevealStagger":    60
}/*EDITMODE-END*/;

/* ── Trust brands (global client grid) ──────────────────────────────── */
const TRUST_BRANDS = [
  { name: 'Calvin Klein',    sector: 'Fashion',               scope: 'Indonesia social & digital campaigns' },
  { name: 'HSBC',            sector: 'Finance',               scope: 'Indonesia brand & performance marketing' },
  { name: 'GoPro',           sector: 'Consumer Tech',         scope: 'Southeast Asia consumer activation' },
  { name: 'Park Hyatt',      sector: 'Hospitality',           scope: 'Indonesia hospitality & social' },
  { name: 'Verisign',        sector: 'Internet Infrastructure', scope: 'APAC digital presence' },
  { name: 'Mayo Clinic',     sector: 'Healthcare',            scope: 'Indonesia healthcare awareness' },
  { name: 'Goodyear',        sector: 'Automotive',            scope: 'Indonesia automotive activation' },
  { name: 'Dunlop',          sector: 'Sports & Industrial',   scope: 'Indonesia brand campaigns' },
  { name: 'Danbi Education', sector: 'Education',             scope: 'Indonesia market entry' },
];

/* ── Country codes ───────────────────────────────────────────────────── */
const PHONE_CODES = [
  { code: '+62', label: '🇮🇩 +62' },
  { code: '+1',  label: '🇺🇸 +1' },
  { code: '+44', label: '🇬🇧 +44' },
  { code: '+61', label: '🇦🇺 +61' },
  { code: '+65', label: '🇸🇬 +65' },
  { code: '+60', label: '🇲🇾 +60' },
  { code: '+66', label: '🇹🇭 +66' },
  { code: '+63', label: '🇵🇭 +63' },
  { code: '+84', label: '🇻🇳 +84' },
  { code: '+852',label: '🇭🇰 +852' },
  { code: '+82', label: '🇰🇷 +82' },
  { code: '+81', label: '🇯🇵 +81' },
  { code: '+86', label: '🇨🇳 +86' },
  { code: '+91', label: '🇮🇳 +91' },
  { code: '+971',label: '🇦🇪 +971' },
  { code: '+966',label: '🇸🇦 +966' },
  { code: '+49', label: '🇩🇪 +49' },
  { code: '+33', label: '🇫🇷 +33' },
  { code: '+31', label: '🇳🇱 +31' },
  { code: '+55', label: '🇧🇷 +55' },
  { code: '+7',  label: '🇷🇺 +7' },
];

const COUNTRY_TO_PHONE = {
  'United States': '+1', 'Canada': '+1', 'United Kingdom': '+44',
  'Australia': '+61', 'Germany': '+49', 'France': '+33',
  'Netherlands': '+31', 'United Arab Emirates': '+971',
  'Singapore': '+65', 'Malaysia': '+60', 'Thailand': '+66',
  'Vietnam': '+84', 'Philippines': '+63', 'Japan': '+81',
  'South Korea': '+82', 'China': '+86', 'Hong Kong': '+852',
  'Taiwan': '+886', 'India': '+91', 'Indonesia': '+62',
  'Brazil': '+55', 'Other': '+1',
};

const HQ_COUNTRIES = [
  'United States','United Kingdom','Canada','Australia','Germany','France',
  'Netherlands','United Arab Emirates','Singapore','Malaysia','Thailand',
  'Vietnam','Philippines','Japan','South Korea','China','Hong Kong',
  'Taiwan','India','Indonesia','Other',
];

const SERVICES = [
  'Mix / Integrated Engagement',
  'Communicate (Creative & Production)',
  'Amplify (Advertising & Media)',
  'Socialize (Social & Influence)',
  'Analyze (Insight & Analytics)',
  'Market Entry Diagnostic',
];

const BUDGETS = [
  'Not sure yet / Exploring',
  'USD 2,000 – 6,000 / month',
  'USD 6,000 – 15,000 / month',
  'USD 15,000 – 50,000 / month',
  'USD 50,000+ / month',
  'Project-based / Not yet defined',
];

const FREE_DOMAINS = ['gmail.com','yahoo.com','hotmail.com','outlook.com','icloud.com','ymail.com','mail.com'];

const SCOPE_ICONS = [
  <svg viewBox="0 0 28 28" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"><circle cx="14" cy="14" r="10.5"/><circle cx="14" cy="14" r="6"/><circle cx="14" cy="14" r="1.5" fill="currentColor"/></svg>,
  <svg viewBox="0 0 28 28" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"><line x1="4" y1="22" x2="4" y2="18"/><line x1="10" y1="22" x2="10" y2="14"/><line x1="16" y1="22" x2="16" y2="9"/><line x1="22" y1="22" x2="22" y2="5"/><line x1="2" y1="25" x2="26" y2="25"/></svg>,
  <svg viewBox="0 0 28 28" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"><circle cx="9" cy="11" r="3"/><circle cx="19" cy="11" r="3"/><circle cx="14" cy="19" r="3"/></svg>,
  <svg viewBox="0 0 28 28" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"><rect x="4" y="4" width="20" height="20"/><line x1="4" y1="14" x2="24" y2="14"/><line x1="14" y1="4" x2="14" y2="24"/></svg>,
  <svg viewBox="0 0 28 28" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"><path d="M 4 22 C 4 14 14 14 14 8 S 24 8 24 6"/></svg>,
  <svg viewBox="0 0 28 28" fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"><rect x="4" y="9" width="20" height="10"/><line x1="10" y1="9" x2="10" y2="19"/><line x1="16" y1="9" x2="16" y2="19"/></svg>,
];

/* ── Hero Preview Card ───────────────────────────────────────────────── */
function HeroPreviewCard({ score, domain }) {
  const has = !!score;
  const s = score || {};
  const b = s.bands || {};
  const rows = [
    ['Brand Readiness',    b.brandReadiness],
    ['Opportunity Score',  b.opportunityScore],
    ['Persona Mapping',    b.personaMapping],
    ['Competitive',        b.competitiveAnalysis],
    ['GTM Strategy',       b.gtmStrategy],
    ['Budget Framework',   b.budgetFramework],
  ];
  return (
    <div className={`hero-preview-card${has ? ' hero-preview-card--active' : ''}`}>
      <div className="hero-preview-card__head">
        <span className="hero-preview-card__eyebrow">Indonesia Score Preview</span>
        {domain && <span className="hero-preview-card__domain">{domain}</span>}
      </div>
      <div className="hero-preview-card__score-row">
        <span className="hero-preview-card__num">{has ? s.score : '—'}</span>
        <span className="hero-preview-card__den">/100</span>
        {has && <span className="hero-preview-card__tier">Preview · 35% confidence</span>}
      </div>
      <div className="hero-preview-card__bars">
        {rows.map(([label, val]) => (
          <div key={label} className="hero-preview-card__bar-row">
            <span className="hero-preview-card__bar-label">{label}</span>
            <div className="hero-preview-card__bar-track">
              <div
                className={`hero-preview-card__bar-fill${has && val ? '' : ' hero-preview-card__bar-fill--locked'}`}
                style={{ width: (has && val) ? val + '%' : '0%' }}
              />
            </div>
            <span className="hero-preview-card__bar-val">{(has && val) ? val : '—'}</span>
          </div>
        ))}
      </div>
      {!has && <p className="hero-preview-card__hint">Type your domain above to preview your score</p>}
      {has && <p className="hero-preview-card__unlock">Submit to get the full 6-dimension assessment by email</p>}
    </div>
  );
}

/* ── Audit Wizard ────────────────────────────────────────────────────── */
function AuditWizard({ reduceMotion, onComplete }) {
  const [step, setStep]           = useState(0);
  const [url, setUrl]             = useState('');
  const [urlError, setUrlError]   = useState('');
  const [category, setCategory]   = useState('');
  const [country, setCountry]     = useState('');
  const [budget, setBudget]       = useState('');
  const [email, setEmail]         = useState('');
  const [emailError, setEmailError] = useState('');
  const [loading, setLoading]     = useState(false);
  const [linkedin, setLinkedin]   = useState('');
  const [instagram, setInstagram] = useState('');
  const [tiktok, setTiktok]       = useState('');
  const [wizScore, setWizScore]   = useState(null);
  const [prevScore, setPrevScore] = useState(0);
  const [displayScore, setDisplayScore] = useState(0);
  const [tickerIdx, setTickerIdx] = useState(0);
  const [scorePulsing, setScorePulsing] = useState(false);
  const [liveScore, setLiveScore]       = useState(null);
  const [liveDomain, setLiveDomain]     = useState('');
  const domainRef = useRef('');

  const CATS = [
    'SaaS',
    'Fintech',
    'Food & Beverage',
    'Beauty & Personal Care',
    'Fashion & Apparel',
    'Health & Wellness',
    'Consumer Electronics',
    'Education',
    'Hospitality',
    'Luxury',
    'Retail',
    'B2B Services',
    'Media & Entertainment',
    'Healthcare',
  ];
  const BUDGETS = T.wizardBudgets || [['Under $10K','Testing the market'],['$10K – $30K','Competitive entry'],['$30K – $70K','Serious market play'],['$70K+','Category leadership']];
  const tickers = T.bridgeTicker || [];

  const RING_R = 56, RING_C = 2 * Math.PI * RING_R;

  // Score roll animation
  useEffect(() => {
    if (!wizScore) return;
    if (reduceMotion) { setDisplayScore(wizScore.score); return; }
    const from = prevScore, to = wizScore.score;
    const t0 = performance.now();
    const ease = p => 1 - Math.pow(1 - p, 3);
    let raf;
    const tick = now => {
      const p = Math.min(1, (now - t0) / 900);
      setDisplayScore(Math.round(from + (to - from) * ease(p)));
      if (p < 1) raf = requestAnimationFrame(tick); else setDisplayScore(to);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [wizScore]);

  // Ring pulse on score change
  useEffect(() => {
    if (!wizScore) return;
    setScorePulsing(true);
    const id = setTimeout(() => setScorePulsing(false), 950);
    return () => clearTimeout(id);
  }, [wizScore]);

  // Ticker rotation on step 0
  useEffect(() => {
    if (step !== 0 || !tickers.length) return;
    const id = setInterval(() => setTickerIdx(i => (i + 1) % tickers.length), 5000);
    return () => clearInterval(id);
  }, [step]);

  const parseDomain = raw => {
    const n = /^https?:\/\//.test(raw) ? raw : 'https://' + raw;
    try { return new URL(n).hostname.replace(/^www\./, ''); }
    catch { return raw.replace(/^https?:\/\//, '').replace(/^www\./, '').split('/')[0]; }
  };

  const toCatKey = c => c.toLowerCase().replace(/[\s&/]+/g, '_');

  const handleUrl = async () => {
    const trimmed = url.trim();
    if (!trimmed) { setUrlError(T.heroUrlError); return; }
    const dom = parseDomain(trimmed);
    if (!dom || dom.length < 3) { setUrlError(T.heroUrlError); return; }
    domainRef.current = dom;
    setUrlError('');
    setLoading(true);
    const normalized = /^https?:\/\//.test(trimmed) ? trimmed : 'https://' + trimmed;
    fetch('/api/preview', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({url:normalized}) }).catch(()=>{});
    if (!reduceMotion) await new Promise(r => setTimeout(r, 1100));
    const sr = scoreFor({ domain: dom, tier: 'preview', category: 'unknown' });
    setPrevScore(0); setDisplayScore(0); setWizScore(sr);
    setLoading(false); setStep(1);
    if (window.activateMap) window.activateMap();
    if (window.gtag) window.gtag('event', 'wizard_url', { domain: dom });
  };

  const handleCategory = cat => {
    setCategory(cat);
    const prev = wizScore.score;
    const sr = scoreFor({ domain: domainRef.current, tier: 'preview', category: toCatKey(cat) });
    setPrevScore(prev); setWizScore(sr);
    setTimeout(() => setStep(2), 420);
  };

  const handleCountry = () => {
    const prev = wizScore.score;
    const sr = scoreFor({ domain: domainRef.current, tier: 'verified', category: toCatKey(category || 'unknown'), hqCountry: country });
    setPrevScore(prev); setWizScore(sr);
    setTimeout(() => setStep(3), 380);
  };

  const handleBudget = val => {
    setBudget(val);
    setTimeout(() => setStep(4), 300);
  };

  const handleEmail = async () => {
    const trimmedEmail = email.trim();
    if (!trimmedEmail) { setEmailError('Required'); return; }
    if (!/^\S+@\S+\.\S+$/.test(trimmedEmail)) { setEmailError('Enter a valid email'); return; }
    if (FREE_DOMAINS.includes(trimmedEmail.split('@')[1]?.toLowerCase())) { setEmailError('Please use your work email'); return; }
    setLoading(true);
    const prev = wizScore.score;
    const sr = scoreFor({ domain: domainRef.current, tier: 'complete', category: toCatKey(category || 'unknown'), hqCountry: country, enrichment: { hasBudget: !!budget, hasLinkedin: !!linkedin, hasInstagram: !!instagram, hasTikTok: !!tiktok } });
    setPrevScore(prev); setWizScore(sr);
    const normalized = /^https?:\/\//.test(url) ? url : 'https://' + url;
    fetch('/api/analyze', {
      method:'POST', headers:{'Content-Type':'application/json'},
      body: JSON.stringify({ email: trimmedEmail, websiteUrl: normalized, hqCountry: country, budget, service: category, companyName:'', phone:'', name:'', linkedinUrl: linkedin, metaUrl: instagram, tiktokUrl: tiktok, lang: document.documentElement.lang || 'en', referrer: document.referrer || '', landing_url: window.location.href }),
    }).catch(()=>{});
    if (window.gtag) window.gtag('event', 'wizard_complete', { score: sr.score });
    if (!reduceMotion) await new Promise(r => setTimeout(r, 600));
    setLoading(false); setStep(6);
    if (onComplete) onComplete({ email: trimmedEmail, url, category, country, budget, score: sr.score });
  };

  const reset = () => {
    setStep(0); setUrl(''); setCategory(''); setCountry(''); setBudget(''); setEmail('');
    setLinkedin(''); setInstagram(''); setTiktok('');
    setWizScore(null); setPrevScore(0); setDisplayScore(0); setScorePulsing(false);
  };

  const conf = wizScore ? wizScore.confidence : 0;
  const ringColor = displayScore >= 70 ? '#1A9A4A' : displayScore >= 46 ? '#D97706' : '#E8192C';
  const tierIdx = wizScore ? ['preview','verified','complete','complete-skip'].indexOf(wizScore.tier) : -1;
  const tierLabel = (T.confidenceLabel && tierIdx >= 0) ? T.confidenceLabel[tierIdx] : '';
  const delta = wizScore ? wizScore.score - prevScore : 0;
  const gapsCount = wizScore ? (displayScore >= 70 ? 1 : displayScore >= 46 ? 2 : 3) : 0;

  return (
    <div className={`wizard${step >= 1 ? ' wizard--active' : ''}`}>

      {/* Left column — score ring, anchored while questions change on right */}
      {step >= 1 && (
        <div className="wizard-left">
          <div className={`wizard-score${step === 6 ? ' wizard-score--done' : ''}`}>
            <div className={`wizard-score__ring-wrap${scorePulsing ? ' is-pulsing' : ''}`}>
              <svg viewBox="0 0 140 140" className="wizard-score__svg" aria-hidden="true">
                {/* Instrument tick marks — 12 marks around the bezel */}
                {[...Array(12)].map((_, i) => {
                  const angle = (i / 12) * 2 * Math.PI;
                  const cos = Math.cos(angle), sin = Math.sin(angle);
                  const isMajor = i % 3 === 0;
                  const rInner = isMajor ? 60 : 62, rOuter = 66;
                  return <line key={i}
                    x1={70 + rInner * cos} y1={70 + rInner * sin}
                    x2={70 + rOuter * cos} y2={70 + rOuter * sin}
                    stroke="rgba(255,255,255,0.22)" strokeWidth={isMajor ? 2 : 1}
                    strokeLinecap="round"
                  />;
                })}
                {/* Ring track */}
                <circle cx="70" cy="70" r={RING_R} fill="none" stroke="var(--ring-track)" strokeWidth="7"/>
                {/* Score fill */}
                <circle cx="70" cy="70" r={RING_R} fill="none" stroke={ringColor} strokeWidth="7"
                  strokeLinecap="round"
                  strokeDasharray={`${(displayScore / 100) * RING_C} ${RING_C}`}
                  strokeDashoffset={RING_C * 0.25}
                  style={{transition:'stroke-dasharray 0.85s ease, stroke 0.5s ease'}}
                />
                {/* Score glow layer */}
                <circle cx="70" cy="70" r={RING_R} fill="none" stroke={ringColor} strokeWidth="3"
                  strokeLinecap="round" opacity="0.28"
                  strokeDasharray={`${(displayScore / 100) * RING_C} ${RING_C}`}
                  strokeDashoffset={RING_C * 0.25}
                  style={{transition:'stroke-dasharray 0.85s ease, stroke 0.5s ease', filter:'blur(3px)'}}
                />
              </svg>
              <div className="wizard-score__inner">
                <span className="wizard-score__num" style={{color: ringColor}}>{displayScore}</span>
                <span className="wizard-score__den">/100</span>
              </div>
            </div>
            <div className="wizard-score__meta">
              {delta > 0 && step < 6 && <span className="wizard-score__delta" key={displayScore}>▲ +{delta}</span>}
              {step >= 1 && step < 6 && gapsCount > 0 && <span className="wizard-score__gaps">{gapsCount} gap{gapsCount > 1 ? 's' : ''} identified</span>}
              {step < 6 && <span className="wizard-score__tier">{tierLabel}</span>}
              {step === 6 && <span className="wizard-score__tier" style={{color:'#1A9A4A'}}>Complete</span>}
            </div>
            {step >= 1 && step <= 5 && wizScore && (
              <p className="wizard-score__band">
                {displayScore >= 70 ? 'Entry-ready. Focus: execution.' : displayScore >= 46 ? 'Strong foundation. Gaps to close.' : 'Significant gaps. Fix before entry.'}
              </p>
            )}
            {step >= 1 && step <= 5 && (
              <p className="wizard-score__method">Brand fit · Market timing · Competitive density · Channel readiness · Persona depth · Budget calibration</p>
            )}
          </div>

          {step >= 1 && step <= 5 && (
            <div className="wizard-progress" aria-label="Progress">
              {[1,2,3,4,5].map(s => (
                <span key={s} className={`wizard-progress__dot${step >= s ? ' is-active' : ''}`}/>
              ))}
            </div>
          )}
        </div>
      )}

      {/* Right column — step content */}
      <div className="wizard-content">

        {step === 0 && (
          <div className="wizard-step0-grid">
            <div className="wizard-step0-left">
              <div className="wizard-step" key="s0">
                <span className="wizard-eyebrow">{T.eyebrow}</span>
                <h1 className="wizard-headline">{T.headline}</h1>
                <p className="wizard-subhead">{T.subhead}</p>
                <div className="hero-proof">
                  <span className="hero-proof-label">Trusted by</span>
                  <span className="hero-proof-names">Mayo Clinic &nbsp;·&nbsp; HSBC &nbsp;·&nbsp; Park Hyatt &nbsp;·&nbsp; GoPro</span>
                </div>
                <div className="wizard-stats-atf">
                  <div className="wizard-stats-atf__item">
                    <span className="wizard-stats-atf__num">15+</span>
                    <span className="wizard-stats-atf__label">Years in Indonesia</span>
                  </div>
                  <div className="wizard-stats-atf__item">
                    <span className="wizard-stats-atf__num">3,000+</span>
                    <span className="wizard-stats-atf__label">Campaigns executed</span>
                  </div>
                  <div className="wizard-stats-atf__item">
                    <span className="wizard-stats-atf__num">9+</span>
                    <span className="wizard-stats-atf__label">Global entry clients</span>
                  </div>
                </div>
                <div className="wizard-url-row">
                  <input className="wizard-url-input" type="text" placeholder={T.heroUrlPh}
                    value={url}
                    onChange={e => {
                      const v = e.target.value;
                      setUrl(v); setUrlError('');
                      const d = parseDomain(v.trim());
                      if (d && d.length >= 3) {
                        setLiveDomain(d);
                        setLiveScore(scoreFor({ domain: d, tier: 'preview', category: 'unknown' }));
                      } else { setLiveScore(null); setLiveDomain(''); }
                    }}
                    onKeyDown={e => e.key === 'Enter' && !loading && handleUrl()}
                    disabled={loading} autoComplete="off" spellCheck="false"
                  />
                  <button className="wizard-url-btn" onClick={handleUrl} disabled={loading}>
                    {loading ? <span className="wizard-spinner"/> : T.heroUrlBtn}
                  </button>
                </div>
                {urlError && <p className="wizard-error">{urlError}</p>}
                {liveScore && (
                  <div className="hero-score-teaser">
                    <span className="hero-score-teaser__num">{liveScore.score}</span>
                    <span className="hero-score-teaser__denom">/100</span>
                    <div className="hero-score-teaser__bar">
                      <div className="hero-score-teaser__fill" style={{width: liveScore.score + '%'}} />
                    </div>
                    <span className="hero-score-teaser__label">Submit for full report</span>
                  </div>
                )}
                <p className="wizard-helper">{T.heroUrlHelper}</p>
                {tickers.length > 0 && <p className="wizard-ticker" key={tickerIdx}>{tickers[tickerIdx]}</p>}
              </div>
            </div>
            <div className="wizard-step0-right">
              <HeroPreviewCard score={liveScore} domain={liveDomain} />
            </div>
          </div>
        )}

        {step === 1 && (
          <div className="wizard-step" key="s1">
            <p className="wizard-step-num">01 / 04</p>
            <h2 className="wizard-q">{T.wizardCatQ}</h2>
            <div className="wizard-pills">
              {CATS.map(c => (
                <button key={c}
                  className={`wizard-pill${category === c ? ' is-selected' : ''}`}
                  onClick={() => handleCategory(c)}>{c}</button>
              ))}
            </div>
            <button className="wizard-skip" onClick={() => { setCategory(''); setStep(2); }}>{T.wizardSkip}</button>
          </div>
        )}

        {step === 2 && (
          <div className="wizard-step" key="s2">
            <p className="wizard-step-num">02 / 04</p>
            <h2 className="wizard-q">{T.wizardCountryQ}</h2>
            <p className="wizard-q-sub" style={{marginBottom:'16px'}}>Brand entry strategy differs significantly by source market. Korean, US, and European brands each face different cultural, regulatory, and channel barriers in Indonesia.</p>
            <select className="wizard-select" value={country} onChange={e => setCountry(e.target.value)}>
              <option value="">{T.selectCountry}</option>
              {HQ_COUNTRIES.map(c => <option key={c} value={c}>{c}</option>)}
            </select>
            <button className="wizard-next-btn" onClick={handleCountry} disabled={!country}>{T.wizardContinue}</button>
            <button className="wizard-skip" onClick={() => setStep(3)}>{T.wizardSkip}</button>
          </div>
        )}

        {step === 3 && (
          <div className="wizard-step" key="s3">
            <p className="wizard-step-num">03 / 04</p>
            <h2 className="wizard-q">{T.wizardBudgetQ}</h2>
            <div className="wizard-budget-tiles">
              {BUDGETS.map(([val, sub]) => (
                <button key={val} className="wizard-budget-tile" onClick={() => handleBudget(val)}>
                  <span className="wizard-budget-tile__val">{val}</span>
                  <span className="wizard-budget-tile__sub">{sub}</span>
                </button>
              ))}
            </div>
            <button className="wizard-skip" onClick={() => setStep(4)}>{T.wizardSkip}</button>
          </div>
        )}

        {step === 4 && (
          <div className="wizard-step" key="s4">
            <p className="wizard-step-num">04 / 04</p>
            <h2 className="wizard-q">{T.wizardSocialsQ || 'Make your report sharper.'}</h2>
            <p className="wizard-q-sub">{T.wizardSocialsNote || 'Optional. Each profile we scan adds more specific personas, competitors, and GTM depth.'}</p>
            <div style={{display:'flex',flexDirection:'column',gap:'10px',width:'100%'}}>
              <input className="wizard-email-input" type="url" placeholder="https://linkedin.com/company/…"
                value={linkedin} onChange={e => setLinkedin(e.target.value)} />
              <input className="wizard-email-input" type="url" placeholder="https://instagram.com/yourbrand"
                value={instagram} onChange={e => setInstagram(e.target.value)} />
              <input className="wizard-email-input" type="url" placeholder="https://tiktok.com/@yourbrand"
                value={tiktok} onChange={e => setTiktok(e.target.value)} />
            </div>
            <button className="wizard-next-btn" onClick={() => setStep(5)} style={{marginTop:'16px'}}>
              {(linkedin || instagram || tiktok) ? (T.wizardSocialsBtn || 'Add to my report →') : (T.wizardContinue || 'Continue →')}
            </button>
            <button className="wizard-skip" onClick={() => setStep(5)}>{T.wizardSkip}</button>
          </div>
        )}

        {step === 5 && (
          <div className="wizard-step" key="s5">
            <h2 className="wizard-q">{T.wizardEmailQ}</h2>
            <p className="wizard-q-sub">{T.wizardEmailSub}</p>
            {T.wizardEmailBullets && (
              <ul className="wizard-email-bullets">
                {T.wizardEmailBullets.map((b, i) => (
                  <li key={i} className="wizard-email-bullet"><span className="wizard-bullet-icon">→</span>{b}</li>
                ))}
              </ul>
            )}
            <div className="wizard-email-row">
              <input className="wizard-email-input" type="email" placeholder="jane@yourbrand.com"
                value={email} onChange={e => { setEmail(e.target.value); setEmailError(''); }}
                onKeyDown={e => e.key === 'Enter' && !loading && handleEmail()}
                disabled={loading} autoFocus
              />
              <button className="wizard-submit-btn" onClick={handleEmail} disabled={loading}>
                {loading ? <span className="wizard-spinner"/> : T.wizardSend}
              </button>
            </div>
            {emailError && <p className="wizard-error">{emailError}</p>}
            <p className="wizard-helper">{T.freeNote}</p>
            <p className="wizard-helper" style={{marginTop:'4px',opacity:'0.6'}}>{T.privacyNote}</p>
          </div>
        )}

        {step === 6 && (
          <div className="wizard-step wizard-step--done" key="s6">
            <span className="wizard-done-check">✓</span>
            <h2 className="wizard-done-title">{T.wizardDoneTitle}</h2>
            <p className="wizard-done-sub">{T.successDesc} <strong>{email}</strong></p>
            <div className="wizard-gap-reveal">
              <p className="wizard-gap-reveal__label">What we found</p>
              <p className="wizard-gap-reveal__text">Your assessment identified <strong>{gapsCount} gap{gapsCount > 1 ? 's' : ''}</strong> between your current brand position and what Indonesia entry requires. Your full assessment shows exactly which to fix first and what each costs you if left unaddressed.</p>
            </div>
            <p className="wizard-done-note">{T.successSpam}</p>
            <div className="wizard-done-actions">
              <a className="wizard-book-btn" href="https://calendly.com/ideoworks" target="_blank" rel="noopener noreferrer">{T.successBook}</a>
              <button className="wizard-reset" onClick={reset}>{T.successAnother}</button>
            </div>
          </div>
        )}

      </div>
    </div>
  );
}

/* ── Score Toast ─────────────────────────────────────────────────────── */
function ScoreToast({ toast, onDismiss }) {
  useEffect(() => {
    if (!toast) return;
    const id = setTimeout(onDismiss, 4800);
    return () => clearTimeout(id);
  }, [toast]);
  if (!toast) return null;
  let msg = '';
  if (toast.type === 'verified') msg = T.toastVerified.replace('{delta}', toast.delta);
  else if (toast.type === 'complete') msg = T.toastComplete;
  else msg = T.toastSkip;
  return (
    <div className="score-toast" role="status" aria-live="polite" onClick={onDismiss}>
      {msg}
    </div>
  );
}

/* ── Upgrade Strip ───────────────────────────────────────────────────── */
function UpgradeStrip({ tier }) {
  if (tier !== 'preview' && tier !== 'verified') return null;
  const msg = tier === 'verified' ? T.upgradeStripVerified : T.upgradeStripPreview;
  return (
    <div className={`upgrade-strip upgrade-strip--${tier}`} role="note">
      {msg}
    </div>
  );
}

/* ── Data Inputs Dots ────────────────────────────────────────────────── */
function DataInputsDots({ filled }) {
  const dots = T.dataInputDots || ['URL','Email','Country','Socials','Budget','Category'];
  return (
    <div className="data-inputs-dots">
      <span className="data-inputs-dots__label">{T.dataInputsLabel}</span>
      <div className="data-inputs-dots__row">
        {dots.map((d, i) => (
          <span key={d} className={`data-inputs-dots__dot${filled[i] ? ' is-filled' : ''}`} title={d}>
            <span className="data-inputs-dots__pip" />
            <span className="data-inputs-dots__name">{d}</span>
          </span>
        ))}
      </div>
    </div>
  );
}

/* ── Conversion Bridge ───────────────────────────────────────────────── */
function ConversionBridge({ scoreData, tier, onUnlock }) {
  const [tickerIdx, setTickerIdx] = useState(0);
  const tickers = T.bridgeTicker || [];

  useEffect(() => {
    if (!tickers.length) return;
    const id = setInterval(() => setTickerIdx(i => (i + 1) % tickers.length), 6000);
    return () => clearInterval(id);
  }, []);

  if (!scoreData || tier === 'idle') return null;
  const { score } = scoreData;
  let h2 = score >= 65 ? T.bridgeH2High : score >= 50 ? T.bridgeH2Mid : T.bridgeH2Low;
  h2 = h2.replace('{score}', score);

  const lockedCards = [
    { label: T.lockedPersona, visible: T.bridgePersonaVisible.replace('{N}','1').replace('{a}','24').replace('{b}','35') },
    { label: T.lockedGtm,     visible: T.bridgeGtmVisible },
    { label: T.lockedBudget,  visible: T.bridgeBudgetVisible },
  ];
  const isLocked = tier === 'preview';

  return (
    <section className="conversion-bridge reveal" aria-label="What the full report reveals">
      <div className="wrap">
        <h2 className="conversion-bridge__h2">{h2}</h2>
        <div className="conversion-bridge__cards">
          {lockedCards.map(c => (
            <div key={c.label} className={`cb-card${isLocked ? ' cb-card--locked' : ''}`}>
              <span className="cb-card__label">{c.label}</span>
              {isLocked ? (
                <span className="cb-card__locked">{T.bridgeLocked}</span>
              ) : (
                <span className="cb-card__preview">{c.visible}</span>
              )}
            </div>
          ))}
        </div>
        <div className="conversion-bridge__cta-row">
          <button className="cb-unlock-btn" onClick={onUnlock}>{T.bridgeCta}</button>
          <div className="cb-delivery">
            {(T.bridgeDelivery || []).map(d => <span key={d} className="cb-delivery__item">{d}</span>)}
          </div>
        </div>
        {tickers.length > 0 && (
          <div className="cb-ticker" aria-live="off">
            <span key={tickerIdx} className="cb-ticker__line">{tickers[tickerIdx]}</span>
          </div>
        )}
      </div>
    </section>
  );
}

/* ── Main App ────────────────────────────────────────────────────────── */
function App() {
  const [t, setTweak]     = useTweaks(TWEAK_DEFAULTS);
  const [submitState, setSubmitState] = useState('idle'); // 'idle'|'step2'|'done'
  const [serverError, setServerError] = useState('');
  const [form, setForm] = useState({
    name: '', email: '', phoneCode: '+62', phone: '',
    websiteUrl: '', hqCountry: '', budget: BUDGETS[0],
    service: SERVICES[0], linkedinUrl: '', metaUrl: '', tiktokUrl: '',
  });
  const [errors, setErrors] = useState({});

  // Hero interactive audit
  const [heroUrl, setHeroUrl]           = useState('');
  const [heroUrlError, setHeroUrlError] = useState('');
  const [heroAuditState, setHeroAuditState] = useState('empty'); // 'empty'|'loading'|'populated'|'blocked'
  const [heroResult, setHeroResult]     = useState(null);
  const [heroRunCount, setHeroRunCount] = useState(74);
  const heroCache = useRef({});

  // Scoring & tier state
  const [heroTier, setHeroTier]     = useState('idle');
  const [scoreData, setScoreData]   = useState(null);
  const [scoreToast, setScoreToast] = useState(null); // {type, delta}
  const [dataFilled, setDataFilled] = useState([false,false,false,false,false,false]);

  const orbRef = useRef(null);
  const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  const isCoarse     = window.matchMedia('(pointer: coarse)').matches || window.innerWidth < 1024;

  // Sticky CTA
  const [showSticky, setShowSticky]           = useState(false);
  const [stickyDismissed, setStickyDismissed] = useState(false);
  const [heroInView, setHeroInView]           = useState(true);
  const [formInView, setFormInView]           = useState(false);
  const lastScrollY    = useRef(0);
  const scrollTimeout  = useRef(null);
  const [scrollDir, setScrollDir] = useState('idle'); // 'up'|'down'|'idle'

  const updateForm = (k, v) => setForm(f => ({ ...f, [k]: v }));

  useEffect(() => {
    const r = document.documentElement;
    r.style.setProperty('--accent', t.accent);
    r.style.setProperty('--accent-soft', t.accent + '1A');
    r.style.setProperty('--headline-size', t.headlineSize + 'px');
    r.style.setProperty('--dot-opacity', t.dotGridOpacity / 100);
    r.style.setProperty('--scan-speed', t.scanLineSpeed + 's');
  }, [t.accent, t.headlineSize, t.dotGridOpacity, t.scanLineSpeed]);

  useEffect(() => {
    if (!t.showCursorOrb || isCoarse || reduceMotion || !orbRef.current) return;
    let tx = window.innerWidth / 2, ty = window.innerHeight / 2, cx = tx, cy = ty;
    const onMove = e => { tx = e.clientX; ty = e.clientY; };
    document.addEventListener('mousemove', onMove, { passive: true });
    let raf;
    const tick = () => {
      cx += (tx - cx) * 0.12; cy += (ty - cy) * 0.12;
      if (orbRef.current) { orbRef.current.style.left = cx + 'px'; orbRef.current.style.top = cy + 'px'; }
      raf = requestAnimationFrame(tick);
    };
    tick();
    return () => { document.removeEventListener('mousemove', onMove); cancelAnimationFrame(raf); };
  }, [t.showCursorOrb, isCoarse, reduceMotion]);

  useEffect(() => {
    const counters = document.querySelectorAll('.counter');
    const easeOut  = p => 1 - Math.pow(1 - p, 3);
    const animate  = el => {
      const target = parseInt(el.dataset.target, 10) || 0;
      const suffix = el.dataset.suffix || '';
      if (reduceMotion) { el.textContent = target + suffix; return; }
      const start = performance.now();
      const step  = now => {
        const p = Math.min(1, (now - start) / 1200);
        el.textContent = Math.floor(easeOut(p) * target) + suffix;
        if (p < 1) requestAnimationFrame(step); else el.textContent = target + suffix;
      };
      requestAnimationFrame(step);
    };
    if ('IntersectionObserver' in window) {
      const io = new IntersectionObserver(entries => {
        entries.forEach(e => { if (e.isIntersecting) { animate(e.target); io.unobserve(e.target); } });
      }, { threshold: 0.4 });
      counters.forEach(c => io.observe(c));
      return () => io.disconnect();
    }
    counters.forEach(animate);
  }, [t.showStats, t.showHistory]);

  useEffect(() => {
    const els = document.querySelectorAll('.reveal');
    if (reduceMotion || !('IntersectionObserver' in window)) {
      els.forEach(el => el.classList.add('is-revealed'));
      return;
    }
    const io = new IntersectionObserver(entries => {
      entries.forEach(e => {
        if (e.isIntersecting) { e.target.classList.add('is-revealed'); io.unobserve(e.target); }
      });
    }, { threshold: 0.08, rootMargin: '0px 0px -48px 0px' });
    els.forEach(el => io.observe(el));
    return () => io.disconnect();
  }, [t.showHistory, reduceMotion]);

  // IntersectionObserver for sticky CTA logic
  useEffect(() => {
    const heroEl = document.querySelector('.hero');
    const formEl = document.querySelector('.form-section');
    if (!heroEl || !formEl) return;
    const io = new IntersectionObserver(entries => {
      entries.forEach(e => {
        if (e.target === heroEl) setHeroInView(e.isIntersecting);
        if (e.target === formEl) {
          setFormInView(e.isIntersecting);
          if (e.isIntersecting) setStickyDismissed(true);
        }
      });
    }, { threshold: 0.05 });
    io.observe(heroEl);
    io.observe(formEl);
    return () => io.disconnect();
  }, []);

  // Scroll direction for sticky CTA
  useEffect(() => {
    const onScroll = () => {
      const y = window.scrollY;
      setScrollDir(y > lastScrollY.current ? 'down' : 'up');
      lastScrollY.current = y;
      clearTimeout(scrollTimeout.current);
      scrollTimeout.current = setTimeout(() => setScrollDir('idle'), 200);
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => { window.removeEventListener('scroll', onScroll); clearTimeout(scrollTimeout.current); };
  }, []);

  // Derived sticky visibility
  useEffect(() => {
    setShowSticky(!stickyDismissed && !heroInView && !formInView && scrollDir !== 'down');
  }, [stickyDismissed, heroInView, formInView, scrollDir]);

  const scrollToForm = () => {
    document.getElementById('form').scrollIntoView({ behavior: reduceMotion ? 'auto' : 'smooth', block: 'start' });
    setTimeout(() => document.getElementById('f-email')?.focus({ preventScroll: true }), 700);
  };

  // Hero URL audit
  const runHeroAudit = async (rawUrl) => {
    const trimmed = (rawUrl || '').trim();
    if (!trimmed) { setHeroUrlError(T.heroUrlError); return; }
    const normalized = /^https?:\/\//.test(trimmed) ? trimmed : 'https://' + trimmed;
    let domain;
    try { domain = new URL(normalized).hostname; }
    catch { setHeroUrlError(T.heroUrlError); return; }
    setHeroUrlError('');

    if (heroCache.current[domain]) {
      setHeroResult(heroCache.current[domain]);
      setHeroAuditState('populated');
      return;
    }

    setHeroAuditState('loading');
    setHeroRunCount(c => c + 1);
    if (window.gtag) window.gtag('event', 'preview_url_submitted', { domain });

    try {
      const res  = await fetch('/api/preview', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: normalized }) });
      const data = await res.json();
      heroCache.current[domain] = data;
      setHeroResult(data);
      const sr = scoreFor({ domain, tier: 'preview', category: (data.category || 'unknown') });
      setScoreData(sr);
      setHeroTier('preview');
      setDataFilled(f => { const n=[...f]; n[0]=true; return n; });
      setTimeout(() => {
        setHeroAuditState(data.crawlBlocked ? 'blocked' : 'populated');
        if (window.gtag) window.gtag('event', 'preview_animation_completed', { domain, score: data.score });
      }, 1500);
    } catch {
      setHeroAuditState('empty');
      setHeroUrlError(T.heroUrlError);
    }
  };

  const onHeroUnlock = () => {
    if (window.gtag) window.gtag('event', 'preview_unlock_clicked');
    const trimmed = heroUrl.trim();
    const normalized = /^https?:\/\//.test(trimmed) ? trimmed : (trimmed ? 'https://' + trimmed : '');
    if (normalized) updateForm('websiteUrl', normalized);
    scrollToForm();
  };

  // Step 1 validation
  const validateStep1 = () => {
    const e = {};
    if (!form.email.trim()) e.email = 'Required';
    else if (!/^\S+@\S+\.\S+$/.test(form.email)) e.email = 'Enter a valid email';
    else {
      const domain = form.email.split('@')[1]?.toLowerCase() || '';
      if (FREE_DOMAINS.includes(domain)) e.email = 'Please use your work email';
    }
    if (!form.websiteUrl.trim()) e.websiteUrl = 'Required';
    else if (!/^https?:\/\/.+\..+/.test(form.websiteUrl)) e.websiteUrl = 'Enter a valid URL (include https://)';
    if (!form.hqCountry) e.hqCountry = 'Required';
    return e;
  };

  // Step 1 submit — fires analysis, moves to step 2
  const onStep1Submit = async e => {
    e.preventDefault();
    const errs = validateStep1();
    setErrors(errs);
    if (Object.keys(errs).length) return;

    const phoneCode = COUNTRY_TO_PHONE[form.hqCountry] || '+62';
    updateForm('phoneCode', phoneCode);
    setSubmitState('step2');
    setServerError('');
    if (window.gtag) window.gtag('event', 'form_step1_submitted');

    const verDomain = form.websiteUrl.trim().replace(/^https?:\/\//, '').replace(/^www\./, '').split('/')[0];
    const vsr = scoreFor({ domain: verDomain, tier: 'verified', hqCountry: form.hqCountry, category: scoreData ? scoreData.category : 'unknown' });
    setScoreData(vsr);
    setHeroTier('verified');
    setDataFilled(f => { const n=[...f]; n[1]=true; n[2]=true; return n; });
    setScoreToast({ type: 'verified', delta: vsr.delta });
    window.dispatchEvent(new CustomEvent('tier-transition', { detail: { tier:'verified', score:vsr.score, delta:vsr.delta } }));

    // Fire & forget — email delivery does NOT depend on step 2
    fetch('/api/analyze', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        companyName: '', email: form.email.trim(), phone: '',
        websiteUrl: form.websiteUrl.trim(), hqCountry: form.hqCountry,
        budget: '', service: SERVICES[0],
        linkedinUrl: '', metaUrl: '', tiktokUrl: '',
        lang: document.documentElement.lang || 'en',
        referrer: document.referrer || '',
        landing_url: window.location.href,
      }),
    }).catch(() => {});
  };

  // Step 2 submit — optional enrichment only
  const onStep2Submit = async e => {
    e.preventDefault();
    if (window.gtag) window.gtag('event', 'form_step2_submitted');
    const enrichment = {
      hasLinkedin:  !!form.linkedinUrl,
      hasInstagram: !!form.metaUrl,
      hasTikTok:    !!form.tiktokUrl,
      hasBudget:    !!(form.budget && form.budget !== BUDGETS[0]),
    };
    const cDomain = form.websiteUrl.trim().replace(/^https?:\/\//, '').replace(/^www\./, '').split('/')[0];
    const csr = scoreFor({ domain: cDomain, tier: 'complete', hqCountry: form.hqCountry, category: scoreData ? scoreData.category : 'unknown', enrichment });
    setScoreData(csr);
    setHeroTier('complete');
    setDataFilled([true,true,true,!!(form.metaUrl||form.tiktokUrl),enrichment.hasBudget,true]);
    setScoreToast({ type: 'complete', delta: csr.delta });
    window.dispatchEvent(new CustomEvent('tier-transition', { detail: { tier:'complete', score:csr.score, delta:csr.delta } }));
    try {
      await fetch('/api/enrich', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          email: form.email, name: form.name,
          phone: form.phone ? form.phoneCode + form.phone : '',
          budget: form.budget, service: form.service,
          linkedinUrl: form.linkedinUrl, metaUrl: form.metaUrl, tiktokUrl: form.tiktokUrl,
        }),
      });
    } catch {}
    setSubmitState('done');
  };

  const skipStep2 = () => {
    if (window.gtag) window.gtag('event', 'form_step2_skipped');
    if (scoreData) {
      const sDomain = form.websiteUrl.trim().replace(/^https?:\/\//, '').replace(/^www\./, '').split('/')[0];
      const ssr = scoreFor({ domain: sDomain, tier: 'complete-skip', hqCountry: form.hqCountry, category: scoreData.category });
      setScoreData(ssr);
      setHeroTier('complete-skip');
      setScoreToast({ type: 'skip' });
      window.dispatchEvent(new CustomEvent('tier-transition', { detail: { tier:'complete-skip', score:ssr.score } }));
    }
    setSubmitState('done');
  };

  const resetForm = () => {
    setForm({ name:'', email:'', phoneCode:'+62', phone:'', websiteUrl:'', hqCountry:'', budget:BUDGETS[0], service:SERVICES[0], linkedinUrl:'', metaUrl:'', tiktokUrl:'' });
    setErrors({}); setServerError(''); setSubmitState('idle');
  };

  const headlineLines = (LANG !== 'en' ? T.headline : t.headline).split('\n');
  const stagger = t.wordRevealStagger / 1000;
  let wordIdx = 0;

  return (
    <>
      {t.showDotGrid   && <div className="bg-dotgrid" aria-hidden="true" />}
      {t.showScanLine  && <div className="bg-scanline" aria-hidden="true" />}
      {t.showCursorOrb && !isCoarse && <div className="bg-orb" ref={orbRef} aria-hidden="true" />}

      <a href="#top" className="wordmark" aria-label="Ideoworks">
        <span className="wordmark__mark" aria-hidden="true">
          <svg viewBox="0 0 32 32" width="22" height="22">
            <circle cx="16" cy="16" r="14" fill="none" stroke="currentColor" strokeWidth="1.4"/>
            <circle cx="16" cy="16" r="3.2" fill="currentColor"/>
          </svg>
        </span>
        <span className="wordmark__type">IDEO<b>WORKS</b></span>
      </a>
      <LanguageSwitcher />
      <ScoreToast toast={scoreToast} onDismiss={() => setScoreToast(null)} />

      <main id="top">
        {/* ── Hero ─────────────────────────────────────────────── */}
        <section className="hero hero--wizard" data-screen-label="01 Hero">
          <img className="hero-map-bg" src="/assets/indonesia-clean.svg" alt="" aria-hidden="true" loading="lazy" />
          <div className="hero-vignette" aria-hidden="true" />
          <div className="wrap">
            <AuditWizard reduceMotion={reduceMotion} onComplete={data => {
              if (data.email)   updateForm('email', data.email);
              if (data.url)     updateForm('websiteUrl', /^https?:\/\//.test(data.url) ? data.url : 'https://' + data.url);
              if (data.country) updateForm('hqCountry', data.country);
            }} />
          </div>
          <div className="hero-scroll-hint">Scroll</div>
        </section>


        {/* ── The Window ───────────────────────────────────────── */}
        {t.showHistory && (
          <section className="indonesia-now" data-screen-label="02 Market Timing">
            <div className="wrap">
              <header className="section-head reveal">
                <span className="eyebrow"><span className="dot" />Market Timing</span>
                <h2>The window that <span className="em">24 months ago did not exist.</span></h2>
              </header>
              <div className="indonesia-now__body reveal reveal--d1">
                <p>Indonesia's social commerce infrastructure changed materially in late 2023. TikTok Shop's forced closure, followed by its government-sanctioned reopening through Tokopedia, produced a new commerce layer that is now maturing. Brands building creator relationships here in 2024 and 2025 are accumulating first-mover algorithmic position that was not available in 2022.</p>
                <p>Simultaneously, Indonesia's digital middle class reached approximately 85 million households in 2024, with disposable income sufficient to buy international brands at home-market price points across premium categories. The 2024-to-2026 window is where purchasing power and commerce infrastructure maturation converge. In fast-moving categories, the early distribution agreements are being signed now.</p>
              </div>
              <div className="indonesia-now__barriers reveal reveal--d2">
                <details className="barrier-block">
                  <summary className="barrier-block__tag">Platform and channel architecture</summary>
                  <p className="barrier-block__body">Indonesia's media and commerce stack is architecturally different from every other market in Asia Pacific. TikTok Shop, Tokopedia, Shopee, local premium digital publishers, and a KOL ecosystem operating in four distinct regional tiers are not interchangeable with channels that worked in Singapore, Korea, or Australia. Brands that enter without knowing which channels activate which city tiers, in which sequence, waste 40 to 60 percent of their first-year media spend on architecturally wrong placements.</p>
                </details>
                <details className="barrier-block">
                  <summary className="barrier-block__tag">Cultural distance</summary>
                  <p className="barrier-block__body">The distance between your home market's consumer psychology and Indonesia's is not a variable to minimize. It is the variable that eliminates competitors who do not invest in it. The cultural gap is exactly as large as your competitors think it is. For the brand with local intelligence, that gap is a moat.</p>
                </details>
                <details className="barrier-block">
                  <summary className="barrier-block__tag">Market fragmentation</summary>
                  <p className="barrier-block__body">Seventeen thousand islands, four major regional languages, and a GDP-per-capita variance of more than four to one between Tier 1 and Tier 3 cities. For brands using broadcast strategy, this is a cost problem. For brands using precision strategy, it is a filter.</p>
                </details>
              </div>
              <div className="indonesia-now__competitor reveal reveal--d3">
                <span className="indonesia-now__competitor-label">The competitive picture</span>
                <p>Marketing teams at five to seven global brands per category are actively conducting Indonesia market intelligence right now. In fast-moving segments like beauty, health and wellness, and B2B SaaS, the first distribution agreements are already being signed. The window is closing, not closed.</p>
              </div>
            </div>
          </section>
        )}

        {/* ── Intelligence Layers ──────────────────────────────── */}
        <section className="scope" id="scope" data-screen-label="03 Intelligence Layers">
          <div className="wrap">
            <header className="section-head reveal">
              <span className="eyebrow"><span className="dot" />The Assessment</span>
              <h2>{T.scopeTitle} <span className="em">{T.scopeEm}</span></h2>
              <p className="section-subtext">Your brand URL is scored against six areas. Each is a dimension where global brands have made category-specific, preventable mistakes entering Indonesia. Each dimension is scored from live Indonesia market data, benchmarked against campaigns run here since 2010.</p>
            </header>
            <div className="intel-grid reveal">
              {T.scopeCards.map(([label, desc], i) => (
                <div className="intel-item" key={i}>
                  <div className="intel-num" aria-hidden="true">{String(i + 1).padStart(2, '0')}</div>
                  <div className="intel-body">
                    <h3 className="intel-label">{label}</h3>
                    <p className="intel-desc">{desc}</p>
                  </div>
                </div>
              ))}
            </div>
          </div>
        </section>

        {/* ── Agency × AI Pipeline ─────────────────────────────── */}
        {t.showHistory && (
          <section className="pipeline" data-screen-label="04 Agency Pipeline">
            <div className="wrap">
              <header className="section-head reveal">
                <span className="eyebrow"><span className="dot" />How It Works</span>
                <h2>The agency layer <span className="em">is the point.</span></h2>
                <p className="section-subtext">There are two parts to your assessment. The automated scan runs first. The Jakarta team builds the second.</p>
              </header>
              <div className="pipeline-track reveal">
                <div className="pipeline-step">
                  <span className="pipeline-step__num">01</span>
                  <span className="pipeline-step__tag">90 seconds</span>
                  <h3 className="pipeline-step__title">Automated Scan</h3>
                  <p className="pipeline-step__desc">The tool reads your public digital footprint across 50+ signals: brand search volume, social presence, platform penetration, SEO authority, and category share of voice. Your preview score is ready within 90 seconds. This is the starting framework.</p>
                </div>
                <div className="pipeline-connector" aria-hidden="true">→</div>
                <div className="pipeline-step">
                  <span className="pipeline-step__num">02</span>
                  <span className="pipeline-step__tag">Jakarta, on the ground</span>
                  <h3 className="pipeline-step__title">Agency Layer</h3>
                  <p className="pipeline-step__desc">The Ideoworks team benchmarks your scan against Indonesia's live market conditions: channel costs this team has negotiated, KOL rates this team has paid, and competitive moves observed this week rather than last quarter. This context cannot be scraped or approximated from global data sets. It comes from the team that has executed 3,000+ campaigns in-market.</p>
                </div>
                <div className="pipeline-connector" aria-hidden="true">→</div>
                <div className="pipeline-step">
                  <span className="pipeline-step__num">03</span>
                  <span className="pipeline-step__tag">Written assessment · within 24 hours</span>
                  <h3 className="pipeline-step__title">Your Market Entry Assessment</h3>
                  <p className="pipeline-step__desc">Your written assessment is delivered to your inbox within 24 hours of submission. Four sections, built and reviewed by the Ideoworks Jakarta team:</p>
                  <ul className="pipeline-deliverable">
                    <li>Brand entry readiness score with dimensional breakdown</li>
                    <li>Indonesia-specific persona profiles for your category and city tier</li>
                    <li>90-day GTM sequence: city order, channel priority, KOL tier</li>
                    <li>Three budget tiers at real Indonesia market rates</li>
                  </ul>
                </div>
              </div>
            </div>
          </section>
        )}

        {/* ── Proof Editorial ─────────────────────────────────── */}
        {t.showHistory && (
          <section className="proof-editorial reveal">
            <div className="wrap">
              <div className="proof-editorial__layout">
                <div className="proof-editorial__proof">
                  <span className="proof-editorial__tag">Healthcare · Indonesia Market Entry</span>
                  <h3 className="proof-editorial__client">Mayo Clinic</h3>
                  <p className="proof-editorial__story">Mayo Clinic entered Indonesia targeting the HNWI and UHNWI segment. This is the highest-value outbound medical audience in Southeast Asia, concentrated in Jakarta and Surabaya's premium districts. The brief was awareness and consideration: making Mayo Clinic the unambiguous first choice for complex cases requiring expertise unavailable locally.</p>
                  <p className="proof-editorial__story" style={{marginTop:'14px'}}>Ideoworks mapped the channels and audience profiles that indexed highest against Indonesia's AB-income segment, then built the targeting and placement strategy to reach them. Precision digital, not broadcast. Tier 1 cities only, where the intended audience lives.</p>
                  <div className="proof-result">
                    <span className="proof-result__item">Healthcare · HNWI / UHNWI segment</span>
                    <span className="proof-result__item">Brand awareness · Consideration</span>
                    <span className="proof-result__item">Precision channel and audience targeting</span>
                    <span className="proof-result__item">Jakarta · Surabaya · Tier 1 only</span>
                  </div>
                  <a className="proof-result__link" href="https://ideoworks.id" target="_blank" rel="noopener noreferrer">See our Indonesia work →</a>
                </div>
                <div className="proof-editorial__roster">
                  <span className="proof-editorial__roster-label">Also across</span>
                  <div className="proof-editorial__names">
                    {[
                      ['HSBC', 'Financial Services'],
                      ['Park Hyatt', 'Luxury Hospitality'],
                      ['GoPro', 'Consumer Electronics'],
                      ['Goodyear', 'Automotive'],
                      ['Calvin Klein', 'Fashion'],
                      ['Danbi Education', 'Education'],
                      ['Verisign', 'Technology'],
                      ['Dunlop', 'Sporting Goods'],
                    ].map(([name, cat]) => (
                      <span key={name} className="proof-editorial__brand-item">
                        <span className="proof-editorial__brand-name">{name}</span>
                        <span className="proof-editorial__brand-cat">{cat}</span>
                      </span>
                    ))}
                  </div>
                  <span className="proof-editorial__tally">9 global brands · 8 industries · 15+ countries of origin</span>
                </div>
              </div>
            </div>
          </section>
        )}

        {/* ── Proof & Trust ─────────────────────────────────────── */}
        {t.showHistory && (
          <section className="who who--lean" id="who" data-screen-label="06 Trust">
            <div className="wrap">
              <header className="section-head reveal">
                <span className="eyebrow"><span className="dot" />{T.whoEyebrow}</span>
                <h2>{T.whoTitle}<span className="em">{T.whoTitleEm}</span></h2>
                <p className="section-subtext">{T.whoLede}</p>
              </header>
              <div className="partners-bar reveal reveal--d2">
                <span className="trust-bar__label">{T.recognizedBy}</span>
                <div className="partners-bar__row">
                  <PremierBadge />
                </div>
              </div>
              <div className="proof-human reveal reveal--d2">
                <div className="proof-human__avatar proof-human__avatar--photo" aria-hidden="true"><img src="/assets/arianto-bigman.png" alt="Arianto Bigman" /></div>
                <div className="proof-human__body">
                  <span className="proof-human__name">Arianto Bigman</span>
                  <span className="proof-human__title">Managing Director · Ideoworks · Jakarta</span>
                  <p className="proof-human__quote">"Every score we produce is benchmarked against campaigns this team has actually run in Indonesia. If we have not negotiated that channel cost or paid that KOL rate ourselves, it does not go into the assessment."</p>
                </div>
              </div>
              <div className="proof-human proof-human--vs reveal reveal--d3">
                <div className="proof-human__avatar proof-human__avatar--photo" aria-hidden="true"><img src="/assets/vienesia-sutrisno.png" alt="Vienesia Sutrisno" /></div>
                <div className="proof-human__body">
                  <span className="proof-human__name">Vienesia Sutrisno</span>
                  <span className="proof-human__title">COO · Ideoworks · Jakarta</span>
                  <p className="proof-human__quote">"The brands that perform here are not necessarily the ones with the largest budgets. They are the ones that arrived knowing which city to enter first, which audience to activate, and which channels those people actually use."</p>
                </div>
              </div>
            </div>
          </section>
        )}

        {/* ── What Happens After ─────────────────────────────── */}
        {t.showHistory && (
          <section className="after-submit" data-screen-label="07 After Submit">
            <div className="wrap">
              <header className="section-head reveal">
                <span className="eyebrow"><span className="dot" />After You Submit</span>
                <h2>Here is exactly what happens <span className="em">after you enter your URL.</span></h2>
              </header>
              <div className="after-submit__timeline reveal reveal--d1">
                <p>Within 90 seconds, your preview score appears on screen. It covers all six dimensions with an initial confidence rating. This is your starting point, built from the automated scan.</p>
                <p>Within 24 hours, your written assessment arrives by email. It is built by the Ideoworks team in Jakarta, calibrated against current Indonesia market conditions. This is the agency layer: the part that no platform produces.</p>
              </div>
              <div className="after-submit__deliverables reveal reveal--d2">
                <span className="after-submit__label">Your assessment contains four sections:</span>
                <div className="after-submit__grid">
                  <div className="after-submit__item">
                    <span className="after-submit__num">01</span>
                    <h3 className="after-submit__title">Brand Entry Readiness</h3>
                    <p className="after-submit__desc">Every dimension scored. Each gap ranked by what it costs you at entry.</p>
                  </div>
                  <div className="after-submit__item">
                    <span className="after-submit__num">02</span>
                    <h3 className="after-submit__title">Persona Profiles</h3>
                    <p className="after-submit__desc">Two to three buyer profiles built for your exact category, city tier, and price point. Not extrapolated from APAC averages.</p>
                  </div>
                  <div className="after-submit__item">
                    <span className="after-submit__num">03</span>
                    <h3 className="after-submit__title">90-Day GTM Sequence</h3>
                    <p className="after-submit__desc">City order, channel priority, KOL tier, and budget allocation for your category and competitive set.</p>
                  </div>
                  <div className="after-submit__item">
                    <span className="after-submit__num">04</span>
                    <h3 className="after-submit__title">Budget Framework</h3>
                    <p className="after-submit__desc">Three spend tiers at real Indonesia market rates, from campaigns run in the last 90 days.</p>
                  </div>
                </div>
              </div>
              <p className="after-submit__close reveal reveal--d3">The assessment is free. There is no sales call unless you ask for one.</p>
            </div>
          </section>
        )}

        {/* ── Form ─────────────────────────────────────────────── */}
        <section className="form-section" id="form" data-screen-label="08 Form">
          <div className="wrap">
            <div className="form-shell reveal">
              <header className="section-head">
                <span className="eyebrow"><span className="dot" />{T.formEyebrow}</span>
                <h2 style={{marginTop:24}}>
                  {submitState === 'done' ? T.formDoneTitle : T.formTitle}
                </h2>
                {submitState === 'idle' && (
                  <>
                    <p className="form-commission-note">Your preview score is ready in 90 seconds. The full written assessment covers brand entry readiness, Indonesia-specific personas, a 90-day GTM sequence, and a budget framework built from real Indonesia market rates. It arrives in your inbox within 24 hours.</p>
                    <div className="sample-preview">
                      <div className="sample-preview__header">
                        <span className="sample-preview__label">Sample · Indonesia Market Entry Assessment</span>
                        <span className="sample-preview__redacted">Redacted</span>
                      </div>
                      <div className="sample-preview__body">
                        <div className="sample-preview__section">
                          <span className="sample-preview__sec-num">01</span>
                          <div>
                            <span className="sample-preview__sec-title">Brand Entry Readiness</span>
                            <div className="sample-preview__bars">
                              {[['Brand Readiness','72'],['Opportunity Score','81'],['Persona Mapping','68'],['Competitive Analysis','74'],['GTM Strategy','77'],['Budget Framework','65']].map(([label, val]) => (
                                <div key={label} className="sample-preview__bar-row">
                                  <span className="sample-preview__bar-label">{label}</span>
                                  <div className="sample-preview__bar-track">
                                    <div className="sample-preview__bar-fill" style={{width: val + '%'}} />
                                  </div>
                                  <span className="sample-preview__bar-val">{val}</span>
                                </div>
                              ))}
                            </div>
                          </div>
                        </div>
                        <div className="sample-preview__section">
                          <span className="sample-preview__sec-num">02</span>
                          <div>
                            <span className="sample-preview__sec-title">Persona Profiles</span>
                            <p className="sample-preview__sec-body">Tier 1 urban professional · Jakarta · Age 28–38 · AB income · ████████ ███ ████ platform behavior ████████ purchase triggers ████</p>
                          </div>
                        </div>
                        <div className="sample-preview__section">
                          <span className="sample-preview__sec-num">03</span>
                          <div>
                            <span className="sample-preview__sec-title">90-Day GTM Sequence</span>
                            <p className="sample-preview__sec-body">Week 1–4: ████████ · Week 5–8: ████ KOL activation ████████ · Week 9–12: ████████ conversion optimization</p>
                          </div>
                        </div>
                        <div className="sample-preview__section">
                          <span className="sample-preview__sec-num">04</span>
                          <div>
                            <span className="sample-preview__sec-title">Budget Framework</span>
                            <p className="sample-preview__sec-body">Minimum viable entry: ████████ · Competitive launch: ████████ · Aggressive capture: ████████ <span className="sample-preview__note">(real Indonesia market rates)</span></p>
                          </div>
                        </div>
                      </div>
                      <p className="sample-preview__cta">Submit your domain to receive your version →</p>
                    </div>
                  </>
                )}
              </header>

              {/* ── Step 1 ── */}
              {submitState === 'idle' && (
                <>
                  <ol className="mini-steps" aria-label="What happens next">
                    <li><span className="mini-steps__num">01</span><span className="mini-steps__lbl">{T.step1Title}</span></li>
                    <li aria-hidden="true" className="mini-steps__sep" />
                    <li><span className="mini-steps__num">02</span><span className="mini-steps__lbl">{T.step2Title}</span></li>
                    <li aria-hidden="true" className="mini-steps__sep" />
                    <li><span className="mini-steps__num">03</span><span className="mini-steps__lbl">{T.step3Title}</span></li>
                  </ol>

                  <form onSubmit={onStep1Submit} noValidate>
                    <FormField id="f-email" label={T.fEmail} type="email" placeholder={T.fEmailPh}
                      value={form.email} onChange={v => updateForm('email',v)}
                      error={errors.email} reduceMotion={reduceMotion} required />

                    <FormField id="f-website" label={T.fWebsite} type="url" placeholder={T.fWebsitePh}
                      value={form.websiteUrl} onChange={v => updateForm('websiteUrl',v)}
                      error={errors.websiteUrl} helper={T.fWebsiteHelper}
                      reduceMotion={reduceMotion} required />

                    <div className="field">
                      <label htmlFor="f-country">{T.fCountry} <span style={{color:'var(--accent)',marginLeft:2}}>*</span></label>
                      <div className="field-row">
                        <select id="f-country" className="field-select-full" value={form.hqCountry}
                          onChange={e => updateForm('hqCountry',e.target.value)} required>
                          <option value="">{T.selectCountry}</option>
                          {HQ_COUNTRIES.map(c => <option key={c} value={c}>{c}</option>)}
                        </select>
                      </div>
                      {errors.hqCountry && <p className="field-error">{errors.hqCountry}</p>}
                    </div>

                    {serverError && (
                      <p style={{fontFamily:'var(--f-mono)',fontSize:'12px',color:'#FF6B6B',margin:'0 0 20px',lineHeight:1.5}}>{serverError}</p>
                    )}

                    <div className="submit-wrap">
                      <button className="submit idle" type="submit">
                        <span className="submit__label">{T.step1Cta}</span>
                        <span className="submit__dot" aria-hidden="true" />
                      </button>
                    </div>

                    <div className="form-foot">
                      <p className="form-microcopy"><span className="reassure-dot" aria-hidden="true" /> {T.freeNote}</p>
                      <p className="form-privacy">{T.privacyNote}</p>
                    </div>
                  </form>
                </>
              )}

              {/* ── Step 2 ── */}
              {submitState === 'step2' && (
                <div className="step2-wrap">
                  <div className="step2-status">
                    <span className="step2-dot" aria-hidden="true" />
                    <span className="step2-status__text">{T.step2Head}</span>
                  </div>
                  <p className="step2-sub">{T.step2Sub}</p>

                  <form onSubmit={onStep2Submit} noValidate>
                    <FormField id="f-name" label={T.fName} type="text" placeholder={T.fNamePh}
                      value={form.name} onChange={v => updateForm('name',v)}
                      optional optionalLabel={T.optional} reduceMotion={reduceMotion} />

                    <div className="field">
                      <label htmlFor="f-phone">
                        {T.fPhone}
                        <span className="field-optional">{T.step2PhoneTag}</span>
                      </label>
                      <div className="field-row phone-row">
                        <select className="phone-code" value={form.phoneCode} onChange={e => updateForm('phoneCode',e.target.value)} aria-label="Country code">
                          {PHONE_CODES.map(c => <option key={c.code} value={c.code}>{c.label}</option>)}
                        </select>
                        <input id="f-phone" type="tel" placeholder={T.fPhonePh}
                          value={form.phone} onChange={e => updateForm('phone',e.target.value)} />
                      </div>
                    </div>

                    <div className="frow frow-2">
                      <div className="field">
                        <label htmlFor="f-budget">{T.fBudget} <span className="field-optional">{T.optional}</span></label>
                        <div className="field-row">
                          <select id="f-budget" className="field-select-full" value={form.budget}
                            onChange={e => updateForm('budget',e.target.value)}>
                            {BUDGETS.map(b => <option key={b} value={b}>{b}</option>)}
                          </select>
                        </div>
                      </div>
                      <div className="field">
                        <label htmlFor="f-service">{T.fService} <span className="field-optional">{T.optional}</span></label>
                        <div className="field-row">
                          <select id="f-service" className="field-select-full" value={form.service}
                            onChange={e => updateForm('service',e.target.value)}>
                            {SERVICES.map(s => <option key={s} value={s}>{s}</option>)}
                          </select>
                        </div>
                      </div>
                    </div>

                    <div className="frow frow-2">
                      <FormField id="f-linkedin" label={T.fLinkedin} type="url"
                        placeholder={T.fLinkedinPh} optional
                        value={form.linkedinUrl} onChange={v => updateForm('linkedinUrl',v)}
                        reduceMotion={reduceMotion} optionalLabel={T.optional} />
                      <FormField id="f-meta" label={T.fMeta} type="url"
                        placeholder={T.fMetaPh} optional
                        value={form.metaUrl} onChange={v => updateForm('metaUrl',v)}
                        reduceMotion={reduceMotion} optionalLabel={T.optional} />
                    </div>

                    <FormField id="f-tiktok" label={T.fTikTok} type="url"
                      placeholder={T.fTikTokPh} optional
                      value={form.tiktokUrl} onChange={v => updateForm('tiktokUrl',v)}
                      reduceMotion={reduceMotion} optionalLabel={T.optional} />

                    <div className="submit-wrap">
                      <button className="submit idle" type="submit">
                        <span className="submit__label">{T.step2Btn}</span>
                        <span className="submit__dot" aria-hidden="true" />
                      </button>
                    </div>

                    <div className="form-foot" style={{alignItems:'center'}}>
                      <button type="button" className="step2-skip" onClick={skipStep2}>{T.step2Skip}</button>
                    </div>
                  </form>
                </div>
              )}

              {/* ── Done ── */}
              {submitState === 'done' && (
                <div className="success">
                  <div className="success__check">
                    <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
                      <polyline points="4,12 9,17 20,6" stroke="var(--accent)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
                    </svg>
                  </div>
                  <h3>{T.successTitle}</h3>
                  <p>{T.successDesc} <strong>{form.email}</strong></p>
                  <p style={{fontSize:'12px',fontFamily:'var(--f-mono)',color:'var(--muted-2)',letterSpacing:'0.04em'}}>{T.successSpam}</p>
                  <div className="success__actions">
                    <a href="https://calendly.com/ideoworks" target="_blank" rel="noopener noreferrer" className="btn-primary">{T.successBook}</a>
                    <button className="btn-ghost-sm" type="button" onClick={resetForm}>{T.successAnother}</button>
                  </div>
                </div>
              )}
            </div>
          </div>
        </section>

        <footer>
          <div className="wrap footer-row">
            <div className="footer-meta">
              <span>© 2026 Ideoworks (PT. Cipta Urban Darsana)</span>
              <span className="footer-sub">Pejaten Barat 46, Jakarta Selatan 12510 · Indonesia</span>
            </div>
            <div className="footer-links">
              <a className="footer-link" href="https://www.instagram.com/ideoworks.id/"
                target="_blank" rel="noopener noreferrer" aria-label="Ideoworks on Instagram">
                <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                  <rect x="3" y="3" width="18" height="18" rx="5"/>
                  <circle cx="12" cy="12" r="4"/>
                  <circle cx="17.5" cy="6.5" r="0.6" fill="currentColor" stroke="none"/>
                </svg>
                @ideoworks.id
              </a>
              <span className="footer-sep">·</span>
              <a className="footer-link" href="https://ideoworks.id" target="_blank" rel="noopener noreferrer">ideoworks.id</a>
            </div>
          </div>
        </footer>
      </main>

      {/* ── Sticky CTA ───────────────────────────────────────── */}
      <div className={`sticky-cta ${showSticky ? 'is-visible' : ''}`} role="region" aria-label="Quick request">
        <span className="sticky-cta__pulse" aria-hidden="true" />
        {scoreData && heroTier !== 'idle' ? (
          <span className="sticky-cta__text">
            <strong>{T.stickyScoreStrong.replace('{score}', scoreData.score)}</strong>
            <span className="sticky-cta__sub">{T.stickyScoreSub}</span>
          </span>
        ) : (
          <span className="sticky-cta__text">
            <strong>{T.stickyStrong}</strong>
            <span className="sticky-cta__sub">{T.stickySub}</span>
          </span>
        )}
        <button className="sticky-cta__btn" type="button" onClick={scrollToForm}>
          {scoreData && heroTier !== 'idle' ? T.stickyScoreBtn : <>{T.stickyBtn} <span aria-hidden="true">→</span></>}
        </button>
        <button className="sticky-cta__close" type="button" aria-label="Dismiss" onClick={() => setStickyDismissed(true)}>×</button>
      </div>

      {/* ── Tweaks panel ─────────────────────────────────────── */}
      <TweaksPanel title="Landing Page · Tweaks">
        <TweakSection label="Brand">
          <TweakColor  label="Accent color"  value={t.accent}       onChange={v => setTweak('accent',v)} />
          <TweakText   label="CTA label"     value={t.ctaLabel}     onChange={v => setTweak('ctaLabel',v)} />
          <TweakText   label="Submit label"  value={t.submitLabel}  onChange={v => setTweak('submitLabel',v)} />
        </TweakSection>
        <TweakSection label="Copy">
          <TweakText   label="Headline"      value={t.headline}     onChange={v => setTweak('headline',v)} />
          <TweakText   label="Subhead"       value={t.subhead}      onChange={v => setTweak('subhead',v)} />
        </TweakSection>
        <TweakSection label="Type">
          <TweakSlider label="Headline size"   value={t.headlineSize}      min={36} max={96} unit="px" onChange={v => setTweak('headlineSize',v)} />
          <TweakSlider label="Word stagger"    value={t.wordRevealStagger} min={0}  max={200} unit="ms" onChange={v => setTweak('wordRevealStagger',v)} />
        </TweakSection>
        <TweakSection label="Sections">
          <TweakToggle label="Who We Are"  value={t.showHistory} onChange={v => setTweak('showHistory',v)} />
          <TweakToggle label="Hero stats"  value={t.showStats}   onChange={v => setTweak('showStats',v)} />
        </TweakSection>
        <TweakSection label="Atmosphere">
          <TweakToggle label="Scan line"          value={t.showScanLine}         onChange={v => setTweak('showScanLine',v)} />
          <TweakToggle label="Cursor orb"          value={t.showCursorOrb}        onChange={v => setTweak('showCursorOrb',v)} />
          <TweakToggle label="Calibration nodes"   value={t.showCalibrationNodes} onChange={v => setTweak('showCalibrationNodes',v)} />
          <TweakToggle label="Dot grid"            value={t.showDotGrid}          onChange={v => setTweak('showDotGrid',v)} />
          <TweakSlider label="Dot grid opacity"    value={t.dotGridOpacity} min={0} max={10} unit="%" onChange={v => setTweak('dotGridOpacity',v)} />
          <TweakSlider label="Scan line cycle"     value={t.scanLineSpeed}  min={2} max={12} unit="s" onChange={v => setTweak('scanLineSpeed',v)} />
        </TweakSection>
      </TweaksPanel>
    </>
  );
}

/* ── Audit Card (interactive, 3 states) ─────────────────────────────── */
function AuditCard({ auditState, result, runCount, onUnlock, crawlBlockText, reduceMotion, scoreData, heroTier, dataFilled }) {
  const DEMO_SCORE  = 74;
  const [score, setScore]       = useState(reduceMotion ? DEMO_SCORE : 0);
  const [loaded, setLoaded]     = useState(false);
  const [tick, setTick]         = useState(0);
  const [signalIdx, setSignalIdx] = useState(0);

  const SIGNALS = [
    { label: 'Cultural fit',          verdict: 'Strong',          tone: 'green'  },
    { label: 'Price positioning',     verdict: 'On point',        tone: 'green'  },
    { label: 'Market Access Friction', verdict: 'Manageable',      tone: 'yellow' },
    { label: 'Local search demand',   verdict: 'Rising',          tone: 'green'  },
    { label: 'Competitor density',    verdict: 'Crowded',         tone: 'yellow' },
    { label: 'Cost-per-acquire',      verdict: 'Below APAC avg',  tone: 'green'  },
  ];
  const CATEGORIES = ['SaaS','Fintech','Hospitality','Consumer','Luxury','B2B Services'];
  const [pillSet, setPillSet] = useState([0, 1, 2]);

  const targetScore = (auditState === 'populated' && result) ? result.score : DEMO_SCORE;
  const displayRows = (auditState === 'populated' && result?.rows) ? result.rows : [
    { label: 'Cultural Fit',          value: 'High',      tone: 'green'  },
    { label: 'Competitor Density',    value: 'Crowded',   tone: 'yellow' },
    { label: 'Market Access Friction', value: 'Medium',    tone: 'accent' },
  ];
  const displayBars = (auditState === 'populated' && result?.bars) ? result.bars : [
    { city: 'Jakarta',  val: 142, pct: 100 },
    { city: 'Surabaya', val: 88,  pct: 62  },
    { city: 'Bandung',  val: 54,  pct: 38  },
    { city: 'Medan',    val: 41,  pct: 29  },
  ];
  const displaySignal = (auditState === 'populated' && result?.signal) ? result.signal : SIGNALS[signalIdx];
  const displayLabel  = (auditState === 'populated' && result?.label) ? result.label : 'Strong Entry Position';
  const displayDelta  = (auditState === 'populated' && result?.comparator) ? result.comparator : '▲ +6 vs. F&B avg';

  // Score animation on mount and on result change
  useEffect(() => {
    const t1 = setTimeout(() => setLoaded(true), reduceMotion ? 0 : 700);
    if (reduceMotion) { setScore(targetScore); return () => clearTimeout(t1); }
    const start = performance.now();
    const startDelay = auditState === 'populated' ? 200 : 700;
    const duration = 1000;
    const easeOut = p => 1 - Math.pow(1 - p, 3);
    let raf;
    const step = now => {
      const elapsed = now - start - startDelay;
      if (elapsed < 0) { raf = requestAnimationFrame(step); return; }
      const p = Math.min(1, elapsed / duration);
      setScore(Math.floor(easeOut(p) * targetScore));
      if (p < 1) raf = requestAnimationFrame(step); else setScore(targetScore);
    };
    raf = requestAnimationFrame(step);
    return () => { clearTimeout(t1); cancelAnimationFrame(raf); };
  }, [reduceMotion, targetScore, auditState]);

  useEffect(() => {
    if (reduceMotion) return;
    const id = setInterval(() => setTick(v => v + 1), 3200);
    return () => clearInterval(id);
  }, [reduceMotion]);

  useEffect(() => {
    if (!loaded || reduceMotion || auditState === 'populated') return;
    const drift = tick % 4 === 0 ? -1 : tick % 4 === 2 ? 1 : 0;
    setScore(DEMO_SCORE + drift);
    setSignalIdx(i => (i + 1) % SIGNALS.length);
    if (tick % 2 === 1) {
      setPillSet(prev => {
        const next = [...prev];
        const replaceAt = tick % 3;
        const used = new Set(next);
        for (let i = 0; i < CATEGORIES.length; i++) {
          const candidate = (prev[replaceAt] + 1 + i) % CATEGORIES.length;
          if (!used.has(candidate)) { next[replaceAt] = candidate; break; }
        }
        return next;
      });
    }
  }, [tick, loaded, reduceMotion, auditState]);

  const isLoading    = auditState === 'loading';
  const isBlocked    = auditState === 'blocked';
  const isPopulated  = auditState === 'populated';
  const isEmpty      = auditState === 'empty';
  const showEmpty    = isEmpty || isLoading;

  return (
    <aside className={`audit-card${isLoading ? ' is-loading' : ''}`} aria-label="Live brand audit preview">
      <div className="audit-head">
        <span className={`audit-pulse${isLoading ? ' is-fast' : ''}`} aria-hidden="true" />
        <span className="audit-head__label">Live · Indonesia</span>
        <span className="audit-head__id">RUN&nbsp;0{runCount}&nbsp;·&nbsp;ID-JKT</span>
      </div>

      {isBlocked ? (
        <div className="audit-blocked">
          <p>{crawlBlockText}</p>
          <button className="audit-blocked__cta" onClick={onUnlock}>Get the full audit →</button>
        </div>
      ) : (
        <>
          <div className="audit-score">
            <span className="audit-score__num" aria-label={`Brand score ${showEmpty ? '—' : score} out of 100`}>
              {showEmpty ? <span style={{color:'var(--muted-2)'}}>—</span> : score}
            </span>
            <span className="audit-score__den">/100</span>
            {!showEmpty && <span className="audit-score__delta" aria-hidden="true">{displayDelta}</span>}
          </div>

          {isLoading && (
            <div className="audit-loading-bar">
              <div className="audit-loading-bar__track"><div className="audit-loading-bar__fill" /></div>
              <p className="audit-loading-bar__label">Scoring against 270M consumer benchmark…</p>
            </div>
          )}

          {!isLoading && (
            <>
              <div className="audit-bar" aria-hidden="true">
                <div className={`audit-bar__fill ${loaded && !showEmpty ? 'is-loaded' : ''}`}
                  style={isPopulated ? {width: score + '%', transition:'width 1.2s cubic-bezier(0.2,0.7,0.2,1)'} : {}} />
              </div>
              {scoreData && heroTier !== 'idle' ? (
                <div className="audit-confidence">
                  <span className="audit-confidence__label">
                    {T.confidenceLabel ? T.confidenceLabel[['preview','verified','complete','complete-skip'].indexOf(heroTier)] || T.confidenceLabel[0] : heroTier}
                  </span>
                  <div className="audit-confidence__bar">
                    <div className="audit-confidence__fill"
                      style={{width: scoreData.confidence + '%', transition:'width 0.8s ease'}} />
                  </div>
                  <span className="audit-confidence__pct">{scoreData.confidence}%</span>
                </div>
              ) : (
                <div className="audit-bar__caption">
                  <span><b>{displayLabel}</b></span>
                  {isPopulated
                    ? <span>Score {score}/100</span>
                    : <span>{showEmpty ? 'Enter your URL to begin' : 'P74 · Top quartile'}</span>
                  }
                </div>
              )}
              {scoreData && dataFilled && (
                <DataInputsDots filled={dataFilled} />
              )}
            </>
          )}

          <div className="audit-rows" role="list">
            {displayRows.map((row, i) => (
              <div className="audit-row" role="listitem" key={i}>
                <span className="audit-row__label">{row.label}</span>
                <span className="audit-row__value">
                  <span className={`audit-row__dot audit-row__dot--${row.tone}`} />
                  {showEmpty ? '—' : row.value}
                </span>
              </div>
            ))}
            {heroTier === 'preview' && (
              <>
                {[T.lockedPersona, T.lockedGtm, T.lockedBudget].map(lbl => (
                  <div className="audit-row audit-row--locked" role="listitem" key={lbl}>
                    <span className="audit-row__label">{lbl}</span>
                    <span className="audit-row__value" style={{color:'var(--muted)',fontSize:'10px',letterSpacing:'0.05em'}}>
                      {T.lockedNeedsInput}
                    </span>
                  </div>
                ))}
              </>
            )}
          </div>

          <div className="audit-ticker" aria-live="polite">
            <span className="audit-ticker__tag">SIGNAL</span>
            <span className="audit-ticker__body" key={signalIdx + (isPopulated ? 'pop' : '')}>
              <span className={`audit-row__dot audit-row__dot--${displaySignal.tone}`} />
              <span className="audit-ticker__label">{displaySignal.label}</span>
              <span className="audit-ticker__sep">·</span>
              <span className="audit-ticker__verdict">{showEmpty ? '—' : displaySignal.verdict}</span>
            </span>
          </div>

          <div className="audit-chart" aria-label="Search demand by city, indexed">
            <div className="audit-chart__legend">
              <span>Search demand · indexed</span>
              <span className="audit-chart__legend-unit">vs. 12-mo baseline</span>
            </div>
            <div className="audit-chart__cols">
              {displayBars.map((bar, i) => (
                <div key={bar.city} className={`audit-chart__col${i === 0 ? ' audit-chart__col--lead' : ''} ${loaded && !showEmpty ? 'is-loaded' : ''}`}>
                  <span className="audit-chart__val">{showEmpty ? '—' : bar.val}</span>
                  <div className="audit-chart__bar-track">
                    <div className="audit-chart__bar" style={{height: showEmpty ? '12%' : bar.pct + '%'}} />
                  </div>
                  <span className="audit-chart__label">{bar.city}</span>
                </div>
              ))}
            </div>
          </div>
        </>
      )}
    </aside>
  );
}

/* ── Language Switcher (globe dropdown + toast) ──────────────────────── */
function LanguageSwitcher() {
  const langs = [
    { code: 'en', label: 'EN', native: 'English',       path: '/en' },
    { code: 'ko', label: 'KO', native: '한국어',         path: '/ko' },
    { code: 'zh', label: 'ZH', native: '中文',           path: '/zh' },
    { code: 'ms', label: 'MY', native: 'Bahasa Melayu', path: '/ms' },
    { code: 'th', label: 'TH', native: 'ภาษาไทย',       path: '/th' },
  ];
  const [open, setOpen]   = useState(false);
  const [toast, setToast] = useState(null);
  const btnRef     = useRef(null);
  const dropRef    = useRef(null);
  const currentLang = langs.find(l => l.code === LANG) || langs[0];

  // One-time browser language detection
  useEffect(() => {
    if (sessionStorage.getItem('lang-chosen')) return;
    const code = (navigator.language || '').split('-')[0];
    const match = langs.find(l => l.code === code && l.code !== LANG);
    if (match) setToast(match);
  }, []);

  // Close on outside click
  useEffect(() => {
    if (!open) return;
    const handler = e => {
      if (!dropRef.current?.contains(e.target) && !btnRef.current?.contains(e.target)) setOpen(false);
    };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [open]);

  const onKeyDown = e => {
    if (!open) return;
    if (e.key === 'Escape') { setOpen(false); btnRef.current?.focus(); return; }
    if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
      e.preventDefault();
      const items = Array.from(dropRef.current?.querySelectorAll('a') || []);
      if (!items.length) return;
      const idx = items.indexOf(document.activeElement);
      if (e.key === 'ArrowDown') items[Math.min(idx + 1, items.length - 1)]?.focus();
      else idx > 0 ? items[idx - 1]?.focus() : btnRef.current?.focus();
    }
  };

  const dismissToast = () => { setToast(null); sessionStorage.setItem('lang-chosen', '1'); };

  return (
    <>
      <div className="lang-switcher" onKeyDown={onKeyDown}>
        <button
          ref={btnRef}
          className="lang-btn"
          onClick={() => setOpen(o => !o)}
          aria-haspopup="listbox"
          aria-expanded={open}
          aria-label={`Language: ${currentLang.native}`}
        >
          <svg width="14" height="14" viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <circle cx="10" cy="10" r="8"/>
            <path d="M10 2a14.5 14.5 0 0 1 0 16M10 2a14.5 14.5 0 0 0 0 16M2 10h16"/>
          </svg>
          <span>{currentLang.label}</span>
          <svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" style={{transition:'transform 0.2s', transform: open ? 'rotate(180deg)' : 'rotate(0)'}}>
            <polyline points="2,3.5 5,6.5 8,3.5"/>
          </svg>
        </button>
        {open && (
          <div ref={dropRef} className="lang-dropdown" role="listbox" aria-label="Select language">
            {langs.map(l => (
              <a
                key={l.code}
                href={l.path}
                hrefLang={l.code}
                className={`lang-option${LANG === l.code ? ' is-active' : ''}`}
                role="option"
                aria-selected={LANG === l.code}
                onClick={() => { sessionStorage.setItem('lang-chosen', '1'); setOpen(false); }}
              >
                <span className="lang-option__native">{l.native}</span>
                <span className="lang-option__code">{l.label}</span>
              </a>
            ))}
          </div>
        )}
      </div>

      {toast && (
        <div className="lang-toast" role="status">
          <span>View this page in <strong>{toast.native}</strong>?</span>
          <a href={toast.path} className="lang-toast__switch" onClick={() => sessionStorage.setItem('lang-chosen', '1')}>Switch</a>
          <button type="button" className="lang-toast__stay" onClick={dismissToast}>Stay in English</button>
        </div>
      )}
    </>
  );
}

/* ── Sub-components ──────────────────────────────────────────────────── */
function FormField({ id, type, label, placeholder, value, onChange, error, helper, optional, reduceMotion, required, optionalLabel }) {
  const [localFocused, setLocalFocused] = useState(false);
  const [counterKey, setCounterKey]     = useState(0);
  const [scanId, setScanId]             = useState('00');
  const isFocused = localFocused || (value && value.trim().length > 0);
  const acMap = { email:'email', tel:'tel', url:'url', name:'name', organization:'organization' };
  const ac = acMap[id === 'f-email' ? 'email' : id === 'f-company' ? 'organization' : type] || 'on';
  return (
    <div className="field">
      <label htmlFor={id}>
        {label}
        {optional  && <span className="field-optional">{optionalLabel || 'optional'}</span>}
        {required  && <span style={{color:'var(--accent)',marginLeft:2}}>*</span>}
      </label>
      <div className={`field-row ${isFocused ? 'is-focused' : ''}`}>
        <input id={id} type={type} placeholder={placeholder}
          value={value} onChange={e => onChange(e.target.value)}
          onFocus={() => {
            setLocalFocused(true);
            if (!reduceMotion) { setScanId(String(Math.floor(Math.random()*90)+10)); setCounterKey(k=>k+1); }
          }}
          onBlur={() => setLocalFocused(false)}
          autoComplete={ac} required={required} />
        <span key={counterKey} className="field-counter is-active">SCAN&nbsp;{scanId}</span>
      </div>
      {helper && !error && <p className="field-helper">{helper}</p>}
      {error  && <p className="field-error">{error}</p>}
    </div>
  );
}

function PremierBadge() {
  return (
    <a className="premier-badge"
      href="https://www.google.com/partners/agency?id=4969964657"
      target="_blank" rel="noopener noreferrer"
      aria-label="Google Premier Partner">
      <img
        src="https://www.gstatic.com/partners/badge/images/2026/PremierBadgeClickable.svg"
        alt="Google Premier Partner 2026"
        width="96" height="96" loading="lazy"/>
    </a>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
