/* AUTOPILOT — main app */
const { useEffect, useState } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "light",
  "accent": "#E60000",
  "fontPair": "grotesk",
  "bodyFont": "inter",
  "headerFont": "inter",
  "buttonFont": "inter",
  "caseHeader": "none",
  "caseBody": "none",
  "caseButton": "none",
  "splineOn": true,
  "taglineMode": "stack",
  "taglineMainSize": 86,
  "taglineSubSize": 14,
  "titleSize": 36,
  "cardSize": 18,
  "leadSize": 18,
  "leadFont": "inter",
  "bodySize": 14,
  "bodyLine": 1.55,
  "labelSize": 12,
  "uiSize": 14,
  "numFont": "grotesk",
  "numSize": 48,
  "lang": "EN",
  "headerThaiFont": "prompt",
  "bodyThaiFont": "prompt",
  "buttonThaiFont": "noto",
  "leadThaiFont": "prompt",
  "numThaiFont": "prompt",
  "eyebrowFont": "mono",
  "eyebrowThaiFont": "noto",
  "headerThaiWeight": "300",
  "bodyThaiWeight": "300",
  "buttonThaiWeight": "400",
  "leadThaiWeight": "300",
  "numThaiWeight": "300",
  "eyebrowThaiWeight": "400"
}/*EDITMODE-END*/;

// Latin font stacks. Thai font is layered in at runtime via
// buildFontStack() so every text group (header / body / button / lead /
// num / eyebrow) can pair independently. EN mode: browser does per-glyph
// fallback (Latin → Latin font, Thai → Thai font). TH mode: Thai font
// wins for both Latin and Thai chars so the page reads as one language.
const FONT_PAIRS = {
  grotesk: { display: '"Space Grotesk", sans-serif', body: '"JetBrains Mono", monospace', label: 'Grotesk + Mono' },
};

const BODY_FONTS = {
  inter:   { stack: '"Inter", "Helvetica Neue", Helvetica, Arial, sans-serif',     label: 'Inter (default)' },
  mono:    { stack: '"JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace', label: 'JetBrains Mono' },
};

const DISPLAY_FONTS = {
  inter:     { stack: '"Inter", "Helvetica Neue", Arial, sans-serif',                label: 'Inter (default)' },
  grotesk:   { stack: '"Space Grotesk", "Helvetica Neue", Arial, sans-serif',        label: 'Space Grotesk' },
  jetbrains: { stack: '"JetBrains Mono", ui-monospace, monospace',                   label: 'JetBrains Mono' },
};

// Thai fonts loaded from Google Fonts in index.html. Pick any per group
// in the dev tweaks panel. All have Latin glyphs too, but they're inserted
// AFTER the Latin font in the stack so Latin chars stay in Inter/Grotesk.
const THAI_FONTS = {
  noto:    { stack: '"Noto Sans Thai"', label: 'Noto Sans Thai (default)' },
  kanit:   { stack: '"Kanit"',          label: 'Kanit' },
  prompt:  { stack: '"Prompt"',         label: 'Prompt' },
};

// Thai font weight options — applied only in TH mode, overriding the
// per-group CSS weight variables. Browser does nearest-weight fallback
// for fonts that don't expose every weight (e.g., Mitr has no Thin).
const THAI_WEIGHTS = [
  { value: '100', label: 'Thin (100)' },
  { value: '300', label: 'Light (300)' },
  { value: '400', label: 'Regular (400)' },
  { value: '500', label: 'Medium (500)' },
  { value: '600', label: 'SemiBold (600)' },
  { value: '700', label: 'Bold (700)' },
];

// Build the runtime font stack. In EN mode the Latin font wins for Latin
// chars and the Thai font cascades for Thai codepoints. In TH mode the
// Thai font wins for everything — Latin text inside Thai sentences also
// renders in the chosen Thai font (Noto Sans Thai and Kanit both have
// Latin glyphs), so the page reads as one cohesive language switch.
// Falls back to the first key in THAI_FONTS if the requested key is
// unknown, so stale tweak values from previous palettes don't break.
function buildFontStack(latinStack, thaiKey, lang) {
  const thai = (THAI_FONTS[thaiKey] || Object.values(THAI_FONTS)[0]).stack;
  if (lang === 'TH') return `${thai}, ${latinStack}`;
  const i = latinStack.indexOf(',');
  if (i === -1) return `${latinStack}, ${thai}`;
  return `${latinStack.slice(0, i + 1)} ${thai},${latinStack.slice(i + 1)}`;
}

// Visitor-facing language preference. Independent of useTweaks because
// useTweaks posts to the Antigravity bundler host (which rewrites source
// on disk) and does NOT persist to browser localStorage. First visit:
// auto-detect from navigator.languages; Thai browsers land in TH, all
// others in EN. User's manual choice is sticky across visits.
const LANG_STORAGE_KEY = 'autopilot-lang';
function useLang() {
  const [lang, setLangState] = useState(() => {
    try {
      const saved = localStorage.getItem(LANG_STORAGE_KEY);
      if (saved === 'EN' || saved === 'TH') return saved;
    } catch (e) { /* localStorage may be blocked (private mode, file://) */ }
    const langs = (typeof navigator !== 'undefined')
      ? (navigator.languages || [navigator.language || ''])
      : [];
    return langs.some(l => (l || '').toLowerCase().startsWith('th')) ? 'TH' : 'EN';
  });
  const setLang = (v) => {
    if (v !== 'EN' && v !== 'TH') return;
    try { localStorage.setItem(LANG_STORAGE_KEY, v); } catch (e) {}
    setLangState(v);
  };
  return [lang, setLang];
}

function App() {
  const [tweaks, setTweak] = window.useTweaks
    ? window.useTweaks(TWEAK_DEFAULTS)
    : useFallback(TWEAK_DEFAULTS);

  const [lang, setLang] = useLang();
  const t = window.I18N[lang] || window.I18N.EN;

  useEffect(() => {
    const root = document.documentElement;
    root.dataset.theme = tweaks.theme;
    root.dataset.lang = lang;
    // Set <html lang> so screen readers switch voice, browser translate
    // UI doesn't offer to translate already-localized content, and search
    // engines understand intent.
    root.lang = (lang === 'TH') ? 'th' : 'en';
    if (t && t.meta && t.meta.title) document.title = t.meta.title;
    const fp = FONT_PAIRS[tweaks.fontPair] || FONT_PAIRS.grotesk;
    // --font-display is the global display fallback — pair it with the
    // header Thai font choice so it stays consistent with --font-header.
    root.style.setProperty('--font-display', buildFontStack(fp.display, tweaks.headerThaiFont, lang));
    const bf = BODY_FONTS[tweaks.bodyFont] || BODY_FONTS.inter;
    root.style.setProperty('--font-body', buildFontStack(bf.stack, tweaks.bodyThaiFont, lang));
    const hf = DISPLAY_FONTS[tweaks.headerFont] || DISPLAY_FONTS.inter;
    root.style.setProperty('--font-header', buildFontStack(hf.stack, tweaks.headerThaiFont, lang));
    const btf = DISPLAY_FONTS[tweaks.buttonFont] || DISPLAY_FONTS.grotesk;
    root.style.setProperty('--font-button', buildFontStack(btf.stack, tweaks.buttonThaiFont, lang));
    root.style.setProperty('--case-header', tweaks.caseHeader || 'none');
    root.style.setProperty('--case-body',   tweaks.caseBody   || 'none');
    root.style.setProperty('--case-button', tweaks.caseButton || 'none');
    root.style.setProperty('--accent', tweaks.accent);
    root.style.setProperty('--accent-soft', hexA(tweaks.accent, 0.12));
    root.style.setProperty('--tagline-main-size', `clamp(40px, ${(tweaks.taglineMainSize || 80) / 14}vw, ${tweaks.taglineMainSize || 80}px)`);
    root.style.setProperty('--tagline-sub-size',  `${tweaks.taglineSubSize || 14}px`);

    // Typography library — each slider rebuilds one CSS variable. The clamp()
    // ranges keep responsive scaling on smaller screens; the user-controlled
    // value sets the desktop max so changing one slider updates every place
    // that style is used across the page.
    const titleMax = tweaks.titleSize || 42;
    const leadVal  = tweaks.leadSize || 20;
    const bodyLg   = Math.max(13, Math.min(28, (tweaks.bodySize || 15) + 4));
    root.style.setProperty('--text-title-size', `clamp(26px, 3.1vw, ${titleMax}px)`);
    root.style.setProperty('--text-card-size',  `${tweaks.cardSize || 18}px`);
    // Lead size: direct px so the slider applies at any value (the previous
    // clamp had a 20px floor that ignored values below it).
    root.style.setProperty('--text-lead-size',  `${leadVal}px`);
    root.style.setProperty('--text-body-size',  `${tweaks.bodySize || 15}px`);
    root.style.setProperty('--text-body-size-large', `clamp(${tweaks.bodySize || 15}px, 1.5vw, ${bodyLg}px)`);
    root.style.setProperty('--text-body-line',  String(tweaks.bodyLine || 1.55));
    root.style.setProperty('--text-label-size', `${tweaks.labelSize || 11}px`);
    root.style.setProperty('--text-ui-size',    `${tweaks.uiSize || 14}px`);

    // Eyebrow label font — overrides the CSS default (var(--font-mono)) so
    // both Latin and Thai eyebrow fonts can be tuned independently of body.
    const eyeF = BODY_FONTS[tweaks.eyebrowFont] || BODY_FONTS.mono;
    root.style.setProperty('--text-label-family', buildFontStack(eyeF.stack, tweaks.eyebrowThaiFont, lang));

    // Lead font dropdown — pick the Inter / Grotesk / JetBrains stack and
    // write it to the variable that every Lead Paragraph reads.
    const leadF = DISPLAY_FONTS[tweaks.leadFont] || DISPLAY_FONTS.inter;
    root.style.setProperty('--text-lead-family', buildFontStack(leadF.stack, tweaks.leadThaiFont, lang));

    // Big Number font + size — controls .why-num and .result-stat together.
    const numF = DISPLAY_FONTS[tweaks.numFont] || DISPLAY_FONTS.grotesk;
    root.style.setProperty('--text-num-family', buildFontStack(numF.stack, tweaks.numThaiFont, lang));
    root.style.setProperty('--text-num-size',   `${tweaks.numSize || 48}px`);

    // Per-group Thai weight overrides — Thai fonts often need a different
    // weight than the matching Latin to look balanced. Apply only in TH
    // mode; in EN mode, clear the inline overrides so the CSS root
    // defaults (declared at the top of styles.css) take over again.
    // Header tweak controls THREE related weight variables: --text-title
    // (h2/h3 etc.), --text-mega (.display-1, .hero-mark, .cta h2), and
    // --text-card (.cap-card h3, .faq-q, .why-spine-title). Conceptually
    // they're all heading-weight; we collapse them into one user control.
    const weightMap = [
      ['--text-title-weight', tweaks.headerThaiWeight],
      ['--text-mega-weight',  tweaks.headerThaiWeight],
      ['--text-card-weight',  tweaks.headerThaiWeight],
      ['--text-body-weight',  tweaks.bodyThaiWeight],
      ['--text-ui-weight',    tweaks.buttonThaiWeight],
      ['--text-lead-weight',  tweaks.leadThaiWeight],
      ['--text-num-weight',   tweaks.numThaiWeight],
      ['--text-label-weight', tweaks.eyebrowThaiWeight],
    ];
    if (lang === 'TH') {
      weightMap.forEach(([cssVar, val]) => {
        if (val) root.style.setProperty(cssVar, String(val));
      });
    } else {
      weightMap.forEach(([cssVar]) => root.style.removeProperty(cssVar));
    }
  }, [tweaks, lang]);

  // Defer non-critical chrome (side nav, sticky mobile bar) until after
  // first paint so they don't add to the initial layout cost. The page
  // is fully usable without them — they're enhancements.
  const [chromeReady, setChromeReady] = useState(false);
  useEffect(() => {
    let id;
    const mount = () => setChromeReady(true);
    if ('requestIdleCallback' in window) {
      id = window.requestIdleCallback(mount, { timeout: 1200 });
      return () => window.cancelIdleCallback && window.cancelIdleCallback(id);
    }
    id = setTimeout(mount, 250);
    return () => clearTimeout(id);
  }, []);

  // scroll reveal observer
  useEffect(() => {
    const els = document.querySelectorAll('.reveal');
    els.forEach(el => el.classList.add('reveal-pre'));
    requestAnimationFrame(() => {
      els.forEach(el => {
        const r = el.getBoundingClientRect();
        if (r.top < window.innerHeight && r.bottom > 0) el.classList.add('in');
      });
    });
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); } });
    }, { threshold: 0, rootMargin: '0px 0px -10% 0px' });
    els.forEach(el => { if (!el.classList.contains('in')) io.observe(el); });
    const tt = setTimeout(() => {
      document.querySelectorAll('.reveal-pre:not(.in)').forEach(el => el.classList.add('in'));
    }, 2000);
    return () => { io.disconnect(); clearTimeout(tt); };
  }, [tweaks.splineOn, tweaks.taglineMode]);

  return (
    <>
      {chromeReady && window.SideNav && <window.SideNav accent={tweaks.accent} t={t} lang={lang} setLang={setLang} />}
      {window.LangSwitchFloat && <window.LangSwitchFloat lang={lang} setLang={setLang} />}
      <Hero
        taglineMode={tweaks.taglineMode}
        splineOn={tweaks.splineOn}
        accent={tweaks.accent}
        t={t}
      />
      {window.Tools && <window.Tools t={t} />}
      <Problem accent={tweaks.accent} t={t} />
      <Results accent={tweaks.accent} t={t} />
      <HowItWorks accent={tweaks.accent} t={t} />
      <About accent={tweaks.accent} t={t} />
      <Capabilities accent={tweaks.accent} t={t} />
      <Why accent={tweaks.accent} t={t} />
      {window.Pricing && <window.Pricing accent={tweaks.accent} t={t} />}
      <FAQ accent={tweaks.accent} t={t} />
      <CTA accent={tweaks.accent} t={t} />
      <Footer t={t} />
      {chromeReady && window.StickyMobileCTA && <window.StickyMobileCTA accent={tweaks.accent} t={t} />}

      {window.TweaksPanel && (
        <window.TweaksPanel title="Tweaks">
          <window.TweakSection title="Appearance">
            <window.TweakRadio
              label="Theme"
              value={tweaks.theme}
              options={[{value:'dark',label:'Dark'},{value:'light',label:'Light'}]}
              onChange={v => setTweak('theme', v)}
            />
            <window.TweakColor
              label="Accent"
              value={tweaks.accent}
              onChange={v => setTweak('accent', v)}
            />
          </window.TweakSection>

          <window.TweakSection title="Typography">
            <window.TweakSelect
              label="Header font"
              value={tweaks.headerFont}
              options={Object.entries(DISPLAY_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('headerFont', v)}
            />
            <window.TweakSelect
              label="Header Thai font"
              value={tweaks.headerThaiFont}
              options={Object.entries(THAI_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('headerThaiFont', v)}
            />
            <window.TweakSelect
              label="Header Thai weight"
              value={tweaks.headerThaiWeight}
              options={THAI_WEIGHTS}
              onChange={v => setTweak('headerThaiWeight', v)}
            />
            <window.TweakRadio
              label="Header case"
              value={tweaks.caseHeader}
              options={[{value:'none',label:'Proper'},{value:'uppercase',label:'Upper'}]}
              onChange={v => setTweak('caseHeader', v)}
            />
            <window.TweakSelect
              label="Body font"
              value={tweaks.bodyFont}
              options={Object.entries(BODY_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('bodyFont', v)}
            />
            <window.TweakSelect
              label="Body Thai font"
              value={tweaks.bodyThaiFont}
              options={Object.entries(THAI_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('bodyThaiFont', v)}
            />
            <window.TweakSelect
              label="Body Thai weight"
              value={tweaks.bodyThaiWeight}
              options={THAI_WEIGHTS}
              onChange={v => setTweak('bodyThaiWeight', v)}
            />
            <window.TweakRadio
              label="Body case"
              value={tweaks.caseBody}
              options={[{value:'none',label:'Proper'},{value:'uppercase',label:'Upper'}]}
              onChange={v => setTweak('caseBody', v)}
            />
            <window.TweakSelect
              label="Button font"
              value={tweaks.buttonFont}
              options={Object.entries(DISPLAY_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('buttonFont', v)}
            />
            <window.TweakSelect
              label="Button Thai font"
              value={tweaks.buttonThaiFont}
              options={Object.entries(THAI_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('buttonThaiFont', v)}
            />
            <window.TweakSelect
              label="Button Thai weight"
              value={tweaks.buttonThaiWeight}
              options={THAI_WEIGHTS}
              onChange={v => setTweak('buttonThaiWeight', v)}
            />
            <window.TweakRadio
              label="Button case"
              value={tweaks.caseButton}
              options={[{value:'none',label:'Proper'},{value:'uppercase',label:'Upper'}]}
              onChange={v => setTweak('caseButton', v)}
            />
          </window.TweakSection>

          <window.TweakSection title="Hero">
            <window.TweakRadio
              label="Tagline"
              value={tweaks.taglineMode}
              options={[
                { value:'stack', label:'AUTOPILOT / WORKFLOW' },
                { value:'line',  label:'Your workflow, on autopilot.' },
              ]}
              onChange={v => setTweak('taglineMode', v)}
            />
            <window.TweakToggle
              label="3D scene"
              value={tweaks.splineOn}
              onChange={v => setTweak('splineOn', v)}
            />
            <window.TweakSlider
              label="Main size (px)"
              value={tweaks.taglineMainSize}
              min={32} max={140} step={2}
              onChange={v => setTweak('taglineMainSize', v)}
            />
            <window.TweakSlider
              label="Sub size (px)"
              value={tweaks.taglineSubSize}
              min={10} max={48} step={1}
              onChange={v => setTweak('taglineSubSize', v)}
            />
          </window.TweakSection>

          {/* Each slider here updates one CSS variable that's read by every
              place a given text style is used across the page. Drag a slider
              and watch all matching elements move together. */}
          <window.TweakSection title="Text styles">
            <window.TweakSlider
              label="Section title (px)"
              value={tweaks.titleSize}
              min={20} max={72} step={1}
              onChange={v => setTweak('titleSize', v)}
            />
            <window.TweakSlider
              label="Card title (px)"
              value={tweaks.cardSize}
              min={12} max={28} step={1}
              onChange={v => setTweak('cardSize', v)}
            />
            <window.TweakSelect
              label="Lead font"
              value={tweaks.leadFont}
              options={Object.entries(DISPLAY_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('leadFont', v)}
            />
            <window.TweakSelect
              label="Lead Thai font"
              value={tweaks.leadThaiFont}
              options={Object.entries(THAI_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('leadThaiFont', v)}
            />
            <window.TweakSelect
              label="Lead Thai weight"
              value={tweaks.leadThaiWeight}
              options={THAI_WEIGHTS}
              onChange={v => setTweak('leadThaiWeight', v)}
            />
            <window.TweakSlider
              label="Lead paragraph (px)"
              value={tweaks.leadSize}
              min={16} max={40} step={1}
              onChange={v => setTweak('leadSize', v)}
            />
            <window.TweakSlider
              label="Body paragraph (px)"
              value={tweaks.bodySize}
              min={12} max={22} step={1}
              onChange={v => setTweak('bodySize', v)}
            />
            <window.TweakSlider
              label="Body line-height"
              value={tweaks.bodyLine}
              min={1.2} max={2.0} step={0.05}
              onChange={v => setTweak('bodyLine', v)}
            />
            <window.TweakSelect
              label="Eyebrow font"
              value={tweaks.eyebrowFont}
              options={Object.entries(BODY_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('eyebrowFont', v)}
            />
            <window.TweakSelect
              label="Eyebrow Thai font"
              value={tweaks.eyebrowThaiFont}
              options={Object.entries(THAI_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('eyebrowThaiFont', v)}
            />
            <window.TweakSelect
              label="Eyebrow Thai weight"
              value={tweaks.eyebrowThaiWeight}
              options={THAI_WEIGHTS}
              onChange={v => setTweak('eyebrowThaiWeight', v)}
            />
            <window.TweakSlider
              label="Eyebrow label (px)"
              value={tweaks.labelSize}
              min={9} max={18} step={1}
              onChange={v => setTweak('labelSize', v)}
            />
            <window.TweakSlider
              label="UI text (px)"
              value={tweaks.uiSize}
              min={10} max={20} step={1}
              onChange={v => setTweak('uiSize', v)}
            />
            <window.TweakSelect
              label="Big number font"
              value={tweaks.numFont}
              options={Object.entries(DISPLAY_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('numFont', v)}
            />
            <window.TweakSelect
              label="Big number Thai font"
              value={tweaks.numThaiFont}
              options={Object.entries(THAI_FONTS).map(([value, v]) => ({ value, label: v.label }))}
              onChange={v => setTweak('numThaiFont', v)}
            />
            <window.TweakSelect
              label="Big number Thai weight"
              value={tweaks.numThaiWeight}
              options={THAI_WEIGHTS}
              onChange={v => setTweak('numThaiWeight', v)}
            />
            <window.TweakSlider
              label="Big number (px)"
              value={tweaks.numSize}
              min={24} max={96} step={1}
              onChange={v => setTweak('numSize', v)}
            />
          </window.TweakSection>
        </window.TweaksPanel>
      )}
    </>
  );
}

function useFallback(defaults) {
  const [s, setS] = useState(defaults);
  const set = (k, v) => setS(prev => typeof k === 'object' ? { ...prev, ...k } : { ...prev, [k]: v });
  return [s, set];
}

function hexA(hex, a) {
  if (!hex || hex[0] !== '#') return `rgba(230,0,0,${a})`;
  const h = hex.slice(1);
  const v = h.length === 3
    ? h.split('').map(c => parseInt(c+c,16))
    : [parseInt(h.slice(0,2),16), parseInt(h.slice(2,4),16), parseInt(h.slice(4,6),16)];
  return `rgba(${v[0]},${v[1]},${v[2]},${a})`;
}

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