/* global React */
// YachtingStack — Yachting AI News landing, recreated inside the storefront.
// Signup lives HERE on the main website; digest generation, approval and sending
// stay in the dedicated news system (news.yachtingstack.ai). The form POSTs to
// that system's public API (/api/leads/free, CORS *) so leads land in its leads
// table (and auto-mirror into Central CRM server-side).
//
// The form captures an audience profile: Yacht Crew (yacht size + role onboard)
// or Shore Professional (segment + LinkedIn). Segment list mirrors
// yachting-visibility/shared/schema.ts SEGMENTS — flagged to become the shared
// "Intelligence & CRM for yachting" segment taxonomy. The news API currently
// persists {email, source} and strips the extra profile fields (zod non-strict);
// a compact profile is therefore ALSO packed into `source` (≤64 chars) so
// nothing is lost until the API grows matching columns.
const { Icon, Btn, Reveal } = window;

const NEWS_API = "https://news.yachtingstack.ai/api";
const NEWS_APP = "https://news.yachtingstack.ai";

// Same segments as Yachting Visibility (shared/schema.ts SEGMENTS).
const SEGMENTS = [
  "Broker (Sales & Purchase)", "Charter Company", "Shipyard (New Build)", "Shipyard (Refit & Repair)",
  "Boatyard / Service Center", "Marina / Port", "Yacht Agent", "Provisioning & Supplies",
  "Chandlery / Marine Supplies", "Insurance Broker", "Surveyor", "Naval Architect / Designer",
  "Design & Engineering", "Interior Designer / Furnishings", "Crew Agency", "Management Company",
  "Brand / Equipment Manufacturer", "Electronics / Navigation Specialist", "Paint / Coating / Refinishing",
  "Rigging / Sail Maker", "Engineering / Mechanical", "PR / Marketing Agency", "Classification Society",
  "Clusters, Forums & Associations", "Transport / Logistics", "Legal / Flag State", "Finance / Leasing",
  "Fuel / Bunkering", "IT / Communications", "Security Services", "Medical / Health Services",
  "Tender / Watersports", "Yacht Club", "Yacht/Boat Shows", "Other",
];
// LOA brackets — <20m, then 10m steps up to 100m+.
const YACHT_SIZES = ["<20m", "20-30m", "30-40m", "40-50m", "50-60m", "60-70m", "70-80m", "80-90m", "90-100m", "100m+"];
const CREW_ROLES = ["Captain", "Officer / Deck", "Engineer / ETO", "Chief Stew / Interior", "Chef / Galley", "Purser / Admin", "Other"];

// Full-height snap section — product:news is a snapRoute (index.html), so the
// page scrolls one section per wheel like home / onboard / custom-dev.
const NSection = ({ children, id, style = {}, bg = null, bgOpacity = 0.14, bgSize = "cover" }) => (
  <section id={id} className="snap-sec" style={{ position: "relative", minHeight: "100vh", padding: "110px 32px 84px",
    display: "flex", flexDirection: "column", justifyContent: "center", ...(bg ? { overflow: "hidden" } : null), ...style }}>
    {bg && <div aria-hidden="true" style={{ position: "absolute", inset: 0, backgroundImage: `url(${bg})`, backgroundSize: bgSize,
      backgroundRepeat: "no-repeat", backgroundPosition: "center", opacity: bgOpacity, pointerEvents: "none" }} />}
    {/* scrim under the centered copy — same trick as the custom-dev sections,
        the wireframe strokes are bright and run through the grey body text */}
    {bg && <div aria-hidden="true" style={{ position: "absolute", inset: 0, pointerEvents: "none",
      background: "radial-gradient(ellipse 62% 55% at 50% 40%, rgba(7,22,37,.75), transparent 72%)" }} />}
    <div style={{ width: "100%", maxWidth: 1080, margin: "0 auto", position: "relative" }}>{children}</div>
  </section>
);

const NHead = ({ children, style = {} }) => (
  <h2 style={{ fontFamily: "var(--font-head)", fontWeight: 400, fontSize: "clamp(26px,3.3vw,40px)", lineHeight: 1.14, color: "var(--ink)", margin: 0, ...style }}>{children}</h2>
);

const fieldStyle = {
  width: "100%", boxSizing: "border-box", height: 44, padding: "0 12px", borderRadius: 8,
  border: "1px solid var(--hairline-2)", background: "var(--bg-deep)", color: "var(--ink)",
  fontFamily: "var(--font-ui)", fontSize: 14, outline: "none",
};
const labelStyle = {
  display: "block", fontFamily: "var(--font-mono)", fontSize: 9.5, fontWeight: 700,
  letterSpacing: ".12em", textTransform: "uppercase", color: "var(--ink-4)", marginBottom: 6,
};

function Field({ label, children }) {
  return (
    <div style={{ flex: "1 1 200px", minWidth: 0 }}>
      <label style={labelStyle}>{label}</label>
      {children}
    </div>
  );
}

function SelectField({ value, onChange, placeholder, options }) {
  return (
    <select value={value} onChange={(e) => onChange(e.target.value)}
      style={{ ...fieldStyle, appearance: "none", WebkitAppearance: "none", cursor: "pointer",
        color: value ? "var(--ink)" : "var(--ink-4)",
        backgroundImage: "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394C1DA' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>\")",
        backgroundRepeat: "no-repeat", backgroundPosition: "right 12px center", paddingRight: 34 }}>
      <option value="" disabled style={{ background: "#0d1626", color: "#8A97A6" }}>{placeholder}</option>
      {options.map((o) => <option key={o} value={o} style={{ background: "#0d1626", color: "#fff" }}>{o}</option>)}
    </select>
  );
}

function CheckRow({ checked, onToggle, required, children }) {
  return (
    <div style={{ display: "flex", alignItems: "flex-start", gap: 10 }}>
      <button type="button" onClick={onToggle} aria-checked={checked} role="checkbox"
        style={{ all: "unset", cursor: "pointer", width: 18, height: 18, flexShrink: 0, marginTop: 1, borderRadius: 5, boxSizing: "border-box",
          border: checked ? "1px solid rgba(80,134,182,.6)" : "1px solid var(--hairline-2)",
          background: checked ? "rgba(80,134,182,.15)" : "var(--bg-deep)",
          display: "flex", alignItems: "center", justifyContent: "center", transition: "background .2s, border-color .2s" }}>
        {checked && <Icon name="Check" size={13} color="var(--cyan-2)" />}
      </button>
      <span style={{ fontFamily: "var(--font-ui)", fontWeight: 300, fontSize: 11, lineHeight: 1.5, color: "var(--ink-3)" }}>
        {children}{required && <span style={{ color: "var(--cyan-2)" }}> *</span>}
      </span>
    </div>
  );
}

// The signup form — audience-profiled free-digest subscription, POSTing into the
// dedicated news system. `source` carries a compact profile (≤64 chars) so the
// data is visible in the news admin today; the full structured fields ride along
// in the body for when the API persists them natively.
function SignupCard({ source, onPrivacy }) {
  const [firstName, setFirstName] = React.useState("");
  const [lastName, setLastName] = React.useState("");
  const [email, setEmail] = React.useState("");
  const [company, setCompany] = React.useState("");
  const [audience, setAudience] = React.useState(""); // "" | crew | shore
  const [yachtSize, setYachtSize] = React.useState("");
  const [role, setRole] = React.useState("");
  const [segment, setSegment] = React.useState("");
  const [linkedin, setLinkedin] = React.useState("");
  const [marketing, setMarketing] = React.useState(false);
  const [gdpr, setGdpr] = React.useState(false);
  const [state, setState] = React.useState("idle"); // idle | pending | done | exists | error

  const emailOk = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim());
  const nameOk = firstName.trim() && lastName.trim();
  const profileOk = audience === "crew" ? (yachtSize && role) : audience === "shore" ? !!segment : false;
  const valid = emailOk && nameOk && profileOk && gdpr;

  async function submit(e) {
    if (e) e.preventDefault();
    if (!valid || state === "pending") return;
    setState("pending");
    const compact = [source, audience, ...(audience === "crew" ? [yachtSize, role] : [segment])].join("|").slice(0, 64);
    try {
      const r = await fetch(`${NEWS_API}/leads/free`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          email: email.trim().toLowerCase(),
          source: compact,
          firstName: firstName.trim(),
          lastName: lastName.trim(),
          company: company.trim() || undefined,
          audience,
          yachtSize: audience === "crew" ? yachtSize : undefined,
          roleOnboard: audience === "crew" ? role : undefined,
          segment: audience === "shore" ? segment : undefined,
          linkedin: audience === "shore" && linkedin.trim() ? linkedin.trim() : undefined,
          marketingOptIn: marketing,
          gdprConsent: gdpr,
        }),
      });
      if (!r.ok) throw new Error("bad status");
      const data = await r.json();
      setState(data.alreadyExisted ? "exists" : "done");
    } catch {
      setState("error");
    }
  }

  if (state === "done" || state === "exists") {
    return (
      <div className="ymfade" style={{ padding: "26px 24px", borderRadius: 16, background: "var(--surface)", border: "1px solid rgba(80,134,182,.3)", textAlign: "center" }}>
        <span style={{ width: 44, height: 44, margin: "0 auto 12px", borderRadius: "50%", background: "rgba(80,134,182,.1)", border: "1px solid rgba(80,134,182,.3)",
          display: "flex", alignItems: "center", justifyContent: "center", color: "var(--cyan-2)" }}><Icon name="CheckCircle2" size={20} /></span>
        <div style={{ fontFamily: "var(--font-ui)", fontSize: 16, fontWeight: 600, color: "var(--ink)" }}>
          {state === "exists" ? "You're already subscribed!" : "Welcome aboard."}
        </div>
        <p style={{ fontFamily: "var(--font-ui)", fontWeight: 300, fontSize: 13.5, lineHeight: 1.6, color: "var(--ink-3)", margin: "8px 0 0" }}>
          {state === "exists"
            ? "Your email is already on the list for the weekly digest."
            : "You're on the list. Look out for the next weekly digest in your inbox."}
        </p>
      </div>
    );
  }

  const audienceBtn = (key, ic, label) => {
    const active = audience === key;
    return (
      <button type="button" onClick={() => setAudience(key)}
        style={{ all: "unset", cursor: "pointer", flex: 1, boxSizing: "border-box", padding: "12px 14px", borderRadius: 10, textAlign: "center",
          border: active ? "1px solid rgba(80,134,182,.5)" : "1px solid var(--hairline-2)",
          background: active ? "rgba(80,134,182,.1)" : "var(--wa-02)", transition: "background .2s, border-color .2s" }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 8, fontFamily: "var(--font-ui)", fontSize: 14, fontWeight: active ? 600 : 400,
          color: active ? "var(--cyan-2)" : "var(--ink-2)" }}>
          <Icon name={ic} size={16} color={active ? "var(--cyan-2)" : "var(--ink-3)"} />{label}
        </span>
      </button>
    );
  };

  return (
    <div style={{ padding: "22px 22px", borderRadius: 16, background: "var(--surface)", border: "1px solid var(--hairline-2)" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, marginBottom: 16, flexWrap: "wrap" }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
          <span className="aura" style={{ width: 8, height: 8, borderRadius: "50%", background: "var(--cyan)" }} />
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, fontWeight: 700, letterSpacing: ".14em", textTransform: "uppercase", color: "var(--cyan-2)" }}>Free weekly digest</span>
        </span>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--ink-4)" }}>Weekly</span>
      </div>

      <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
          <Field label="First name">
            <input type="text" value={firstName} onChange={(e) => setFirstName(e.target.value)}
              placeholder="First name" aria-label="First name" autoComplete="given-name" style={fieldStyle}
              onFocus={(e) => e.currentTarget.style.borderColor = "rgba(80,134,182,.45)"}
              onBlur={(e) => e.currentTarget.style.borderColor = "var(--hairline-2)"} />
          </Field>
          <Field label="Last name">
            <input type="text" value={lastName} onChange={(e) => setLastName(e.target.value)}
              placeholder="Last name" aria-label="Last name" autoComplete="family-name" style={fieldStyle}
              onFocus={(e) => e.currentTarget.style.borderColor = "rgba(80,134,182,.45)"}
              onBlur={(e) => e.currentTarget.style.borderColor = "var(--hairline-2)"} />
          </Field>
        </div>

        <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
          <Field label="Work email">
            <input type="email" value={email} onChange={(e) => { setEmail(e.target.value); if (state === "error") setState("idle"); }}
              placeholder="you@company.com" aria-label="Work email" autoComplete="email" style={fieldStyle}
              onFocus={(e) => e.currentTarget.style.borderColor = "rgba(80,134,182,.45)"}
              onBlur={(e) => e.currentTarget.style.borderColor = "var(--hairline-2)"} />
          </Field>
          <Field label="Company / Yacht (optional)">
            <input type="text" value={company} onChange={(e) => setCompany(e.target.value)}
              placeholder="Company or yacht name" aria-label="Company or yacht" autoComplete="organization" style={fieldStyle}
              onFocus={(e) => e.currentTarget.style.borderColor = "rgba(80,134,182,.45)"}
              onBlur={(e) => e.currentTarget.style.borderColor = "var(--hairline-2)"} />
          </Field>
        </div>

        <div>
          <label style={labelStyle}>I am…</label>
          <div style={{ display: "flex", gap: 10 }}>
            {audienceBtn("crew", "Ship", "Yacht Crew")}
            {audienceBtn("shore", "Building2", "Shore Professional")}
          </div>
        </div>

        {audience === "crew" && (
          <div className="ymfade" style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
            <Field label="Yacht size (LOA)">
              <SelectField value={yachtSize} onChange={setYachtSize} placeholder="Select size…" options={YACHT_SIZES} />
            </Field>
            <Field label="Role on board">
              <SelectField value={role} onChange={setRole} placeholder="Select role…" options={CREW_ROLES} />
            </Field>
          </div>
        )}

        {audience === "shore" && (
          <div className="ymfade" style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
            <Field label="Segment">
              <SelectField value={segment} onChange={setSegment} placeholder="Select segment…" options={SEGMENTS} />
            </Field>
            <Field label="LinkedIn (optional)">
              <input type="url" value={linkedin} onChange={(e) => setLinkedin(e.target.value)}
                placeholder="linkedin.com/in/you" aria-label="LinkedIn profile" style={fieldStyle}
                onFocus={(e) => e.currentTarget.style.borderColor = "rgba(80,134,182,.45)"}
                onBlur={(e) => e.currentTarget.style.borderColor = "var(--hairline-2)"} />
            </Field>
          </div>
        )}

        <div style={{ display: "flex", flexDirection: "column", gap: 9, paddingTop: 2 }}>
          <CheckRow checked={gdpr} onToggle={() => setGdpr(!gdpr)} required>
            I agree to the processing of my personal data to receive the digest, per the{" "}
            <button type="button" onClick={onPrivacy} style={{ all: "unset", cursor: "pointer", color: "var(--cyan-2)", textDecoration: "underline", textUnderlineOffset: 2 }}>Privacy Policy</button>.
          </CheckRow>
          <CheckRow checked={marketing} onToggle={() => setMarketing(!marketing)}>
            I'd also like to receive occasional product news and marketing communications from YachtingStack.
          </CheckRow>
        </div>

        <div style={{ display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap", marginTop: 2 }}>
          <Btn size="lg" disabled={!valid || state === "pending"} onClick={submit} style={{ minWidth: 170 }}>
            {state === "pending" ? "Subscribing…" : "Subscribe free"}
          </Btn>
          {state === "error" && (
            <span style={{ fontFamily: "var(--font-ui)", fontSize: 12.5, color: "var(--bad)" }}>Something went wrong. Please try again.</span>
          )}
        </div>
      </form>

      <div style={{ display: "flex", gap: 18, flexWrap: "wrap", marginTop: 16, paddingTop: 14, borderTop: "1px solid var(--hairline)" }}>
        {["No spam, ever", "5-min read", "Unsubscribe anytime"].map((t) => (
          <span key={t} style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: "var(--font-ui)", fontSize: 12, color: "var(--ink-3)" }}>
            <Icon name="CheckCircle2" size={13} color="var(--cyan-2)" />{t}
          </span>
        ))}
      </div>
    </div>
  );
}

// ---- From noise to signal — qualitative contrast, no invented metrics ----
// Left: the weekly media noise as it actually feels. Right: an illustrative
// digest mock. Tells the story without stats we can't back up.
const NOISE_CHIPS = [
  "Trade press", "LinkedIn", "Newsletters", "Press releases", "Group chats", "Show dailies",
  "Brokerage blasts", "Trade press (again)", "Forums", "The same story, rehashed", "Webinars", "PR wires",
];
function NoiseCard() {
  return (
    <div style={{ height: "100%", padding: "24px 24px", borderRadius: 18, background: "var(--surface)", border: "1px solid var(--hairline)" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 16 }}>
        <Icon name="Volume2" size={15} color="var(--ink-3)" />
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, fontWeight: 700, letterSpacing: ".16em", textTransform: "uppercase", color: "var(--ink-3)" }}>Every week, everywhere</span>
      </div>
      <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginBottom: 18 }}>
        {NOISE_CHIPS.map((t, i) => (
          <span key={t} style={{ fontFamily: "var(--font-ui)", fontSize: 12.5, color: i % 3 === 2 ? "var(--ink-4)" : "var(--ink-3)",
            padding: "5px 11px", borderRadius: 999, background: "var(--wa-02)", border: "1px dashed var(--hairline-2)",
            transform: `rotate(${(i % 5 - 2) * 1.2}deg)` }}>{t}</span>
        ))}
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
        {["The same announcement, rewritten by every outlet", "No way to tell what actually matters this week", "The story that did matter, buried on page four"].map((t) => (
          <span key={t} style={{ display: "flex", gap: 9, alignItems: "flex-start", fontFamily: "var(--font-ui)", fontWeight: 300, fontSize: 13.5, lineHeight: 1.55, color: "var(--ink-3)" }}>
            <Icon name="AlertTriangle" size={15} color="var(--ink-4)" style={{ marginTop: 2, flexShrink: 0 }} />{t}
          </span>
        ))}
      </div>
    </div>
  );
}

// Illustrative digest preview — clearly a mock, not real published stories.
// One broad industry digest for everyone; per-segment customization is the next
// product iteration, so no segment/category labels are shown here.
const DIGEST_ROWS = [
  "AI aboard: the tools crews are actually adopting",
  "The week's market moves, clustered into one clear story",
  "The regulation change everyone will be talking about",
];
function SignalCard() {
  return (
    <div style={{ height: "100%", padding: "24px 24px", borderRadius: 18, background: "var(--surface)", border: "1px solid rgba(80,134,182,.28)" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 16 }}>
        <Icon name="Newspaper" size={15} color="var(--cyan-2)" />
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, fontWeight: 700, letterSpacing: ".16em", textTransform: "uppercase", color: "var(--cyan-2)" }}>Your weekly digest</span>
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 10, marginBottom: 18 }}>
        {DIGEST_ROWS.map((headline) => (
          <div key={headline} style={{ display: "flex", gap: 11, alignItems: "center", padding: "13px 14px", borderRadius: 12,
            background: "var(--wa-02)", border: "1px solid var(--hairline)" }}>
            <span style={{ width: 7, height: 7, flexShrink: 0, borderRadius: "50%", background: "var(--cyan)" }} />
            <span style={{ fontFamily: "var(--font-ui)", fontSize: 13.5, fontWeight: 500, lineHeight: 1.4, color: "var(--ink)" }}>{headline}</span>
          </div>
        ))}
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
        {["One digest, every week — a five-minute read", "Duplicates clustered into a single story, ranked by impact", "Written for yachting professionals, on board and on shore"].map((t) => (
          <span key={t} style={{ display: "flex", gap: 9, alignItems: "flex-start", fontFamily: "var(--font-ui)", fontWeight: 300, fontSize: 13.5, lineHeight: 1.55, color: "var(--ink-2)" }}>
            <Icon name="CheckCircle2" size={15} color="var(--cyan-2)" style={{ marginTop: 2, flexShrink: 0 }} />{t}
          </span>
        ))}
      </div>
    </div>
  );
}

function NewsPage({ go, from = "home" }) {
  const [privacyOpen, setPrivacyOpen] = React.useState(false);
  const LegalModal = window.LegalModal;

  const steps = [
    ["Zap", "Ingest", "Aggregating global yachting news, press releases, and market signals."],
    ["Shield", "Cluster", "AI models group related stories and filter out duplicate noise."],
    ["LineChart", "Curate", "Ranking impact and extracting the core “so what” for operators."],
    ["Clock", "Deliver", "Clean, precise digests sent weekly, straight to your inbox."],
  ];
  return (
    <div style={{ background: "var(--bg)" }}>
      {/* hero — the single signup surface, centered */}
      <section id="subscribe" className="snap-sec" style={{ position: "relative", overflow: "hidden", minHeight: "100vh", padding: "110px 32px 64px",
        display: "flex", flexDirection: "column", justifyContent: "center", background: "var(--bg-deep)" }}>
        {/* world map line-art — "the global yachting industry", kept faint under the signup card */}
        <div aria-hidden="true" style={{ position: "absolute", inset: 0, backgroundImage: "url(/assets/images/world.webp)", backgroundSize: "cover",
          backgroundRepeat: "no-repeat", backgroundPosition: "center", opacity: 0.08, pointerEvents: "none" }} />
        <div style={{ position: "absolute", inset: 0, background: "radial-gradient(ellipse 70% 75% at 50% 0%, rgba(80,134,182,.09), transparent 62%)" }} />
        <div aria-hidden="true" style={{ position: "absolute", left: 0, right: 0, bottom: 0, height: "36%", pointerEvents: "none", background: "linear-gradient(to bottom, transparent, var(--bg))" }} />
        {/* back — same left alignment as the other pages' back links (the 1080 content
            rail, under the nav logo), but absolute so it costs no vertical space */}
        <div style={{ position: "absolute", left: 32, right: 32, top: 88, zIndex: 3, pointerEvents: "none" }}>
          <div style={{ maxWidth: 1080, margin: "0 auto" }}>
            <button onClick={() => go("home")} style={{ all: "unset", cursor: "pointer", pointerEvents: "auto",
              display: "inline-flex", alignItems: "center", gap: 7, fontFamily: "var(--font-ui)", fontSize: 13, color: "var(--ink-3)" }}
              onMouseEnter={(e) => e.currentTarget.style.color = "var(--ink)"} onMouseLeave={(e) => e.currentTarget.style.color = "var(--ink-3)"}>
              <Icon name="ArrowLeft" size={15} /> Home
            </button>
          </div>
        </div>

        <div style={{ width: "100%", maxWidth: 760, margin: "0 auto", position: "relative", textAlign: "center" }}>
          {/* no logo/wordmark here — the nav carries the Yachting AI News lockup */}
          <h1 className="rise" style={{ fontFamily: "var(--font-head)", fontWeight: 400, fontSize: "clamp(28px,3.4vw,42px)",
            lineHeight: 1.12, letterSpacing: "-0.01em", color: "#fff", margin: "0 auto", maxWidth: 680 }}>
            AI news and <span style={{ color: "var(--cyan)", whiteSpace: "nowrap" }}>curated intelligence</span> for the global yachting industry.
          </h1>

          <div className="rise" style={{ animationDelay: ".12s", maxWidth: 640, margin: "30px auto 0", textAlign: "left" }}>
            <SignupCard source="www-hero" onPrivacy={() => setPrivacyOpen(true)} />
          </div>
        </div>
      </section>

      {/* how it works */}
      <NSection>
        <Reveal style={{ textAlign: "center", maxWidth: 680, margin: "0 auto" }}>
          <NHead>The <span style={{ color: "var(--cyan)", whiteSpace: "nowrap" }}>intelligence engine</span> behind<br />every digest.</NHead>
          <p style={{ fontFamily: "var(--font-ui)", fontWeight: 300, fontSize: 15.5, lineHeight: 1.7, color: "var(--ink-3)", margin: "14px auto 0", maxWidth: 560 }}>
            Four stages that turn thousands of raw signals into something worth your attention.
          </p>
        </Reveal>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(210px, 1fr))", gap: 14, marginTop: 40, position: "relative" }}>
          {/* the story-packet flowing stage to stage — rides the icon-chip centerline
              (top 42px = 22px card padding + half the 40px chip); keyframes in index.html
              share the pulse's 8s clock so it lands as each card lights up */}
          <div className="news-flow" aria-hidden="true" style={{ position: "absolute", left: 0, right: 0, top: 42, height: 0, zIndex: 2, pointerEvents: "none" }}>
            <span className="news-flow-dot" style={{ position: "absolute", top: 0, width: 7, height: 7, borderRadius: "50%", transform: "translate(-50%,-50%)",
              background: "var(--cyan-2)", boxShadow: "0 0 10px 2px rgba(148,193,218,.65)", opacity: 0 }} />
          </div>
          {steps.map(([ic, t, desc], i) => (
            <Reveal key={t} delay={i * 70}>
              {/* news-stage / news-stage-chip: sequential pipeline pulse (keyframes in
                  index.html) — the same i*2s delay on card and chip keeps them in step */}
              <div className="news-stage" style={{ height: "100%", padding: "22px 20px", borderRadius: 16, background: "var(--surface)", border: "1px solid var(--hairline)", animationDelay: `${i * 2}s` }}>
                <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 13 }}>
                  <span className="news-stage-chip" style={{ width: 40, height: 40, borderRadius: 11, background: "rgba(80,134,182,.07)", border: "1px solid rgba(80,134,182,.18)",
                    display: "flex", alignItems: "center", justifyContent: "center", color: "var(--cyan-2)", animationDelay: `${i * 2}s` }}><Icon name={ic} size={18} /></span>
                  <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, fontWeight: 700, letterSpacing: ".14em", color: "var(--ink-4)" }}>0{i + 1}</span>
                </div>
                <div style={{ fontFamily: "var(--font-ui)", fontSize: 15.5, fontWeight: 600, color: "var(--ink)" }}>{t}</div>
                <p style={{ fontFamily: "var(--font-ui)", fontWeight: 300, fontSize: 13, lineHeight: 1.6, color: "var(--ink-3)", margin: "7px 0 0" }}>{desc}</p>
              </div>
            </Reveal>
          ))}
        </div>
      </NSection>

      {/* from noise to signal — same backdrop as custom-dev's "building to deciding" */}
      <NSection bg="/assets/images/old-new-red.webp" bgOpacity={0.15} bgSize="100% auto">
        <Reveal style={{ textAlign: "center", maxWidth: 680, margin: "0 auto" }}>
          <NHead>From <em style={{ fontStyle: "italic" }}>noise</em> to <span style={{ color: "var(--cyan)" }}>signal</span>.</NHead>
          <p style={{ fontFamily: "var(--font-ui)", fontWeight: 300, fontSize: 15.5, lineHeight: 1.7, color: "var(--ink-3)", margin: "14px auto 0", maxWidth: 580 }}>
            The industry's week arrives scattered, repeated and unfiltered. We cluster it, rank it, and hand you the part that matters to your operation.
          </p>
        </Reveal>
        <div className="responsive-grid" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16, marginTop: 40 }}>
          <Reveal><NoiseCard /></Reveal>
          <Reveal delay={100}><SignalCard /></Reveal>
        </div>
        <Reveal delay={140}>
          <div style={{ textAlign: "center", marginTop: 36 }}>
            <Btn size="lg" onClick={() => { const el = document.getElementById("subscribe"); if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY, behavior: "smooth" }); }} iconRight="ArrowRight">
              Subscribe free
            </Btn>
          </div>
        </Reveal>
      </NSection>

      {privacyOpen && LegalModal && <LegalModal doc="privacy" onClose={() => setPrivacyOpen(false)} />}
    </div>
  );
}

Object.assign(window, { NewsPage });
