import { useState, useRef } from "react";
import { motion, AnimatePresence } from "framer-motion";

type Content = Record<string, unknown>;

export type MicroStepItem = {
  label: string;
  emoji: string;
  fill: string;
  ring: string;
  desc: string;
};

export type MacroIterationItem = {
  quarter: string;
  label: string;
  desc: string;
};

const defaultMicroLabel = "Micro cycle";
const defaultMacroLabel = "Macro cycle";

const defaultMicroSteps: MicroStepItem[] = [
  { label: "Understand", emoji: "💛", fill: "hsl(195, 80%, 82%)", ring: "hsl(62, 90%, 55%)", desc: "Understand users deeply through interviews, observation, and immersion in their world." },
  { label: "Observe", emoji: "👁️", fill: "hsl(350, 70%, 76%)", ring: "hsl(62, 90%, 55%)", desc: "Collect baseline data, notice patterns, and document what's really happening — not what you assume." },
  { label: "Define Point\nof View", emoji: "🎯", fill: "hsl(72, 45%, 62%)", ring: "hsl(62, 90%, 55%)", desc: "Synthesize insights into a clear Point of View. What's the real problem beneath the surface?" },
  { label: "Ideate", emoji: "💡", fill: "hsl(30, 80%, 78%)", ring: "hsl(62, 90%, 55%)", desc: "Diverge wide — brainstorm without judgment. 'How Might We…?' questions unlock creative solutions." },
  { label: "Prototype", emoji: "🔧", fill: "hsl(15, 85%, 66%)", ring: "hsl(62, 90%, 55%)", desc: "Build quick, low-fidelity models. Fail fast, learn faster. Make ideas tangible and testable." },
  { label: "Test", emoji: "🧪", fill: "hsl(330, 80%, 62%)", ring: "hsl(62, 90%, 55%)", desc: "Put prototypes in front of real users. Collect data, observe reactions, and let evidence guide iteration." },
];

const defaultMacroIterations: MacroIterationItem[] = [
  { quarter: "Q1", label: "Discover & Define", desc: "Wide exploration — students diverge into empathy research, casting a broad net to understand the problem space." },
  { quarter: "Q2", label: "Ideate & Prototype", desc: "Maximum divergence in ideation, then converging toward testable prototypes through concept sprints." },
  { quarter: "Q3", label: "Test & Iterate", desc: "Convergence accelerates — data from user testing narrows solutions. Diverge only to solve specific failures." },
  { quarter: "Q4", label: "Implement & Showcase", desc: "Strong convergence — refined solutions are implemented with partners and presented at Exhibition." },
];

const defaultDivergeTitle = "Divergent Thinking";
const defaultDivergeSubtitle = "Expand possibilities";
const defaultDivergeBody =
  "Focused on generating a wide range of ideas, possibilities, and solutions. An exploratory, open-ended, free-flowing process — brainstorming, mind mapping, and creative techniques to think outside the box.";
const defaultDivergeItems = [
  "Generate as many ideas as possible",
  "Explore unconventional solutions",
  "No judgment — quantity over quality",
  "Sparks new connections & surprises",
];

const defaultConvergeTitle = "Convergent Thinking";
const defaultConvergeSubtitle = "Narrow to the best";
const defaultConvergeBody =
  "Focused on finding the best solution from a range of options. An analytical, logical process — evaluating, selecting, and refining the most promising ideas to reach the strongest answer.";
const defaultConvergeItems = [
  "Evaluate & select the best ideas",
  "Narrow down to practical solutions",
  "Logical, focused, evidence-based",
  "Leads to clear, actionable outcomes",
];

const defaultDivergeEmoji = "💡";
const defaultConvergeEmoji = "🎯";
const defaultInsightLead = "The magic is in the rhythm.";
const defaultInsightBody =
  "Students diverge wide to explore possibilities, then converge to select the best path forward. Each micro-cycle repeats this pattern — and over time, the macro-cycle narrows from open-ended problem space to refined, impactful solutions.";

const defaultAxisConverge = "CONVERGE";
const defaultAxisDiverge = "DIVERGE";
const defaultAxisProblem = "PROBLEM";
const defaultAxisTime = "TIME";

function str(c: unknown): string {
  return typeof c === "string" ? c : "";
}

function parseStringList(raw: unknown, fallback: string[]): string[] {
  if (!Array.isArray(raw) || raw.length === 0) return fallback;
  const parsed = raw
    .map((p) =>
      typeof p === "string"
        ? p
        : typeof (p as { label?: unknown })?.label === "string"
          ? (p as { label: string }).label
          : "",
    )
    .map((s) => s.trim())
    .filter(Boolean);
  return parsed.length > 0 ? parsed : fallback;
}

function parseMicroSteps(content: Content | undefined): MicroStepItem[] {
  const raw = content?.microSteps;
  if (!Array.isArray(raw) || raw.length === 0) return defaultMicroSteps;
  const parsed = raw
    .filter((x): x is Record<string, unknown> => x != null && typeof x === "object")
    .map((o, i) => {
      const fallback = defaultMicroSteps[i % defaultMicroSteps.length];
      return {
        label: str(o.label).trim() || fallback.label,
        emoji: str(o.emoji).trim() || fallback.emoji,
        fill: str(o.fill).trim() || fallback.fill,
        ring: str(o.ring).trim() || fallback.ring,
        desc: str(o.desc).trim() || fallback.desc,
      };
    });
  return parsed.length > 0 ? parsed : defaultMicroSteps;
}

function parseMacroIterations(content: Content | undefined): MacroIterationItem[] {
  const raw = content?.macroIterations;
  if (!Array.isArray(raw) || raw.length === 0) return defaultMacroIterations;
  const parsed = raw
    .filter((x): x is Record<string, unknown> => x != null && typeof x === "object")
    .map((o, i) => {
      const fallback = defaultMacroIterations[i % defaultMacroIterations.length];
      return {
        quarter: str(o.quarter).trim() || fallback.quarter,
        label: str(o.label).trim() || fallback.label,
        desc: str(o.desc).trim() || fallback.desc,
      };
    });
  return parsed.length > 0 ? parsed : defaultMacroIterations;
}

/** Core viz without CMS section wrapper (for nesting in annual flow, etc.). */
export function DivergeConvergeVizCore({ content }: { content?: Content } = {}) {
  const microLabel = str(content?.microLabel).trim() || defaultMicroLabel;
  const macroLabel = str(content?.macroLabel).trim() || defaultMacroLabel;
  const microSteps = parseMicroSteps(content);
  const macroIterations = parseMacroIterations(content);

  const divergeTitle = str(content?.divergeTitle).trim() || defaultDivergeTitle;
  const divergeSubtitle = str(content?.divergeSubtitle).trim() || defaultDivergeSubtitle;
  const divergeBody = str(content?.divergeBody).trim() || defaultDivergeBody;
  const divergeItems = parseStringList(content?.divergeItems, defaultDivergeItems);
  const divergeEmoji = str(content?.divergeEmoji).trim() || defaultDivergeEmoji;

  const convergeTitle = str(content?.convergeTitle).trim() || defaultConvergeTitle;
  const convergeSubtitle = str(content?.convergeSubtitle).trim() || defaultConvergeSubtitle;
  const convergeBody = str(content?.convergeBody).trim() || defaultConvergeBody;
  const convergeItems = parseStringList(content?.convergeItems, defaultConvergeItems);
  const convergeEmoji = str(content?.convergeEmoji).trim() || defaultConvergeEmoji;

  const insightLead = str(content?.insightLead).trim() || defaultInsightLead;
  const insightBody = str(content?.insightBody).trim() || defaultInsightBody;

  const axisConverge = str(content?.axisConverge).trim() || defaultAxisConverge;
  const axisDiverge = str(content?.axisDiverge).trim() || defaultAxisDiverge;
  const axisProblem = str(content?.axisProblem).trim() || defaultAxisProblem;
  const axisTime = str(content?.axisTime).trim() || defaultAxisTime;

  const [selectedMicroStep, setSelectedMicroStep] = useState<number | null>(null);
  const [selectedMacroStep, setSelectedMacroStep] = useState<number | null>(null);
  const [hoveredMicro, setHoveredMicro] = useState<number | null>(null);
  const microRef = useRef<HTMLDivElement>(null);

  const dotColors = microSteps.map((s) => s.fill);

  const scrollToMicro = (dotIndex: number) => {
    const stepIndex = dotIndex % microSteps.length;
    setSelectedMicroStep(stepIndex);
    microRef.current?.scrollIntoView({ behavior: "smooth", block: "center" });
  };

  /* ── Helix dots for macro diagram ── */
  const helixDots: { x: number; y: number; color: string }[] = [];
  const helixCount = 24;
  for (let i = 0; i < helixCount; i++) {
    const t = i / (helixCount - 1);
    const baseX = 100 + t * 420;
    const baseY = 230 - t * 180;
    const offset = Math.sin(t * Math.PI * 4) * 14;
    helixDots.push({
      x: baseX + offset * 0.5,
      y: baseY + offset,
      color: dotColors[i % dotColors.length],
    });
  }

  const helixDots2: { x: number; y: number; color: string }[] = [];
  for (let i = 0; i < helixCount; i++) {
    const t = i / (helixCount - 1);
    const baseX = 100 + t * 420;
    const baseY = 230 - t * 180;
    const offset = Math.sin(t * Math.PI * 4 + Math.PI) * 14;
    helixDots2.push({
      x: baseX + offset * 0.5,
      y: baseY + offset,
      color: dotColors[(i + 3) % dotColors.length],
    });
  }

  return (
    <div className="space-y-6">
      {/* ═══ MICRO CYCLE ═══ */}
      <div ref={microRef} className="bg-muted/30 rounded-2xl p-6 pb-8 border border-border/50">
        <div className="flex items-center justify-end mb-2">
          <span className="text-sm font-display font-black tracking-tight px-3 py-1 bg-sunflower text-foreground">
            {microLabel}
          </span>
        </div>

        <div className="flex justify-center">
          <svg viewBox="0 0 750 220" className="w-full max-w-3xl" style={{ overflow: "visible" }}>
            <defs>
              <marker id="arrow-micro" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
                <polygon points="0 0, 10 3.5, 0 7" fill="hsl(var(--foreground))" opacity="0.7" />
              </marker>
            </defs>

            {[0, 1, 2, 3, 4].map((i) => {
              const x1 = 75 + i * 120 + 40;
              const x2 = 75 + (i + 1) * 120 - 40;
              const cy = 115;
              return (
                <motion.line
                  key={`fwd-${i}`}
                  x1={x1} y1={cy} x2={x2} y2={cy}
                  stroke="hsl(var(--foreground))" strokeWidth={2} strokeOpacity={0.6}
                  markerEnd="url(#arrow-micro)"
                  initial={{ pathLength: 0 }}
                  whileInView={{ pathLength: 1 }}
                  viewport={{ once: true }}
                  transition={{ duration: 0.4, delay: 0.12 * i + 0.6 }}
                />
              );
            })}

            <motion.path
              d="M 675 78 C 660 -5 90 -5 75 78"
              fill="none"
              stroke="hsl(var(--foreground))"
              strokeWidth={2}
              strokeOpacity={0.5}
              markerEnd="url(#arrow-micro)"
              initial={{ pathLength: 0 }}
              whileInView={{ pathLength: 1 }}
              viewport={{ once: true }}
              transition={{ duration: 1.2, delay: 0.8 }}
            />

            <motion.path
              d="M 660 82 C 640 10 210 10 195 82"
              fill="none"
              stroke="hsl(var(--foreground))"
              strokeWidth={1.8}
              strokeOpacity={0.4}
              markerEnd="url(#arrow-micro)"
              initial={{ pathLength: 0 }}
              whileInView={{ pathLength: 1 }}
              viewport={{ once: true }}
              transition={{ duration: 1, delay: 1 }}
            />

            <motion.path
              d="M 645 85 C 625 25 330 25 315 82"
              fill="none"
              stroke="hsl(var(--foreground))"
              strokeWidth={1.8}
              strokeOpacity={0.4}
              markerEnd="url(#arrow-micro)"
              initial={{ pathLength: 0 }}
              whileInView={{ pathLength: 1 }}
              viewport={{ once: true }}
              transition={{ duration: 1, delay: 1.1 }}
            />

            <motion.path
              d="M 555 148 C 530 185 340 185 315 148"
              fill="none"
              stroke="hsl(var(--foreground))"
              strokeWidth={1.5}
              strokeOpacity={0.35}
              markerEnd="url(#arrow-micro)"
              initial={{ pathLength: 0 }}
              whileInView={{ pathLength: 1 }}
              viewport={{ once: true }}
              transition={{ duration: 0.8, delay: 1.2 }}
            />

            <motion.path
              d="M 630 88 C 610 35 450 35 435 85"
              fill="none"
              stroke="hsl(var(--foreground))"
              strokeWidth={1.5}
              strokeOpacity={0.35}
              markerEnd="url(#arrow-micro)"
              initial={{ pathLength: 0 }}
              whileInView={{ pathLength: 1 }}
              viewport={{ once: true }}
              transition={{ duration: 0.8, delay: 1.3 }}
            />

            <motion.path
              d="M 555 145 C 540 175 460 175 435 145"
              fill="none"
              stroke="hsl(var(--foreground))"
              strokeWidth={1.5}
              strokeOpacity={0.3}
              markerEnd="url(#arrow-micro)"
              initial={{ pathLength: 0 }}
              whileInView={{ pathLength: 1 }}
              viewport={{ once: true }}
              transition={{ duration: 0.6, delay: 1.4 }}
            />

            {microSteps.map((step, i) => {
              const cx = 75 + i * 120;
              const cy = 115;
              const isHovered = hoveredMicro === i;
              const isSelected = selectedMicroStep === i;
              const r = i === 2 ? 42 : 38;
              const rActual = isHovered ? r + 3 : r;

              return (
                <g
                  key={`${step.label}-${i}`}
                  className="cursor-pointer"
                  onClick={() => setSelectedMicroStep(isSelected ? null : i)}
                  onMouseEnter={() => setHoveredMicro(i)}
                  onMouseLeave={() => setHoveredMicro(null)}
                >
                  <motion.circle
                    cx={cx} cy={cy} r={rActual + 5}
                    fill="none"
                    stroke={step.ring}
                    strokeWidth={3}
                    initial={{ scale: 0, opacity: 0 }}
                    whileInView={{ scale: 1, opacity: 1 }}
                    viewport={{ once: true }}
                    transition={{ delay: 0.12 * i + 0.3, duration: 0.4 }}
                    style={{ transformOrigin: `${cx}px ${cy}px` }}
                  />
                  <motion.circle
                    cx={cx} cy={cy} r={rActual}
                    fill={step.fill}
                    initial={{ scale: 0 }}
                    whileInView={{ scale: 1 }}
                    viewport={{ once: true }}
                    transition={{ delay: 0.12 * i + 0.3, type: "spring", stiffness: 200 }}
                    style={{ transformOrigin: `${cx}px ${cy}px` }}
                  />
                  {step.label.includes("\n") ? (
                    <>
                      <text x={cx} y={cy - 8} textAnchor="middle" dominantBaseline="middle" fontSize={10} fontWeight={700} fontFamily="Outfit, sans-serif" fill="hsl(var(--foreground))" className="pointer-events-none">
                        {step.label.split("\n")[0]}
                      </text>
                      <text x={cx} y={cy + 5} textAnchor="middle" dominantBaseline="middle" fontSize={10} fontWeight={700} fontFamily="Outfit, sans-serif" fill="hsl(var(--foreground))" className="pointer-events-none">
                        {step.label.split("\n")[1]}
                      </text>
                      <text x={cx} y={cy + 18} textAnchor="middle" dominantBaseline="middle" fontSize={10} fontWeight={700} fontFamily="Outfit, sans-serif" fill="hsl(var(--foreground))" className="pointer-events-none">
                        {step.label.split("\n")[2] || ""}
                      </text>
                    </>
                  ) : (
                    <text x={cx} y={cy + 2} textAnchor="middle" dominantBaseline="middle" fontSize={11} fontWeight={700} fontFamily="Outfit, sans-serif" fill="hsl(var(--foreground))" className="pointer-events-none">
                      {step.label}
                    </text>
                  )}

                  {isSelected && (
                    <motion.circle
                      cx={cx} cy={cy} r={rActual + 10}
                      fill="none" stroke={step.ring} strokeWidth={2} strokeDasharray="4 3"
                      initial={{ opacity: 0 }} animate={{ opacity: 1 }}
                    />
                  )}
                </g>
              );
            })}
          </svg>
        </div>

        <AnimatePresence>
          {selectedMicroStep !== null && microSteps[selectedMicroStep] && (
            <motion.div
              className="max-w-md mx-auto mt-4 bg-card border-2 rounded-xl p-5 relative text-center"
              style={{ borderColor: microSteps[selectedMicroStep].ring }}
              initial={{ opacity: 0, y: 10 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: 10 }}
              key={selectedMicroStep}
            >
              <button onClick={() => setSelectedMicroStep(null)} className="absolute top-2 right-3 text-muted-foreground hover:text-foreground text-sm">✕</button>
              <h4 className="font-display text-sm font-bold text-foreground">{microSteps[selectedMicroStep].label.replace("\n", " ")}</h4>
              <p className="text-muted-foreground text-xs mt-1 leading-relaxed">{microSteps[selectedMicroStep].desc}</p>
            </motion.div>
          )}
        </AnimatePresence>
      </div>

      {/* ═══ Connection arrow — dashed curved ═══ */}
      <div className="flex justify-center -my-4">
        <svg viewBox="0 0 80 50" className="w-16 h-10" style={{ overflow: "visible" }}>
          <defs>
            <marker id="arrow-conn" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
              <polygon points="0 0, 8 3, 0 6" fill="hsl(var(--muted-foreground))" />
            </marker>
          </defs>
          <path d="M 40 5 C 20 20 20 35 40 45" fill="none" stroke="hsl(var(--muted-foreground))" strokeWidth={2} strokeDasharray="4 3" markerEnd="url(#arrow-conn)" />
          {[
            { cx: 30, cy: 25, color: microSteps[0]?.fill ?? defaultMicroSteps[0].fill, r: 4 },
            { cx: 40, cy: 20, color: microSteps[1]?.fill ?? defaultMicroSteps[1].fill, r: 3.5 },
            { cx: 45, cy: 28, color: microSteps[2]?.fill ?? defaultMicroSteps[2].fill, r: 3.5 },
            { cx: 35, cy: 32, color: microSteps[3]?.fill ?? defaultMicroSteps[3].fill, r: 3 },
            { cx: 48, cy: 35, color: microSteps[4]?.fill ?? defaultMicroSteps[4].fill, r: 3 },
          ].map((d, i) => (
            <circle key={i} cx={d.cx} cy={d.cy} r={d.r} fill={d.color} opacity={0.8} />
          ))}
        </svg>
      </div>

      {/* ═══ MACRO CYCLE ═══ */}
      <div className="bg-muted/30 rounded-2xl p-6 pt-4 border border-border/50">
        <div className="flex items-center justify-end mb-2">
          <span className="text-sm font-display font-black tracking-tight px-3 py-1 bg-sunflower text-foreground">
            {macroLabel}
          </span>
        </div>

        <div className="flex justify-center">
          <svg viewBox="0 0 600 310" className="w-full max-w-2xl" style={{ overflow: "visible" }}>
            <defs>
              <marker id="arrow-axis" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
                <polygon points="0 0, 8 3, 0 6" fill="hsl(var(--foreground))" />
              </marker>
            </defs>

            <motion.line
              x1={90} y1={30} x2={90} y2={280}
              stroke="hsl(var(--foreground))" strokeWidth={2}
              markerStart="url(#arrow-axis)"
              initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 0.5 }}
            />
            <motion.line
              x1={90} y1={155} x2={560} y2={155}
              stroke="hsl(var(--foreground))" strokeWidth={2}
              markerEnd="url(#arrow-axis)"
              initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 0.5 }}
            />

            <text x={75} y={50} fontSize={10} fontWeight={700} fontFamily="Outfit, sans-serif" fill="hsl(var(--foreground))" textAnchor="end" transform="rotate(-90, 75, 50)">
              {axisConverge}
            </text>
            <text x={75} y={265} fontSize={10} fontWeight={700} fontFamily="Outfit, sans-serif" fill="hsl(var(--foreground))" textAnchor="end" transform="rotate(-90, 75, 265)">
              {axisDiverge}
            </text>
            <text x={45} y={158} fontSize={11} fontWeight={800} fontFamily="Outfit, sans-serif" fill="hsl(var(--foreground))" textAnchor="middle">
              {axisProblem}
            </text>
            <text x={550} y={172} fontSize={11} fontWeight={800} fontFamily="Outfit, sans-serif" fill="hsl(var(--foreground))" textAnchor="end">
              {axisTime}
            </text>

            <motion.path
              d="M 95 155 L 180 230 Q 300 260 520 165"
              fill="none" stroke="hsl(var(--muted-foreground))" strokeWidth={1.5} strokeOpacity={0.35}
              initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay: 0.4 }}
            />
            <motion.path
              d="M 95 155 L 180 100 Q 300 50 520 145"
              fill="none" stroke="hsl(var(--muted-foreground))" strokeWidth={1.5} strokeOpacity={0.35}
              initial={{ pathLength: 0 }} whileInView={{ pathLength: 1 }} viewport={{ once: true }} transition={{ duration: 1, delay: 0.4 }}
            />

            <motion.path
              d="M 95 155 L 180 230 Q 300 260 520 165 L 520 145 Q 300 50 180 100 Z"
              fill="hsl(var(--primary))" fillOpacity={0.03} stroke="none"
              initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} viewport={{ once: true }} transition={{ delay: 1 }}
            />

            {helixDots.map((dot, i) => (
              <motion.circle
                key={`h1-${i}`}
                cx={dot.x} cy={dot.y} r={5}
                fill={dot.color}
                className="cursor-pointer"
                onClick={() => scrollToMicro(i)}
                whileHover={{ scale: 1.6 }}
                initial={{ scale: 0 }}
                whileInView={{ scale: 1 }}
                viewport={{ once: true }}
                transition={{ delay: 0.06 * i + 0.8, type: "spring", stiffness: 300 }}
                style={{ transformOrigin: `${dot.x}px ${dot.y}px` }}
              />
            ))}

            {helixDots2.map((dot, i) => (
              <motion.circle
                key={`h2-${i}`}
                cx={dot.x} cy={dot.y} r={5}
                fill={dot.color}
                fillOpacity={0.7}
                className="cursor-pointer"
                onClick={() => scrollToMicro(i)}
                whileHover={{ scale: 1.6 }}
                initial={{ scale: 0 }}
                whileInView={{ scale: 1 }}
                viewport={{ once: true }}
                transition={{ delay: 0.06 * i + 1, type: "spring", stiffness: 300 }}
                style={{ transformOrigin: `${dot.x}px ${dot.y}px` }}
              />
            ))}

            {helixDots2.map((dot, i) => (
              <motion.circle
                key={`h2b-${i}`}
                cx={dot.x} cy={dot.y} r={5}
                fill={dot.color}
                fillOpacity={0.7}
                initial={{ scale: 0 }}
                whileInView={{ scale: 1 }}
                viewport={{ once: true }}
                transition={{ delay: 0.06 * i + 1, type: "spring", stiffness: 300 }}
                style={{ transformOrigin: `${dot.x}px ${dot.y}px` }}
              />
            ))}

            {helixDots.map((dot, i) => (
              <motion.line
                key={`conn-${i}`}
                x1={dot.x} y1={dot.y}
                x2={helixDots2[i].x} y2={helixDots2[i].y}
                stroke="hsl(var(--muted-foreground))" strokeWidth={0.5} strokeOpacity={0.2}
                initial={{ opacity: 0 }}
                whileInView={{ opacity: 1 }}
                viewport={{ once: true }}
                transition={{ delay: 0.06 * i + 1.2 }}
              />
            ))}

            {macroIterations.map((q, i) => {
              const t = (i + 0.5) / 4;
              const bx = 100 + t * 420;
              const by = 230 - t * 180;
              return (
                <g key={`${q.quarter}-${i}`} className="cursor-pointer" onClick={() => setSelectedMacroStep(selectedMacroStep === i ? null : i)}>
                  <motion.rect
                    x={bx - 16} y={by + 22} width={32} height={18} rx={9}
                    fill="hsl(var(--foreground))" fillOpacity={0.85}
                    initial={{ scale: 0 }}
                    whileInView={{ scale: 1 }}
                    viewport={{ once: true }}
                    transition={{ delay: 0.2 * i + 1.5, type: "spring" }}
                    style={{ transformOrigin: `${bx}px ${by + 31}px` }}
                  />
                  <text
                    x={bx} y={by + 33}
                    textAnchor="middle" dominantBaseline="middle"
                    fontSize={8} fontWeight={700} fontFamily="Outfit, sans-serif"
                    fill="hsl(var(--background))" className="pointer-events-none"
                  >
                    {q.quarter}
                  </text>
                  {selectedMacroStep === i && (
                    <motion.rect
                      x={bx - 20} y={by + 18} width={40} height={26} rx={13}
                      fill="none" stroke="hsl(var(--sunflower))" strokeWidth={2}
                      initial={{ opacity: 0 }} animate={{ opacity: 1 }}
                    />
                  )}
                </g>
              );
            })}
          </svg>
        </div>

        <AnimatePresence>
          {selectedMacroStep !== null && macroIterations[selectedMacroStep] && (
            <motion.div
              className="max-w-md mx-auto mt-4 bg-card border-2 border-sunflower rounded-xl p-5 relative text-center"
              initial={{ opacity: 0, y: 10 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: 10 }}
              key={selectedMacroStep}
            >
              <button onClick={() => setSelectedMacroStep(null)} className="absolute top-2 right-3 text-muted-foreground hover:text-foreground text-sm">✕</button>
              <span className="font-display text-xs font-bold tracking-wider uppercase text-foreground">
                {macroIterations[selectedMacroStep].quarter} — {macroIterations[selectedMacroStep].label}
              </span>
              <p className="text-muted-foreground text-xs mt-2 leading-relaxed">{macroIterations[selectedMacroStep].desc}</p>
            </motion.div>
          )}
        </AnimatePresence>
      </div>

      {/* ═══ DIVERGENT vs CONVERGENT THINKING ═══ */}
      <div className="grid md:grid-cols-2 gap-5">
        <motion.div
          className="bg-muted/30 rounded-2xl p-6 border border-border/50"
          initial={{ opacity: 0, x: -20 }}
          whileInView={{ opacity: 1, x: 0 }}
          viewport={{ once: true }}
          transition={{ duration: 0.5 }}
        >
          <div className="flex items-center gap-3 mb-4">
            <div className="w-10 h-10 rounded-full bg-sunflower/20 flex items-center justify-center text-lg">{divergeEmoji}</div>
            <div>
              <h3 className="font-display text-sm font-bold text-foreground">{divergeTitle}</h3>
              <p className="text-[10px] text-muted-foreground font-display uppercase tracking-wider">{divergeSubtitle}</p>
            </div>
          </div>
          <p className="text-muted-foreground text-xs leading-relaxed mb-4">
            {divergeBody}
          </p>
          <ul className="space-y-2">
            {divergeItems.map((item, i) => (
              <li key={i} className="text-xs text-muted-foreground flex items-start gap-2">
                <span className="text-sunflower font-bold mt-0.5">↗</span> {item}
              </li>
            ))}
          </ul>
        </motion.div>

        <motion.div
          className="bg-muted/30 rounded-2xl p-6 border border-border/50"
          initial={{ opacity: 0, x: 20 }}
          whileInView={{ opacity: 1, x: 0 }}
          viewport={{ once: true }}
          transition={{ duration: 0.5 }}
        >
          <div className="flex items-center gap-3 mb-4">
            <div className="w-10 h-10 rounded-full bg-deep-sea/20 flex items-center justify-center text-lg">{convergeEmoji}</div>
            <div>
              <h3 className="font-display text-sm font-bold text-foreground">{convergeTitle}</h3>
              <p className="text-[10px] text-muted-foreground font-display uppercase tracking-wider">{convergeSubtitle}</p>
            </div>
          </div>
          <p className="text-muted-foreground text-xs leading-relaxed mb-4">
            {convergeBody}
          </p>
          <ul className="space-y-2">
            {convergeItems.map((item, i) => (
              <li key={i} className="text-xs text-muted-foreground flex items-start gap-2">
                <span className="text-deep-sea font-bold mt-0.5">↘</span> {item}
              </li>
            ))}
          </ul>
        </motion.div>
      </div>

      <motion.div
        className="bg-card border-2 border-sunflower/30 rounded-xl p-5 text-center"
        initial={{ opacity: 0, y: 10 }}
        whileInView={{ opacity: 1, y: 0 }}
        viewport={{ once: true }}
      >
        <p className="text-xs text-muted-foreground leading-relaxed max-w-xl mx-auto">
          <span className="font-display font-bold text-foreground">{insightLead}</span>{" "}
          {insightBody}
        </p>
      </motion.div>
    </div>
  );
}

/** CMS page block with self-contained section wrapper. */
export function DivergeConvergeVizBlock({ content }: { content?: Record<string, unknown> }) {
  return (
    <section className="pt-12 pb-12 bg-muted/30">
      <div className="container mx-auto px-6 max-w-5xl">
        <DivergeConvergeVizCore content={content} />
      </div>
    </section>
  );
}
