/* Shared UI atoms. */
const { useEffect, useRef, useState, useMemo, useCallback } = React;
function useReveal() {
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); } });
}, { rootMargin: '0px 0px -8% 0px', threshold: 0.05 });
els.forEach((el) => io.observe(el));
return () => io.disconnect();
});
}
const SectionLabel = ({ num, children, dark }) => (
{num}
{children}
);
const Eyebrow = ({ children, className = "" }) => (
{children}
);
const Btn = ({ as: As = "button", variant = "primary", children, className = "", ...rest }) => {
const base = "inline-flex items-center gap-2 px-5 h-11 rounded-full text-[14px] font-medium transition-colors duration-150 whitespace-nowrap";
const styles = {
primary: "bg-teal-700 text-paper hover:bg-teal-800",
primaryGold:"bg-gold text-teal-900 hover:bg-gold-600 hover:text-teal-950",
ghost: "bg-transparent text-ink border border-line hover:border-teal-500 hover:text-teal-700",
ghostLight: "bg-transparent text-paper border border-paper/30 hover:border-paper",
dark: "bg-teal-900 text-paper hover:bg-teal-950",
}[variant];
return {children};
};
const Card = ({ children, className = "", as: As = "div" }) => (
{children}
);
/* Formatter: ₽ thousand-separator with NBSP */
const fmt = (n) => {
const sign = n < 0 ? "−" : "";
const v = Math.abs(Math.round(n));
return sign + v.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "\u202f");
};
const fmtK = (n) => {
if (Math.abs(n) >= 1_000_000) return (n / 1_000_000).toFixed(1).replace('.', ',') + " млн";
if (Math.abs(n) >= 1_000) return Math.round(n / 1000) + " тыс";
return fmt(n);
};
window.useReveal = useReveal;
window.SectionLabel = SectionLabel;
window.Eyebrow = Eyebrow;
window.Btn = Btn;
window.Card = Card;
window.fmt = fmt;
window.fmtK = fmtK;