// site-product.jsx — R24 Response: 10 Core Integrated Modules + deep-dive
// Operator platform (security firms, GSOCs, critical-infrastructure NOCs)

const RESPONSE_MODULES = [
  { id: 1, num: "01", name: "Shift &amp; Roster Command",                tag: "OPERATE",
    sub: "Live shift board across all sites, regions, and contracts. Officer attendance verified by geofence on clock-in." },
  { id: 2, num: "02", name: "Patrol &amp; Checkpoint Verification",       tag: "VERIFY",
    sub: "NFC and GPS-verified patrols. Every checkpoint scan is timestamped, geolocked, and signed — no more paper rounds." },
  { id: 3, num: "03", name: "Incident Dispatch Console",                   tag: "DISPATCH",
    sub: "Live incident queue, nearest qualified responder logic, ETA tracking, and geo-verified arrival — across every contract." },
  { id: 4, num: "04", name: "Body-cam &amp; Evidence Capture",             tag: "EVIDENCE",
    sub: "Stream-then-store body-cam video, audio, and photo evidence with cryptographic hash + chain-of-custody — court-grade by default." },
  { id: 5, num: "05", name: "SLA &amp; KPI Enforcement",                   tag: "SLA",
    sub: "Real-time SLA timer per incident. Live scorecard per contract. Penalties calculated from facts — not vendor self-reports." },
  { id: 6, num: "06", name: "Workforce &amp; HR Compliance",               tag: "WORKFORCE",
    sub: "PSIRA / SIA / state-licence validity, training currency, firearm competency, medical fitness — checked at every shift assignment." },
  { id: 7, num: "07", name: "Client Portal &amp; Reporting",               tag: "CLIENT",
    sub: "Branded client view: live incidents, SLA scorecard, monthly reports, and one-click audit export. The proof your clients ask for." },
  { id: 8, num: "08", name: "Compliance &amp; Licence Vault",              tag: "COMPLIANCE",
    sub: "Every licence, insurance certificate, and SLA contract in one signed vault — with expiry alerts and regulator-ready export." },
  { id: 9, num: "09", name: "Tamper-Proof Audit Trail",                    tag: "AUDIT",
    sub: "Every action, scan, dispatch, and evidence file hashed onto an append-only ledger. Disputes resolved by fact, not memory." },
  { id: 10, num: "10", name: "Operations Reporting",                       tag: "REPORT",
    sub: "Board-ready operations reports across sites, contracts, officers, and SLAs. Predictive risk modelling per contract included." },
];

const RESPONSE_DETAILS = {
  1: {
    tagline: "Every shift, every site, every officer — accounted for in one live board.",
    bullets: [
      "Live shift board across sites, regions, and contracts — refreshes every 15 seconds",
      "Geofenced clock-in: officer must be inside the site polygon to mark on-duty",
      "Auto-detect no-shows in under 2 minutes — escalate to on-call supervisor",
      "Roster gaps highlighted by SLA risk, not alphabetical order",
      "Mobile-first for supervisors in the field — works offline, syncs on reconnect",
    ],
    useCase: "Officer Mokoena assigned to Bryanston site, 18:00 shift. At 18:02 he's still 1.4km away — geofence check fails, console pages the supervisor, and the nearest available officer is auto-offered the shift before the client sees a gap.",
    integrates: ["SAP SuccessFactors", "Workday", "Sage", "Custom payroll APIs"],
    metric: "&lt;2 min",
    metricLabel: "No-show detection",
  },
  2: {
    tagline: "Replace paper patrol books with cryptographically signed checkpoints.",
    bullets: [
      "NFC tag + GPS dual verification — neither can be faked without the other",
      "Per-checkpoint photo and voice-note attach (offline-capable, syncs on signal)",
      "Missed checkpoint auto-escalates within 60 seconds of the patrol window",
      "Live patrol map per site for supervisor and client view",
      "Patrol logs hash-signed and exported as a signed PDF on demand",
    ],
    useCase: "12-stop perimeter patrol at a Sandton corporate campus. Checkpoint 7 missed at 02:47. Within 60 seconds, the supervisor's tablet pings, the officer's radio rings, and the live map shows the officer 230m off-route — issue resolved before the client's next-day report.",
    integrates: ["NFC tags", "BLE beacons", "Existing PSIM systems"],
    metric: "100%",
    metricLabel: "Patrols cryptographically signed",
  },
  3: {
    tagline: "One queue. Nearest qualified responder. Verified arrival.",
    bullets: [
      "Live incident queue ranked by severity, SLA timer, and proximity",
      "Auto-suggest nearest qualified responder — checks licence, training, and availability",
      "Geo-fenced arrival verification — patented R24 technology eliminates ghost check-ins",
      "Single API to 1,420+ vetted responders across 87 countries (when surge capacity is needed)",
      "Every dispatch decision logged with operator name, coordinates, and outcome",
    ],
    useCase: "Panic activation, Fourways. Console proposes Officer Smit (1.2km, armed, licence current) — operator confirms with one tap. Arrival verified by geofence at 14:22:38 — 4 min 12 sec SLA, well inside the 8-minute contract.",
    integrates: ["R24 PULSE", "ER24", "Private security partners", "Single API"],
    metric: "1,420+",
    metricLabel: "Vetted responders, global",
  },
  4: {
    tagline: "Body-cam streamed, hashed, stored — admissible by default.",
    bullets: [
      "Stream-then-store: video pushed to vault in real time, not after the shift",
      "SHA-256 hash per file, signed at capture — tampering is mathematically detectable",
      "Chain-of-custody log: who touched the file, when, why — immutable",
      "Photo + audio + video supported, with auto-blur of bystanders for POPIA / GDPR",
      "One-click prosecutor / insurer export with the full chain-of-custody bundle",
    ],
    useCase: "Officer responds to an armed robbery at a Centurion site. Body-cam footage streams live to GSOC; by the time SAPS arrives, the prosecutor's portal already holds the signed evidence bundle — case opened the same morning.",
    integrates: ["Axon", "Reveal Media", "AWS S3 Glacier", "Prosecutor portals"],
    metric: "SHA-256",
    metricLabel: "Per-file, signed at capture",
  },
  5: {
    tagline: "SLA penalties — and credits — calculated from facts, not vendor self-reports.",
    bullets: [
      "Live SLA timer per incident — turns red the moment you risk a breach",
      "Per-contract scorecard: response time, patrol coverage, evidence completeness",
      "Penalties auto-calculated from the audit trail — no end-of-month spreadsheet war",
      "42% KPI-miss problem in the industry — surfaced live, not in next month's report",
      "Shadow-SLA mode for prospects: prove what the incumbent is missing before you bid",
    ],
    useCase: "Critical-infrastructure client SLA: 8 minutes. Incident 14:22, responder verified on-scene 14:26:12. Live timer never went amber. Monthly scorecard auto-shows 99.2% on-time — penalty avoided, credit triggered on a separate site where the SLA was beaten by 40%.",
    integrates: ["Existing CMMS", "ServiceNow", "Jira Service Mgmt", "Finance / ERP"],
    metric: "42%",
    metricLabel: "Avg industry KPI miss closed",
  },
  6: {
    tagline: "Never deploy an officer whose licence, training or fitness is out of date.",
    bullets: [
      "PSIRA / SIA / state licence validity checked at every shift assignment",
      "Firearm competency, first-aid, and site-specific training currency enforced",
      "Medical fitness and fit-for-duty status surfaced before the roster locks",
      "Expiry alerts at 60 / 30 / 7 days — no surprises, no regulator letters",
      "Per-officer compliance file exported for client audits in two clicks",
    ],
    useCase: "Roster auto-pulled for the high-risk cash-in-transit contract. Two officers flagged: one PSIRA grade expires in 6 days, one firearm requalification due next week. Both replaced before the shift locks — zero non-compliant deployments.",
    integrates: ["PSIRA", "SIA registry", "Workday", "Custom HRIS"],
    metric: "0",
    metricLabel: "Non-compliant deployments, target",
  },
  7: {
    tagline: "Give your clients the proof they ask for — branded, live, on demand.",
    bullets: [
      "Branded client view per contract — your colours, your logo, your data",
      "Live incident feed, SLA scorecard, and patrol map — read-only for the client",
      "Monthly report auto-generated, signed, and pushed on the contract day",
      "Client comments thread per incident — questions answered with evidence, not email",
      "One-click audit export — the file your client's auditor actually wants",
    ],
    useCase: "Mining client opens her tablet at 06:00 Monday: month's scorecard 98.4% SLA, 312 incidents managed, 4 patrols escalated, full chain-of-custody intact. Her quarterly review meeting takes 12 minutes instead of 90.",
    integrates: ["Single sign-on", "Branded portal", "PDF / CSV / API export"],
    metric: "98.4%",
    metricLabel: "Avg client SLA proven, live",
  },
  8: {
    tagline: "Every licence, certificate, contract — one signed vault, regulator-ready.",
    bullets: [
      "PSIRA, SIA, insurance, BBBEE, and contract docs in one ledger",
      "Expiry monitoring: 60 / 30 / 7-day rolling alerts to ops, finance, and legal",
      "Hash-signed at upload — version drift and silent edits are detectable",
      "Regulator export: pre-built packs for PSIRA, SIA, NIS2, GDPR, POPIA audits",
      "Per-site, per-contract, per-officer views — slice the vault the way auditors think",
    ],
    useCase: "PSIRA audit notice arrives Tuesday for a Thursday inspection. Compliance officer exports the signed pack from the vault in 90 seconds — 412 officers, 18 sites, every licence current and provable. Audit closes without a single follow-up.",
    integrates: ["DocuSign", "SharePoint", "AWS S3", "PSIRA API"],
    metric: "90s",
    metricLabel: "From audit notice to signed pack",
  },
  9: {
    tagline: "Append-only ledger. Every action provable. Disputes end here.",
    bullets: [
      "Hash-chained ledger: each entry references the hash of the previous — tampering is detectable end-to-end",
      "Every shift clock-in, patrol scan, dispatch, evidence file, SLA event recorded",
      "External witness: daily ledger root anchored to a public timestamp service",
      "Operator name, coordinates, device ID and timestamp on every entry — full provenance",
      "Disputes resolved by replay, not memory — the record speaks for itself",
    ],
    useCase: "Client claims response was 22 minutes; their CCTV shows 6 minutes. Replay the ledger: dispatch 14:22:08, geo-verified on-scene 14:28:11 — 6 min 3 sec. Dispute closed in the meeting, not in court.",
    integrates: ["Public timestamp anchors", "Internal SIEM", "Forensic tooling"],
    metric: "Append-only",
    metricLabel: "Hash-chained ledger, by design",
  },
  10: {
    tagline: "Board-ready operations reporting across sites, contracts, officers, and SLAs.",
    bullets: [
      "Four standing report families — Operations, SLA, Workforce, and Evidence",
      "Predictive risk modelling per contract: which sites will breach SLA in the next 30 days",
      "Cross-contract benchmarking — find the operational patterns that win renewals",
      "Every report hash-signed and exportable as PDF, CSV, or JSON",
      "Board-pack auto-builds for the 06:00 Monday standup — no slide deck required",
    ],
    useCase: "Group COO opens the Monday board pack. SLA trending up 1.4 points, two contracts on the renewal-risk list, one officer cohort flagged for refresher training. Three decisions made before the meeting starts.",
    integrates: ["Tableau", "Power BI", "Finance ERP", "Slack / Teams"],
    metric: "4 families",
    metricLabel: "1 signed audit trail beneath",
  },
};

// =============================================================
// Visual placeholders per Response module
// =============================================================
function ResponseModuleMock({ m, detail }) {
  const tone = "red";
  return (
    <div className="resp-mock">
      <div className="resp-mock__head">
        <div className="resp-mock__id">
          <span className="resp-mock__num">MODULE · {m.num}</span>
          <span className="resp-mock__tag">{m.tag}</span>
        </div>
        <h4 className="resp-mock__title" dangerouslySetInnerHTML={{ __html: m.name }}/>
        <p className="resp-mock__tagline">{detail.tagline}</p>
      </div>

      <div className="resp-mock__body">
        <div className="resp-mock__metric">
          <div className="resp-mock__metric-val" dangerouslySetInnerHTML={{ __html: detail.metric }}/>
          <div className="resp-mock__metric-lab">{detail.metricLabel}</div>
        </div>
        <ul className="resp-mock__bullets">
          {detail.bullets.slice(0, 3).map((b, i) => (
            <li key={i}>
              <span className="resp-mock__check"><SIcon d={"M20 6 9 17l-5-5"} size={11} stroke={2.5}/></span>
              <span>{b}</span>
            </li>
          ))}
        </ul>
      </div>

      <div className="resp-mock__foot">
        <span className="resp-mock__foot-label">In production</span>
        <p>{detail.useCase}</p>
      </div>
    </div>
  );
}

function ResponseModulesSection() {
  const [active, setActive] = React.useState(1);
  const [time, setTime] = React.useState(() => fmt(new Date()));
  React.useEffect(() => {
    const t = setInterval(() => setTime(fmt(new Date())), 1000);
    return () => clearInterval(t);
  }, []);
  function fmt(d) {
    const h = String(d.getUTCHours()).padStart(2, "0");
    const m = String(d.getUTCMinutes()).padStart(2, "0");
    const s = String(d.getUTCSeconds()).padStart(2, "0");
    return `${h}:${m}:${s}`;
  }
  const current = RESPONSE_MODULES.find(m => m.id === active);

  // Smooth scroll + open the matching deep-dive when a rail item is double-clicked,
  // or when the user clicks the "Open deep-dive" tile.
  const openDeepDive = (id) => {
    setActive(id);
    const el = document.getElementById(`response-module-${id}`);
    if (el) {
      el.setAttribute("open", "");
      const top = el.getBoundingClientRect().top + window.scrollY - 88;
      window.scrollTo({ top, behavior: "smooth" });
    }
  };

  return (
    <section id="response-modules" className="response-modules" style={{
      background: "var(--white)",
      padding: "var(--sp-section) 0",
      borderTop: "1px solid var(--gray-200)",
    }}>
      <div className="container">

        {/* Section header — red accent */}
        <div className="section-header section-header--modules section-header--red">
          <p className="eyebrow eyebrow--red">
            <span style={{
              display: "inline-block", width: 8, height: 8, borderRadius: "50%",
              background: "var(--red-500)", marginRight: 10,
              boxShadow: "0 0 0 4px rgba(200,35,51,0.18)",
              animation: "blink 2s infinite", verticalAlign: "middle"
            }}/>
            R24 Response · Operator Platform Architecture
          </p>
          <h2 className="section-h2 section-h2--modules">
            <span className="section-h2__count section-h2__count--red">10 Core</span> integrated modules.
            <br/>
            <span className="section-h2__lede">Every SLA proved. Every shift defended.</span>
          </h2>
          <p className="section-sub">
            Built for the operators running 24/7 response — security firms, GSOCs, and critical-infrastructure NOCs. Adopt the modules you need, expand as the operation grows. Native API connection back to R24 PULSE.
          </p>
        </div>

        {/* Interactive demo console — auto-fits any screen */}
        <window.FitScaler designWidth={1320} className="console-fit">
        <div className="console-wrap console-wrap--red" style={{ width: "100%", margin: "0 0 24px" }}>
          <aside className="rail rail--red">
            <div className="rail__head">
              <p className="rail__title">Live demo</p>
              <p className="rail__sub">10 integrated modules</p>
            </div>
            <ul className="rail__list">
              {RESPONSE_MODULES.map((m) => (
                <li
                  key={m.id}
                  className={`module module--red ${active === m.id ? "module--active" : ""}`}
                  onClick={() => setActive(m.id)}
                  onDoubleClick={() => openDeepDive(m.id)}
                  title="Click to preview · double-click to open deep-dive"
                >
                  <span className="module__num">{m.num}</span>
                  <span className="module__name" dangerouslySetInnerHTML={{ __html: m.name }}/>
                  <span className="module__tag">{m.tag}</span>
                </li>
              ))}
            </ul>
            <div className="rail__footer">
              <span className="live live--red">LIVE · NOC-01</span>
              <span className="tabular">{time} UTC</span>
            </div>
          </aside>

          <section className="canvas">
            <div className="canvas__bar">
              <div className="canvas__bar-left">
                <span className="crumb">
                  <span className="crumb__id crumb__id--red">MODULE · {current.num}</span>
                  <span className="crumb__title" dangerouslySetInnerHTML={{ __html: current.name }}/>
                </span>
              </div>
              <div className="canvas__bar-right">
                <span><span className="dot dot--red"/>5 SHIFTS</span>
                <span><span className="dot dot--amber"/>12 SITES</span>
                <span><span className="dot dot--green"/>98.4% SLA</span>
                <span style={{ paddingLeft: 14, borderLeft: "1px solid var(--gray-200)" }} className="tabular">{time}</span>
              </div>
            </div>
            <div className="canvas__body canvas__body--resp">
              {RESPONSE_MODULES.map((m) => (
                <div key={m.id} className={`canvas__view ${active === m.id ? "canvas__view--active" : ""}`}>
                  {active === m.id ? (
                    <ResponseModuleMock m={m} detail={RESPONSE_DETAILS[m.id]}/>
                  ) : null}
                </div>
              ))}
            </div>
            <div className="canvas__cta-row">
              <a href="#contact" className="canvas__cta-primary canvas__cta-primary--red">
                <SIcon d={"M8 2v4M16 2v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"} size={14} stroke={2}/>
                Book an Operator demo
              </a>
              <button className="canvas__cta-link canvas__cta-link--red" onClick={() => openDeepDive(active)}>
                Open the {current.num} deep-dive
                <SIcon d={"M5 12h14M12 5l7 7-7 7"} size={13} stroke={2.2}/>
              </button>
            </div>
          </section>
        </div>
        </window.FitScaler>

        <p className="console-hint">
          ↑ Click any module to preview · double-click to jump to its deep-dive
        </p>

        {/* Section break heading */}
        <div className="section-header" style={{ marginTop: 40 }}>
          <p className="eyebrow eyebrow--red">Deep dive</p>
          <h2 className="section-h2">Each module, in detail.</h2>
          <p className="section-sub">
            What each module actually does, how it integrates, and the metric that proves it works.
          </p>
        </div>

        {/* Deep-dive blocks */}
        <div className="deep-dives deep-dives--red">
          {RESPONSE_MODULES.map((m) => {
            const detail = RESPONSE_DETAILS[m.id];
            return (
              <details key={m.id} className="deep-dive deep-dive--red" id={`response-module-${m.id}`}>
                <summary className="deep-dive__summary">
                  <div className="deep-dive__num">{m.num}</div>
                  <div className="deep-dive__sum-body">
                    <div className="deep-dive__head">
                      <span className="pill pill--coral">{m.tag}</span>
                      <h3 className="deep-dive__name" dangerouslySetInnerHTML={{ __html: m.name }}/>
                    </div>
                    <p className="deep-dive__tagline">{detail.tagline}</p>
                  </div>
                  <div className="deep-dive__metric">
                    <div className="deep-dive__metric-val" dangerouslySetInnerHTML={{ __html: detail.metric }}/>
                    <div className="deep-dive__metric-lab">{detail.metricLabel}</div>
                  </div>
                  <svg className="deep-dive__chev" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                    <polyline points="6 9 12 15 18 9"/>
                  </svg>
                </summary>
                <div className="deep-dive__body">
                  <ul className="deep-dive__bullets">
                    {detail.bullets.map((b, i) => (
                      <li key={i}>
                        <span className="deep-dive__check"><SIcon d={"M20 6 9 17l-5-5"} size={12} stroke={2.5}/></span>
                        <span>{b}</span>
                      </li>
                    ))}
                  </ul>
                  <div className="deep-dive__use-case">
                    <div className="deep-dive__use-case-label">In production</div>
                    <p>{detail.useCase}</p>
                  </div>
                  <div className="deep-dive__footer">
                    <div className="deep-dive__integrates">
                      <span className="deep-dive__integrates-label">Integrates with</span>
                      {detail.integrates.map((x, i) => (
                        <span key={i} className="deep-dive__chip">{x}</span>
                      ))}
                    </div>
                    <a href="#contact" className="deep-dive__cta deep-dive__cta--red">See module → </a>
                  </div>
                </div>
              </details>
            );
          })}
        </div>
      </div>
    </section>
  );
}

function ProductSections() { return <ResponseModulesSection/>; }
window.ProductSections = ProductSections;
window.ResponseModulesSection = ResponseModulesSection;
window.RESPONSE_MODULES = RESPONSE_MODULES;
window.RESPONSE_DETAILS = RESPONSE_DETAILS;
