/* ============== VANCED About — app shell, tweaks, reveal ============== */
const { useState, useEffect, useRef } = React;

const DECK_URL = 'https://featpaper.com/l/kzub3PgA'; /* 회사 소개서 (featpaper) */

/* stable base palettes — dark/gradient blocks derive from these so they adapt across themes */
const THEMES = {
  aurora:    { paper: '#07090c', ink: '#f4f7fb', ink2: '#a3adbd', ink3: '#5f6b7d', surface: 'rgba(255,255,255,.035)', sline: 'rgba(255,255,255,.09)', shadow: '0 1px 0 rgba(255,255,255,.04) inset, 0 24px 60px -28px rgba(0,0,0,.7)', glass: 1 },
  editorial: { paper: '#edeae1', ink: '#17170f', ink2: '#54534a', ink3: '#918f81', surface: '#fbfaf6', sline: 'rgba(23,23,15,.07)', shadow: '0 1px 2px rgba(40,38,28,.05), 0 14px 34px -18px rgba(40,38,28,.22)', glass: 0 },
  mono:      { paper: '#f4f4f1', ink: '#0a0a0a', ink2: '#585858', ink3: '#9a9a9a', surface: '#ffffff', sline: 'rgba(11,11,11,.07)', shadow: '0 1px 2px rgba(0,0,0,.05), 0 14px 34px -18px rgba(0,0,0,.16)', glass: 0 },
};

/* presets */
const PRESETS = {
  aurora:    { theme: 'aurora',    pair: 'grotesk', accent: '#23d18b', display: 1.04, h: 1.02, body: 1, label: 1, space: 1.08, reveal: 1.1,  track: -0.03,  weight: 600 },
  editorial: { theme: 'editorial', pair: 'archivo', accent: '#0c7a64', display: 1,    h: 1,    body: 1, label: 1, space: 1,    reveal: 1,    track: -0.02,  weight: 600 },
  mono:      { theme: 'mono',      pair: 'grotesk', accent: '#0b5e7a', display: 1.02, h: 1,    body: 1, label: 1, space: 0.92, reveal: 0.85, track: -0.025, weight: 600 },
};

const DEFAULTS = {
  preset: 'aurora',
  theme: 'aurora',
  pair: 'grotesk',
  accent: '#23d18b',
  display: 1.04, h: 1.02, body: 1, label: 1,
  space: 1.08, maxw: 1240, reveal: 1.1, track: -0.03, weight: 600,
  anim: 'on', aurora: 'on', gradtext: 'on', glow: 'on',
  approach: 'accordion',
};

function applyTokens(t) {
  const r = document.documentElement;
  const th = THEMES[t.theme] || THEMES.editorial;
  r.setAttribute('data-theme', t.theme);
  r.setAttribute('data-pair', t.pair);
  r.setAttribute('data-anim', t.anim);
  /* stable bases */
  r.style.setProperty('--c-paper', th.paper);
  r.style.setProperty('--c-ink', th.ink);
  r.style.setProperty('--c-accent', t.accent);
  /* semantic (default/paper context) */
  r.style.setProperty('--bg', th.paper);
  r.style.setProperty('--ink', th.ink);
  r.style.setProperty('--ink-2', th.ink2);
  r.style.setProperty('--ink-3', th.ink3);
  r.style.setProperty('--line', hexA(th.ink, 0.14));
  r.style.setProperty('--line-2', hexA(th.ink, 0.07));
  r.style.setProperty('--surface', th.surface);
  r.style.setProperty('--surface-line', th.sline);
  r.style.setProperty('--shadow', th.shadow);
  r.style.setProperty('--glass', th.glass ? '1' : '0');
  r.setAttribute('data-glass', th.glass ? 'on' : 'off');
  r.style.setProperty('--accent', t.accent);
  r.style.setProperty('--accent-soft', hexA(t.accent, th.glass ? 0.16 : (t.theme === 'dark' ? 0.2 : 0.12)));
  /* scales */
  r.style.setProperty('--scale-display', t.display);
  r.style.setProperty('--scale-h', t.h);
  r.style.setProperty('--scale-body', t.body);
  r.style.setProperty('--scale-label', t.label);
  r.style.setProperty('--space', t.space);
  r.style.setProperty('--maxw', t.maxw + 'px');
  r.style.setProperty('--reveal-dist', (18 * t.reveal) + 'px');
  r.style.setProperty('--reveal-dur', (900 * (0.55 + 0.45 * t.reveal)) + 'ms');
  r.style.setProperty('--track', t.track + 'em');
  r.style.setProperty('--w-head', t.weight);
  r.setAttribute('data-aurora', t.aurora === 'off' ? 'off' : 'on');
  r.setAttribute('data-gradtext', t.gradtext === 'off' ? 'off' : 'on');
  r.setAttribute('data-glow', t.glow === 'off' ? 'off' : 'on');
  r.setAttribute('data-approach', t.approach || 'accordion');
}
function hexA(hex, a) {
  const c = hex.replace('#', '');
  const r = parseInt(c.substr(0, 2), 16), g = parseInt(c.substr(2, 2), 16), b = parseInt(c.substr(4, 2), 16);
  return `rgba(${r},${g},${b},${a})`;
}

/* ----------------------------- Tweaks panel ----------------------------- */
function Panel() {
  const [t, setTweak] = useTweaks(DEFAULTS);
  const lastPreset = useRef(t.preset);

  useEffect(() => { applyTokens(t); }, [t]);

  useEffect(() => {
    if (t.preset !== lastPreset.current) {
      lastPreset.current = t.preset;
      const p = PRESETS[t.preset];
      if (p) setTweak({ ...p });
    }
  }, [t.preset]);

  return (
    <TweaksPanel title="Tweaks · 밴스드 About">
      <TweakRadio label="시안 프리셋" value={t.preset} onChange={v => setTweak('preset', v)}
        options={[{ value: 'aurora', label: '오로라' }, { value: 'editorial', label: '에디토리얼' }, { value: 'mono', label: '모노' }]} />


      <TweakSection label="브랜드 · Brand">
        <TweakColor label="포인트 컬러" value={t.accent} onChange={v => setTweak('accent', v)}
          options={['#23d18b', '#19c0c0', '#3b82f6', '#0c7a64', '#0b5e7a', '#7c5cff']} />
        <TweakSelect label="영문 폰트" value={t.pair} onChange={v => setTweak('pair', v)}
          options={[{ value: 'grotesk', label: 'Space Grotesk (기본)' }, { value: 'archivo', label: 'Archivo' }, { value: 'serif', label: 'Newsreader (세리프)' }]} />
        <TweakSelect label="테마 (배경/대비)" value={t.theme} onChange={v => setTweak('theme', v)}
          options={[{ value: 'aurora', label: '오로라 (다크 · 글래스)' }, { value: 'editorial', label: '에디토리얼 (웜 라이트)' }, { value: 'mono', label: '모노 (퓨어 화이트)' }]} />
      </TweakSection>

      <TweakSection label="타이포 위계 · Type Scale">
        <TweakSlider label="디스플레이 (대형 타이틀)" min={0.72} max={1.5} step={0.02} value={t.display} onChange={v => setTweak('display', v)} />
        <TweakSlider label="헤딩 (항목 제목)" min={0.78} max={1.4} step={0.02} value={t.h} onChange={v => setTweak('h', v)} />
        <TweakSlider label="본문" min={0.86} max={1.3} step={0.02} value={t.body} onChange={v => setTweak('body', v)} />
        <TweakSlider label="라벨 (키커·영문)" min={0.82} max={1.35} step={0.02} value={t.label} onChange={v => setTweak('label', v)} />
        <TweakSlider label="제목 굵기 (weight)" min={400} max={700} step={100} value={t.weight} onChange={v => setTweak('weight', v)} />
        <TweakSlider label="자간 (디스플레이)" min={-0.05} max={0.02} step={0.005} value={t.track} onChange={v => setTweak('track', v)} />
      </TweakSection>

      <TweakSection label="여백 · 레이아웃">
        <TweakSlider label="섹션 세로 여백" min={0.55} max={1.6} step={0.05} value={t.space} onChange={v => setTweak('space', v)} />
        <TweakSlider label="콘텐츠 최대 폭" min={1000} max={1480} step={20} unit="px" value={t.maxw} onChange={v => setTweak('maxw', v)} />
      </TweakSection>

      <TweakSection label="퓨처 · Futuristic">
        <TweakToggle label="오로라 배경 (다크 전용)" value={t.aurora !== 'off'} onChange={v => setTweak('aurora', v ? 'on' : 'off')} />
        <TweakToggle label="그라데이션 텍스트" value={t.gradtext !== 'off'} onChange={v => setTweak('gradtext', v ? 'on' : 'off')} />
        <TweakToggle label="글로우 강조" value={t.glow !== 'off'} onChange={v => setTweak('glow', v ? 'on' : 'off')} />
      </TweakSection>

      <TweakSection label="모션 · Motion">
        <TweakToggle label="스크롤 애니메이션" value={t.anim === 'on'} onChange={v => setTweak('anim', v ? 'on' : 'off')} />
        <TweakSlider label="애니메이션 세기" min={0.3} max={1.8} step={0.05} value={t.reveal} onChange={v => setTweak('reveal', v)} />
      </TweakSection>
    </TweaksPanel>
  );
}

/* ----------------------------- Section rail ----------------------------- */
const RAIL_SECTIONS = [
  ['why', 'Why VANCED'], ['approach', 'How We Work'],
  ['clientsget', 'What Clients Get'], ['whoworkwith', 'Who We Work With'], ['vision', 'Vision'],
];
function SectionRail() {
  const [active, setActive] = useState(0);
  const [offset, setOffset] = useState(0);
  const [show, setShow] = useState(false);
  const items = useRef([]);
  useEffect(() => {
    const update = () => {
      const focal = window.innerHeight * 0.22;
      let best = 0, bestDist = Infinity;
      RAIL_SECTIONS.forEach(([id], i) => {
        const el = document.getElementById(id);
        if (!el) return;
        const r = el.getBoundingClientRect();
        const c = r.top + r.height / 2;
        const d = Math.abs(c - focal);
        if (d < bestDist) { bestDist = d; best = i; }
      });
      setActive(best);
      const hero = document.getElementById('top');
      const closing = document.getElementById('closing');
      const hb = hero ? hero.getBoundingClientRect().bottom : 0;
      const ct = closing ? closing.getBoundingClientRect().top : 99999;
      setShow(hb < window.innerHeight * 0.32 && ct > window.innerHeight * 0.5);
    };
    update();
    window.addEventListener('scroll', update, { passive: true });
    window.addEventListener('resize', update);
    return () => { window.removeEventListener('scroll', update); window.removeEventListener('resize', update); };
  }, []);
  useEffect(() => {
    const el = items.current[active];
    if (el) setOffset(window.innerHeight * 0.22 - (el.offsetTop + el.offsetHeight / 2));
  }, [active, show]);
  return (
    <nav className="srail" aria-label="섹션 네비게이션"
      style={{ opacity: show ? 1 : 0, pointerEvents: show ? 'auto' : 'none' }}>
      <ul style={{ transform: `translateY(${offset}px)` }}>
        {RAIL_SECTIONS.map(([id, en], i) => (
          <li key={id} ref={el => items.current[i] = el} className={i === active ? 'on' : ''}>
            <a href={`#${id}`}>{en}</a>
          </li>
        ))}
      </ul>
    </nav>
  );
}

/* ----------------------------- Page ----------------------------- */
function App() {
  useEffect(() => {
    // rect-based reveal. Elements already on-screen at load show INSTANTLY (no
    // transition — avoids a blank flash when a freshly-loaded iframe pauses
    // compositing); elements arriving via scroll get the animated reveal.
    const sweep = (instant) => {
      const vh = window.innerHeight || document.documentElement.clientHeight;
      document.querySelectorAll('.reveal:not(.in):not(.seen)').forEach(el => {
        const r = el.getBoundingClientRect();
        if (r.top < vh * 0.95 && r.bottom > -40) el.classList.add(instant ? 'seen' : 'in');
      });
    };
    sweep(true);
    requestAnimationFrame(() => sweep(true));
    const timers = [120, 400, 900].map(ms => setTimeout(() => sweep(true), ms));
    const onScroll = () => sweep(false);
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    return () => {
      timers.forEach(clearTimeout);
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', onScroll);
    };
  }, []);

  return (
    <div className="app">
      <Nav />
      <SectionRail />
      <Hero />
      <Why />
      <Approach />
      <ClientsGet />
      <WhoWeWorkWith />
      <Vision />
      <Closing deckUrl={DECK_URL} />
    </div>
  );
}

/* 게시본: localStorage에 저장된 미세조정 값을 기본값 위에 병합해 초기 적용 (패널 없이도 반영) */
function loadInitialTweaks() {
  try {
    const saved = JSON.parse(localStorage.getItem('vanced_about_tweaks') || '{}') || {};
    return { ...DEFAULTS, ...saved };
  } catch (e) { return DEFAULTS; }
}
applyTokens(loadInitialTweaks());
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
ReactDOM.createRoot(document.getElementById('panel-root')).render(<Panel />);
