/* Federica Gori — motion condiviso: scroll-reveal + micro-interazioni. Espone window.Reveal. Il CSS è iniettato da qui, così i delle pagine non vanno tenuti allineati a mano. Movimento misurato, coerente coi token del DS (--dur-*, --ease-*): niente rimbalzi, niente loop. */ (function () { const s = document.createElement("style"); s.textContent = ` /* Dissolvenze morbide: durata lunga, curva che si spegne dolcemente, risalita minima — l'ingresso deve sembrare un respiro, non uno scatto. */ .fg-reveal { opacity: 0; transform: translateY(10px); transition: opacity 850ms cubic-bezier(0.25, 0.6, 0.35, 1), transform 950ms cubic-bezier(0.22, 0.8, 0.3, 1); transition-delay: var(--reveal-delay, 0ms); } .fg-reveal.is-in { opacity: 1; transform: none; } /* zoom lieve dell'immagine quando la card è in hover */ .fg-cardimg { transition: transform var(--dur-slow, 480ms) var(--ease-soft, ease); } .fg-card:hover .fg-cardimg { transform: scale(1.04); } /* «Leggi l'articolo →»: underline e freccia via CSS (anche da tastiera) */ .fg-readmore:hover, .fg-readmore:focus-visible { text-decoration: underline; } .fg-readmore .fg-arrow { display: inline-block; transition: transform var(--dur-fast, 140ms) var(--ease-soft, ease); } .fg-readmore:hover .fg-arrow { transform: translateX(3px); } /* chip dei temi del diario */ .fg-chip { transition: background var(--dur-fast, 140ms) var(--ease-soft, ease), border-color var(--dur-fast, 140ms) var(--ease-soft, ease); } .fg-chip:hover { background: var(--sand-200, #F1E9DA); border-color: var(--terra-400, #C98B62) !important; } /* Ritmo verticale: il token DS arriva a 128px per lato e due sezioni adiacenti sommavano ~256px di vuoto. Tetto più basso: 56→96px. */ :root { --section-y: clamp(3.5rem, 6.5vw, 6rem); } /* su mobile il testo dell'hero viene prima della foto */ @media (max-width: 880px) { .fg-media-first { order: 2; } } /* header fisso: ombra leggera solo quando la pagina è scrollata */ header[data-fg-sticky] { transition: box-shadow 300ms ease; } header[data-fg-sticky].is-scrolled { box-shadow: 0 6px 24px rgba(42, 39, 36, 0.07); } /* mobile: più aria ai lati e hamburger con touch-target pieno, allineato otticamente al gutter */ @media (max-width: 760px) { :root { --gutter: 1.5rem; } header button[aria-label="Menu"] { padding: 10px !important; margin: -10px -4px -10px 0; } } @media (prefers-reduced-motion: reduce) { .fg-reveal { opacity: 1 !important; transform: none !important; transition: none !important; } .fg-cardimg, .fg-readmore .fg-arrow { transition: none !important; } .fg-card:hover .fg-cardimg { transform: none !important; } }`; document.head.appendChild(s); })(); const FG_REDUCED = window.matchMedia("(prefers-reduced-motion: reduce)"); /* Observer condiviso, one-shot: rivela ed esce. */ let fgIO = null; function fgObserve(el, onIn) { if (!fgIO) { fgIO = new IntersectionObserver((entries) => { for (const e of entries) { if (e.isIntersecting) { if (e.target.__fgIn) e.target.__fgIn(); fgIO.unobserve(e.target); } } }, { rootMargin: "0px 0px -8% 0px", threshold: 0.1 }); } el.__fgIn = onIn; fgIO.observe(el); return () => fgIO.unobserve(el); } /* — dissolve+rise quando entra nel viewport. Above the fold scatta al frame dopo il mount → dolce entrance al load. Figli di una grid: passare style={{ height: "100%" }}. */ function Reveal({ as = "div", delay = 0, className = "", style = {}, children, ...rest }) { const ref = React.useRef(null); const [inView, setInView] = React.useState(FG_REDUCED.matches); React.useEffect(() => { if (inView || !ref.current) return; return fgObserve(ref.current, () => setInView(true)); }, [inView]); const Tag = as; return ( {children} ); } Object.assign(window, { Reveal });