// Board.jsx — top-section Kanban. Three hierarchy lanes stacked vertically:
//   1. Initiative + Epic in two parallel columns (shared 5-status shape)
//   2. Card lane full-width below (11 statuses, cycle bands on left edge)
//   3. Orthogonal strip (Blocked + Rejected)
//
// Role filter dims non-matching statuses only — shape never changes.
// Each status card: activity verb (headline) + owner chips + one-line summary inline,
// full detail on hover/click via popover.

const { useState } = React;

function Board({ filter, customerOnly, cardType, onOpen }) {
  const { initiativeStatuses, epicStatuses, cardStatuses, orthogonalStates, cycles, rules, transitions } = CONTENT;

  return (
    <section id="board" className="relative">
      <div className="max-w-[1280px] mx-auto px-8 pt-16 pb-10">
        <div className="eyebrow">02 · Board</div>
        <h2 className="font-display text-[34px] font-medium mt-2 text-[color:var(--ink)] max-w-3xl">
          The shape of work through Jira.
        </h2>
        <p className="mt-4 text-[14.5px] leading-relaxed text-[color:var(--ink-dim)]">
          {transitions.boardIntro}
        </p>

        {/* Half-day callout — the single biggest behavioral change */}
        <div className="mt-6 p-4 rounded-xl hairline-strong flex gap-4 items-start"
          style={{ background: "linear-gradient(180deg, rgba(39,194,182,0.07), rgba(39,194,182,0.02))" }}>
          <div className="shrink-0 mt-0.5">
            <div className="w-8 h-8 rounded-full flex items-center justify-center"
              style={{ background: "rgba(39,194,182,0.15)", border: "1px solid rgba(39,194,182,0.4)" }}>
              <span className="font-mono text-[11px] text-[color:var(--accent-ink)]">½</span>
            </div>
          </div>
          <div>
            <div className="eyebrow" style={{ color: "var(--accent-ink)" }}>Important · Jira hygiene</div>
            <p className="mt-1 text-[14px] leading-relaxed text-[color:var(--ink)]">
              {transitions.boardHalfDayNote}
            </p>
          </div>
        </div>
      </div>

      {/* Parallel Initiative + Epic lanes */}
      <div className="max-w-[1280px] mx-auto px-8 pb-4">
        <div className="eyebrow mb-4">Initiative and Epic run the same 5-status shape</div>
        <div className="grid grid-cols-1 md:grid-cols-2 gap-5">
          <Lane
            title="Initiative"
            jiraType="Initiative"
            docId="milestone"
            docName="Milestone"
            storage="Confluence · product space"
            customerFacing="full"
            accent="amber"
            statuses={initiativeStatuses}
            cycles={cycles}
            popoverSide="right"
            filter={filter} customerOnly={customerOnly} cardType={cardType}
            onOpen={onOpen}
          />
          <Lane
            title="Epic"
            jiraType="Epic"
            docId="spec"
            docName="Spec"
            storage="Confluence under Milestone"
            customerFacing="partial"
            accent="violet"
            statuses={epicStatuses}
            cycles={cycles}
            popoverSide="left"
            filter={filter} customerOnly={customerOnly} cardType={cardType}
            onOpen={onOpen}
          />
        </div>
      </div>

      {/* Transition paragraph */}
      <div className="max-w-[1280px] mx-auto px-8 pt-10 pb-6">
        <p className="text-[14.5px] leading-relaxed text-[color:var(--ink-dim)] italic font-serif">
          {transitions.initEpicToCard}
        </p>
      </div>

      {/* Card lane */}
      <div className="max-w-[1280px] mx-auto px-8 pb-10">
        <div className="eyebrow mb-4">Cards run 11 statuses · Tasks skip UAT</div>
        <CardLane
          statuses={cardStatuses}
          cycles={cycles}
          rules={rules}
          filter={filter} customerOnly={customerOnly} cardType={cardType}
          onOpen={onOpen}
        />
      </div>

      {/* Transition */}
      <div className="max-w-[1280px] mx-auto px-8 pt-4 pb-6">
        <p className="text-[14.5px] leading-relaxed text-[color:var(--ink-dim)] italic font-serif">
          {transitions.cardToOrthogonal}
        </p>
      </div>

      {/* Orthogonal states */}
      <div className="max-w-[1280px] mx-auto px-8 pb-14">
        <div className="eyebrow mb-4">Off-flow · Blocked and Rejected apply at any level</div>
        <div className="grid grid-cols-1 md:grid-cols-2 gap-5">
          {orthogonalStates.map(o => <OrthogonalCard key={o.id} state={o} />)}
        </div>
      </div>
    </section>
  );
}

// ──────────────────────────────────────────────────────────────
// LANE (Initiative or Epic — shared 5-status shape)
// ──────────────────────────────────────────────────────────────
function Lane({ title, jiraType, docId, docName, storage, accent, customerFacing, statuses, cycles, filter, customerOnly, cardType, popoverSide, onOpen }) {
  const accentCss = accent === "amber" ? "var(--customer)" : accent === "violet" ? "oklch(0.72 0.16 295)" : "var(--accent)";
  const cyclesById = Object.fromEntries((cycles || []).map(c => [c.id, c]));
  const docObj = (CONTENT.docs || []).find(d => d.id === docId);
  const visuals = docObj && docObj.visuals;
  // Group consecutive statuses by cycleId — same approach as CardLane
  const groups = [];
  let cur = null;
  statuses.forEach((s, i) => {
    const cid = s.cycleId;
    if (!cur || cur.cycleId !== cid) {
      if (cur) groups.push(cur);
      cur = { cycleId: cid, statuses: [] };
    }
    cur.statuses.push({ ...s, _index: i + 1 });
  });
  if (cur) groups.push(cur);

  return (
    <div className="rounded-2xl p-5 hairline" style={{ background: "rgba(14,19,34,0.6)" }}>
      {/* Lane header */}
      <div className="flex items-start justify-between gap-3 mb-4">
        <div>
          <div className="eyebrow" style={{ color: accentCss }}>{jiraType} · Jira issue type</div>
          <div className="font-display text-[22px] font-medium text-[color:var(--ink)] mt-1">{title}</div>
          <button onClick={() => onOpen({ type: "doc", id: docId })}
            className="mt-2 inline-flex items-center gap-2 text-left hover:opacity-80 flex-wrap">
            <span className="font-mono text-[10.5px] uppercase tracking-[0.22em] text-[color:var(--ink-faint)]">Active doc</span>
            <span className="font-display text-[14px] font-medium text-[color:var(--ink)]">{docName}</span>
            {customerFacing === "full" && (
              <span className="customer-pill rounded-full px-2 py-0.5 text-[9px] font-mono uppercase tracking-[0.2em] flex items-center gap-1 whitespace-nowrap">
                <span className="customer-dot" /> Customer-facing
              </span>
            )}
            {customerFacing === "partial" && (
              <span className="customer-pill rounded-full px-2 py-0.5 text-[9px] font-mono uppercase tracking-[0.2em] flex items-center gap-1 whitespace-nowrap opacity-90">
                AC is customer-facing
              </span>
            )}
            {visuals && (
              <span className="rounded-full px-2 py-0.5 text-[9px] font-mono uppercase tracking-[0.2em] inline-flex items-center gap-1 whitespace-nowrap"
                style={{
                  background: visuals.level === "required" ? "rgba(191,148,255,0.14)" : "rgba(191,148,255,0.08)",
                  border: `1px solid ${visuals.level === "required" ? "rgba(191,148,255,0.42)" : "rgba(191,148,255,0.26)"}`,
                  color: "oklch(0.85 0.12 300)",
                }}
                title={visuals.content}>
                <svg width="8" height="8" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6">
                  <rect x="2" y="3" width="12" height="9" rx="1"/>
                  <path d="M2 11l3.5-3 2.5 2 3-3 3 3"/>
                </svg>
                Visuals · {visuals.level === "required" ? "Required" : visuals.level === "encouraged" ? "Encouraged" : "Situational"}
              </span>
            )}
          </button>
          <div className="font-mono text-[10.5px] uppercase tracking-[0.22em] text-[color:var(--ink-faint)] mt-1">
            Stored · {storage}
          </div>
        </div>
      </div>

      {/* Status rows with left-edge cycle bands (mirrors CardLane) */}
      <div>
        {groups.map((g, gi) => {
          const cycle = g.cycleId ? cyclesById[g.cycleId] : null;
          const isCustomerCycle = cycle && cycle.id === "customer";
          const bandBg = isCustomerCycle
            ? "linear-gradient(180deg, rgba(240, 196, 132, 0.12), rgba(240, 196, 132, 0.03))"
            : "linear-gradient(180deg, rgba(39,194,182,0.10), rgba(39,194,182,0.03))";
          const bandBorder = isCustomerCycle
            ? "1px dashed rgba(240, 196, 132, 0.45)"
            : "1px solid rgba(39,194,182,0.25)";
          const bandFg = isCustomerCycle ? "var(--customer)" : "var(--accent-ink)";
          return (
            <div key={gi} className="flex gap-2.5 mb-2.5">
              {/* Left-edge cycle band */}
              <button
                onClick={() => cycle && onOpen({ type: "cycle", id: cycle.id })}
                disabled={!cycle}
                className="shrink-0 w-14 relative rounded-lg overflow-hidden text-left transition-colors"
                style={{
                  background: cycle ? bandBg : "rgba(255,255,255,0.02)",
                  border: cycle ? bandBorder : "1px dashed var(--line)",
                  cursor: cycle ? "pointer" : "default",
                }}>
                {cycle ? (
                  <div className="h-full flex flex-col items-center justify-center px-1.5 py-3">
                    <div className="font-display text-[10.5px] font-medium uppercase tracking-[0.22em] text-center"
                      style={{ writingMode: "vertical-rl", transform: "rotate(180deg)", letterSpacing: "0.3em", color: bandFg }}>
                      {cycle.name.replace(" Cycle", "")}
                    </div>
                  </div>
                ) : (
                  <div className="h-full flex items-center justify-center px-1">
                    <div className="font-mono text-[9px] uppercase tracking-[0.18em] text-[color:var(--ink-faint)] text-center leading-tight">
                      off<br />cycle
                    </div>
                  </div>
                )}
              </button>

              {/* Status column */}
              <div className="flex-1 space-y-2.5">
                {g.statuses.map(s => (
                  <StatusRow key={s.id} status={s} index={s._index} total={statuses.length}
                    filter={filter} customerOnly={customerOnly} cardType={cardType}
                    laneAccent={accentCss} popoverSide={popoverSide} onOpen={onOpen} />
                ))}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// CARD LANE (full-width, left-edge cycle bands)
// ──────────────────────────────────────────────────────────────
function CardLane({ statuses, cycles, rules, filter, customerOnly, cardType, onOpen }) {
  const cyclesById = Object.fromEntries(cycles.map(c => [c.id, c]));
  // Group consecutive statuses by cycleId so we can draw cycle bands on left edge
  const groups = [];
  let cur = null;
  statuses.forEach((s, i) => {
    const cid = s.cycleId;
    if (!cur || cur.cycleId !== cid) {
      if (cur) groups.push(cur);
      cur = { cycleId: cid, statuses: [] };
    }
    cur.statuses.push({ ...s, _index: i + 1 });
  });
  if (cur) groups.push(cur);

  return (
    <div className="rounded-2xl p-5 hairline" style={{ background: "rgba(14,19,34,0.6)" }}>
      {/* Card lane header */}
      <div className="flex items-start justify-between gap-4 mb-4 flex-wrap">
        <div>
          <div className="eyebrow" style={{ color: "var(--accent-ink)" }}>Card · Jira issue type</div>
          <button onClick={() => onOpen({ type: "doc", id: "plan" })}
            className="mt-2 inline-flex items-baseline gap-2 text-left hover:opacity-80 flex-wrap">
            <span className="font-display text-[22px] font-medium text-[color:var(--ink)]">Plan is the active doc</span>
            <span className="rounded-full px-2 py-0.5 text-[9px] font-mono uppercase tracking-[0.2em] inline-flex items-center gap-1 whitespace-nowrap self-center"
              style={{
                background: "rgba(191,148,255,0.08)",
                border: "1px solid rgba(191,148,255,0.26)",
                color: "oklch(0.85 0.12 300)",
              }}
              title="Component-detail mockups, before/during screenshots, implementation sketches.">
              <svg width="8" height="8" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6">
                <rect x="2" y="3" width="12" height="9" rx="1"/>
                <path d="M2 11l3.5-3 2.5 2 3-3 3 3"/>
              </svg>
              Visuals · Encouraged
            </span>
          </button>
          <div className="font-mono text-[10.5px] uppercase tracking-[0.22em] text-[color:var(--ink-faint)] mt-1">
            Stored · codebase · specs/plans/&#123;active,complete&#125;/&lt;card-id&gt;-&lt;slug&gt;.md
          </div>
        </div>
        {/* Card type legend */}
        <div className="flex items-center gap-2">
          <span className="font-mono text-[10px] uppercase tracking-[0.22em] text-[color:var(--ink-faint)]">Types</span>
          <CardTypePill ct="feature" />
          <CardTypePill ct="bug" />
          <CardTypePill ct="task" />
        </div>
      </div>

      {/* Status rows with left-edge cycle bands */}
      <div>
        {groups.map((g, gi) => {
          const cycle = g.cycleId ? cyclesById[g.cycleId] : null;
          const cycleRule = cycle ? rules.find(r => r.cycleId === cycle.id) : null;
          // Customer cycle gets a distinct amber treatment; others use accent teal
          const isCustomerCycle = cycle && cycle.id === "customer";
          const bandBg = isCustomerCycle
            ? "linear-gradient(180deg, rgba(240, 196, 132, 0.12), rgba(240, 196, 132, 0.03))"
            : "linear-gradient(180deg, rgba(39,194,182,0.10), rgba(39,194,182,0.03))";
          const bandBorder = isCustomerCycle
            ? "1px dashed rgba(240, 196, 132, 0.45)"
            : "1px solid rgba(39,194,182,0.25)";
          const bandFg = isCustomerCycle ? "var(--customer)" : "var(--accent-ink)";
          return (
            <div key={gi} className="flex gap-3 mb-2.5">
              {/* Left-edge cycle band */}
              <button
                onClick={() => cycle && onOpen({ type: "cycle", id: cycle.id })}
                disabled={!cycle}
                className="shrink-0 w-16 md:w-20 relative rounded-lg overflow-hidden text-left transition-colors"
                style={{
                  background: cycle ? bandBg : "rgba(255,255,255,0.02)",
                  border: cycle ? bandBorder : "1px dashed var(--line)",
                  cursor: cycle ? "pointer" : "default",
                }}>
                {cycle ? (
                  <div className="h-full flex flex-col items-center justify-center px-1.5 py-3">
                    <div className="font-display text-[11px] font-medium uppercase tracking-[0.22em] text-center"
                      style={{ writingMode: "vertical-rl", transform: "rotate(180deg)", letterSpacing: "0.3em", color: bandFg }}>
                      {cycle.name.replace(" Cycle", "")}
                    </div>
                  </div>
                ) : (
                  <div className="h-full flex items-center justify-center px-1">
                    <div className="font-mono text-[9px] uppercase tracking-[0.18em] text-[color:var(--ink-faint)] text-center leading-tight">
                      off<br />cycle
                    </div>
                  </div>
                )}
              </button>

              {/* Status column */}
              <div className="flex-1 space-y-2.5">
                {g.statuses.map(s => (
                  <StatusRow key={s.id} status={s} index={s._index} total={statuses.length}
                    filter={filter} customerOnly={customerOnly} cardType={cardType}
                    laneAccent="var(--accent)" showCardTypes={true}
                    onOpen={onOpen} />
                ))}
              </div>
            </div>
          );
        })}
      </div>

      {/* Cycle rules summary — all 5 MKS cycles; Customer Cycle is non-contiguous across lanes */}
      <div className="mt-5 pt-5 border-t border-[color:var(--line)]">
        <div className="eyebrow mb-3">The five MKS cycles · click any to filter · Customer is non-contiguous by design</div>
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-3">
          {cycles.map(c => {
            const rule = rules.find(r => r.cycleId === c.id);
            const isCustomer = c.id === "customer";
            return (
              <button key={c.id} onClick={() => onOpen({ type: "cycle", id: c.id })}
                className="text-left p-3 rounded-lg hairline hover:border-[rgba(39,194,182,0.4)] transition-colors"
                style={isCustomer ? { borderStyle: "dashed", borderColor: "rgba(240,196,132,0.35)" } : undefined}>
                <div className="flex items-center gap-1.5 flex-wrap">
                  <div className="font-display text-[13px] font-medium text-[color:var(--ink)]">{c.name}</div>
                  {isCustomer && (
                    <span className="font-mono text-[8.5px] uppercase tracking-[0.2em] px-1.5 py-0.5 rounded"
                      style={{ background: "rgba(240,196,132,0.10)", color: "var(--customer)", border: "1px dashed rgba(240,196,132,0.4)" }}>
                      Non-contig
                    </span>
                  )}
                </div>
                <div className="font-mono text-[10px] uppercase tracking-[0.2em] text-[color:var(--ink-faint)] mt-1">{c.jiraStatus}</div>
                {rule && <div className="text-[12px] text-[color:var(--ink-dim)] mt-2 leading-snug">{rule.summary}</div>}
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────
// STATUS ROW — the atomic unit, used in all three lanes.
// Two layouts branch on `showCardTypes` (the Card-lane flag):
//   • Card lane (showCardTypes=true): full-width rows → split layout,
//     summary on the left half, detail always visible on the right half.
//     No popover.
//   • Initiative / Epic (showCardTypes=false): narrower rows in two side-
//     by-side lanes. Single card; clicking the arrow slides a detail
//     popover out toward the page centre (Initiative → right, Epic →
//     left). Popover is wider than the anchor so the two directions meet
//     in the middle.
// Chip clicks on any variant still open the drawer for roles/docs.
// ──────────────────────────────────────────────────────────────
function StatusRow({ status, index, total, filter, customerOnly, cardType, laneAccent, showCardTypes, popoverSide, onOpen }) {
  const [popOpen, setPopOpen] = useState(false);
  const { roles, docs } = CONTENT;
  const rolesById = Object.fromEntries(roles.map(r => [r.id, r]));
  const docsById = Object.fromEntries(docs.map(d => [d.id, d]));

  // Role filter: dim if status not owned by filtered role
  const matchRole = !filter || filter.type !== "role" || (status.owners || []).includes(filter.id);
  const matchDoc = !filter || filter.type !== "doc" || status.activeDoc === filter.id;
  const matchCycle = !filter || filter.type !== "cycle" || status.cycleId === filter.id;
  const matchCustomer = !customerOnly || status.customerFacing === true || status.customerFacing === "partial";
  const matchCardType = !cardType || !status.appliesTo || status.appliesTo === "fbt" ||
    (cardType === "task" ? status.appliesTo !== "fb" : true);
  const active = matchRole && matchDoc && matchCycle && matchCustomer && matchCardType;

  const isCustomerFull = status.customerFacing === true;
  const isCustomerPartial = status.customerFacing === "partial";
  const isTerminal = !!status.terminal;
  const isQueue = !!status.queue;
  const taskExcluded = status.appliesTo === "fb";
  const derivedDoc = status.derivedArtifact ? docsById[status.derivedArtifact] : null;

  // Color treatment
  let rowStyle = { background: "rgba(255,255,255,0.02)", borderColor: "var(--line)" };
  if (isCustomerFull) {
    rowStyle = {
      background: "linear-gradient(180deg, rgba(125,238,200,0.06), rgba(125,238,200,0.02))",
      borderColor: "rgba(125,238,200,0.28)",
    };
  } else if (isCustomerPartial) {
    rowStyle = {
      background: "linear-gradient(180deg, rgba(125,238,200,0.03), rgba(255,255,255,0.01))",
      borderColor: "rgba(125,238,200,0.15)",
    };
  }
  const cardStyle = {
    ...rowStyle,
    border: `1px solid ${rowStyle.borderColor}`,
    borderRadius: "0.5rem",
  };

  // ── SUMMARY BODY (shared across both layouts) ────────────────
  const renderHeaderPills = (withArrow) => (
    <div className="flex items-center gap-2 flex-wrap">
      <span className="font-mono text-[10px] uppercase tracking-[0.22em] text-[color:var(--ink-faint)] tabular-nums shrink-0">
        {String(index).padStart(2, "0")}/{String(total).padStart(2, "0")}
      </span>
      <span className="font-display text-[14.5px] font-semibold text-[color:var(--ink)] whitespace-nowrap">{status.name}</span>
      {isQueue && (
        <span className="font-mono text-[9px] uppercase tracking-[0.2em] px-1.5 py-0.5 rounded whitespace-nowrap"
          style={{ background: "rgba(148,163,184,0.1)", color: "var(--ink-dim)", border: "1px solid var(--line-strong)" }}>
          Queue
        </span>
      )}
      {isTerminal && (
        <span className="font-mono text-[9px] uppercase tracking-[0.2em] px-1.5 py-0.5 rounded whitespace-nowrap"
          style={{ background: "rgba(148,163,184,0.1)", color: "var(--ink-dim)", border: "1px solid var(--line-strong)" }}>
          Terminal
        </span>
      )}
      <span className="flex-1" />
      {showCardTypes && isCustomerFull && (
        <span className="customer-pill rounded-full px-2 py-0.5 text-[9px] font-mono uppercase tracking-[0.2em] flex items-center gap-1 whitespace-nowrap">
          <span className="customer-dot" /> Customer
        </span>
      )}
      {showCardTypes && isCustomerPartial && (
        <span className="customer-pill rounded-full px-2 py-0.5 text-[9px] font-mono uppercase tracking-[0.2em] whitespace-nowrap opacity-80">
          Partial
        </span>
      )}
      {withArrow && (
        <button
          onClick={() => setPopOpen(v => !v)}
          className={`flip-btn ${popOpen ? "is-active" : ""}`}
          title={popOpen ? "Close detail" : "Show detail"}
          aria-label={popOpen ? "Close detail" : "Show detail"}>
          {popOpen ? (
            <svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6"><path d="M12 4L4 12M4 4l8 8"/></svg>
          ) : (
            <svg width="13" height="13" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5">
              <circle cx="8" cy="8" r="6.25"/>
              <path d="M8 7.25v4.25" strokeLinecap="round"/>
              <circle cx="8" cy="5" r="0.6" fill="currentColor" stroke="none"/>
            </svg>
          )}
        </button>
      )}
    </div>
  );

  const renderSummaryBody = () => (
    <>
      <div className="mt-2 font-display text-[17px] font-medium text-[color:var(--ink)] leading-snug">
        {status.activityVerb}
      </div>
      <div className="mt-1 text-[12.5px] leading-relaxed text-[color:var(--ink-dim)]">
        {status.summary}
      </div>
      <div className="mt-2.5 flex items-center gap-2 flex-wrap">
        {(status.owners || []).map(rid => {
          const r = rolesById[rid];
          if (!r) return null;
          const cls = r.tier === "customer" ? "role-chip-customer" : r.tier === "oversight" ? "role-chip-oversight" : "role-chip";
          return (
            <button key={rid}
              onClick={(e) => { e.stopPropagation(); onOpen({ type: "role", id: rid }); }}
              className={`${cls} rounded-full px-2 py-0.5 text-[10px] font-mono uppercase tracking-[0.2em] hover:opacity-85`}>
              {r.name}
            </button>
          );
        })}
        {derivedDoc && (
          <button
            onClick={(e) => { e.stopPropagation(); onOpen({ type: "doc", id: derivedDoc.id }); }}
            className="customer-pill rounded px-2 py-0.5 text-[10px] font-mono uppercase tracking-[0.2em] hover:opacity-85 flex items-center gap-1.5"
            title={"Derived publication surfaces here: " + derivedDoc.name}>
            <span>↑</span> {derivedDoc.name}
          </button>
        )}
        {showCardTypes && (
          <div className="flex items-center gap-1 ml-auto">
            <CardTypePill ct="feature" />
            <CardTypePill ct="bug" />
            <CardTypePill ct="task" dim={taskExcluded} />
          </div>
        )}
      </div>
    </>
  );

  // ── CARD LANE LAYOUT: split left/right, no popover ──────────
  if (showCardTypes) {
    return (
      <div className={`relative transition-all ${active ? "" : "opacity-25 saturate-50"}`} style={cardStyle}>
        <div className="grid grid-cols-1 md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]">
          <div className="p-3.5">
            {renderHeaderPills(false)}
            {renderSummaryBody()}
          </div>
          <div className="p-3.5 md:border-l border-[color:var(--line)]">
            <div className="flex items-center gap-2">
              <span className="eyebrow" style={{ color: "var(--accent-ink)" }}>Detail</span>
              <span className="flex-1" />
              <button onClick={() => onOpen({ type: "status", id: status.id })}
                className="font-mono text-[10px] uppercase tracking-[0.22em] text-[color:var(--ink-dim)] hover:text-[color:var(--accent-ink)] transition-colors whitespace-nowrap">
                Open full view →
              </button>
            </div>
            <p className="mt-2 text-[13px] leading-relaxed text-[color:var(--ink)]">
              {status.detail}
            </p>
          </div>
        </div>
      </div>
    );
  }

  // ── INITIATIVE / EPIC LAYOUT: single card + directional popover ──────
  const popClass = `detail-popover ${popoverSide === "right" ? "popover-right" : "popover-left"} ${popOpen ? "is-open" : ""}`;
  return (
    <div className={`status-row-shell ${popOpen ? "popover-open" : ""} transition-all ${active ? "" : "opacity-25 saturate-50"}`}>
      {/* Anchor card */}
      <div style={cardStyle} className="relative">
        <div className="p-3.5">
          {renderHeaderPills(true)}
          {renderSummaryBody()}
        </div>
      </div>

      {/* Popover — rendered as a sibling so it can overflow the anchor */}
      <div className={popClass} role="dialog" aria-hidden={!popOpen}>
        <div className="flex items-center gap-2">
          <span className="font-mono text-[10px] uppercase tracking-[0.22em] text-[color:var(--ink-faint)] tabular-nums">
            {String(index).padStart(2, "0")}/{String(total).padStart(2, "0")}
          </span>
          <span className="font-display text-[14px] font-semibold text-[color:var(--ink)]">{status.name}</span>
          <span className="eyebrow" style={{ color: "var(--accent-ink)" }}>· Detail</span>
          <span className="flex-1" />
          <button onClick={() => setPopOpen(false)} className="flip-btn" title="Close" aria-label="Close detail">
            <svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6">
              <path d="M12 4L4 12M4 4l8 8"/>
            </svg>
          </button>
        </div>
        <p className="mt-2.5 text-[13px] leading-relaxed text-[color:var(--ink)]">
          {status.detail}
        </p>
        <div className="mt-3 pt-3 border-t border-[color:var(--line)] flex items-center justify-between gap-2">
          <span className="font-mono text-[10px] uppercase tracking-[0.22em] text-[color:var(--ink-faint)]">
            {status.activityVerb}
          </span>
          <button onClick={() => onOpen({ type: "status", id: status.id })}
            className="font-mono text-[10px] uppercase tracking-[0.22em] text-[color:var(--ink-dim)] hover:text-[color:var(--accent-ink)] transition-colors whitespace-nowrap">
            Open full view →
          </button>
        </div>
      </div>
    </div>
  );
}

// (FlipRow removed — popover replaced it.)

// ──────────────────────────────────────────────────────────────
// Card type pill — Feature (green) · Bug (red) · Task (blue)
// ──────────────────────────────────────────────────────────────
function CardTypePill({ ct, dim }) {
  const palette = {
    feature: { bg: "rgba(125, 220, 140, 0.12)", bd: "rgba(125, 220, 140, 0.35)", fg: "oklch(0.88 0.14 150)", label: "Feature" },
    bug:     { bg: "rgba(238, 125, 125, 0.12)", bd: "rgba(238, 125, 125, 0.35)", fg: "oklch(0.82 0.14 25)",  label: "Bug" },
    task:    { bg: "rgba(125, 170, 238, 0.12)", bd: "rgba(125, 170, 238, 0.35)", fg: "oklch(0.82 0.13 240)", label: "Task" },
  }[ct];
  return (
    <span className={`rounded px-1.5 py-0.5 text-[9.5px] font-mono uppercase tracking-[0.2em] ${dim ? "opacity-25 line-through" : ""}`}
      style={{ background: palette.bg, border: `1px solid ${palette.bd}`, color: palette.fg }}
      title={dim ? `${palette.label} skips this status` : palette.label}>
      {palette.label}
    </span>
  );
}

// ──────────────────────────────────────────────────────────────
// Orthogonal card — Blocked / Rejected
// ──────────────────────────────────────────────────────────────
function OrthogonalCard({ state }) {
  return (
    <div className="p-5 rounded-xl hairline-strong"
      style={{ background: "linear-gradient(180deg, rgba(30,38,60,0.5), rgba(12,17,31,0.5))" }}>
      <div className="flex items-baseline gap-3">
        <div className="font-display text-[22px] font-medium text-[color:var(--ink)]">{state.name}</div>
        <span className="font-mono text-[10px] uppercase tracking-[0.22em] text-[color:var(--ink-faint)]">Orthogonal · any level</span>
      </div>
      <p className="mt-2 font-serif italic text-[16px] text-[color:var(--ink-dim)] leading-snug">{state.headline}</p>
      <p className="mt-4 text-[13.5px] leading-relaxed text-[color:var(--ink)]">{state.body}</p>
      <div className="mt-4 pt-4 border-t border-[color:var(--line)]">
        <div className="eyebrow mb-2">Required field</div>
        <div className="font-mono text-[12px] text-[color:var(--ink)]">{state.field}</div>
        <div className="mt-2 flex flex-wrap gap-1.5">
          {state.fieldExamples.map((ex, i) => (
            <span key={i} className="font-mono text-[10px] text-[color:var(--ink-dim)] px-2 py-0.5 rounded"
              style={{ background: "rgba(255,255,255,0.03)", border: "1px solid var(--line)" }}>
              {ex}
            </span>
          ))}
        </div>
      </div>
      <p className="mt-4 text-[12px] leading-relaxed text-[color:var(--ink-faint)] italic">{state.note}</p>
    </div>
  );
}

window.Board = Board;
