// app.jsx — "My Business Credit Score" page (design v2 — Manrope / Instrument Serif, navy+blue theme)
// Sections:
//   1. Hero — radial gauge + score history line chart + risk legend + verdict
//   2. Score factors (What goes into your score)
//   3. FAQ accordion
//   4. Articles / blog grid
//   5. Page footer
//
// NOTE: all live-data wiring is unchanged from the previous version —
// fetchCreditScore() / window.RBI_API.getCreditScore(), the loading
// skeleton, the error+retry state, and the RBI_STATE scenario switch
// all work exactly as before. Only the visual layer changed.

const { useState, useMemo, useEffect, useRef } = React;

// Profile from GET /v1/bi/profile, fetched at login and held in memory by
// RBI_API — never persisted. `{}` until the call lands.
function getStoredProfile() {
  return (window.RBI_API && window.RBI_API.profile()) || {};
}

// Re-renders the calling component when the profile arrives, and kicks off the
// fetch if this page load hasn't made it yet (hard refresh / deep link).
// Returns [profile, settled] — `settled` flips to true once the fetch has
// finished, whether it succeeded or not, so callers never wait forever.
function useProfile() {
  const [state, setState] = useState(() => {
    const p = getStoredProfile();
    return { profile: p, settled: !!p.email };
  });
  useEffect(() => {
    let alive = true;
    function onProfile(e) {
      if (alive) setState({ profile: (e.detail && e.detail.profile) || {}, settled: true });
    }
    window.addEventListener("rbi:profile", onProfile);
    if (window.RBI_API && window.RBI_API.ensureProfile) {
      window.RBI_API.ensureProfile()
        .then((p) => { if (alive) setState({ profile: p || {}, settled: true }); })
        .catch(() => { if (alive) setState({ profile: {}, settled: true }); });
    } else {
      setState({ profile: {}, settled: true });
    }
    return () => { alive = false; window.removeEventListener("rbi:profile", onProfile); };
  }, []);
  return [state.profile, state.settled];
}

// Business name for the dashboard header/greeting. Falls back to "Your Business".
function getBusinessDisplayName(p) {
  p = p || getStoredProfile();
  if (p.business_name && p.business_name.trim()) return p.business_name.trim();
  return "Your Business";
}

// Account owner (first + last name) shown in the topbar account chip.
function getOwnerDisplayName(fallback, p) {
  p = p || getStoredProfile();
  const full = (p.owner_name || [p.first_name, p.last_name].filter(Boolean).join(" ")).trim();
  return full || fallback || "Your Account";
}

// City shown under the owner name in the topbar account chip.
function getCityDisplay(fallback, p) {
  p = p || getStoredProfile();
  if (p.city && p.city.trim()) return p.city.trim();
  return fallback || "";
}

// ── Color helpers (derive translucent / light / dark variants from a
//    single hex accent so every risk band gets a consistent look even
//    though only the "High Risk" state was supplied in the new design) ──
function hexToRgb(hex) {
  const h = hex.replace("#", "");
  return {
    r: parseInt(h.substring(0, 2), 16),
    g: parseInt(h.substring(2, 4), 16),
    b: parseInt(h.substring(4, 6), 16),
  };
}
function rgbaColor(hex, a) {
  const { r, g, b } = hexToRgb(hex);
  return `rgba(${r},${g},${b},${a})`;
}
function mixColor(hex, target, t) {
  const { r, g, b } = hexToRgb(hex);
  const m = (c) => Math.round(c + (target - c) * t);
  return `rgb(${m(r)},${m(g)},${m(b)})`;
}
function lightenColor(hex, t) { return mixColor(hex, 255, t); }
function darkenColor(hex, t) { return mixColor(hex, 0, t); }

// ── Score range config ────────────────────────────────────────────────────────
// SBFE range: 706–999. Colors match the new design's swatches; "accent"/
// "strong" are only defined for the High Risk band shown in the mockup —
// the rest are derived at runtime so the palette stays consistent.
const SCORE_MIN = 706;
const SCORE_MAX = 999;
const SCORE_RANGES = [
  { min: 706, max: 799, label: "High Risk", dot: "#EF4444", accent: "#F04A4A", strong: "#D8232A" },
  { min: 800, max: 839, label: "Moderate – High Risk", dot: "#F97316" },
  { min: 840, max: 879, label: "Moderate Risk", dot: "#F5C13D" },
  { min: 880, max: 899, label: "Low – Moderate Risk", dot: "#4CB782" },
  { min: 900, max: 999, label: "Low Risk", dot: "#2AA96B" },
];

function getRangeMeta(value) {
  const r = SCORE_RANGES.find(rb => value >= rb.min && value <= rb.max) || SCORE_RANGES[0];
  const accent = r.accent || r.dot;
  const strong = r.strong || darkenColor(accent, 0.18);
  const textTint = lightenColor(accent, 0.42);
  return { ...r, accent, strong, textTint };
}

// ── Radial gauge ──────────────────────────────────────────────────────────────
// 240° arc (120° gap at the bottom), center (140,140) r=120 — matches the
// new design's SVG geometry exactly. Score number + risk badge render as an
// absolutely-positioned overlay on top (cs-gauge-center) rather than inside
// the SVG, for crisp text.
function RadialGauge({ value, meta }) {
  const pct = Math.min(1, Math.max(0, (value - SCORE_MIN) / (SCORE_MAX - SCORE_MIN)));
  const CX = 140, CY = 140, R = 120;
  const START_DEG = 150, SWEEP_DEG = 240;
  const TRACK_LEN = 2 * Math.PI * R * (SWEEP_DEG / 360);
  const fillLen = pct * TRACK_LEN;

  function polar(deg) {
    const rad = (deg * Math.PI) / 180;
    return [CX + R * Math.cos(rad), CY + R * Math.sin(rad)];
  }
  const [sx, sy] = polar(START_DEG);
  const [ex, ey] = polar(START_DEG + SWEEP_DEG);
  const trackPath = `M${sx.toFixed(2)},${sy.toFixed(2)} A${R},${R} 0 1 1 ${ex.toFixed(2)},${ey.toFixed(2)}`;
  const gradId = "gaugeGrad" + meta.min;

  return (
    <svg viewBox="0 0 280 250" className="cs-gauge-svg" aria-label={`Score ${value} of ${SCORE_MAX}`}>
      <defs>
        <linearGradient id={gradId} x1="0" y1="1" x2="1" y2="0">
          <stop offset="0%" stopColor={darkenColor(meta.accent, 0.25)} />
          <stop offset="100%" stopColor={meta.accent} />
        </linearGradient>
      </defs>
      <path d={trackPath} fill="none" stroke="rgba(255,255,255,0.09)" strokeWidth="22" strokeLinecap="round" />
      <path
        d={trackPath}
        fill="none"
        stroke={`url(#${gradId})`}
        strokeWidth="22"
        strokeLinecap="round"
        strokeDasharray={`${fillLen} ${TRACK_LEN}`}
        style={{ filter: `drop-shadow(0 0 14px ${rgbaColor(meta.accent, 0.45)})` }}
      />
    </svg>
  );
}

// ── Score history chart ───────────────────────────────────────────────────────
function ScoreChart({ history, meta }) {
  const W = 780, H = 260;
  const PLOT_TOP = 40, PLOT_BOTTOM = 216;
  const PLOT_LEFT = 100, PLOT_RIGHT = 740;
  const GRID_X1 = 70, GRID_X2 = 760;
  const LABEL_X = 52, XLABEL_Y = 248;
  const col = meta.accent;

  const vals = history.map(d => d.score);
  const mn = Math.min(...vals) - 2;
  const mx = Math.max(...vals) + 2;

  function xOf(i) { return PLOT_LEFT + (i / (history.length - 1)) * (PLOT_RIGHT - PLOT_LEFT); }
  function yOf(v) { return PLOT_TOP + (1 - (v - mn) / (mx - mn)) * (PLOT_BOTTOM - PLOT_TOP); }

  const linePts = history.map((d, i) => `${xOf(i)},${yOf(d.score)}`).join(" L");
  const linePath = `M${linePts}`;
  const areaPath =
    `M${xOf(0)},${yOf(history[0].score)} L` +
    history.slice(1).map((d, i) => `${xOf(i + 1)},${yOf(d.score)}`).join(" L") +
    ` L${xOf(history.length - 1)},${PLOT_BOTTOM} L${xOf(0)},${PLOT_BOTTOM} Z`;

  const yTicks = [mn + 1, Math.round((mn + mx) / 2), mx - 1];
  const gridYs = [PLOT_TOP, (PLOT_TOP + PLOT_BOTTOM) / 2 + 9, PLOT_BOTTOM - 26];

  const last = history[history.length - 1];
  const lx = xOf(history.length - 1);
  const ly = yOf(last.score);
  const pillW = 68, pillH = 32;
  const pillX = lx - 48, pillY = ly - 54;

  return (
    <svg viewBox={`0 0 ${W} ${H}`} className="cs-chart-svg" aria-label="Score history chart">
      <defs>
        <linearGradient id="csAreaFill" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={col} stopOpacity="0.34" />
          <stop offset="100%" stopColor={col} stopOpacity="0" />
        </linearGradient>
      </defs>

      <g stroke="rgba(255,255,255,0.09)" strokeWidth="1" strokeDasharray="3 6">
        {yTicks.map((v, i) => (
          <line key={i} x1={GRID_X1} y1={yOf(v)} x2={GRID_X2} y2={yOf(v)} />
        ))}
      </g>
      <g fill="#8AA3C2" fontFamily="Manrope, sans-serif" fontSize="15" fontWeight="600" textAnchor="end">
        {yTicks.map((v, i) => (
          <text key={i} x={LABEL_X} y={yOf(v) + 5}>{v}</text>
        ))}
      </g>

      <path d={areaPath} fill="url(#csAreaFill)" />
      <path d={linePath} fill="none" stroke={col} strokeWidth="3.4" strokeLinecap="round" strokeLinejoin="round" />

      <g fill="#071A33" stroke={col} strokeWidth="3.4">
        {history.slice(0, -1).map((d, i) => (
          <circle key={i} cx={xOf(i)} cy={yOf(d.score)} r="6.5" />
        ))}
        <circle cx={lx} cy={ly} r="7.5" fill={col} stroke={rgbaColor(col, 0.28)} strokeWidth="8" />
      </g>

      <g>
        <rect x={pillX} y={pillY} width={pillW} height={pillH} rx="10" fill={meta.strong} />
        <text x={pillX + pillW / 2} y={pillY + pillH / 2 + 5.5} fill="#fff" fontFamily="Manrope, sans-serif" fontSize="15" fontWeight="800" textAnchor="middle">
          {last.score}
        </text>
      </g>

      <g fill="#8AA3C2" fontFamily="Manrope, sans-serif" fontSize="15" fontWeight="600">
        {history.map((d, i) => (
          <text
            key={i}
            x={xOf(i)}
            y={XLABEL_Y}
            textAnchor={i === 0 ? "start" : i === history.length - 1 ? "end" : "middle"}
          >{d.label}</text>
        ))}
      </g>
    </svg>
  );
}

// ── Accordion item ────────────────────────────────────────────────────────────
// Controlled by the parent (open/onToggle) so the FAQ list can enforce
// "only one open at a time" — opening one item closes whichever was open.
function AccordionItem({ q, a, open, onToggle }) {
  const bodyRef = useRef(null);
  useEffect(() => {
    const el = bodyRef.current;
    if (!el) return;
    el.style.maxHeight = open ? el.scrollHeight + "px" : "0";
  }, [open]);

  return (
    <div className={"cs-faq-item" + (open ? " open" : "")}>
      <button className="cs-faq-q" onClick={onToggle} aria-expanded={open}>
        <span>{q}</span>
        <span className="cs-faq-chevron">
          <svg width="16" height="16" viewBox="0 0 20 20" fill="none" aria-hidden="true">
            <path d="M5 8l5 5 5-5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
          </svg>
        </span>
      </button>
      <div className="cs-faq-body" ref={bodyRef}>
        <div className="cs-faq-body-inner">{a}</div>
      </div>
    </div>
  );
}

// ── Score factor icons (paths match the new design exactly) ──────────────────
function IconPayment() {
  return (
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true">
      <rect x="2.5" y="5" width="19" height="14" rx="3" stroke="currentColor" strokeWidth="1.7" />
      <path d="M2.5 9.5h19" stroke="currentColor" strokeWidth="1.7" />
      <path d="M6 14h4" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" />
    </svg>
  );
}
function IconCredit() {
  return (
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true">
      <path d="M6 3h7l5 5v13a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z" stroke="currentColor" strokeWidth="1.7" />
      <path d="M13 3v5h5" stroke="currentColor" strokeWidth="1.7" />
      <path d="M8.5 13h7M8.5 16.5h4" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" />
    </svg>
  );
}
function IconUsage() {
  return (
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true">
      <circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.7" />
      <circle cx="12" cy="12" r="3.2" stroke="currentColor" strokeWidth="1.7" />
      <path d="M12 3v3.5M12 17.5V21" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" />
    </svg>
  );
}
function IconReporting() {
  return (
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true">
      <rect x="3.5" y="4.5" width="17" height="16" rx="3" stroke="currentColor" strokeWidth="1.7" />
      <path d="M8 3v3M16 3v3M8 13l2.6 2.6L16 10.5" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}
function IconArrow() {
  return (
    <svg width="15" height="15" viewBox="0 0 16 16" fill="none" aria-hidden="true">
      <path d="M3 8h9M8.5 4.5 12 8l-3.5 3.5" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

// ── Greeting (kept exactly as existing — intentionally not restyled) ─────────
function Greeting({ profile, user, loaded, serif, navy }) {
  const stateLabels = {
    declined: "Today",
    improving: "Today · 60 days post-decline",
    reeligible: "Today · 142 days post-decline",
  };
  const u = user || {};
  const apiFirst = u.first_name || (u.owner_name || "").split(" ")[0];
  const firstName = (apiFirst && apiFirst.trim())
    ? apiFirst.trim()
    : profile.business.owner.split(" ")[0];
  const bizName = getBusinessDisplayName(u);
  let line;
  if (profile.state === "declined") {
    line = (
      <h1>
        Good morning, {firstName}. Here's <span className="accent">where {bizName} stands</span> right now.
      </h1>
    );
  } else if (profile.state === "improving") {
    line = (
      <h1>
        {firstName} — the numbers <span className="accent">have moved.</span> Here's where {bizName} is today.
      </h1>
    );
  } else {
    line = (
      <h1>
        {firstName} — you'd be <span className="accent">approved today.</span> The picture changed.
      </h1>
    );
  }
  return (
    <div className={"rbi-greeting" + (serif ? " rbi-greeting-serif" : "")}>
      <div>
        <p className="rbi-greeting-eb">{stateLabels[profile.state]} · {profile.business.industry.split(" · ")[0]}</p>
        {line}
      </div>
      {/* DUNS from GET /profile. Skeleton while the call is in flight; the whole
          block is dropped if the profile failed or has no DUNS — no placeholder,
          and no orphaned "Connected ·" line under a missing number. */}
      {!loaded ? (
        <div className="rbi-greeting-meta">
          <div className="cs-skel cs-skel-line" style={{ width: 150, height: 14 }} />
          <div className="cs-skel cs-skel-line" style={{ width: 210, marginTop: 8 }} />
        </div>
      ) : u.duns ? (
        <div className="rbi-greeting-meta">
          <div><b>DUNS · {u.duns}</b></div>
          <div>Connected · last refreshed 8 minutes ago</div>
        </div>
      ) : null}
    </div>
  );
}
// ── Hero skeleton loader (while getCreditScore is in flight) ────────────────────
function HeroSkeleton() {
  return (
    <div className="cs-hero-card" aria-busy="true" aria-label="Loading credit score">
      <div className="cs-hero-left">
        <div className="cs-gauge-wrap">
          <div className="cs-skel cs-skel-gauge" />
        </div>
        <div className="cs-skel-legend">
          {Array.from({ length: 5 }, (_, i) => (
            <div key={i} className="cs-skel cs-skel-line" style={{ width: `${88 - i * 6}%` }} />
          ))}
        </div>
        <div className="cs-skel cs-skel-verdict" />
      </div>
      <div className="cs-hero-right">
        <div className="cs-skel cs-skel-line" style={{ width: "40%", height: 18 }} />
        <div className="cs-skel cs-skel-chart" />
        <div className="cs-skel cs-skel-annotation" />
      </div>
    </div>
  );
}

// ── Hero error state (with retry) ───────────────────────────────────────────────
function HeroError({ onRetry, retrying, noDuns }) {
  return (
    <div className="cs-hero-card cs-hero-error">
      <div className="cs-error-box">
        <div className="cs-error-icon" aria-hidden="true">
          <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
            strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <circle cx="12" cy="12" r="10" />
            <line x1="12" y1="8" x2="12" y2="13" />
            <line x1="12" y1="16.5" x2="12" y2="16.5" />
          </svg>
        </div>
        <p className="cs-error-title">
          {noDuns ? "No DUNS number found" : "Failed to fetch credit score"}
        </p>
        <p className="cs-error-sub">
          {noDuns
            ? "We couldn't find a DUNS number for your business, so we can't pull your business credit score yet."
            : "Something went wrong while loading your business credit score."}
        </p>
        {!noDuns && (
          <button className="cs-error-retry" onClick={onRetry} disabled={retrying}>
            {retrying ? "Retrying…" : "Retry"}
          </button>
        )}
      </div>
    </div>
  );
}

// ══ Page footer ═════════════════════════════════════════
function Footer() {
  return (
    <footer className="cs-page-footer">
      <div className="cs-footer-inner">
        <span>+1 877-662-3489 (M-F 9am – 7pm)</span>
        <div className="cs-footer-center">
          <span>©2026 Revenued (Business Intelligence)</span>
          <span className="cs-footer-sep">|</span>
          <a href="#">All Rights Reserved</a>
          <span className="cs-footer-sep">|</span>
          <a href="#">Terms of Service</a>
          <span className="cs-footer-sep">|</span>
          <a href="#" onClick={(e) => { e.preventDefault(); window.RBI_NAV("privacy"); }}>Privacy Policy</a>
        </div>
        <div className="cs-footer-social">
          <a href="https://www.youtube.com/@revenuedcard" aria-label="YouTube" className="cs-footer-icon" target="_blank" rel="noopener noreferrer">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M21.6 7.2a2.6 2.6 0 0 0-1.8-1.8C18 5 12 5 12 5s-6 0-7.8.4A2.6 2.6 0 0 0 2.4 7.2C2 9 2 12 2 12s0 3 .4 4.8a2.6 2.6 0 0 0 1.8 1.8C6 19 12 19 12 19s6 0 7.8-.4a2.6 2.6 0 0 0 1.8-1.8C22 15 22 12 22 12s0-3-.4-4.8ZM10 15.5v-7l6 3.5-6 3.5Z" /></svg>
          </a>
          <a href="https://www.facebook.com/revenued/" aria-label="Facebook" className="cs-footer-icon" target="_blank" rel="noopener noreferrer">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M13.5 21v-8h2.8l.4-3.2h-3.2V7.8c0-.9.3-1.5 1.6-1.5h1.7V3.4c-.3 0-1.3-.1-2.5-.1-2.5 0-4.2 1.5-4.2 4.3v2.2H7.3V13h2.8v8h3.4Z" /></svg>
          </a>
          <a href="https://www.linkedin.com/company/revenued" aria-label="LinkedIn" className="cs-footer-icon" target="_blank" rel="noopener noreferrer">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5ZM3 21h4V9.5H3V21Zm7 0h4v-6.2c0-1.6 1-2.3 2-2.3s1.9.8 1.9 2.3V21h4v-6.8c0-3.4-1.9-5-4.4-5-1.7 0-2.7.9-3.2 1.7V9.5h-4V21Z" /></svg>
          </a>
          <a href="https://www.instagram.com/revenuedcard/" aria-label="Instagram" className="cs-footer-icon" target="_blank" rel="noopener noreferrer">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.2c-2.7 0-3 0-4.1.06-1 .05-1.7.2-2.3.44a4.6 4.6 0 0 0-1.7 1.1 4.6 4.6 0 0 0-1.1 1.7c-.24.6-.4 1.3-.44 2.3C2.2 9 2.2 9.3 2.2 12s0 3 .06 4.1c.05 1 .2 1.7.44 2.3a4.6 4.6 0 0 0 1.1 1.7 4.6 4.6 0 0 0 1.7 1.1c.6.24 1.3.4 2.3.44 1.1.06 1.4.06 4.1.06s3 0 4.1-.06c1-.05 1.7-.2 2.3-.44a4.9 4.9 0 0 0 2.8-2.8c.24-.6.4-1.3.44-2.3.06-1.1.06-1.4.06-4.1s0-3-.06-4.1c-.05-1-.2-1.7-.44-2.3a4.6 4.6 0 0 0-1.1-1.7 4.6 4.6 0 0 0-1.7-1.1c-.6-.24-1.3-.4-2.3-.44C15 2.2 14.7 2.2 12 2.2Zm0 4.8a5 5 0 1 1 0 10 5 5 0 0 1 0-10Zm0 1.8a3.2 3.2 0 1 0 0 6.4 3.2 3.2 0 0 0 0-6.4Zm5.2-3a1.2 1.2 0 1 1 0 2.4 1.2 1.2 0 0 1 0-2.4Z" /></svg>
          </a>
          <a href="https://twitter.com/revenuedcard" aria-label="X / Twitter" className="cs-footer-icon" target="_blank" rel="noopener noreferrer">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M17.5 3h3l-6.6 7.6L21.8 21h-5.4l-4.2-5.5L7 21H4l7-8L2.6 3H8l4 5.2L17.5 3Z" /></svg>
          </a>
        </div>
      </div>
    </footer>
  );
}

// ── Main App ──────────────────────────────────────────────────────────────────
function App() {
  const scenario = window.useScenario();
  const profile = window.RBI_PROFILES[scenario] || window.RBI_PROFILES.declined;

  // ── Live credit score (getCreditScore) ──────────────────────────────────
  // Real API data only — no mock score / history. Shows skeleton while loading
  // and the existing empty/error states when there is no DUNS or the call fails.
  //
  // DUNS comes from GET /v1/bi/profile (`duns_number`), fetched at login. While
  // that call is in flight the profile is `{}`, so we hold the loading state
  // rather than deciding there is no DUNS; once it lands the effect re-runs.
  const [user, profileLoaded] = useProfile();
  const CREDIT_SCORE_DUNS = user.duns || "";
  const noDuns = profileLoaded && !CREDIT_SCORE_DUNS;
  const [creditData, setCreditData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(false);

  // ── FAQ accordion — single-open group. Only one item is expanded at a
  // time; opening one closes whichever was open (matches the design's
  // defaultFaqOpen: first item starts open, -1 means "all closed").
  const [openFaq, setOpenFaq] = useState(0);

  const fetchCreditScore = React.useCallback(() => {
    // Profile still loading — stay in the skeleton, the effect re-runs on arrival.
    if (!CREDIT_SCORE_DUNS && !profileLoaded) {
      setLoading(true);
      setError(false);
      setCreditData(null);
      return;
    }
    // No DUNS on file — nothing to fetch; surface the "no DUNS found" state.
    if (!CREDIT_SCORE_DUNS) {
      setLoading(false);
      setError(false);
      setCreditData(null);
      return;
    }
    setLoading(true);
    setError(false);
    setCreditData(null);
    const loginDate = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
    return window.RBI_API
      .getCreditScore({ duns: CREDIT_SCORE_DUNS, loginDate })
      .then((res) => {
        if (res.ok && res.data && res.data.power_score != null) {
          setCreditData(res.data);
        } else {
          setError(true);
        }
      })
      .catch(() => setError(true))
      .finally(() => setLoading(false));
  }, [CREDIT_SCORE_DUNS, profileLoaded]);

  useEffect(() => { fetchCreditScore(); }, [fetchCreditScore]);

  // Score + risk band come only from the live API response.
  const sbfeScore = creditData && creditData.power_score != null
    ? Number(creditData.power_score)
    : null;
  const rangeMeta = sbfeScore != null ? getRangeMeta(sbfeScore) : null;

  // Score history — only real API history (no fabricated prior months).
  const scoreHistory = useMemo(() => {
    if (!creditData) return [];
    const raw = creditData.score_history || creditData.history || creditData.scoreHistory;
    if (!Array.isArray(raw) || !raw.length) return [];
    return raw
      .map(function (row) {
        const score = Number(row.score != null ? row.score : row.power_score);
        if (score == null || isNaN(score)) return null;
        const label = row.label || row.month || row.period || row.date || "";
        return { label: String(label), score: score };
      })
      .filter(Boolean);
  }, [creditData]);

  const scoreUpdatedLabel = useMemo(() => {
    if (!creditData) return "";
    const raw = creditData.updated_on || creditData.updatedOn || creditData.as_of || creditData.asOf;
    if (raw) {
      const d = new Date(raw);
      if (!isNaN(d.getTime())) {
        return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
      }
      return String(raw);
    }
    return new Date().toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
  }, [creditData]);

  const scorePeriodLabel = useMemo(() => {
    return new Date().toLocaleDateString("en-US", { month: "short", year: "numeric" }).replace(" ", "-");
  }, []);

  // Verdict copy driven by risk band
  const verdictLabel = useMemo(() => {
    if (!rangeMeta) return "";
    const label = rangeMeta.label.toLowerCase();
    if (label.includes("high risk") && !label.includes("moderate")) return "a high risk credit score";
    if (label.includes("moderate – high")) return "a moderate-high credit score";
    if (label.includes("moderate risk")) return "a moderate credit score";
    if (label.includes("low – moderate")) return "a low-moderate credit score";
    return "a low risk credit score";
  }, [rangeMeta]);

  // Reasons come only from the live getCreditScore response.
  const verdictBullets = useMemo(() => {
    if (!creditData) return [];
    return [creditData.reason_1, creditData.reason_2, creditData.reason_3].filter(Boolean);
  }, [creditData]);
  // Matches the new design's visual pattern: first two reasons carry the
  // primary risk-band accent, the third uses the secondary amber tone.
  const bulletDotColors = rangeMeta
    ? [rangeMeta.accent, rangeMeta.accent, "#F5C13D"]
    : ["#F5C13D", "#F5C13D", "#F5C13D"];

  // const SCORE_FACTORS = [
  //   {
  //     icon: <IconPayment />,
  //     title: "Payment history",
  //     body: "Paying your business expenses on time (or early) is a major factor in your business credit score. Doing so will help establish your business credit profile.",
  //   },
  //   {
  //     icon: <IconCredit />,
  //     title: "Types of credit",
  //     body: "Not all business credit sources report trade lines and lines of credit to credit bureaus. Utilizing sources of financing that report to credit bureaus (like Revenued does to Dun & Bradstreet) is a must in order to build business credit.",
  //   },
  //   {
  //     icon: <IconUsage />,
  //     title: "Responsible credit usage",
  //     body: "Utilize the credit your business has access to regularly and responsibly by paying amounts due on time. Most bureaus recommend keeping your total utilization below 30% to maintain a better score.",
  //   },
  //   {
  //     icon: <IconReporting />,
  //     title: "Accurate reporting",
  //     body: "Continually checking your business credit score for changes and updates will help keep you on the right path to build your business credit profile. If you notice inaccuracies, you can request updates for free through Dun & Bradstreet.",
  //   },
  // ];

  // const FAQ_ITEMS = [
  //   {
  //     q: "What does my score mean?",
  //     a: (
  //       <div>
  //         <p>Your score is an indicator of the risk your business is perceived to be at of potentially making a late financial services payment over the next 12 months. Risk level changes depending on where your SBFE score falls:</p>
  //         <ul>
  //           {SCORE_RANGES.map((r, i) => (
  //             <li key={i}>
  //               <span className="cs-faq-range-dot" style={{ background: r.dot }} />
  //               {r.min}–{r.max}: {r.label}
  //             </li>
  //           ))}
  //         </ul>
  //       </div>
  //     ),
  //   },
  //   {
  //     q: "Why is it important I maintain a good business credit score?",
  //     a: <p>A strong business credit score unlocks better financing terms, higher credit limits, and more lender options. It can also affect supplier payment terms and insurance premiums.</p>
  //   },
  //   {
  //     q: "How does a business credit score differ from a personal credit score?",
  //     a: <p>Business credit scores are typically on a 706–999 scale (SBFE/D&B) while personal scores use 300–850 (FICO/VantageScore). Business scores are tied to your EIN, not your SSN, and are built through business tradelines and commercial activity.</p>
  //   },
  //   {
  //     q: "How often will my D&B SBFE Score change?",
  //     a: <p>Your SBFE score is updated as new data is reported by lenders and creditors, typically on a monthly cycle. Significant events like late payments or new credit can cause faster changes.</p>
  //   },
  //   {
  //     q: "Will viewing my score in Revenued affect my business credit score?",
  //     a: <p>No. Viewing your own score is considered a "soft pull" and does not affect your business credit score in any way.</p>
  //   },
  //   {
  //     q: "Who uses this score?",
  //     a: <p>Financial institutions, lenders, suppliers, and vendors may review your SBFE score when evaluating credit applications, payment terms, or business relationships.</p>
  //   },
  //   {
  //     q: "How are these scores calculated and what do they measure?",
  //     a: <p>The SBFE score is calculated by Dun & Bradstreet using data from SBFE member institutions. It weighs payment history, utilization, account age, and public records to predict the likelihood of a late payment in the next 12 months.</p>
  //   },
  //   {
  //     q: "How do I manage my business credit scores?",
  //     a: <p>Pay bills on time, keep utilization low, use credit sources that report to bureaus, and regularly monitor your score for inaccuracies. You can dispute errors directly with Dun & Bradstreet at no charge.</p>
  //   },
  // ];

  // Articles — same 8 pieces of content as before, remapped onto the new
  // design's layout: 1 dark feature card, a 3-up row, then a bordered list.
  const ARTICLE_CARDS = [
    {
      tag: "BUILD CREDIT",
      num: "01",
      title: "Everything You Need to Do to Build & Establish Business Credit",
      excerpt: "Good business credit is just as important for your company as having a high personal credit score is…",
      link: "https://www.revenued.com/business-credit",
    },
    {
      tag: "GETTING STARTED",
      num: "02",
      title: "How Do I Establish Business Credit for the First Time?",
      excerpt: "Entrepreneurs face tremendous challenges when attempting to start a new business. Many run out of…",
      link: "https://www.revenued.com/business-credit",
    },
    {
      tag: "REPORTING",
      num: "03",
      title: "How to Read a Business Credit Report",
      excerpt: "Most small business owners are familiar with the process of applying for the funds they need in orde…",
      link: "https://www.revenued.com/articles/business-credit/how-to-read-a-business-credit-report",
    },
  ];

  const ARTICLE_ROWS = [
    {
      num: "04",
      title: "What is Your Business Credit Score Used for?",
      excerpt: "If you are a new small business owner, chances are you haven't built up any business credit yet so…",
      link: "https://www.revenued.com/business-credit",
    },
    {
      num: "05",
      title: "How is Business Credit Score Calculated?",
      excerpt: "Bank loans, credit cards, and lines of credit can bolster your working capital, giving you resources…",
      link: "https://www.revenued.com/business-credit",
    },
    {
      num: "06",
      title: "What is a Business Credit Score and Why Does it Matter?",
      excerpt: "Your business credit score can be the make-or-break factor when you're applying for a business loan…",
      link: "https://www.revenued.com/business-credit",
    },
    {
      num: "07",
      title: "Business Credit VS. Personal Credit: What's The Difference?",
      excerpt: "If you are a new small business owner, chances are you haven't built up any business credit yet so…",
      link: "https://www.revenued.com/business-credit",
    },
  ];

  return (
    <div className="rbi-app">
      {/* Topbar */}
      <window.RBITopbar
        business={{
          ...profile.business,
          name: getBusinessDisplayName(user),
          owner: getOwnerDisplayName(profile.business.owner, user),
          city: getCityDisplay("", user),
          duns: user.duns || "",
          dunsLoading: !profileLoaded,
          // The account chip is DUNS-driven here; blank out the mock bank so a
          // failed profile shows nothing rather than falling back to it.
          bank: "",
        }}
        activeView="creditscore"
        onTweaks={() => window.postMessage({ type: "__activate_edit_mode" }, "*")}
      />

      {/* Breadcrumb bar */}
      <div className="cs-breadbar" style={{ display: "none" }}>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none"
          stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"
          strokeLinejoin="round" style={{ color: "rgba(255,255,255,0.55)", flexShrink: 0 }}>
          <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
          <polyline points="9 22 9 12 15 12 15 22" />
        </svg>
        <svg width="12" height="12" viewBox="0 0 24 24" fill="none"
          stroke="currentColor" strokeWidth="2" strokeLinecap="round"
          strokeLinejoin="round" style={{ color: "rgba(255,255,255,0.35)", flexShrink: 0 }}>
          <polyline points="9 18 15 12 9 6" />
        </svg>
        <span className="cs-breadbar-label">My Business Credit Score</span>
      </div>

      {/* ── Greeting (keep as-is per requirement) ─────────────── */}
      <div className="rbi-body cs-greeting-wrap">
        <Greeting profile={profile} user={user} loaded={profileLoaded} serif={true} navy={false} />
      </div>

      <div className="rbi-body cs-page">

        {/* ══ Section 1: Hero — real API score only; else empty/error states ══ */}
        {loading ? (
          <HeroSkeleton />
        ) : noDuns ? (
          <HeroError noDuns />
        ) : error || !creditData || sbfeScore == null || !rangeMeta ? (
          <HeroError onRetry={fetchCreditScore} retrying={loading} />
        ) : (
          <div className="cs-hero-card">

            {/* Left — gauge + legend + verdict */}
            <div className="cs-hero-left">
              <span className="cs-gauge-eyebrow">D&amp;B SBFE BUSINESS CREDIT SCORE</span>

              <div className="cs-gauge-wrap">
                <RadialGauge value={sbfeScore} meta={rangeMeta} />
                <div className="cs-gauge-center">
                  <span className="cs-gauge-score">{sbfeScore}</span>
                  <span
                    className="cs-gauge-badge"
                    style={{
                      background: rgbaColor(rangeMeta.accent, 0.16),
                      border: `1px solid ${rgbaColor(rangeMeta.accent, 0.34)}`,
                      color: rangeMeta.textTint,
                    }}
                  >{rangeMeta.label.toUpperCase()}</span>
                </div>
              </div>

              <div className="cs-gauge-scale">
                <span>{SCORE_MIN}</span>
                <span>{SCORE_MAX}</span>
              </div>

              {/* Risk band legend */}
              <div className="cs-risk-legend">
                {SCORE_RANGES.map((rb, i) => (
                  <div key={i} className="cs-risk-row">
                    <span className="cs-risk-dot" style={{ background: rb.dot }} />
                    <span className="cs-risk-range">{rb.min}–{rb.max}</span>
                    <span className="cs-risk-label">{rb.label}</span>
                  </div>
                ))}
              </div>

              {/* Verdict chip */}
              <div
                className="cs-verdict"
                style={{
                  background: rgbaColor(rangeMeta.accent, 0.09),
                  border: `1px solid ${rgbaColor(rangeMeta.accent, 0.24)}`,
                }}
              >
                <div className="cs-verdict-top">
                  <span className="cs-verdict-badge" style={{ background: rangeMeta.strong }}>
                    {rangeMeta.label.toUpperCase()}
                  </span>
                  <span className="cs-verdict-date">Updated on {scoreUpdatedLabel}</span>
                </div>
                <p className="cs-verdict-title">You have {verdictLabel}</p>
                <a
                  href="#factors"
                  className="cs-verdict-link"
                  style={{ color: rangeMeta.textTint, borderBottomColor: rgbaColor(rangeMeta.accent, 0.4) }}
                  onClick={e => { e.preventDefault(); document.getElementById("cs-factors").scrollIntoView({ behavior: "smooth" }); }}
                >
                  Check below to learn more about your business credit score →
                </a>
              </div>
            </div>

            {/* Right — chart + annotation */}
            <div className="cs-hero-right">
              <div className="cs-chart-header">
                <div className="cs-chart-header-text">
                  <span className="cs-chart-eyebrow">SCORE HISTORY</span>
                  <h2 className="cs-chart-title">SBFE Business Credit Score</h2>
                </div>
                <div className="cs-chart-tabs">
                  <span className="cs-chart-tab">Overall</span>
                </div>
              </div>

              <div className="cs-chart-wrap">
                {scoreHistory.length >= 2 ? (
                  <ScoreChart history={scoreHistory} meta={rangeMeta} />
                ) : (
                  <div className="cs-error-box" style={{ margin: "24px auto", minHeight: 180, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }}>
                    <p className="cs-error-title">Score history not available</p>
                    <p className="cs-error-sub">Historical score data is not available for this business yet.</p>
                  </div>
                )}
              </div>

              {/* Current period annotation */}
              <div className="cs-chart-annotation">
                <div className="cs-annotation-header">
                  <span className="cs-annotation-date">
                    {scorePeriodLabel} · {sbfeScore} Credit Score
                  </span>
                  <span
                    className="cs-annotation-band"
                    style={{
                      background: rgbaColor(rangeMeta.accent, 0.16),
                      border: `1px solid ${rgbaColor(rangeMeta.accent, 0.3)}`,
                      color: rangeMeta.textTint,
                    }}
                  >{rangeMeta.label.toUpperCase()}</span>
                </div>
                <div className="cs-annotation-bullets">
                  {verdictBullets.map((b, i) => (
                    <div key={i} className="cs-annotation-bullet">
                      <span className="cs-annotation-bullet-dot" style={{ background: bulletDotColors[i] || rangeMeta.accent }} />
                      <p>{b}</p>
                    </div>
                  ))}
                </div>
              </div>
            </div>
          </div>
        )}

        {/* ══ Section 2: Score Factors ═════════════════════════════ */}
        {/* <section id="cs-factors" className="cs-section">
          <div className="cs-section-head-row">
            <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
              <span className="cs-section-rule" />
              <h2 className="cs-section-title">What Goes Into Your Business Credit Score</h2>
            </div>
            <p className="cs-section-desc">Understanding the factors that influence your score helps you take targeted action to improve it over time.</p>
          </div>
          <div className="cs-factors-grid">
            {SCORE_FACTORS.map((f, i) => (
              <div key={i} className="cs-factor-card">
                <div className="cs-factor-icon-wrap">{f.icon}</div>
                <h3 className="cs-factor-title">{f.title}</h3>
                <p className="cs-factor-text">{f.body}</p>
              </div>
            ))}
          </div>
        </section> */}

        {/* ══ Section 3: FAQ ═══════════════════════════════════════ */}
        {/* <section className="cs-section">
          <div className="cs-section-head-col">
            <span className="cs-section-rule" />
            <h2 className="cs-section-title">Business Credit Frequently Asked Questions</h2>
          </div>
          <div className="cs-faq-card">
            {FAQ_ITEMS.map((item, i) => (
              <AccordionItem
                key={i}
                q={item.q}
                a={item.a}
                open={openFaq === i}
                onToggle={() => setOpenFaq(prev => (prev === i ? -1 : i))}
              />
            ))}
          </div>
        </section> */}

        {/* ══ Section 4: Articles ══════════════════════════════════ */}
        <section className="cs-section">
          <div className="cs-section-head-col">
            <span className="cs-section-rule" />
            <h2 className="cs-section-title">More About Business Credit From Revenued</h2>
          </div>

          <div className="cs-articles-wrap">
            {/* Featured dark hero card */}
            <article className="cs-article-feature">
              <div className="cs-article-feature-body">
                <div className="cs-article-feature-tags">
                  <span className="cs-article-feature-tag">FEATURED GUIDE</span>
                  <span className="cs-article-feature-sub">Business credit basics</span>
                </div>
                <h3 className="cs-article-feature-title">Understand Your Business Credit Score</h3>
                <p className="cs-article-feature-text">Every individual has a credit score that reflects their likelihood of repaying debt, but did you kno…</p>
                <a
                  href="https://www.revenued.com/business-credit"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="cs-article-feature-cta"
                >
                  Read More <IconArrow />
                </a>
              </div>
              <div className="cs-article-feature-img">
                <img src="design-system/images/credit-hero-illustration.webp" alt="" />
              </div>
            </article>

            {/* 3-up card row */}
            <div className="cs-articles-row3">
              {ARTICLE_CARDS.map((c, i) => (
                <a key={i} href={c.link} target="_blank" rel="noopener noreferrer" className="cs-article-card">
                  <div className="cs-article-card-top">
                    <span className="cs-article-card-tag">{c.tag}</span>
                    <span className="cs-article-card-num">{c.num}</span>
                  </div>
                  <h4>{c.title}</h4>
                  <p>{c.excerpt}</p>
                  <span className="cs-article-card-link">Read More →</span>
                </a>
              ))}
            </div>

            {/* Bordered list rows */}
            <div className="cs-articles-list">
              {ARTICLE_ROWS.map((r, i) => (
                <a key={i} href={r.link} target="_blank" rel="noopener noreferrer" className="cs-article-row">
                  <span className="cs-article-row-num">{r.num}</span>
                  <h4>{r.title}</h4>
                  <p>{r.excerpt}</p>
                  <span className="cs-article-row-arrow"><IconArrow /></span>
                </a>
              ))}
            </div>
          </div>
        </section>

        {/* ══ Disclaimer ══════════════════════════════════════════ */}
        <div className="cs-disclaimer">
          <p><em>Note: Revenued is not a credit repair organization as defined under federal or state law, including the Credit Repair Organizations Act. Revenued does not provide "credit repair" services or advice or assistance regarding "rebuilding" or "improving" your credit record, credit history or credit rating.</em></p>
          <p><em>Revenued provided your Dun &amp; Bradstreet business credit scores in the Revenued Portal for educational purposes. Revenued cannot provide assistance regarding improving your credit scores except for addressing any disputes you may have regarding accounts you have with Revenued.</em></p>
        </div>

      </div>{/* end .rbi-body */}

      {/* ══ Page footer ═════════════════════════════════════════ */}
      <Footer />

      {/* Tweaks panel */}
      <TweaksPanel>
        <TweakSection label="Scenario" />
        <TweakSelect
          label="Business state"
          value={scenario}
          options={[
            { value: "declined", label: "Declined · High Risk score" },
            { value: "improving", label: "Healthy & improving · Moderate score" },
            { value: "reeligible", label: "Re-eligible · Low Risk score" },
          ]}
          onChange={(v) => window.RBI_STATE.set(v)}
        />
      </TweaksPanel>
    </div>
  );
}

window.HomeApp = App;