/* ── The Method · Deep-dive sections: VISDI · The Ledger · CLV ──
   Content sourced from Minerva_VISDI_Ledger_CLV_Explained.pptx.
   Consumes shared globals: Eyebrow, Icon. Exposes window.MethodDeepDive. */

const VISDI_SKY = "#3FB1E5";
const LEDGER_GREEN = "#069348";
const CLV_GOLD = "#8E86C8";

/* ---------- small shared building blocks ---------- */

function DDHead({ eyebrow, accent, title, lead, mb = 52, leadMaxWidth = 680 }) {
  return (
    <div data-animate style={{ maxWidth: 720, marginBottom: mb }}>
      <Eyebrow color={accent}>{eyebrow}</Eyebrow>
      <h2 style={{ fontSize: 44, fontWeight: 700, lineHeight: 1.08, letterSpacing: "-0.025em",
        fontFamily: "var(--baroque-display)", margin: "20px 0 0", color: "#fff" }}>{title}</h2>
      {lead && <p style={{ fontSize: 19, lineHeight: 1.6, color: "#C8DAEC", margin: "20px 0 0", maxWidth: leadMaxWidth }}>{lead}</p>}
    </div>);

}

function SubHead({ accent, kicker, children, noRule, center }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 14, margin: "8px 0 22px",
      justifyContent: center ? "center" : "flex-start" }}>
      <span style={{ width: 9, height: 9, borderRadius: "50%", background: accent, flexShrink: 0 }} />
      <h3 style={{ fontSize: 14, fontWeight: 700, letterSpacing: "0.14em", textTransform: "uppercase",
        color: accent, fontFamily: "var(--wix-text)", margin: 0 }}>{kicker}</h3>
      {!noRule && <span style={{ flex: 1, height: 1, background: "rgba(255,255,255,0.10)" }} />}
      {children}
    </div>);

}

/* a small feature card: icon + title + description */
function FeatureCard({ icon, accent, title, desc, tall }) {
  return (
    <div style={{ background: "rgba(255,255,255,0.035)", border: "1px solid rgba(255,255,255,0.09)",
      borderRadius: "var(--radius-lg)", padding: "24px 24px", display: "flex", flexDirection: "column", gap: 13,
      height: "100%" }}>
      <div style={{ width: 46, height: 46, borderRadius: 13, flexShrink: 0,
        background: `${accent}18`, border: `1px solid ${accent}38`,
        display: "flex", alignItems: "center", justifyContent: "center" }}>
        <Icon name={icon} size={24} color={accent} strokeWidth={1.8} />
      </div>
      <h4 style={{ fontSize: 18, fontWeight: 700, color: "#EEF4FC", fontFamily: "var(--wix-display)",
        margin: 0, letterSpacing: "-0.01em" }}>{title}</h4>
      <p style={{ fontSize: 15, lineHeight: 1.58, color: "#B9CDDF", margin: 0 }}>{desc}</p>
    </div>);

}

/* Expandable pillar card - collapsed shows icon + title (+ optional subtitle);
   the chevron button expands to reveal the body copy and optional deliverables. */
function PillarCard({ icon, title, tag, body, deliver, accent = VISDI_SKY, titleSize = 25, image, titleNoWrap }) {
  const [open, setOpen] = React.useState(false);
  const innerRef = React.useRef(null);
  const [h, setH] = React.useState(0);
  const toggle = () => {
    if (innerRef.current) setH(innerRef.current.scrollHeight);
    setOpen((o) => !o);
  };
  return (
    <div style={{ background: `${accent}0C`, border: `1px solid ${accent}30`,
      borderRadius: "var(--radius-lg)", overflow: "hidden" }}>
      <button type="button" onClick={toggle} aria-expanded={open}
      style={{ display: "block", width: "100%", textAlign: "left", margin: 0, padding: "30px 30px",
        background: "transparent", border: "none", cursor: "pointer", color: "inherit",
        appearance: "none", WebkitAppearance: "none" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
          <div style={{ width: 54, height: 54, borderRadius: 14, flexShrink: 0,
            background: `${accent}1C`, border: `1px solid ${accent}40`,
            display: "flex", alignItems: "center", justifyContent: "center" }}>
            <Icon name={icon} size={28} color={accent} strokeWidth={1.8} />
          </div>
          <h3 style={{ flex: titleNoWrap ? "0 0 auto" : 1, minWidth: 0, overflow: "hidden", whiteSpace: titleNoWrap ? "nowrap" : "normal", overflowWrap: "anywhere", fontSize: titleSize, fontWeight: 800, color: "#fff", fontFamily: "var(--wix-display)",
            letterSpacing: "-0.02em", margin: 0 }}>{title}</h3>
          <span aria-hidden="true" style={{ flexShrink: 0, marginLeft: titleNoWrap ? 4 : "auto", width: 40, height: 40, borderRadius: "50%",
            background: `${accent}1C`, border: `1px solid ${accent}3A`,
            display: "flex", alignItems: "center", justifyContent: "center",
            rotate: open ? "180deg" : "0deg",
            transition: "rotate 320ms cubic-bezier(0.2,0.8,0.2,1)" }}>
            <Icon name="chevron-down" size={22} color={accent} strokeWidth={2.2} />
          </span>
        </div>
        {tag && <p style={{ fontSize: 17, fontWeight: 700, color: accent, lineHeight: 1.45, margin: "16px 0 0",
          fontFamily: "var(--wix-display)" }}>{tag}</p>}
        {image && <img src={window.__asset(image)} alt="" style={{ width: "100%", height: "auto", display: "block",
          marginTop: 20, pointerEvents: "none", userSelect: "none" }} />}
      </button>
      <div style={{ overflow: "hidden", maxHeight: open ? h : 0,
        transition: "max-height 360ms cubic-bezier(0.2,0.8,0.2,1)" }}>
        <div ref={innerRef} style={{ padding: "0 30px 30px" }}>
          <p style={{ fontSize: 16, lineHeight: 1.62, color: "#C8DAEC", margin: deliver ? "4px 0 18px" : "4px 0 0" }}>{body}</p>
          {deliver &&
          <div style={{ paddingTop: 16, borderTop: `1px solid ${accent}24` }}>
            <span style={{ fontSize: 12, fontWeight: 700, letterSpacing: "0.12em", textTransform: "uppercase",
              color: "#7FA8C4", fontFamily: "var(--wix-text)" }}>Deliverables</span>
            <p style={{ fontSize: 15, color: "#AEC6DA", margin: "6px 0 0", lineHeight: 1.55 }}>{deliver}</p>
          </div>}
        </div>
      </div>
    </div>);

}

/* Build an explicit grid track list ("208px 208px 208px") rather than the
   repeat(N, …) shorthand — responsive.css has a generic [style*="...repeat(4"]
   safety-net rule that would otherwise override our fixed square tracks. */
function squareTracks(size, fallback) {
  if (!size) return fallback;
  return Array(size.cols).fill(`${size.w}px`).join(" ");
}

/* detect hover-capable (desktop) vs touch (mobile): desktop reveals body on
   hover/focus, touch expands it on tap */
function useCanHover() {
  const [canHover, setCanHover] = React.useState(true);
  React.useEffect(() => {
    if (!window.matchMedia) return;
    const mq = window.matchMedia("(hover: hover) and (pointer: fine)");
    const update = () => setCanHover(mq.matches);
    update();
    mq.addEventListener ? mq.addEventListener("change", update) : mq.addListener(update);
    return () => {mq.removeEventListener ? mq.removeEventListener("change", update) : mq.removeListener(update);};
  }, []);
  return canHover;
}

/* equalize heights of matching elements inside a container, re-running on resize
   — keeps the two collapsed pillar headers the same size even when one subtitle
   wraps to an extra line at narrow widths */
function useEqualHeights(ref, selector) {
  React.useLayoutEffect(() => {
    const root = ref.current;
    if (!root) return;
    const apply = () => {
      const els = [...root.querySelectorAll(selector)];
      if (els.length < 2) return;
      els.forEach((el) => {el.style.minHeight = "";});
      let max = 0;
      els.forEach((el) => {max = Math.max(max, el.offsetHeight);});
      els.forEach((el) => {el.style.minHeight = max + "px";});
    };
    apply();
    const timers = [120, 400, 900].map((ms) => setTimeout(apply, ms));
    window.addEventListener("resize", apply);
    if (document.fonts && document.fonts.ready) document.fonts.ready.then(apply);
    const imgs = [...root.querySelectorAll("img")];
    imgs.forEach((im) => {if (!im.complete) im.addEventListener("load", apply);});
    return () => {window.removeEventListener("resize", apply);timers.forEach(clearTimeout);imgs.forEach((im) => im.removeEventListener("load", apply));};
  }, []);
}

/* Find the smallest SQUARE side that fully contains the tallest card's *expanded*
   content, then lock every card to that fixed size. The box is therefore big enough
   that revealing the body never resizes it, yet as small as possible so there's
   minimal empty space once the text is showing. Re-runs on resize / font / image load.
   Returns the side in px (null until first measure → cards fall back to aspect-ratio).
   colOptions: candidate column counts, largest first; picks the largest whose square
   would be a sensible width, else the smallest (which then drops to a single column). */
function useSnugSquare(ref, colOptions = [2, 1]) {
  const [size, setSize] = React.useState(null);
  React.useLayoutEffect(() => {
    const root = ref.current;
    if (!root) return;
    const measureAt = (w) => {
      const cards = [...root.querySelectorAll("button")];
      let max = 0;
      cards.forEach((c) => {
        const gw = c.querySelector(".oc-reveal");
        const img = c.querySelector(".oc-img");
        const sv = { w: c.style.width, mw: c.style.maxWidth, h: c.style.height,
          ar: c.style.aspectRatio, jc: c.style.justifyContent, rows: gw.style.gridTemplateRows,
          imgD: img && img.style.display };
        c.style.aspectRatio = "auto";
        c.style.height = "auto";
        c.style.width = w + "px";
        c.style.maxWidth = w + "px";
        c.style.justifyContent = "flex-start";
        // closed state: image shown, reveal collapsed
        gw.style.gridTemplateRows = "0fr";
        if (img) img.style.display = "";
        const closedH = c.scrollHeight;
        // open state: image hidden, reveal expanded (text replaces image)
        gw.style.gridTemplateRows = "1fr";
        if (img) img.style.display = "none";
        const openH = c.scrollHeight;
        max = Math.max(max, closedH, openH);
        c.style.width = sv.w;c.style.maxWidth = sv.mw;c.style.height = sv.h;
        c.style.aspectRatio = sv.ar;c.style.justifyContent = sv.jc;gw.style.gridTemplateRows = sv.rows;
        if (img) img.style.display = sv.imgD || "";
      });
      return max;
    };
    const apply = () => {
      // available width is the COLUMN's width (parent), not the grid's own shrink-to-fit
      // width — using the grid itself would feed its locked track size back in.
      const avail = (root.parentElement || root).clientWidth;
      const gap = 14;
      // pick the largest candidate column count whose per-column width is still sensible
      let cols = colOptions[colOptions.length - 1];
      let perCol = Math.floor((avail - gap * (cols - 1)) / cols);
      for (const opt of colOptions) {
        const pc = Math.floor((avail - gap * (opt - 1)) / opt);
        if (pc >= 168) {cols = opt;perCol = pc;break;}
      }
      const cap = Math.max(160, Math.min(300, perCol));
      // smallest square side S in [160, cap] whose width holds the expanded content within S
      let chosen = null;
      for (let s = 160; s <= cap; s += 6) {
        if (measureAt(s) <= s) {chosen = { w: s, h: s, cols };break;}
      }
      // no square fits within the column width → keep width at cap and grow height to
      // the content (snug portrait) so text never clips and the box still never resizes
      if (!chosen) {chosen = { w: cap, h: Math.ceil(measureAt(cap)), cols };}
      setSize((prev) => prev && prev.w === chosen.w && prev.h === chosen.h && prev.cols === chosen.cols ? prev : chosen);
    };
    apply();
    const timers = [120, 400, 900].map((ms) => setTimeout(apply, ms));
    window.addEventListener("resize", apply);
    if (document.fonts && document.fonts.ready) document.fonts.ready.then(apply);
    return () => {window.removeEventListener("resize", apply);timers.forEach(clearTimeout);};
  }, []);
  return size;
}

/* Outcome card: collapsed shows icon + title only. Desktop reveals the body on
   hover/focus; touch toggles it on tap. */
function OutcomeCard({ icon, accent, title, desc, canHover, size, image, imageMaxH = 78, stacked }) {
  const [open, setOpen] = React.useState(false);
  const show = () => setOpen(true);
  const hide = () => setOpen(false);
  const toggle = () => setOpen((o) => !o);

  const interaction = canHover ?
  { onMouseEnter: show, onMouseLeave: hide, onFocus: show, onBlur: hide } :
  { onClick: toggle };

  return (
    <button type="button" aria-expanded={open} {...interaction}
    style={{ display: "flex", flexDirection: "column",
      justifyContent: open ? "flex-start" : "center",
      ...(stacked ? { width: "100%" } : size ? { width: size.w, height: size.h } : { aspectRatio: "1 / 1", width: "100%" }),
      textAlign: "left", margin: 0,
      background: open ? `${accent}14` : `${accent}0A`,
      border: `1px solid ${open ? accent + "4D" : accent + "2B"}`,
      borderRadius: "var(--radius-lg)", padding: "18px", cursor: "pointer",
      color: "inherit", appearance: "none", WebkitAppearance: "none", position: "relative" }}>
      {image ?
      <React.Fragment>
        <span aria-hidden="true" style={{ position: "absolute", top: 14, right: 14, width: 28, height: 28, borderRadius: "50%",
          background: `${accent}1C`, border: `1px solid ${accent}3A`,
          display: "flex", alignItems: "center", justifyContent: "center",
          rotate: open ? "180deg" : "0deg", transition: "rotate 320ms cubic-bezier(0.2,0.8,0.2,1)" }}>
          <Icon name="chevron-down" size={16} color={accent} strokeWidth={2.2} />
        </span>
        <h4 style={{ fontSize: 16, fontWeight: 700, color: "#EEF4FC", textAlign: "center",
          fontFamily: "var(--wix-display)", margin: "0 22px", letterSpacing: "-0.01em", lineHeight: 1.25 }}>{title}</h4>
        <img className="oc-img" src={window.__asset(image)} alt="" style={{ width: "100%", maxHeight: imageMaxH, height: "auto",
          objectFit: "contain", display: open ? "none" : "block", margin: "12px auto 0", pointerEvents: "none" }} />
      </React.Fragment> :
      <div style={{ display: "flex", alignItems: "flex-start", gap: 11 }}>
        <div style={{ width: 40, height: 40, borderRadius: 11, flexShrink: 0,
          background: `${accent}18`, border: `1px solid ${accent}38`,
          display: "flex", alignItems: "center", justifyContent: "center" }}>
          <Icon name={icon} size={21} color={accent} strokeWidth={1.8} />
        </div>
        <h4 style={{ flex: "0 1 auto", minWidth: 0, fontSize: 16, fontWeight: 700, color: "#EEF4FC",
          fontFamily: "var(--wix-display)", margin: "8px 0 0", letterSpacing: "-0.01em", lineHeight: 1.25 }}>{title}</h4>
        <span aria-hidden="true" style={{ flexShrink: 0, marginLeft: stacked ? "auto" : 3, width: 28, height: 28, borderRadius: "50%",
          background: `${accent}1C`, border: `1px solid ${accent}3A`,
          display: "flex", alignItems: "center", justifyContent: "center",
          rotate: open ? "180deg" : "0deg",
          transition: "rotate 320ms cubic-bezier(0.2,0.8,0.2,1)" }}>
          <Icon name="chevron-down" size={16} color={accent} strokeWidth={2.2} />
        </span>
      </div>}
      {/* robust collapse: grid-template-rows 0fr->1fr needs no height measurement.
          No CSS transition here on purpose — the page's scroll-animation engine wedges
          CSS transitions on React-rendered nodes (documented quirk), so the reveal is
          instant and 100% reliable rather than stuck at frame 0. */}
      <div className="oc-reveal" style={{ display: "grid", gridTemplateRows: open ? "1fr" : "0fr" }}>
        <div style={{ overflow: "hidden", minHeight: 0 }}>
          <p style={{ fontSize: 14, lineHeight: 1.55, color: "#B9CDDF", margin: 0, paddingTop: 12,
            textAlign: image ? "center" : "left" }}>{desc}</p>
        </div>
      </div>
    </button>);

}

/* ================= SECTION 1 · VISDI ================= */

function VisdiDeepDive() {
  const canHover = useCanHover();
  const pillarsRef = React.useRef(null);
  useEqualHeights(pillarsRef, "button");
  const outcomesRef = React.useRef(null);
  const sqSize = useSnugSquare(outcomesRef);
  const visCaps = [
  { icon: "git-merge", title: "Process Maps", desc: "UML-standard flow diagrams integrating intuitive structure, custom visuals, and pre-defined language for any process, system, or workflow." },
  { icon: "eye", title: "Technical Illustrations", desc: "Accurate scientific visuals depicting biological and physical processes, components, and conditions - fast to produce and easy to update." },
  { icon: "package", title: "3D Visualizations", desc: "Isometric and dynamic 3D representations of physical, chemical, and biological systems - from cellular interactions to facility-level flows." },
  { icon: "network", title: "Visuals for ML & AI", desc: "Labeled visual datasets designed for immediate human comprehension and direct use in machine learning and AI model training." },
  { icon: "layout-grid", title: "Infographics", desc: "Combinations of text, graphics, and images that communicate complex relationships in an engaging, understandable format for any audience." },
  { icon: "activity", title: "KPI Dashboards", desc: "Continuously updated visual dashboards that surface operational and quality performance data - structured to support the right decisions at the right time." }];

  const digOutcomes = [
  { icon: "zap", title: "Turn data into actionable intelligence", image: "uploads/Pareto Chart.png", desc: "Structure and visualize complex operational data to accelerate investigations, identify risks earlier, and support faster compliant decisions." },
  { icon: "activity", title: "Accelerate innovation with analytics", image: "uploads/KPI.png", desc: "Apply ML and AI-assisted evaluation to identify patterns, improve process understanding, and strengthen decision-making with traceability." },
  { icon: "network", title: "Connect your operational ecosystem", image: "uploads/Operational ecosystem v3.png", imageMaxH: 132, desc: "Integrate MES, ERP, EBR, QMS, laboratory, and process systems into connected digital environments with improved visibility and execution." },
  { icon: "users", title: "Enable cross-functional execution", image: "uploads/Cross functional team v2.png", desc: "Create shared visual-digital environments that reduce ambiguity and align multidisciplinary teams around a common operational understanding." }];

  const digDeliverables = [
  ["Electronic Batch Records (EBR)", "Process knowledge structured for MES, ERP, and manufacturing environments."],
  ["Digital QMS", "Quality management systems digitalized using industry platforms and low-code solutions."],
  ["Custom Knowledge Databases", "Low-code and enterprise apps that centralize product, process, quality, and regulatory info."],
  ["Predictive Digital Models", "Computational simulations that reduce uncertainty before physical implementation."]];


  return (
    <section data-screen-label="Deep dive · VISDI" style={{ background: "#0B1828", padding: "96px 0" }}>
      <div style={{ maxWidth: 1280, margin: "0 auto", padding: "0 80px" }}>

        {/* Two pillars - expandable */}
        <div ref={pillarsRef} data-stagger style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 24, marginBottom: 64, alignItems: "start" }}>
          {[
          { icon: "eye", title: "Visualization", image: "uploads/Visualizations v4-82f99534.png",
            tag: "See, understand, and accelerate informed decision making.",
            body: "Minerva creates visual representations of complex physical and biological processes - helping researchers, engineers, quality, and regulatory teams quickly understand conditions, risks, and improvement opportunities.",
            deliver: "Process maps · technical illustrations · 3D models · infographics · KPI dashboards · Visuals for ML & AI." },
          { icon: "database", title: "Digitalization", image: "uploads/Digitalization.png",
            tag: "Transform fragmented operational data into trusted, executable knowledge.",
            body: "Minerva converts manufacturing, quality, technical, and operational data into structured visual-digital knowledge environments - connecting people, systems, and processes into governed digital environments that improve decisions and compliant execution.",
            deliver: "Digital QMS · EBR integration · Custom Databases · AI-ready data structures · Predictive Digital Models." }].
          map((p) => <PillarCard key={p.title} {...p} />)}
        </div>

        {/* Digitalization outcomes — centered header + body on top, four cards in a row below */}
        <div className="visdi-outcomes-row" style={{ display: "block" }}>
          <div style={{ textAlign: "center", maxWidth: 720, margin: "0 auto 40px" }}>
            <SubHead accent={VISDI_SKY} kicker="VISDI · what it does for you" noRule center />
            <p style={{ fontSize: 18, color: "#C8DAEC", lineHeight: 1.65, margin: "0 auto", maxWidth: 560 }}>
              Minerva connects people, systems, processes, and operational knowledge into governed digital environments.
            </p>
          </div>
          <div ref={outcomesRef} data-stagger className="visdi-cards" style={{ display: "grid", width: "100%", gridTemplateColumns: "repeat(4, minmax(0, 1fr))", gap: 14, alignItems: "start" }}>
            {digOutcomes.map((c) => <OutcomeCard key={c.title} accent={VISDI_SKY} canHover={canHover} {...c} />)}
          </div>
        </div>
      </div>
    </section>);

}

/* ================= SECTION 2 · THE LEDGER ================= */

function LedgerDeepDive() {
  const canHover = useCanHover();
  const rolesRef = React.useRef(null);
  const roleSize = useSnugSquare(rolesRef, [3, 1]);
  const jobs = [
  { icon: "scale", title: "Governance", desc: "Enforces who can create, verify, and approve at each risk level. Defines accountability at every gate." },
  { icon: "message-circle", title: "Communication", desc: "Provides the client-facing view of the knowledge layers- what exists, what changed, what was rejected and why." },
  { icon: "git-merge", title: "Traceability", desc: "Keeps the full history of every knowledge packet from the moment it passed the trust gate. Nothing is erased. Everything is linked." }];

  const roles = [
  { icon: "eye", title: "Observer", desc: "Present during the activity. Confirms the action happened as described. Used for lower-risk routine tasks." },
  { icon: "shield-check", title: "Verifier", desc: "Reviews the model's output and confirms it is accurate before the packet is accepted into the Ledger." },
  { icon: "badge", title: "Approver", desc: "Authorizes the packet for use. Signs off at the risk level required - regulatory submissions require the most senior approval." }];


  return (
    <section data-screen-label="Deep dive · The Ledger" style={{ background: "#0D1C30", padding: "96px 0" }}>
      <div style={{ maxWidth: 1280, margin: "0 auto", padding: "0 80px" }}>

        {/* Three jobs */}
        <div data-stagger className="jobs-grid" style={{ display: "grid", gap: 18, marginBottom: 72, alignItems: "start" }}>
          {jobs.map((c) => <PillarCard key={c.title} accent={LEDGER_GREEN} titleSize={20} titleNoWrap icon={c.icon} title={c.title} body={c.desc} />)}
        </div>

        {/* Governance structure — narrative left, role cards stacked right */}
        <div className="gov-roles-row" style={{ display: "grid",
          gridTemplateColumns: "minmax(0,0.9fr) minmax(0,1.1fr)", gap: 48, alignItems: "start" }}>
          <div>
            <SubHead accent={LEDGER_GREEN} kicker="Governance structure · accountability graded to risk" noRule />
            <p style={{ fontSize: 17, lineHeight: 1.7, color: "#C8DAEC", margin: "0 0 22px" }}>
              Not every action needs the same review. The Ledger grades each activity to its risk and routes it to the right validation layer. A generic log records events; the Ledger records events <em style={{ color: "#EAF4EE", fontStyle: "italic" }}>and</em> enforces who may approve them, and at what level of scrutiny.
            </p>
            <p style={{ fontSize: 16, lineHeight: 1.65, color: "#A7BDD2", margin: 0 }}>
              Result: the Ledger produces the validation evidence an auditor expects to find - not as a retrospective effort, but as a natural product of how work is done.
            </p>
          </div>
          <div>
            <p style={{ fontSize: 14, fontWeight: 700, letterSpacing: "0.14em", textTransform: "uppercase",
              color: LEDGER_GREEN, fontFamily: "var(--wix-text)", margin: "0 0 16px" }}>Human-in-command roles</p>
            <div ref={rolesRef} data-stagger className="role-cards" style={{ display: "grid", width: "100%", gridTemplateColumns: "1fr", gap: 12, alignItems: "start", minHeight: 340, alignContent: "start" }}>
              {roles.map((c) => <OutcomeCard key={c.title} accent={LEDGER_GREEN} canHover={canHover} stacked {...c} />)}
            </div>
          </div>
        </div>
      </div>
    </section>);

}

/* ================= SECTION 3 · CLV ================= */

/* Lifecycle phase card: collapsed shows phase number + title only; clicking the box
   expands it to reveal the lead line and bullet detail. Uses the grid-template-rows
   0fr→1fr reveal (no measurement, no CSS transition that the scroll-animation engine
   could wedge). */
function PhaseCard({ n, title, bullets, lead, accent }) {
  const [open, setOpen] = React.useState(false);
  const innerRef = React.useRef(null);
  const [h, setH] = React.useState(0);
  const toggle = () => {
    if (innerRef.current) setH(innerRef.current.scrollHeight);
    setOpen((o) => !o);
  };
  // Reveal lives OUTSIDE the button (sibling), same structure as PillarCard — this is
  // what lets the max-height transition animate smoothly here; nesting it inside the
  // button leaves the transition wedged by the page's scroll-animation engine.
  return (
    <div style={{ background: "rgba(255,255,255,0.035)", border: "1px solid rgba(255,255,255,0.09)",
      borderRadius: "var(--radius-lg)", borderTop: `3px solid ${accent}`, overflow: "hidden" }}>
      <button type="button" onClick={toggle} aria-expanded={open}
      style={{ display: "block", width: "100%", textAlign: "left", margin: 0, padding: "22px 18px",
        background: open ? "rgba(255,255,255,0.02)" : "transparent", border: "none", cursor: "pointer",
        color: "inherit", appearance: "none", WebkitAppearance: "none" }}>
        <div style={{ fontSize: 13, fontWeight: 900, color: accent, fontFamily: "var(--wix-text)",
          letterSpacing: "0.06em", marginBottom: 10 }}>{n}</div>
        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <h4 style={{ flex: 1, minWidth: 0, fontSize: 18, fontWeight: 800, color: "#EEF4FC",
            fontFamily: "var(--wix-display)", margin: 0, letterSpacing: "-0.01em" }}>{title}</h4>
          <span aria-hidden="true" style={{ flexShrink: 0, width: 26, height: 26, borderRadius: "50%",
            background: `${accent}1C`, border: `1px solid ${accent}3A`,
            display: "flex", alignItems: "center", justifyContent: "center",
            rotate: open ? "180deg" : "0deg", transition: "rotate 320ms cubic-bezier(0.2,0.8,0.2,1)" }}>
            <Icon name="chevron-down" size={15} color={accent} strokeWidth={2.2} />
          </span>
        </div>
      </button>
      <div style={{ overflow: "hidden", maxHeight: open ? h : 0,
        transition: "max-height 360ms cubic-bezier(0.2,0.8,0.2,1)" }}>
        <div ref={innerRef} style={{ padding: "0 18px 22px" }}>
          {lead && <p style={{ fontSize: 15, lineHeight: 1.55, color: "#AEC6DA", margin: "0 0 8px" }}>{lead}</p>}
          <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 7 }}>
            {bullets.map((b, bi) =>
            <li key={bi} style={{ display: "flex", gap: 8, alignItems: "flex-start",
              fontSize: 15, lineHeight: 1.55, color: "#AEC6DA" }}>
                <span style={{ flexShrink: 0, width: 5, height: 5, borderRadius: "50%", background: accent, marginTop: 7 }} />
                <span>{b}</span>
              </li>
            )}
          </ul>
        </div>
      </div>
    </div>);

}

/* Lifecycle loop diagram — the five ring boxes ARE the expandable phase cards:
   each carries a chevron and reveals its lead + bullets in place (accordion, one open
   at a time). The open box raises its z-index and overlays as a popover so the ring
   layout stays intact. This replaces the separate horizontal phase-card row. */
function RingPhaseBox({ p, open, onToggle, accent }) {
  const innerRef = React.useRef(null);
  const [h, setH] = React.useState(0);
  const handle = () => { if (innerRef.current) setH(innerRef.current.scrollHeight); onToggle(); };
  return (
    <div style={{ position: "absolute", left: p.x + "%", top: p.y + "%",
      transform: "translate(-50%,-50%)", boxSizing: "border-box",
      width: open ? 250 : "20cqw", minHeight: open ? 0 : "8cqw",
      background: "#14233F", border: `1px solid ${open ? accent + "99" : "rgba(142,134,200,0.36)"}`,
      borderRadius: open ? 14 : "1.5cqw", zIndex: open ? 30 : 2,
      boxShadow: open ? "0 18px 50px rgba(0,0,0,0.55)" : "none",
      transition: "box-shadow .3s, border-color .3s" }}>
      <button type="button" onClick={handle} aria-expanded={open}
        style={{ position: "relative", width: "100%", background: "none", border: "none",
          cursor: "pointer", color: "inherit", padding: open ? "14px 16px 0" : "1.8cqw",
          display: "block", textAlign: "center" }}>
        <div style={{ fontFamily: "var(--baroque-display)", fontWeight: 700, color: "#B3ACDD",
          fontSize: open ? 20 : "3.1cqw", lineHeight: 1.1, marginBottom: open ? 3 : "0.7cqw" }}>{p.label}</div>
        <div style={{ fontFamily: "var(--wix-text)", color: "#C4D8EE",
          fontSize: open ? 12.5 : "1.85cqw", lineHeight: 1.3 }}>{p.sub}</div>
        <span aria-hidden="true" style={{ position: "absolute", top: open ? 12 : "1.3cqw", right: open ? 12 : "1.3cqw",
          width: open ? 24 : "3.2cqw", height: open ? 24 : "3.2cqw", borderRadius: "50%",
          background: `${accent}1C`, border: `1px solid ${accent}3A`,
          display: "flex", alignItems: "center", justifyContent: "center",
          rotate: open ? "180deg" : "0deg", transition: "rotate 320ms cubic-bezier(0.2,0.8,0.2,1)" }}>
          <Icon name="chevron-down" size={open ? 15 : 11} color={accent} strokeWidth={2.2} />
        </span>
      </button>
      <div style={{ overflow: "hidden", maxHeight: open ? h : 0,
        transition: "max-height 360ms cubic-bezier(0.2,0.8,0.2,1)" }}>
        <div ref={innerRef} style={{ padding: "12px 16px 16px", textAlign: "left" }}>
          {p.lead && <p style={{ fontSize: 13, lineHeight: 1.5, color: "#AEC6DA", margin: "0 0 8px" }}>{p.lead}</p>}
          <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 6 }}>
            {p.bullets.map((b, bi) =>
            <li key={bi} style={{ display: "flex", gap: 8, alignItems: "flex-start",
              fontSize: 13, lineHeight: 1.5, color: "#AEC6DA" }}>
                <span style={{ flexShrink: 0, width: 5, height: 5, borderRadius: "50%", background: accent, marginTop: 6 }} />
                <span>{b}</span>
              </li>
            )}
          </ul>
        </div>
      </div>
    </div>);
}

function SeqPhaseBox({ p, n, accent, open, onToggle }) {
  const innerRef = React.useRef(null);
  const [h, setH] = React.useState(0);
  const handle = () => { if (innerRef.current) setH(innerRef.current.scrollHeight); onToggle(); };
  return (
    <div style={{ background: "#14233F", border: `1px solid ${open ? accent + "99" : "rgba(142,134,200,0.36)"}`,
      borderRadius: 14, alignSelf: "start", boxShadow: open ? "0 18px 50px rgba(0,0,0,0.45)" : "none",
      transition: "border-color .3s, box-shadow .3s" }}>
      <button type="button" onClick={handle} aria-expanded={open}
        style={{ width: "100%", background: "none", border: "none", cursor: "pointer", color: "inherit",
          padding: "18px 16px", display: "block", textAlign: "center" }}>
        <div style={{ fontFamily: "var(--wix-text)", fontWeight: 700, color: accent, fontSize: 13,
          letterSpacing: "0.12em" }}>{String(n).padStart(2, "0")}</div>
        <div style={{ fontFamily: "var(--baroque-display)", fontWeight: 700, color: "#B3ACDD",
          fontSize: 21, lineHeight: 1.1, margin: "6px 0 4px" }}>{p.label}</div>
        <div style={{ fontFamily: "var(--wix-text)", color: "#C4D8EE", fontSize: 13, lineHeight: 1.3, minHeight: "2.6em", display: "flex", alignItems: "center", justifyContent: "center" }}>{p.sub}</div>
        <span aria-hidden="true" style={{ display: "inline-flex", marginTop: 10, width: 24, height: 24, borderRadius: "50%",
          background: `${accent}1C`, border: `1px solid ${accent}3A`, alignItems: "center", justifyContent: "center",
          rotate: open ? "180deg" : "0deg", transition: "rotate 320ms cubic-bezier(0.2,0.8,0.2,1)" }}>
          <Icon name="chevron-down" size={14} color={accent} strokeWidth={2.2} />
        </span>
      </button>
      <div style={{ overflow: "hidden", maxHeight: open ? h : 0, transition: "max-height 360ms cubic-bezier(0.2,0.8,0.2,1)" }}>
        <div ref={innerRef} style={{ padding: "4px 16px 16px", textAlign: "left" }}>
          {p.lead && <p style={{ fontSize: 13, lineHeight: 1.5, color: "#AEC6DA", margin: "0 0 8px" }}>{p.lead}</p>}
          <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 6 }}>
            {p.bullets.map((b, bi) =>
            <li key={bi} style={{ display: "flex", gap: 8, alignItems: "flex-start", fontSize: 13, lineHeight: 1.5, color: "#AEC6DA" }}>
              <span style={{ flexShrink: 0, width: 5, height: 5, borderRadius: "50%", background: accent, marginTop: 6 }} />
              <span>{b}</span>
            </li>
            )}
          </ul>
        </div>
      </div>
    </div>);
}

function LifecycleLoop() {
  const [openIdx, setOpenIdx] = React.useState(-1);
  // box centers as % of container W/H (ring around the centered panel)
  // five boxes spaced evenly (72° apart) on one circle, so the connecting
  // arrows can be true arcs of that same circle. Each box also carries the
  // phase detail (lead + bullets) revealed on chevron toggle.
  const phases = [
  { label: "Define", sub: "Visualize + Structure", x: 50, y: 10.7,
    lead: "Map the context layer:",
    bullets: ["What components are needed (skills, tools, documents, MD files).", "Define what each should do.", "What language standards apply."] },
  { label: "Lock", sub: "Verify \u00b7 Trust Gate", x: 76.2, y: 37.9,
    bullets: ["Version and approve every artifact.", "Assign each component a locked state.", "Production may only use locked, approved context - no ad-hoc changes."] },
  { label: "Apply", sub: "Digitalize + Execute", x: 66.2, y: 81.8,
    bullets: ["The live system runs on locked context only.", "Every interaction is traceable to a specific version of every context component in use."] },
  { label: "Monitor", sub: "Automatic flagging", x: 33.8, y: 81.8,
    bullets: ["Continuously watch for drift, ambiguity, and stale content.", "Any context that no longer matches the process it describes triggers a versioned update."] },
  { label: "Review", sub: "Feed back · Learning Gate", x: 23.9, y: 37.9,
    bullets: ["Formal review loops back to Define.", "New process knowledge, new risk findings, or model behavior changes can all trigger a new cycle."] }];

  // Cycle arrows are arcs of ONE circle (center 500,350, radius R) in a
  // 1000×700 space. Each arc runs between two boxes with a wide angular gap at
  // each box (±27°) so both endpoints — including the arrowhead — sit clear of
  // the boxes (boxes are centered on the circle and extend past R at the corners).
  return (
    <div style={{ width: "100%", maxWidth: 980, margin: "0 auto 64px" }}>
      {/* sequential row: Define → Lock → Apply → Monitor → Review */}
      <div className="clv-seq" style={{ display: "flex", alignItems: "flex-start", gap: 8, flexWrap: "wrap" }}>
        {phases.map((p, i) =>
        <React.Fragment key={p.label}>
          <div style={{ flex: "1 1 150px", minWidth: 140 }}>
            <SeqPhaseBox p={p} n={i + 1} accent="#8E86C8"
              open={openIdx === i} onToggle={() => setOpenIdx(openIdx === i ? -1 : i)} />
          </div>
          {i < phases.length - 1 &&
          <div aria-hidden="true" style={{ flex: "0 0 auto", alignSelf: "flex-start", marginTop: 40 }}>
            <Icon name="chevron-right" size={22} color="#8E86C8" strokeWidth={2.2} />
          </div>}
        </React.Fragment>
        )}
      </div>

      {/* dashed loop-back: Review feeds back to Define */}
      <div aria-hidden="true" style={{ position: "relative", height: 48, margin: "12px 0 0" }}>
        <div style={{ position: "absolute", right: "9%", top: 0, height: 22, borderRight: "2px dashed rgba(142,134,200,0.6)" }} />
        <div style={{ position: "absolute", left: "9%", right: "9%", top: 22, borderTop: "2px dashed rgba(142,134,200,0.6)" }} />
        <div style={{ position: "absolute", left: "9%", top: 0, height: 22, borderLeft: "2px dashed rgba(142,134,200,0.6)" }} />
        <div style={{ position: "absolute", left: "9%", top: -7, transform: "translateX(-6px)", width: 0, height: 0,
          borderLeft: "6px solid transparent", borderRight: "6px solid transparent", borderBottom: "9px solid #8E86C8" }} />
        <div style={{ position: "absolute", left: "50%", top: 22, transform: "translate(-50%,-50%)", background: "#0B1828", padding: "0 16px" }}>
          <span style={{ fontSize: 13, fontWeight: 600, color: "#C8DAEC", whiteSpace: "nowrap" }}>Review feeds back to Define. One continuous loop.</span>
        </div>
      </div>

      {/* maintained-state descriptor */}
      <div style={{ marginTop: 26, textAlign: "center", background: "#142136", border: "1px solid #6E66A8",
        borderRadius: 14, padding: "22px 24px", maxWidth: 680, marginInline: "auto" }}>
        <div style={{ fontFamily: "var(--wix-text)", fontWeight: 700, color: "#B3ACDD", fontSize: 14,
          letterSpacing: "0.13em", textTransform: "uppercase" }}>Maintained state{" "}
          <span style={{ fontStyle: "italic", fontWeight: 400, color: "#9DB2C6", textTransform: "none", letterSpacing: 0 }}>(draft candidates)</span>
        </div>
        <div style={{ fontFamily: "var(--baroque-display)", fontWeight: 700, color: "#E9F1FB", fontSize: 19, marginTop: 8 }}>
          Current · Complete · Relevant · Traceable · Consistent
        </div>
      </div>
    </div>);

}

function CsvClvTable({ compare, accent }) {
  const [open, setOpen] = React.useState(false);
  const innerRef = React.useRef(null);
  const [h, setH] = React.useState(0);
  const toggle = () => { if (innerRef.current) setH(innerRef.current.scrollHeight); setOpen(o => !o); };
  return (
    <div>
      <button type="button" onClick={toggle} aria-expanded={open}
        style={{ width: "100%", background: "none", border: "none", cursor: "pointer", color: "inherit",
          display: "flex", alignItems: "center", justifyContent: "center", gap: 14,
          padding: "4px 0 18px", textAlign: "center" }}>
        <span style={{ fontSize: 13, fontWeight: 700, letterSpacing: "0.16em", textTransform: "uppercase",
          color: accent, fontFamily: "var(--wix-text)" }}>CSV vs CLV · the key differences</span>
        <span aria-hidden="true" style={{ flexShrink: 0, width: 32, height: 32, borderRadius: "50%",
          background: `${accent}1C`, border: `1px solid ${accent}3A`,
          display: "flex", alignItems: "center", justifyContent: "center",
          rotate: open ? "180deg" : "0deg", transition: "rotate 320ms cubic-bezier(0.2,0.8,0.2,1)" }}>
          <Icon name="chevron-down" size={18} color={accent} strokeWidth={2.2} />
        </span>
      </button>
      <div style={{ overflow: "hidden", maxHeight: open ? h : 0,
        transition: "max-height 400ms cubic-bezier(0.2,0.8,0.2,1)" }}>
        <div ref={innerRef} style={{ border: "1px solid rgba(255,255,255,0.10)", borderRadius: "var(--radius-lg)",
          overflow: "hidden" }}>
          <div style={{ display: "grid", gridTemplateColumns: "1.1fr 1fr 1.2fr",
            background: "rgba(255,255,255,0.04)", borderBottom: "1px solid rgba(255,255,255,0.10)" }}>
            <div style={{ padding: "16px 22px", fontSize: 13, fontWeight: 700, letterSpacing: "0.12em",
              textTransform: "uppercase", color: "#8FA6BC", fontFamily: "var(--wix-text)" }}>Dimension</div>
            <div style={{ padding: "16px 22px", fontSize: 13, fontWeight: 700, letterSpacing: "0.12em",
              textTransform: "uppercase", color: "#8FA6BC", fontFamily: "var(--wix-text)" }}>CSV</div>
            <div style={{ padding: "16px 22px", fontSize: 13, fontWeight: 700, letterSpacing: "0.12em",
              textTransform: "uppercase", color: accent, fontFamily: "var(--wix-text)" }}>CLV</div>
          </div>
          {compare.map(([dim, csv, clv], i) =>
          <div key={dim} style={{ display: "grid", gridTemplateColumns: "1.1fr 1fr 1.2fr",
            borderBottom: i < compare.length - 1 ? "1px solid rgba(255,255,255,0.06)" : "none",
            background: i % 2 ? "rgba(255,255,255,0.012)" : "transparent" }}>
              <div style={{ padding: "16px 22px", fontSize: 15, fontWeight: 700, color: "#E2ECF6",
              fontFamily: "var(--wix-display)" }}>{dim}</div>
              <div style={{ padding: "16px 22px", fontSize: 15, color: "#A7BDD2", lineHeight: 1.5 }}>{csv}</div>
              <div style={{ padding: "16px 22px", fontSize: 15, color: "#CFC9EC", lineHeight: 1.5,
              background: `${accent}08` }}>{clv}</div>
            </div>
          )}
        </div>
      </div>
    </div>);

}

function ClvIntroReveal({ accent, children }) {
  const [open, setOpen] = React.useState(false);
  const innerRef = React.useRef(null);
  const [h, setH] = React.useState(0);
  const toggle = () => { if (innerRef.current) setH(innerRef.current.scrollHeight); setOpen(o => !o); };
  return (
    <div style={{ marginBottom: 56 }}>
      <button type="button" onClick={toggle} aria-expanded={open}
        style={{ display: "flex", alignItems: "center", gap: 12, background: "none", border: "none",
          cursor: "pointer", color: "inherit", padding: "0 0 4px" }}>
        <span aria-hidden="true" style={{ flexShrink: 0, width: 40, height: 40, borderRadius: "50%",
          background: `${accent}1C`, border: `1px solid ${accent}3A`, display: "flex", alignItems: "center", justifyContent: "center",
          rotate: open ? "180deg" : "0deg", transition: "rotate 320ms cubic-bezier(0.2,0.8,0.2,1)" }}>
          <Icon name="chevron-down" size={20} color={accent} strokeWidth={2.2} />
        </span>
        <span style={{ fontSize: 14, fontWeight: 700, letterSpacing: "0.06em", color: accent, fontFamily: "var(--wix-text)" }}>{open ? "Hide" : "What CLV governs"}</span>
      </button>
      <div style={{ overflow: "hidden", maxHeight: open ? h : 0, transition: "max-height 400ms cubic-bezier(0.2,0.8,0.2,1)" }}>
        <div ref={innerRef} style={{ paddingTop: 24 }}>{children}</div>
      </div>
    </div>);
}

function ClvDeepDive() {
  const canHover = useCanHover();
  const ctxRef = React.useRef(null);
  const ctxSize = useSnugSquare(ctxRef, [4, 2, 1]);
  const compare = [
  ["What it validates", "The software system", "The context layer (inputs, language, packets)"],
  ["End state", "Frozen validated state", "Continuously maintained validated state"],
  ["Duration", "One-time + periodic review", "Never ends - continuous learning cycle"],
  ["Trigger for change", "System change control", "Any context update - versioned automatically"],
  ["Output", "Validation dossier", "Full audit trail of context evolution"]];

  const lifecycle = [
  ["01", "Define", ["What components are needed (skills, tools, documents, MD files).", "Define what each should do.", "What language standards apply."], "Map the context layer:"],
  ["02", "Lock", ["Version and approve every artifact.", "Assign each component a locked state.", "Production may only use locked, approved context - no ad-hoc changes."]],
  ["03", "Deploy", ["The live system runs on locked context only.", "Every interaction is traceable to a specific version of every context component in use."]],
  ["04", "Monitor", ["Continuously watch for drift, ambiguity, and stale content.", "Any context that no longer matches the process it describes triggers a versioned update."]],
  ["05", "Review", ["Formal review loops back to Define.", "New process knowledge, new risk findings, or model behavior changes can all trigger a new cycle."]]];

  const contextTypes = [
  { icon: "zap", title: "Skills & Tools", desc: "The instructions that govern how an AI agent behaves in a given task." },
  { icon: "book-open", title: "Documents & SOPs", desc: "Retrieved knowledge that grounds AI outputs in approved, current content." },
  { icon: "database", title: "MD / Context Files", desc: "The operational 'brain' files that describe projects, teams, and processes to the model." },
  { icon: "eye", title: "Visual language", desc: "The shape, structure, and terminology of images and pictorials within knowledge packets." }];


  return (
    <section data-screen-label="Deep dive · CLV" style={{ background: "#0B1828", padding: "96px 0" }}>
      <div style={{ maxWidth: 1280, margin: "0 auto", padding: "0 80px" }}>
        <DDHead
          eyebrow="CLV · What it is"
          accent={CLV_GOLD}
          title="Context Language Validation"
          lead="A governance framework coined by Minerva. CSV validates the system. CLV validates everything the system depends on." />

        <ClvIntroReveal accent={CLV_GOLD}>
          <div data-stagger style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 24 }}>
            <p style={{ fontSize: 17, lineHeight: 1.7, color: "#C8DAEC", margin: 0 }}>
              Every AI system produces output based on its context - the instructions, documents, tools, and parameters it
              is given. If that context drifts, degrades, or contains inconsistent language, the system's output degrades
              with it, silently, in ways that may not be visible until an audit.
            </p>
            <p style={{ fontSize: 17, lineHeight: 1.7, color: "#C8DAEC", margin: 0 }}>
              CLV is the discipline Minerva built to govern the context layer itself - one layer upstream of the software
              validation you already do. Where Computer System Validation (CSV) asks "does the system behave as specified?",
              CLV asks "is what the system is being given still accurate, consistent, and trustworthy?"
            </p>
          </div>
        </ClvIntroReveal>

        {/* Lifecycle */}
        <SubHead accent={CLV_GOLD} kicker="The lifecycle · five phases, one continuous loop" />
        <p style={{ fontSize: 17, lineHeight: 1.6, color: "#C8DAEC", margin: "0 0 26px", maxWidth: 760 }}>
          Context behaves like an SOP you change every day. CLV is the framework that keeps it in a validated state as it evolves.
        </p>
        <LifecycleLoop />

        {/* CSV vs CLV table — collapsed behind a chevron */}
        <CsvClvTable compare={compare} accent={CLV_GOLD} />
      </div>
    </section>);

}

function MethodDeepDive() {
  return (
    <React.Fragment>
      <ClvDeepDive />
    </React.Fragment>);

}

window.MethodDeepDive = MethodDeepDive;