// Components.jsx — LexiPanel for Defense (PRD-2026-05-21-MILTECH-DSS)
// Single-file React + Babel-standalone pattern (no build step).
// Day 4: DemoRiskScore state machine + INPUT_FORM + SCORE_DISPLAY + FALLBACK_STATIC.
// Style: DLI engineering register — no emoji, no exclamation, numbers preferred.

// ============================================================================
// 1) DLI TOKENS (vendored from DLI-NEWSLETTER/DLITemplates.jsx — DO NOT EDIT here)
// ============================================================================

const DLI_PALETTE = {
  bg: '#0a1024', bgDeep: '#070b1a',
  surface: '#0f172a', surfaceCard: '#111a36',
  border: 'rgba(148,163,184,0.12)', borderStrong: 'rgba(148,163,184,0.22)',
  fg: '#f8fafc', fgMuted: '#94a3b8', fgSubtle: '#64748b',
  lime: '#84cc16', limeBright: '#a3e635',
  amber: '#e0a82e', amberBright: '#f59e0b',
  indigo: '#6366f1', indigoBright: '#818cf8',
  red: '#ef4444',
};

const API_ENDPOINT = '/api/v1/score-risk-miltech';
const SUBMIT_TIMEOUT_MS = 3000;

// ============================================================================
// 2) BILINGUAL TRANSLATION MAP
// ============================================================================

const T = {
  brand_name:           { en: 'LexiPanel',                                            ua: 'LexiPanel' },
  brand_vertical:       { en: 'for Defense',                                          ua: 'для Оборони' },

  hero_eyebrow:         { en: 'UA Online Miltech Conference 2026 · ShowCases · 30 May',
                          ua: 'UA Online Miltech Conference 2026 · ShowCases · 30 травня' },
  hero_h1_a:            { en: 'Score any miltech decision.',                          ua: 'Оціни будь-яке мілтех-рішення.' },
  hero_h1_b:            { en: 'See which factors moved the needle.',                  ua: 'Побач, які фактори зрушили стрілку.' },
  hero_lede:            { en: 'A KAN-powered Universal Risk Score with the symbolic formula your auditor can read — not a black-box opinion.',
                          ua: 'KAN-оцінка універсального ризику з символьною формулою, яку прочитає твій аудитор — а не чорний ящик.' },
  cta_primary:          { en: 'Get your indicative score',                            ua: 'Отримати індикативну оцінку' },
  cta_secondary:        { en: '15-min feedback chat',                                 ua: '15-хв розмова про відгук' },

  section_router_label: { en: 'WHO ARE YOU SCORING FOR?',                             ua: 'ХТО ОЦІНЮЄ?' },
  section_router_title: { en: 'Three roles. One model. Formulas you can audit.',     ua: 'Три ролі. Одна модель. Формули, які витримують аудит.' },

  role_defense_key:     { en: '01 · DEFENSE',                                         ua: '01 · ОБОРОНА' },
  role_defense_title:   { en: 'Defense company',                                      ua: 'Оборонна компанія' },
  role_defense_body:    { en: 'You build for the front. Score your next contract for legal, dual-use, and sanctions risk before you bid.',
                          ua: 'Ти будуєш для фронту. Оціни свій наступний контракт на юридичний, dual-use та санкційний ризик до подачі заявки.' },

  role_dualuse_key:     { en: '02 · DUAL-USE',                                        ua: '02 · DUAL-USE' },
  role_dualuse_title:   { en: 'Dual-use business',                                    ua: 'Dual-use бізнес' },
  role_dualuse_body:    { en: 'Civilian core, defense edge. Evaluate the regulatory and export-control gap before you cross it.',
                          ua: 'Цивільне ядро, оборонний край. Оціни регуляторний та експортно-контрольний розрив до того, як перетнеш його.' },

  role_investor_key:    { en: '03 · INVESTOR',                                        ua: '03 · ІНВЕСТОР' },
  role_investor_title:  { en: 'Miltech investor',                                     ua: 'Мілтех-інвестор' },
  role_investor_body:   { en: 'You back miltech. Stress-test a portfolio company risk profile in 90 seconds.',
                          ua: 'Ти інвестуєш у мілтех. Стрес-тест ризик-профілю портфельної компанії за 90 секунд.' },

  role_cta:             { en: 'Score as this role →',                                 ua: 'Оцінити в цій ролі →' },

  // Demo state machine — INPUT_FORM
  form_title_defense:   { en: 'Score this contract',                                  ua: 'Оцінити цей контракт' },
  form_title_dualuse:   { en: 'Score this deal',                                      ua: 'Оцінити цю угоду' },
  form_title_investor:  { en: 'Score this portfolio company',                         ua: 'Оцінити цю портфельну компанію' },
  form_sub:             { en: 'Seven factors. KAN inference + symbolic formula in under a second.',
                          ua: 'Сім факторів. KAN-інференс + символьна формула менш ніж за секунду.' },
  form_back:            { en: '← Back to roles',                                      ua: '← Назад до ролей' },
  form_submit:          { en: 'Calculate risk score',                                 ua: 'Розрахувати оцінку ризику' },

  field_value_label_defense:  { en: 'Contract value (EUR)',           ua: 'Вартість контракту (EUR)' },
  field_value_label_dualuse:  { en: 'Deal value (EUR)',               ua: 'Вартість угоди (EUR)' },
  field_value_label_investor: { en: 'Round size (EUR)',               ua: 'Розмір раунду (EUR)' },
  field_value_help:           { en: 'Stored as log10(value). 1k → 3, 1M → 6, 100M → 8.',
                                ua: 'Зберігається як log10(value). 1k → 3, 1М → 6, 100М → 8.' },

  field_country_label:        { en: 'Counterparty jurisdiction',                       ua: 'Юрисдикція контрагента' },
  field_country_opt_1:        { en: '1 — EU/NATO core (DE, FR, UK, US)',               ua: '1 — Ядро EU/NATO (DE, FR, UK, US)' },
  field_country_opt_2:        { en: '2 — EU/NATO periphery (PL, IT, ES, TR)',          ua: '2 — Периферія EU/NATO (PL, IT, ES, TR)' },
  field_country_opt_3:        { en: '3 — Allied non-NATO (UA, IL, AU, KR)',            ua: '3 — Союзники non-NATO (UA, IL, AU, KR)' },
  field_country_opt_4:        { en: '4 — Neutral (CH, IN, AR, BR)',                    ua: '4 — Нейтральні (CH, IN, AR, BR)' },
  field_country_opt_5:        { en: '5 — High-risk (RU, IR, NK, CN)',                  ua: '5 — Високого ризику (RU, IR, NK, CN)' },

  field_dualuse_label:        { en: 'Dual-use class (EU Reg 2021/821)',                ua: 'Dual-use клас (EU Reg 2021/821)' },
  field_dualuse_opt_0:        { en: '0 — Pure civilian (no dual-use)',                  ua: '0 — Суто цивільне (без dual-use)' },
  field_dualuse_opt_1:        { en: '1 — Annex I controlled (license required)',       ua: '1 — Annex I контрольоване (потрібна ліцензія)' },
  field_dualuse_opt_2:        { en: '2 — Wassenaar Cat 2-9 (specific authorization)',  ua: '2 — Wassenaar Cat 2-9 (спецдозвіл)' },
  field_dualuse_opt_3:        { en: '3 — Wassenaar Cat 1 (military)',                  ua: '3 — Wassenaar Cat 1 (військове)' },

  field_experience_label:     { en: 'Team defense experience (years, sum across team)',
                                ua: 'Досвід команди в обороні (років, сума по команді)' },

  field_overlap_label:        { en: 'Overlapping regulatory regimes',                  ua: 'Регуляторні регіми (накладання)' },
  field_overlap_help:         { en: 'e.g. EU + UA + NATO + ITAR = 4',                  ua: 'напр. EU + UA + NATO + ITAR = 4' },

  field_sanctions_label:      { en: 'Counterparty distance from sanctions lists',      ua: 'Відстань контрагента від санкційних списків' },
  field_sanctions_opt_0:      { en: '0 — Direct hit (sanctioned)',                     ua: '0 — Пряме потрапляння (під санкціями)' },
  field_sanctions_opt_1:      { en: '1 — 1 hop (board member sanctioned)',             ua: '1 — 1 hop (член ради під санкціями)' },
  field_sanctions_opt_2:      { en: '2 — 2 hops (UBO sanctioned)',                     ua: '2 — 2 hops (UBO під санкціями)' },
  field_sanctions_opt_3:      { en: '3 — Clean (no nexus found)',                      ua: '3 — Чисто (звʼязків не знайдено)' },

  field_trl_label:            { en: 'Technology Readiness Level (NATO TRL)',           ua: 'Рівень готовності технології (NATO TRL)' },
  field_trl_opt_1:            { en: '1 — Basic principles observed',                   ua: '1 — Базові принципи спостерігаються' },
  field_trl_opt_2:            { en: '2 — Technology concept formulated',               ua: '2 — Концепт сформульовано' },
  field_trl_opt_3:            { en: '3 — Experimental proof of concept',               ua: '3 — Експериментальний PoC' },
  field_trl_opt_4:            { en: '4 — Lab validation',                              ua: '4 — Валідація в лабораторії' },
  field_trl_opt_5:            { en: '5 — Validation in relevant environment',          ua: '5 — Валідація у релевантному середовищі' },
  field_trl_opt_6:            { en: '6 — Demonstration in relevant environment',       ua: '6 — Демонстрація у релевантному середовищі' },
  field_trl_opt_7:            { en: '7 — Operational environment prototype',           ua: '7 — Прототип в операційному середовищі' },
  field_trl_opt_8:            { en: '8 — System complete and qualified',               ua: '8 — Система завершена і кваліфікована' },
  field_trl_opt_9:            { en: '9 — Proven in operational use',                   ua: '9 — Підтверджена в операційному використанні' },

  // Demo state machine — SUBMITTING
  submitting_text:            { en: 'Calling KAN inference',                           ua: 'Виклик KAN-інференсу' },

  // Demo state machine — SCORE_DISPLAY
  score_label:                { en: 'RISK SCORE',                                      ua: 'ОЦІНКА РИЗИКУ' },
  score_factors_label:        { en: 'TOP 3 RISK FACTORS',                              ua: '3 ТОП-ФАКТОРИ РИЗИКУ' },
  score_formula_label:        { en: 'SYMBOLIC FORMULA (KAN-LEARNED)',                  ua: 'СИМВОЛЬНА ФОРМУЛА (ВИВЧЕНА KAN)' },
  score_meta_label:           { en: 'INFERENCE META',                                  ua: 'МЕТА ІНФЕРЕНСУ' },
  score_cta_apply:            { en: 'Apply this to my real case →',                    ua: 'Застосувати до мого реального кейсу →' },
  score_cta_feedback:         { en: '15-min feedback chat',                            ua: '15-хв розмова про відгук' },
  score_back:                 { en: '← Try another role',                              ua: '← Інша роль' },
  score_label_low:            { en: 'LOW',                                             ua: 'НИЗЬКА' },
  score_label_moderate:       { en: 'MODERATE',                                        ua: 'ПОМІРНА' },
  score_label_high:           { en: 'ELEVATED',                                        ua: 'ПІДВИЩЕНА' },

  score_factor_increases:     { en: 'increases risk',                                  ua: 'підвищує ризик' },
  score_factor_decreases:     { en: 'decreases risk',                                  ua: 'знижує ризик' },

  // Fallback state
  fallback_banner:            { en: 'KAN inference offline — score computed client-side from the disclosed formula.',
                                ua: 'KAN-інференс офлайн — оцінка обчислена клієнтом за оприлюдненою формулою.' },

  indicative:                 { en: 'Indicative — synthetic-calibrated v0 (Art.21 KE2)',
                                ua: 'Індикативно — синтетична калібровка v0 (Art.21 KE2)' },

  // Demo intro (when no role selected yet)
  demo_stub_pre:              { en: 'Pick a role above to score a deal. Backend live at',
                                ua: 'Обери роль вище, щоб оцінити угоду. Бекенд працює на' },
  demo_stub_post:             { en: '— returns score + symbolic formula + top-3 factors.',
                                ua: '— повертає score + символьну формулу + 3 топ-фактори.' },

  // Feature name labels (used in top_factors display)
  feature_contract_value_eur_log:          { en: 'Contract value',              ua: 'Вартість контракту' },
  feature_country_risk_class:              { en: 'Counterparty jurisdiction',   ua: 'Юрисдикція контрагента' },
  feature_dual_use_export_class:           { en: 'Dual-use classification',     ua: 'Dual-use класифікація' },
  feature_team_defense_experience_years:   { en: 'Team defense experience',     ua: 'Досвід команди в обороні' },
  feature_regulatory_overlap_count:        { en: 'Regulatory overlap',          ua: 'Регуляторне накладання' },
  feature_counterparty_sanctions_distance: { en: 'Sanctions distance',          ua: 'Відстань санкцій' },
  feature_trl_level:                       { en: 'TRL level',                   ua: 'Рівень TRL' },

  cred_label_engine:    { en: 'INFERENCE ENGINE',                                     ua: 'INFERENCE ENGINE' },
  cred_val_engine:      { en: 'KAN Phase 8.1',                                        ua: 'KAN Фаза 8.1' },
  cred_label_arch:      { en: 'ARCHITECTURE',                                         ua: 'АРХІТЕКТУРА' },
  cred_val_arch:        { en: 'FastKAN [7,4,1]',                                      ua: 'FastKAN [7,4,1]' },
  cred_label_speaker:   { en: 'SPEAKER',                                              ua: 'СПІКЕР' },
  cred_val_speaker:     { en: 'Yaroslav Baienko',                                     ua: 'Ярослав Баєнко' },
  cred_val_speaker_role:{ en: 'GOLAW · Dual MSc Law + CS',                            ua: 'GOLAW · Подвійний магістр Право + ІТ' },
  cred_label_event:     { en: 'EVENT',                                                ua: 'ПОДІЯ' },
  cred_val_event:       { en: '30 May 2026',                                          ua: '30 травня 2026' },

  footer_brand:         { en: 'LexiPanel for Defense',                                ua: 'LexiPanel для Оборони' },
  footer_byline:        { en: 'KAN-powered strategic decision support for defense, dual-use, investor decisions.',
                          ua: 'KAN-підтримка стратегічних рішень для оборони, dual-use, інвесторів.' },
  footer_meta:          { en: 'PRD-2026-05-21-MILTECH-DSS · LexiPanel vertical · Hetzner + Caddy + KAN',
                          ua: 'PRD-2026-05-21-MILTECH-DSS · LexiPanel вертикаль · Hetzner + Caddy + KAN' },
};

const t = (key, lang) => (T[key] && T[key][lang]) || (T[key] && T[key].en) || key;

// ============================================================================
// 3) FORM DEFAULTS + CLIENT-SIDE FORMULA (matches kan-engine/main.py disclosed formula)
// ============================================================================

const DEFAULT_FORM = {
  contract_value_eur_log: 5.0,   // EUR 100k
  country_risk_class: 3,
  dual_use_export_class: 1,
  team_defense_experience_years: 5,
  regulatory_overlap_count: 2,
  counterparty_sanctions_distance: 3,
  trl_level: 6,
};

// In-form display: contract value as EUR (convert log10 ↔ EUR via 10^x)
const logToEur = (log) => Math.round(Math.pow(10, log));
const eurToLog = (eur) => {
  if (!eur || eur <= 0) return 3;
  return Math.max(3, Math.min(18, Math.log10(eur)));
};

function sigmoid(x) {
  if (x >= 0) return 1 / (1 + Math.exp(-x));
  const e = Math.exp(x);
  return e / (1 + e);
}

// Client-side replica of /v1/score-risk-miltech for FALLBACK_STATIC
// MUST match kan-engine/app/main.py _MILTECH_FORMULA_TEXT byte-for-byte.
function clientSideFormula(v) {
  const raw =
    0.31 * Math.tanh(v.contract_value_eur_log - 12)
    + 0.18 * (v.country_risk_class - 3)
    + 0.21 * v.dual_use_export_class
    - 0.12 * Math.tanh(v.team_defense_experience_years - 5)
    + 0.09 * (v.regulatory_overlap_count - 1) * (3 - v.counterparty_sanctions_distance)
    - 0.15 * (v.trl_level - 5) / 4
    + 0.1;
  return Math.max(0, Math.min(1, sigmoid(raw)));
}

function clientSideTopFactors(v) {
  const coupling = 0.09 * (v.regulatory_overlap_count - 1) * (3 - v.counterparty_sanctions_distance);
  const contribs = {
    contract_value_eur_log: 0.31 * Math.tanh(v.contract_value_eur_log - 12),
    country_risk_class: 0.18 * (v.country_risk_class - 3),
    dual_use_export_class: 0.21 * v.dual_use_export_class,
    team_defense_experience_years: -0.12 * Math.tanh(v.team_defense_experience_years - 5),
    regulatory_overlap_count: coupling * 0.5,
    counterparty_sanctions_distance: coupling * 0.5,
    trl_level: -0.15 * (v.trl_level - 5) / 4,
  };
  return Object.entries(contribs)
    .sort((a, b) => Math.abs(b[1]) - Math.abs(a[1]))
    .slice(0, 3)
    .map(([feature, c]) => ({
      feature,
      contribution: Math.round(c * 10000) / 10000,
      direction: c > 0 ? 'increases' : 'decreases',
    }));
}

const FORMULA_TEXT =
  'sigmoid(0.31*tanh(contract_value_eur_log - 12) + 0.18*(country_risk_class - 3) + ' +
  '0.21*dual_use_export_class - 0.12*tanh(team_defense_experience_years - 5) + ' +
  '0.09*(regulatory_overlap_count - 1)*(3 - counterparty_sanctions_distance) - ' +
  '0.15*(trl_level - 5)/4 + 0.1)';

// ============================================================================
// 4) UI ATOMS
// ============================================================================

function BrandMark() {
  return (
    <span className="brand-mark" aria-hidden="true">
      <svg width="18" height="18" viewBox="0 0 24 24" fill="none"
           strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round">
        <path d="M12 3v18" />
        <path d="M5 7h14" />
        <path d="M5 7l-3 7a4 4 0 0 0 8 0l-3-7" />
        <path d="M19 7l3 7a4 4 0 0 1-8 0l3-7" />
        <path d="M7 21h10" />
      </svg>
    </span>
  );
}

function LangToggle({ lang, setLang }) {
  return (
    <div className="lang-toggle" role="group" aria-label="Language">
      <button className={lang === 'en' ? 'active' : ''} onClick={() => setLang('en')} aria-pressed={lang === 'en'}>EN</button>
      <button className={lang === 'ua' ? 'active' : ''} onClick={() => setLang('ua')} aria-pressed={lang === 'ua'}>UA</button>
    </div>
  );
}

// ============================================================================
// 5) HEADER / HERO / ROLE ROUTER
// ============================================================================

function Header({ lang, setLang }) {
  return (
    <header className="header">
      <div className="container header-inner">
        <a href="/" className="brand">
          <BrandMark />
          <span className="brand-name">{t('brand_name', lang)}</span>
          <span className="brand-vertical">{t('brand_vertical', lang)}</span>
        </a>
        <LangToggle lang={lang} setLang={setLang} />
      </div>
    </header>
  );
}

function Hero({ lang, onPrimaryCTA }) {
  return (
    <section className="hero">
      <div className="container">
        <div className="eyebrow">
          <span className="eyebrow-dot" aria-hidden="true"></span>
          {t('hero_eyebrow', lang)}
        </div>
        <h1 className="h1">
          {t('hero_h1_a', lang)}<br />
          <em>{t('hero_h1_b', lang)}</em>
        </h1>
        <p className="lede">{t('hero_lede', lang)}</p>
        <div className="cta-row">
          <button className="btn btn-primary" onClick={onPrimaryCTA}>{t('cta_primary', lang)}</button>
          <button className="btn btn-ghost" onClick={onPrimaryCTA}>{t('cta_secondary', lang)}</button>
        </div>
        <span className="indicative-banner">{t('indicative', lang)}</span>
      </div>
    </section>
  );
}

function RoleCard({ accent, keyText, title, body, ctaText, onClick, isActive }) {
  return (
    <button
      className={`role-card ${accent}${isActive ? ' active' : ''}`}
      onClick={onClick}
      type="button"
    >
      <span className="role-accent" aria-hidden="true"></span>
      <div className="role-key">{keyText}</div>
      <h3 className="role-title">{title}</h3>
      <p className="role-body">{body}</p>
      <span className="role-cta">{ctaText}</span>
    </button>
  );
}

function RoleRouter({ lang, currentRole, onRoleSelect }) {
  return (
    <section className="role-section" id="role-router">
      <div className="container">
        <div className="section-label">{t('section_router_label', lang)}</div>
        <h2 className="section-title">{t('section_router_title', lang)}</h2>
        <div className="role-grid">
          <RoleCard accent="lime"
            keyText={t('role_defense_key', lang)} title={t('role_defense_title', lang)}
            body={t('role_defense_body', lang)} ctaText={t('role_cta', lang)}
            isActive={currentRole === 'defense'}
            onClick={() => onRoleSelect('defense')}
          />
          <RoleCard accent="amber"
            keyText={t('role_dualuse_key', lang)} title={t('role_dualuse_title', lang)}
            body={t('role_dualuse_body', lang)} ctaText={t('role_cta', lang)}
            isActive={currentRole === 'dualuse'}
            onClick={() => onRoleSelect('dualuse')}
          />
          <RoleCard accent="indigo"
            keyText={t('role_investor_key', lang)} title={t('role_investor_title', lang)}
            body={t('role_investor_body', lang)} ctaText={t('role_cta', lang)}
            isActive={currentRole === 'investor'}
            onClick={() => onRoleSelect('investor')}
          />
        </div>
      </div>
    </section>
  );
}

// ============================================================================
// 6) DEMO STATE MACHINE: ROLE_SELECT → INPUT_FORM → SUBMITTING → SCORE_DISPLAY
//                                                ↓ (5xx / timeout)
//                                          FALLBACK_STATIC
// ============================================================================

function DemoIntro({ lang }) {
  return (
    <div className="demo-stub">
      {t('demo_stub_pre', lang)} <code>POST /api/v1/score-risk-miltech</code> {t('demo_stub_post', lang)}
    </div>
  );
}

function NumberField({ id, value, onChange, min, max, step, help }) {
  return (
    <div className="field-input-wrap">
      <input
        id={id} type="number" inputMode="numeric"
        min={min} max={max} step={step ?? 1}
        value={value}
        onChange={(e) => onChange(e.target.value === '' ? '' : Number(e.target.value))}
      />
      {help && <div className="field-help">{help}</div>}
    </div>
  );
}

function SelectField({ id, value, onChange, options }) {
  return (
    <select id={id} className="field-select" value={value} onChange={(e) => onChange(Number(e.target.value))}>
      {options.map(([v, label]) => <option key={v} value={v}>{label}</option>)}
    </select>
  );
}

function InputForm({ lang, role, formData, setFormData, onSubmit, onBack }) {
  // contract value is shown to user as EUR but stored as log10
  const eurValue = logToEur(formData.contract_value_eur_log);

  const titleKey = role === 'dualuse' ? 'form_title_dualuse'
                : role === 'investor' ? 'form_title_investor'
                : 'form_title_defense';
  const valueLabelKey = role === 'dualuse' ? 'field_value_label_dualuse'
                     : role === 'investor' ? 'field_value_label_investor'
                     : 'field_value_label_defense';

  const setField = (k, v) => setFormData({ ...formData, [k]: v });

  return (
    <div className="demo-card">
      <button className="demo-back" onClick={onBack} type="button">{t('form_back', lang)}</button>
      <h3 className="demo-title">{t(titleKey, lang)}</h3>
      <p className="demo-sub">{t('form_sub', lang)}</p>

      <div className="form-grid">
        <div className="field">
          <label htmlFor="f-value">{t(valueLabelKey, lang)}</label>
          <NumberField id="f-value" value={eurValue} min={1000} max={100000000} step={1000}
            onChange={(eur) => setField('contract_value_eur_log', eur === '' ? 3 : eurToLog(eur))}
            help={t('field_value_help', lang)}
          />
        </div>

        <div className="field">
          <label htmlFor="f-country">{t('field_country_label', lang)}</label>
          <SelectField id="f-country" value={formData.country_risk_class}
            onChange={(v) => setField('country_risk_class', v)}
            options={[
              [1, t('field_country_opt_1', lang)], [2, t('field_country_opt_2', lang)],
              [3, t('field_country_opt_3', lang)], [4, t('field_country_opt_4', lang)],
              [5, t('field_country_opt_5', lang)],
            ]}
          />
        </div>

        <div className="field">
          <label htmlFor="f-dualuse">{t('field_dualuse_label', lang)}</label>
          <SelectField id="f-dualuse" value={formData.dual_use_export_class}
            onChange={(v) => setField('dual_use_export_class', v)}
            options={[
              [0, t('field_dualuse_opt_0', lang)], [1, t('field_dualuse_opt_1', lang)],
              [2, t('field_dualuse_opt_2', lang)], [3, t('field_dualuse_opt_3', lang)],
            ]}
          />
        </div>

        <div className="field">
          <label htmlFor="f-exp">{t('field_experience_label', lang)}</label>
          <NumberField id="f-exp" value={formData.team_defense_experience_years} min={0} max={15}
            onChange={(v) => setField('team_defense_experience_years', Math.max(0, Math.min(15, Number(v) || 0)))}
          />
        </div>

        <div className="field">
          <label htmlFor="f-overlap">{t('field_overlap_label', lang)}</label>
          <NumberField id="f-overlap" value={formData.regulatory_overlap_count} min={0} max={5}
            onChange={(v) => setField('regulatory_overlap_count', Math.max(0, Math.min(5, Number(v) || 0)))}
            help={t('field_overlap_help', lang)}
          />
        </div>

        <div className="field">
          <label htmlFor="f-sanctions">{t('field_sanctions_label', lang)}</label>
          <SelectField id="f-sanctions" value={formData.counterparty_sanctions_distance}
            onChange={(v) => setField('counterparty_sanctions_distance', v)}
            options={[
              [0, t('field_sanctions_opt_0', lang)], [1, t('field_sanctions_opt_1', lang)],
              [2, t('field_sanctions_opt_2', lang)], [3, t('field_sanctions_opt_3', lang)],
            ]}
          />
        </div>

        <div className="field field-full">
          <label htmlFor="f-trl">{t('field_trl_label', lang)}</label>
          <SelectField id="f-trl" value={formData.trl_level}
            onChange={(v) => setField('trl_level', v)}
            options={[1,2,3,4,5,6,7,8,9].map(n => [n, t('field_trl_opt_' + n, lang)])}
          />
        </div>
      </div>

      <div className="form-actions">
        <button className="btn btn-primary" onClick={onSubmit} type="button">{t('form_submit', lang)}</button>
      </div>
    </div>
  );
}

function Submitting({ lang }) {
  return (
    <div className="demo-card demo-loading">
      <div className="spinner" aria-hidden="true"></div>
      <div className="loading-text">
        <span>{t('submitting_text', lang)}</span>
        <code>POST {API_ENDPOINT}</code>
      </div>
    </div>
  );
}

function ScoreDisplay({ lang, response, isFallback, onReset, onLead }) {
  const score = response.score_0_100;
  const tier = response.risk_label;
  const tierClass = tier === 'high' ? 'risk-elevated'
                  : tier === 'moderate' ? 'risk-moderate'
                  : 'risk-low';
  const tierLabelKey = tier === 'high' ? 'score_label_high'
                     : tier === 'moderate' ? 'score_label_moderate'
                     : 'score_label_low';

  return (
    <div className="demo-card score-display">
      {isFallback && <div className="fallback-banner">{t('fallback_banner', lang)}</div>}

      <div className="score-grid">
        <div className="score-gauge">
          <div className={'gauge ' + tierClass}>
            <div className="gauge-num">{score}</div>
            <div className="gauge-cap">/ 100</div>
          </div>
          <div className={'gauge-label ' + tierClass}>{t(tierLabelKey, lang)}</div>
          <div className="indicative-banner" style={{ marginTop: 12 }}>{t('indicative', lang)}</div>
        </div>

        <div className="score-detail">
          <div className="section-label">{t('score_factors_label', lang)}</div>
          <ul className="factor-list">
            {response.top_factors.map((f, i) => (
              <li key={i} className={'factor ' + (f.direction === 'increases' ? 'factor-up' : 'factor-down')}>
                <div className="factor-name">{t('feature_' + f.feature, lang)}</div>
                <div className="factor-meta">
                  <span className="factor-direction">{t(f.direction === 'increases' ? 'score_factor_increases' : 'score_factor_decreases', lang)}</span>
                  <code className="factor-contrib">{f.contribution >= 0 ? '+' : ''}{f.contribution.toFixed(3)}</code>
                </div>
              </li>
            ))}
          </ul>

          <div className="section-label" style={{ marginTop: 24 }}>{t('score_formula_label', lang)}</div>
          <pre className="formula"><code>{response.formula_text || FORMULA_TEXT}</code></pre>

          <div className="section-label" style={{ marginTop: 24 }}>{t('score_meta_label', lang)}</div>
          <div className="score-meta">
            <span>model: <code>{response.model_id}</code></span>
            <span>latency: <code>{response.latency_ms}ms</code></span>
            {isFallback && <span style={{ color: DLI_PALETTE.amber }}>mode: <code>fallback-static</code></span>}
          </div>
        </div>
      </div>

      <div className="form-actions" style={{ marginTop: 32 }}>
        <button className="btn btn-primary" onClick={onLead} type="button">{t('score_cta_apply', lang)}</button>
        <button className="btn btn-ghost" onClick={onLead} type="button">{t('score_cta_feedback', lang)}</button>
        <button className="btn btn-ghost" onClick={onReset} type="button">{t('score_back', lang)}</button>
      </div>
    </div>
  );
}

function DemoRiskScore({ lang, currentRole, onRoleReset, onLeadCapture }) {
  const [state, setState] = React.useState('IDLE');           // IDLE | INPUT_FORM | SUBMITTING | SCORE_DISPLAY | FALLBACK_STATIC
  const [formData, setFormData] = React.useState(DEFAULT_FORM);
  const [response, setResponse] = React.useState(null);
  const [isFallback, setIsFallback] = React.useState(false);

  // When user picks a role above, transition to INPUT_FORM
  React.useEffect(() => {
    if (currentRole && state === 'IDLE') setState('INPUT_FORM');
  }, [currentRole, state]);

  const handleSubmit = React.useCallback(async () => {
    setState('SUBMITTING');
    setIsFallback(false);

    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), SUBMIT_TIMEOUT_MS);

    try {
      const r = await fetch(API_ENDPOINT, {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ entity: formData, metadata: { caller: 'miltech-landing', role: currentRole } }),
        signal: controller.signal,
      });
      clearTimeout(timeoutId);
      if (!r.ok) throw new Error('http_' + r.status);
      const data = await r.json();
      setResponse(data);
      setState('SCORE_DISPLAY');
    } catch (_err) {
      // FALLBACK_STATIC — client-side formula eval
      clearTimeout(timeoutId);
      const risk = clientSideFormula(formData);
      const score = Math.round(risk * 100);
      const label = risk >= 0.66 ? 'high' : (risk >= 0.33 ? 'moderate' : 'low');
      setResponse({
        risk_0_1: risk, risk_label: label, score_0_100: score,
        top_factors: clientSideTopFactors(formData),
        formula_text: FORMULA_TEXT,
        model_id: 'client-side-fallback',
        latency_ms: 1,
      });
      setIsFallback(true);
      setState('FALLBACK_STATIC');
    }
  }, [formData, currentRole]);

  const handleReset = React.useCallback(() => {
    setState('IDLE');
    setResponse(null);
    setIsFallback(false);
    onRoleReset();
  }, [onRoleReset]);

  const handleBack = React.useCallback(() => {
    setState('IDLE');
    onRoleReset();
  }, [onRoleReset]);

  return (
    <section className="container" id="demo">
      {state === 'IDLE' && <DemoIntro lang={lang} />}
      {state === 'INPUT_FORM' && (
        <InputForm lang={lang} role={currentRole}
          formData={formData} setFormData={setFormData}
          onSubmit={handleSubmit} onBack={handleBack}
        />
      )}
      {state === 'SUBMITTING' && <Submitting lang={lang} />}
      {(state === 'SCORE_DISPLAY' || state === 'FALLBACK_STATIC') && response && (
        <ScoreDisplay lang={lang} response={response}
          isFallback={isFallback}
          onReset={handleReset}
          onLead={onLeadCapture}
        />
      )}
    </section>
  );
}

// ============================================================================
// 7) CREDIBILITY + FOOTER
// ============================================================================

function CredibilityStrip({ lang }) {
  return (
    <section className="credibility">
      <div className="container">
        <div className="cred-grid">
          <div className="cred-item">
            <div className="cred-val"><span className="accent-lime">{t('cred_val_engine', lang)}</span></div>
            <div className="cred-label">{t('cred_label_engine', lang)}</div>
          </div>
          <div className="cred-item">
            <div className="cred-val"><span className="accent-amber">{t('cred_val_arch', lang)}</span></div>
            <div className="cred-label">{t('cred_label_arch', lang)}</div>
          </div>
          <div className="cred-item">
            <div className="cred-val">{t('cred_val_speaker', lang)}</div>
            <div className="cred-label">{t('cred_val_speaker_role', lang)}</div>
          </div>
          <div className="cred-item">
            <div className="cred-val"><span className="accent-indigo">{t('cred_val_event', lang)}</span></div>
            <div className="cred-label">{t('cred_label_event', lang)}</div>
          </div>
        </div>
      </div>
    </section>
  );
}

function Footer({ lang, version }) {
  return (
    <footer className="footer">
      <div className="container">
        <div className="footer-row">
          <div>
            <div style={{ color: DLI_PALETTE.fg, fontWeight: 700 }}>{t('footer_brand', lang)}</div>
            <div style={{ color: DLI_PALETTE.fgMuted, marginTop: 4 }}>{t('footer_byline', lang)}</div>
          </div>
          <div style={{ textAlign: 'right' }}>
            <code>miltech.advocacy.uno</code>
            <div className="footer-meta">{t('footer_meta', lang)}</div>
            <div className="footer-meta" style={{ marginTop: 4 }}>build: {version}</div>
          </div>
        </div>
      </div>
    </footer>
  );
}

// ============================================================================
// 8) ROOT
// ============================================================================

function detectLang() {
  if (typeof navigator === 'undefined' || !navigator.language) return 'en';
  return navigator.language.toLowerCase().startsWith('uk') ? 'ua' : 'en';
}

function Page() {
  const [lang, setLangRaw] = React.useState(detectLang());
  const [currentRole, setCurrentRole] = React.useState(null);

  const setLang = React.useCallback((l) => {
    setLangRaw(l);
    document.documentElement.lang = l === 'ua' ? 'uk' : 'en';
  }, []);
  React.useEffect(() => { document.documentElement.lang = lang === 'ua' ? 'uk' : 'en'; }, [lang]);

  const scrollToRouter = React.useCallback(() => {
    const el = document.getElementById('role-router');
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  }, []);

  const handleRoleSelect = React.useCallback((role) => {
    setCurrentRole(role);
    // give React a tick to mount the form, then scroll
    setTimeout(() => {
      const el = document.getElementById('demo');
      if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }, 50);
  }, []);

  const handleRoleReset = React.useCallback(() => {
    setCurrentRole(null);
    setTimeout(() => {
      const el = document.getElementById('role-router');
      if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }, 50);
  }, []);

  // Day-5 will swap this stub for LeadCaptureModal
  const handleLeadCapture = React.useCallback(() => {
    const subject = encodeURIComponent('LexiPanel for Defense — 15-min feedback');
    const body = encodeURIComponent('Hi Yaroslav,\n\nSaw the LexiPanel for Defense demo at the ShowCases. Would love to talk.\n\n— ');
    window.location.href = `mailto:y.baienko@golaw.ua?subject=${subject}&body=${body}`;
  }, []);

  const version = (typeof window !== 'undefined' && window.__MILTECH_BUILD__) || 'dev';

  return (
    <React.Fragment>
      <div className="top-accent" />
      <Header lang={lang} setLang={setLang} />
      <main>
        <Hero lang={lang} onPrimaryCTA={scrollToRouter} />
        <RoleRouter lang={lang} currentRole={currentRole} onRoleSelect={handleRoleSelect} />
        <DemoRiskScore lang={lang} currentRole={currentRole}
          onRoleReset={handleRoleReset} onLeadCapture={handleLeadCapture}
        />
        <CredibilityStrip lang={lang} />
      </main>
      <Footer lang={lang} version={version} />
    </React.Fragment>
  );
}
