PageSourceSearch

https://cardcompass.app/

html cardcompass.app collected 2026-09-24 14:30:28 UTC 111,303 bytes, 1,598 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="UTF-8">
5  <meta name="fo-verify" content="7c1b2d98-52dc-49f3-95fc-792906ed2a9b" />
6  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
8  <meta http-equiv="Pragma" content="no-cache">
9  <title>CardCompass — Find Your Perfect Credit Card</title>
10
11  <!-- Favicon & PWA -->
12  <link rel="icon" href="images/logo-icon.svg" type="image/png">
13  <link rel="icon" href="favicon.svg" type="image/svg+xml">
14  <link rel="manifest" href="site.webmanifest">
15  <meta name="theme-color" content="#071E4A">
16
17  <!-- SEO -->
18  <meta name="description" content="CardCompass finds your best credit card in 60 seconds. Compare cash back, travel rewards, and hotel points cards — personalized to your spending habits.">
19  <link rel="canonical" href="https://cardcompass.app/">
20
21  <!-- Open Graph -->
22  <meta property="og:type" content="website">
23  <meta property="og:url" content="https://cardcompass.app/">
24  <meta property="og:title" content="CardCompass — Find Your Perfect Credit Card">
25  <meta property="og:description" content="Stop leaving money on the table. CardCompass matches you with the best credit card for your spending in under 60 seconds.">
26  <meta property="og:image" content="https://cardcompass.app/og-image.png">
27  <meta property="og:site_name" content="CardCompass">
28
29  <!-- Twitter Card -->
30  <meta name="twitter:card" content="summary_large_image">
31  <meta name="twitter:title" content="CardCompass — Find Your Perfect Credit Card">
32  <meta name="twitter:description" content="Find the best credit card for your spending in 60 seconds.">
33  <meta name="twitter:image" content="https://cardcompass.app/og-image.png">
34
35  <!-- Structured Data -->
36  
36<script type="application/ld+json">
37  {
38    "@context": "https://schema.org",
39    "@type": "Organization",
40    "name": "CardCompass",
41    "url": "https://cardcompass.app",
42    "description": "Credit card comparison and recommendation tool that helps consumers find the best credit card for their spending habits.",
43    "contactPoint": { "@type": "ContactPoint", "email": "[email protected]", "contactType": "customer service" },
44    "sameAs": ["https://www.instagram.com/cardcompassapp/", "https://www.facebook.com/cardcompassapp"]
45  }
46  </script>
46
47
48  
48<script type="application/ld+json">
49  {
50    "@context": "https://schema.org",
51    "@type": "WebSite",
52    "name": "CardCompass",
53    "url": "https://cardcompass.app",
54    "description": "Credit card comparison and recommendation tool that helps consumers find the best credit card for their spending habits."
55  }
56  </script>
56
57
58  <!-- Google Analytics 4 (consent-gated) -->
vendor: 66 bytes, lines 58-59
58
59  <script async src="https://www.googletagmanager.com/gtag/js?id=
59G-CYNSKD3EBQ
vendor: 14 bytes, lines 59-60
59"></script>
60  
60<script>
61    window.dataLayer = window.dataLayer || [];
62    function gtag(){dataLayer.push(arguments);}
63    gtag('js', new Date());
64    // EU/UK visitors (Europe/* timezone): opt-in (GDPR). Everyone else: on by default with opt-out (US state law model).
65    gtag('consent', 'default', { analytics_storage: (function () { try { var s = localStorage.getItem('cc_consent'); if (s) return s; return /^Europe\//.test(Intl.DateTimeFormat().resolvedOptions().timeZone) ? 'denied' : 'granted'; } catch (e) { return 'denied'; } })() });
66    gtag('config', 'G-CYNSKD3EBQ');
67  </script>
67
68
69  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
70  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer">
71  
71<script src="cards-data.js?v=13"></script>
71
72  
72<script src="recommend-engine.js?v=4"></script>
72
73  
73<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
73
74  <link rel="stylesheet" href="/styles.css?v=2">
75  <style>
76/* ─── NAVBAR ─── */
77    .navbar { position: sticky; top: 0; z-index: 1000; background: var(--primary-dark); box-shadow: 0 2px 12px rgba(0,0,0,0.35); }
78    .nav-inner { max-width: 1280px; margin: 0 auto; padding: 0 24px; display: flex; align-items: center; height: 64px; gap: 28px; }
79    .logo { display: flex; align-items: center; gap: 10px; text-decoration: none; flex-shrink: 0; }
80    .logo-icon { width: 40px; height: 40px; border-radius: 50%; overflow: hidden; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
81    .logo-icon img { width: 100%; height: 100%; object-fit: cover; display: block; }
82    .logo-text { font-size: 20px; font-weight: 800; color: #fff; letter-spacing: -0.5px; }
83    .logo-text span { color: var(--accent-light); }
84    .nav-links { display: flex; align-items: center; gap: 2px; flex: 1; }
85    .nav-item { position: relative; }
86    .nav-link { display: flex; align-items: center; gap: 5px; padding: 8px 14px; color: rgba(255,255,255,.85); font-size: 14px; font-weight: 500; text-decoration: none; border-radius: 6px; transition: all .2s; white-space: nowrap; cursor: pointer; background: none; border: none; font-family: inherit; }
87    .nav-link i { font-size: 10px; opacity: .7; }
88    .nav-link:hover { color: #fff; background: rgba(255,255,255,.1); }
89    .dropdown { position: absolute; top: calc(100% + 8px); left: 0; background: #fff; border-radius: var(--r-md); box-shadow: var(--shadow-lg); padding: 12px; min-width: 230px; opacity: 0; visibility: hidden; transform: translateY(-8px); transition: all .2s; border: 1px solid var(--border); max-height: calc(100vh - 80px); overflow-y: auto; }
90    .nav-item:hover .dropdown { opacity: 1; visibility: visible; transform: translateY(0); }
91    .dropdown a { display: flex; align-items: center; gap: 10px; padding: 9px 12px; color: var(--text-dark); text-decoration: none; font-size: 14px; border-radius: var(--r-sm); transition: background .15s; }
92    .dropdown a:hover { background: var(--bg-light); color: var(--primary); }
93    .dropdown a i { width: 18px; color: var(--accent); font-size: 13px; }
94    .nav-actions { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
95    .btn-outline { padding: 8px 18px; border: 1.5px solid rgba(255,255,255,.4); color: #fff; background: transparent; border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; transition: all .2s; text-decoration: none; font-family: inherit; }
96    .btn-outline:hover { border-color: #fff; background: rgba(255,255,255,.1); }
97    .btn-primary { padding: 8px 18px; background: var(--accent); color: #fff; border: none; border-radius: 6px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all .2s; text-decoration: none; font-family: inherit; }
98    .btn-primary:hover { background: var(--accent-light); transform: translateY(-1px); }
99
100    /* ─── SHARED ─── */
101    .section { padding: 76px 24px; }
102    .section-alt { background: var(--bg-light); }
103    .section-inner { max-width: 1280px; margin: 0 auto; }
104    .section-label { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 1.5px; color: var(--accent); margin-bottom: 10px; }
105    .section-title { font-size: 36px; font-weight: 800; color: var(--text-dark); letter-spacing: -.5px; line-height: 1.2; }
106    .section-sub { font-size: 16px; color: var(--text-gray); margin-top: 10px; }
107    .section-hd { margin-bottom: 44px; }
108
109    /* ─── COMPARISON TABLE ─── */
110    .comp-section { background: var(--primary-dark); padding: 76px 24px; color: #fff; }
111    .comp-section .section-title { color: #fff; }
112    .comp-section .section-sub { color: rgba(255,255,255,.6); }
113    .comp-section .section-label { color: var(--accent-light); }
114
115    /* ─── CATEGORY TABS (Best Cards section) ─── */
116    .comp-tabs-wrap { overflow-x: auto; scrollbar-width: none; margin-bottom: 28px; padding-bottom: 4px; }
117    .comp-tabs-wrap::-webkit-scrollbar { display: none; }
118    .comp-tabs { display: flex; gap: 8px; white-space: nowrap; }
119    .comp-tab { padding: 9px 18px; border: 1.5px solid rgba(255,255,255,.2); background: rgba(255,255,255,.06); color: rgba(255,255,255,.7); border-radius: 100px; font-size: 13px; font-weight: 600; cursor: pointer; transition: all .2s; font-family: inherit; white-space: nowrap; }
120    .comp-tab:hover { background: rgba(255,255,255,.14); color: #fff; border-color: rgba(255,255,255,.4); }
121    .comp-tab.active { background: var(--accent); color: #fff; border-color: var(--accent); }
122    .comp-table-loading { text-align: center; padding: 40px; color: rgba(255,255,255,.45); font-size: 15px; }
123    .comp-table { background: rgba(255,255,255,.05); border-radius: var(--r-lg); overflow: hidden; border: 1px solid rgba(255,255,255,.1); }
124    .comp-header, .comp-row { display: grid; grid-template-columns: 2.2fr 1.1fr 1fr .9fr auto; gap: 16px; padding: 18px 28px; align-items: center; }
125    .comp-header { background: rgba(255,255,255,.08); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; color: rgba(255,255,255,.45); }
126    .comp-row { border-top: 1px solid rgba(255,255,255,.07); transition: background .2s; cursor: pointer; }
127    .comp-row:hover { background: rgba(255,255,255,.06); }
128    .comp-info { display: flex; align-items: center; gap: 14px; }
129    .comp-card-img { width: 90px; height: 57px; border-radius: 8px; overflow: hidden; flex-shrink: 0; position: relative; box-shadow: 0 3px 10px rgba(0,0,0,.4); }
130    .comp-card-img img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 8px; display: block; }
131    /* Brand-accurate card badges — Chase Sapphire (navy), Amex Gold (gold), Cap One Venture X (dark), Discover (orange), Citi (blue) */
132    .ci-chase { background: linear-gradient(135deg,#0A2342 0%,#0F3D70 100%); border:1px solid rgba(255,255,255,.18); }
133    .ci-amex  { background: linear-gradient(135deg,#C9951A 0%,#9A7215 55%,#C9951A 100%); }
134    .ci-citi  { background: linear-gradient(135deg,#003B70 0%,#0057A8 100%); }
135    .ci-cap   { background: linear-gradient(135deg,#1A1A2E 0%,#2D1B4E 100%); border:1px solid rgba(209,48,39,.5); }
136    .ci-disc  { background: linear-gradient(135deg,#F76F20 0%,#E85D11 100%); }
137    .comp-name { font-size: 15px; font-weight: 600; }
138    .comp-sub { font-size: 12px; color: rgba(255,255,255,.45); margin-top: 2px; }
139    .comp-cell { font-size: 14px; color: rgba(255,255,255,.82); font-weight: 500; }
140    .comp-cell .hi { color: var(--accent-gold); font-weight: 700; }
141    .comp-cell .tiny { font-size: 11px; color: rgba(255,255,255,.4); }
142    .comp-cell .badge { background: rgba(30,127,212,.25); color: var(--accent-light); padding: 3px 9px; border-radius: 5px; font-size: 12px; font-weight: 600; }
143    .comp-btn { background: var(--accent); color: #fff; border: none; border-radius: 6px; padding: 9px 18px; font-size: 13px; font-weight: 600; cursor: pointer; transition: all .2s; font-family: inherit; white-space: nowrap; }
144    .comp-btn:hover { background: var(--accent-light); transform: translateY(-1px); }
145    /* ─── COMP PAGINATION & FOOTER ─── */
146    .comp-footer { display: flex; align-items: center; justify-content: space-between; margin-top: 24px; gap: 16px; flex-wrap: wrap; }
147    .comp-pagination { display: flex; align-items: center; gap: 6px; }
148    .comp-pager-btn { width: 36px; height: 36px; border-radius: 8px; border: 1.5px solid rgba(255,255,255,.2); background: rgba(255,255,255,.06); color: rgba(255,255,255,.75); font-size: 13px; cursor: pointer; transition: all .2s; display: inline-flex; align-items: center; justify-content: center; font-family: inherit; }
149    .comp-pager-btn:hover:not([disabled]) { background: rgba(255,255,255,.15); color: #fff; border-color: rgba(255,255,255,.4); }
150    .comp-pager-btn[disabled] { opacity: .28;
150 cursor: not-allowed; }
151    .comp-pager-num { width: 36px; height: 36px; border-radius: 8px; border: 1.5px solid transparent; background: transparent; color: rgba(255,255,255,.6); font-size: 14px; font-weight: 600; cursor: pointer; transition: all .2s; display: inline-flex; align-items: center; justify-content: center; font-family: inherit; }
152    .comp-pager-num:hover { background: rgba(255,255,255,.08); color: #fff; }
153    .comp-pager-num.active { background: var(--accent); color: #fff; border-color: var(--accent); }
154    .comp-see-all { display: inline-flex; align-items: center; gap: 8px; background: rgba(255,255,255,.1); border: 1.5px solid rgba(255,255,255,.25); color: #fff; padding: 9px 20px; border-radius: 8px; font-size: 14px; font-weight: 600; text-decoration: none; transition: all .2s; white-space: nowrap; }
155    .comp-see-all:hover { background: rgba(255,255,255,.18); border-color: rgba(255,255,255,.45); transform: translateY(-1px); }
156
157    /* ─── FOOTER ─── */
158    footer { background: var(--primary-dark); color: rgba(255,255,255,.65); padding: 60px 24px 28px; }
159    .footer-inner { max-width: 1280px; margin: 0 auto; }
160    .footer-top { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 48px; padding-bottom: 48px; border-bottom: 1px solid rgba(255,255,255,.1); }
161    .footer-brand p { font-size: 14px; line-height: 1.75; margin-top: 14px; color: rgba(255,255,255,.5); }
162    .footer-col h4 { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; color: rgba(255,255,255,.9); margin-bottom: 18px; }
163    .footer-col a { display: block; font-size: 14px; color: rgba(255,255,255,.5); text-decoration: none; margin-bottom: 11px; transition: color .2s; }
164    .footer-col a:hover { color: rgba(255,255,255,.9); }
165    .footer-bottom { padding-top: 26px; display: flex; justify-content: space-between; align-items: center; font-size: 12px; color: rgba(255,255,255,.3); flex-wrap: wrap; gap: 12px; }
166    .footer-bottom a { color: rgba(255,255,255,.3); text-decoration: none; }
167    .footer-bottom a:hover { color: rgba(255,255,255,.6); }
168    .foot-links { display: flex; gap: 20px; }
169
170    /* ─── SCROLL TOP ─── */
171    .scroll-top { position: fixed; bottom: 24px; right: 24px; width: 46px; height: 46px; background: var(--primary); color: #fff; border: none; border-radius: 50%; font-size: 17px; cursor: pointer; box-shadow: var(--shadow-md); display: flex; align-items: center; justify-content: center; transition: all .2s; z-index: 999; }
172    .scroll-top:hover { background: var(--primary-light); transform: translateY(-2px); }
173
174    /* ════════════════════════════════════════
175       NEW CSS ADDITIONS
176    ════════════════════════════════════════ */
177
178    /* ─── REVEAL ANIMATIONS ─── */
179    .reveal { opacity: 0; transform: translateY(28px); transition: opacity .65s ease, transform .65s ease; }
180    .reveal.visible { opacity: 1; transform: translateY(0); }
181    .reveal-d1 { transition-delay: .08s; }
182    .reveal-d2 { transition-delay: .16s; }
183    .reveal-d3 { transition-delay: .24s; }
184    .reveal-d4 { transition-delay: .32s; }
185    .reveal-d5 { transition-delay: .40s; }
186    .reveal-d6 { transition-delay: .48s; }
187    .reveal-d7 { transition-delay: .56s; }
188
189    /* ─── HAMBURGER ─── */
190    .hamburger { display: none; flex-direction: column; justify-content: center; align-items: center; width: 40px; height: 40px; background: none; border: none; cursor: pointer; gap: 5px; padding: 6px; border-radius: 6px; transition: background .2s; margin-left: auto; flex-shrink: 0; }
191    .hamburger:hover { background: rgba(255,255,255,.1); }
192    .hamburger span { display: block; width: 22px; height: 2px; background: rgba(255,255,255,.85); border-radius: 2px; transition: all .3s ease; }
193    .hamburger.open span:nth-child(1) { transform: rotate(45deg) translate(5px, 5px); }
194    .hamburger.open span:nth-child(2) { opacity: 0; transform: scaleX(0); }
195    .hamburger.open span:nth-child(3) { transform: rotate(-45deg) translate(5px, -5px); }
196
197    /* ─── MOBILE NAV ─── */
198    .nav-links.mobile-open { display: flex !important; flex-direction: column; align-items: flex-start; position: absolute; top: 64px; left: 0; right: 0; background: var(--primary-dark); padding: 12px 16px 20px; border-top: 1px solid rgba(255,255,255,.1); box-shadow: 0 8px 32px rgba(0,0,0,.3); z-index: 999; max-height: calc(100vh - 64px); overflow-y: auto; }
199    .nav-links.mobile-open .nav-link { width: 100%; padding: 12px 16px; }
200    .nav-links.mobile-open .nav-item { width: 100%; }
201    .nav-links.mobile-open .dropdown { position: static; opacity: 1; visibility: visible; transform: none; box-shadow: none; background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.1); margin-top: 4px; }
202    .nav-links.mobile-open .dropdown a { color: rgba(255,255,255,.75); }
203    .nav-links.mobile-open .dropdown a:hover { background: rgba(255,255,255,.08); color: #fff; }
204    .nav-links.mobile-open .dropdown a i { color: var(--accent-light); }
205    @media (max-width: 640px) { .logo-text { display: none; } .nav-inner { gap: 8px; padding: 0 16px; } }
206
207    /* ─── NEWSLETTER ─── */
208    .newsletter-section { background: var(--bg-light); padding: 64px 24px; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
209    .newsletter-inner { max-width: 640px; margin: 0 auto; text-align: center; }
210    .newsletter-icon { font-size: 42px; margin-bottom: 16px; display: block; }
211    .newsletter-inner h2 { font-size: 28px; font-weight: 800; letter-spacing: -.5px; margin-bottom: 10px; }
212    .newsletter-inner > p { font-size: 16px; color: var(--text-gray); margin-bottom: 28px; line-height: 1.65; }
213    .newsletter-form { display: flex; gap: 10px; margin-bottom: 14px; }
214    .newsletter-input { flex: 1; padding: 13px 16px; border: 1.5px solid var(--border); border-radius: var(--r-sm); font-size: 15px; outline: none; transition: border-color .2s; font-family: inherit; background: #fff; }
215    .newsletter-input:focus { border-color: var(--accent); }
216    .newsletter-submit { padding: 13px 22px; background: var(--primary); color: #fff; border: none; border-radius: var(--r-sm); font-size: 15px; font-weight: 700; cursor: pointer; transition: all .2s; font-family: inherit; white-space: nowrap; }
217    .newsletter-submit:hover { background: var(--primary-light); transform: translateY(-1px); }
218    .newsletter-error { color: #DC2626; font-size: 13px; margin-bottom: 10px; display: none; }
219    .newsletter-meta { font-size: 13px; color: var(--text-light); display: flex; gap: 20px; justify-content: center; flex-wrap: wrap; }
220    .newsletter-meta span { display: flex; align-items: center; gap: 5px; }
221    .newsletter-success { display: none; background: #ECFDF5; border-radius: var(--r-md); border: 1px solid #6EE7B7; padding: 24px; }
222    .newsletter-success h3 { font-size: 18px; font-weight: 700; color: #059669; margin-bottom: 6px; }
223    .newsletter-success p { font-size: 14px; color: #065F46; }
224    .newsletter-already { display: none; background: #EBF4FF; border-radius: var(--r-md); border: 1px solid var(--accent-light); padding: 16px 20px; font-size: 14px; color: var(--primary); font-weight: 500; }
225
226    /* ─── CARD DRAWER ─── */
227    .drawer-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.52); z-index: 1100; opacity: 0; visibility: hidden; transition: all .3s; }
228    .drawer-overlay.open { opacity: 1; visibility: visible; }
229    .drawer { position: fixed; top: 0; right: 0; width: 440px; height: 100vh; background: #fff; z-index: 1101; overflow-y: auto; transform: translateX(100%); transition: transform .35s cubic-bezier(.4,0,.2,1); box-shadow: -8px 0 40px rgba(0,0,0,.2); }
230    .drawer.open { transform: translateX(0); }
231    .drawer-header { display: flex; align-items: center; justify-content: space-between; padding: 18px 24px; border-bottom: 1px solid var(--border); position: sticky; top: 0; background: #fff; z-index: 2; }
232    .drawer-header span { font-size: 13px; color: var(--text-gray); }
233    .drawer-close { width: 32px; height: 32px; background: var(--bg-light); border: none; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 14px; color: var(--text-gray); transition: all .2s; }
234    .drawer-close:hover { background: var(--border); color: var(--text-dark); }
235    .drawer-body { padding: 24px; }
236    .drawer-card-hd { display: flex; align-items: center; gap: 16px; margin-bottom: 18px; }
237    .drawer-card-img { width: 72px; height: 46px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; flex-shrink: 0; }
238    .drawer-card-name { font-size: 18px; font-weight: 800; line-height: 1.3; }
239    .drawer-card-sub { font-size: 13px; color: var(--text-gray); margin-top: 3px; }
240    .drawer-score-bar { display: flex; align-items: center; gap: 10px; background: var(--bg-light); border-radius: var(--r-sm); padding: 10px 14px; margin-bottom: 20px; }
241    .drawer-stars { color: var(--accent-gold); font-size: 15px; letter-spacing: 1px; }
242    .drawer-score-val { font-size: 15px; font-weight: 700; }
243    .drawer-score-lbl { font-size: 13px; color: var(--text-gray); }
244    .drawer-divider { height: 1px; background: var(--border); margin: 18px 0; }
245    .drawer-details { display: flex; flex-direction: column; gap: 11px; }
246    .drawer-row { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; }
247    .drawer-lbl { font-size: 13px; color: var(--text-gray); font-weight: 500; }
248    .drawer-val { font-size: 14px; font-weight: 600; color: var(--text-dark); text-align: right; }
249    .drawer-val.gold { color: #D97706; }
250    .drawer-proscons { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
251    .drawerpc h5 { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .8px; margin-bottom: 10px; }
252    .pros-title { color: #059669; }
253    .cons-title { color: #DC2626; }
254    .drawerpc ul { list-style: none; display: flex; flex-direction: column; gap: 8px; }
255    .drawerpc ul li { font-size: 13px; color: var(--text-gray); display: flex; gap: 7px; align-items: flex-start; line-height: 1.4; }
256    .drawerpc ul li span { flex-shrink: 0; font-size: 12px;
256 margin-top: 1px; }
257    .drawer-actions { display: flex; gap: 12px; position: sticky; bottom: 0; background: #fff; padding: 16px 24px; border-top: 1px solid var(--border); margin: 0 -24px -24px; }
258    .drawer-apply { flex: 1; padding: 13px; background: var(--primary); color: #fff; border: none; border-radius: var(--r-sm); font-size: 15px; font-weight: 700; cursor: pointer; transition: all .2s; font-family: inherit; }
259    .drawer-apply:hover { background: var(--primary-light); }
260    .drawer-learn { padding: 13px 18px; background: var(--bg-light); color: var(--text-dark); border: 1.5px solid var(--border); border-radius: var(--r-sm); font-size: 14px; font-weight: 600; cursor: pointer; transition: all .2s; font-family: inherit; white-space: nowrap; }
261    .drawer-learn:hover { border-color: var(--accent); color: var(--accent); }
262
263    /* ════════════════════════════════════════
264       RESPONSIVE
265    ════════════════════════════════════════ */
266    @media (max-width: 1024px) {
267      .nav-links { display: none; }
268      .hamburger { display: flex; }
269      .nav-actions { gap: 6px; }
270      .nav-actions .btn-primary, .nav-actions .btn-outline { padding: 7px 10px; font-size: 12px; white-space: nowrap; }
271      .navbar { position: relative; }
272      .comp-header { display: none; }
273      .comp-row { grid-template-columns: 1fr 1fr; gap: 10px; padding: 16px 20px; }
274      .comp-info { grid-column: 1 / -1; }
275      .footer-top { grid-template-columns: 1fr 1fr; gap: 36px; }
276      .drawer { width: 100%; max-width: 440px; }
277    }
278    @media (max-width: 768px) {
279      .section { padding: 52px 20px; }
280      .section-title { font-size: 26px; }
281      .comp-row { grid-template-columns: 1fr; }
282      .footer-top { grid-template-columns: 1fr; gap: 28px; }
283      .footer-bottom { flex-direction: column; align-items: flex-start; gap: 10px; }
284      .newsletter-form { flex-direction: column; }
285      .newsletter-submit { width: 100%; }
286      .drawer { width: 100%; }
287    }
288
289    /* ─── SKIP LINK ─── */
290    .skip-link { position: absolute; top: -100%; left: 16px; background: var(--accent); color: #fff; padding: 10px 18px; border-radius: 0 0 var(--r-sm) var(--r-sm); font-size: 14px; font-weight: 700; text-decoration: none; z-index: 9999; transition: top .2s; }
291    .skip-link:focus { top: 0; }
292
293    /* ─── ADVERTISER DISCLOSURE BAR ─── */
294    .adv-bar { background: #FFFBEB; border-bottom: 1px solid #FDE68A; padding: 10px 24px; }
295    .adv-bar-inner { max-width: 1280px; margin: 0 auto; font-size: 13px; color: #78350F; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
296    .adv-bar-inner i { color: #D97706; flex-shrink: 0; }
297    .adv-bar-inner a { color: #92400E; font-weight: 700; text-decoration: underline; }
298    .adv-bar-inner a:hover { color: #78350F; }
299
300    /* ─── COOKIE BANNER ─── */
301    .cookie-banner { position: fixed; bottom: 0; left: 0; right: 0; background: var(--primary-dark); border-top: 1px solid rgba(255,255,255,.15); padding: 16px 24px; z-index: 2000; display: flex; align-items: center; gap: 20px; flex-wrap: wrap; box-shadow: 0 -4px 24px rgba(0,0,0,.3); animation: slideUp .35s ease; }
302    .cookie-banner.hidden { display: none; }
303    @keyframes slideUp { from { transform: translateY(100%); } to { transform: translateY(0); } }
304    .cookie-banner p { font-size: 14px; color: rgba(255,255,255,.8); flex: 1; min-width: 200px; line-height: 1.5; margin: 0; }
305    .cookie-banner p a { color: var(--accent-light); text-decoration: underline; }
306    .cookie-actions { display: flex; gap: 10px; flex-shrink: 0; }
307    .cookie-accept { padding: 9px 20px; background: var(--accent); color: #fff; border: none; border-radius: 6px; font-size: 14px; font-weight: 700; cursor: pointer; transition: background .2s; font-family: inherit; }
308    .cookie-accept:hover { background: var(--accent-light); }
309    .cookie-decline { padding: 9px 16px; background: transparent; color: rgba(255,255,255,.65); border: 1px solid rgba(255,255,255,.25); border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; transition: all .2s; font-family: inherit; }
310    .cookie-decline:hover { border-color: rgba(255,255,255,.6); color: #fff; }
311
312    /* ─── USER NAV (logged-in state) ─── */
313    .user-nav { position: relative; }
314    .user-btn { display: flex; align-items: center; gap: 9px; padding: 5px 12px 5px 6px; background: rgba(255,255,255,.1); border: 1.5px solid rgba(255,255,255,.22); border-radius: 100px; cursor: pointer; transition: all .2s; color: #fff; font-family: inherit; font-size: 14px; font-weight: 600; }
315    .user-btn:hover { background: rgba(255,255,255,.18); border-color: rgba(255,255,255,.45); }
316    .user-avatar-sm { width: 30px; height: 30px; background: var(--accent); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 800; color: #fff; flex-shrink: 0; letter-spacing: -.5px; }
317    .user-name-sm { max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
318    .user-btn .fa-chevron-down { font-size: 10px; opacity: .65; }
319    .user-dropdown { position: absolute; top: calc(100% + 10px); right: 0; background: #fff; border-radius: var(--r-md); box-shadow: var(--shadow-lg); border: 1px solid var(--border); min-width: 226px; padding: 10px; opacity: 0; visibility: hidden; transform: translateY(-8px); transition: all .2s; z-index: 2000; }
320    .user-nav.open .user-dropdown { opacity: 1; visibility: visible; transform: translateY(0); }
321    .user-dropdown-header { padding: 10px 12px 14px; border-bottom: 1px solid var(--border); margin-bottom: 8px; }
322    .user-dropdown-name { font-size: 15px; font-weight: 700; color: var(--text-dark); }
323    .user-dropdown-email { font-size: 12px; color: var(--text-gray); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 190px; }
324    .user-dropdown a { display: flex; align-items: center; gap: 10px; padding: 9px 12px; color: var(--text-dark); text-decoration: none; font-size: 14px; border-radius: var(--r-sm); transition: background .15s; }
325    .user-dropdown a:hover { background: var(--bg-light); color: var(--primary); }
326    .user-dropdown a i { width: 16px; color: var(--accent); font-size: 13px; text-align: center; }
327    .user-dropdown-divider { height: 1px; background: var(--border); margin: 8px 0; }
328    .user-signout { display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 12px; color: #DC2626; background: none; border: none; font-size: 14px; cursor: pointer; border-radius: var(--r-sm); transition: background .15s; font-family: inherit; text-align: left; }
329    .user-signout:hover { background: #FEF2F2; }
330    .user-signout i { width: 16px; font-size: 13px; text-align: center; }
331
332    /* ─── PERSONAL MATCH BANNER (logged-in) ─── */
333    .personal-banner { background: linear-gradient(135deg, #071E4A 0%, #0C2660 100%); border-bottom: 2px solid rgba(30,127,212,.6); padding: 13px 24px; }
334    .personal-banner.hidden { display: none; }
335    .personal-banner-inner { max-width: 1280px; margin: 0 auto; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
336    .pb-greeting { font-size: 14px; color: rgba(255,255,255,.65); white-space: nowrap; flex-shrink: 0; }
337    .pb-greeting b { color: #fff; font-weight: 700; }
338    .pb-sep { width: 1px;
338 height: 26px; background: rgba(255,255,255,.14); flex-shrink: 0; }
339    .pb-label { font-size: 11px; color: rgba(255,255,255,.45); white-space: nowrap; flex-shrink: 0; font-weight: 600; text-transform: uppercase; letter-spacing: .8px; }
340    .pb-match { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; }
341    .pb-badge { width: 78px; height: 49px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 8px; font-weight: 700; flex-shrink: 0; overflow: hidden; }
342    .pb-card-name { font-size: 14px; font-weight: 700; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
343    .pb-card-rate { font-size: 12px; color: rgba(255,255,255,.45); margin-top: 1px; white-space: nowrap; }
344    .pb-earn { font-size: 20px; font-weight: 800; color: var(--accent-gold); white-space: nowrap; flex-shrink: 0; line-height: 1; }
345    .pb-earn small { font-size: 10px; color: rgba(255,255,255,.4); font-weight: 400; display: block; margin-top: 2px; }
346    .pb-actions { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }
347    .pb-acct-btn { padding: 7px 13px; background: rgba(255,255,255,.1); color: rgba(255,255,255,.85); border: 1px solid rgba(255,255,255,.2); border-radius: 6px; font-size: 12px; font-weight: 600; text-decoration: none; transition: all .2s; white-space: nowrap; display: inline-flex; align-items: center; gap: 5px; }
348    .pb-acct-btn:hover { background: rgba(255,255,255,.18); color: #fff; border-color: rgba(255,255,255,.45); }
349    .pb-retake { padding: 7px 13px; background: var(--accent); color: #fff; border: none; border-radius: 6px; font-size: 12px; font-weight: 600; cursor: pointer; transition: background .2s; font-family: inherit; white-space: nowrap; }
350    .pb-retake:hover { background: var(--accent-light); }
351    @media (max-width: 768px) { .pb-sep { display: none; } .pb-label { display: none; } .pb-earn { font-size: 17px; } }
352
353    /* ─── HERO: SPEND CALCULATOR ─── */
354    .sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
355    .hx-inner { max-width: 1280px; margin: 0 auto; }
356    /* the hand: photo tinted into the navy, small line, five real cards fanned across the seam */
357    .hx { position: relative; overflow: hidden; }
358    .hand { position: relative; overflow: hidden; background: var(--primary-dark); height: 640px; }
359    .hand::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 44px; z-index: 2; background: linear-gradient(to bottom right, transparent 49.5%, #fff 50.5%); }
360    .hand-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 60% 40%; }
361    .hand-scrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(7,30,74,.8) 0, rgba(7,30,74,.8) 200px, rgba(7,30,74,.68) 300px, rgba(7,30,74,.68) 380px, var(--primary-dark) 520px); }
362    .hand-copy { position: relative; z-index: 3; padding: 36px 24px 0; }
363    .hand-copy h1 { font-size: 26px; font-weight: 800; color: #fff; line-height: 1.3; letter-spacing: -.5px; }
364    .hand-actions { display: flex; align-items: center; gap: 22px; margin-top: 16px; flex-wrap: wrap; }
365    .hand-go { display: inline-flex; align-items: center; height: 46px; padding: 0 20px; border: 1.5px solid rgba(255,255,255,.55); border-radius: 6px; color: #fff; font-size: 15px; font-weight: 600; text-decoration: none; }
366    .hand-go:hover { border-color: #fff; background: rgba(255,255,255,.08); }
367    .hand-all { display: inline-flex; align-items: center; min-height: 44px; color: #fff; font-size: 15px; font-weight: 600; }
368    /* the fan sits outside the clipped band so its lowest cards cross the seam onto the white */
369    .hand-fan { position: absolute; left: 50%; top: 400px; width: 1060px; height: 520px; margin-left: -530px; z-index: 2; pointer-events: none; }
370    .hf { position: absolute; transform-origin: 50% 160%; }
371    .hf img { display: block; width: 460px; height: 290px; object-fit: cover; border-radius: 24px; box-shadow: 0 8px 20px rgba(0,0,0,.5); }
372    .hf1 { left: 0; top: 70px; transform: rotate(-28deg); }
373    .hf2 { left: 150px; top: 22px; transform: rotate(-14deg); }
374    .hf3 { left: 300px; top: 0; z-index: 1; }
375    .hf4 { left: 450px; top: 22px; transform: rotate(14deg); }
376    .hf5 { left: 600px; top: 70px; transform: rotate(28deg); }
377    .hx-calc-hd { padding: 290px 24px 0; }
378    .hx-calc-hd h2 { font-size: 52px; font-weight: 800; color: var(--primary-dark); line-height: 1.13; letter-spacing: -1.5px; font-variant-numeric: tabular-nums; }
379    .hero-badge { display: inline-flex; align-items: center; gap: 8px; background: rgba(255,255,255,.11); border: 1px solid rgba(255,255,255,.2); color: var(--accent-light); padding: 6px 14px; border-radius: 100px; font-size: 13px; font-weight: 500; margin-bottom: 18px; }
380    .hero-badge[hidden] { display: none; }
381    .hx-body { display: grid; grid-template-columns: minmax(0, 11fr) minmax(0, 13fr); gap: 72px; padding: 4px 24px 56px; align-items: start; }
382
383    .hx-head { display: flex; justify-content: space-between; padding-bottom: 10px; border-bottom: 1.5px solid var(--primary-dark); font-size: 13px; color: var(--text-gray); }
384    .hx-row { display: grid; grid-template-columns: 124px minmax(0, 1fr) 92px; align-items: center; gap: 16px; padding: 10px 0; border-bottom: 1px solid var(--border); }
385    .hx-row-label { font-size: 15px; font-weight: 600; color: var(--primary-dark); }
386    .hx-row-label small { display: block; font-size: 12px; font-weight: 400; line-height: 1.3; color: var(--text-gray); }
387    .hx-seg { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; border: 1px solid #CBD5E0; border-radius: 6px; overflow: hidden; }
388    .hx-seg button { height: 44px; padding: 0; border: 0; border-left: 1px solid #CBD5E0; background: #fff; color: var(--primary-dark); font: 600 14px/1 inherit; font-variant-numeric: tabular-nums; cursor: pointer; }
389    .hx-seg button:first-child { border-left: 0; }
390    .hx-seg button:hover { background: var(--bg-light); }
391    .hx-seg button[aria-pressed="true"] { background: var(--primary); color: #fff; }
392    .hx-seg button:focus-visible, .hx-tabs button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
393    .hx-earn { text-align: right; font-size: 14px; color: var(--text-gray); white-space: nowrap; font-variant-numeric: tabular-nums; }
394    .hx-earn strong { color: var(--primary-dark); font-weight: 700; }
395    .hx-note { margin-top: 16px; font-size: 13px; line-height: 1.6; color: var(--text-gray); }
396    .hx-note a, .hx-legal a { color: inherit; }
397
398    .hx-tabs { display: flex; gap: 24px; border-bottom: 1.5px solid var(--primary-dark); }
399    .hx-tabs button { height: 44px; padding: 0; border: 0; border-bottom: 3px solid transparent; margin-bottom: -1.5px; background: none; color: var(--text-gray); font: 600 14px/1 inherit; cursor: pointer; }
400    .hx-tabs button[aria-pressed="true"] { color: var(--primary-dark); border-bottom-color: var(--accent); }
401    .hx-stage { position: relative; height: 296px; margin-top: 8px; }
402    .hx-art { position: absolute; display: block; }
403    .hx-art img { display: block; width: 100%; height: 100%; }
404    /* Issuer art is a flat JPEG with white corners: clip them. 8.25% = 5.2% x the card's 1.586 ratio. */
405    .hx-art.flat img, .cc-thumb.flat img { object-fit: cover; border-radius: 5.2% / 8.25%; }
406    .hx-art.flat img { box-shadow: 0 2px 3px rgba(7,30,74,.25), 14px 30px 56px rgba(7,30,74,.3); }
407    .hx-art.asis img, .cc-thumb.asis img { object-fit: contain; }
408    .hx-art.asis img { filter: drop-shadow(8px 18px 22px rgba(7,30,74,.28)); }
409    /* The Amex Gold art is two cards on a white field: blend the white away, never clip or shadow it. */
410    .hx-art.gold img, .cc-thumb.gold img { object-fit: contain; mix-blend-mode: multiply; }
411    .hx-win { left: 0; top: 30px; width: 352px; height: 222px; transform: rotate(-8deg); z-index: 3; transition: transform .25s ease; }
412    .hx-win:hover { transform: rotate(-8deg) translateY(-6px); }
413    .hx-win.gold { transform: none; }
414    .hx-r2 { left: 206px; top: 14px; width: 280px; height: 177px; z-index: 2; }
415    .hx-r3 { left: 318px; top: 42px; width: 280px; height: 177px; transform: rotate(9deg); z-index: 1; }
416    .hx-meta { font-size: 13px; color: var(--text-gray); }
417    .hx-name { margin-top: 2px; font-size: 28px; font-weight: 800; letter-spacing: -.6px; line-height: 1.2; }
418    .hx-name a { color: var(--primary-dark); text-decoration: none; }
419    .hx-name a:hover { text-decoration: underline; }
420    .hx-figrow { display: flex; align-items: baseline; gap: 12px; margin-top: 10px; flex-wrap: wrap; }
421    .hx-fig { font-size: 64px; font-weight: 800; letter-spacing: -2.1px; line-height: 1; color: var(--primary-dark); font-variant-numeric: tabular-nums; }
422    .hx-figlabel { font-size: 15px; font-weight: 600; color: var(--text-gray); }
423    .hx-recip { margin-left: auto; font-size: 14px; color: var(--text-gray); font-variant-numeric: tabular-nums; }
424    .hx-recip strong { color: var(--primary-dark); }
425    .hx-ledger { margin-top: 14px; border-top: 1px solid var(--border); font-size: 14px; font-variant-numeric: tabular-nums; }
426    .hx-ledger div { display: flex; justify-content: space-between; gap: 16px; padding: 8px 0; border-bottom: 1px solid var(--border); color: var(--text-gray); }
427    .hx-ledger strong { color: var(--primary-dark); white-space: nowrap; }
428    .hx-worth { margin-top: 10px; font-size: 13px; line-height: 1.5; color: var(--text-gray); }
429    .hx-next { display: flex; gap: 8px 24px; flex-wrap: wrap; margin-top: 12px; font-size: 14px; color: var(--text-gray); font-variant-numeric: tabular-nums; }
430    .hx-next strong { color: var(--primary-dark); }
431    .hx-actions { display: flex; align-items: center; gap: 18px; margin-top: 16px; flex-wrap: wrap; }
432    .hx-cta { display: inline-flex; align-items: center; height: 48px; padding: 0 26px; background: var(--primary); color: #fff; border-radius: 6px; font-size: 15px; font-weight: 700; text-decoration: none; }
433    .hx-cta:hover { background: var(--primary-light); }
434    .hx-actions span { font-size: 14px; color: var(--text-gray); }
435    .hx-links { display: flex; flex-wrap: wrap; gap: 4px 22px; margin-top: 6px; font-size: 14px; font-weight: 600; }
436    .hx-links a { display: inline-flex; align-items: center; min-height: 44px; color: var(--primary); }
437    .hx-legal { margin-top: 10px; padding-top: 12px; border-top: 1px solid var(--border); font-size: 12px; line-height: 1.5; color: var(--text-gray); }
438
439    /* ─── HOMEPAGE SECTIONS ─── */
440    .hp { padding: 0 24px; }
441    .hp-inner { max-width: 1280px; margin: 0 auto; padding: 56px 0 64px; border-top: 1px solid var(--border); }
442    .hp-first .hp-inner { border-top: 0; }
443    .hp-hd { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; margin-bottom: 24px; }
444    .hp-hd h2 { font-size: 36px; font-weight: 800; letter-spacing: -1px; line-height: 1.2; color: var(--primary-dark); }
445    .hp-hd > a, .hp-hd > span { font-size: 15px; white-space: nowrap; }
446    .hp-hd > a { display: inline-flex; align-items: center; min-height: 44px; font-weight: 600; color: var(--primary); }
447    .hp-hd > span { color: var(--text-gray); }
448    .cc-thumb { display: block; flex-shrink: 0; }
449    .cc-thumb img { display: block; width: 100%; height: 100%; }
450    .cc-thumb.flat img { box-shadow: 0 1px 2px rgba(7,30,74,.25), 4px 8px 16px rgba(7,30,74,.2); }
451
452    .tools { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 72px; align-items: start; }
453    .cmp-row { display: grid; grid-template-columns: 150px repeat(3, minmax(0, 1fr)); column-gap: 20px; align-items: baseline; padding: 13px 0; border-bottom: 1px solid var(--border); font-size: 15px; font-variant-numeric: tabular-nums; }
454    .cmp-row > span:first-child { font-size: 14px; color: var(--text-gray); }
455    .cmp-row > span + span { font-weight: 600; color: var(--primary-dark); }
456    .cmp-head { align-items: end; padding: 0 0 14px; border-bottom: 1.5px solid var(--primary-dark); }
457    .cmp-head > span:first-child { font-size: 13px; }
458    .cmp-card { display: flex; flex-direction: column; gap: 10px; font-weight: 700; line-height: 1.3; }
459    .cmp-card .cc-thumb { width: 132px; height: 83px; }
460    .quiz-q { padding-bottom: 14px; border-bottom: 1.5px solid var(--primary-dark); font-size: 17px; font-weight: 700; line-height: 1.4; color: var(--primary-dark); }
461    .quiz-opt { display: flex; align-items: center; justify-content: space-between; min-height: 52px; border-bottom: 1px solid var(--border); font-size: 15px; font-weight: 500; color: var(--primary-dark); text-decoration: none; }
462    .quiz-opt:hover { color: var(--accent); }
463    .quiz-foot { margin-top: 14px; font-size: 13px; color: var(--text-gray); }
464
465    .off-row { display: grid; grid-template-columns: 88px minmax(0, 1.1fr) minmax(0, 1.5fr) 96px 96px 104px; column-gap: 24px; align-items: center; padding: 12px 0; border-bottom: 1px solid var(--border); font-size: 15px; color: var(--primary-dark); text-decoration: none; font-variant-numeric: tabular-nums; }
466    a.off-row:hover .off-name { text-decoration: underline; }
467    .off-head { padding: 0 0 8px; border-bottom: 1.5px solid var(--primary-dark); font-size: 13px; color: var(--text-gray); }
468    .off-row .cc-thumb { width: 88px; height: 55px; }
469    .off-name { font-weight: 700; line-height: 1.3; }
470    .off-issuer { display: block; font-size: 13px; font-weight: 400; color: var(--text-gray); }
471    .off-desc { color: var(--text-gray); line-height: 1.4; }
472    .off-val { font-size: 22px; font-weight: 800; letter-spacing: -.5px; }
473    .off-r { text-align: right; }
474
475    .lanes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
476    .lane { display: flex; flex-direction: column; justify-content: space-between; gap: 20px; padding: 24px; border: 1px solid var(--border); border-radius: var(--r-sm); color: var(--primary-dark); text-decoration: none; overflow: hidden; }
477    .lane:hover { border-color: var(--primary); }
478    .lane-art { position: relative; height: 128px; }
479    .lane-art .cc-thumb { position: absolute; width: 170px; height: 107px; }
480    .lane-art .cc-thumb:first-child { left: 0; top: 18px; transform: rotate(-5deg); z-index: 1; }
481    .lane-art .cc-thumb + .cc-thumb { left: 96px; top: 0; transform: rotate(6deg); }
482    .lane-ft { display: flex; justify-content: space-between; align-items: baseline; }
483    .lane-ft strong { font-size: 22px; font-weight: 800; letter-spacing: -.4px; }
484    .lane-ft span { font-size: 14px; color: var(--text-gray); }
485
486    .issuers { padding: 20px 24px; background: var(--bg-light); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
487    .issuers p { max-width: 1280px; margin: 0 auto; display: flex; flex-wrap: wrap; gap: 6px 28px; align-items: baseline; font-size: 15px; font-weight: 700; color: var(--primary-dark); }
488    .issuers p span:first-child { font-size: 13px; font-weight: 400; color: var(--text-gray); margin-right: 8px; }
489
490    .guides { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 72px; }
491    .guides a { color: var(--primary-dark); text-decoration: none; }
492    .guides a:hover h3 { text-decoration: underline; }
493    .g-tag { font-size: 13px; color: var(--accent); font-weight: 600; }
494    .g-meta { font-size: 13px; color: var(--text-gray); }
495    .g-lead { display: flex; flex-direction: column; gap: 14px; padding-top: 20px; border-top: 1.5px solid var(--primary-dark); }
496    .g-lead h3 { font-size: 34px; font-weight: 800; letter-spacing: -.9px; line-height: 1.18; }
497    .g-lead p { font-size: 17px; line-height: 1.6; color: var(--text-gray); }
498    .g-item { display: flex; flex-direction: column; gap: 6px; padding: 20px 0; border-top: 1px solid var(--border); }
499    .g-item:first-child { border-top: 1.5px solid var(--primary-dark); }
500    .g-item h3 { font-size: 19px; font-weight: 700; letter-spacing: -.2px; line-height: 1.3; }
501    .g-item p { font-size: 14px; line-height: 1.55; color: var(--text-gray); }
502
503    @media (max-width: 1024px) {
504      .hx-body { grid-template-columns: minmax(0, 1fr); gap: 40px; }
505      .hx-result { order: -1; }
506      .tools, .guides { grid-template-columns: minmax(0, 1fr); gap: 48px; }
507      .off-row { grid-template-columns: 88px minmax(0, 1fr) 96px 104px; }
508      .off-desc, .off-fee { display: none; }
509    }
510    @media (max-width: 640px) {
511      .hand { height: 500px; }
512      .hand::after { height: 24px; }
513      .hand-scrim { background: linear-gradient(180deg, rgba(7,30,74,.8) 0, rgba(7,30,74,.8) 150px, rgba(7,30,74,.68) 210px, rgba(7,30,74,.68) 290px, var(--primary-dark) 400px); }
514      .hand-copy { padding: 28px 20px 0; }
515      .hand-copy h1 { font-size: 24px; line-height: 1.25; max-width: 300px; }
516      .hand-actions { gap: 4px 18px; margin-top: 12px; }
517      .hand-go { height: 44px; padding: 0 18px; font-size: 14px; }
518      .hand-fan { top: 236px; width: 390px; height: 330px; margin-left: -195px; }
519      .hf { transform-origin: 50% 130%; }
520      .hf img { width: 210px; height: 132px; border-radius: 11px; }
521      .hf1, .hf5 { display: none; }
522      .hf2 { left: 40px; top: 44px; transform: rotate(-13deg); }
523      .hf3 { left: 90px; top: 0; }
524      .hf4 { left: 140px; top: 44px; transform: rotate(13deg); }
525      .hx-calc-hd { padding: 36px 20px 0; }
526      .hx-calc-hd h2 { font-size: 28px; letter-spacing: -.8px; }
527      .hx-body { padding: 0 20px 40px; }
528      .hx-row { grid-template-columns: minmax(0, 1fr) auto; gap: 8px 12px; }
529      .hx-seg { grid-column: 1 / -1; grid-row: 2; }
530      .hx-stage { height: 226px; }
531      .hx-win { width: 290px; height: 183px; top: 18px; }
532      .hx-r2 { left: 150px; top: 6px; width: 200px; height: 126px; }
533      .hx-r3 { display: none; }
534      .hx-fig { font-size: 56px; letter-spacing: -1.8px; }
535      .hx-recip { margin-left: 0; flex-basis: 100%; }
536      .hx-cta { width: 100%; justify-content: center; }
537      .hp { padding: 0 20px; }
538      .hp-inner { padding: 40px 0 44px; }
539      .hp-hd h2 { font-size: 26px; letter-spacing: -.6px; }
540      .cmp-row { grid-template-columns: 96px repeat(3, minmax(0, 1fr)); column-gap: 10px; font-size: 13px; }
541      .cmp-row > span:first-child { font-size: 12px; }
542      .cmp-card .cc-thumb { width: 100%; height: auto; aspect-ratio: 1.586; }
543      .off-row { grid-template-columns: 72px minmax(0, 1fr) auto; column-gap: 14px; }
544      .off-row .cc-thumb { width: 72px; height: 45px; }
545      .off-checked { display: none; }
546      .lanes { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
547      .lane { padding: 16px; gap: 14px; }
548      .lane-art { height: 84px; }
549      .lane-art .cc-thumb { width: 112px; height: 71px; }
550      .lane-art .cc-thumb + .cc-thumb { display: none; }
551      .lane-ft { flex-direction: column; gap: 2px; }
552      .lane-ft strong { font-size: 18px; }
553      .g-lead h3 { font-size: 24px; letter-spacing: -.5px; }
554      .g-lead p { font-size: 15px; }
555    }
556    @media (max-width: 1024px) and (min-width: 641px) { .hand-fan { transform: scale(.78); transform-origin: 50% 100%; } }
557    @media (prefers-reduced-motion: reduce) {
558      *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
559      .reveal { opacity: 1 !important; transform: none !important; }
560    }
561  </style>
562  
562<script src="nav-search.js?v=2"></script>
562
563</head>
564<body>
565<a href="#main-content" class="skip-link">Skip to main content</a>
566
567<!-- ═══════════ NAVBAR ═══════════ -->
568<nav class="navbar">
569  <div class="nav-inner">
570    <a href="/" class="logo">
571      <div class="logo-icon">
572        <img src="images/logo-icon.svg" alt="CardCompass compass logo" width="40" height="40">
573      </div>
574      <span class="logo-text">Card<span>Compass</span></span>
575    </a>
576
577    <div class="nav-links" id="nav-links">
578      <div class="nav-item">
579        <button class="nav-link" aria-expanded="false" aria-haspopup="true">Credit Cards <i class="fas fa-chevron-down"></i></button>
580        <div class="dropdown">
581          <a href="/all-cards" style="font-weight:700"><i class="fas fa-th-list"></i> All Credit Cards</a>
582          <div style="height:1px;background:#E2E8F0;margin:6px 0;"></div>
583          <a href="/bonus-offers"><i class="fas fa-gift"></i> Current Bonus Offers</a>
584          <a href="/cards?cat=cashback"><i class="fas fa-star"></i> Best Cash Back Cards</a>
585          <a href="/cards?cat=travel"><i class="fas fa-plane"></i> Best Travel Cards</a>
586          <a href="/cards?cat=hotel"><i class="fas fa-hotel"></i> Best Hotel Cards</a>
587          <a href="/cards?cat=airline"><i class="fas fa-plane-departure"></i> Best Airline Cards</a>
588          <a href="/cards?cat=gas"><i class="fas fa-gas-pump"></i> Best Gas Cards</a>
589          <a href="/cards?cat=dining"><i class="fas fa-utensils"></i> Best Dining Cards</a>
590          <a href="/cards?cat=nofee"><i class="fas fa-shield-alt"></i> No Annual Fee Cards</a>
591          <a href="/cards?cat=balancetransfer"><i class="fas fa-sync-alt"></i> Balance Transfer Cards</a>
592          <a href="/cards?cat=business"><i class="fas fa-briefcase"></i> Best Business Cards</a>
593          <a href="/cards?cat=student"><i class="fas fa-graduation-cap"></i> Student Cards</a>
594          <a href="/cards?cat=secured"><i class="fas fa-lock"></i> Build Credit / Secured</a>
595        </div>
596      </div>
597      <div class="nav-item">
598        <button class="nav-link" aria-expanded="false" aria-haspopup="true">Rewards <i class="fas fa-chevron-down"></i></button>
599        <div class="dropdown">
600          <a href="/rewards-calculator"><i class="fas fa-calculator"></i> Points Calculator</a>
601          <a href="/rewards-partners"><i class="fas fa-exchange-alt"></i> Transfer Partners</a>
602          <a href="/rewards-maximize"><i class="fas fa-chart-line"></i> Maximize Your Points</a>
603          <a href="/rewards-award-travel"><i class="fas fa-suitcase"></i> Award Travel Guide</a>
604          <a href="/rewards-optimizer"><i class="fas fa-dollar-sign"></i> Cash Back Optimizer</a>
605          <a href="/balance-transfer-calculator"><i class="fas fa-sync-alt"></i> Balance Transfer Calc</a>
606        </div>
607      </div>
608      <div class="nav-item">
609        <button class="nav-link" aria-expanded="false" aria-haspopup="true">Airlines <i class="fas fa-chevron-down"></i></button>
610        <div class="dropdown">
611          <a href="/airlines" style="font-weight:700"><i class="fas fa-plane"></i> All Airlines</a>
612          <div style="height:1px;background:#E2E8F0;margin:6px 0;"></div>
613                    <a href="/airline-transfer-matrix"><i class="fas fa-table"></i> Transfer Partner Matrix</a>
614          <a href="/airline-search-programs"><i class="fas fa-search"></i> Search All 23 Programs</a>
615          <div style="height:1px;background:#E2E8F0;margin:6px 0;"></div>
616          <a href="/airlines/united"><i class="fas fa-plane-departure"></i> United MileagePlus</a>
617          <a href="/airlines/delta"><i class="fas fa-plane-departure"></i> Delta SkyMiles</a>
618          <a href="/airlines/american"><i class="fas fa-plane-departure"></i> American AAdvantage</a>
619          <a href="/airlines/southwest"><i class="fas fa-plane-departure"></i> Southwest Rapid Rewards</a>
620          <a href="/airlines/alaska"><i class="fas fa-plane-departure"></i> Alaska Mileage Plan</a>
621          <a href="/airlines/jetblue"><i class="fas fa-plane-departure"></i> JetBlue TrueBlue</a>
622          <a href="/airlines/hawaiian"><i class="fas fa-plane-departure"></i> Hawaiian Miles</a>
623        </div>
624      </div>
625      <a href="/quiz" class="nav-link">Card Quiz</a>
626      <a href="/compare" class="nav-link">Compare Cards</a>
627      <a href="/my-current-wallet" class="nav-link">My Current Wallet</a>
628      <a href="/guides" class="nav-link">Guides</a>
629    </div>
630
631    <div class="nav-actions">
632      <a href="/login" class="btn-outline">Log In</a>
633      <a href="/get-started" class="btn-primary">Get Started Free</a>
634    </div>
635    <button class="hamburger" id="hamburger" aria-label="Toggle menu">
636      <span></span><span></span><span></span>
637    </button>
638  </div>
639</nav>
640
641<!-- ═══════════ HERO: SPEND CALCULATOR ═══════════ -->
642<section class="hx" id="main-content">
643  <div class="hand">
644    <img class="hand-photo" src="https://images.unsplash.com/photo-1556740738-b6a63e27c4df?w=1600&q=75&auto=format&fit=crop&monochrome=071e4a&con=-35&exp=8&blend=071e4a&bm=normal&blend-alpha=40" alt="" aria-hidden="true" fetchpriority="low">
645    <div class="hand-scrim" aria-hidden="true"></div>
646    <div class="hx-inner hand-copy">
647      <div class="hero-badge" id="hero-src-badge" hidden><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--accent-gold)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"/></svg>Welcome to CardCompass. Start with a rough month of spending.</div>
648      
648<script>(function(){try{var q=new URLSearchParams(location.search),s=(q.get('utm_source')||(q.get('gclid')||q.get('gbraid')||q.get('wbraid')?'google':q.get('fbclid')?'facebook':q.get('ref'))||'').toLowerCase();if(s)sessionStorage.setItem('cc_src',s);if(sessionStorage.getItem('cc_src'))document.getElementById('hero-src-badge').hidden=false;}catch(e){}})();</script>
648
649      <h1 id="hx-h1">Find the card that fits how you spend.</h1>
650      <p class="hand-actions"><a class="hand-go" href="#calc">Start with your spending</a><a class="hand-all" href="/all-cards">All&nbsp;<span data-card-count>114</span>&nbsp;cards</a></p>
651    </div>
652  </div>
653  <div class="hand-fan" aria-hidden="true">
654    <span class="hf hf1"><img src="https://cdn.prodstatic.com/shared/images/cards/500x315/083f25c0-504f-11f0-962e-072d632f0110.png" alt="" loading="eager" decoding="async"></span>
655    <span class="hf hf2"><img src="https://cdn.prodstatic.com/shared/images/cards/500x315/8cd47490-949f-11f0-832a-f3f3309a1b0c.png" alt="" loading="eager" decoding="async"></span>
656    <span class="hf hf3"><img src="https://cdn.prodstatic.com/shared/images/cards/500x315/ae837480-ed19-11ee-b6aa-83dad90afdcd.png" alt="" loading="eager" decoding="async"></span>
657    <span class="hf hf4"><img src="https://cdn.prodstatic.com/shared/images/cards/500x315/a5c974a0-eb11-11f0-8b83-5b931725a212.png" alt="" loading="eager" decoding="async"></span>
658    <span class="hf hf5"><img src="https://cdn.prodstatic.com/shared/images/cards/500x315/4f675c90-7268-11e9-8bc5-4d4394516d65.png" alt="" loading="eager" decoding="async"></span>
659  </div>
660  <div class="hx-inner hx-calc-hd" id="calc">
661    <h2 id="hx-calc-h2">What <span id="hx-total">$1,650</span> a month earns on a credit card</h2>
662  </div>
663  <div class="hx-inner hx-body">
664    <div class="hx-inputs">
665      <div class="hx-head"><span>Per month, roughly</span><span>Earns per year</span></div>
666      <div id="hx-rows" role="group" aria-label="Monthly spending"></div>
667      <p class="hx-note">Points counted at 1 cent each. Welcome offers counted at a conservative value, and only when this spending meets the offer's requirement. This ranks general rewards and cash back cards. Hotel, airline, business and credit-building cards are in <a href="/quiz">the quiz</a>.</p>
668    </div>
669    <div class="hx-result">
670      <div class="hx-tabs" role="group" aria-label="Period">
671        <button type="button" data-mode="yearOne" aria-pressed="true">Year one</button>
672        <button type="button" data-mode="after" aria-pressed="false">Every year after</button>
673      </div>
674      <div class="hx-stage" id="hx-stage"></div>
675      <div id="hx-detail"></div>
676      <p class="hx-legal">Rates and fees apply. Offers can change. We may earn a commission when you apply through our links and are approved. <a href="/advertiser-disclosure">Advertiser disclosure</a></p>
677      <div class="sr-only" role="status" id="hx-status"></div>
678    </div>
679  </div>
680</section>
681
682<!-- ═══════════ ADVERTISER DISCLOSURE BAR ═══════════ -->
683<div class="adv-bar">
684  <div class="adv-bar-inner">
685    <i class="fas fa-info-circle"></i>
686    <span><a href="/advertiser-disclosure">Advertiser Disclosure</a> — CardCompass may earn a commission when you apply through our links. This does not affect our ratings or rankings.</span>
687  </div>
688</div>
689
690<!-- ═══════════ PERSONAL MATCH BANNER (logged-in) ═══════════ -->
691<div class="personal-banner hidden" id="personal-banner">
692  <div class="personal-banner-inner">
693    <div class="pb-greeting"><i class="fas fa-hand"></i> Hey, <b id="pb-name">there</b></div>
694    <div class="pb-sep"></div>
695    <div class="pb-label">Your top match</div>
696    <div class="pb-match">
697      <div class="pb-badge" id="pb-badge"></div>
698      <div>
699        <div class="pb-card-name" id="pb-card-name"></div>
700        <div class="pb-card-rate" id="pb-card-rate"></div>
701      </div>
702    </div>
703    <div class="pb-earn" id="pb-earn"><small>est. yearly value</small></div>
704    <div class="pb-actions">
705      <a href="/account" class="pb-acct-btn"><i class="fas fa-user"></i> My Account</a>
706      <button class="pb-retake" onclick="location.href='/quiz'"><i class="fas fa-bullseye"></i> Update Preferences</button>
707    </div>
708  </div>
709</div>
710
711<!-- ═══════════ TOOLS: COMPARE + QUIZ ═══════════ -->
712<section class="hp hp-first" id="quiz">
713  <div class="hp-inner tools">
714    <div>
715      <div class="hp-hd" id="compare"><h2>Compare Cards</h2><a href="/compare" id="cmp-link">Compare these three</a></div>
716      <div id="cmp-table" role="table" aria-label="Your top three cards, side by side"></div>
717    </div>
718    <div>
719      <div class="hp-hd"><h2>Card Quiz</h2><span>7 questions</span></div>
720      <p class="quiz-q">What's your primary goal with a new credit card?</p>
721      <div id="quiz-opts">
722        <a class="quiz-opt" href="/quiz?goal=travel" data-goal="travel">Earn travel rewards<i class="fas fa-chevron-right" aria-hidden="true" style="font-size:12px;color:var(--text-gray)"></i></a>
723        <a class="quiz-opt" href="/quiz?goal=cashback" data-goal="cashback">Maximize cash back<i class="fas fa-chevron-right" aria-hidden="true" style="font-size:12px;color:var(--text-gray)"></i></a>
724        <a class="quiz-opt" href="/quiz?goal=airline" data-goal="airline">Earn airline miles<i class="fas fa-chevron-right" aria-hidden="true" style="font-size:12px;color:var(--text-gray)"></i></a>
725        <a class="quiz-opt" href="/quiz?goal=hotel" data-goal="hotel">Earn hotel points<i class="fas fa-chevron-right" aria-hidden="true" style="font-size:12px;color:var(--text-gray)"></i></a>
726        <a class="quiz-opt" href="/quiz?goal=credit" data-goal="credit">Build or improve my credit<i class="fas fa-chevron-right" aria-hidden="true" style="font-size:12px;color:var(--text-gray)"></i></a>
727        <a class="quiz-opt" href="/quiz?goal=business" data-goal="business">Business card for my company<i class="fas fa-chevron-right" aria-hidden="true" style="font-size:12px;color:var(--text-gray)"></i></a>
728      </div>
729      <p class="quiz-foot">It picks up the spending you entered above.</p>
730    </div>
731  </div>
732</section>
733
734<!-- ═══════════ CURRENT BONUS OFFERS ═══════════ -->
735<section class="hp">
736  <div class="hp-inner">
737    <div class="hp-hd"><h2>Current Bonus Offers</h2><a href="/bonus-offers">All bonus offers</a></div>
738    <div id="off-table" role="table" aria-label="Welcome offers, by our value"></div>
739  </div>
740</section>
741
742<!-- ═══════════ CARDS BY TYPE ═══════════ -->
743<section class="hp" id="categories">
744  <div class="hp-inner">
745    <div class="hp-hd"><h2><span data-card-count>114</span> cards, by type</h2><a href="/all-cards">All cards</a></div>
746    <div class="lanes" id="lanes"></div>
747  </div>
748</section>
749
750<!-- ═══════════ ISSUERS ═══════════ -->
751<div class="issuers"><p id="issuers"></p></div>
752
753<!-- ═══════════ GUIDES ═══════════ -->
754<section class="hp hp-first">
755  <div class="hp-inner">
756    <div class="hp-hd"><h2>Guides</h2><a href="/guides">All guides</a></div>
757    <div class="guides">
758      <a class="g-lead" href="/guides/marriott-bonvoy-credit-cards-2026">
759        <span class="g-tag">Hotel Cards</span>
760        <h3>Marriott Bonvoy Credit Cards 2026: Bold vs. Boundless vs. Brilliant vs. Business</h3>
761        <p>Four cards, two issuers, a $0 to $650 fee range. Here's which Bonvoy card's Free Night Award actually covers its own annual fee.</p>
762        <span class="g-meta">September 4, 2026 &nbsp;&middot;&nbsp; 9 min read</span>
763      </a>
764      <div>
765        <a class="g-item" href="/guides/marriott-bonvoy-points-value-2026">
766          <span class="g-tag">Rewards Strategy</span>
767          <h3>Marriott Bonvoy Points Value in 2026: What Your Points Are Really Worth</h3>
768          <p>A 100,000-point balance sounds like $1,000. It's closer to $750. Here's the formula to check any redemption before you book it.</p>
769          <span class="g-meta">September 4, 2026 &nbsp;&middot;&nbsp; 7 min read</span>
770        </a>
771        <a class="g-item" href="/guides/best-business-travel-credit-cards-2026">
772          <span class="g-tag">Business Cards</span>
773          <h3>Best Business Credit Cards for Travel in 2026</h3>
774          <p>Free employee cards, higher limits, and spend that stays off your personal credit report. Here&rsquo;s which airline and hotel business co-brands are worth the fee.</p>
775          <span class="g-meta">September 3, 2026 &nbsp;&middot;&nbsp; 10 min read</span>
776        </a>
777        <a class="g-item" href="/guides/best-hotel-credit-cards-2026">
778          <span class="g-tag">Hotel Cards</span>
779          <h3>Best Hotel Credit Cards in 2026</h3>
780          <p>Most hotel cards are bought for the points and kept for the free night certificate. Here&rsquo;s which certificates actually cover their own annual fee.</p>
781          <span class="g-meta">August 31, 2026 &nbsp;&middot;&nbsp; 10 min read</span>
782        </a>
783      </div>
784    </div>
785  </div>
786</section>
787
788<!-- ═══════════ NEWSLETTER ═══════════ -->
789<section class="newsletter-section">
790  <div class="newsletter-inner reveal">
791    <span class="newsletter-icon"><i class="fas fa-envelope-open-text" style="color:var(--accent-gold)"></i></span>
792    <h2>Get the best card deals in your inbox</h2>
793    <p>An alert when we add a card or a welcome bonus jumps, and a roundup on the 1st of each month. No spam, ever.</p>
794    <div id="newsletter-wrap">
795      <div class="newsletter-form">
796        <input type="email" class="newsletter-input" id="nl-email" placeholder="[email protected]" autocomplete="email">
797        <button class="newsletter-submit" onclick="submitNewsletter()">Subscribe Free →</button>
798      </div>
799      <div class="cf-turnstile" data-sitekey="0x4AAAAAADiVOynXw_ZhYDP0" style="margin:14px 0;"></div>
800      <div class="newsletter-error" id="nl-error">Please enter a valid email address.</div>
801      <div class="newsletter-meta" style="justify-content:center;">
802        <span><i class="fas fa-check"></i> Unsubscribe anytime</span>
803        <span><i class="fas fa-check"></i> No spam, ever</span>
804      </div>
805    </div>
806    <div class="newsletter-success" id="nl-success">
807      <h3><i class="fas fa-champagne-glasses"></i> You're in!</h3>
808      <p>Check your inbox to confirm your subscription. Your first deal alert is on the way.</p>
809    </div>
810    <div class="newsletter-already" id="nl-already">
811      <i class="fas fa-check" style="color:#22c55e"></i> You're already subscribed — we'll keep sending you the best card deal
811s each month.
812    </div>
813  </div>
814</section>
815
816<!-- ═══════════ FOOTER ═══════════ -->
817<footer>
818  <div class="footer-inner">
819    <div class="footer-top">
820      <div class="footer-brand">
821        <a href="/" class="logo">
822          <div class="logo-icon">
823            <img src="images/logo-icon.svg" alt="CardCompass compass logo" width="40" height="40">
824          </div>
825          <span class="logo-text">Card<span>Compass</span></span>
826        </a>
827        <p>CardCompass helps you navigate the crowded world of credit cards with honest, data-driven recommendations — so you earn more on every dollar you spend.</p>
828      </div>
829      <div class="footer-col">
830        <h4>Credit Cards</h4>
831        <a href="/cards?cat=cashback">Best Cash Back</a><a href="/cards?cat=travel">Best Travel Cards</a><a href="/cards?cat=hotel">Best Hotel Cards</a><a href="/cards?cat=airline">Best Airline Cards</a><a href="/cards?cat=nofee">No Annual Fee</a><a href="/cards?cat=balancetransfer">Balance Transfer</a><a href="/cards?cat=business">Business Cards</a><a href="/cards?cat=student">Student Cards</a><a href="/cards?cat=secured">Build Credit</a>
832      </div>
833      <div class="footer-col">
834        <h4>Rewards</h4>
835        <a href="/rewards-calculator">Points Calculator</a><a href="/rewards-partners">Transfer Partners</a><a href="/rewards-award-travel">Award Travel Guide</a><a href="/rewards-maximize">Maximize Rewards</a><a href="/airlines">Airport Lounge Access</a><a href="/my-current-wallet">My Current Wallet</a>
836      </div>
837      <div class="footer-col">
838        <h4>Company</h4>
839        <a href="/guides">Guides</a><a href="/about">About Us</a><a href="/about#methodology">How We Rate Cards</a><a href="/editorial-policy">Editorial Policy</a><a href="/advertiser-disclosure">Advertiser Disclosure</a><a href="/contact">Contact Us</a>
840        <a href="/account" id="footer-account-link" style="display:none;">My Account</a>
841      </div>
842    </div>
843    <div class="footer-bottom">
844      <span>© 2026 CardCompass, Inc. CardCompass may receive compensation through credit card issuer partnerships. This does not influence our ratings or recommendations. <span class="footer-social" style="display:inline-flex;align-items:center;gap:14px;vertical-align:middle;margin-left:10px;"><a href="https://www.instagram.com/cardcompassapp/" target="_blank" rel="noopener" aria-label="CardCompass on Instagram" style="display:inline-flex;margin:0;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="20" height="20" x="2" y="2" rx="5" ry="5"/><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"/><line x1="17.5" x2="17.51" y1="6.5" y2="6.5"/></svg></a><a href="https://www.facebook.com/cardcompassapp" target="_blank" rel="noopener" aria-label="CardCompass on Facebook" style="display:inline-flex;margin:0;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"/></svg></a></span></span>
845      <div class="foot-links"><a href="/privacy-policy">Privacy Policy</a><a href="/terms">Terms of Service</a><a href="/advertiser-disclosure">Advertiser Disclosure</a></div>
846    </div>
847  </div>
848</footer>
849
850<button class="scroll-top" onclick="window.scrollTo({top:0,behavior:'smooth'})" aria-label="Back to top">
851  <i class="fas fa-arrow-up"></i>
852</button>
853
854<!-- ═══════════ DRAWER ═══════════ -->
855<div class="drawer-overlay" id="drawer-overlay" onclick="closeDrawer()"></div>
856<div class="drawer" id="card-drawer">
857  <div class="drawer-header">
858    <span>Card Details</span>
859    <button class="drawer-close" onclick="closeDrawer()" aria-label="Close">&times;</button>
860  </div>
861  <div class="drawer-body">
862    <div class="drawer-card-hd">
863      <div class="drawer-card-img" id="d-img"></div>
864      <div>
864<div class="drawer-card-name" id="d-name"></div><div class="drawer-card-sub" id="d-sub"></div></div>
865    </div>
866    <div class="drawer-score-bar">
867      <span class="drawer-stars" id="d-stars"></span>
868      <span class="drawer-score-val" id="d-score"></span>
869      <span class="drawer-score-lbl">/ 5 — CardCompass Score</span>
870    </div>
871    <div class="drawer-divider"></div>
872    <div class="drawer-details" id="d-details"></div>
873    <div class="drawer-divider"></div>
874    <div class="drawer-proscons" id="d-proscons"></div>
875  </div>
876  <div class="drawer-actions">
877    <button class="drawer-apply" id="drawer-apply-btn">Apply Now →</button>
878    <button class="drawer-learn" onclick="closeDrawer()">Close</button>
879  </div>
880</div>
881
882<!-- ═══════════ COOKIE CONSENT BANNER ═══════════ -->
883<div class="cookie-banner hidden" id="cookie-banner" role="dialog" aria-label="Cookie consent">
884  <p>We use cookies to analyze site traffic and improve your experience. See our <a href="/privacy-policy">Privacy Policy</a> for details.</p>
885  <div class="cookie-actions">
886    <button class="cookie-accept" onclick="acceptCookies()">Accept</button>
887    <button class="cookie-decline" onclick="declineCookies()">Decline</button>
888  </div>
889</div>
890
891<script src="nav-auth.js?v=2"></script>
vendor: 1 bytes, line 891
891
892<script>
893/* ═══════════════════════════════════════════
894   DATA — full card pool now comes from cards-data.js /
895   recommend-engine.js (window.ALL_CARDS / window.CCEngine), not a
896   hardcoded 5-card subset. See cardBadgeHtml() below for the shared
897   image-or-issuer-badge renderer used by the quiz results, banner, and
898   drawer instead of the old per-card badgeClass/badgeText fields.
899═══════════════════════════════════════════ */
900// Fills whatever sized container it's placed in (.banner-card-img,
901// .drawer-card-img, .qrc-img all already set width/height via CSS).
902function cardBadgeHtml(c) {
903  if (c.cardImage) {
904    return '<img src="' + c.cardImage + '" alt="' + c.name + '" style="width:100%;height:100%;object-fit:cover;border-radius:6px;" onerror="this.style.display=\'none\'">';
905  }
906  const bg = (c.cardArt && c.cardArt.bg) || 'linear-gradient(135deg,#1A3F6F 0%,#0D2A4A 100%)';
907  const label = (c.issuer || '').substring(0, 4).toUpperCase();
908  return '<div style="width:100%;height:100%;background:' + bg + ';color:#fff;font-size:10px;font-weight:800;display:flex;align-items:center;justify-content:center;border-radius:6px;">' + label + '</div>';
909}
910
911/* ═══════════════════════════════════════════
912   AFFILIATE APPLY NOW
913═══════════════════════════════════════════ */
914let currentBannerCardId = null;
915
916function applyNow(cardId, source) {
917  const allCards = window.ALL_CARDS || window.CCEngine.getCardPool();
918  const c = allCards.find(x => x.id === cardId);
919  if (!c) return;
920  if (typeof gtag === 'function') {
921    gtag('event', 'apply_click', { card_name: c.name, card_issuer: c.issuer, source: source });
922  }
923  window.open(window.getApplyUrl ? window.getApplyUrl(c) : c.applyUrl, '_blank', 'noopener,noreferrer');
924}
925
926const REVIEWS = [
927  { name: 'Sarah K.', initials: 'SK', av: 'av-blue',  card: 'Chase Sapphire Preferred®', rating: 5, quote: 'Earned over $1,200 in travel rewards my first year. The sign-up bonus alone paid for a round-trip flight to Europe.' },
928  { name: 'Marcus T.', initials: 'MT', av: 'av-accent', card: 'Amex Gold Card', rating: 5, quote: 'Best dining card I\'ve ever had. The 4× points at restaurants adds up incredibly fast — I earned enough for a free flight in 6 months.' },
929  { name: 'Priya L.', initials: 'PL', av: 'av-gold',  card: 'Citi Double Cash®', rating: 4, quote: 'Perfect for someone who doesn\'t want to think about categories. Flat 2% on everything, no annual fee. Simple and effective.' },
930  { name: 'James R.', initials: 'JR', av: 'av-red',    card: 'Capital One Venture X',     rating: 5, quote: 'The lounge access alone justifies the fee. Free Priority Pass plus the $300 travel credit — it basically pays for itself year after year.' },
931  { name: 'Emily C.', initials: 'EC', av: 'av-green',  card: 'Discover it® Cash Back',    rating: 4, quote: 'Great starter card. The Cashback Match in year one was a game changer — I made $400 cash back my first year with zero annual fee.' },
932  { name: 'David M.', initials: 'DM', av: 'av-blue',   card: 'Chase Sapphire Preferred®', rating: 5, quote: 'CardCompass matched me to this card based on my spending. Projected $1,100/year — I\'m actually earning $1,350. Incredible tool.' },
933  { name: 'Rachel H.', initials: 'RH', av: 'av-accent', card: 'Amex Platinum',             rating: 5, quote: 'After the $200 airline fee credit, $200 hotel credit, and Centurion lounge access, I\'m paying around $300 net for benefits worth well over $2,000.' },
934  { name: 'Tyler B.', initials: 'TB', av: 'av-purple',  card: 'Chase Freedom Unlimited',   rating: 5, quote: 'No annual fee and I\'m earning $580 a year. CardCompass showed me I was leaving money on the table with my old card — switched immediately.' },
935  { name: 'Natalie W.', initials: 'NW', av: 'av-teal', card: 'World of Hyatt Card',        rating: 4, quote: 'Hyatt points are worth 2–3× more than Marriott. CardCompass\'s comparison made it obvious. I got a free 5-night stay in my first year.' },
936  { name: 'Kevin S.', initials: 'KS', av: 'av-gold',   card: 'Capital One Venture',        rating: 5, quote: 'Transferred 80,000 miles to Air Canada and flew business class to London. Would have been $4,800 to buy the seat outright. This card is unreal.' },
937  { name: 'Aisha J.', initials: 'AJ', av: 'av-green',  card: 'Amex Gold Card',             rating: 5, quote: 'I spend a lot on groceries and restaurants. The 4× categories earn me $900+ per year in points. The $120 dining credit covers Uber Eats monthly.' },
938  { name: 'Michael T.', initials: 'MT', av: 'av-red',  card: 'Citi Custom Cash®',          rating: 5, quote: 'Automatically earns 5% on my top spend category each month. I don\'t have to think about it — it just optimizes itself. Best no-fee card I\'ve had.' },
939  { name: 'Lauren P.', initials: 'LP', av: 'av-blue',  card: 'Chase Sapphire Reserve®',   rating: 5, quote: 'The $300 travel credit drops the effective fee to $250. Add Priority Pass, TSA PreCheck reimbursement, and 3× on travel — it pays for itself easily.' }
940];
941
942/* ═══════════════════════════════════════════
943   CARD DRAWER
944═══════════════════════════════════════════ */
945let drawerTriggerEl = null;
946let drawerCardId = null;
947
948const MIN_CREDIT_LABELS = {
949  poor: 'Poor – Fair (under 640)', fair: 'Fair – Good (640+)', building: 'Building Credit',
950  good: 'Good – Excellent (700+)', verygood: 'Very Good (740+)', excellent: 'Excellent (750+)'
951};
952
953function openDrawer(id) {
954  const allCards = window.ALL_CARDS || window.CCEngine.getCardPool();
955  const c = allCards.find(x => x.id === id);
956  if (!c) return;
957
958  drawerCardId = id;
959  drawerTriggerEl = document.activeElement;
960
961  document.getElementById('d-img').className = 'drawer-card-img';
962  document.getElementById('d-img').innerHTML = cardBadgeHtml(c);
963  document.getElementById('d-name').textContent = c.name;
964  document.getElementById('d-sub').textContent = 'Best for: ' + c.bestFor;
965
966  const fullStars = Math.round(c.cardScore || 4);
967  const dStarFull = '<i class="fas fa-star" style="color:#F5A623"></i>';
968  const dStarEmpty = '<i class="fas fa-star" style="color:#F5A623;opacity:.25"></i>';
969  document.getElementById('d-stars').innerHTML = dStarFull.repeat(fullStars) + dStarEmpty.repeat(5 - fullStars);
970  document.getElementById('d-score').textContent = (c.cardScore || 4).toFixed(1);
971
972  document.getElementById('d-details').innerHTML = `
973    <div class="drawer-row"><span class="drawer-lbl">Welcome Bonus</span><span class="drawer-val gold">${c.bonusDesc || c.bonusShort || 'See terms'}</span></div>
974    <div class="drawer-row"><span class="drawer-lbl">Annual Fee</span><span class="drawer-val">${c.annualFee > 0 ? '$' + c.annualFee + ' / year' : 'None'}</span></div>
975    <div class="drawer-row"><span class="drawer-lbl">Best Rewards Rate</span><span class="drawer-val">${c.rateLabel}</span></div>
976    <div class="drawer-row"><span class="drawer-lbl">Foreign Transaction Fee</span><span class="drawer-val">${c.foreignFee}</span></div>
977    <div class="drawer-row"><span class="drawer-lbl">Recommended Credit</span><span class="drawer-val">${MIN_CREDIT_LABELS[c.minScore] || 'Good – Excellent (700+)'}</span></div>
978  `;
979
980  const pros = c.pros.map(p => `<li><span><i class="fas fa-check-circle" style="color:#22c55e"></i></span>${p}</li>`).join('');
981  const cons = c.cons.map(p => `<li><span><i class="fas fa-times-circle" style="color:#ef4444"></i></span>${p}</li>`).join('');
982  document.getElementById('d-proscons').innerHTML = `
983    <div class="drawerpc pros-col"><h5 class="pros-title">Pros</h5><ul>${pros}</ul></div>
984    <div class="drawerpc cons-col"><h5 class="cons-title">Cons</h5><ul>${cons}</ul></div>
985  `;
986
987  // Wire Apply Now button
988  const applyBtn = document.getElementById('drawer-apply-btn');
989  applyBtn.onclick = () => applyNow(id, 'drawer');
990
991  document.getElementById('drawer-overlay').classList.add('open');
992  const drawer = document.getElementById('card-drawer');
993  drawer.classList.add('open');
994  document.body.style.overflow = 'hidden';
995
996  // Focus the close button after transition
997  setTimeout(() => {
998    const closeBtn = drawer.querySelector('.drawer-close');
999    if (closeBtn) closeBtn.focus();
1000  }, 350);
1001
1002  if (typeof gtag === 'function') {
1003    gtag('event', 'card_detail_view', { card_name: c.name, card_issuer: c.issuer });
1004  }
1005
1006  // Focus trap
1007  const FOCUSABLE = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
1008  drawer.addEventListener('keydown', trapFocus);
1009  function trapFocus(e) {
1010    if (e.key !== 'Tab') return;
1011    const focusable = Array.from(drawer.querySelectorAll(FOCUSABLE)).filter(el => !el.disabled);
1012    if (!focusable.length) { e.preventDefault(); return; }
1013    const first = focusable[0], last = focusable[focusable.length - 1];
1014    if (e.shiftKey) { if (document.activeElement === first) { e.preventDefault(); last.focus(); } }
1015    else            { if (document.activeElement === last)  { e.preventDefault(); first.focus(); } }
1016  }
1017  drawer._trapFocus = trapFocus;
1018}
1019
1020function closeDrawer() {
1021  const drawer = document.getElementById('card-drawer');
1022  if (drawer._trapFocus) { drawer.removeEventListener('keydown', drawer._trapFocus); delete drawer._trapFocus; }
1023  document.getElementById('drawer-overlay').classList.remove('open');
1024  drawer.classList.remove('open');
1025  document.body.style.overflow = '';
1026  if (drawerTriggerEl) { drawerTriggerEl.focus(); drawerTriggerEl = null; }
1027}
1028
1029document.addEventListener('keydown', e => { if (e.key === 'Escape') closeDrawer(); });
1030
1031/* ═══════════════════════════════════════════
1032   REVIEWS CAROUSEL
1033═══════════════════════════════════════════ */
1034let carouselIndex = 0;
1035let carouselTimer;
1036
1037function getPerPage() {
1038  return window.innerWidth < 768 ? 1 : window.innerWidth < 1024 ? 2 : 3;
1039}
1040
1041function renderTrack() {
1042  const track = document.getElementById('reviews-track');
1043  if (!track) return;
1044  const rvStarFull = '<i class="fas fa-star" style="color:#F5A623"></i>';
1045  const rvStarEmpty = '<i class="fas fa-star" style="color:#F5A623;opacity:.25"></i>';
1046  track.innerHTML = REVIEWS.map(r => {
1047    const stars = rvStarFull.repeat(r.rating) + rvStarEmpty.repeat(5 - r.rating);
1048    return `<div class="review-card">
1049      <div class="review-stars">${stars}</div>
1050      <div class="review-quote">${r.quote}</div>
1051      <div class="review-author">
1052        <div class="review-avatar ${r.av}">${r.initials}</div>
1053        <div><div class="review-name">${r.name}</div><div class="review-card-name">${r.card}</div></div>
1054      </div>
1055    </div>`;
1056  }).join('');
1057}
1058
1059function slideToPage(page) {
1060  const perPage = getPerPage();
1061  const track = document.getElementById('reviews-track');
1062  if (!track) return;
1063  const card = track.querySelector('.review-card');
1064  if (!card) return;
1065  const cardW = card.offsetWidth;
1066  const gap = 24;
1067  const maxPage = Math.ceil(REVIEWS.length / perPage) - 1;
1068  const safePage = Math.min(page, maxPage);
1069  track.style.transform = `translateX(-${safePage * perPage * (cardW + gap)}px)`;
1070}
1071
1072function updateDots() {
1073  const perPage = getPerPage();
1074  const pages = Math.ceil(REVIEWS.length / perPage);
1075  const dots = document.getElementById('carousel-dots');
1076  if (!dots) return;
1077  dots.innerHTML = '';
1078  for (let i = 0; i < pages; i++) {
1079    const d = document.createElement('button');
1080    d.className = 'carousel-dot' + (i === carouselIndex ? ' active' : '');
1081    d.setAttribute('aria-label', `Page ${i + 1}`);
1082    d.onclick = () => { carouselIndex = i; slideToPage(i); updateDots(); resetTimer(); };
1083    dots.appendChild(d);
1084  }
1085}
1086
1087function carousel(dir) {
1088  const perPage = getPerPage();
1089  const pages = Math.ceil(REVIEWS.length / perPage);
1090  carouselIndex = (carouselIndex + dir + pages) % pages;
1091  slideToPage(carouselIndex);
1092  updateDots();
1093  resetTimer();
1094}
1095
1096function resetTimer() {
1097  clearInterval(carouselTimer);
1098  carouselTimer = setInterval(() => carousel(1), 5000);
1099}
1100
1101
1102/* ═══════════════════════════════════════════
1103   SCROLL ANIMATIONS (IntersectionObserver)
1104═══════════════════════════════════════════ */
1105const revealObserver = new IntersectionObserver((entries) => {
1106  entries.forEach(el => {
1107    if (el.isIntersecting) { el.target.classList.add('visible'); revealObserver.unobserve(el.target); }
1108  });
1109}, { threshold: 0.12 });
1110
1111document.querySelectorAll('.reveal').forEach(el => revealObserver.observe(el));
1112
1113
1114/* ═══════════════════════════════════════════
1115   COUNTER ANIMATION
1116═══════════════════════════════════════════ */
1117function animateCount(el) {
1118  const target = parseInt(el.dataset.target);
1119  const divisor = parseInt(el.dataset.divisor) || 1;
1120  const suffix = el.dataset.suffix || '';
1121  const prefix = el.dataset.prefix || '';
1122  const duration = 1500;
1123  const start = performance.now();
1124
1125  function step(now) {
1126    const progress = Math.min((now - start) / duration, 1);
1127    const ease = 1 - Math.pow(1 - progress, 3);
1128    const val = Math.round(target * ease / divisor);
1129    el.textContent = prefix + val.toLocaleString() + suffix;
1130    if (progress < 1) requestAnimationFrame(step);
1131    else el.textContent = el.dataset.final;
1132  }
1133
1134  el.dataset.final = el.textContent;
1135  requestAnimationFrame(step);
1136}
1137
1138const counterObserver = new IntersectionObserver((entries) => {
1139  entries.forEach(e => {
1140    if (e.isIntersecting) { animateCount(e.target); counterObserver.unobserve(e.target); }
1141  });
1142}, { threshold: 0.5 });
1143
1144document.querySelectorAll('[data-card-count]').forEach(el => {
1145  el.textContent = window.ALL_CARDS.length;
1146  if (el.dataset.target) el.dataset.target = window.ALL_CARDS.length;
1147});
1148document.querySelectorAll('.trust-item .num[data-target]').forEach(el => counterObserver.observe(el));
1149
1150/* ═══════════════════════════════════════════
1151   HAMBURGER (MOBILE NAV)
1152═══════════════════════════════════════════ */
1153const hamburger = document.getElementById('hamburger');
1154const navLinks  = document.getElementById('nav-links');
1155
1156hamburger.addEventListener('click', () => {
1157  const open = hamburger.classList.toggle('open');
1158  navLinks.classList.toggle('mobile-open', open);
1159  hamburger.setAttribute('aria-expanded', open ? 'true' : 'false');
1160});
1161
1162document.addEventListener('click', e => {
1163  if (!hamburger.contains(e.target) && !navLinks.contains(e.target)) {
1164    hamburger.classList.remove('open');
1165    navLinks.classList.remove('mobile-open');
1166  }
1167});
1168
1169/* ═══════════════════════════════════════════
1170   NEWSLETTER
1171═══════════════════════════════════════════ */
1172async function submitNewsletter() {
1173  const emailEl = document.getElementById('nl-email');
1174  const errEl   = document.getElementById('nl-error');
1175  const btn     = document.querySelector('.newsletter-submit');
1176  const email   = emailEl.value.trim();
1177  errEl.style.display = 'none';
1178
1179  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
1180    errEl.style.display = 'block';
1181    emailEl.focus();
1182    return;
1183  }
1184
1185  const token = window.turnstile?.getResponse();
1186  if (!token) {
1187    errEl.textContent = 'Please complete the verification below.';
1188    errEl.style.display = 'block';
1189    return;
1190  }
1191
1192  btn.disabled = true;
1193  btn.textContent = 'Subscribing…';
1194
1195  try {
1196    const res  = await fetch('/api/subscribe', {
1197      method: 'POST',
1198      headers: { 'Content-Type': 'application/json' },
1199      body: JSON.stringify({ email, cfToken: token })
1200    });
1201    const data = await res.json();
1202
1203    if (data.status === 'subscribed') {
1204      localStorage.setItem('cc_subscribed', email);
1205      document.getElementById('newsletter-wrap').style.display = 'none';
1206      document.getElementById('nl-success').style.display = 'block';
1207      if (typeof gtag === 'function') gtag('event', 'newsletter_signup');
1208    } else {
1209      throw new Error('bad response');
1210    }
1211  } catch {
1212    errEl.textContent = 'Something went wrong — please try again.';
1213    errEl.style.display = 'block';
1214    btn.disabled = false;
1215    btn.textContent = 'Subscribe Free →';
1216    window.turnstile?.reset();
1217  }
1218}
1219
1220(function checkSubscribed() {
1221  if (localStorage.getItem('cc_subscribed')) {
1222    document.getElementById('newsletter-wrap').style.display = 'none';
1223    document.getElementById('nl-already').style.display = 'block';
1224  }
1225})();
1226
1227/* ═══════════════════════════════════════════
1228   NAV SCROLL HELPERS
1229═══════════════════════════════════════════ */
1230
1231/* ═══════════════════════════════════════════
1232   WELCOME TOAST (post-login redirect)
1233═══════════════════════════════════════════ */
1234(function () {
1235  const msg = sessionStorage.getItem('cc_welcome');
1236  if (!msg) return;
1237  sessionStorage.removeItem('cc_welcome');
1238  const t = document.createElement('div');
1239  t.style.cssText = 'position:fixed;bottom:28px;left:50%;transform:translateX(-50%) translateY(80px);background:#1A1A2E;color:#fff;padding:13px 22px;border-radius:12px;font-size:14px;font-weight:500;z-index:9999;opacity:0;transition:all .35s cubic-bezier(.4,0,.2,1);max-width:calc(100vw - 32px);width:max-content;text-align:center;box-shadow:0 8px 28px rgba(0,0,0,.25);font-family:Inter,sans-serif;';
1240  // msg carries the user's name, so it goes in as text, not HTML.
1241  t.innerHTML = '<i class="fas fa-hand" style="margin-right:6px"></i>';
1242  t.append(msg);
1243  document.body.appendChild(t);
1244  setTimeout(() => { t.style.opacity = '1'; t.style.transform = 'translateX(-50%) translateY(0)'; }, 100);
1245  setTimeout(() => { t.style.opacity = '0'; t.style.transform = 'translateX(-50%) translateY(80px)'; }, 4000);
1246  setTimeout(() => t.remove(), 4500);
1247})();
1248
1249/* ═══════════════════════════════════════════
1250   BEST CARDS TABLE — DYNAMIC CATEGORY TABS
1251═══════════════════════════════════════════ */
1252const ISSUER_BADGE = {
1253  'Chase':             'ci-chase',
1254  'American Express':  'ci-amex',
1255  'Citi':              'ci-citi',
1256  'Capital One':       'ci-cap',
1257  'Discover':          'ci-disc',
1258};
1259function issuerBadge(issuer) {
1260  return ISSUER_BADGE[issuer] || 'ci-chase';
1261}
1262
1263const COMP_PAGE_SIZE = 6;
1264let _compCat = 'bestoffers';
1265
1266function _getFilteredCards(cat) {
1267  const allCards = window.ALL_CARDS || window.CCEngine.getCardPool();
1268  let filtered = [...allCards]
1269    .filter(c => (c.categories || []).includes(cat))
1270    .sort((a, b) => (b.cardScore || 0) - (a.cardScore || 0));
1271  // Fallback: if no cards match, show top-rated overall
1272  if (!filtered.length) {
1273    filtered = [...allCards].sort((a, b) => (b.cardScore || 0) - (a.cardScore || 0));
1274  }
1275  return filtered;
1276}
1277
1278function renderCompTable(cat, page) {
1279  page = (page === undefined) ? 0 : page;
1280  _compCat = cat;
1281
1282  const filtered    = _getFilteredCards(cat);
1283  const totalPages  = Math.max(1, Math.ceil(filtered.length / COMP_PAGE_SIZE));
1284  const safePage    = Math.min(Math.max(0, page), totalPages - 1);
1285  const pageCards   = filtered.slice(safePage * COMP_PAGE_SIZE, (safePage + 1) * COMP_PAGE_SIZE);
1286
1287  const tbody = document.getElementById('comp-table-body');
1288  if (!tbody) return;
1289  const header = `<div class="comp-header">
1290    <span></span><span>Card</span><span>Welcome Bonus</span><span>Best Rate</span><span>Annual Fee</span><span></span>
1291  </div>`;
1292
1293  const rows = pageCards.map(c => {
1294    const badge = issuerBadge(c.issuer);
1295    const imgHtml = c.cardImage
1296      ? `<img src="${c.cardImage}" alt="${c.name}" loading="lazy" style="position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:8px;" onerror="this.style.display='none'">`
1297      : '';
1298    const bonusShort = c.bonusShort || (c.bonusDesc ? c.bonusDesc.split(' after')[0] : '—');
1299    const bonusVal   = c.bonusValue ? `≈ $${c.bonusValue.toLocaleStr
1299ing()} value` : '&nbsp;';
1300    const feeLabel   = c.annualFee === 0
1301      ? '<span style="color:#10B981;font-weight:700;">$0/yr</span>'
1302      : `$${c.annualFee}/yr`;
1303    return `<div class="comp-row" onclick="openDrawer('${c.id}')">
1304      <div class="comp-info">
1305        <div class="comp-card-img ${badge}" style="position:relative;">${imgHtml}</div>
1306        <div>
1307          <div class="comp-name">${c.name}</div>
1308          <div class="comp-sub">${c.bestFor || ''}</div>
1309        </div>
1310      </div>
1311      <div class="comp-cell"><span class="hi">${bonusShort}</span><br><span class="tiny">${bonusVal}</span></div>
1312      <div class="comp-cell"><span class="badge">${c.rateLabel || '—'}</span></div>
1313      <div class="comp-cell">${feeLabel}</div>
1314      <div class="comp-cell"><button class="comp-btn" onclick="event.stopPropagation();applyNow('${c.id}','comp_table')">Apply Now</button></div>
1315    </div>`;
1316  }).join('');
1317
1318  tbody.innerHTML = header + rows;
1319  tbody.classList.add('visible');
1320
1321  // Render pagination controls
1322  const pg = document.getElementById('comp-pagination');
1323  if (pg) {
1324    if (totalPages <= 1) {
1325      pg.innerHTML = '';
1326    } else {
1327      let pgHtml = `<button class="comp-pager-btn" onclick="renderCompTable('${cat}',${safePage - 1})" ${safePage === 0 ? 'disabled' : ''}><i class="fas fa-chevron-left"></i></button>`;
1328      for (let i = 0; i < totalPages; i++) {
1329        pgHtml += `<button class="comp-pager-num${i === safePage ? ' active' : ''}" onclick="renderCompTable('${cat}',${i})">${i + 1}</button>`;
1330      }
1331      pgHtml += `<button class="comp-pager-btn" onclick="renderCompTable('${cat}',${safePage + 1})" ${safePage === totalPages - 1 ? 'disabled' : ''}><i class="fas fa-chevron-right"></i></button>`;
1332      pg.innerHTML = pgHtml;
1333    }
1334  }
1335}
1336
1337// Wire up the category tabs — resets to page 0 on every tab switch
1338(function initCompTabs() {
1339  const tabs = document.querySelectorAll('.comp-tab');
1340  renderCompTable('bestoffers', 0);
1341  tabs.forEach(btn => {
1342    btn.addEventListener('click', () => {
1343      tabs.forEach(t => t.classList.remove('active'));
1344      btn.classList.add('active');
1345      renderCompTable(btn.dataset.cat, 0);
1346    });
1347  });
1348})();
1349
1350/* ═══════════════════════════════════════════
1351   AUTH — PERSONAL BANNER (scores the full window.ALL_CARDS pool via
1352   window.CCEngine — this used to only ever consider 5 hardcoded cards)
1353═══════════════════════════════════════════ */
1354(function updateBannerForAuth() {
1355  if (!localStorage.getItem('cc_token')) return;
1356  let user = null;
1357  try { user = JSON.parse(localStorage.getItem('cc_user') || 'null'); } catch(e) {}
1358  if (!user || !user.prefs) return;
1359
1360  const prefs  = user.prefs;
1361  const profile = window.CCEngine.profileFromQuickForm(prefs.goal, prefs.spend, prefs.credit, prefs.maxFee);
1362  const maxFee = parseFloat(prefs.maxFee) || 9999;
1363
1364  const scored = window.CCEngine.rankCards(profile, { limit: 20 })
1365    .filter(c => c.annualFee <= maxFee)
1366    .map(c => {
1367      const yearly = Object.keys(profile.spend).reduce(
1368        (sum, cat) => sum + window.CCEngine.estimateEarn(c, cat, profile.spend[cat]) * 12, 0);
1369      const net = Math.round(yearly + (c.bonusValue / 2) - c.annualFee);
1370      return Object.assign({}, c, { yearly: Math.round(yearly), net: net });
1371    })
1372    .sort((a, b) => b.net - a.net);
1373
1374  if (!scored.length) return;
1375  const top = scored[0];
1376  const fname = user.fname || 'there';
1377  document.getElementById('pb-name').textContent      = fname;
1378  const badge = document.getElementById('pb-badge');
1379  badge.className = 'pb-badge';
1380  badge.innerHTML = cardBadgeHtml(top);
1381  document.getElementById('pb-card-name').textContent = top.name;
1382  document.getElementById('pb-card-rate').textContent = top.rateLabel + (top.annualFee > 0 ? ' · $' + top.annualFee + '/yr' : ' · No fee');
1383  document.getElementById('pb-earn').innerHTML = '$' + top.net.toLocaleString() + '<small>est. yearly value</small>';
1384  document.getElementById('personal-banner').classList.remove('hidden');
1385})();
1386
1387function toggleUserDropdown() {
1388  const nav = document.getElementById('user-nav');
1389  if (!nav) return;
1390  const open = nav.classList.toggle('open');
1391  document.getElementById('user-btn').setAttribute('aria-expanded', open ? 'true' : 'false');
1392}
1393
1394/* Close dropdown on outside click */
1395document.addEventListener('click', function(e) {
1396  const nav = document.getElementById('user-nav');
1397  if (nav && !nav.contains(e.target)) {
1398    nav.classList.remove('open');
1399    const btn = document.getElementById('user-btn');
1400    if (btn) btn.setAttribute('aria-expanded', 'false');
1401  }
1402});
1403
1404// signOut() is provided by nav-auth.js (window.signOut) — it clears cc_token/cc_user
1405// and calls /api/auth/logout. Not redefined here so that shared implementation wins.
1406
1407/* ═══════════════════════════════════════════
1408   COOKIE CONSENT
1409═══════════════════════════════════════════ */
1410function acceptCookies() {
1411  localStorage.setItem('cc_consent', 'granted');
1412  document.getElementById('cookie-banner').classList.add('hidden');
1413  if (typeof gtag === 'function') {
1414    gtag('consent', 'update', { analytics_storage: 'granted' });
1415  }
1416}
1417
1418function declineCookies() {
1419  localStorage.setItem('cc_consent', 'denied');
1420  document.getElementById('cookie-banner').classList.add('hidden');
1421  if (typeof gtag === 'function') {
1422    gtag('consent', 'update', { analytics_storage: 'denied' });
1423  }
1424}
1425
1426(function initCookieBanner() {
1427  if (localStorage.getItem('cc_consent')) return;
1428  const eu = /^Europe\//.test(Intl.DateTimeFormat().resolvedOptions().timeZone);
1429  const banner = document.getElementById('cookie-banner');
1430  if (!eu) {
1431    banner.querySelector('p').innerHTML = 'We use analytics cookies to understand site traffic and improve CardCompass. You can opt out anytime — see our <a href="/privacy-policy">Privacy Policy</a>.';
1432    banner.querySelector('.cookie-accept').textContent = 'OK';
1433    banner.querySelector('.cookie-decline').textContent = 'Opt out';
1434  }
1435  // Show banner after a short delay so page renders first
1436  setTimeout(() => banner.classList.remove('hidden'), 1500);
1437})();
1438
1439/* ═══════════════════════════════════════════
1440   HOMEPAGE: SPEND CALCULATOR, COMPARE, OFFERS, LANES
1441   All ranking is window.CCEngine.rankBySpend (recommend-engine.js).
1442   Spend options are quiz.html's own buckets, so /quiz?grocery=450...
1443   pre-fills its spending question exactly.
1444═══════════════════════════════════════════ */
1445(function homepage() {
1446  const cards = window.ALL_CARDS || [];
1447  const E = window.CCEngine;
1448  if (!cards.length || !E || !E.rankBySpend) return;
1449
1450  const CATS = [
1451    ['grocery', 'Groceries', [0, 200, 450, 800]],
1452    ['dining', 'Dining out', [0, 200, 450, 800]],
1453    ['travel', 'Travel', [0, 200, 450, 800], 'booked through the card’s portal'],
1454    ['gas', 'Gas', [0, 200, 450, 800]],
1455    ['other', 'Everything else', [200, 450, 800, 1500]]
1456  ];
1457  const spend = { grocery: 450, dining: 200, travel: 0, gas: 200, other: 800 };
1458  let mode = 'yearOne';
1459  let touched = false;
1460
1461  const $ = id => document.getElementById(id);
1462  const esc = s => String(s).replace(/[&<>"]/g, ch => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[ch]));
1463  const money = n => (n < 0 ? '−$' : '$') + Math.abs(Math.round(n)).toLocaleString('en-US');
1464  const short = c => c.name.replace(/[®™℠]/g, '').replace(/\s+(Credit )?Card( from .*)?$/i, '').trim();
1465  const rate = (r, k) => (r.rates[k] || 0) + ((r.card.categories || []).includes('cashback') ? '%' : '×');
1466  const day = iso => new Date(iso + 'T12:00:00').toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
1467  const track = cta => { if (typeof gtag === 'function') gtag('event', 'hero_cta_click', { cta: cta }); };
1468
1469  // The site stores 219px issuer art; the same host serves 500px. Art from anywhere
1470  // else is shown as supplied (it is often angled or transparent).
1471  const COMPOSITE = ['amex-gold'];
1472  function art(c, cls, tag) {
1473    const src = (c.cardImage || '').replace('/cards/219x139/', '/cards/500x315/');
1474    const kind = COMPOSITE.includes(c.id) ? 'gold' : /cdn\.prodstatic\.com/.test(src) ? 'flat' : 'asis';
1475    const img = '<img src="' + esc(src) + '" alt="' + (tag === 'a' ? esc(c.name) : '') + '" loading="lazy">';
1476    return tag === 'a'
1477      ? '<a class="' + cls + ' ' + kind + '" href="/card/' + c.id + '" data-cta="card">' + img + '</a>'
1478      : '<span class="' + cls + ' ' + kind + '" aria-hidden="true">' + img + '</span>';
1479  }
1480
1481  function render() {
1482    const ranked = E.rankBySpend(spend, { mode: mode });
1483    const top = ranked[0], c = top.card;
1484    const total = CATS.reduce((s, x) => s + spend[x[0]], 0);
1485    const after = mode === 'after';
1486    $('hx-total').textContent = money(total);
1487
1488    $('hx-rows').innerHTML = CATS.map(([k, label, opts, sub]) =>
1489      '<div class="hx-row"><span class="hx-row-label">' + label + (sub ? '<small>' + sub + '</small>' : '') + '</span>' +
1490      '<div class="hx-seg" role="group" aria-label="' + label + ' per month">' +
1491      opts.map(v => '<button type="button" data-cat="' + k + '" data-val="' + v + '" aria-pressed="' + (spend[k] === v) + '">' + money(v) + '</button>').join('') +
1492      '</div><span class="hx-earn">' + rate(top, k) + ' <strong>' + money(top.perCat[k]) + '</strong></span></div>').join('');
1493
1494    // Two cards fan out behind the winner. Composite art cannot sit in a fan, so the
1495    // fan skips it; "Next best" below still names the true second and third.
1496    const fan = COMPOSITE.includes(c.id) ? [] : ranked.slice(1).filter(r => !COMPOSITE.includes(r.card.id)).slice(0, 2);
1497    $('hx-stage').innerHTML = art(c, 'hx-art hx-win', 'a') +
1498      (fan[0] ? art(fan[0].card, 'hx-art hx-r2') : '') + (fan[1] ? art(fan[1].card, 'hx-art hx-r3') : '');
1499
1500    const q = new URLSearchParams(spend).toString();
1501    const three = ranked.slice(0, 3).map(r => r.card);
1502    const cmpHref = '/compare?' + three.map((x, i) => 'abc'[i] + '=' + x.id).join('&');
1503    const welcome = top.met
1504      ? '<div><span>Welcome offer: ' + esc(c.bonusDesc || c.bonusShort || '') + '</span><strong>+' + money(top.welcome) + '</strong></div>'
1505      : '<div><span>Welcome offer needs ' + money(top.req.amount) + ' in ' + top.req.months + ' months, not counted at this spending</span><strong>$0</strong></div>';
1506    $('hx-detail').innerHTML =
1507      '<div class="hx-meta">' + esc(c.issuer) + (top.checked ? ' · Offer checked ' + day(top.checked) : '') + '</div>' +
1508      '<h2 class="hx-name"><a href="/card/' + c.id + '" data-cta="card">' + esc(c.name) + '</a></h2>' +
1509      '<div class="hx-figrow"><span class="hx-fig">' + money(after ? top.after : top.yearOne) + '</span>' +
1510      '<span class="hx-figlabel">' + (after ? 'every year after' : 'in year one') + '</span>' +
1511      '<span class="hx-recip"><strong>' + money(after ? top.yearOne : top.after) + '</strong> ' + (after ? 'in year one' : 'every year after') + '</span></div>' +
1512      '<div class="hx-actions"><a class="hx-cta" href="/quiz?' + q + '" data-cta="quiz">Continue in the quiz</a>' +
1513      '<span>Your numbers carry over. It ranks all ' + cards.length + ' cards.<
1513/span></div>' +
1514      '<div class="hx-ledger"><div><span>Rewards on this spending</span><strong>' + money(top.rewards) + '</strong></div>' +
1515      (after ? '' : welcome) +
1516      '<div><span>Annual fee</span><strong>' + (top.fee ? '−' + money(top.fee) : '$0') + '</strong></div></div>' +
1517      (c.note ? '<p class="hx-worth">' + esc(c.note) + '</p>' : '') +
1518      '<div class="hx-next"><span>Next best</span>' + ranked.slice(1, 3).map(r =>
1519        '<span>' + esc(short(r.card)) + ' <strong>' + money(after ? r.after : r.yearOne) + '</strong></span>').join('') + '</div>' +
1520      '<p class="hx-links"><a href="' + cmpHref + '" data-cta="compare">Compare these three side by side</a>' +
1521      '<a href="/card/' + c.id + '" data-cta="card">Card details</a>' +
1522      (c.guideUrl ? '<a href="' + esc(c.guideUrl) + '" data-cta="guide">Our guide</a>' : '') + '</p>';
1523    $('hx-status').textContent = c.name + ', ' + money(after ? top.after : top.yearOne) + (after ? ' every year after.' : ' in year one.');
1524
1525    // Compare Cards follows the same three.
1526    const row = (label, f) => '<div class="cmp-row" role="row"><span role="rowheader">' + label + '</span>' + three.map(x => '<span role="cell">' + f(x) + '</span>').join('') + '</div>';
1527    const floor = x => { const r = ranked.find(y => y.card === x); return r.offer ? money(r.offer) : 'None'; };
1528    $('cmp-table').innerHTML =
1529      '<div class="cmp-row cmp-head" role="row"><span role="columnheader">Your top three, from the numbers above</span>' +
1530      three.map(x => '<span class="cmp-card" role="columnheader">' + art(x, 'cc-thumb') + esc(short(x)) + '</span>').join('') + '</div>' +
1531      row('Welcome offer', x => esc(x.bonusShort || 'None')) + row('Our value', floor) +
1532      row('Annual fee', x => money(x.annualFee || 0)) +
1533      CATS.map(([k, label]) => row(label, x => rate(ranked.find(y => y.card === x), k))).join('');
1534    $('cmp-link').href = cmpHref;
1535    document.querySelectorAll('#quiz-opts a').forEach(a => { a.href = '/quiz?goal=' + a.dataset.goal + '&' + q; });
1536  }
1537
1538  $('hx-rows').addEventListener('click', e => {
1539    const b = e.target.closest('button[data-cat]');
1540    if (!b) return;
1541    spend[b.dataset.cat] = +b.dataset.val;
1542    if (!touched && typeof gtag === 'function') gtag('event', 'hero_calc_use', { category: b.dataset.cat });
1543    touched = true;
1544    render();
1545    const again = $('hx-rows').querySelector('[data-cat="' + b.dataset.cat + '"][data-val="' + b.dataset.val + '"]');
1546    if (again) again.focus();   // the rows re-render; keep the keyboard user's place
1547  });
1548  document.querySelectorAll('.hx-tabs button').forEach(b => b.addEventListener('click', () => {
1549    mode = b.dataset.mode;
1550    document.querySelectorAll('.hx-tabs button').forEach(x => x.setAttribute('aria-pressed', String(x === b)));
1551    render();
1552  }));
1553  document.querySelector('.hx').addEventListener('click', e => {
1554    const a = e.target.closest('a[data-cta]');
1555    if (a) track(a.dataset.cta);
1556  });
1557  render();
1558
1559  /* ── Current Bonus Offers: the conservative floor, never the headline; stale offers are skipped ── */
1560  const F = window.CARD_FRESHNESS || {};
1561  const offers = cards
1562    .filter(x => F[x.id] && F[x.id].bonusFloor > 0 && !(window.getBonusDisplay && window.getBonusDisplay(x).stale))
1563    .sort((a, b) => F[b.id].bonusFloor - F[a.id].bonusFloor || (a.annualFee || 0) - (b.annualFee || 0))
1564    .slice(0, 7);
1565  $('off-table').innerHTML =
1566    '<div class="off-row off-head" role="row"><span></span><span role="columnheader">Card</span><span class="off-desc" role="columnheader">Welcome offer</span>' +
1567    '<span class="off-r" role="columnheader">Our value</span><span class="off-r off-fee" role="columnheader">Annual fee</span><span class="off-r off-checked" role="columnheader">Last checked</span></div>' +
1568    offers.map(x => '<a class="off-row" role="row" href="/card/' + x.id + '">' + art(x, 'cc-thumb') +
1569      '<span class="off-name" role="cell">' + esc(x.name) + '<span class="off-issuer">' + esc(x.issuer) + '</span></span>' +
1570      '<span class="off-desc" role="cell">' + esc(x.bonusDesc || x.bonusShort || '') + '</span>' +
1571      '<span class="off-val off-r" role="cell">' + money(F[x.id].bonusFloor) + '</span>' +
1572      '<span class="off-r off-fee" role="cell">' + money(x.annualFee || 0) + '</span>' +
1573      '<span class="off-r off-checked" role="cell">' + day(F[x.id].bonusUpdated) + '</span></a>').join('');
1574
1575  /* ── Cards by type: live counts, the two best-scored cards of each lane as art ── */
1576  const LANES = [['travel', 'Travel'], ['cashback', 'Cash back'], ['dining', 'Dining'], ['nofee', 'No annual fee'], ['secured', 'Build credit'], ['business', 'Business']];
1577  const used = new Set();
1578  $('lanes').innerHTML = LANES.map(([k, label]) => {
1579    const inLane = cards.filter(x => (x.categories || []).includes(k));
1580    const pics = inLane.filter(x => /cdn\.prodstatic\.com/.test(x.cardImage || '') && !COMPOSITE.includes(x.id) && !used.has(x.id)
1581        && (k === 'business' || !(x.categories || []).includes('business')))   // consumer lanes show consumer cards
1582      .sort((a, b) => (b.cardScore || 0) - (a.cardScore || 0)).slice(0, 2);
1583    pics.forEach(x => used.add(x.id));
1584    return '<a class="lane" href="/cards?cat=' + k + '"><div class="lane-art">' + pics.map(x => art(x, 'cc-thumb')).join('') + '</div>' +
1585      '<div class="lane-ft"><strong>' + label + '</strong><span>' + inLane.length + ' cards</span></div></a>';
1586  }).join('');
1587
1588  /* ── Issuers ── */
1589  const byIssuer = {};
1590  cards.forEach(x =>
1590 { byIssuer[x.issuer] = (byIssuer[x.issuer] || 0) + 1; });
1591  const names = Object.keys(byIssuer).sort((a, b) => byIssuer[b] - byIssuer[a]);
1592  $('issuers').innerHTML = '<span>' + cards.length + ' cards from ' + names.length + ' issuers</span>' + names.slice(0, 9).map(n => '<span>' + esc(n) + '</span>').join('');
1593})();
1594</script>
vendor: 1 bytes, line 1594
1594
1595<script src="/newsletter-popup.js" defer></script>
vendor: 1 bytes, line 1595
1595
1596<script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a4027cbb9a8b36b2',t:'MTc5MDI2MDIyOA=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script>
1596<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"e79d8b0449fb411087aba9b1640e3938","r":1,"spa":2}' crossorigin="anonymous"></script>
1596
1597</body>
1598</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.