// modules.jsx — All 9 product UI previews for R24 PULSE platform
const { useState, useEffect, useRef } = React;

// ============================================================
// Icon set (Lucide-style inline SVGs at 1.5 stroke)
// ============================================================
const Icon = ({ d, size = 16, stroke = 1.5, fill = "none", style }) =>
<svg width={size} height={size} viewBox="0 0 24 24" fill={fill} stroke="currentColor"
strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round" style={style}>
    {typeof d === "string" ? <path d={d} /> : d}
  </svg>;

const Icons = {
  shield: "M12 22s-8-4-8-12V5l8-3 8 3v5c0 8-8 12-8 12z",
  globe: <><circle cx="12" cy="12" r="10" /><path d="M2 12h20M12 2a15 15 0 0 1 0 20M12 2a15 15 0 0 0 0 20" /></>,
  users: <><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" /><circle cx="9" cy="7" r="4" /><path d="M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75" /></>,
  database: <><ellipse cx="12" cy="5" rx="9" ry="3" /><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" /></>,
  broadcast: <><path d="M5 12c0-3.87 3.13-7 7-7s7 3.13 7 7" /><path d="M2 12c0-5.52 4.48-10 10-10s10 4.48 10 10" /><circle cx="12" cy="12" r="2" /><path d="M12 14v8" /></>,
  route: <><circle cx="6" cy="19" r="3" /><circle cx="18" cy="5" r="3" /><path d="M6 16V8a5 5 0 0 1 5-5h2" /><path d="M18 8v8a5 5 0 0 1-5 5h-2" /></>,
  alert: <><path d="M12 9v4M12 17h.01" /><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" /></>,
  shield2: "M12 22s-8-4-8-12V5l8-3 8 3v5c0 8-8 12-8 12z",
  trending: <><polyline points="22 7 13.5 15.5 8.5 10.5 2 17" /><polyline points="16 7 22 7 22 13" /></>,
  truck: <><path d="M10 17h4V5H2v12h3" /><path d="M20 17h2v-3.34a4 4 0 0 0-1.17-2.83L19 9h-5v8h2" /><circle cx="7.5" cy="17.5" r="2.5" /><circle cx="17.5" cy="17.5" r="2.5" /></>,
  phone: <><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" /></>,
  mail: <><rect x="2" y="4" width="20" height="16" rx="2" /><path d="m22 7-10 5L2 7" /></>,
  msg: <><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" /></>,
  bell: <><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" /><path d="M13.73 21a2 2 0 0 1-3.46 0" /></>,
  // WhatsApp — chat bubble with phone glyph (monoline, currentColor)
  whatsapp: <><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" /><path d="M9 10.5c0 2.5 2 4.5 4.5 4.5l1-1.2 1.8.7" /></>,
  // MS Teams — "T" in rounded square + chat tail
  teams: <><rect x="3" y="3" width="18" height="15" rx="2" /><path d="M7 21l3-3" /><path d="M8 8h8M12 8v7" /></>,
  pin: <><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" /><circle cx="12" cy="10" r="3" /></>,
  check: "M20 6 9 17l-5-5",
  clock: <><circle cx="12" cy="12" r="10" /><polyline points="12 6 12 12 16 14" /></>,
  arrow: "M5 12h14M12 5l7 7-7 7",
  lock: <><rect x="3" y="11" width="18" height="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" /></>,
  eye: <><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z" /><circle cx="12" cy="12" r="3" /></>,
  signal: <><path d="M2 20h.01M7 20v-4M12 20v-8M17 20V8M22 4v16" /></>,
  filter: "M22 3H2l8 9.46V19l4 2v-8.54L22 3z",
  zap: "M13 2 3 14h9l-1 8 10-12h-9l1-8z",
  briefcase: <><rect x="2" y="7" width="20" height="14" rx="2" /><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16" /></>,
  api: <><path d="M3 3h7v7H3zM14 14h7v7h-7zM3 14h7v7H3zM14 3h7v7h-7z" /></>,
  cpu: <><rect x="4" y="4" width="16" height="16" rx="2" /><rect x="9" y="9" width="6" height="6" /><path d="M9 1v3M15 1v3M9 20v3M15 20v3M20 9h3M20 14h3M1 9h3M1 14h3" /></>
};

// ============================================================
// World map (R24-platform-style: real HERE Maps tile as background;
// pin/zone markers stack on top)
// ============================================================
const WorldMap = ({ children, className = "" }) =>
<div className={`world ${className}`} style={{ position: "absolute", inset: 0 }}>
    <div className="world__grid" />
    {children}
  </div>;


// ============================================================
// Module 01 — Real-Time Risk and User/Asset Matching (section 03)
// Mirrors the R24 PULSE "Threat Warning + Incoming Threats" view:
//   1. Incident header
//   2. Two-column body: Map (with threats + matched users + asset) | Incoming Threats list
//   3. Action bar overlaid on map (Show Users / Show Threats)
// (Responses + stats cards have moved to section 04.)
// ============================================================
const Module01 = () => {
  // Threats on the map — spread so each pin is individually readable
  const threats = [
  { x: 60.0, y: 55.5, sev: "red",   kind: "protest", name: "Planned protest over unemployment and service delivery", region: "Majakaneng, Bojanala Platinum District", category: "Limited" },
  { x: 56.0, y: 76.0, sev: "amber", kind: "civil",   name: "Service delivery protest at Golden Highway / R554", region: "Lehae, Lenasia", category: "Limited" },
  { x: 50.5, y: 44.0, sev: "amber", kind: "road",    name: "Protest action reported on the N2 highway", region: "Between Tsolo and Mthatha", category: "Limited" },
  { x: 68.5, y: 67.0, sev: "red",   kind: "crime",   name: "Armed robbery suspect at large near Sandton", region: "Sandton, JNB", category: "Severe" }];


  // Polished threat-kind icon set — filled glyphs in white on coloured background
  const kindIcon = (k) => {
    const wrap = (children) =>
    <svg width="13" height="13" viewBox="0 0 24 24" fill="#fff" stroke="none">
        {children}
      </svg>;

    switch (k) {
      case "protest":
        // Megaphone (civil unrest / protest)
        return wrap(<>
          <path d="M3 11v2a1 1 0 0 0 1 1h2l5 5V5L6 10H4a1 1 0 0 0-1 1z" />
          <path d="M14 9v6c1.66 0 3-1.34 3-3s-1.34-3-3-3z" />
          <path d="M18 6.5a8 8 0 0 1 0 11" stroke="#fff" strokeWidth="1.6" fill="none" strokeLinecap="round" />
        </>);
      case "civil":
        // Group of people (crowd)
        return wrap(<>
          <circle cx="8" cy="8" r="3" />
          <circle cx="17" cy="9" r="2.4" />
          <path d="M2 19c0-3 2.7-5 6-5s6 2 6 5v1H2z" />
          <path d="M15 19c0-2.2 1.8-3.5 4-3.5s3 1.3 3 3.5v1h-7z" />
        </>);
      case "road":
        // Road / lane closure
        return wrap(<>
          <path d="M7 3l-2 18h3l1-8h6l1 8h3L17 3z" />
          <rect x="11" y="9" width="2" height="3" fill="#000" opacity="0.35" />
          <rect x="11" y="14" width="2" height="3" fill="#000" opacity="0.35" />
        </>);
      case "crime":
        // Skull (armed crime)
        return wrap(<>
          <path d="M12 3a8 8 0 0 0-5 14v2a1 1 0 0 0 1 1h2v-2h4v2h2a1 1 0 0 0 1-1v-2a8 8 0 0 0-5-14z" />
          <circle cx="9" cy="11" r="1.4" fill="#000" />
          <circle cx="15" cy="11" r="1.4" fill="#000" />
          <path d="M11 14h2v2h-2z" fill="#000" opacity="0.55" />
        </>);
      case "weather":
        // Lightning / storm
        return wrap(<>
          <path d="M13 2L5 14h6l-1 8 10-12h-6l1-8z" />
        </>);
      case "fire":
        // Flame
        return wrap(<>
          <path d="M12 2c-1 4-5 5-5 11a5 5 0 0 0 10 0c0-3-3-3-3-7 0 4-2 4-2 0z" />
        </>);
      case "medical":
        // Medical cross
        return wrap(<>
          <path d="M10 3h4v6h6v4h-6v6h-4v-6H4V9h6z" />
        </>);
      default:
        // Generic warning triangle
        return wrap(<>
          <path d="M12 3l10 18H2z" />
          <rect x="11" y="10" width="2" height="6" fill="#000" opacity="0.55" />
          <rect x="11" y="17" width="2" height="2" fill="#000" opacity="0.55" />
        </>);
    }
  };

  // Office / asset markers — just the Lagos field office (the Sandton HQ removed —
  // the map is illustrative; office presence is conveyed by the icon's purpose, not exact placement)
  const offices = [
  { x: 52.4, y: 46.0, label: "Lagos Office" }];


  // User markers inside the Sandton geofence — spread out so each is
  // visually distinguishable (was a tight 1–2% cluster, now spans the
  // whole geofence so the matched users are readable at a glance)
  const insideUsers = [
  { x: 51.0, y: 60.0, s: "ok" },
  { x: 66.0, y: 59.0, s: "not_ok" },
  { x: 53.0, y: 72.0, s: "ok" },
  { x: 65.0, y: 73.0, s: "ok" },
  { x: 58.5, y: 56.0, s: "ok" }];

  // Users outside the geofence (cleared)
  const outsideUsers = [
  { x: 51.0, y: 45.0 }, // Lagos
  { x: 67.0, y: 35.5 }, // Dubai
  { x: 53.0, y: 20.0 } // Berlin
  ];

  // Threat-kind icon mapping — small lucide-style glyphs centered in the marker
  // (See `kindIcon` above — kept for backward reference)

  return (
    <div className="m01">
      {/* Incident header */}
      <div className="m01__hdr">
        <span className="m01__hdr-title">
          <Icon d={Icons.alert} size={14} />Threat Warning
        </span>
        <div className="m01__hdr-fields">
          <span className="m01__hdr-field">
            <span className="m01__hdr-lab">Risk Category</span>
            <span className="m01__hdr-val m01__hdr-val--red">Criminality</span>
          </span>
          <span className="m01__hdr-field">
            <span className="m01__hdr-lab">Risk Type</span>
            <span className="m01__hdr-val">Murder</span>
          </span>
          <span className="m01__hdr-field">
            <span className="m01__hdr-lab">Impact</span>
            <span className="m01__hdr-val tabular">5 / 5</span>
          </span>
          <span className="m01__hdr-field">
            <span className="m01__hdr-lab">Country</span>
            <span className="m01__hdr-val">ZAF</span>
          </span>
          <span className="m01__hdr-field">
            <span className="m01__hdr-lab">Status</span>
            <span className="m01__hdr-val m01__hdr-val--amber">Pending Review</span>
          </span>
        </div>
      </div>

      <div className="m01__grid">
        {/* Map */}
        <div className="m01__map">
          <WorldMap>
            <div className="geofence" style={{ left: "58%", top: "65%" }}>
              <div className="geofence__core" />
            </div>

            {threats.map((t, i) =>
            <div key={`t-${i}`} className={`threat-pin threat-pin--${t.sev}`}
            style={{ left: `${t.x}%`, top: `${t.y}%` }}
            title={t.name}>
                {kindIcon(t.kind)}
              </div>
            )}

            {insideUsers.map((u, i) =>
            <div key={`in-${i}`} className={`upin upin--${u.s === "not_ok" ? "red" : "green"}`}
            style={{ left: `${u.x}%`, top: `${u.y}%` }}>
                <Icon d={Icons.users} size={10} />
              </div>
            )}
            {outsideUsers.map((u, i) =>
            <div key={`out-${i}`} className="upin upin--gray"
            style={{ left: `${u.x}%`, top: `${u.y}%` }}>
                <Icon d={Icons.users} size={10} />
              </div>
            )}

            {offices.map((o, i) =>
            <div key={`o-${i}`} className="office-pin"
            style={{ left: `${o.x}%`, top: `${o.y}%` }}
            title={o.label}>
                <svg width="11" height="11" viewBox="0 0 24 24" fill="none"
              stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <rect x="4" y="2" width="16" height="20" rx="1" />
                  <line x1="9" y1="6" x2="9" y2="6" />
                  <line x1="15" y1="6" x2="15" y2="6" />
                  <line x1="9" y1="10" x2="9" y2="10" />
                  <line x1="15" y1="10" x2="15" y2="10" />
                  <line x1="9" y1="14" x2="9" y2="14" />
                  <line x1="15" y1="14" x2="15" y2="14" />
                  <path d="M10 22v-3h4v3" />
                </svg>
              </div>
            )}

            <div className="map-corner" style={{ top: 14, left: 16 }}>GEOFENCE · RADIUS 18km</div>
            <div className="map-corner" style={{ top: 14, right: 16 }}>27 MAY · 09:03</div>
          </WorldMap>
        </div>

        {/* Incoming Threats list — mirrors the R24 PULSE platform panel */}
        <aside className="m01__right">
          <div className="m01__threats">
            <div className="m01__threats-head">
              <span className="m01__threats-title">
                <Icon d={Icons.alert} size={13} />
                Incoming Threats <span className="m01__threats-count">(118)</span>
              </span>
              <button className="m01__threats-filter" title="Filter">
                <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" />
                </svg>
              </button>
            </div>
            <ul className="m01__threats-list">
              {threats.map((t, i) =>
              <li key={i} className="m01__threats-item">
                  <div className="m01__threats-text">
                    <div className="m01__threats-name">{t.name}</div>
                    <div className="m01__threats-region">{t.region}</div>
                  </div>
                  <span className={`m01__threats-sev m01__threats-sev--${t.sev}`}>{t.category}</span>
                </li>
              )}
            </ul>
          </div>
          <button className="m01__threats-all">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" /><circle cx="12" cy="12" r="3" />
            </svg>
            View all threats
          </button>
        </aside>
      </div>

      {/* Action bar — full-width footer below map + threats (4-layer set, consistent with section 02) */}
      <div className="m04__actions">
        <div className="m08__action"><Icon d={Icons.users} size={16} />Show Users</div>
        <div className="m08__action"><Icon d={Icons.alert} size={16} />Show Threats</div>
        <div className="m08__action"><Icon d={Icons.shield} size={16} />Show Police</div>
        <div className="m08__action"><Icon d={Icons.api} size={16} />Show Hospitals</div>
      </div>
    </div>);

};

// ============================================================
// Module 02 — Purpose-Driven Location Matching
// (Location is dormant until risk emerges. Match → alert affected → if NOT OK, dispatch.)
// ============================================================
const Module02 = () => {
  const people = [
  { i: "RM", n: "R. Mehta", l: "Sandton zone · ±5m", s: "red", reply: "NOT OK", p: [{ x: 67, y: 63 }] },
  { i: "AK", n: "A. Khoury", l: "Beirut zone · ±7m", s: "amber", reply: "PENDING", p: [{ x: 68, y: 36 }] },
  { i: "JL", n: "J. Liang", l: "Mumbai zone · ±4m", s: "green", reply: "SAFE", p: [{ x: 80, y: 43 }] },
  { i: "SO", n: "S. Okafor", l: "Lagos zone · ±6m", s: "green", reply: "SAFE", p: [{ x: 59, y: 52 }] },
  { i: "ES", n: "E. Sørensen", l: "Copenhagen zone · ±5m", s: "green", reply: "SAFE", p: [{ x: 63, y: 22 }] },
  { i: "MD", n: "M. Da Silva", l: "São Paulo zone · ±8m", s: "green", reply: "SAFE", p: [{ x: 37, y: 62 }] },
  { i: "HN", n: "H. Nakamura", l: "Tashkent zone · ±5m", s: "green", reply: "SAFE", p: [{ x: 75, y: 30 }] },
  { i: "PV", n: "P. Volkov", l: "Almaty zone · ±7m", s: "amber", reply: "PENDING", p: [{ x: 82, y: 28 }] }];

  return (
    <div className="m02">
      <div className="m01__map" style={{ position: "relative" }}>
        <WorldMap>
          {people.map((p, i) =>
          <div key={i} className={`pin pin--${p.s === "green" ? "green" : p.s === "amber" ? "amber" : ""}`}
          style={{ left: `${p.p[0].x}%`, top: `${p.p[0].y}%` }}>
              <div className="pin__accuracy" />{p.i}
            </div>
          )}
          <div className="map-corner" style={{ top: 14, left: 16 }}>R24 · MATCHED USERS · 8 IN ACTIVE RISK VICINITIES</div>
          <div className="map-corner" style={{ top: 14, right: 16 }}>GPS DORMANT EXCEPT ON MATCH</div>
          <div className="map-corner" style={{ bottom: 14, left: 16 }}>PURPOSE-DRIVEN · NOT CONTINUOUS</div>
          <div className="map-corner" style={{ bottom: 14, right: 16 }}>GDPR · POPIA · LOG-IT-ALL</div>
        </WorldMap>
      </div>
      <div className="card" style={{ display: "flex", flexDirection: "column", minHeight: 0 }}>
        <div className="card__head">
          <span className="card__title">Matched users · vicinity reply</span>
          <span className="pill pill--navy">8 in zone</span>
        </div>
        <div style={{ overflow: "auto", flex: 1 }}>
          {people.map((p, i) =>
          <div key={i} className="person-row">
              <div className="person-row__avatar">{p.i}</div>
              <div>
                <div className="person-row__name">{p.n}</div>
                <div className="person-row__loc">{p.l}</div>
              </div>
              <span className={`pill pill--${p.s === "green" ? "green" : p.s === "amber" ? "gold" : "coral"}`}>{p.reply}</span>
            </div>
          )}
        </div>
      </div>
    </div>);

};

// ============================================================
// Module 03 — Master Data Management
// ============================================================
// ============================================================
// Module 03 — Master Data Management (Section 01 in the demo rail)
// "Stack-reduction" tool: each card cycles through 3 states —
//   Integrated (R24 connects to it)
//   Reducing   (R24 absorbs partial workload)
//   R24-Native (fully migrated to R24)
// Plus a "Bring your own vendor" slot.
// The animated pipe colours its dots to match each card's state.
// ============================================================
const Module03 = () => {
  const initialSources = [
  { heading: "Contact Management", category: "HR Integration", state: "integrated" },
  { heading: "Threat and Risk Intelligence", category: "Sigma7 Threat Intel Integration", state: "reducing" },
  { heading: "Mass Communication", category: "Everbridge / Twilio Integration", state: "reducing" },
  { heading: "Travel Management", category: "Concur Integration", state: "integrated" },
  { heading: "Outsourced Control Room / GSOC", category: "External GSOC Integration", state: "native" },
  { heading: "Service Provider Management", category: "R24 Service Provider Integration", state: "integrated" }];


  const [sources, setSources] = useState(initialSources);
  const [byovName, setByovName] = useState("");

  const cycleState = (i) => {
    setSources((prev) => prev.map((s, idx) => {
      if (idx !== i) return s;
      const order = ["integrated", "reducing", "native"];
      const next = order[(order.indexOf(s.state) + 1) % order.length];
      return { ...s, state: next };
    }));
  };

  const stateMeta = {
    integrated: { label: "INTEGRATED", color: "#2EA770", hint: "R24 connects to it" },
    reducing: { label: "REDUCING", color: "#E5A82E", hint: "R24 absorbs workload" },
    native: { label: "R24 NATIVE", color: "#1A8A9A", hint: "Fully on R24" }
  };

  // Stack-reduction tally — % of cards moved to R24 native + half-credit for reducing
  const total = sources.length;
  const nativeCount = sources.filter((s) => s.state === "native").length;
  const reducingCount = sources.filter((s) => s.state === "reducing").length;
  const reductionPct = Math.round((nativeCount + reducingCount * 0.5) / total * 100);

  // Pipe animation Y positions — one per source row + BYOV
  const yPositions = [60, 115, 170, 225, 280, 335, 390];
  const rowStates = [...sources.map((s) => s.state), "integrated"]; // BYOV is integrated

  return (
    <div className="m03">
      <div className="m03__sources">
        {/* Stack-reduction counter */}
        <div className="m03__reduce">
          <div className="m03__reduce-row">
            <span className="m03__reduce-label">STACK REDUCTION</span>
            <span className="m03__reduce-val tabular">{reductionPct}%</span>
          </div>
          <div className="m03__reduce-bar"><i style={{ width: `${reductionPct}%` }} /></div>
          <div className="m03__reduce-hint">
            {nativeCount} retired · {reducingCount} reducing · {total - nativeCount - reducingCount} integrated · click to flip
          </div>
        </div>

        {sources.map((s, i) =>
        <div key={i}
        className={`source-row source-row--split source-row--state-${s.state}`}
        onClick={() => cycleState(i)}
        role="button"
        title={stateMeta[s.state].hint}>
            <div className="source-row__top">
              <div className="source-row__heading">{s.heading}</div>
            </div>
            <div className="source-row__bottom">
              <span className="source-row__category">{s.category}</span>
              <span className={`source-row__state source-row__state--${s.state}`}>
                <span className="source-row__state-dot" />
                {stateMeta[s.state].label}
              </span>
            </div>
          </div>
        )}

        {/* Bring your own vendor */}
        <div className="source-row source-row--byov">
          <div className="source-row__top source-row__top--byov">
            <div className="source-row__heading source-row__heading--byov">+ Bring your own vendor</div>
          </div>
          <div className="source-row__bottom">
            <input className="source-row__byov-input"
            placeholder="Add a system you use today…"
            value={byovName}
            onChange={(e) => setByovName(e.target.value)} />
            <span className="source-row__state source-row__state--integrated">
              <span className="source-row__state-dot" />
              READY
            </span>
          </div>
        </div>
      </div>

      <div className="m03__pipe">
        <svg className="pipe-svg" viewBox="0 0 200 500" preserveAspectRatio="none">
          <defs>
            <linearGradient id="pipe-grad" x1="0" x2="1">
              <stop offset="0" stopColor="rgba(45,42,96,0.2)" />
              <stop offset="1" stopColor="rgba(201,173,97,0.6)" />
            </linearGradient>
          </defs>
          {yPositions.map((y, i) =>
          <path key={i}
          d={`M 0 ${y} C 60 ${y}, 120 250, 200 250`}
          stroke="url(#pipe-grad)"
          strokeWidth="1.5"
          fill="none"
          strokeDasharray="2 4" />
          )}
          {yPositions.map((y, i) =>
          <circle key={`d-${i}`}
          r="3"
          fill={stateMeta[rowStates[i]] ? stateMeta[rowStates[i]].color : "var(--r24-gold)"}>
              <animateMotion dur={`${3 + i % 3 * 0.7}s`}
            repeatCount="indefinite"
            path={`M 0 ${y} C 60 ${y}, 120 250, 200 250`} />
            </circle>
          )}
          <circle cx="200" cy="250" r="22" fill="rgba(201,173,97,0.15)" stroke="var(--r24-gold)" strokeWidth="1" />
          <circle cx="200" cy="250" r="6" fill="var(--r24-gold)" />
        </svg>
      </div>

      <div className="m03__golden">
        <div className="golden-card">
          <div>
            <div className="golden-card__label">Golden Record</div>
            <div className="golden-card__name">Rohan Mehta</div>
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 0, flex: 1 }}>
            <div className="field-row"><span>Employee ID</span><span>R24-EMP-2841</span></div>
            <div className="field-row"><span>Role</span><span>Sr. Mining Engineer</span></div>
            <div className="field-row"><span>Travel status</span><span style={{ color: "#FF4A66" }}>IN-TRANSIT · JNB→DUR</span></div>
            <div className="field-row"><span>Geo</span><span>−26.10, 28.05</span></div>
            <div className="field-row"><span>Medical alerts</span><span>Penicillin allergy</span></div>
            <div className="field-row"><span>Last sync</span><span>2m ago · {total} sources</span></div>
            <div className="field-row" style={{ borderBottom: 0 }}><span>Manual uploads</span><span style={{ color: "var(--r24-success)" }}>0</span></div>
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", paddingTop: 8, borderTop: "1px solid rgba(255,255,255,0.08)" }}>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.08em", color: "rgba(255,255,255,0.5)" }}>SCHEMA v2.1</span>
            <span className="pill pill--gold" style={{ background: "rgba(201,173,97,0.16)", color: "var(--r24-gold)" }}>VERIFIED</span>
          </div>
        </div>
      </div>
    </div>);

};

// ============================================================
// Module 04 — Multi-Channel Broadcasting
// ============================================================
const Module04 = () => {
  return (
    <div className="m04">
      <div className="m04__grid">
        <div className="composer">
        <div className="composer__label">Broadcast · Compose</div>
        <div>
          <div className="composer__title">Civil Unrest · Marseille Region</div>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, color: "var(--fg-muted)", marginTop: 4, letterSpacing: "0.04em" }}>SEVERITY · LEVEL 2 · AUTO-CASCADE</div>
        </div>
        <div className="composer__msg">
          Civil unrest reported within 4km of your location. Avoid Place Castellane and the Vieux-Port. Return to hotel or shelter in place. Reply <strong>OK</strong> to confirm. R24 GSOC monitoring.
        </div>
        <div>
          <div className="composer__label" style={{ marginBottom: 6 }}>Recipients</div>
          <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
            <span className="pill pill--navy">GROUP · FR-Marseille</span>
            <span className="pill pill--navy">12 PERSONNEL</span>
          </div>
        </div>
        <div>
          <div className="composer__label" style={{ marginBottom: 6 }}>Channels · Cascading</div>
          <div className="composer__chan">
            <span className="chip chip--on"><Icon d={Icons.bell} size={12} />App Push</span>
            <span className="chip chip--on"><Icon d={Icons.msg} size={12} />SMS</span>
            <span className="chip chip--on"><Icon d={Icons.whatsapp} size={12} />WhatsApp</span>
            <span className="chip chip--on"><Icon d={Icons.teams} size={12} />MS Teams</span>
            <span className="chip chip--on"><Icon d={Icons.mail} size={12} />Email</span>
            <span className="chip chip--on"><Icon d={Icons.phone} size={12} />Voice</span>
          </div>
        </div>
        <button className="btn-coral" style={{ marginTop: "auto" }}>Send Broadcast →</button>
      </div>

      <div className="cascade">
        <div className="cascade__head">
          <div className="cascade__title">Delivery · Real-Time</div>
          <span className="pill pill--ghost">98.5% RATE</span>
        </div>
        {[
          { name: "App Push", icon: Icons.bell, pct: 100, count: "12/12" },
          { name: "SMS", icon: Icons.msg, pct: 92, count: "11/12" },
          { name: "WhatsApp", icon: Icons.whatsapp, pct: 100, count: "12/12" },
          { name: "MS Teams", icon: Icons.teams, pct: 100, count: "12/12" },
          { name: "Email", icon: Icons.mail, pct: 100, count: "12/12" },
          { name: "Voice", icon: Icons.phone, pct: 18, count: "1/12", fail: true }].
          map((c, i) =>
          <div key={i} className={`channel ${c.fail ? "channel--failed" : ""}`}>
            <div className="channel__name"><Icon d={c.icon} size={14} />{c.name}</div>
            <div className="channel__bar"><i style={{ width: `${c.pct}%` }} /></div>
            <div className="channel__pct">{c.count}</div>
          </div>
          )}
        <div style={{
            marginTop: 6, padding: "10px 12px",
            background: "rgba(46,139,107,0.12)", border: "1px solid rgba(46,139,107,0.3)",
            borderRadius: 8, fontFamily: "var(--font-mono)", fontSize: 11,
            color: "#7CE0B8", display: "flex", justifyContent: "space-between"
          }}>
          <span>↳ CASCADE COMPLETE · 12/12 REACHED</span>
          <span>0.8s</span>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginTop: 4 }}>
          <div style={{ padding: 12, background: "rgba(255,255,255,0.04)", border: "1px solid rgba(255,255,255,0.08)", borderRadius: 8 }}>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 9.5, letterSpacing: "0.12em", textTransform: "uppercase", color: "rgba(255,255,255,0.5)" }}>SAFE responses</div>
            <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 28, color: "#fff", letterSpacing: "-0.01em" }}>9<span style={{ fontSize: 14, color: "rgba(255,255,255,0.5)" }}>/12</span></div>
          </div>
          <div style={{ padding: 12, background: "rgba(255,255,255,0.04)", border: "1px solid rgba(255,255,255,0.08)", borderRadius: 8 }}>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 9.5, letterSpacing: "0.12em", textTransform: "uppercase", color: "rgba(255,255,255,0.5)" }}>2-way confirm</div>
            <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 28, color: "#fff", letterSpacing: "-0.01em" }}>75<small style={{ fontSize: 14, color: "var(--r24-gold)" }}>%</small></div>
          </div>
        </div>
      </div>
      </div>

      {/* Bottom action bar — same set as Module 03 (Risk Monitoring) */}
      <div className="m04__actions">
        <div className="m08__action"><Icon d={Icons.users} size={16} />Show Users</div>
        <div className="m08__action"><Icon d={Icons.alert} size={16} />Show Threats</div>
        <div className="m08__action"><Icon d={Icons.shield} size={16} />Show Police</div>
        <div className="m08__action"><Icon d={Icons.api} size={16} />Show Hospitals</div>
      </div>
    </div>);

};

// ============================================================
// Module 05 — Journey Management
// ============================================================
const Module05 = () => {
  return (
    <div className="m05">
      <div className="itinerary">
        <div className="itinerary__head">
          <div>
            <div className="itinerary__title">JNB → Cape Town</div>
            <div className="itinerary__route">JNY-2841 · R. Mehta · 24 MAR 26</div>
          </div>
          <span className="pill pill--coral">DEVIATION</span>
        </div>
        <div className="tl">
          <div className="tl__item tl__item--done">
            <div className="tl__time">06:00 · APPROVED</div>
            <div className="tl__title">Pre-trip risk score: 38 / 100</div>
            <div className="tl__sub">Auto-approved · low risk</div>
          </div>
          <div className="tl__item tl__item--done">
            <div className="tl__time">10:15 · CHECK-IN</div>
            <div className="tl__title">Departure · OR Tambo</div>
            <div className="tl__sub">On schedule · SAFE confirmed</div>
          </div>
          <div className="tl__item tl__item--done">
            <div className="tl__time">11:42 · WAYPOINT</div>
            <div className="tl__title">Bloemfontein refuel</div>
            <div className="tl__sub">+8 min vs plan</div>
          </div>
          <div className="tl__item tl__item--alert">
            <div className="tl__time">13:08 · DEVIATION</div>
            <div className="tl__title" style={{ color: "var(--r24-coral)" }}>Off-route 14km · ZONE-AMBER-0117</div>
            <div className="tl__sub">Auto-escalation triggered · GSOC notified</div>
          </div>
          <div className="tl__item tl__item--active">
            <div className="tl__time">13:09 · IN PROGRESS</div>
            <div className="tl__title">Welfare check · auto-dialing</div>
            <div className="tl__sub">No manual intervention required</div>
          </div>
          <div className="tl__item">
            <div className="tl__time">17:30 · SCHEDULED</div>
            <div className="tl__title">Arrival · Cape Town Lodge</div>
            <div className="tl__sub">Auto check-in armed</div>
          </div>
        </div>
      </div>

      <div className="m01__map" style={{ height: "100%" }}>
        <div style={{
          position: "absolute", inset: 0,
          background: "radial-gradient(circle at 50% 50%, #1A1840 0%, #0E0D24 100%)"
        }} />
        <svg viewBox="0 0 600 500" style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }} preserveAspectRatio="xMidYMid slice">
          {/* Coast outline */}
          <path d="M 80 80 Q 200 60, 320 90 Q 440 110, 540 200 Q 560 300, 480 400 Q 360 450, 220 420 Q 100 380, 60 280 Q 50 160, 80 80 Z"
          fill="rgba(255,255,255,0.04)" stroke="rgba(255,255,255,0.15)" strokeWidth="1" />
          {/* Roads */}
          <path d="M 130 140 Q 220 200, 280 230 Q 340 260, 420 360"
          stroke="rgba(255,255,255,0.2)" strokeWidth="1" fill="none" strokeDasharray="3 4" />
          {/* Planned route */}
          <path d="M 130 140 Q 200 180, 250 200 Q 320 230, 420 360"
          stroke="rgba(124,224,184,0.55)" strokeWidth="2" fill="none" />
          {/* Actual route (deviating) */}
          <path d="M 130 140 Q 200 180, 250 200 Q 290 220, 320 280"
          stroke="var(--r24-coral)" strokeWidth="2.5" fill="none" />
          {/* Zone */}
          <circle cx="320" cy="280" r="40" fill="rgba(217,34,67,0.12)" stroke="var(--r24-coral)" strokeWidth="1" strokeDasharray="4 4" />

          {/* Waypoint markers */}
          <circle cx="130" cy="140" r="6" fill="#7CE0B8" />
          <circle cx="250" cy="200" r="6" fill="#7CE0B8" />
          <circle cx="320" cy="280" r="8" fill="var(--r24-coral)" />
          <circle cx="320" cy="280" r="14" fill="none" stroke="var(--r24-coral)" strokeWidth="1.5" opacity="0.5" />
          <circle cx="420" cy="360" r="6" fill="none" stroke="rgba(255,255,255,0.4)" strokeWidth="1.5" />
        </svg>
        <div className="map-label" style={{ left: "16%", top: "26%" }}>JOHANNESBURG</div>
        <div className="map-label" style={{ left: "38%", top: "38%" }}>BLOEMFONTEIN</div>
        <div className="map-label" style={{ left: "44%", top: "60%", background: "rgba(217,34,67,0.6)", border: "1px solid var(--r24-coral)" }}>OFF-ROUTE · 14KM</div>
        <div className="map-label" style={{ left: "62%", top: "74%" }}>CAPE TOWN</div>
        <div className="map-corner" style={{ top: 14, left: 16 }}>JOURNEY · JNY-2841 · ACTIVE</div>
        <div className="map-corner" style={{ top: 14, right: 16 }}>13:09 UTC+2</div>
      </div>
    </div>);

};

// ============================================================
// Module 06 — Reverse Panic & Silent Distress
// ============================================================
const Module06 = () => {
  return (
    <div className="m06">
      <div className="phone phone--shot">
        <div className="phone__screen phone__screen--shot">
          <img
            src={window.__asset('panicAlert','assets/reverse-panic-friend-alert.jpeg')}
            alt="Response24+ app — a friend's duress alert received, with one-tap options to trigger ER24 medical or armed response, navigate, message, or call"
            className="phone__shot-img" />
          <span className="phone__shot-tag">LIVE APP · FRIEND ALERT</span>
        </div>
      </div>

      <div className="gsoc">
        <div className="gsoc__bar">
          <div className="gsoc__title">LEVEL 1 · DURESS</div>
          <div style={{ display: "flex", gap: 8 }}>
            <span className="pill pill--coral" style={{ background: "rgba(217,34,67,0.16)", color: "#FF4A66" }}>SILENT</span>
            <span className="pill pill--ghost">GSOC-04</span>
          </div>
        </div>
        <div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
          <div className="gsoc__row"><span>Subject</span><span>R. Mehta · EMP-2841</span></div>
          <div className="gsoc__row"><span>Trigger</span><span>Duress PIN entered</span></div>
          <div className="gsoc__row"><span>Visible to subject</span><span>Decoy unlock screen</span></div>
          <div className="gsoc__row"><span>Location</span><span>−26.10, 28.05 · ±5m</span></div>
          <div className="gsoc__row"><span>Battery</span><span>74% · GPS HIGH</span></div>
          <div className="gsoc__row"><span>Audio buffer</span><span>00:42 captured</span></div>
        </div>
        <div className="gsoc__audio">
          <div className="audio-bars">
            <i /><i /><i /><i /><i /><i />
          </div>
          <span>BACKGROUND AUDIO · RECORDING</span>
          <span style={{ marginLeft: "auto" }}>+ EVIDENCE LOG</span>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
          <div style={{ padding: 12, background: "rgba(217,34,67,0.10)", border: "1px solid rgba(217,34,67,0.3)", borderRadius: 8 }}>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 9.5, letterSpacing: "0.12em", textTransform: "uppercase", color: "rgba(255,255,255,0.6)" }}>Responder ETA</div>
            <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 28, color: "#fff" }}>7<small style={{ fontSize: 14, color: "var(--r24-coral-400)" }}>min</small></div>
          </div>
          <div style={{ padding: 12, background: "rgba(255,255,255,0.04)", border: "1px solid rgba(255,255,255,0.08)", borderRadius: 8 }}>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 9.5, letterSpacing: "0.12em", textTransform: "uppercase", color: "rgba(255,255,255,0.5)" }}>Alert age</div>
            <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 28, color: "#fff" }}>0:11</div>
          </div>
        </div>
        <div style={{
          marginTop: "auto",
          padding: "10px 12px",
          background: "rgba(255,255,255,0.04)",
          border: "1px dashed rgba(255,255,255,0.1)",
          borderRadius: 8,
          fontFamily: "var(--font-mono)",
          fontSize: 10.5,
          color: "rgba(255,255,255,0.5)",
          letterSpacing: "0.04em"
        }}>
          ↳ subject app shows: "INCORRECT PIN — TRY AGAIN" · no indication of alert
        </div>
      </div>
    </div>);

};

// ============================================================
// Module 07 — Audit Traceability
// ============================================================
const Module07 = () => {
  const rows = [
  { hash: "0x9c1f…42a8", t: "14:22:08", who: "GSOC-04 · M. Patel", sop: "SOP-INC-002 §3.1", action: "Acknowledged duress alert · EMP-2841", chip: { c: "coral", t: "ESCALATION" } },
  { hash: "0x8d3a…f019", t: "14:22:02", who: "PULSE Core", sop: "SOP-INC-001 §1.4", action: "Auto-broadcast cascade initiated", chip: { c: "navy", t: "AUTO" } },
  { hash: "0x7e02…b117", t: "14:21:57", who: "PULSE Core", sop: "SOP-INC-001 §1.1", action: "Duress trigger detected · subject EMP-2841", chip: { c: "coral", t: "TRIGGER" } },
  { hash: "0x6b4c…91d4", t: "14:18:33", who: "T. Bekele", sop: "SOP-OPS-014 §2.0", action: "Geofence ZONE-AMBER-0117 expanded +500m", chip: { c: "gold", t: "CHANGE" } },
  { hash: "0x5a8f…c266", t: "13:55:12", who: "PULSE Core", sop: "SOP-OPS-021 §1.2", action: "HRIS sync · 1,284 records reconciled", chip: { c: "green", t: "SYNC" } },
  { hash: "0x4c19…3387", t: "13:42:01", who: "L. Reyes", sop: "SOP-OPS-009 §4.3", action: "Manual broadcast · group FR-Marseille", chip: { c: "navy", t: "BROADCAST" } },
  { hash: "0x3f70…d8e2", t: "13:08:44", who: "PULSE Core", sop: "SOP-JNY-003 §2.1", action: "Journey JNY-2841 · deviation 14km flagged", chip: { c: "coral", t: "ANOMALY" } }];

  return (
    <div className="m07">
      <div className="audit-stats">
        <div className="card" style={{ padding: 14 }}>
          <div className="kpi__label">Events · 24h</div>
          <div className="kpi__value tabular">84,219</div>
        </div>
        <div className="card" style={{ padding: 14 }}>
          <div className="kpi__label">Active SOPs</div>
          <div className="kpi__value tabular">142</div>
        </div>
        <div className="card" style={{ padding: 14 }}>
          <div className="kpi__label">Cryptographic chain</div>
          <div className="kpi__value tabular" style={{ color: "var(--r24-success)", fontSize: 22 }}>INTACT</div>
        </div>
        <div className="card" style={{ padding: 14, background: "var(--r24-navy)", color: "#fff", borderColor: "var(--r24-navy)" }}>
          <div className="kpi__label" style={{ color: "rgba(255,255,255,0.6)" }}>ISO 31030 export</div>
          <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 8 }}>
            <span className="pill pill--gold" style={{ background: "rgba(201,173,97,0.2)", color: "var(--r24-gold)" }}>1-CLICK</span>
            <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "rgba(255,255,255,0.6)" }}>CSV · JSON · PDF</span>
          </div>
        </div>
      </div>

      <div className="audit-table">
        <div style={{ padding: "14px 16px", display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: "1px solid rgba(255,255,255,0.08)" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            <span style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 16, color: "#fff" }}>Immutable Event Log</span>
            <span className="pill" style={{ background: "rgba(201,173,97,0.16)", color: "var(--r24-gold)" }}>CRYPTO-SIGNED</span>
          </div>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, color: "rgba(255,255,255,0.5)", letterSpacing: "0.06em" }}>
            HASH · CHAIN · WHO · WHAT · WHEN · WHY
          </div>
        </div>
        <div className="audit-table__head">
          <span>Hash</span>
          <span>When</span>
          <span>Actor</span>
          <span>Linked SOP</span>
          <span>Action</span>
          <span style={{ textAlign: "right" }}>Tag</span>
        </div>
        <div style={{ overflow: "auto", flex: 1 }}>
          {rows.map((r, i) =>
          <div key={i} className="audit-row">
              <span className="audit-row__hash">{r.hash}</span>
              <span className="audit-row__when">{r.t}</span>
              <span className="audit-row__actor">{r.who}</span>
              <span className="audit-row__sop">{r.sop}</span>
              <span className="audit-row__action">{r.action}</span>
              <span className="audit-row__chip"><span className={`pill pill--${r.chip.c}`} style={r.chip.c === "navy" ? { background: "rgba(255,255,255,0.08)", color: "rgba(255,255,255,0.85)" } : r.chip.c === "gold" ? { background: "rgba(201,173,97,0.16)", color: "var(--r24-gold)" } : r.chip.c === "green" ? { background: "rgba(46,139,107,0.16)", color: "#7CE0B8" } : { background: "rgba(217,34,67,0.16)", color: "#FF4A66" }}>{r.chip.t}</span></span>
            </div>
          )}
        </div>
      </div>
    </div>);

};

// ============================================================
// Module 08 — Executive Dashboard (mirrors real R24 PULSE portal)
// LIVE — Threats rotate every 4.5s, NOT-OK count fluctuates, popup persona
// cycles every 7s, geofence + markers pulse via CSS. Snappy, no bounce.
// VRO toasts cycle every ~6s — the major automation differentiator.
// ============================================================

// VRO = Virtual Risk Operator. Agent updates that prove the platform isn't
// just a dashboard — it's doing work on the operator's behalf, with proof.
const VRO_MESSAGES = [
  {
    title: "Manager Notified",
    sub: "Country Director paged on duress alert · acknowledged in 12s",
    icon: "bell",
  },
  {
    title: "Ambulance Dispatched",
    sub: "ER24 unit 7 en-route to D. Smit · ETA 6 min",
    icon: "amb",
  },
  {
    title: "Audit Trail Sealed",
    sub: "INC-0412 hash-signed · 14:22:38 UTC · prosecutor pack ready",
    icon: "lock",
  },
];

const VROToast = ({ msg, onClose }) => {
  const [closing, setClosing] = React.useState(false);
  React.useEffect(() => {
    const fade = setTimeout(() => setClosing(true), 5600);
    const drop = setTimeout(onClose, 6100);
    return () => { clearTimeout(fade); clearTimeout(drop); };
  }, [onClose]);
  return (
    <div className={`vro-toast ${closing ? "vro-toast--out" : ""}`} role="status">
      <div className="vro-toast__head">
        <span className="vro-toast__chip">
          <span className="vro-toast__spark" aria-hidden="true">✦</span>
          VRO · Agent
        </span>
        <span className="vro-toast__when">just now</span>
      </div>
      <div className="vro-toast__body">
        <div className="vro-toast__title">{msg.title}</div>
        <div className="vro-toast__sub">{msg.sub}</div>
      </div>
    </div>
  );
};

const Module08 = () => {
  const POPUP_PROFILES = React.useMemo(() => ([
    { name: "Dohan Smit",           role: "Sr. Developer",     country: "South Africa", lastSeen: "26 May, 16:45", battery: "64%", left: "52%", top: "22%" },
    { name: "Aisha Mokoena",        role: "Field Engineer",    country: "South Africa", lastSeen: "26 May, 16:48", battery: "41%", left: "48%", top: "30%" },
    { name: "Marlize Holtzhausen",  role: "Country Director",  country: "South Africa", lastSeen: "26 May, 16:52", battery: "82%", left: "55%", top: "26%" },
  ]), []);

  const THREAT_POOL = React.useMemo(() => ([
    { t: "Armed robbery, Sandton",                sev: "major", label: "Major" },
    { t: "Hijacking, N3 Heidelberg",              sev: "mod",   label: "Moderate" },
    { t: "Civil unrest, Mahikeng CBD",            sev: "major", label: "Major" },
    { t: "Power outage, Joburg South",            sev: "ltd",   label: "Limited" },
    { t: "Truck blockade, Vereeniging",           sev: "mod",   label: "Moderate" },
    { t: "Smash-and-grab, Rosebank",              sev: "mod",   label: "Moderate" },
    { t: "Wildfire risk, Pilanesberg",            sev: "ltd",   label: "Limited" },
    { t: "Service delivery protest, Brakpan",     sev: "ltd",   label: "Limited" },
    { t: "Mall evacuation, Centurion",            sev: "major", label: "Major" },
    { t: "Floods warning, Mooi River",            sev: "mod",   label: "Moderate" },
    { t: "Taxi violence, Diepkloof",              sev: "major", label: "Major" },
    { t: "Burst water main, Sunninghill",         sev: "ltd",   label: "Limited" },
  ]), []);

  const initialThreats = React.useMemo(() => ([
    { id: 1, t: "Planned protest, Majakaneng",     sev: "ltd",   label: "Limited" },
    { id: 2, t: "Bystanders shot, Kgobokwane",     sev: "major", label: "Major" },
    { id: 3, t: "Community shutdown, Mahikeng",    sev: "ltd",   label: "Limited" },
    { id: 4, t: "Cash-in-transit robbery, Welkom", sev: "mod",   label: "Moderate" },
    { id: 5, t: "Severe weather warning, KZN",     sev: "mod",   label: "Moderate" },
  ]), []);

  const [threats, setThreats] = React.useState(initialThreats);
  const [threatCount, setThreatCount] = React.useState(23);
  const [countTick, setCountTick] = React.useState(0);
  const [popupIdx, setPopupIdx] = React.useState(0);
  const [notOk, setNotOk] = React.useState(6);
  const [notOkBump, setNotOkBump] = React.useState(0);
  const [toasts, setToasts] = React.useState([]);
  const [bellBump, setBellBump] = React.useState(0);
  const nextId = React.useRef(initialThreats.length + 1);
  const toastIdRef = React.useRef(0);

  // Rotate the Incoming Threats list every 4.5s
  React.useEffect(() => {
    const t = setInterval(() => {
      const fresh = THREAT_POOL[Math.floor(Math.random() * THREAT_POOL.length)];
      const id = nextId.current++;
      setThreats(prev => [{ ...fresh, id }, ...prev].slice(0, 5));
      setThreatCount(c => c + 1);
      setCountTick(k => k + 1);
    }, 4500);
    return () => clearInterval(t);
  }, [THREAT_POOL]);

  // Cycle the user popup persona every 7s
  React.useEffect(() => {
    const t = setInterval(() => setPopupIdx(i => (i + 1) % POPUP_PROFILES.length), 7000);
    return () => clearInterval(t);
  }, [POPUP_PROFILES.length]);

  // Fluctuate NOT-OK widget every 8s — feels alive without being chaotic
  React.useEffect(() => {
    const t = setInterval(() => {
      setNotOk(n => Math.max(3, Math.min(11, n + (Math.random() > 0.5 ? 1 : -1))));
      setNotOkBump(b => b + 1);
    }, 8000);
    return () => clearInterval(t);
  }, []);

  // VRO toast scheduler — fire first message at 2.5s, then a new one every 5.5s.
  // Keep only the two most-recent on screen.
  React.useEffect(() => {
    let idx = 0;
    const fire = () => {
      const id = ++toastIdRef.current;
      const msg = VRO_MESSAGES[idx % VRO_MESSAGES.length];
      setToasts(prev => [...prev, { id, ...msg }].slice(-2));
      setBellBump(b => b + 1);
      idx += 1;
    };
    const first = setTimeout(fire, 2500);
    const interval = setInterval(fire, 5500);
    return () => { clearTimeout(first); clearInterval(interval); };
  }, []);

  const removeToast = React.useCallback((id) => {
    setToasts(prev => prev.filter(t => t.id !== id));
  }, []);

  const popup = POPUP_PROFILES[popupIdx];

  return (
    <div className="m08">
      <div className="m08__topbar">
        <div className="logo-circle" style={{ background: "transparent", border: 0, padding: 0 }}>
          <img src={window.__asset('iconEmblem','assets/r24i-icon.png')} alt="R24" style={{ width: "100%", height: "100%", objectFit: "contain", display: "block" }} />
        </div>
        <div className="m08__search">
          <Icon d={Icons.filter} size={14} stroke={1.5} />
          <span>Gauteng, South Africa</span>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <div key={bellBump} className="m08__bell m08__bell--ring" style={{ position: "relative", color: "rgba(255,255,255,0.7)" }}>
            <Icon d={Icons.bell} size={16} />
            <span style={{
              position: "absolute", top: -4, right: -6,
              background: "var(--r24-coral)", color: "#fff",
              fontSize: 8, fontWeight: 700,
              borderRadius: 999, padding: "1px 4px",
              fontFamily: "var(--font-mono)"
            }}>06</span>
          </div>
          <div className="m08__user">
            <div className="m08__user-avatar">MH</div>
            <div>
              <div className="m08__user-name">R24 International</div>
              <div className="m08__user-role">M. Holtzhausen · Group CEO</div>
            </div>
          </div>
        </div>
      </div>
      <div className="m08__body">
        <div className="m08__sidebar">
          <div className="m08__sidebar-item m08__sidebar-item--active"><Icon d={Icons.shield} size={18} /></div>
          <div className="m08__sidebar-item"><Icon d={Icons.broadcast} size={18} /></div>
          <div className="m08__sidebar-item"><Icon d={Icons.alert} size={18} /></div>
          <div className="m08__sidebar-item"><Icon d={Icons.users} size={18} /></div>
          <div className="m08__sidebar-item"><Icon d={Icons.route} size={18} /></div>
          <div className="m08__sidebar-item"><Icon d={Icons.truck} size={18} /></div>
          <div className="m08__sidebar-item"><Icon d={Icons.msg} size={18} /></div>
          <div className="m08__sidebar-divider" aria-hidden="true" />
          <div
            key={bellBump}
            className="m08__sidebar-item m08__sidebar-item--vro"
            title="VRO · Virtual Risk Operator (agent active)"
          >
            <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
              <path d="M12 2 L13.6 8.4 L20 10 L13.6 11.6 L12 18 L10.4 11.6 L4 10 L10.4 8.4 Z" />
            </svg>
            <span className="m08__sidebar-vro-dot" aria-hidden="true" />
          </div>
        </div>
        <div className="m08__main">
          {/* Live map background — drop a cleaner screenshot to replace.
              Inline style because React 18 doesn't map className → class on
              custom elements (it passes literal "classname"). */}
          <image-slot
            id="m08-pulse-map"
            src={window.__asset('mapGauteng','assets/m08-map-gauteng.png')}
            fit="cover"
            shape="rect"
            placeholder="Drop a cleaner map screenshot"
            style={{ position: "absolute", inset: 0, width: "auto", height: "auto", zIndex: 0 }}
          ></image-slot>
          <svg className="m08__map-svg" viewBox="0 0 800 600" preserveAspectRatio="xMidYMid slice">
            {/* threat geofence (large pink circle around personnel cluster) */}
            <circle cx="420" cy="320" r="170" fill="rgba(217,34,67,0.10)" stroke="var(--r24-coral)" strokeWidth="1.5" />
          </svg>

          {/* VRO toast stack — the major differentiator: agent acting on the operator's behalf */}
          <div className="vro-toasts" aria-live="polite">
            {toasts.map(t => (
              <VROToast key={t.id} msg={t} onClose={() => removeToast(t.id)} />
            ))}
          </div>

          {/* Markers */}
          <div className="mkr mkr--red" style={{ left: "42%", top: "40%" }}><Icon d={Icons.alert} size={12} /></div>
          <div className="mkr mkr--amber" style={{ left: "38%", top: "46%" }}><Icon d={Icons.shield} size={12} /></div>
          <div className="mkr mkr--amber" style={{ left: "46%", top: "44%" }}><Icon d={Icons.shield} size={12} /></div>
          <div className="mkr mkr--cluster mkr--green" style={{ left: "50%", top: "52%" }}>4</div>
          <div className="mkr mkr--cluster mkr--green" style={{ left: "54%", top: "58%" }}>2</div>
          <div className="mkr mkr--red" style={{ left: "58%", top: "56%" }}><Icon d={Icons.alert} size={12} /></div>
          <div className="mkr mkr--amber" style={{ left: "30%", top: "54%" }}><Icon d={Icons.shield} size={12} /></div>
          <div className="mkr mkr--red" style={{ left: "33%", top: "73%" }}><Icon d={Icons.alert} size={12} /></div>
          <div className="mkr mkr--green" style={{ left: "49%", top: "83%" }}><Icon d={Icons.users} size={12} /></div>
          <div className="mkr mkr--green" style={{ left: "55%", top: "79%" }}><Icon d={Icons.users} size={12} /></div>

          {/* User detail popup (cycles persona every 7s) */}
          <div key={popupIdx} className="user-popup" style={{ left: popup.left, top: popup.top }}>
            <div className="user-popup__head">
              <div className="user-popup__name">{popup.name}</div>
              <span className="pill pill--coral">NOT OK</span>
            </div>
            <div className="user-popup__row"><span>Status</span><span style={{ color: "var(--r24-coral)" }}>Not OK</span></div>
            <div className="user-popup__row"><span>Country</span><span>{popup.country}</span></div>
            <div className="user-popup__row"><span>Role</span><span>{popup.role}</span></div>
            <div className="user-popup__row"><span>Last seen</span><span>{popup.lastSeen}</span></div>
            <div className="user-popup__row"><span>Battery</span><span>{popup.battery}</span></div>
            <button className="user-popup__btn">View Details</button>
          </div>

          {/* Floating incoming threats panel */}
          <div className="m08__threat-panel">
            <div className="m08__threat-head">
              <span style={{ display: "flex", alignItems: "center", gap: 6 }}>
                <Icon d={Icons.alert} size={13} />
                Incoming Threats
              </span>
              <span
                key={countTick}
                className="m08__threat-count m08__threat-count--tick"
                style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "rgba(255,255,255,0.5)" }}
              >
                {threatCount}
              </span>
            </div>
            {threats.map((t, i) =>
              <div
                key={t.id}
                className="m08__threat-row"
                style={{ animationDelay: `${i * 60}ms` }}
              >
                <span style={{ flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{t.t}</span>
                <span className={`m08__threat-pill m08__threat-pill--${t.sev}`}>{t.label}</span>
              </div>
            )}
          </div>

          {/* Right widgets */}
          <div className="m08__widgets">
            <div className="m08__widget">
              <div className="m08__widget-head">
                <span className="m08__widget-badge">Not OK</span>
                <span style={{ marginLeft: 6 }}>Not OK</span>
              </div>
              <div className="m08__widget-value">
                <span key={notOkBump} className="m08__widget-value--bump">{notOk}</span>
                {" "}
                <span style={{ fontSize: 9, color: "rgba(255,255,255,0.55)", fontWeight: 600, fontFamily: "var(--font-mono)", letterSpacing: "0.12em" }}>USERS</span>
              </div>
            </div>
            <div className="m08__widget">
              <div className="m08__widget-head">
                <span style={{ width: 8, height: 8, borderRadius: "50%", background: "var(--r24-warning)", flexShrink: 0 }} />
                Not Compliant
              </div>
              <div className="m08__widget-value">8 <span style={{ fontSize: 9, color: "rgba(255,255,255,0.55)", fontWeight: 600, fontFamily: "var(--font-mono)", letterSpacing: "0.12em" }}>USERS</span></div>
            </div>
            <div className="m08__widget">
              <div className="m08__widget-head"><Icon d={Icons.broadcast} size={12} />Active Broadcasts</div>
              <div className="m08__widget-line"><span className="dot" style={{ background: "var(--r24-coral)" }}>1</span>Emergency</div>
              <div className="m08__widget-line"><span className="dot" style={{ background: "var(--r24-warning)" }}>29</span>Alert</div>
              <div className="m08__widget-line"><span className="dot" style={{ background: "var(--r24-info)" }}>4</span>Info</div>
            </div>
            <div className="m08__widget">
              <div className="m08__widget-head"><Icon d={Icons.route} size={12} />Travel</div>
              <div className="m08__widget-line"><span className="dot" style={{ background: "var(--r24-success)" }}>1</span>In Progress</div>
              <div className="m08__widget-line"><span className="dot" style={{ background: "var(--r24-coral)" }}>1</span>Overdue</div>
            </div>
          </div>

          {/* Bottom action bar */}
          <div className="m08__bottom">
            <div className="m08__action"><Icon d={Icons.users} size={16} />Show Users</div>
            <div className="m08__action"><Icon d={Icons.alert} size={16} />Show Threats</div>
            <div className="m08__action"><Icon d={Icons.shield} size={16} />Show Police</div>
            <div className="m08__action"><Icon d={Icons.api} size={16} />Show Hospitals</div>
          </div>
        </div>
      </div>
    </div>);

};

// ============================================================
// Module 09 — Responder Integration
// ============================================================
const Module09 = () => {
  return (
    <div className="m09">
      <div className="m09__map">
        <div style={{
          position: "absolute", inset: 0,
          background: "radial-gradient(circle at 50% 50%, #1A1840 0%, #0E0D24 100%)"
        }} />
        <svg viewBox="0 0 600 500" style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }} preserveAspectRatio="xMidYMid slice">
          {/* Street grid */}
          {[...Array(7)].map((_, i) =>
          <line key={`h-${i}`} x1="0" y1={60 + i * 60} x2="600" y2={60 + i * 60} stroke="rgba(255,255,255,0.08)" strokeWidth="0.6" />
          )}
          {[...Array(11)].map((_, i) =>
          <line key={`v-${i}`} x1={i * 60} y1="0" x2={i * 60} y2="500" stroke="rgba(255,255,255,0.08)" strokeWidth="0.6" />
          )}
          {/* Main roads */}
          <path d="M 0 200 L 600 220" stroke="rgba(255,255,255,0.15)" strokeWidth="3" />
          <path d="M 280 0 L 320 500" stroke="rgba(255,255,255,0.15)" strokeWidth="3" />
          {/* Geo-fence around subject */}
          <circle cx="360" cy="260" r="38" fill="rgba(124,224,184,0.10)" stroke="#7CE0B8" strokeWidth="1" strokeDasharray="4 3" />
          {/* Route */}
          <path d="M 120 100 Q 200 150, 240 190 Q 290 230, 360 260"
          stroke="var(--r24-gold)" strokeWidth="2.5" fill="none" strokeDasharray="5 4">
            <animate attributeName="stroke-dashoffset" from="0" to="-18" dur="1.2s" repeatCount="indefinite" />
          </path>
          {/* Subject */}
          <circle cx="360" cy="260" r="8" fill="var(--r24-coral)" />
          <circle cx="360" cy="260" r="14" fill="none" stroke="var(--r24-coral)" strokeWidth="1.5" opacity="0.6">
            <animate attributeName="r" from="8" to="22" dur="1.6s" repeatCount="indefinite" />
            <animate attributeName="opacity" from="0.6" to="0" dur="1.6s" repeatCount="indefinite" />
          </circle>
          {/* Responder vehicle */}
          <g transform="translate(120 100)">
            <rect x="-12" y="-10" width="24" height="20" rx="4" fill="var(--r24-gold)" />
            <circle r="20" fill="none" stroke="var(--r24-gold)" strokeWidth="1" opacity="0.5" />
          </g>
        </svg>
        <div className="map-label" style={{ left: "16%", top: "16%", background: "rgba(201,173,97,0.6)", border: "1px solid var(--r24-gold)" }}>RESPONDER UNIT 7</div>
        <div className="map-label" style={{ left: "58%", top: "48%", background: "rgba(217,34,67,0.6)", border: "1px solid var(--r24-coral)" }}>SUBJECT · EMP-2841</div>
        <div className="map-corner" style={{ top: 14, left: 16 }}>SANDTON · GAUTENG · LIVE</div>
        <div className="map-corner" style={{ top: 14, right: 16 }}>RESPONDER NET · 142 VETTED</div>
        <div className="map-corner" style={{ bottom: 14, left: 16 }}>ARRIVAL VERIFICATION · GEO-FENCED</div>
        <div className="map-corner" style={{ bottom: 14, right: 16 }}>NO GHOST CHECK-INS</div>
      </div>

      <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        <div className="eta-card">
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.16em", textTransform: "uppercase", color: "rgba(255,255,255,0.5)" }}>Live ETA</div>
          <div className="eta-number tabular">7<small>min</small><span style={{ fontSize: 14, color: "rgba(255,255,255,0.5)", fontWeight: 500, marginLeft: 8 }}>· 2.4 km</span></div>
          <div style={{ display: "flex", gap: 8, marginTop: 10 }}>
            <span className="pill pill--gold" style={{ background: "rgba(201,173,97,0.16)", color: "var(--r24-gold)" }}>AUTO-DISPATCHED</span>
            <span className="pill pill--ghost">NEAREST QUALIFIED</span>
          </div>
          <div className="responder-card">
            <div className="responder-card__icon"><Icon d={Icons.truck} size={20} /></div>
            <div>
              <div style={{ fontFamily: "var(--font-ui)", fontWeight: 700, fontSize: 13, color: "#fff" }}>Hi-Risk Response · Unit 7</div>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, color: "rgba(255,255,255,0.5)" }}>Armed · medical-trained · vetted</div>
            </div>
            <span className="pill" style={{ background: "rgba(124,224,184,0.16)", color: "#7CE0B8" }}>EN ROUTE</span>
          </div>
          <div className="responder-card">
            <div className="responder-card__icon" style={{ background: "rgba(124,224,184,0.12)", color: "#7CE0B8" }}><Icon d={Icons.shield} size={20} /></div>
            <div>
              <div style={{ fontFamily: "var(--font-ui)", fontWeight: 700, fontSize: 13, color: "#fff" }}>Backup · Unit 12</div>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, color: "rgba(255,255,255,0.5)" }}>On standby · 14 min</div>
            </div>
            <span className="pill pill--ghost">QUEUED</span>
          </div>
        </div>

        <div className="card" style={{ padding: 14 }}>
          <div className="kpi__label">Responder API · global</div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12, marginTop: 10 }}>
            <div>
              <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 22, color: "var(--r24-navy)" }}>87</div>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--fg-subtle)", letterSpacing: "0.08em", textTransform: "uppercase" }}>Countries</div>
            </div>
            <div>
              <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 22, color: "var(--r24-navy)" }}>1,420+</div>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--fg-subtle)", letterSpacing: "0.08em", textTransform: "uppercase" }}>Providers</div>
            </div>
            <div>
              <div style={{ fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 22, color: "var(--r24-navy)" }}>1</div>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--fg-subtle)", letterSpacing: "0.08em", textTransform: "uppercase" }}>API</div>
            </div>
          </div>
        </div>
      </div>
    </div>);

};

// Export to window
Object.assign(window, {
  Icon, Icons,
  Module01, Module02, Module03, Module04, Module05,
  Module06, Module07, Module08, Module09
});