/* global React, ReactDOM */
const { useState, useEffect, useRef, useCallback } = React;

/* ============================================================
   DATA
   ============================================================ */
const WORKS = [
{ id: "work-1", title: "Spring Explosion", year: "2026", medium: "Acrylic on canvas", size: "50 × 70 cm", link: "https://www.saatchiart.com/en-de/art/Painting-Spring-Explosion/1481511/13665937/view" },
{ id: "work-2", title: "Chromatic Burst", year: "2026", medium: "Acrylic on canvas", size: "50 × 50 cm", link: "https://www.saatchiart.com/en-de/art/Painting-Chromatic-Burst/1481511/13655763/view" },
{ id: "work-3", title: "Vibrant Energy", year: "2026", medium: "Acrylic on canvas", size: "50 × 50 cm", link: "https://www.saatchiart.com/en-de/art/Painting-Vibrant-Energy/1481511/13655735/view" },
{ id: "work-4", title: "Dynamic Pulse", year: "2026", medium: "Acrylic on canvas", size: "50 × 70 cm", link: "https://www.saatchiart.com/en-de/art/Painting-Dynamic-Pulse/1481511/13745687/view" },
{ id: "work-5", title: "Ethereal Bloom", year: "2026", medium: "Acrylic on canvas", size: "50 × 70 cm", link: "https://www.saatchiart.com/en-de/art/Painting-Ethereal-Bloom/1481511/13684545/view" },
{ id: "work-6", title: "Vibrant Pulse", year: "2026", medium: "Acrylic on canvas", size: "100 × 80 cm" },
{ id: "work-7", title: "First Light", year: "2025", medium: "Oil & acrylic on canvas", size: "80 × 60 cm" },
{ id: "work-8", title: "The sky in dream colors", year: "2024", medium: "Oil on canvas", size: "100 × 70 cm" },
{ id: "work-9", title: "Golden Hour", year: "2025", medium: "Oil on canvas", size: "40 × 30 cm" }];


const CV = [
{
  cat: "Solo Exhibitions",
  rows: [
  { yr: "2013", ttl: "Solo Exhibition", loc: "Kherson Cultural Centre, Kherson, Ukraine" }]

},
{
  cat: "Group Exhibitions",
  rows: [
  { yr: "2024", ttl: "Art Alt Stadt MH Reloaded", loc: "Petrikirche, Mülheim an der Ruhr, Germany" }]

},
{
  cat: "Memberships",
  rows: [
  { yr: "2015", ttl: "“Dnieper Palette”", loc: "Member, Kherson Regional Union of Fine & Decorative Arts, Ukraine" }]

},
{
  cat: "Education",
  rows: [
  { yr: "2010–15", ttl: "Kherson National Technical University", loc: "Faculty of Design, Ukraine" },
  { yr: "2006–10", ttl: "Kherson College of Culture", loc: "Department of Fine & Decorative Arts, Ukraine" }]

},
{
  cat: "Collections",
  rows: [
  { yr: "—", ttl: "Private collections", loc: "United States, France, Italy & Germany" }]

}];


const SAATCHI = "https://www.saatchiart.com/en-de/zavadskayaart";
const EMAIL = "e.zavadskaya91@gmail.com";

/* ============================================================
   NAV
   ============================================================ */
function Nav({ onJump }) {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const on = () => setScrolled(window.scrollY > 40);
    on();
    window.addEventListener("scroll", on, { passive: true });
    return () => window.removeEventListener("scroll", on);
  }, []);
  const link = (id, label) =>
  <a href={"#" + id} onClick={(e) => {e.preventDefault();onJump(id);}}>{label}</a>;

  return (
    <nav className={"nav" + (scrolled ? " scrolled" : "")}>
      <a className="brand" href="#top" onClick={(e) => {e.preventDefault();onJump("top");}}>
        Kateryna Zavadska
        <small>Painter</small>
      </a>
      <div className="nav-links">
        {link("work", "Work")}
        {link("about", "About")}
        {link("exhibitions", "Exhibitions")}
        <a className="nav-cta" href="#commission" onClick={(e) => {e.preventDefault();onJump("commission");}}>Commission</a>
      </div>
    </nav>);

}

/* ============================================================
   HERO
   ============================================================ */
function Hero({ onJump }) {
  return (
    <header className="hero" id="top">
      <div className="hero-text">
        <p className="eyebrow">Gestural Abstraction · Painting</p>
        <h1>Painting the<br />weather of <em>feeling</em></h1>
        <p className="medium">MÜLHEIM AN DER RUHR — WORKING IN OIL, ACRYLIC & MIXED MEDIA</p>
        <p className="lede">
          Large-scale abstract paintings built from gesture, memory and atmosphere —
          where colour is allowed to behave like light moving through a room.
        </p>
        <div className="hero-actions">
          <button className="btn btn-solid" onClick={() => onJump("work")}>View the work</button>
          <a className="btn btn-link" href="#commission" onClick={(e) => {e.preventDefault();onJump("commission");}}>
            Commission a piece <span className="arrow">→</span>
          </a>
        </div>
      </div>
      <figure className="hero-figure">
        <image-slot id="work-hero" shape="rect" fit="cover" placeholder="Drop your featured painting"></image-slot>
        <figcaption className="fig-cap">
          <span>Featured</span>
          <em>Dynamic Pulse, 2025</em>
        </figcaption>
      </figure>
    </header>);

}

/* ============================================================
   GALLERY
   ============================================================ */
function Gallery({ onOpen }) {
  return (
    <section className="gallery wrap" id="work">
      <div className="sec-head reveal">
        <span className="idx">01 / Selected Works</span>
        <h2>Paintings</h2>
        <p className="head-note">A selection of recent canvases and works on paper. Click any piece to view it larger.</p>
      </div>
      <div className="grid">
        {WORKS.map((w, i) =>
        <figure className="work reveal" key={w.id} style={{ transitionDelay: i % 3 * 80 + "ms" }}
        onClick={() => onOpen(i)}>
            <div className="frame-wrap">
              <span className="view-hint">View</span>
              <image-slot id={w.id} shape="rect" fit="cover"
            placeholder={`Drop “${w.title}”`}></image-slot>
            </div>
            <figcaption>
              <div className="meta">
                <span className="t">{w.title}</span>
                <span className="yr">{w.year}</span>
              </div>
              <div className="meta-sub">{w.medium} · {w.size}</div>
            </figcaption>
          </figure>
        )}
      </div>
      <div className="gallery-foot reveal">
        <p>Original works &amp; prints are available through</p>
        <a className="lb-saatchi" href={SAATCHI} target="_blank" rel="noopener">Saatchi Art ↗</a>
      </div>
    </section>);

}

/* ============================================================
   LIGHTBOX
   ============================================================ */
function Lightbox({ index, onClose, onPrev, onNext, onInquire }) {
  const open = index !== null;
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => {
      if (e.key === "Escape") onClose();else
      if (e.key === "ArrowLeft") onPrev();else
      if (e.key === "ArrowRight") onNext();
    };
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [open, onClose, onPrev, onNext]);

  const w = open ? WORKS[index] : null;
  return (
    <div className={"lb" + (open ? " open" : "")} aria-hidden={!open}>
      <button className="lb-close" onClick={onClose} aria-label="Close">
        <svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="1.4">
          <path d="M2 2l14 14M16 2L2 16" />
        </svg>
      </button>
      <button className="lb-nav lb-prev" onClick={onPrev} aria-label="Previous">
        <svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="1.3">
          <path d="M12 3L5 10l7 7" />
        </svg>
      </button>
      <button className="lb-nav lb-next" onClick={onNext} aria-label="Next">
        <svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" strokeWidth="1.3">
          <path d="M8 3l7 7-7 7" />
        </svg>
      </button>
      <div className="lb-stage">
        {open &&
        <image-slot key={w.id} id={w.id} shape="rect" fit="contain"
        placeholder="Drop this painting to preview"></image-slot>
        }
      </div>
      {open &&
      <div className="lb-panel">
          <div className="num">{String(index + 1).padStart(2, "0")} — {String(WORKS.length).padStart(2, "0")}</div>
          <h3>{w.title}</h3>
          <dl className="lb-meta">
            <div className="row"><dt>Year</dt><dd>{w.year}</dd></div>
            <div className="row"><dt>Medium</dt><dd>{w.medium}</dd></div>
            <div className="row"><dt>Size</dt><dd>{w.size}</dd></div>
          </dl>
          <div className="lb-actions">
            <a className="lb-saatchi" href={w.link || SAATCHI} target="_blank" rel="noopener">{w.link ? "Acquire on Saatchi Art ↗" : "View on Saatchi Art ↗"}</a>
            <a className="lb-inquire" href="#commission"
          onClick={(e) => {e.preventDefault();onInquire();}}>Or enquire about this piece</a>
          </div>
        </div>
      }
    </div>);

}

/* ============================================================
   ABOUT
   ============================================================ */
function About() {
  return (
    <section className="about wrap" id="about">
      <div className="sec-head reveal">
        <span className="idx">02 / Studio</span>
        <h2>About</h2>
      </div>
      <div className="about-grid">
        <div className="about-portrait reveal">
          <image-slot id="portrait" shape="rect" fit="cover" placeholder="Drop a studio portrait"></image-slot>
          <p className="p-cap">KATERYNA ZAVADSKA, STUDIO — MÜLHEIM AN DER RUHR
</p>
        </div>
        <div className="about-body reveal">
          <p>Kateryna Zavadska is a painter based in Mülheim an der Ruhr. Her canvases begin without a plan — a single gesture, a remembered colour, the residue of a particular light — and grow through layering, erasure and return.




          </p>
          <p className="pull">
            “I am not painting a landscape. I am painting the moment the landscape
            became a feeling.”
          </p>
          <p className="small">
            The result is abstraction that stays close to the body: weather, water
            and breath as organising forces rather than subjects. Each surface holds
            its own history of decisions, the visible record of being made slowly.
          </p>
          <p className="small">Her work is held in private collections in the United States, France, Italy and Germany, and is shown internationally through the Saatchi Art platform and private collections across Europe and North America.



          </p>
          <div className="about-sign">— Kateryna</div>
        </div>
      </div>
    </section>);
}

/* ============================================================
   EXHIBITIONS / CV
   ============================================================ */
function Exhibitions() {
  return (
    <section className="cv" id="exhibitions">
      <div className="wrap">
        <div className="sec-head reveal" style={{ borderTopColor: "var(--line)" }}>
          <span className="idx">03 / Curriculum</span>
          <h2>Exhibitions &amp; Recognition</h2>
        </div>
        <div className="cv-grid">
          {CV.map((block) =>
          <div className="cv-block reveal" key={block.cat}>
              <div className="cv-cat">{block.cat}</div>
              <div className="cv-list">
                {block.rows.map((r, i) =>
              <div className="cv-row" key={i}>
                    <span className="yr">{r.yr}</span>
                    <span className="desc">
                      <span className="ttl">{r.ttl}</span>
                      {r.loc && <span className="loc">, {r.loc}</span>}
                    </span>
                  </div>
              )}
              </div>
            </div>
          )}
        </div>
      </div>
    </section>);

}

/* ============================================================
   COMMISSION FORM
   ============================================================ */
const BUDGETS = ["Under €1,500", "€1,500 – €3,500", "€3,500 – €7,000", "€7,000 +", "Not sure yet"];
const KINDS = ["Original painting", "Commissioned piece", "Print enquiry", "Exhibition / press", "Other"];

function Commission({ formRef, prefill }) {
  const [values, setValues] = useState({
    name: "", email: "", kind: "", size: "", budget: "", timeline: "", message: ""
  });
  const [errors, setErrors] = useState({});
  const [sent, setSent] = useState(false);

  useEffect(() => {
    if (prefill) {
      setValues((v) => ({
        ...v,
        kind: v.kind || "Original painting",
        message: v.message || `I'm interested in "${prefill}". Could you tell me more about availability?`
      }));
    }
  }, [prefill]);

  const set = (k) => (e) => {
    setValues((v) => ({ ...v, [k]: e.target.value }));
    setErrors((er) => er[k] ? { ...er, [k]: false } : er);
  };

  const validate = () => {
    const er = {};
    if (!values.name.trim()) er.name = true;
    if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(values.email.trim())) er.email = true;
    if (!values.message.trim()) er.message = true;
    setErrors(er);
    return Object.keys(er).length === 0;
  };

  const submit = (e) => {
    e.preventDefault();
    if (validate()) setSent(true);
  };

  const reset = () => {
    setSent(false);
    setValues({ name: "", email: "", kind: "", size: "", budget: "", timeline: "", message: "" });
    setErrors({});
  };

  return (
    <section className="commission wrap" id="commission" ref={formRef}>
      <div className="sec-head reveal">
        <span className="idx">04 / Enquiries</span>
        <h2>Commission a Work</h2>
        <p className="head-note">For acquisitions of available paintings, please use Saatchi Art. For commissions and all other enquiries, write below.</p>
      </div>
      <div className="comm-grid">
        <div className="comm-intro reveal">
          <h2>Let's make<br />something for<br /><em style={{ fontStyle: "italic" }}>your</em> space.</h2>
          <p>
            I take on a small number of commissions each year — paintings made in
            dialogue with your space, light and intention.
          </p>
          <div className="comm-steps">
            <div className="step"><span className="n">1</span><div><div className="s-t">Conversation</div><div className="s-d">We discuss scale, palette, and the feeling you want the work to hold.</div></div></div>
            <div className="step"><span className="n">2</span><div><div className="s-t">Sketches</div><div className="s-d">I share studies and a proposal, with timeline and pricing.</div></div></div>
            <div className="step"><span className="n">3</span><div><div className="s-t">The painting</div><div className="s-d">The work is made over 4–10 weeks, with progress shared along the way.</div></div></div>
          </div>
        </div>

        <div className="reveal">
          {!sent ?
          <form className="comm-form" onSubmit={submit} noValidate>
              <div className="field-row">
                <div className={"field" + (errors.name ? " invalid" : "")}>
                  <label>Name <span className="req">*</span></label>
                  <input type="text" value={values.name} onChange={set("name")} placeholder="Your name" />
                  <div className="err-msg">Please enter your name.</div>
                </div>
                <div className={"field" + (errors.email ? " invalid" : "")}>
                  <label>Email <span className="req">*</span></label>
                  <input type="email" value={values.email} onChange={set("email")} placeholder="you@email.com" />
                  <div className="err-msg">Please enter a valid email.</div>
                </div>
              </div>

              <div className="field-row">
                <div className="field">
                  <label>Type of enquiry</label>
                  <select value={values.kind} onChange={set("kind")}>
                    <option value="">Select…</option>
                    {KINDS.map((k) => <option key={k} value={k}>{k}</option>)}
                  </select>
                </div>
                <div className="field">
                  <label>Approx. size</label>
                  <input type="text" value={values.size} onChange={set("size")} placeholder="e.g. 120 × 100 cm" />
                </div>
              </div>

              <div className="field-row">
                <div className="field">
                  <label>Budget range</label>
                  <select value={values.budget} onChange={set("budget")}>
                    <option value="">Select…</option>
                    {BUDGETS.map((b) => <option key={b} value={b}>{b}</option>)}
                  </select>
                </div>
                <div className="field">
                  <label>Ideal timeline</label>
                  <input type="text" value={values.timeline} onChange={set("timeline")} placeholder="e.g. Within 3 months" />
                </div>
              </div>

              <div className={"field" + (errors.message ? " invalid" : "")}>
                <label>Tell me about the work <span className="req">*</span></label>
                <textarea value={values.message} onChange={set("message")}
              placeholder="The space, the feeling, any colours or paintings of mine you're drawn to…"></textarea>
                <div className="err-msg">Please add a short message.</div>
              </div>

              <div className="form-foot">
                <p className="note">I reply personally, usually within 2–3 working days.</p>
                <button type="submit" className="submit-btn">Send enquiry</button>
              </div>
            </form> :

          <div className="comm-form">
              <div className="form-success">
                <div className="check">
                  <svg width="22" height="22" viewBox="0 0 22 22" fill="none" stroke="currentColor" strokeWidth="1.4">
                    <path d="M4 11.5l4.5 4.5L18 6" />
                  </svg>
                </div>
                <h3>Thank you, {values.name.split(" ")[0] || "friend"}.</h3>
                <p>Your enquiry has been noted. I read every message personally and will reply to <strong>{values.email}</strong> within a few days.</p>
                <p>In the meantime, you're welcome to browse available originals on Saatchi Art.</p>
                <button onClick={reset}>Send another enquiry</button>
              </div>
            </div>
          }
        </div>
      </div>
    </section>);

}

/* ============================================================
   FOOTER
   ============================================================ */
function Footer({ onJump }) {
  return (
    <footer className="footer" id="contact">
      <div className="wrap">
        <p className="eyebrow">Get in touch</p>
        <div className="footer-lead">
          <a className="footer-mail" href={"mailto:" + EMAIL}>{EMAIL}</a>
          <div className="footer-social">
            <a href={SAATCHI} target="_blank" rel="noopener">Saatchi Art ↗</a>
            <a href="https://www.instagram.com/kateryna_zavadska_art/" target="_blank" rel="noopener">Instagram ↗</a>
            <a href="#commission" onClick={(e) => {e.preventDefault();onJump("commission");}}>Commission a work</a>
          </div>
        </div>
        <div className="footer-bottom">
          <span>© {new Date().getFullYear()} Kateryna Zavadska</span>
          <span>STUDIO — MÜLHEIM AN DER RUHR</span>
          <span>Gestural Abstraction</span>
        </div>
      </div>
    </footer>);

}

/* ============================================================
   APP
   ============================================================ */
function App() {
  const [lbIndex, setLbIndex] = useState(null);
  const [prefill, setPrefill] = useState(null);
  const commissionRef = useRef(null);

  const jump = useCallback((id) => {
    const el = id === "top" ? document.body : document.getElementById(id);
    if (el) {
      const y = id === "top" ? 0 : el.getBoundingClientRect().top + window.scrollY - 12;
      window.scrollTo({ top: y, behavior: "smooth" });
    }
  }, []);

  const open = useCallback((i) => setLbIndex(i), []);
  const close = useCallback(() => setLbIndex(null), []);
  const prev = useCallback(() => setLbIndex((i) => (i + WORKS.length - 1) % WORKS.length), []);
  const next = useCallback(() => setLbIndex((i) => (i + 1) % WORKS.length), []);

  const inquire = useCallback(() => {
    if (lbIndex !== null) setPrefill(WORKS[lbIndex].title);
    setLbIndex(null);
    setTimeout(() => jump("commission"), 120);
  }, [lbIndex, jump]);

  // Scroll reveal — opt-in via .anim so content is never hidden if JS lags
  useEffect(() => {
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (reduce) return;
    document.documentElement.classList.add("anim");
    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 -8% 0px" });
    els.forEach((el) => io.observe(el));
    return () => {io.disconnect();document.documentElement.classList.remove("anim");};
  }, []);

  return (
    <React.Fragment>
      <Nav onJump={jump} />
      <Hero onJump={jump} />
      <main>
        <Gallery onOpen={open} />
        <About />
        <Exhibitions />
        <Commission formRef={commissionRef} prefill={prefill} />
      </main>
      <Footer onJump={jump} />
      <Lightbox index={lbIndex} onClose={close} onPrev={prev} onNext={next} onInquire={inquire} />
    </React.Fragment>);

}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);