PageSourceSearch

https://perqt.ai/assets/catalog-health.lazy-P80Hmvjf.js

js perqt.ai collected 2026-10-02 01:13:38 UTC 61,043 bytes, 1 lines download raw bytes

1import{f as Ae,v as Z,w as X,x as ee,h as cs,r as k,t as f,j as e,B as $,I as os,c as ys,N as js,L as Ve,p as ds,i as ne,k as G,l as W,m as Y,s as K}from"./index-BKuXz_lx.js";import{A as vs}from"./auto-review-panel-BCwc8ZW7.js";import{u as je}from"./useQuery-Bz14us_N.js";import{u as Ne}from"./useMutation-BF1Hdgha.js";import{u as H}from"./useServerFn-DruDSVLX.js";import{L as I}from"./loader-circle-CBLTRqHC.js";import{R as te}from"./refresh-cw-DBVO72O8.js";import{S as bs}from"./shield-check-D4DHkjPh.js";import{R as ws}from"./rotate-ccw-Be5fJL9Q.js";import{T as Ns}from"./trash-2-BbqMbnun.js";import{C as us}from"./circle-check-ByACOMw5.js";import{E as ms}from"./external-link-HoP5N-og.js";import{B as _s}from"./back-link-Cu1gDYAu.js";import{w as ks,s as Ge}from"./import-benefits-stream-C5ccAJX0.js";import{t as We}from"./benefit-write-row-D9D-Yyw-.js";import{C as me,c as ye}from"./card-Cez4CVsR.js";import{B as O}from"./badge-Ctlu4O3Q.js";import{S as $s,a as Cs,b as Ss,c as Rs,d as de}from"./select-wMiXnjQh.js";import{u as Ye}from"./format-xqYhVKQ8.js";import{a as Fs,s as Es}from"./seed-earning-rates.functions-CwhjeLqD.js";import{u as qs,i as Ze}from"./use-session-expired-BJrKf_KU.js";import{I as zs}from"./info-ZGWILGHP.js";import{S as _e}from"./sparkles-bm4VxieG.js";import{W as Re}from"./wand-sparkles-DssD89dh.js";import{C as fs}from"./chevron-down-C-0pMlkS.js";import{T as ue}from"./triangle-alert-BqWhhR-9.js";import{L as Xe}from"./link-2-BrBmZL4v.js";import"./use-authenticated-server-fn-BskzYOmC.js";import"./arrow-left-CjswZ4jf.js";import"./ai-cost.functions-CioM0F2e.js";const Ps=[["path",{d:"m10.852 19.772-.383.924",key:"r7sl7d"}],["path",{d:"m13.148 14.228.383-.923",key:"1d5zpm"}],["path",{d:"M13.148 19.772a3 3 0 1 0-2.296-5.544l-.383-.923",key:"1ydik7"}],["path",{d:"m13.53 20.696-.382-.924a3 3 0 1 1-2.296-5.544",key:"1m1vsf"}],["path",{d:"m14.772 15.852.923-.383",key:"660p6e"}],["path",{d:"m14.772 18.148.923.383",key:"hrcpis"}],["path",{d:"M4.2 15.1a7 7 0 1 1 9.93-9.858A7 7 0 0 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.2",key:"j2q98n"}],["path",{d:"m9.228 15.852-.923-.383",key:"1p9ong"}],["path",{d:"m9.228 18.148-.923.383",key:"6558rz"}]],As=Ae("cloud-cog",Ps);const Is=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",ry:"2",key:"1m3agn"}],["circle",{cx:"9",cy:"9",r:"2",key:"af1f0g"}],["path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21",key:"1xmnt7"}]],es=Ae("image",Is);const Ms=[["path",{d:"M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0",key:"1r0f0z"}],["circle",{cx:"12",cy:"10",r:"3",key:"ilqhr7"}]],Bs=Ae("map-pin",Ms),hs=Z({method:"POST"}).middleware([X]).handler(ee("08a527aa9820d8399cf950244e4c5d973c009645840820736c8a5b1b635f061e")),Ts=Z({method:"POST"}).middleware([X]).handler(ee("20416ab5f96bdc4b6affeff2b43dc1f3be7bc7fc6dfbe40d2b3c843b4573e897")),Ls=Z({method:"GET"}).middleware([X]).handler(ee("726a95b93def9305e7d7e3f38cfdb24fdcc23e9d2ed383bb04a6abcd8eaa3377")),Os=Z({method:"POST"}).middleware([X]).handler(ee("126e275cfd2067b9eb09f09458737656356b3971879b5f496b5b924096f95fe6")),Ks=Z({method:"POST"}).middleware([X]).handler(ee("a86520bf275b36450368664446b76592fd1f153d73d532c7ae291818ade82caf"));function Qs({cardIds:s,label:n}){const u=cs(),m=H(hs),g=H(Ls),j=H(Os),h=H(Ks),N=H(Ts),[p,Q]=k.useState(!1),{data:w,isLoading:P}=je({queryKey:["catalog-reverify-status"],queryFn:()=>g(),refetchInterval:b=>b.state.data?.active?5e3:3e4}),B=Ne({mutationFn:()=>m({data:{cardIds:s}}),onSuccess:b=>{f.success(b.enqueued>0?`Queued ${b.enqueued} card${b.enqueued===1?"":"s"} — you can close this page`:"Every one of those cards is already in the queue"),u.invalidateQueries({queryKey:["catalog-reverify-status"]})},onError:b=>f.error(b?.message??"Could not queue re-verification")}),J=Ne({mutationFn:()=>N(),onSuccess:b=>{f.success(b.enqueued>0?`Queued ${b.enqueued} card${b.enqueued===1?"":"s"} for issuer-only re-verification (${b.rows} rows cite a reviewer page)`:b.cards>0?"Those cards are already in the queue":"No benefits are relying on reviewer pages"),u.invalidateQueries({queryKey:["catalog-reverify-status"]})},onError:b=>f.error(b?.message??"Could not queue re-verification")}),E=Ne({mutationFn:()=>j(),onSuccess:()=>u.invalidateQueries({queryKey:["catalog-reverify-status"]})}),x=Ne({mutationFn:()=>h(),onSuccess:b=>{f.success(`${b.requeued} card${b.requeued===1?"":"s"}
1 re-queued`),u.invalidateQueries({queryKey:["catalog-reverify-status"]})}}),y=(w?.done??0)+(w?.failed??0),_=w?.total??0,ie=_>0?Math.round(y/_*100):0;return e.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/60 p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(As,{className:"size-5 shrink-0 text-primary mt-0.5"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-medium",children:"Automatic background re-verification"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Runs on the server and keeps going on its own. Queue it once, close the page — the remaining cards keep processing and failures retry automatically."})]})]}),e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row",children:[e.jsx($,{className:"w-full sm:w-auto",onClick:()=>B.mutate(),disabled:B.isPending||s.length===0,children:B.isPending?e.jsxs(e.Fragment,{children:[e.jsx(I,{className:"size-4 animate-spin"})," Queueing…"]}):e.jsxs(e.Fragment,{children:[e.jsx(te,{className:"size-4"})," Verify in background (",s.length,")"]})}),e.jsx($,{variant:"outline",className:"w-full sm:w-auto",onClick:()=>J.mutate(),disabled:J.isPending,children:J.isPending?e.jsxs(e.Fragment,{children:[e.jsx(I,{className:"size-4 animate-spin"})," Queueing…"]}):e.jsxs(e.Fragment,{children:[e.jsx(bs,{className:"size-4"})," Re-verify unofficial sources"]})}),(w?.failed??0)>0&&e.jsxs($,{variant:"outline",className:"w-full sm:w-auto",onClick:()=>x.mutate(),disabled:x.isPending,children:[e.jsx(ws,{className:"size-4"})," Retry failed (",w?.failed,")"]}),!w?.active&&_>0&&e.jsxs($,{variant:"ghost",className:"w-full sm:w-auto",onClick:()=>E.mutate(),disabled:E.isPending,children:[e.jsx(Ns,{className:"size-4"})," Clear history"]})]}),e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["Scope: ",n]}),P?e.jsx("p",{className:"text-xs text-muted-foreground",children:"Checking queue…"}):_===0?e.jsx("p",{className:"text-xs text-muted-foreground",children:"Queue is empty."}):e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[w?.active&&e.jsx(I,{className:"size-4 animate-spin text-primary"}),e.jsxs("span",{children:[y," / ",_," cards processed",w?.active?" · still running on the server":" · run complete"]})]}),e.jsx("div",{className:"h-1.5 w-full overflow-hidden rounded-full bg-muted",children:e.jsx("div",{className:"h-full bg-primary transition-all",style:{width:`${ie}%`}})}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[w?.queued??0," waiting · ",w?.running??0," in progress ·"," ",w?.done??0," verified · ",w?.failed??0," need attention"]}),(w?.failures?.length??0)>0&&e.jsxs("div",{className:"text-xs",children:[e.jsxs("button",{type:"button",className:"underline underline-offset-2",onClick:()=>Q(b=>!b),children:[p?"Hide":"Show"," what needs attention"]}),p&&e.jsx("ul",{className:"mt-2 space-y-1 text-muted-foreground",children:w?.failures.map(b=>e.jsxs("li",{children:[e.jsx("span",{className:"font-mono",children:b.card_catalog_id.slice(0,8)})," ·"," ",b.last_error??"unknown error"," (after ",b.attempts," attempts)"]},b.card_catalog_id))})]})]})]})}const Us=Z({method:"POST"}).middleware([X]).handler(ee("1e4cb26335a5273f6fce4401dea4da4f366523607c85098914dabec405a5c5eb")),Ds=Z({method:"POST"}).middleware([X]).handler(ee("f33a7db07bcef3c98df7a1885293522ead0e230407ad6f344df7a6a758376564")),ke=8;function Hs({onPinned:s}){const[n,u]=k.useState(!1),[m,g]=k.useState(0),[j,h]=k.useState(null),[N,p]=k.useState(null),[Q,w]=k.useState({}),[P,B]=k.useState({}),J=async x=>{u(!0);try{const y=await Us({data:{limit:ke,offset:x}});h(y),g(x),f.success(`${y.withCandidates} of ${y.scanned} unpinned cards have a suggested page`+(y.remaining>0?` · ${y.remaining} more unpinned`:""))}catch(y){f.error(y instanceof Error?y.message:"Could not generate suggestions")}finally{u(!1)}},E=async(x,y)=>{p(`${x}:${y}`);try{const _=await Ds({data:{card_catalog_id:x,url:y}});w(ie=>({...ie,[x]:_.pin})),f.success(`Pinned · ${_.flagged} row${_.flagged===1?"":"s"} now flagged off pin, ${_.cleared} cleared`),s?.()}catch(_){f.error(_ instanceof Error?_.message:"Pin rejected")}finally{p(null)}};return e.jsxs("section",{className:"mt-6 rounded-2xl border border-metallic bg-metallic/20 p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{className:"max-w-2xl",children:[e.jsxs("h2",{className:"font-display text-lg flex items-center gap-2",children:[e.jsx(Bs,{className:"size-4 text-gold","aria-hidden":!0}),"Suggested canonical issuer pages"]}),e.jsx("p",{className:"text-xs text-titanium mt-1",children:"For each card with no pinned page, this proposes the issuer page most likely to be its definition of truth — ranked by how much existing evidence already cites it, verified live, and rejected outright if it names a sibling product or is a press page or PDF. No AI credits are used. Nothing is written until you confirm one."})]}),e.jsx($,{size:"sm",disabled:n,onClick:()=>J(0),children:n?e.jsx(I,{className:"size-4 animate-spin"}):"Generate suggestions"})]}),j&&e.jsxs("div",{className:"mt-4 space-y-3 text-xs",children:[e.jsx("div",{className:"grid grid-cols-3 gap-2",children:[["Cards scanned",j.scanned],["With a suggestion",j.withCandidates],["Unpinned remaining",j.remaining]].map(([x,y])=>e.jsxs("div",{className:"rounded-xl border border-metallic bg-black/20 p-2",children:[e.jsx("p",{className:"text-titanium",children:x}),e.jsx("p",{className:"font-display text-lg",children:String(y)})]},String(x)))}),e.jsx("ul",{className:"space-y-2",children:j.suggestions.map(x=>{const y=Q[x.cardCatalogId];return e.jsxs("li",{className:"rounded-xl border border-metallic bg-black/20 p-2.5",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs("p",{className:"font-medium text-platinum",children:[x.issuer," ",x.name]}),y&&e.jsxs("span",{className:"flex items-center gap-1 text-gold",children:[e.jsx(us,{className:"size-3.5","aria-hidden":!0})," pinned"]})]}),y?e.jsx("p",{className:"mt-1 break-all text-titanium",children:y}):e.jsxs(e.Fragment,{children:[x.candidates.length===0&&e.jsxs("p",{className:"mt-1 text-amber-300/90",children:["No usable c
1andidate",x.reason?` — ${x.reason}`:"",". Paste the issuer page below if you know it."]}),e.jsx("ul",{className:"mt-1.5 space-y-1.5",children:x.candidates.map(_=>e.jsxs("li",{className:"rounded-lg border border-metallic/60 bg-metallic/10 p-2",children:[e.jsxs("a",{href:_.url,target:"_blank",rel:"noreferrer noopener",className:"break-all text-platinum underline decoration-gold/40 underline-offset-2 hover:text-gold",children:[_.url,e.jsx(ms,{className:"ml-1 inline size-3","aria-hidden":!0})]}),e.jsx("p",{className:"mt-0.5 text-titanium",children:_.note}),e.jsx($,{size:"sm",variant:"outline",className:"mt-1.5",disabled:N!==null,onClick:()=>E(x.cardCatalogId,_.url),children:N===`${x.cardCatalogId}:${_.url}`?e.jsx(I,{className:"size-4 animate-spin"}):"Confirm this pin"})]},_.url))}),e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[e.jsx(os,{value:P[x.cardCatalogId]??"",onChange:_=>B(ie=>({...ie,[x.cardCatalogId]:_.target.value})),placeholder:"https://issuer.com/… (pin your own page)",className:"h-8 max-w-md text-xs"}),e.jsx($,{size:"sm",variant:"outline",disabled:N!==null||!(P[x.cardCatalogId]??"").trim(),onClick:()=>E(x.cardCatalogId,(P[x.cardCatalogId]??"").trim()),children:"Pin this URL"})]})]})]},x.cardCatalogId)})}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx($,{size:"sm",variant:"outline",disabled:n||m===0,onClick:()=>J(Math.max(m-ke,0)),children:"Previous"}),e.jsxs($,{size:"sm",variant:"outline",disabled:n||j.remaining===0,onClick:()=>J(m+ke),children:["Next ",ke," unpinned"]})]})]})]})}const Js=Z({method:"POST"}).middleware([X]).handler(ee("7d77d2c6d378a060ad4eedc20025f71aa948c9c7e30864440c3ed8dec0613c32")),Fe=Z({method:"POST"}).middleware([X]).handler(ee("caa6b1297bd7a3bc0ab072cdabf112d9f2a15e943a3ec9ad7616d937d6108fcf")),ss="the preview reloaded mid-request — nothing was changed, run it again";function $e(s,n=0,u=new Set){if(n>4||s==null)return[];if(typeof s=="string")return[s];if(typeof s!="object")return[];if(u.has(s))return[];u.add(s);const m=[];if(Array.isArray(s)){for(const g of s)m.push(...$e(g,n+1,u));return m}for(const g of["message","body","data","error","statusText","detail","details","cause"]){const j=s[g];m.push(...$e(j,n+1,u))}return m}function qe(s){return/FORCE_RELOAD/i.test(s)||/window\.parent\.postMessage/i.test(s)||/^<(!doctype|html)/i.test(s)||/<html[\s>]/i.test(s)||/<script[\s>]/i.test(s)}function D(s,n="unknown error"){const u=$e(s);if(u.some(qe))return ss;const m=typeof s=="string"?s:s instanceof Error?s.message:String(s?.message??u[0]??""),g=String(m??"").trim();return g?qe(g)?ss:g:n}function Vs(s){return $e(s).some(qe)}const Gs=[{pattern:/\b(marriott|bonvoy)\b/i,label:"Marriott"},{pattern:/\b(hilton|aspire|honors)\b/i,label:"Hilton"},{pattern:/\bhyatt\b/i,label:"Hyatt"},{pattern:/\b(ihg|holiday inn)\b/i,label:"IHG"},{pattern:/\b(delta|skymiles)\b/i,label:"Delta"},{pattern:/\b(united|mileageplus)\b/i,label:"United"},{pattern:/\b(american airlines|aadvantage)\b/i,label:"American Airlines"},{pattern:/\b(jetblue|trueblue)\b/i,label:"JetBlue"},{pattern:/\b(aeroplan|air canada)\b/i,label:"Aeroplan"},{pattern:/\b(alaska)\b/i,label:"Alaska"},{pattern:/\b(southwest|rapid rewards)\b/i,label:"Southwest"}];function as(s){const n=[],u=s.unevidencedMonetary??0;u>0&&n.push({code:"unevidenced_value",message:`${u} benefit row${u===1?"":"s"} claim a dollar value with no issuer source URL or quoted wording. Members see no dollar value for these.`}),(s.benefits??0)>0&&s.verifiedBenefits===0&&n.push({code:"no_confirmed_benefits",message:"Benefit rows exist but none have been confirmed against the issuer."});const m=`${s.rewards_summary??""} ${s.description??""}`,g=new Set;for(const P of m.matchAll(/\$(\d[\d,]*)\s+annual fee/gi)){const B=Number(P[1].replace(/,/g,""));Number.isFinite(B)&&g.add(B)}const j=[...g].filter(P=>P!==s.annual_fee);if(j.length>0&&n.push({code:"prose_fee_mismatch",message:`Card summary mentions $${j.join("/$")} annual fee but the stored fee is $${s.annual_fee} — re-read the pinned page and correct the prose.`}),(s.benefitCategories??[]).some(P=>P?.toLowerCase()==="elite_status")||s.annual_fee<395)return n;const Q=`${s.name} ${s.rewards_summary??""} ${s.description??""}`.toLowerCase();if(/\b(elite|status|diamond|globalist|titanium|platinum medallion|executive platinum)\b/.test(Q))return n;const w=Gs.find(P=>P.pattern.test(s.name));return w&&n.push({code:"missing_elite_status",message:`Missing expected ${w.label} elite status (co-brand card, $${s.annual_fee} fee)`}),n}const Ws=/(reserve|platinum|infinite|elite|premier|business preferred|x card)/i;function ze(s){return s.rates>0}function Ys(s){if(s.benefits===0&&s.rates===0)return"stub";const n=ze(s),u=s.benefits>0;return!n||!u||s.annual_fee===0&&Ws.test(s.name)||(s.unevidencedMonetary??0)>0?"partial":"complete"}const Ia=ys("/_authenticated/_admin/catalog-health")({component:ia}),Ce="perqt.catalog-health.reverify-done",Zs=1440*60*1e3;function Pe(){if(typeof window>"u")return null;try{const s=window.localStorage.getItem(Ce);if(!s)return null;const n=JSON.parse(s);return!n.at||Date.now()-n.at>Zs?(window.localStorage.removeItem(Ce),null):n}catch{return null}}function Xs(){const s=Pe();return new Set(Array.isArray(s?.ids)?s.ids:[])}function ts(s,n=!1,u){if(!(typeof window>"u"))try{window.localStorage.setItem(Ce,JSON.stringify({at:Date.now(),ids:Array.from(s),active:n,scopeIds:u}))}catch{}}function Ee(){if(!(typeof window>"u"))try{window.localStorage.removeItem(Ce)}catch{}}let pe=null;async function ea(){return pe||(pe=(async()=>{try{const{data:s}=await K.auth.getSession(),n=s.session?.expires_at;if(!n)return;n-Math.floor(Date.now()/1e3)<300&&await K.auth.refreshSession()}catch{}finally{pe=null}})(),pe)}function ae(s){return Ys(s)}function ns(s){return/^Centurion/i.test(s.name)?`The American Express Centurion Card (known as the "Black Card") is an ultra-exclusive, invitation-only charge card for the world's highest earners. The card requires a significant six-figure annual spend and has a $5,000 annual fee alongside a $10,000 initiation fee.`:/J\.?P\.?\s*Morgan\s*Reserve/i.test(s.name)||/palladium/i.test(s.name)?"The J.P. Morgan Reserve Card (formerly known as the Palladium Card) is an exclusive, invitation-only credit card reserved for clients of J.P. Morgan's Global Private Bank.":null}
1function is({label:s,message:n,className:u}){const[m,g]=k.useState(!1);return e.jsxs(e.Fragment,{children:[e.jsx(O,{variant:"outline",role:"button",tabIndex:0,onClick:()=>g(j=>!j),className:ne("text-[10px] gap-1 cursor-pointer select-none",u),children:s}),m&&e.jsx("div",{className:"w-full rounded-md border border-gold/30 bg-metallic/30 px-2 py-1.5 text-[11px] leading-snug text-platinum",children:n})]})}function sa(s,n){const u=m=>{try{const g=new URL(m);return`${g.hostname.toLowerCase().replace(/^www\./,"")}${g.pathname.replace(/\/+$/,"").toLowerCase()}`}catch{return m.toLowerCase()}};return u(s)===u(n)}function rs({row:s}){const[n,u]=k.useState(!1),m=s.sources,g=[s.canonicalSourceUrl,...s.canonicalSourceAliases].filter(p=>typeof p=="string"&&p.length>0),j=p=>g.some(Q=>sa(Q,p)),h=m.filter(p=>!j(p.url)).length,N=p=>{try{return new URL(p).hostname.replace(/^www\./,"")}catch{return p}};return m.length===0?e.jsxs("p",{className:"text-[11px] text-muted-foreground flex items-center gap-1.5",children:[e.jsx(Xe,{className:"size-3 shrink-0"})," No source links stored for this card's benefits or rates."]}):e.jsxs("div",{className:"rounded-md border border-metallic/40 bg-metallic/10",children:[e.jsxs("button",{type:"button",onClick:()=>u(p=>!p),"aria-expanded":n,className:"flex w-full items-center gap-1.5 px-2 py-1.5 text-left text-[11px] text-titanium hover:text-platinum",children:[n?e.jsx(fs,{className:"size-3 shrink-0"}):e.jsx(ds,{className:"size-3 shrink-0"}),e.jsx(Xe,{className:"size-3 shrink-0"}),e.jsxs("span",{children:[m.length," source ",m.length===1?"link":"links"]}),!n&&e.jsxs("span",{className:"truncate text-muted-foreground",children:["· ",m.slice(0,2).map(p=>N(p.url)).join(", "),m.length>2?` +${m.length-2}`:"",g.length>0&&h>0?` · ${h} off pin`:"",g.length===0?" · unpinned":""]})]}),n&&e.jsx("div",{className:"border-t border-metallic/40 px-2 py-1.5 text-[11px]",children:s.canonicalSourceUrl?e.jsxs("p",{className:"text-muted-foreground",children:[e.jsx("span",{className:"text-gold",children:"Pinned issuer page:"})," ",e.jsx("a",{href:s.canonicalSourceUrl,target:"_blank",rel:"noreferrer noopener",className:"break-all text-platinum underline decoration-gold/40 underline-offset-2 hover:text-gold",children:s.canonicalSourceUrl}),s.canonicalSourceAliases.length>0&&e.jsxs(e.Fragment,{children:[" ","· ",s.canonicalSourceAliases.length," verified equivalent",s.canonicalSourceAliases.length===1?"":"s"]})]}):e.jsx("p",{className:"text-amber-300/90",children:"No pinned issuer page yet — this card is still built from whatever official pages discovery finds."})}),n&&e.jsx("ul",{className:"space-y-1 border-t border-metallic/40 px-2 py-1.5",children:m.map(p=>e.jsxs("li",{className:"flex items-start gap-1.5 text-[11px]",children:[e.jsxs("a",{href:p.url,target:"_blank",rel:"noreferrer noopener",className:"min-w-0 flex-1 break-all text-platinum underline decoration-gold/40 underline-offset-2 hover:text-gold",children:[p.url,e.jsx(ms,{className:"ml-1 inline size-3 align-[-1px]"})]}),g.length>0&&e.jsx("span",{className:`shrink-0 rounded px-1 py-[1px] text-[10px] ${j(p.url)?"bg-emerald-500/15 text-emerald-300":"bg-amber-500/15 text-amber-300"}`,title:j(p.url)?"Matches this card's pinned page (or a verified equivalent)":"Not the pinned page — rows citing this page are flagged for review",children:j(p.url)?"on pin":"off pin"}),e.jsxs("span",{className:"shrink-0 whitespace-nowrap font-mono text-muted-foreground",children:[p.benefits>0&&`${p.benefits}b`,p.benefits>0&&p.rates>0&&" · ",p.rates>0&&`${p.rates}r`]})]},p.url))})]})}function aa(){const{data:s=[]}=je({queryKey:["catalog-fee-drift"],queryFn:async()=>{const{data:n,error:u}=await K.from("card_catalog_change_log").select("id,card_catalog_id,before_value,after_value,source_url,source_snippet,created_at").eq("field","annual_fee").eq("method","pinned_doc_fee_drift").eq("written",!1).order("created_at",{ascending:!1}).limit(100);if(u)throw u;const m=n??[],g=[...new Set(m.map(h=>h.card_catalog_id).filter(Boolean))],j=new Map;try{if(g.length){const{data:h}=await K.from("card_catalog").select("*").in("id",g);for(const N of h??[])j.set(N.id,`${N.issuer} · ${N.name}`)}}catch{}return m.map(h=>({id:h.id,card:j.get(h.card_catalog_id)??"Unknown card",stored:String(h.before_value??""),pinned:String(h.after_value??""),url:h.source_url??null,snippet:h.source_snippet??""}))}});return s.length===0?null:e.jsx(me,{className:"mt-6 border-amber-500/40",children:e.jsxs(ye,{className:"p-4 sm:p-5",children:[e.jsxs("p",{className:"text-xs uppercase tracking-[0.2em] text-amber-400",children:["Annual fee mismatch · ",s.length," card",s.length===1?"":"s"]}),e.jsx("p",{className:"text-sm text-titanium mt-2",children:"A pinned issuer page states a different annual fee than the catalog. Nothing is changed automatically — read the quote, then correct the fee if the issuer is right."}),e.jsx("ul",{className:"mt-3 space-y-3",children:s.map(n=>e.jsxs("li",{className:"text-sm",children:[e.jsx("span",{className:"font-medium",children:n.card})," ",e.jsxs("span",{className:"text-titanium",children:["— catalog $",n.stored,", pinned page $",n.pinned]}),n.snippet?e.jsxs("blockquote",{className:"mt-1 text-xs text-titanium border-l-2 border-titanium/30 pl-2",children:["“",n.snippet.slice(0,220),"”"]}
1):null,n.url?e.jsx("a",{href:n.url,target:"_blank",rel:"noreferrer",className:"text-xs underline text-titanium hover:text-platinum",children:"Open pinned page"}):null]},n.id))})]})})}function ta(){const{data:s=[]}=je({queryKey:["catalog-pinned-reread"],queryFn:async()=>{const{data:n,error:u}=await K.from("card_catalog_change_log").select("id,card_catalog_id,field,before_value,after_value,source_url,validator_notes,created_at").in("method",["pinned_doc_rate_review","pinned_doc_offer_review","pinned_doc_benefit_review"]).eq("written",!1).order("created_at",{ascending:!1}).limit(100);if(u)throw u;const m=n??[],g=[...new Set(m.map(h=>h.card_catalog_id).filter(Boolean))],j=new Map;try{if(g.length){const{data:h}=await K.from("card_catalog").select("*").in("id",g);for(const N of h??[])j.set(N.id,`${N.issuer} · ${N.name}`)}}catch{}return m.map(h=>({id:h.id,card:j.get(h.card_catalog_id)??"Unknown card",field:String(h.field??""),note:String(h.validator_notes??""),url:h.source_url??null}))}});return s.length===0?null:e.jsx(me,{className:"mt-6 border-amber-500/40",children:e.jsxs(ye,{className:"p-4 sm:p-5",children:[e.jsxs("p",{className:"text-xs uppercase tracking-[0.2em] text-amber-400",children:["Pinned page re-read · ",s.length," item",s.length===1?"":"s"," need a call"]}),e.jsx("p",{className:"text-sm text-titanium mt-2",children:"Earning rates, welcome offers and benefit amounts that a pinned issuer capture contradicts unambiguously are already corrected. These could not be decided from the quote alone."}),e.jsx("ul",{className:"mt-3 space-y-2",children:s.map(n=>e.jsxs("li",{className:"text-sm",children:[e.jsx("span",{className:"font-medium",children:n.card})," ",e.jsxs("span",{className:"text-titanium",children:["—"," ",n.field==="welcome_offer"?"welcome offer":n.field==="benefit_dollar_value"?"benefit amount":"earning rates",": ",n.note]}),n.url?e.jsxs(e.Fragment,{children:[" ",e.jsx("a",{href:n.url,target:"_blank",rel:"noreferrer",className:"text-xs underline text-titanium hover:text-platinum",children:"Open pinned page"})]}):null]},n.id))})]})})}function na(){const{data:s}=je({queryKey:["catalog-unsourced-rates"],queryFn:async()=>{const{data:n,error:u}=await K.from("card_earning_rates").select("id,card_catalog_id,category,multiplier").is("source_verified_at",null).limit(1e3);if(u)throw u;const m=new Map;for(const h of n??[]){const N=h.card_catalog_id;m.set(N,(m.get(N)??0)+1)}const g=[...m.keys()],j=new Map;for(let h=0;h<g.length;h+=40){const{data:N}=await K.from("card_catalog").select("id,issuer,name").in("id",g.slice(h,h+40));for(const p of N??[])j.set(p.id,`${p.issuer} · ${p.name}`)}return{total:(n??[]).length,cards:g.map(h=>({id:h,label:j.get(h)??"Unknown card",count:m.get(h)??0})).sort((h,N)=>N.count-h.count)}
1}});return!s||s.total===0?null:e.jsx(me,{className:"mt-6 border-titanium/30",children:e.jsxs(ye,{className:"p-4 sm:p-5",children:[e.jsxs("p",{className:"text-xs uppercase tracking-[0.2em] text-titanium",children:["Unverified earning rates · ",s.total," row",s.total===1?"":"s"," on ",s.cards.length," card",s.cards.length===1?"":"s"]}),e.jsx("p",{className:"text-sm text-titanium mt-2",children:"No issuer quote is stored behind these rates, so they are not proven. Pin a terms or pricing page for the card and the weekly re-read will reconcile them."}),e.jsx("ul",{className:"mt-3 space-y-1 text-sm",children:s.cards.map(n=>e.jsxs("li",{children:[e.jsx("span",{className:"font-medium",children:n.label})," ",e.jsxs("span",{className:"text-titanium",children:["— ",n.count," unverified rate rows"]})]},n.id))})]})})}function ia(){const s=cs(),n=js(),u=qs(),m=H(Js),g=H(ks),j=H(Fs),h=H(Es),N=H(hs),[p,Q]=k.useState(!1),[w,P]=k.useState("all"),[B,J]=k.useState(""),[E,x]=k.useState(null),[y,_]=k.useState(!1),[ie,b]=k.useState({}),[xs,Ie]=k.useState(null),[V,Me]=k.useState(!1),[re,Be]=k.useState({done:0,total:0,failed:0}),Te=k.useRef(!1),{data:R=[],isLoading:U}=je({queryKey:["catalog-health"],queryFn:async()=>{async function a(r){let C=0;const T=[];for(;;){const{data:ce,error:L}=await r().range(C,C+1e3-1);if(L)throw L;const M=ce??[];if(T.push(...M),M.length<1e3)break;C+=1e3}return T}const[{data:i,error:c},o,t]=await Promise.all([K.from("card_catalog").select("id,issuer,name,annual_fee,description,rewards_summary,fee_verified_at,fee_source_url,card_type,canonical_source_url,canonical_source_aliases").order("issuer").order("name"),a(()=>K.from("card_benefits").select("card_catalog_id,category,dollar_value,source_url,source_snippet,verification_state,created_at").eq("status","active")),a(()=>K.from("card_earning_rates").select("card_catalog_id,source_url"))]);if(c)throw c;const l=new Map,d=new Map,v=new Map,F=new Map,z=new Map,oe=new Map,se=new Map,xe=(r,S,C)=>{const T=(S??"").trim();if(!T)return;const ce=se.get(r)??new Map,L=ce.get(T)??{benefits:0,rates:0};L[C]+=1,ce.set(T,L),se.set(r,ce)},A=(r,S)=>r.set(S,(r.get(S)??0)+1);for(const r of o??[]){A(l,r.card_catalog_id);const S=d.get(r.card_catalog_id)??[];r.category&&S.push(r.category),d.set(r.card_catalog_id,S),xe(r.card_catalog_id,r.source_url,"benefits");const C=Number(r.dollar_value??0);if(Number.isFinite(C)&&C>0&&(A(v,r.card_catalog_id),(r.source_url??"").trim()&&(r.source_snippet??"").trim()||A(F,r.card_catalog_id)),r.verification_state==="verified"&&A(z,r.card_catalog_id),r.created_at){const T=oe.get(r.card_catalog_id);(!T||r.created_at>T)&&oe.set(r.card_catalog_id,r.created_at)}}const le=new Map;for(const r of t??[])le.set(r.card_catalog_id,(le.get(r.card_catalog_id)??0)+1),xe(r.card_catalog_id,r.source_url,"rates");return(i??[]).map(r=>({id:r.id,issuer:r.issuer,name:r.name,annual_fee:Number(r.annual_fee),description:r.description,rewards_summary:r.rewards_summary,benefits:l.get(r.id)??0,rates:le.get(r.id)??0,monetaryBenefits:v.get(r.id)??0,unevidencedMonetary:F.get(r.id)??0,verifiedBenefits:z.get(r.id)??0,fee_verified_at:r.fee_verified_at??null,fee_source_url:r.fee_source_url??null,lastBenefitAt:oe.get(r.id)??null,card_type:r.card_type??"personal",benefitCategories:d.get(r.id)??[],canonicalSourceUrl:r.canonical_source_url??null,canonicalSourceAliases:Array.isArray(r.canonical_source_aliases)?r.canonical_source_aliases:[],sources:Array.from(se.get(r.id)?.entries()??[]).map(([S,C])=>({url:S,benefits:C.benefits,rates:C.rates})).sort((S,C)=>C.benefits+C.rates-(S.benefits+S.rates)||S.url.localeCompare(C.url))}))}}),q=k.useMemo(()=>{const a=B.trim().toLowerCase();return R.filter(i=>{if(w==="unverified-fee"){if(i.fee_verified_at&&i.fee_source_url)return!1}else if(w==="unevidenced-value"){if(i.unevidencedMonetary===0)return!1}else if(w!=="all"&&ae(i)!==w)return!1;return!(a&&!`${i.issuer} ${i.name}`.toLowerCase().includes(a))})},[R,w,B]),fe=k.useMemo(()=>{const a={stub:0,partial:0,complete:0,unverifiedFee:0,unevidencedValue:0};for(const i of R)a[ae(i)]++,(!i.fee_verified_at||!i.fee_source_url)&&a.unverifiedFee++,i.unevidencedMonetary>0&&a.unevidencedValue++;return a},[R]),ve=k.useMemo(()=>R.filter(a=>ae(a)!=="complete"||!a.fee_verified_at||!a.fee_source_url),[R]),he=k.useMemo(()=>{const a=new Map;for(const i of q){const c=i.issuer||"Unknown",o=a.get(c)??[];o.push(i),a.set(c,o)}return Array.from(a.entries()).map(([i,c])=>{const o={stub:0,partial:0,complete:0};for(const t of c)o[ae(t)]++;return{issuer:i,cards:c,counts:o}}).sort((i,c)=>i.issuer.localeCompare(c.issuer))},[q]);async function Se(a){let i="",c="";try{const d=await m({data:{card_catalog_id:a.id}});
1d.changed&&(i=`fee $${d.before.annual_fee}→$${d.after.annual_fee}`,d.fee_method&&(i+=` (${d.fee_method})`)),d.fee_rejected&&(c=`⚠ ${d.fee_rejected} — kept stored fee`)}catch(d){return{ok:!1,msg:`metadata: ${D(d,"failed")}`}}let o=0;if(a.rates===0)try{o=(await j({data:{card_catalog_id:a.id,overwrite:!1}})).inserted??0}catch(d){return{ok:!1,msg:`rates: ${D(d,"failed")}`}}let t=0;if(a.benefits===0){const d=[];let v=null;if(await Ge({issuer:a.issuer,name:a.name,annual_fee:a.annual_fee},{onBenefit:F=>d.push(F),onError:F=>{Ze(F)&&u(),v=F}}),v)return{ok:!1,msg:`benefits: ${v}`};if(d.length>0)try{t=(await g({data:{rows:d.map(z=>We(a.id,z))}})).inserted}catch(F){return{ok:!1,msg:`benefits insert: ${D(F,"failed")}`}}}const l=[i,o>0?`${o} rates`:"",t>0?`${t} benefits`:"",c].filter(Boolean);return{ok:!0,msg:l.length?l.join(", "):"already complete"}}async function Le(a){x(a.id);try{const i=await Se(a);i.ok?f.success(`${a.issuer} ${a.name}: ${i.msg}`):f.error(`${a.issuer} ${a.name}: ${i.msg}`),s.invalidateQueries({queryKey:["catalog-health"]}),s.invalidateQueries({queryKey:["earning-rates",a.id]}),s.invalidateQueries({queryKey:["benefits"]})}finally{x(null)}}async function Oe(a){if(await n({title:`Re-verify welcome offer for ${a.issuer} ${a.name}?`,description:"This re-scrapes the issuer page, re-extracts the offer with AI, and overwrites the stored offer if numbers have changed. Any corrections are logged to the change log.",confirmText:"Re-verify"})){x(a.id);try{const i="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhheWF3bG50dGxybGViZ2RkeXNsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzgyNDg1NDQsImV4cCI6MjA5MzgyNDU0NH0.ULgK7CkPAxpPQ_IHJTHMbIDufA-HPiMKauVOBaJLtWg",c=await fetch("/api/public/hooks/refresh-welcome-offers",{method:"POST",headers:{"Content-Type":"application/json",apikey:i},body:JSON.stringify({catalogIds:[a.id],limit:1})}),o=await c.text();let t=null;try{t=JSON.parse(o)}catch{f.error(`Re-verify offer failed: ${D(o,`server returned ${c.status} ${c.statusText||"an unexpected response"}`)}`);return}if(!c.ok||!t?.ok){f.error(`Re-verify offer failed: ${D(t?.error,c.statusText||`status ${c.status}`)}`);return}const l=t.results?.[0];if(!l){f.warning("No result returned");return}if(!l.updated){f.warning(`Welcome offer not updated: ${l.reason??"unknown"}`);return}if(typeof l.reason=="string"&&l.reason.startsWith("corrected:")){const d=Number(l.reason.split(":")[1])||0;f.success(`Welcome offer corrected — ${d} field${d===1?"":"s"} changed. Logged to change log.`)}else f.success("Welcome offer verified — no changes.")}catch(i){f.error(`Re-verify offer failed: ${D(i)}`)}finally{x(null)}}}async function Ke(a){let i="";try{const l=await m({data:{card_catalog_id:a.id}});l.changed?i=` · fee $${l.before.annual_fee}→$${l.after.annual_fee}`:l.fee_verified&&(i=` · fee verified${l.fee_method?` (${l.fee_method})`:""}`),l.fee_rejected&&(i=` · ⚠ ${l.fee_rejected}`)}catch(l){i=` · ⚠ fee verify failed (${D(l)})`}const c=[];let o=null;if(await Ge({issuer:a.issuer,name:a.name,annual_fee:a.annual_fee,fresh:!0},{onBenefit:l=>c.push(l),onError:l=>{Ze(l)&&u(),o=l}}),o)return{ok:!1,msg:o};if(c.length===0)return{ok:!1,msg:`no benefits returned — existing rows kept${i}`};const t=c.map(l=>We(a.id,l));for(let l=0;l<2;l++)try{const d=await g({data:{rows:t,remapExisting:!0}}),v=d.rejected.length>0?` · ${d.rejected.length} rejected by integrity gate`:"";return{ok:!0,msg:`${a.benefits} → ${d.inserted} benefits${i}${v}`}}catch(d){if(l===0&&Vs(d)){await new Promise(v=>setTimeout(v,1200));continue}return{ok:!1,msg:`insert failed — ${D(d,"failed")}`}}return{ok:!1,msg:`insert failed — ${D(null,"failed")}`}}async function Qe(a,i){const c=a.map(o=>o.id).slice(0,500);if(c.length!==0)try{await N({data:{cardIds:c}}),f.info(`${c.length} card${c.length===1?"":"s"} moved to background re-verification (${i}). It keeps running on the server — you can close this tab.`,{duration:8e3}),s.invalidateQueries({queryKey:["catalog-reverify-status"]})}catch(o){f.error(`Could not queue background re-verification: ${D(o)}`)}}async function Ue(a){if(await n({title:`Re-verify benefits for ${a.issuer} ${a.name}?`,description:`This bypasses the 7-day cache, re-fetches live sources, and REPLACES the ${a.benefits} existing benefit row${a.benefits===1?"":"s"}.`,confirmText:"Re-verify",destructive:!0})){x(a.id);try{const i=await Ke(a);i.ok?f.success(`${a.issuer} ${a.name}: re-verified — ${i.msg}`):(f.error(`${a.issuer} ${a.name}: ${i.msg}`),await Qe([a],"browser run failed"))}finally{s.invalidateQueries({queryKey:["catalog-health"]}),s.invalidateQueries({queryKey:["benefits"]}),x(null)}}}async function be(a,i={}){const c=a.cards;if(c.length===0)return f.info("Nothing to re-verify");const o=Pe(),t=Xs(),l=1440*60*1e3,d=r=>!!r&&Date.now()-new Date(r).getTime()<l;for(const r of c){if(i.ignoreFreshness)break;const S=!!r.fee_source_url&&d(r.fee_verified_at),C=d(r.lastBenefitAt);(S||C)&&t.add(r.id)}const v=c.filter(r=>!t.has(r.id)),F=v.length!==c.length&&v.length>0;if(o?.active&&v.length===0){Ee(),f.success(`Bulk re-verify complete — all ${c.length} cards finished`);return}if(v.length===0){Ee(),f.info(`All ${c.length} cards were already re-verified in the last 24h`);return}const z=v,oe=a.issuer?`${a.issuer} `:"";if(!i.skipConfirmation&&!await n({title:F?`Resume re-verify — ${z.length} of ${c.length} ${oe}cards left?`:`Re-verify ${z.length} ${oe}card${z.length===1?"":"s"}?`,description:F?`${c.length-z.length} card${c.length-z.length===1?" was":"s were"} already re-verified and will be skipped. Any interruption will resume automatically until every card finishes.`:"This bypasses the 7-day cache, re-fetches live issuer sources for every card, and REPLACES their existing benefit rows through the integrity gate. It calls the AI gateway repeatedly and may take a while. Progress 
1is saved and any interruption will resume automatically until every card finishes.",confirmText:F?`Resume (${z.length})`:`Re-verify ${z.length}`,destructive:!0}))return;Me(!0),Be({done:0,total:z.length,failed:0});const se=new Set(t),xe=c.map(r=>r.id);let A=z,le=0;for(ts(se,!0,xe);A.length>0;){le++;let r=0;const S=[],C=[];async function T(){for(;;){const L=r++;if(L>=A.length)return;const M=A[L];if(!M)return;try{await ea();const we=await Ke(M);we.ok?se.add(M.id):(S.push(M),C.push(`${M.issuer} ${M.name}: ${we.msg}`))}catch(we){const gs=we?.message??"unknown error";S.push(M),C.push(`${M.issuer} ${M.name}: ${gs}`)}finally{ts(se,!0,xe),Be({done:se.size-t.size,total:z.length,failed:S.length})}}}const ce=Math.min(3,A.length);if(await Promise.all(Array.from({length:ce},()=>T())),A=S,A.length>0){if(le>=2){console.warn("[catalog-health] handing unfinished cards to the background queue",C),await Qe(A,"retries exhausted in the browser"),A=[];break}const L=Math.min(6e4,5e3*2**Math.min(le-1,4));console.warn("[catalog-health] automatically retrying unfinished cards",C),f.warning(`${A.length} card${A.length===1?"":"s"} paused — retrying automatically in ${Math.round(L/1e3)}s`,{duration:Math.min(L,15e3)}
1),await new Promise(M=>window.setTimeout(M,L))}}s.invalidateQueries({queryKey:["catalog-health"]}),s.invalidateQueries({queryKey:["benefits"]}),Me(!1),Ee(),f.success(`Bulk re-verify complete — all ${z.length} remaining cards finished`)}k.useEffect(()=>{if(U||R.length===0||V||Te.current)return;const a=Pe();if(!a||!a.active&&a.ids.length===0)return;const i=new Set(a.scopeIds?.length?a.scopeIds:R.map(o=>o.id)),c=R.filter(o=>i.has(o.id));c.length!==0&&(Te.current=!0,f.info("Resuming the unfinished re-verification automatically"),be({cards:c},{skipConfirmation:!0}))},[U,R,V]);async function De(a="incomplete"){const i=a==="all"?R:R.filter(l=>ae(l)!=="complete");if(i.length===0)return f.info("Nothing to enrich");const c=a==="all"?"ALL":"incomplete";if(!await n({title:`Enrich ${i.length} ${c} card${i.length===1?"":"s"}?`,description:"This calls the AI gateway and may take several minutes.",confirmText:"Enrich"}))return;_(!0);let o=0,t=0;for(const l of i)x(l.id),(await Se(l)).ok?o++:t++,s.invalidateQueries({queryKey:["catalog-health"]});x(null),_(!1),f[t===0?"success":"warning"](`Bulk enrich: ${o} ok, ${t} failed (out of ${i.length})`)}async function ps(a,i,c){const o=i.filter(d=>ae(d)!=="complete");if(o.length===0)return f.info(`${a}: nothing to enrich`);if(!await n({title:`Enrich ${o.length} incomplete ${a} card${o.length===1?"":"s"}?`,confirmText:"Enrich"}))return;Ie(a);let t=0,l=0;for(const d of o)x(d.id),(await Se(d)).ok?t++:l++,s.invalidateQueries({queryKey:["catalog-health"]});x(null),Ie(null),f[l===0?"success":"warning"](`${a}: ${t} ok, ${l} failed (out of ${o.length})`)}function He(a){b(i=>({...i,[a]:!i[a]}))}function Je(a){const i={};for(const c of he)i[c.issuer]=a;b(i)}return e.jsxs("div",{className:"max-w-6xl mx-auto px-4 py-6 md:px-6 md:py-10",children:[e.jsx(_s,{to:"/admin",className:"mb-4",children:"Back to admin"}),e.jsx("p",{className:"text-xs uppercase tracking-[0.2em] text-titanium",children:"Admin · Data quality"}),e.jsx("h1",{className:"font-display text-3xl sm:text-4xl mt-1 leading-tight",children:"Catalog health"}),e.jsxs("p",{className:"text-sm text-titanium mt-2 max-w-2xl",children:["Flags catalog cards missing benefits, earning rates, or fee data. Click ",e.jsx("em",{children:"Enrich"})," to re-verify metadata, seed rates, and import benefits in one click. Click ",e.jsx("em",{children:"Re-verify offer"})," to refresh the welcome offer for a single card and auto-correct any drift."]}),e.jsx(aa,{}),e.jsx(ta,{}),e.jsx(na,{}),e.jsxs("details",{className:"mt-3 max-w-2xl text-xs text-titanium group",children:[e.jsxs("summary",{className:"cursor-pointer underline hover:text-platinum list-none flex items-center gap-1",children:[e.jsx(zs,{className:"size-3.5"}),e.jsx("span",{children:"How this works & troubleshooting"})]}),e.jsxs("div",{className:"mt-3 space-y-3 pl-5",children:[e.jsxs("p",{children:[e.jsx("strong",{children:"Complete card ="})," earning rates populated, at least one ACTIVE benefit row, and every dollar figure on the card backed by an issuer source URL ",e.jsx("em",{children:"and"})," quoted issuer wording. Row counts alone never certify a value: a card whose monetary rows have no evidence stays",e.jsx("em",{children:" Partial"}),", because members are already shown no dollar value for those rows. Cash-back cards use ",e.jsx("code",{className:"mx-1",children:"cash_back_percent"})," rates applied to real spend, not flat estimates."]}),e.jsxs("p",{children:[e.jsx("strong",{children:"Counts are active rows only."})," Retired and superseded benefit rows are excluded, so a card that legitimately lost rows during catalog normalization is not treated as an empty shell — and a card with rows but no confirmed evidence is not treated as ready."]}),e.jsxs("div",{children:[e.jsx("strong",{children:"If Enrich leaves a card partial:"}),e.jsxs("ol",{className:"list-decimal pl-5 mt-1 space-y-0.5",children:[e.jsx("li",{children:"Retry — transient AI-gateway timeouts are the most common cause."}),e.jsxs("li",{children:["Verify the card name is exact and current; rename on ",e.jsx(Ve,{to:"/ingest",className:"underline",children:"Card catalog"})," if needed."]}
1),e.jsx("li",{children:"Recently launched / region-specific cards may lack public data — wait and retry."}),e.jsxs("li",{children:["Still failing? Hide or delete it on ",e.jsx(Ve,{to:"/ingest",className:"underline",children:"Card catalog"}),"."]})]})]}),e.jsxs("p",{children:[e.jsx("strong",{children:"Scope:"})," Enrich/Re-verify update benefits, rates, and fees only — not card art. Use ",e.jsx("em",{children:"Fetch missing card art"})," for visuals."]}),e.jsxs("p",{children:[e.jsx("strong",{children:"Proposal scanner:"})," requires a verified issuer URL and ≥0.7 confidence (0.85 for fee changes) before surfacing new cards/updates."]}),e.jsxs("p",{children:[e.jsx("strong",{children:"Points valuation:"})," Plaid tx × catalog earning rate, converted with fixed per-program cpp (Chase UR ~2.05¢, Amex MR ~2.0¢, Hyatt ~1.7¢, Hilton ~0.6¢). No welcome bonuses, transfer upside, or activation-required rotating categories. Adjust at ",e.jsx("code",{children:"/admin/valuations"}),"."]})]})]}),e.jsxs("div",{className:"mt-6 grid sm:grid-cols-2 lg:grid-cols-5 gap-3",children:[e.jsx(ge,{label:"Stub",value:fe.stub,tone:"bad"}),e.jsx(ge,{label:"Partial",value:fe.partial,tone:"warn"}),e.jsx(ge,{label:"Complete",value:fe.complete,tone:"ok"}),e.jsx(ge,{label:"Unverified fee",value:fe.unverifiedFee,tone:"warn"}),e.jsx(ge,{label:"Unevidenced value",value:fe.unevidencedValue,tone:"bad"})]}),e.jsxs("div",{className:"mt-6 flex flex-wrap items-center gap-3",children:[e.jsx(os,{placeholder:"Search issuer or name…",value:B,onChange:a=>J(a.target.value),className:"w-full sm:max-w-xs"}),e.jsxs($s,{value:w,onValueChange:a=>P(a),children:[e.jsx(Cs,{className:"w-full sm:w-[200px]",children:e.jsx(Ss,{})}),e.jsxs(Rs,{children:[e.jsx(de,{value:"all",children:"All cards"}),e.jsx(de,{value:"stub",children:"Stub only"}),e.jsx(de,{value:"partial",children:"Partial only"}),e.jsx(de,{value:"complete",children:"Complete only"}),e.jsx(de,{value:"unverified-fee",children:"Unverified fee only"}),e.jsx(de,{value:"unevidenced-value",children:"Unevidenced dollar value only"})]})]}),e.jsxs("div",{className:"grid w-full grid-cols-2 gap-2 sm:ml-auto sm:flex sm:w-auto sm:flex-wrap",children:[e.jsxs($,{variant:"outline",className:"w-full min-w-0 sm:w-auto",onClick:async()=>{f.info("Fetching card art from issuer pages…");try{const a=await Fe({data:{only_missing:!0}});f.success(`Card art: ${a.succeeded}/${a.processed} succeeded`),s.invalidateQueries({queryKey:["catalog-health"]})}catch(a){f.error(`Card art fetch failed: ${a instanceof Error?a.message:String(a)}`)}},children:[e.jsx(_e,{className:"size-4"})," ",e.jsx("span",{className:"hidden sm:inline",children:"Fetch missing card art"}),e.jsx("span",{className:"sm:hidden",children:"Fetch art"})]}),e.jsx($,{variant:"outline",className:"w-full min-w-0 sm:w-auto",disabled:p||U,onClick:async()=>{Q(!0);try{let a=0,i=0,c=0,o=1/0,t=0;for(f.info("Seeding earning rates across catalog…");o>0&&t<20;){const l=await h({data:{overwrite:!1,batch_size:15}});if(a+=l.inserted,i+=l.processed,c+=l.failed,o=l.eligible_remaining,t++,l.processed===0)break}f.success(`Seeded ${a} rates across ${i} cards${c?` · ${c} failed`:""}${o>0?` · ${o} still remaining`:""}`),s.invalidateQueries({queryKey:["catalog-health"]})}catch(a){f.error(`Seed failed: ${a instanceof Error?a.message:String(a)}`)}finally{Q(!1)}},children:p?e.jsxs(e.Fragment,{children:[e.jsx(I,{className:"size-4 shrink-0 animate-spin"})," ",e.jsx("span",{className:"truncate",children:"Seeding rates…"})]}):e.jsxs(e.Fragment,{children:[e.jsx(_e,{className:"size-4"})," ",e.jsx("span",{className:"hidden sm:inline",children:"Seed earning rates"}),e.jsx("span",{className:"sm:hidden",children:"Seed rates"})]})}),e.jsx($,{variant:"secondary",className:"w-full min-w-0 sm:w-auto",disabled:y||U,onClick:()=>De("incomplete"),children:y?e.jsxs(e.Fragment,{children:[e.jsx(I,{className:"size-4 animate-spin"})," Enriching…"]}):e.jsxs(e.Fragment,{children:[e.jsx(Re,{className:"size-4"})," ",e.jsx("span",{className:"hidden sm:inline",children:"Enrich incomplete"}),e.jsx("span",{className:"sm:hidden",children:"Incomplete"})]})}),e.jsx($,{variant:"gold",className:"w-full min-w-0 sm:w-auto",disabled:y||U,onClick:()=>De("all"),children:y?e.jsxs(e.Fragment,{children:[e.jsx(I,{className:"size-4 animate-spin"})," Enriching…"]}):e.jsxs(e.Fragment,{children:[e.jsx(Re,{className:"size-4"})," ",e.jsx("span",{className:"hidden sm:inline",children:"Enrich ALL cards"}),e.jsx("span",{className:"sm:hidden",children:"All"})]})}),q.length>0&&q.length!==R.length&&e.jsx($,{variant:"secondary",className:"w-full min-w-0 sm:w-auto",disabled:V||y||U,onClick:()=>be({cards:q}),children:V?e.jsxs(e.Fragment,{children:[e.jsx(I,{className:"size-4 animate-spin"})," Re-verifying…"]}):e.jsxs(e.Fragment,{children:[e.jsx(te,{className:"size-4 shrink-0"}),e.jsxs("span",{className:"hidden sm:inline",children:["Re-verify filtered (",q.length,")"]}),e.jsxs("span",{className:"truncate sm:hidden",children:["Filtered (",q.length,")"]})]})}),ve.length>0&&e.jsx($,{variant:"secondary",className:"w-full min-w-0 sm:w-auto",disabled:V||y||U,onClick:()=>be({cards:ve},{ignoreFreshness:!0}),children:V?e.jsxs(e.Fragment,{children:[e.jsx(I,{className:"size-4 animate-spin"})," Re-verifying…"]}):e.jsxs(e.Fragment,{children:[e.jsx(te,{className:"size-4 shrink-0"}
1),e.jsxs("span",{className:"hidden sm:inline",children:["Finish remaining (",ve.length,")"]}),e.jsxs("span",{className:"truncate sm:hidden",children:["Remaining (",ve.length,")"]})]})}),e.jsx($,{variant:"destructive",className:"w-full min-w-0 sm:w-auto",disabled:V||y||U||R.length===0,onClick:()=>be({cards:R}),children:V?e.jsxs(e.Fragment,{children:[e.jsx(I,{className:"size-4 animate-spin"})," Re-verifying…"]}):e.jsxs(e.Fragment,{children:[e.jsx(te,{className:"size-4"})," ",e.jsxs("span",{className:"hidden sm:inline",children:["Re-verify ALL benefits (",R.length,")"]}),e.jsx("span",{className:"sm:hidden",children:"Re-verify all"})]})})]})]}),e.jsx("div",{className:"mt-4",children:e.jsx(Qs,{cardIds:(q.length>0?q:R).map(a=>a.id),label:q.length>0&&q.length!==R.length?`${q.length} filtered card${q.length===1?"":"s"}`:`all ${R.length} cards`})}),e.jsx("div",{className:"mt-4",children:e.jsx(vs,{})}),e.jsx("div",{className:"mt-4",children:e.jsx(Hs,{onPinned:()=>s.invalidateQueries({queryKey:["catalog-health"]})})}),V&&e.jsxs("div",{className:"mt-3 rounded-xl border border-white/10 bg-white/5 px-4 py-3 text-sm text-platinum",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(I,{className:"size-4 animate-spin"}),"Re-verifying ",re.done," / ",re.total," cards",re.failed>0?` · ${re.failed} queued for automatic retry`:""]}),e.jsx("div",{className:"mt-2 h-1.5 w-full overflow-hidden rounded-full bg-white/10",children:e.jsx("div",{className:"h-full rounded-full bg-brand-gold transition-all",style:{width:`${re.total?re.done/re.total*100:0}%`}})}),e.jsx("p",{className:"mt-2 text-xs text-titanium",children:"Failed attempts stay in the queue and are retried automatically until every card succeeds."})]}),!U&&he.length>0&&e.jsxs("div",{className:"mt-4 flex items-center gap-3 text-xs text-titanium",children:[e.jsxs("span",{children:[he.length," issuer",he.length===1?"":"s"," · ",q.length," card",q.length===1?"":"s"]}),e.jsx("button",{type:"button",className:"underline hover:text-platinum",onClick:()=>Je(!0),children:"Expand all"}),e.jsx("button",{type:"button",className:"underline hover:text-platinum",onClick:()=>Je(!1),children:"Collapse all"})]}),e.jsx("div",{className:"mt-4 space-y-3",children:U?e.jsx(me,{children:e.jsx(ye,{className:"p-10 text-center text-titanium",children:"Loading catalog…"})}):q.length===0?e.jsx(me,{children:e.jsx(ye,{className:"p-10 text-center text-titanium",children:"No cards match."})}):he.map(a=>{const i=ie[a.issuer]??!1,c=a.counts.stub+a.counts.partial,o=xs===a.issuer;return e.jsxs(me,{className:"overflow-hidden",children:[e.jsxs("div",{role:"button",tabIndex:0,"aria-expanded":i,onClick:()=>He(a.issuer),onKeyDown:t=>{(t.key==="Enter"||t.key===" ")&&(t.preventDefault(),He(a.issuer))},className:"w-full grid grid-cols-[auto_1fr_auto] items-center gap-x-3 gap-y-2 p-3 md:p-4 hover:bg-metallic/30 transition-colors text-left cursor-pointer",children:[i?e.jsx(fs,{className:"size-4 text-titanium shrink-0"}):e.jsx(ds,{className:"size-4 text-titanium shrink-0"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"font-display text-base md:text-lg text-platinum truncate",children:a.issuer}),e.jsxs("div",{className:"text-[11px] text-titanium",children:[a.cards.length," card",a.cards.length===1?"":"s"]})]}),e.jsx($,{size:"sm",variant:"secondary",disabled:o||y||c===0,onClick:t=>{t.stopPropagation(),ps(a.issuer,a.cards)},children:o?e.jsxs(e.Fragment,{children:[e.jsx(I,{className:"size-3.5 animate-spin"})," ",e.jsx("span",{className:"hidden sm:inline",children:"Enriching…"})]}):e.jsxs(e.Fragment,{children:[e.jsx(Re,{className:"size-3.5"})," ",e.jsx("span",{className:"hidden sm:inline",children:"Enrich incomplete"}),e.jsx("span",{className:"sm:hidden",children:"Enrich"})]})}),e.jsxs("div",{className:"col-span-3 flex flex-wrap items-center gap-1.5",children:[a.counts.stub>0&&e.jsxs(O,{variant:"destructive",className:"gap-1 text-[10px]",children:[a.counts.stub," stub"]}),a.counts.partial>0&&e.jsxs(O,{variant:"secondary",className:"gap-1 text-[10px] text-gold border-gold/40",children:[a.counts.partial," partial"]}),a.counts.complete>0&&e.jsxs(O,{variant:"secondary",className:"gap-1 text-[10px] text-emerald-400 border-emerald-400/30",children:[a.counts.complete," complete"]})]})]}),i&&e.jsxs("div",{className:"border-t border-metallic/30",children:[e.jsx("div",{className:"md:hidden divide-y divide-metallic/30",children:a.cards.map(t=>{const l=ae(t),d=!t.fee_verified_at||!t.fee_source_url;return e.jsxs("div",{className:"p-3 space-y-2",children:[e.jsx("div",{className:"flex items-start justify-between gap-2",children:e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-sm text-platinum font-medium break-words",children:t.name}),e.jsxs("div",{className:"mt-1 flex flex-wrap items-center gap-1.5",children:[e.jsx(ls,{status:l}),e.jsx(O,{variant:"outline",className:ne("text-[10px] uppercase tracking-wide",t.card_type==="business"?"border-gold/40 text-gold":"border-titanium/30 text-titanium"),children:t.card_type==="business"?"Business":"Personal"}
1),as(t).map(v=>e.jsx(is,{label:e.jsxs(e.Fragment,{children:[e.jsx(ue,{className:"size-3"})," hint"]}),message:v.message,className:"border-gold/40 text-gold"},v.code)),(()=>{const v=ns(t);return v?e.jsx(is,{label:"Invite-only",message:v,className:"border-gold/60 text-gold"}):null})()]})]})}),e.jsxs("div",{className:"grid grid-cols-3 gap-2 text-[11px]",children:[e.jsxs("div",{className:"rounded-md bg-metallic/20 px-2 py-1.5",children:[e.jsx("div",{className:"text-titanium uppercase tracking-wide text-[9px]",children:"Fee"}),e.jsxs("div",{className:"font-mono text-platinum flex items-center gap-1 whitespace-nowrap",children:[d&&e.jsx(ue,{className:"size-3 text-gold shrink-0"}),t.annual_fee===0?e.jsx("span",{className:"text-muted-foreground",children:"$0"}):Ye(t.annual_fee)]})]}),e.jsxs("div",{className:"rounded-md bg-metallic/20 px-2 py-1.5",children:[e.jsx("div",{className:"text-titanium uppercase tracking-wide text-[9px]",children:"Rates"}),e.jsx("div",{className:ne("font-mono",t.rates===0&&!ze(t)&&"text-destructive"),children:t.rates})]}),e.jsxs("div",{className:"rounded-md bg-metallic/20 px-2 py-1.5",children:[e.jsx("div",{className:"text-titanium uppercase tracking-wide text-[9px]",children:"Benefits"}),e.jsx("div",{className:ne("font-mono",t.benefits===0&&"text-destructive"),children:t.benefits})]})]}),e.jsx(rs,{row:t}),e.jsxs("div",{className:"flex flex-wrap gap-1.5",children:[e.jsx($,{size:"sm",variant:"secondary",className:"flex-1 min-w-[110px]",disabled:E===t.id||y||o,onClick:()=>Le(t),children:E===t.id?e.jsxs(e.Fragment,{children:[e.jsx(I,{className:"size-3.5 animate-spin"})," Working…"]}):e.jsxs(e.Fragment,{children:[e.jsx(_e,{className:"size-3.5"})," Enrich"]})}),e.jsxs($,{size:"sm",variant:"outline",className:"flex-1 min-w-[110px]",disabled:E===t.id||y||o,onClick:()=>Ue(t),children:[e.jsx(te,{className:"size-3.5"})," Re-verify"]}),e.jsxs($,{size:"sm",variant:"outline",className:"flex-1 min-w-[110px]",disabled:E===t.id||y||o,onClick:()=>Oe(t),title:"Re-scrape issuer page and auto-correct stored welcome offer",children:[e.jsx(te,{className:"size-3.5"})," Re-verify offer"]}),e.jsxs($,{size:"sm",variant:"outline",className:"flex-1 min-w-[110px]",disabled:E===t.id||y||o,onClick:async()=>{x(t.id);try{const F=(await Fe({data:{catalog_ids:[t.id],only_missing:!1}})).results[0];F?.ok?f.success(`${t.issuer} ${t.name}: card art updated`):f.error(`${t.issuer} ${t.name}: ${F?.error??"art fetch failed"}`),s.invalidateQueries({queryKey:["catalog-health"]}),s.invalidateQueries({queryKey:["card-tile",t.id]})}catch(v){f.error(`${t.issuer} ${t.name}: ${v instanceof Error?v.message:String(v)}`)}finally{x(null)}},children:[e.jsx(es,{className:"size-3.5"})," Fetch art"]})]})]},t.id)})}),e.jsx("div",{className:"hidden md:block overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-metallic/20 text-titanium text-xs uppercase tracking-wide",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left p-3",children:"Status"}),e.jsx("th",{className:"text-left p-3",children:"Card"}),e.jsx("th",{className:"text-left p-3",children:"Type"}),e.jsx("th",{className:"text-right p-3",children:"Fee"}),e.jsx("th",{className:"text-right p-3",children:"Rates"}),e.jsx("th",{className:"text-right p-3",children:"Benefits"}),e.jsx("th",{className:"text-right p-3",children:"Action"})]})}),e.jsx("tbody",{children:a.cards.map(t=>{const l=ae(t);return e.jsxs(k.Fragment,{children:[e.jsxs("tr",{className:"border-t border-metallic/30",children:[e.jsx("td",{className:"p-3",children:e.jsx(ls,{status:l})}),e.jsx("td",{className:"p-3 text-platinum",children:e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx("span",{children:t.name}),as(t).map(d=>e.jsxs(G,{children:[e.jsx(W,{asChild:!0,children:e.jsxs(O,{variant:"outline",className:"text-[10px] gap-1 border-gold/40 text-gold cursor-help",children:[e.jsx(ue,{className:"size-3"})," hint"]})}),e.jsx(Y,{side:"top",className:"max-w-xs",children:e.jsx("p",{className:"text-xs",children:d.message})})]},d.code)),(()=>{const d=ns(t);
1return d?e.jsxs(G,{children:[e.jsx(W,{asChild:!0,children:e.jsx(O,{variant:"outline",className:"text-[10px] gap-1 border-gold/60 text-gold cursor-help",children:"Invite-only"})}),e.jsx(Y,{side:"top",className:"max-w-xs",children:e.jsx("p",{className:"text-xs",children:d})})]}):null})()]})}),e.jsx("td",{className:"p-3",children:e.jsx(O,{variant:"outline",className:ne("text-[10px] uppercase tracking-wide",t.card_type==="business"?"border-gold/40 text-gold":"border-titanium/30 text-titanium"),children:t.card_type==="business"?"Business":"Personal"})}),e.jsx("td",{className:"p-3 text-right font-mono whitespace-nowrap",children:e.jsxs("div",{className:"inline-flex items-center justify-end gap-1.5",children:[(!t.fee_verified_at||!t.fee_source_url)&&e.jsxs(G,{children:[e.jsx(W,{asChild:!0,children:e.jsx(ue,{className:"size-3.5 text-gold cursor-help"})}),e.jsx(Y,{side:"left",className:"max-w-xs",children:e.jsxs("p",{className:"text-xs",children:["Annual fee has not been verified against an issuer-page citation. Run ",e.jsx("em",{children:"Enrich"})," to re-verify with a cited source."]})})]}),t.annual_fee===0?e.jsx("span",{className:"text-muted-foreground",children:"$0"}):e.jsx("span",{children:Ye(t.annual_fee)})]})}),e.jsx("td",{className:ne("p-3 text-right font-mono",t.rates===0&&!ze(t)&&"text-destructive"),children:t.rates}),e.jsx("td",{className:ne("p-3 text-right font-mono",t.benefits===0&&"text-destructive"),children:t.benefits}),e.jsx("td",{className:"p-3 text-right",children:e.jsxs("div",{className:"inline-flex gap-1.5 justify-end",children:[e.jsx($,{size:"sm",variant:"secondary",disabled:E===t.id||y||o,onClick:()=>Le(t),children:E===t.id?e.jsxs(e.Fragment,{children:[e.jsx(I,{className:"size-3.5 animate-spin"})," Working…"]}):e.jsxs(e.Fragment,{children:[e.jsx(_e,{className:"size-3.5"})," Enrich"]})}),e.jsxs(G,{children:[e.jsx(W,{asChild:!0,children:e.jsxs($,{size:"sm",variant:"outline",disabled:E===t.id||y||o,onClick:()=>Ue(t),children:[e.jsx(te,{className:"size-3.5"})," Re-verify"]})}),e.jsx(Y,{side:"left",className:"max-w-xs",children:e.jsx("p",{className:"text-xs",children:"Bypass the 7-day benefits cache, re-fetch live sources, and replace this card's existing benefits."})})]}),e.jsxs(G,{children:[e.jsx(W,{asChild:!0,children:e.jsxs($,{size:"sm",variant:"outline",disabled:E===t.id||y||o,onClick:()=>Oe(t),children:[e.jsx(te,{className:"size-3.5"})," Re-verify offer"]})}),e.jsx(Y,{side:"left",className:"max-w-xs",children:e.jsx("p",{className:"text-xs",children:"Re-scrape the issuer page, re-extract the welcome offer with AI, and auto-correct stored values if they've drifted. Corrections are logged to the change log."})})]}),e.jsxs(G,{children:[e.jsx(W,{asChild:!0,children:e.jsxs($,{size:"sm",variant:"outline",disabled:E===t.id||y||o,onClick:async()=>{x(t.id);try{const v=(await Fe({data:{catalog_ids:[t.id],only_missing:!1}})).results[0];v?.ok?f.success(`${t.issuer} ${t.name}: card art updated`):f.error(`${t.issuer} ${t.name}: ${v?.error??"art fetch failed"}`),s.invalidateQueries({queryKey:["catalog-health"]}),s.invalidateQueries({queryKey:["card-tile",t.id]})}catch(d){f.error(`${t.issuer} ${t.name}: ${d instanceof Error?d.message:String(d)}`)}finally{x(null)}},children:[e.jsx(es,{className:"size-3.5"})," Fetch art"]})}),e.jsx(Y,{side:"left",className:"max-w-xs",children:e.jsx("p",{className:"text-xs",children:"Scrape the official card rendering from the issuer page and save it to this card. Overwrites any existing art."})})]})]})})]}),e.jsx("tr",{className:"border-t border-metallic/20",children:e.jsx("td",{className:"px-3 pb-3",colSpan:7,children:e.jsx(rs,{row:t})})},`${t.id}-sources`)]},t.id)})})]})})]})]},a.issuer)})})]})}function ge({label:s,value:n,tone:u}){const m=u==="bad"?"text-destructive":u==="warn"?"text-gold":"text-emerald-400";return e.jsxs("div",{className:"rounded-2xl border border-metallic bg-metallic/40 p-5",children:[e.jsx("p",{className:"text-[11px] uppercase tracking-[0.2em] text-titanium",children:s}),e.jsx("p",{className:ne("font-display text-3xl mt-1",m),children:n.toLocaleString()})]})}function ls({status:s}){return s==="stub"?e.jsxs(G,{children:[e.jsx(W,{asChild:!0,children:e.jsxs(O,{variant:"destructive",className:"gap-1 cursor-help",children:[e.jsx(ue,{className:"size-3"})," Stub"]})}),e.jsx(Y,{side:"right",className:"max-w-xs",children:e.jsxs("p",{className:"text-xs",children:["No active benef
1its and no earning rates — this card is essentially an empty shell. Click ",e.jsx("em",{children:"Enrich"})," to import both."]})})]}):s==="partial"?e.jsxs(G,{children:[e.jsx(W,{asChild:!0,children:e.jsxs(O,{variant:"secondary",className:"gap-1 text-gold border-gold/40 cursor-help",children:[e.jsx(ue,{className:"size-3"})," Partial"]})}),e.jsx(Y,{side:"right",className:"max-w-xs",children:e.jsxs("p",{className:"text-xs",children:["Missing benefits or earning rates, a premium card with a suspicious $0 fee, or a card whose dollar figures have no issuer evidence. Evidence gaps are not fixed by ",e.jsx("em",{children:"Enrich"})," — resolve them in Benefits review."]})})]}):e.jsxs(G,{children:[e.jsx(W,{asChild:!0,children:e.jsxs(O,{variant:"secondary",className:"gap-1 text-emerald-400 border-emerald-400/30 cursor-help",children:[e.jsx(us,{className:"size-3"})," Complete"]})}),e.jsx(Y,{side:"right",className:"max-w-xs",children:e.jsx("p",{className:"text-xs",children:"Earning rates and active benefits are populated and every stored dollar figure cites issuer evidence. This card is ready for recommendations."})})]})}export{Ia as Route};

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.