const { useState, useEffect, useRef } = React;

/* ----------------------------------------------------------------- */
/*  Styles (injected once — lets us use media queries + :hover)       */
/* ----------------------------------------------------------------- */
const CSS = `
.wrap { max-width: 1240px; margin: 0 auto; padding: 0 24px; }

/* top bar */
.topbar { display:flex; align-items:center; justify-content:space-between;
  padding: 22px 0 18px; }
.lockup { display:flex; align-items:center; gap:14px; }
.mark { font-family:var(--display); font-weight:900; letter-spacing:-0.04em;
  background:var(--orange); color:#000; font-size:22px; line-height:1;
  padding:9px 11px 8px; border-radius:7px; }
.lockup .org { font-family:var(--display); font-weight:800; letter-spacing:0.02em;
  font-size:15px; text-transform:uppercase; color:var(--ink); }
.lockup .org b { color:var(--orange); }
.topbar .right { font-family:var(--mono); font-size:12px; color:#8c7f6f;
  letter-spacing:0.04em; text-transform:uppercase; font-weight:500; }

/* ticker */
.ticker { border-top:2px solid var(--ink); border-bottom:2px solid var(--ink);
  overflow:hidden; white-space:nowrap; background:var(--ink); }
.ticker .track { display:inline-block; padding:11px 0; animation:scroll 30s linear infinite;
  font-family:var(--display); font-weight:800; font-size:14px; letter-spacing:0.06em;
  text-transform:uppercase; color:var(--cream); }
.ticker .track span { margin:0 14px; }
.ticker .track .dot { color:var(--orange); }
@keyframes scroll { from{transform:translateX(0)} to{transform:translateX(-50%)} }

/* hero grid */
.hero { display:grid; grid-template-columns: 1.05fr 0.95fr; gap:56px;
  align-items:start; padding: 60px 24px 80px; }
@media (max-width: 920px){
  .hero { grid-template-columns:1fr; gap:40px; padding:40px 24px 56px; }
}

.eyebrow { font-family:var(--mono); font-size:12.5px; letter-spacing:0.16em;
  text-transform:uppercase; color:var(--orange); margin:0 0 22px;
  display:flex; align-items:center; gap:10px; }
.eyebrow::before { content:""; width:26px; height:2px; background:var(--orange); display:inline-block; }

h1 { font-family:var(--display); font-weight:900; letter-spacing:-0.03em;
  line-height:1.04; font-size: clamp(48px, 7.4vw, 96px); margin:0 0 26px;
  color:var(--ink); text-wrap:balance; }
h1 .hl { color:var(--orange); }
h1 .strike { position:relative; color:#b0a896; }
h1 .strike::after { content:""; position:absolute; left:-2px; right:-2px; top:54%;
  height:7px; background:var(--orange); transform:rotate(-2.5deg); }

.lede { font-size: clamp(17px, 1.7vw, 20px); line-height:1.55; color:#4a443b;
  max-width:30em; margin:0 0 30px; }
.lede b { color:var(--ink); font-weight:600; }

.callout { background:var(--ink); color:var(--cream); border-radius:14px;
  padding:18px 20px 19px; margin:6px 0 0; max-width:34em; position:relative; }
.callout .tag { display:inline-block; font-family:var(--mono); font-size:11px;
  letter-spacing:0.12em; text-transform:uppercase; color:var(--orange); font-weight:600;
  margin-bottom:9px; }
.callout p { margin:0; font-size:16px; line-height:1.5; font-weight:500; color:#f0e9da; }
.callout b { color:#fff; }

.stats { display:flex; gap:34px; flex-wrap:wrap; border-top:1.5px solid #d3cab6; padding-top:26px; }
.stat .n { font-family:var(--display); font-weight:900; font-size:34px; line-height:1;
  color:var(--ink); letter-spacing:-0.02em; }
.stat:first-child .n { color:var(--orange); }
.stat .l { font-family:var(--mono); font-size:11.5px; letter-spacing:0.04em;
  text-transform:uppercase; color:#8c7f6f; margin-top:8px; max-width:14em; font-weight:500; }

/* form card */
.card { background:#ffffff; color:var(--ink); border-radius:18px;
  padding:34px 32px 30px; box-shadow:0 24px 50px -22px rgba(40,30,10,0.32);
  border:1px solid #e4dccb; position:relative; }
.card .badge { position:absolute; top:-14px; right:24px; background:var(--orange);
  color:#000; font-family:var(--display); font-weight:800; font-size:12px;
  letter-spacing:0.04em; text-transform:uppercase; padding:7px 13px; border-radius:999px;
  transform:rotate(3deg); box-shadow:0 6px 18px -6px rgba(254,85,0,0.7); }
.card h2 { font-family:var(--display); font-weight:900; font-size:27px; letter-spacing:-0.02em;
  margin:0 0 6px; line-height:1.04; }
.card .sub { font-size:14.5px; color:#5d564b; margin:0 0 22px; line-height:1.5; }

.field { margin-bottom:15px; }
.field label { display:block; font-family:var(--mono); font-size:11.5px; letter-spacing:0.05em;
  text-transform:uppercase; color:#6f6a60; margin-bottom:7px; font-weight:500; }
.field label .lblnote { color:#a59e90; text-transform:none; letter-spacing:0; }
.inp { width:100%; border:1.5px solid #d8d0bf; background:#fbf9f3; border-radius:10px;
  padding:13px 14px; font-family:var(--body); font-size:15.5px; color:var(--ink);
  transition:border-color .15s, box-shadow .15s; }
.inp::placeholder { color:#b3ab9b; }
.inp:focus { outline:none; border-color:var(--orange); box-shadow:0 0 0 3px rgba(254,85,0,0.16); }
.inp.err { border-color:#d23f1f; box-shadow:0 0 0 3px rgba(210,63,31,0.13); }
.phone-row { display:flex; gap:8px; }
.phone-row .code { flex:0 0 64px; }
.errmsg { color:#c8381a; font-size:12.5px; margin-top:6px; font-weight:500; }

.opts { display:flex; flex-direction:column; gap:10px; margin:18px 0 22px; }
.opt { display:flex; gap:12px; align-items:flex-start; cursor:pointer;
  border:1.5px solid #ded6c5; border-radius:12px; padding:13px 14px;
  transition:border-color .15s, background .15s; user-select:none; }
.opt:hover { border-color:#c4bba8; }
.opt.on { border-color:var(--orange); background:#fff4ee; }
.opt .box { flex:0 0 22px; width:22px; height:22px; border-radius:6px; border:2px solid #c4bba8;
  background:#fff; display:grid; place-items:center; margin-top:1px; transition:.15s; }
.opt.on .box { background:var(--orange); border-color:var(--orange); }
.opt .box svg { opacity:0; transition:.12s; }
.opt.on .box svg { opacity:1; }
.opt .txt b { display:block; font-weight:700; font-size:14.5px; color:var(--ink); }
.opt .txt span { font-size:13px; color:#6f6a60; line-height:1.45; }

.submit { width:100%; border:none; cursor:pointer; background:var(--orange); color:#000;
  font-family:var(--display); font-weight:900; font-size:18px; letter-spacing:0.01em;
  padding:16px; border-radius:12px; transition:transform .12s, background .15s, box-shadow .15s;
  box-shadow:0 10px 26px -10px rgba(254,85,0,0.8); }
.submit:hover:not(:disabled) { transform:translateY(-2px); box-shadow:0 16px 32px -10px rgba(254,85,0,0.85); }
.submit:active:not(:disabled){ transform:translateY(0); }
.submit:disabled { opacity:.6; cursor:default; }
.finep { font-size:11.5px; color:#8c857a; line-height:1.5; margin:14px 2px 0; text-align:center; }
.finep a { color:#6f6a60; }

.demo-flag { font-family:var(--mono); font-size:10.5px; letter-spacing:0.04em;
  text-transform:uppercase; color:#a59e90; text-align:center; margin-top:12px; }

/* success */
.success { text-align:center; padding:6px 4px 4px; }
.success .ring { width:74px; height:74px; border-radius:50%; background:#fff4ee;
  display:grid; place-items:center; margin:0 auto 20px; }
.success h2 { font-size:30px; margin-bottom:8px; }
.success p { font-size:15px; color:#5d564b; line-height:1.55; margin:0 auto 24px; max-width:26em; }
.wa-btn { display:inline-flex; align-items:center; gap:11px; background:#25D366; color:#06291a;
  font-family:var(--display); font-weight:800; font-size:17px; text-decoration:none;
  padding:15px 26px; border-radius:12px; transition:transform .12s, box-shadow .15s;
  box-shadow:0 12px 26px -12px rgba(37,211,102,0.9); }
.wa-btn:hover { transform:translateY(-2px); }
.success .also { font-size:13px; color:#8c857a; margin-top:20px; }

/* footer */
.foot { border-top:1.5px solid #d3cab6; padding:26px 24px 50px; display:flex;
  justify-content:space-between; gap:18px; flex-wrap:wrap;
  font-family:var(--mono); font-size:11.5px; color:#8c7f6f; letter-spacing:0.03em; font-weight:500; }
.foot a { color:#6f6557; text-decoration:none; }
.foot a:hover { color:var(--orange); }

/* overflow safety net + phone tuning */
html, body { overflow-x: hidden; }
h1 { overflow-wrap: break-word; }
@media (max-width: 560px){
  .hero { padding: 32px 20px 48px; gap: 30px; }
  h1 { font-size: clamp(34px, 11vw, 60px); }
  .card { padding: 26px 20px 24px; }
  .stats { gap: 22px; }
  .foot { padding: 24px 20px 44px; flex-direction: column; gap: 8px; align-items: flex-start; }
}
`;

/* ----------------------------------------------------------------- */
/*  Helpers                                                           */
/* ----------------------------------------------------------------- */
function normalisePhone(raw, code) {
  let p = (raw || "").replace(/[\s()-]/g, "");
  if (!p) return "";
  if (p.startsWith("+")) return p;
  if (p.startsWith("00")) return "+" + p.slice(2);
  if (p.startsWith("0")) return code + p.slice(1);
  return code + p;
}
const emailOk = (e) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e);

async function submitToBrevo(data) {
  // Posts to our own serverless endpoint (api/signup.js). The Brevo key lives
  // there, server-side, and never touches the browser — so the page can't be
  // inspected to reach Brevo or read the contact list.
  const res = await fetch("/api/signup", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify(data),
  });
  const body = await res.json().catch(() => ({}));
  if (res.ok && body.ok) return { ok: true, demo: body.demo, whatsappUrl: body.whatsappUrl };
  throw new Error(body.error || "Signup failed, please try again.");
}

/* ----------------------------------------------------------------- */
/*  Components                                                        */
/* ----------------------------------------------------------------- */
function Check() {
  return (
    <svg width="13" height="13" viewBox="0 0 14 14" fill="none">
      <path d="M2 7.5L5.5 11L12 3.5" stroke="#fff" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function TickerBar() {
  const items = ["Pro pubs", "Pro pints", "Pro growth", "Open late", "Keep Soho loud",
    "Less red tape", "Back our venues", "Soho never sleeps"];
  const row = (
    <span>
      {items.map((t, i) => (
        <span key={i}>{t}<span className="dot"> ✦ </span></span>
      ))}
    </span>
  );
  return (
    <div className="ticker">
      <div className="track">{row}{row}</div>
    </div>
  );
}

function SignupCard() {
  const cfg = window.LFG_CONFIG || {};
  const [firstName, setFirstName] = useState("");
  const [email, setEmail] = useState("");
  const [dial, setDial] = useState(cfg.DEFAULT_DIAL_CODE || "+44");
  const [phone, setPhone] = useState("");
  const [joinWhatsApp, setWA] = useState(false);
  const [joinMailing, setML] = useState(false);
  const [company, setCompany] = useState(""); // honeypot — stays empty for real users
  const [waUrl, setWaUrl] = useState(""); // WhatsApp invite, supplied by the server on success
  const [errors, setErrors] = useState({});
  const [status, setStatus] = useState("idle"); // idle | sending | done | error
  const [serverErr, setServerErr] = useState("");

  function validate() {
    const e = {};
    if (!email.trim()) e.email = "We need your email.";
    else if (!emailOk(email.trim())) e.email = "That email doesn't look right.";
    if (joinWhatsApp && !phone.trim()) e.phone = "Add a number to join the WhatsApp group.";
    if (!joinWhatsApp && !joinMailing) e.opts = "Pick at least one way to take part.";
    setErrors(e);
    return Object.keys(e).length === 0;
  }

  async function onSubmit(ev) {
    ev.preventDefault();
    if (!validate()) return;
    setStatus("sending");
    setServerErr("");
    try {
      const result = await submitToBrevo({
        firstName: firstName.trim(),
        email: email.trim(),
        phone: joinWhatsApp ? normalisePhone(phone, dial) : "",
        joinWhatsApp,
        joinMailing,
        company, // honeypot
      });
      setWaUrl(result.whatsappUrl || "");
      setStatus("done");
    } catch (err) {
      setServerErr(err.message || "Something went wrong.");
      setStatus("error");
    }
  }

  if (status === "done") {
    return (
      <div className="card">
        <div className="success">
          <div className="ring">
            <svg width="34" height="34" viewBox="0 0 14 14" fill="none">
              <path d="M2 7.5L5.5 11L12 3.5" stroke="#FE5500" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </div>
          <h2>You're in. LFG.</h2>
          <p>
            {firstName ? firstName + ", you're" : "You're"} on the list to keep Soho open.
            {joinWhatsApp && waUrl ? " Tap below to join the WhatsApp action group. That's where it all kicks off." : ""}
          </p>
          {joinWhatsApp && waUrl && (
            <a className="wa-btn" href={waUrl} target="_blank" rel="noopener noreferrer">
              <svg width="20" height="20" viewBox="0 0 24 24" fill="#06291a"><path d="M12.04 2C6.58 2 2.13 6.45 2.13 11.91c0 1.75.46 3.45 1.32 4.95L2 22l5.25-1.38a9.9 9.9 0 004.79 1.22h.01c5.46 0 9.91-4.45 9.91-9.91 0-2.65-1.03-5.14-2.9-7.01A9.82 9.82 0 0012.04 2zm5.8 14.13c-.24.68-1.42 1.32-1.95 1.36-.5.05-1.13.21-3.66-.78-3.08-1.21-5.04-4.36-5.19-4.56-.15-.2-1.24-1.65-1.24-3.15s.79-2.24 1.07-2.55c.28-.31.61-.39.82-.39.2 0 .41 0 .59.01.19.01.44-.07.69.53.24.6.82 2.05.89 2.2.07.15.12.32.02.52-.1.2-.15.32-.3.5-.15.18-.31.4-.45.53-.15.15-.3.31-.13.6.17.3.76 1.25 1.63 2.02 1.12.99 2.06 1.3 2.36 1.45.3.15.47.13.65-.08.18-.2.75-.87.95-1.17.2-.3.4-.25.67-.15.27.1 1.72.81 2.02.96.3.15.5.22.57.35.07.13.07.73-.17 1.41z"/></svg>
              Join the WhatsApp group
            </a>
          )}
          <div className="also">
            {joinMailing ? "We'll email you campaign updates too." : "Want updates by email? Sign up again and tick the box."}
          </div>
        </div>
      </div>
    );
  }

  return (
    <form className="card" onSubmit={onSubmit} noValidate>
      <div className="badge">Takes 20 seconds</div>
      <h2>Join the movement</h2>
      <p className="sub">Residents, workers, owners, regulars. Anyone who wants Soho to stay open and thrive. Sign up to organise.</p>

      {/* Honeypot: hidden from people, catches naive bots. Do not remove. */}
      <input type="text" name="company" value={company} tabIndex={-1} autoComplete="off"
        aria-hidden="true" onChange={(e) => setCompany(e.target.value)}
        style={{ position: "absolute", left: "-9999px", width: "1px", height: "1px", opacity: 0 }} />

      <div className="field">
        <label>First name</label>
        <input className="inp" type="text" value={firstName} placeholder="Alex"
          onChange={(e) => setFirstName(e.target.value)} />
      </div>

      <div className="field">
        <label>Email</label>
        <input className={"inp" + (errors.email ? " err" : "")} type="email" value={email}
          placeholder="you@email.com" onChange={(e) => setEmail(e.target.value)} />
        {errors.email && <div className="errmsg">{errors.email}</div>}
      </div>

      <div className="field">
        <label>Mobile <span className="lblnote">(for the WhatsApp group)</span></label>
        <div className="phone-row">
          <input className="inp code" type="text" value={dial} aria-label="Dialling code"
            onChange={(e) => setDial(e.target.value)} />
          <input className={"inp" + (errors.phone ? " err" : "")} type="tel" value={phone}
            style={{ flex: 1 }} placeholder="7700 900000" onChange={(e) => setPhone(e.target.value)} />
        </div>
        {errors.phone && <div className="errmsg">{errors.phone}</div>}
      </div>

      <div className="opts">
        <div className={"opt" + (joinWhatsApp ? " on" : "")} onClick={() => setWA(!joinWhatsApp)}>
          <div className="box"><Check /></div>
          <div className="txt"><b>Join the WhatsApp action group</b><span>Live alerts on license hearings, actions and meetups.</span></div>
        </div>
        <div className={"opt" + (joinMailing ? " on" : "")} onClick={() => setML(!joinMailing)}>
          <div className="box"><Check /></div>
          <div className="txt"><b>Join the mailing list</b><span>I agree to LFG contacting me about important campaigns.</span></div>
        </div>
      </div>
      {errors.opts && <div className="errmsg" style={{ marginTop: "-12px", marginBottom: "14px" }}>{errors.opts}</div>}

      <button className="submit" type="submit" disabled={status === "sending"}>
        {status === "sending" ? "Signing you up…" : "Count me in →"}
      </button>

      {status === "error" && <div className="errmsg" style={{ textAlign: "center", marginTop: "12px" }}>{serverErr}</div>}

      <p className="finep">
        We'll only use your details to organise this campaign. The data collected via this form is processed by Looking For Growth in line with our <a href="https://lookingforgrowth.uk/privacy-policy/" target="_blank" rel="noopener noreferrer">Privacy Policy</a>.
      </p>
    </form>
  );
}

function App() {
  return (
    <React.Fragment>
      <style>{CSS}</style>
      <TickerBar />

      <div className="wrap hero">
        <div className="hero-copy">
          <h1>Don't let Soho go <span className="hl">quiet.</span></h1>
          <p className="lede">
            The Soho Society has been granted a new licensing mandate, meaning it will challenge <b>all new applications for bars and restaurants</b> in the area, including renewals of existing licenses. It will also object to any venue that wishes to open beyond “core hours”, which Westminster council decrees end at 11pm.
          </p>
          <p className="lede" style={{ marginTop: "0" }}>
            And here is the kicker: <b>they're doing it with public money</b>, with local government funding behind the objections that will kill London's nightlife.
          </p>
          <p className="lede" style={{ marginTop: "0" }}>
            <b>We're the movement organising to keep Soho open.</b> Backing venues, packing out license hearings, and making sure the greatest city in the world has a nightlife.
          </p>
        </div>

        <div className="hero-form">
          <SignupCard />
        </div>
      </div>

      <div className="wrap foot">
        <div>© 2026 LFG: Soho Society. A Looking For Growth campaign</div>
        <div>
          <a href="https://lookingforgrowth.uk/privacy-policy/" target="_blank" rel="noopener noreferrer">Privacy Policy</a> · <a href="https://lookingforgrowth.uk/" target="_blank" rel="noopener noreferrer">Looking for Growth</a> · <a href="mailto:hello@lookingforgrowth.uk">Contact</a>
        </div>
      </div>
    </React.Fragment>
  );
}

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