// Primitives — Wohnung Prags
const Eyebrow = ({ children, tone = "mute", style }) => {
const colors = { mute: "var(--fg-muted)", muteDark: "rgba(245,241,234,0.62)", gold: "var(--gold)" };
return (
{children});
};
const Diamond = ({ size = 6, color = "var(--gold)", style }) =>
;
const HairlineGold = ({ width = 56, style }) =>
;
const RuleDiamond = ({ color = "var(--gold)", maxWidth = 220, style }) =>
;
// Renders an array of strings as stacked headline lines.
// Strings may contain ... for italic-gold emphasis.
const Headline = ({ lines, size = 72, light = false, style }) =>
{lines.map((ln, i) =>
)}
;
// Reveal-on-scroll wrapper. Adds a soft fade+rise as the element enters viewport.
const Reveal = ({ children, delay = 0, y = 24, style }) => {
const ref = React.useRef(null);
const [seen, setSeen] = React.useState(false);
React.useEffect(() => {
if (!ref.current) return;
const obs = new IntersectionObserver(
(entries) => entries.forEach((e) => {if (e.isIntersecting) {setSeen(true);obs.disconnect();}}),
{ threshold: 0.18, rootMargin: "0px 0px -10% 0px" }
);
obs.observe(ref.current);
return () => obs.disconnect();
}, []);
return (
{children}
);
};
// Photo plate with crop motion modes: static / kenburns / parallax.
const Plate = ({ src, mode = "static", position = "center", aspect, height, style, children, overlay = false }) => {
const ref = React.useRef(null);
const [parallaxY, setParallaxY] = React.useState(0);
React.useEffect(() => {
if (mode !== "parallax") return;
const onScroll = () => {
if (!ref.current) return;
const rect = ref.current.getBoundingClientRect();
const winH = window.innerHeight;
const progress = (rect.top + rect.height / 2 - winH / 2) / winH;
setParallaxY(-progress * 40);
};
onScroll();
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, [mode]);
return (
);
};
// Monogram SV·31 — typographic mark for St. Veit 31/B.
const Monogram = ({ size = 44, light = false }) => {
const c = light ? "var(--bone)" : "var(--ink)";
return (
);
};
// CTA button.
const Button = ({ children, onClick, variant = "primary", dark = false, type = "button", as = "button", href }) => {
const base = {
display: "inline-flex", alignItems: "center", justifyContent: "center",
fontFamily: "var(--font-sans)", fontSize: 11, fontWeight: 500,
letterSpacing: "0.22em", textTransform: "uppercase",
padding: "14px 26px", border: "1px solid", cursor: "pointer",
background: "transparent", textDecoration: "none",
transition: "background 280ms, color 280ms, border-color 280ms"
};
const styles = {
primary: dark ?
{ background: "var(--gold)", color: "var(--ink)", borderColor: "var(--gold)" } :
{ background: "var(--ink)", color: "var(--bone)", borderColor: "var(--ink)" },
ghost: dark ?
{ background: "transparent", color: "var(--bone)", borderColor: "rgba(245,241,234,0.5)" } :
{ background: "transparent", color: "var(--ink)", borderColor: "var(--ink)" }
};
const Tag = as === "a" ? "a" : "button";
return (
{children});
};
Object.assign(window, { Eyebrow, Diamond, HairlineGold, RuleDiamond, Headline, Reveal, Plate, Monogram, Button });