
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="robots" content="noindex,nofollow">
<title>The Fault Line Diagnostic — Travillian</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,400;0,500;0,600;0,700;0,800;1,400&display=swap" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<style>
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{
  --navy:#1a2e4a;--navy-dk:#0f1d30;--bg:#f5f7fa;--surf:#ffffff;
  --border:#dde3ea;--text:#1e293b;--muted:#64748b;--light:#94a3b8;
  --accent:#2563eb;
  --g:#15803d;--g-bg:#f0fdf4;--g-bd:#bbf7d0;
  --y:#a16207;--y-bg:#fefce8;--y-bd:#fde68a;
  --o:#c2410c;--o-bg:#fff7ed;--o-bd:#fed7aa;
  --r:#b91c1c;--r-bg:#fef2f2;--r-bd:#fecaca;
}
body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.6;min-height:100vh}
.wrap{max-width:720px;margin:0 auto;padding:0 20px}

/* Header */
.hdr{background:var(--navy);padding:14px 0}
.hdr-inner{display:flex;align-items:center;justify-content:space-between;max-width:720px;margin:0 auto;padding:0 20px}
.hdr-logo{height:28px;filter:brightness(0) invert(1);opacity:.9}
.hdr-label{font-size:12px;color:#94a3b8;font-weight:500;letter-spacing:.02em}

/* Progress */
.prog-wrap{background:#e2e8f0;height:3px}
.prog-fill{height:100%;background:var(--accent);transition:width .5s ease}

/* Main */
.main{padding:40px 0 80px}

/* Screens */
.screen{display:none}
.screen.active{display:block;animation:fadeUp .25s ease}
@keyframes fadeUp{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}

/* Cards */
.card{background:var(--surf);border:1px solid var(--border);border-radius:12px;padding:32px;margin-bottom:24px}

/* Intro */
.intro-logo-wrap{text-align:center;margin-bottom:28px}
.intro-logo{height:36px}
.intro-title{font-size:26px;font-weight:800;color:var(--navy);line-height:1.25;margin-bottom:8px;text-align:center}
.intro-tagline{font-size:14px;color:var(--muted);text-align:center;margin-bottom:28px}
.intro-divider{border:none;border-top:1px solid var(--border);margin:24px 0}
.intro-quote{border-left:3px solid var(--navy);padding-left:18px;font-size:14px;color:var(--text);line-height:1.7;margin:0 0 20px}
.intro-cite{font-size:11px;color:var(--light);font-style:italic;line-height:1.5}
.intro-meta{display:flex;gap:24px;margin-top:24px;flex-wrap:wrap}
.intro-meta-item{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--muted)}
.intro-meta-item strong{color:var(--text);font-weight:600}

/* Buttons */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:13px 24px;border-radius:8px;font-weight:600;font-size:14px;cursor:pointer;border:none;transition:all .15s ease;text-decoration:none;font-family:inherit}
.btn-primary{background:var(--navy);color:#fff}
.btn-primary:hover{background:var(--navy-dk)}
.btn-primary:disabled{background:#cbd5e1;cursor:not-allowed;color:#94a3b8}
.btn-ghost{background:transparent;color:var(--muted);border:1px solid var(--border)}
.btn-ghost:hover{background:var(--bg);color:var(--text)}
.btn-block{width:100%}
.btn-lg{padding:16px 32px;font-size:16px}

/* Step indicator */
.step-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}
.step-badge{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--accent);background:#eff6ff;padding:4px 10px;border-radius:20px}
.step-count{font-size:13px;color:var(--muted)}

/* Section */
.sec-title{font-size:20px;font-weight:700;color:var(--navy);margin-bottom:10px}
.sec-ctx{font-size:13px;color:var(--muted);background:#f8fafc;border-left:3px solid #cbd5e1;padding:14px 16px;border-radius:0 6px 6px 0;margin-bottom:28px;line-height:1.65}

/* Questions */
.q-block{margin-bottom:28px}
.q-text{font-size:15px;font-weight:600;color:var(--text);margin-bottom:12px;line-height:1.4}
.options{display:flex;flex-direction:column;gap:7px}
.opt{display:flex;align-items:flex-start;gap:12px;padding:12px 14px;border:1.5px solid var(--border);border-radius:8px;cursor:pointer;transition:all .13s ease;font-size:13.5px;color:var(--text);user-select:none}
.opt:hover{border-color:#94a3b8;background:#f8fafc}
.opt.sel{border-color:var(--navy);background:#eff6ff;color:var(--navy);font-weight:500}
.opt input[type=radio]{width:16px;height:16px;margin-top:2px;flex-shrink:0;accent-color:var(--navy)}

/* Nav */
.nav-row{display:flex;justify-content:space-between;align-items:center;margin-top:28px;gap:12px}
.nav-row .btn{min-width:110px}

/* Intake */
.q-select{width:100%;padding:11px 14px;border:1.5px solid var(--border);border-radius:8px;font-size:14px;font-family:inherit;color:var(--text);background:var(--surf);cursor:pointer;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 12px center}
.q-select:focus{outline:none;border-color:var(--navy)}

/* Results */
.score-hero{text-align:center;padding:40px 32px;border-radius:12px;margin-bottom:24px}
.score-num{font-size:80px;font-weight:800;line-height:1;margin-bottom:6px}
.score-label{font-size:20px;font-weight:700;margin-bottom:14px}
.score-copy{font-size:14px;line-height:1.6;max-width:500px;margin:0 auto;opacity:.9}

/* Chart */
.chart-title{font-size:16px;font-weight:700;color:var(--navy);margin-bottom:18px}
.dim-row{display:flex;align-items:center;gap:12px;margin-bottom:13px}
.dim-name{font-size:12.5px;font-weight:500;color:var(--text);width:200px;flex-shrink:0;line-height:1.3}
.dim-track{flex:1;background:#f1f5f9;height:26px;border-radius:4px;overflow:hidden;position:relative}
.dim-bar{height:100%;border-radius:4px;display:flex;align-items:center;justify-content:flex-end;padding-right:8px;transition:width .9s ease;min-width:32px}
.dim-bar-score{font-size:11px;font-weight:700;color:rgba(0,0,0,.5)}
.dim-score-out{font-size:13px;font-weight:700;min-width:38px;text-align:right}

/* Weakest */
.weakest-card{padding:22px;border-radius:10px;margin-bottom:24px}
.weakest-eyebrow{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.1em;margin-bottom:6px}
.weakest-name{font-size:17px;font-weight:700;margin-bottom:10px}
.weakest-framing{font-size:13px;font-style:italic;margin-bottom:10px;opacity:.75}
.weakest-ctx{font-size:13px;line-height:1.65;opacity:.88}

/* Conversations */
.convos-header{margin-bottom:18px}
.convos-title{font-size:18px;font-weight:700;color:var(--navy);margin-bottom:4px}
.convos-sub{font-size:13px;color:var(--muted)}
.convo-card{border:1.5px solid var(--border);border-radius:10px;padding:18px 20px;margin-bottom:11px}
.convo-num{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--accent);margin-bottom:4px}
.convo-dim{font-size:11px;font-weight:600;color:var(--muted);margin-bottom:8px}
.convo-text{font-size:14.5px;font-weight:500;color:var(--text);line-height:1.55}

/* Info gap */
.gap-banner{background:#fff8f0;border:1px solid var(--o-bd);border-radius:8px;padding:14px 16px;margin-bottom:20px;font-size:13px;color:#92400e}
.gap-banner strong{display:block;font-weight:700;margin-bottom:3px}

/* Lead capture / Email section */
.email-sec-title{font-size:18px;font-weight:700;color:var(--navy);margin-bottom:4px}
.email-sec-sub{font-size:13px;color:var(--muted);margin-bottom:22px}
.pdf-btn-wrap{margin-bottom:24px}
.lead-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:16px}
.lead-field label{display:block;font-size:12px;font-weight:600;color:var(--text);margin-bottom:6px}
.lead-field input{width:100%;padding:11px 14px;border:1.5px solid var(--border);border-radius:8px;font-size:14px;font-family:inherit;color:var(--text);transition:border-color .15s;background:var(--surf)}
.lead-field input:focus{outline:none;border-color:var(--navy)}
.lead-field input.invalid{border-color:#ef4444;background:#fef2f2}
.lead-error{background:#fef2f2;border:1px solid #fecaca;color:#b91c1c;padding:10px 14px;border-radius:8px;font-size:13px;margin-bottom:14px}
.lead-teaser-note{display:flex;align-items:center;gap:10px;padding:14px 16px;background:#eff6ff;border:1px solid #bfdbfe;border-radius:8px;font-size:13px;color:#1e40af;margin-bottom:20px;line-height:1.5}
.lead-teaser-note::before{content:'\1F512';font-size:16px;flex-shrink:0}
input[type=email],input[type=text]{padding:11px 14px;border:1.5px solid var(--border);border-radius:8px;font-size:14px;font-family:inherit;color:var(--text);transition:border-color .15s;background:var(--surf)}
input[type=email]:focus,input[type=text]:focus{outline:none;border-color:var(--navy)}
.chk-label{display:flex;align-items:flex-start;gap:10px;font-size:13px;color:var(--text);cursor:pointer;margin-top:14px;line-height:1.5}
.chk-label input{width:16px;height:16px;flex-shrink:0;margin-top:2px;accent-color:var(--navy)}
.disclosure{font-size:11px;color:var(--light);margin-top:12px;line-height:1.55}
.confirm-msg{text-align:center;padding:20px;background:var(--g-bg);border:1px solid var(--g-bd);border-radius:8px;color:var(--g);font-weight:600;font-size:14px;display:none;margin-bottom:24px}

/* Footer */
.results-footer{font-size:11.5px;color:var(--light);border-top:1px solid var(--border);padding-top:18px;margin-top:28px;line-height:1.6}
.results-footer a{color:var(--light)}

/* PDF hidden render area */
#pdf-stage{position:fixed;left:-9999px;top:0;width:780px;padding:48px 52px;background:#fff;font-family:'Inter',system-ui,sans-serif;color:#1e293b;font-size:11px;line-height:1.5}

@media(max-width:600px){
  .card{padding:20px}
  .intro-title{font-size:20px}
  .score-num{font-size:60px}
  .dim-name{width:130px;font-size:11.5px}
  .nav-row{flex-wrap:wrap}
  .nav-row .btn{flex:1}
  .lead-grid{grid-template-columns:1fr}
  .intro-meta{gap:12px}
}
</style>
</head>
<body>

<header class="hdr">
  <div class="hdr-inner">
    <img src="https://travilliangroup.com/wp-content/uploads/2023/03/Travillian-Logo_2021.png" alt="Travillian" class="hdr-logo" id="hdrLogo" crossorigin="anonymous">
    <span class="hdr-label">The Fault Line Diagnostic</span>
  </div>
</header>
<div class="prog-wrap"><div class="prog-fill" id="progFill" style="width:0%"></div></div>

<main class="main">
  <div class="wrap">

    <!-- INTRO -->
    <div class="screen active" id="screen-intro">
      <div class="card">
        <div class="intro-logo-wrap">
          <img src="https://travilliangroup.com/wp-content/uploads/2023/03/Travillian-Logo_2021.png" alt="Travillian" class="intro-logo" style="display:block;margin:0 auto 20px">
          <h1 class="intro-title">The Fault Line Diagnostic<br>for Bank/Fintech Partnerships</h1>
          <p class="intro-tagline">A partnership readiness assessment from Travillian</p>
        </div>
        <hr class="intro-divider">
        <blockquote class="intro-quote">
          Bank/fintech partnerships are increasingly central to bank strategy — but they fail at an alarming rate. According to the EY-Parthenon 2022 U.S. Banking Strategic Partnership survey, about 40% of all bank partnerships fail to operationalize, mostly due to ineffective strategies, scalability issues, and poor organizational alignment.
          <br><br>
          This diagnostic helps you pressure-test a specific partnership — whether you're exploring, in diligence, or already live — across the five dimensions where partnerships most commonly break down. The output isn't a verdict. It's a set of questions you should be asking.
        </blockquote>
        <p class="intro-cite">Source: EY-Parthenon, "How Banks Can Fix Broken Fintech Partnership Models," 2023. Based on the EY-Parthenon 2022 U.S. Banking Strategic Partnership Survey.</p>
        <hr class="intro-divider">
        <div class="intro-meta">
          <div class="intro-meta-item"><strong>23 questions</strong><span>across 5 dimensions</span></div>
          <div class="intro-meta-item"><strong>6–8 minutes</strong><span>to complete</span></div>
          <div class="intro-meta-item"><strong>Scored results</strong><span>with actionable output</span></div>
        </div>
        <div style="margin-top:28px">
          <button class="btn btn-primary btn-block btn-lg" onclick="startAssessment()">Start Assessment →</button>
        </div>
      </div>
    </div>

    <!-- INTAKE -->
    <div class="screen" id="screen-intake">
      <div class="card">
        <div class="step-row">
          <span class="step-badge">Partnership Context</span>
          <span class="step-count">Step 1 of 7</span>
        </div>
        <h2 class="sec-title">A few questions to frame your results</h2>
        <p class="sec-ctx">These questions help us tailor your results narrative. They do not affect your score.</p>
        <div id="intake-questions"></div>
        <div class="nav-row">
          <button class="btn btn-ghost" onclick="goBack()">← Back</button>
          <button class="btn btn-primary" id="intake-next" onclick="nextFromIntake()" disabled>Next →</button>
        </div>
      </div>
    </div>

    <!-- SECTION SCREENS (1-5) -->
    <div class="screen" id="screen-section">
      <div class="card">
        <div class="step-row">
          <span class="step-badge" id="sec-badge"></span>
          <span class="step-count" id="sec-count"></span>
        </div>
        <h2 class="sec-title" id="sec-title"></h2>
        <p class="sec-ctx" id="sec-ctx"></p>
        <div id="sec-questions"></div>
        <div class="nav-row">
          <button class="btn btn-ghost" onclick="goBack()">← Back</button>
          <button class="btn btn-primary" id="sec-next" onclick="nextSection()" disabled>Next →</button>
        </div>
      </div>
    </div>

    <!-- RESULTS -->
    <div class="screen" id="screen-results">
      <div id="results-content"></div>
    </div>

  </div>
</main>

<!-- PDF render stage (off-screen) -->
<div id="pdf-stage"></div>

<script>
// ─── CONFIG ──────────────────────────────────────────────────────────────────
const CFG = {
  formspree: 'https://formspree.io/f/mbdqgbyk',

  weights: { regulatory:.25, strategic:.25, viability:.20, tech:.15, ledger:.15 },

  bands: [
    { min:80, max:100, label:'Strong Foundation',
      copy:"This partnership shows strong readiness across most dimensions. Focus diligence on any dimension below 75 — even a strong overall score can mask a single critical gap.",
      color:'#15803d', bg:'#f0fdf4', bd:'#bbf7d0' },
    { min:60, max:79,  label:'Proceed with Focused Diligence',
      copy:"There are meaningful gaps in one or more areas. This doesn't mean the partnership won't work — it means you need to address specific risks before committing further.",
      color:'#a16207', bg:'#fefce8', bd:'#fde68a' },
    { min:40, max:59,  label:'Significant Gaps — Slow Down',
      copy:"Multiple dimensions show material risk. Before proceeding, both parties need to invest in closing these gaps. Rushing forward at this stage is how the 40% failure rate happens.",
      color:'#c2410c', bg:'#fff7ed', bd:'#fed7aa' },
    { min:0,  max:39,  label:'Not Ready',
      copy:"This partnership has fundamental readiness issues. Proceeding at this stage carries high risk of operational, regulatory, or financial failure. Consider whether the gaps are closable or structural.",
      color:'#b91c1c', bg:'#fef2f2', bd:'#fecaca' }
  ],

  intake: [
    { id:'stage', label:'What stage is this partnership in?',
      opts:['Exploring / early conversations','In active diligence','Term sheet or contracting','Live and operating','Renewing or expanding'] },
    { id:'goal', label:"What is the bank's primary goal for this partnership?",
      opts:['Deposit growth','Fee income / interchange','Customer acquisition or new segment access','Competitive defense (keep up with peers)','Innovation / organizational learning'] },
    { id:'fintech_stage', label:'Roughly, what stage is the fintech?',
      opts:['Pre-revenue / seed stage','Early revenue / Series A–B','Growth stage / Series C+','Profitable or self-sustaining','Public company'] }
  ],

  sections: [
    {
      id:'regulatory', title:'Regulatory & Compliance Readiness', weight:.25,
      ctx:'The 2023–2025 wave of BaaS-related consent orders (Cross River, Blue Ridge, Piermont, among others) demonstrated that regulatory risk in bank/fintech partnerships falls squarely on the bank. A bank\'s third-party risk management maturity and the fintech\'s compliance posture are leading indicators of whether the partnership will survive regulatory scrutiny.',
      qs:[
        { id:'q1_1', text:'Does your bank have a dedicated third-party risk management function with staff specifically allocated to fintech partner oversight?',
          opts:[
            {t:'Yes, fully staffed and experienced with fintech partnerships',s:3},
            {t:'Yes, but stretched thin or new to fintech-specific oversight',s:2},
            {t:'Shared with broader vendor management, no fintech specialization',s:1},
            {t:'No dedicated function',s:0}],
          conv:"Before going further, you should consider staffing or designating a third-party risk function with fintech-specific expertise. What's your plan and timeline?" },
        { id:'q1_2', text:'Has your bank received any regulatory findings, MRAs, or enforcement actions related to third-party relationships or BaaS activities in the last 36 months?',
          opts:[
            {t:'None',s:3},
            {t:'Informal supervisory feedback only',s:2},
            {t:'Formal MRA or MRIA',s:1},
            {t:'Consent order or enforcement action',s:0}],
          conv:"Your recent regulatory history in third-party relationships may need to be resolved or disclosed before adding a new fintech partnership. Have you discussed this with your examiners?" },
        { id:'q1_3', text:"How would you rate the fintech's compliance program?",
          opts:[
            {t:'Dedicated CCO with banking/regulatory experience',s:3},
            {t:'Compliance lead actively building program',s:2},
            {t:'Outsourced or part-time compliance function',s:1},
            {t:"Unclear, minimal, or haven't evaluated",s:0}],
          conv:"Ask the fintech: Who is your compliance lead, what is their background, and can we review your compliance program documentation?" },
        { id:'q1_4', text:'Has your board explicitly approved this category of partnership and reviewed the associated risk appetite?',
          opts:[
            {t:'Yes, documented board approval with defined risk appetite',s:3},
            {t:'Discussed at board level but not formally documented',s:2},
            {t:'Approved at management level only',s:1},
            {t:'Not yet raised with the board',s:0}],
          conv:"This partnership needs board-level visibility. Prepare a risk appetite memo for your next board meeting before proceeding." }
      ]
    },
    {
      id:'strategic', title:'Strategic Alignment', weight:.25,
      ctx:"According to the EY-Parthenon 2022 U.S. Banking Strategic Partnership survey, about 40% of bank partnerships fail to operationalize, driven primarily by ineffective strategies, scalability issues, and poor organizational alignment. Strategic misalignment is the most common — and most preventable — cause of partnership failure.",
      qs:[
        { id:'q2_1', text:'Have both parties documented what "success" looks like at 12 and 24 months, with shared metrics?',
          opts:[
            {t:'Yes, jointly developed and signed off by both sides',s:3},
            {t:"Bank has defined metrics; fintech hasn't formally agreed",s:2},
            {t:'Informal or verbal discussion only',s:1},
            {t:'Not yet discussed',s:0}],
          conv:"Sit down with the fintech and jointly define success metrics for 12 and 24 months. If you can't agree on what success looks like, the partnership is already misaligned." },
        { id:'q2_2', text:'How aligned are the economic expectations (revenue model, fee splits, volume commitments)?',
          opts:[
            {t:'Term sheet signed with modeled economics reviewed by both sides',s:3},
            {t:'Verbally aligned on economics, not yet modeled together',s:2},
            {t:'Significant gaps or open questions remain',s:1},
            {t:"Haven't discussed economics in detail",s:0}],
          conv:"Before signing anything, model the economics together. What does each party earn, at what volume, on what timeline?" },
        { id:'q2_3', text:"What is the bank's realistic tolerance for how long this partnership takes to produce results?",
          opts:[
            {t:'24+ months — we understand this is a long build',s:3},
            {t:'12–24 months',s:2},
            {t:'6–12 months',s:1},
            {t:'Need results this quarter or next',s:0}],
          conv:"Your internal time-to-value expectations may be unrealistic. Bank/fintech integrations routinely take 12–18 months to produce results. Align your board and leadership on this timeline." },
        { id:'q2_4', text:'If this partnership requires the bank to change internal processes, policies, or systems, has executive sponsorship been secured?',
          opts:[
            {t:'Named executive sponsor with budget authority and organizational mandate',s:3},
            {t:'Sponsor identified, but authority or mandate is unclear',s:2},
            {t:'Champion exists at middle-management level',s:1},
            {t:'No clear internal sponsor',s:0}],
          conv:"This partnership will require internal change. Without an executive sponsor with real authority, it will die in committee. Identify your sponsor before your next meeting with the fintech." }
      ]
    },
    {
      id:'viability', title:'Fintech Viability', weight:.20,
      ctx:"A bank can be perfectly aligned with a fintech that runs out of runway. Fintech viability is the dimension banks most consistently underweight in diligence — partly because fintechs don't volunteer it, and partly because banks aren't accustomed to evaluating early-stage companies. This section measures what the bank has done (or can do) to assess whether the fintech will still be standing in 24 months.",
      qs:[
        { id:'q3_1', text:'Has the fintech shared financial information with your bank?',
          opts:[
            {t:'Audited financials provided and reviewed',s:3},
            {t:'Unaudited financials provided',s:2},
            {t:'High-level projections or pitch-deck-level information only',s:1},
            {t:"Nothing beyond marketing materials, or haven't asked",s:0}],
          conv:"Ask the fintech for financial statements — at minimum, unaudited. If they won't share, that's a signal. You wouldn't extend a commercial loan without financials; don't extend your charter without them either." },
        { id:'q3_2', text:'How dependent is the fintech on your bank specifically to operate?',
          opts:[
            {t:'One of multiple banking relationships; not operationally dependent on you',s:3},
            {t:'Primary bank partner with at least one backup relationship',s:2},
            {t:'You are the sole sponsor bank',s:1},
            {t:'Unclear or have not determined',s:0}],
          conv:"You appear to be the sole or primary sponsor bank. Understand what happens to the fintech — and its end users — if you exit the relationship. Do you have a wind-down plan?" },
        { id:'q3_3', text:'How long has the fintech been operating with live customers?',
          opts:[
            {t:'3+ years with live customers',s:3},
            {t:'1–3 years with live customers',s:2},
            {t:'Under 1 year with live customers',s:1},
            {t:'Pre-launch or in pilot only',s:0}],
          conv:"This fintech has a limited live operating history. Consider a phased launch with volume caps to limit your exposure while they build a track record." },
        { id:'q3_4', text:"Has the fintech's leadership team been stable, and does it include people with banking or regulatory experience?",
          opts:[
            {t:'Stable team with meaningful banking or regulatory experience',s:3},
            {t:'Stable team but limited banking/regulatory background',s:2},
            {t:'Recent senior-level turnover',s:1},
            {t:'Significant leadership churn or very early-stage team with no banking experience',s:0}],
          conv:"Evaluate the fintech's leadership team for stability and banking knowledge. Early-stage teams without regulatory experience are more likely to create compliance incidents." }
      ]
    },
    {
      id:'tech', title:'Tech Integration Realism', weight:.15,
      ctx:"Tech integration failures are the slow-burning version of partnership breakdown. The Apple/Goldman partnership is a high-profile example: the customer experience ambitions outpaced both parties' capacity to integrate, and the question of who owned the customer relationship and associated liabilities became a point of failure. Integration timelines are almost always underestimated, especially when legacy core systems are involved.",
      qs:[
        { id:'q4_1', text:"What is your bank's core banking system, and has the fintech's integration approach been proven on it?",
          opts:[
            {t:'Modern or cloud-native core with a proven integration path for this fintech',s:3},
            {t:'Modern core, but integration approach is novel or unproven',s:2},
            {t:'Legacy core with a proven integration path',s:1},
            {t:'Legacy core with a novel or unproven integration approach',s:0}],
          conv:"Your core system and the fintech's integration approach may not be compatible without significant custom work. Get a realistic technical assessment — from your team, not the fintech's sales team — before committing." },
        { id:'q4_2', text:'Have both parties agreed on a realistic integration timeline?',
          opts:[
            {t:'Both parties agree on a timeline of 12+ months with defined milestones',s:3},
            {t:'Both agree on 6–12 months with milestones',s:2},
            {t:"The bank's expected timeline is longer than the fintech's",s:1},
            {t:"Haven't aligned on timeline or expectations diverge significantly",s:0}],
          conv:"Your integration timelines don't match. This is one of the most common early warning signs. Pin down milestones with penalties or exit ramps, not just target dates." },
        { id:'q4_3', text:'Is it clearly documented who owns the customer relationship, and who holds the deposit and associated liability?',
          opts:[
            {t:'Both clearly documented and agreed in writing',s:3},
            {t:'Customer relationship ownership is clear; deposit/liability terms are still being negotiated',s:2},
            {t:'Under active negotiation, not yet resolved',s:1},
            {t:'Not yet addressed',s:0}],
          conv:"Clarify in writing: who owns the customer relationship, who holds the deposit, and who bears the associated liability. This cannot remain ambiguous." },
        { id:'q4_4', text:"Does the bank have internal technical capacity to oversee the integration, or is it dependent on the fintech and vendors?",
          opts:[
            {t:'Internal team with relevant integration experience',s:3},
            {t:'Internal team, but learning as they go',s:2},
            {t:'Heavily dependent on outside vendors',s:1},
            {t:"Dependent on the fintech itself to manage integration",s:0}],
          conv:"If you're dependent on the fintech or outside vendors to manage your own integration, you've lost oversight. Invest in internal technical capacity or hire it." }
      ]
    },
    {
      id:'ledger', title:'Ledger & Operational Integrity', weight:.15,
      ctx:"Ledger and operational integrity failures are lagging indicators — they typically surface only when a partnership is already under stress, and by then the damage can be severe. The Synapse Financial collapse (2024) and the Wirecard fraud (2020) both demonstrated that when the system of record for customer funds is unclear, ambiguous, or compromised, end users lose access to their money and the bank bears the regulatory and reputational consequences.",
      qs:[
        { id:'q5_1', text:"Who maintains the system of record for customer funds and balances?",
          opts:[
            {t:"Bank's core system",s:3},
            {t:'Bank-controlled middleware or subledger',s:2},
            {t:'Third-party BaaS middleware (not controlled by bank or fintech)',s:1},
            {t:"Fintech's own system, or unclear",s:0}],
          conv:"The system of record for customer funds must be under the bank's control or direct oversight. If it's not, fix this before going live." },
        { id:'q5_2', text:"How frequently are end-user subledgers reconciled against the bank's general ledger?",
          opts:[
            {t:'Real-time or intraday',s:3},
            {t:'Daily',s:2},
            {t:'Weekly or less frequently',s:1},
            {t:'Not yet established or unknown',s:0}],
          conv:"Reconciliation should happen at least daily. Anything less creates a window where discrepancies can compound." },
        { id:'q5_3', text:'Have you mapped the complete funds flow from end-user to bank account, including all intermediaries?',
          opts:[
            {t:'Yes, documented and stress-tested',s:3},
            {t:'Documented but not stress-tested',s:2},
            {t:'Partially understood',s:1},
            {t:'No',s:0}],
          conv:"Map every step of the funds flow — every intermediary, every account, every handoff. If you can't diagram it on a whiteboard, you don't understand it well enough." },
        { id:'q5_4', text:"If the fintech failed or was terminated tomorrow, could the bank independently identify and return each end-user's funds without relying on the fintech's systems?",
          opts:[
            {t:'Yes, confidently — we have independent records and a tested process',s:3},
            {t:'Probably, with significant effort',s:2},
            {t:'Uncertain',s:1},
            {t:"No, or haven't considered this scenario",s:0}],
          conv:"If you cannot independently identify and return every end-user's funds without the fintech's cooperation, you have a Synapse-shaped risk. This is the single most important operational question in any partnership where the bank holds deposits or moves money on behalf of users." }
      ]
    }
  ]
};

// ─── STATE ────────────────────────────────────────────────────────────────────
const S = {
  step: 'intro',   // intro | intake | section | results
  secIdx: 0,       // 0..4
  intake: {},      // { id: value }
  answers: {}      // { qId: { s: score, t: text } }
};

// ─── UTILITIES ────────────────────────────────────────────────────────────────
function getBand(score) {
  return CFG.bands.find(b => score >= b.min && score <= b.max) || CFG.bands[3];
}

function calcScores() {
  const dim = {};
  CFG.sections.forEach(sec => {
    const raw = sec.qs.reduce((acc, q) => acc + (S.answers[q.id]?.s ?? 0), 0);
    dim[sec.id] = Math.round((raw / 12) * 100);
  });
  const overall = Math.round(
    CFG.sections.reduce((sum, sec) => sum + dim[sec.id] * CFG.weights[sec.id], 0)
  );
  return { dim, overall };
}

function gapCount() {
  let n = 0;
  CFG.sections.forEach(sec => sec.qs.forEach(q => { if ((S.answers[q.id]?.s ?? 1) === 0) n++; }));
  return n;
}

function threeWeakest(dim) {
  return CFG.sections
    .map(sec => ({ sec, score: dim[sec.id] }))
    .sort((a, b) => a.score - b.score)
    .slice(0, 3);
}

function lowestQ(sec) {
  return sec.qs.reduce((low, q) => {
    const s = S.answers[q.id]?.s ?? 0;
    return s < (S.answers[low.id]?.s ?? 0) ? q : low;
  }, sec.qs[0]);
}

function setProgress(pct) {
  document.getElementById('progFill').style.width = pct + '%';
}

function showScreen(id) {
  document.querySelectorAll('.screen').forEach(el => el.classList.remove('active'));
  document.getElementById('screen-' + id).classList.add('active');
}

function esc(str) {
  return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}

// ─── NAVIGATION ───────────────────────────────────────────────────────────────
function startAssessment() {
  S.step = 'intake';
  renderIntake();
  showScreen('intake');
  setProgress(5);
  window.scrollTo(0,0);
}

function goBack() {
  if (S.step === 'intake') {
    S.step = 'intro';
    showScreen('intro');
    setProgress(0);
  } else if (S.step === 'section') {
    if (S.secIdx === 0) {
      S.step = 'intake';
      showScreen('intake');
      setProgress(5);
    } else {
      S.secIdx--;
      renderSection(S.secIdx);
      setProgress(10 + S.secIdx * 18);
    }
  }
  window.scrollTo(0,0);
}

function nextFromIntake() {
  const allAnswered = CFG.intake.every(q => S.intake[q.id]);
  if (!allAnswered) return;
  S.step = 'section';
  S.secIdx = 0;
  renderSection(0);
  showScreen('section');
  setProgress(10);
  window.scrollTo(0,0);
}

function nextSection() {
  const sec = CFG.sections[S.secIdx];
  const allAnswered = sec.qs.every(q => S.answers[q.id] !== undefined);
  if (!allAnswered) return;
  if (S.secIdx < CFG.sections.length - 1) {
    S.secIdx++;
    renderSection(S.secIdx);
    setProgress(10 + S.secIdx * 18);
    window.scrollTo(0,0);
  } else {
    S.step = 'results';
    renderResults();
    showScreen('results');
    setProgress(100);
    window.scrollTo(0,0);
  }
}

// ─── INTAKE RENDER ────────────────────────────────────────────────────────────
function renderIntake() {
  const el = document.getElementById('intake-questions');
  el.innerHTML = CFG.intake.map(q => `
    <div class="q-block">
      <div class="q-text">${esc(q.label)}</div>
      <select class="q-select" onchange="setIntake('${q.id}',this.value)" id="intake-${q.id}">
        <option value="">Select an answer…</option>
        ${q.opts.map(o => `<option value="${esc(o)}" ${S.intake[q.id]===o?'selected':''}>${esc(o)}</option>`).join('')}
      </select>
    </div>`).join('');
  checkIntakeNext();
}

function setIntake(id, val) {
  S.intake[id] = val;
  checkIntakeNext();
}

function checkIntakeNext() {
  const btn = document.getElementById('intake-next');
  btn.disabled = !CFG.intake.every(q => S.intake[q.id]);
}

// ─── SECTION RENDER ───────────────────────────────────────────────────────────
function renderSection(idx) {
  const sec = CFG.sections[idx];
  document.getElementById('sec-badge').textContent = `Section ${idx+1} of 5`;
  document.getElementById('sec-count').textContent = `Step ${idx+2} of 7`;
  document.getElementById('sec-title').textContent = sec.title;
  document.getElementById('sec-ctx').textContent = sec.ctx;

  const el = document.getElementById('sec-questions');
  el.innerHTML = sec.qs.map((q, qi) => `
    <div class="q-block">
      <div class="q-text">${qi+1}. ${esc(q.text)}</div>
      <div class="options">
        ${q.opts.map((opt, oi) => {
          const sel = S.answers[q.id]?.s === opt.s && S.answers[q.id]?.t === opt.t;
          return `<label class="opt${sel?' sel':''}">
            <input type="radio" name="${q.id}" value="${oi}" ${sel?'checked':''} onchange="setAnswer('${sec.id}','${q.id}',${opt.s},'${esc(opt.t).replace(/'/g,"\\'")}',this)">
            ${esc(opt.t)}
          </label>`;
        }).join('')}
      </div>
    </div>`).join('');

  checkSectionNext(idx);
}

function setAnswer(secId, qId, score, text, radioEl) {
  S.answers[qId] = { s: score, t: text };
  // update visual selection
  const block = radioEl.closest('.q-block');
  block.querySelectorAll('.opt').forEach(l => l.classList.remove('sel'));
  radioEl.closest('.opt').classList.add('sel');
  checkSectionNext(S.secIdx);
}

function checkSectionNext(idx) {
  const sec = CFG.sections[idx];
  const btn = document.getElementById('sec-next');
  btn.disabled = !sec.qs.every(q => S.answers[q.id] !== undefined);
}

// ─── RESULTS RENDER ───────────────────────────────────────────────────────────
function renderResults() {
  const { dim, overall } = calcScores();
  const band = getBand(overall);
  const gaps = gapCount();
  const weakest3 = threeWeakest(dim);
  const weakest1 = weakest3[0];

  // Sort dims ascending for chart
  const sortedDims = CFG.sections
    .map(sec => ({ sec, score: dim[sec.id] }))
    .sort((a, b) => a.score - b.score);

  // Next conversations
  const convos = weakest3.map((item, i) => {
    const q = lowestQ(item.sec);
    return { num: i+1, dim: item.sec.title, text: q.conv };
  });

  const el = document.getElementById('results-content');
  el.innerHTML = `
    <!-- SCORE HERO (always visible) -->
    <div class="score-hero" style="background:${band.bg};border:1px solid ${band.bd}">
      <div class="score-num" style="color:${band.color}">${overall}</div>
      <div class="score-label" style="color:${band.color}">${band.label}</div>
      <div class="score-copy" style="color:${band.color}">${esc(band.copy)}</div>
    </div>

    <!-- LEAD CAPTURE GATE -->
    <div class="card" id="lead-card">
      <div class="email-sec-title">Unlock your full results</div>
      <div class="email-sec-sub">Get the dimension breakdown, your weakest link, the questions to raise with your team, and a PDF you can share with leadership.</div>
      <div class="lead-teaser-note">Your contact info stays with Travillian — we'll use it only to follow up if you'd like to discuss the results.</div>
      <div class="lead-grid">
        <div class="lead-field">
          <label for="lead-name">Name *</label>
          <input type="text" id="lead-name" autocomplete="name" placeholder="Jane Doe">
        </div>
        <div class="lead-field">
          <label for="lead-company">Company *</label>
          <input type="text" id="lead-company" autocomplete="organization" placeholder="Your bank or fintech">
        </div>
        <div class="lead-field">
          <label for="lead-title">Title *</label>
          <input type="text" id="lead-title" autocomplete="organization-title" placeholder="e.g. Chief Strategy Officer">
        </div>
        <div class="lead-field">
          <label for="lead-email">Work email *</label>
          <input type="email" id="lead-email" autocomplete="email" placeholder="you@yourbank.com">
        </div>
      </div>
      <div id="lead-error" class="lead-error" style="display:none"></div>
      <button class="btn btn-primary btn-block btn-lg" onclick="submitLead()" id="lead-submit-btn">See Full Results &rarr;</button>
      <label class="chk-label">
        <input type="checkbox" id="newsletter-chk">
        Subscribe me to Travillian Next — strategic insights for bank executives.
      </label>
      <p class="disclosure">By providing your information, you agree to be contacted by Travillian Group. We do not sell or share your information. You can unsubscribe at any time.</p>
    </div>

    <!-- LOCKED RESULTS (revealed after lead capture) -->
    <div id="locked-results" style="display:none">
      <div class="confirm-msg" id="confirm-msg" style="display:block">Thanks — your full results are below. A team member from Travillian may follow up if it makes sense.</div>

      ${gaps > 0 ? `<div class="gap-banner">
        <strong>Information gap detected</strong>
        You indicated uncertainty or minimal information on ${gaps} question${gaps>1?'s':''}. In partnership diligence, what you don't know is often more dangerous than what you do. Consider whether these gaps reflect insufficient diligence or the fintech's unwillingness to share information — both are risk signals.
      </div>` : ''}

      <!-- DIMENSION CHART -->
      <div class="card">
        <div class="chart-title">Score by Dimension</div>
        ${sortedDims.map(({ sec, score }) => {
          const b = getBand(score);
          return `<div class="dim-row">
            <div class="dim-name">${esc(sec.title)}</div>
            <div class="dim-track">
              <div class="dim-bar" style="width:${score}%;background:${b.bg};border-right:3px solid ${b.color}">
                <span class="dim-bar-score" style="color:${b.color}">${score}</span>
              </div>
            </div>
            <div class="dim-score-out" style="color:${b.color}">${score}</div>
          </div>`;
        }).join('')}
      </div>

      <!-- WEAKEST LINK -->
      <div class="weakest-card" style="background:${getBand(weakest1.score).bg};border:1px solid ${getBand(weakest1.score).bd}">
        <div class="weakest-eyebrow" style="color:${getBand(weakest1.score).color}">Your Weakest Link</div>
        <div class="weakest-name" style="color:${getBand(weakest1.score).color}">${esc(weakest1.sec.title)}</div>
        <div class="weakest-framing" style="color:${getBand(weakest1.score).color}">Partnerships don't fail at the average — they fail at the weakest point.</div>
        <div class="weakest-ctx" style="color:${getBand(weakest1.score).color}">${esc(weakest1.sec.ctx)}</div>
      </div>

      <!-- NEXT CONVERSATIONS -->
      <div class="card">
        <div class="convos-header">
          <div class="convos-title">Next Conversations</div>
          <div class="convos-sub">Based on your three lowest-scoring dimensions — one question worth raising with your team or your fintech counterpart.</div>
        </div>
        ${convos.map(c => `
          <div class="convo-card">
            <div class="convo-num">Conversation ${c.num}</div>
            <div class="convo-dim">${esc(c.dim)}</div>
            <div class="convo-text">${esc(c.text)}</div>
          </div>`).join('')}
      </div>

      <!-- PDF DOWNLOAD -->
      <div class="card">
        <div class="email-sec-title">Save your report</div>
        <div class="email-sec-sub">Download a PDF of your results to share with your board or leadership team.</div>
        <button class="btn btn-primary" onclick="downloadPDF()" id="pdf-btn">Download PDF</button>
      </div>
    </div>

    <!-- FOOTER -->
    <div class="results-footer">
      <p style="margin-bottom:6px">Built by Travillian. Learn more at <a href="https://travilliangroup.com" target="_blank">travilliangroup.com</a></p>
      <p style="margin-bottom:6px"><em>Source: EY-Parthenon, "How Banks Can Fix Broken Fintech Partnership Models," 2023. Based on the EY-Parthenon 2022 U.S. Banking Strategic Partnership Survey.</em></p>
      <p>This diagnostic is a self-assessment tool designed to surface questions worth asking. It is not legal, regulatory, or financial advice. Scores reflect your own inputs and should be used as a starting point for deeper diligence, not as a substitute for it.</p>
    </div>
  `;
}

// ─── LEAD SUBMIT ──────────────────────────────────────────────────────────────
async function submitLead() {
  const fields = {
    name: document.getElementById('lead-name'),
    company: document.getElementById('lead-company'),
    title: document.getElementById('lead-title'),
    email: document.getElementById('lead-email')
  };
  const values = {
    name: fields.name.value.trim(),
    company: fields.company.value.trim(),
    title: fields.title.value.trim(),
    email: fields.email.value.trim()
  };

  // Reset previous invalid styling
  Object.values(fields).forEach(el => el.classList.remove('invalid'));

  // Validate
  const missing = [];
  if (!values.name) { fields.name.classList.add('invalid'); missing.push('Name'); }
  if (!values.company) { fields.company.classList.add('invalid'); missing.push('Company'); }
  if (!values.title) { fields.title.classList.add('invalid'); missing.push('Title'); }
  const emailOk = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(values.email);
  if (!emailOk) { fields.email.classList.add('invalid'); missing.push('Valid work email'); }

  const errEl = document.getElementById('lead-error');
  if (missing.length) {
    errEl.textContent = 'Please fill in: ' + missing.join(', ');
    errEl.style.display = 'block';
    return;
  }
  errEl.style.display = 'none';

  const btn = document.getElementById('lead-submit-btn');
  btn.disabled = true;
  btn.textContent = 'Unlocking…';

  const newsletter = document.getElementById('newsletter-chk').checked;
  const { overall, dim } = calcScores();
  const band = getBand(overall);

  const payload = {
    name: values.name,
    company: values.company,
    title: values.title,
    email: values.email,
    newsletter_opt_in: newsletter,
    overall_score: overall,
    score_band: band.label,
    regulatory_score: dim.regulatory,
    strategic_score: dim.strategic,
    viability_score: dim.viability,
    tech_score: dim.tech,
    ledger_score: dim.ledger,
    partnership_stage: S.intake.stage || '',
    bank_goal: S.intake.goal || '',
    fintech_stage: S.intake.fintech_stage || '',
    submitted_at: new Date().toISOString()
  };

  try {
    await fetch(CFG.formspree, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
      body: JSON.stringify(payload)
    });
  } catch(e) { /* silent — still unlock results so the user gets value */ }

  // Unlock the rest of the results
  document.getElementById('lead-card').style.display = 'none';
  document.getElementById('locked-results').style.display = 'block';
  // Smooth-scroll to the freshly-revealed content
  setTimeout(() => {
    const el = document.getElementById('locked-results');
    if (el && el.scrollIntoView) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  }, 80);
}

// ─── PDF GENERATION ───────────────────────────────────────────────────────────
async function downloadPDF() {
  const btn = document.getElementById('pdf-btn');
  if (btn) { btn.textContent = 'Generating…'; btn.disabled = true; }

  const { dim, overall } = calcScores();
  const band = getBand(overall);
  const weakest3 = threeWeakest(dim);
  const convos = weakest3.map((item, i) => {
    const q = lowestQ(item.sec);
    return { num: i+1, dim: item.sec.title, text: q.conv };
  });

  const sortedDims = CFG.sections
    .map(sec => ({ sec, score: dim[sec.id] }))
    .sort((a, b) => a.score - b.score);

  // Get logo as data URL
  let logoDataUrl = '';
  try {
    const imgEl = document.getElementById('hdrLogo');
    if (imgEl && imgEl.complete) {
      const c = document.createElement('canvas');
      c.width = imgEl.naturalWidth; c.height = imgEl.naturalHeight;
      const cx = c.getContext('2d');
      cx.drawImage(imgEl, 0, 0);
      logoDataUrl = c.toDataURL('image/png');
    }
  } catch(e) {}

  // Build PDF stage HTML
  const stage = document.getElementById('pdf-stage');
  stage.innerHTML = buildPDFHTML(overall, band, sortedDims, convos, logoDataUrl);

  // Wait for layout
  await new Promise(r => setTimeout(r, 300));

  try {
    const canvas = await html2canvas(stage, {
      scale: 1.5,
      useCORS: true,
      allowTaint: true,
      backgroundColor: '#ffffff',
      logging: false
    });

    const { jsPDF } = window.jspdf;
    const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
    const pdfW = pdf.internal.pageSize.getWidth();
    const pdfH = pdf.internal.pageSize.getHeight();
    const margin = 10;
    const imgW = pdfW - margin * 2;
    const imgH = (canvas.height / canvas.width) * imgW;
    const pageH = pdfH - margin * 2;

    if (imgH <= pageH) {
      pdf.addImage(canvas.toDataURL('image/jpeg', 0.92), 'JPEG', margin, margin, imgW, imgH);
    } else {
      // Multi-page
      let yOffset = 0;
      while (yOffset < imgH) {
        if (yOffset > 0) pdf.addPage();
        const sliceH = Math.min(pageH, imgH - yOffset);
        const sliceCanvas = document.createElement('canvas');
        const scale = canvas.width / imgW;
        sliceCanvas.width = canvas.width;
        sliceCanvas.height = sliceH * scale;
        const ctx = sliceCanvas.getContext('2d');
        ctx.drawImage(canvas, 0, yOffset * scale, canvas.width, sliceH * scale, 0, 0, canvas.width, sliceH * scale);
        pdf.addImage(sliceCanvas.toDataURL('image/jpeg', 0.92), 'JPEG', margin, margin, imgW, sliceH);
        yOffset += sliceH;
      }
    }

    pdf.save('fault-line-diagnostic.pdf');
  } catch(err) {
    console.error('PDF generation error:', err);
  }

  stage.innerHTML = '';
  if (btn) { btn.textContent = 'Download PDF'; btn.disabled = false; }
}

function buildPDFHTML(overall, band, sortedDims, convos, logoDataUrl) {
  const logoTag = logoDataUrl
    ? `<img src="${logoDataUrl}" style="height:28px;margin-bottom:24px;display:block">`
    : `<div style="font-size:16px;font-weight:800;color:#1a2e4a;margin-bottom:24px">TRAVILLIAN</div>`;

  return `
  <div style="font-family:'Inter',system-ui,sans-serif;color:#1e293b;background:#fff;padding:48px 52px;width:780px;font-size:11px;line-height:1.5">
    ${logoTag}
    <div style="font-size:11px;color:#64748b;font-weight:600;letter-spacing:.06em;text-transform:uppercase;margin-bottom:6px">The Fault Line Diagnostic for Bank/Fintech Partnerships</div>
    <hr style="border:none;border-top:2px solid #1a2e4a;margin-bottom:28px">

    <!-- Score -->
    <div style="background:${band.bg};border:1px solid ${band.bd};border-radius:10px;padding:28px 32px;margin-bottom:24px;text-align:center">
      <div style="font-size:64px;font-weight:800;color:${band.color};line-height:1;margin-bottom:6px">${overall}</div>
      <div style="font-size:18px;font-weight:700;color:${band.color};margin-bottom:10px">${band.label}</div>
      <div style="font-size:12px;color:${band.color};max-width:480px;margin:0 auto;opacity:.9">${band.copy}</div>
    </div>

    <!-- Chart -->
    <div style="margin-bottom:24px">
      <div style="font-size:13px;font-weight:700;color:#1a2e4a;margin-bottom:14px">Score by Dimension</div>
      ${sortedDims.map(({ sec, score }) => {
        const b = getBand(score);
        return `<div style="display:flex;align-items:center;gap:10px;margin-bottom:10px">
          <div style="font-size:10.5px;font-weight:500;width:200px;flex-shrink:0;line-height:1.3">${sec.title}</div>
          <div style="flex:1;background:#f1f5f9;height:18px;border-radius:3px;overflow:hidden">
            <div style="width:${score}%;height:100%;background:${b.bg};border-right:3px solid ${b.color};min-width:24px;display:flex;align-items:center;justify-content:flex-end;padding-right:5px">
              <span style="font-size:9px;font-weight:700;color:${b.color}">${score}</span>
            </div>
          </div>
          <div style="font-size:11px;font-weight:700;color:${b.color};min-width:30px;text-align:right">${score}</div>
        </div>`;
      }).join('')}
    </div>

    <!-- Conversations -->
    <div style="margin-bottom:24px">
      <div style="font-size:13px;font-weight:700;color:#1a2e4a;margin-bottom:4px">Next Conversations</div>
      <div style="font-size:11px;color:#64748b;margin-bottom:14px">Based on your three lowest-scoring dimensions.</div>
      ${convos.map(c => `
        <div style="border:1.5px solid #dde3ea;border-radius:8px;padding:14px 16px;margin-bottom:10px">
          <div style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:#2563eb;margin-bottom:3px">Conversation ${c.num}</div>
          <div style="font-size:10px;font-weight:600;color:#64748b;margin-bottom:6px">${c.dim}</div>
          <div style="font-size:12px;font-weight:500;color:#1e293b;line-height:1.5">${c.text}</div>
        </div>`).join('')}
    </div>

    <hr style="border:none;border-top:1px solid #e2e8f0;margin-bottom:14px">
    <div style="font-size:10px;color:#94a3b8;line-height:1.55">
      <p style="margin-bottom:4px"><em>Source: EY-Parthenon, "How Banks Can Fix Broken Fintech Partnership Models," 2023. Based on the EY-Parthenon 2022 U.S. Banking Strategic Partnership Survey.</em></p>
      <p>This diagnostic is a self-assessment tool designed to surface questions worth asking. It is not legal, regulatory, or financial advice. Scores reflect your own inputs and should be used as a starting point for deeper diligence, not as a substitute for it. Built by Travillian — travilliangroup.com</p>
    </div>
  </div>`;
}

// ─── INIT ─────────────────────────────────────────────────────────────────────
// Ensure logo renders (handle file:// fallback gracefully)
document.addEventListener('DOMContentLoaded', () => {
  document.querySelectorAll('img[src*="Travillian-Logo"]').forEach(img => {
    img.onerror = () => { img.style.display = 'none'; };
  });
});
</script>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="//travilliangroup.com/main-sitemap.xsl"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
	<sitemap>
		<loc>https://travilliangroup.com/post-sitemap.xml</loc>
		<lastmod>2026-04-24T16:05:12+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://travilliangroup.com/page-sitemap.xml</loc>
		<lastmod>2026-04-29T15:44:26+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://travilliangroup.com/gutenverse-form-sitemap.xml</loc>
		<lastmod>2025-08-14T15:37:40+00:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://travilliangroup.com/category-sitemap.xml</loc>
		<lastmod>2026-04-24T16:05:12+00:00</lastmod>
	</sitemap>
</sitemapindex>
<!-- XML Sitemap generated by Rank Math SEO Plugin (c) Rank Math - rankmath.com -->