// App — root component, Tweaks wiring, scroll behaviour
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"heroVariant": "video-scroll",
"accent": "premium",
"gallery": "grid",
"particlesOn": true
}/*EDITMODE-END*/;
const TG_SUPPORT_URL = "https://t.me/modelcoresupport";
const CONTACT_EMAIL = "aimodelcore@gmail.com";
const ACCENT_TO_ATTR = { premium:"premium", mint:"mint", violet:"violet", magenta:"magenta", mono:"mono" };
// tweaks-panel.jsx и sections.jsx экспортируют только через window — отдельные Babel-файлы не видят чужие const.
const {
useTweaks, TweaksPanel, TweakSection, TweakRadio, TweakToggle,
Icon, Hero, Problems, Showcase, ConsistencyCompare, UseCases, Modules,
Founder, Testimonials, GetStarted, ForWho, TgChannel, FaqList, FinalCTA, Footer, Lightbox,
TG_CHANNEL_URL,
FORM_ENDPOINT,
} = window;
function App() {
const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
const [openPersona, setOpenPersona] = React.useState(null);
const personaTriggerRef = React.useRef(null);
const [headerVisible, setHeaderVisible] = React.useState(false);
const handleOpenPersona = (p, el) => {
personaTriggerRef.current = el ?? null;
setOpenPersona(p);
};
// Apply accent attribute to document root
React.useEffect(() => {
document.documentElement.setAttribute("data-accent", ACCENT_TO_ATTR[t.accent] || "premium");
}, [t.accent]);
// Scroll progress + sticky header + background shift (--bg-n 0–160)
React.useEffect(() => {
let lastY = 0;
const SCROLL_DELTA = 6;
const bar = document.getElementById("scrollProg");
const onScroll = () => {
const doc = document.documentElement;
const max = doc.scrollHeight - doc.clientHeight;
const y = window.scrollY;
if (bar) bar.style.width = ((y / Math.max(1,max)) * 100).toFixed(2) + "%";
const p = max > 0 ? y / max : 0;
const n = Math.round(160 * Math.sin(p * Math.PI));
document.documentElement.style.setProperty("--bg-n", String(n));
if (y < 120) {
setHeaderVisible(false);
} else if (y < lastY - SCROLL_DELTA) {
setHeaderVisible(true);
} else if (y > lastY + SCROLL_DELTA) {
setHeaderVisible(false);
}
lastY = y;
};
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
return () => window.removeEventListener("scroll", onScroll);
}, []);
// Reveal-on-scroll
React.useEffect(() => {
const els = document.querySelectorAll(".reveal");
const io = new IntersectionObserver((entries) => {
entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } });
}, { threshold: 0.12, rootMargin: "0px 0px -60px 0px" });
els.forEach(el => io.observe(el));
return () => io.disconnect();
}, []);
const openTG = () => window.open(TG_CHANNEL_URL, "_blank", "noopener");
return (
<>